1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "../config.h"
25 #include "gtkbindings.h"
26 #include <gdk/gdkkeysyms.h>
28 /* the number rows memchunk expands at a time */
29 #define CLIST_OPTIMUM_SIZE 512
31 /* the width of the column resize windows */
34 /* minimum allowed width of a column */
35 #define COLUMN_MIN_WIDTH 5
37 /* this defigns the base grid spacing */
38 #define CELL_SPACING 1
40 /* added the horizontal space at the beginning and end of a row*/
41 #define COLUMN_INSET 3
43 /* used for auto-scrolling */
44 #define SCROLL_TIME 100
46 /* gives the top pixel of the given row in context of
47 * the clist's voffset */
48 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
49 (((row) + 1) * CELL_SPACING) + \
52 /* returns the row index from a y pixel location in the
53 * context of the clist's voffset */
54 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
55 ((clist)->row_height + CELL_SPACING))
57 /* gives the left pixel of the given column in context of
58 * the clist's hoffset */
59 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
62 /* returns the column index from a x pixel location in the
63 * context of the clist's hoffset */
65 COLUMN_FROM_XPIXEL (GtkCList * clist,
70 for (i = 0; i < clist->columns; i++)
71 if (clist->column[i].visible)
73 cx = clist->column[i].area.x + clist->hoffset;
75 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
76 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
84 /* returns the top pixel of the given row in the context of
86 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
88 /* returns the left pixel of the given column in the context of
90 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
92 /* returns the total height of the list */
93 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
94 (CELL_SPACING * ((clist)->rows + 1)))
97 /* returns the total width of the list */
99 LIST_WIDTH (GtkCList * clist)
103 for (last_column = clist->columns - 1;
104 last_column >= 0 && !clist->column[last_column].visible; last_column--);
106 if (last_column >= 0)
107 return (clist->column[last_column].area.x +
108 clist->column[last_column].area.width +
109 COLUMN_INSET + CELL_SPACING);
113 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
149 static void sync_selection (GtkCList * clist,
153 /* GtkCList Methods */
154 static void gtk_clist_class_init (GtkCListClass *klass);
155 static void gtk_clist_init (GtkCList *clist);
157 /* GtkObject Methods */
158 static void gtk_clist_destroy (GtkObject *object);
159 static void gtk_clist_finalize (GtkObject *object);
161 /* GtkWidget Methods */
162 static void gtk_clist_realize (GtkWidget *widget);
163 static void gtk_clist_unrealize (GtkWidget *widget);
164 static void gtk_clist_map (GtkWidget *widget);
165 static void gtk_clist_unmap (GtkWidget *widget);
166 static void gtk_clist_draw (GtkWidget *widget,
168 static gint gtk_clist_expose (GtkWidget *widget,
169 GdkEventExpose *event);
170 static gint gtk_clist_key_press (GtkWidget *widget,
172 static gint gtk_clist_button_press (GtkWidget *widget,
173 GdkEventButton *event);
174 static gint gtk_clist_button_release (GtkWidget *widget,
175 GdkEventButton *event);
176 static gint gtk_clist_motion (GtkWidget *widget,
177 GdkEventMotion *event);
178 static void gtk_clist_size_request (GtkWidget *widget,
179 GtkRequisition *requisition);
180 static void gtk_clist_size_allocate (GtkWidget *widget,
181 GtkAllocation *allocation);
182 static void gtk_clist_draw_focus (GtkWidget *widget);
183 static gint gtk_clist_focus_in (GtkWidget *widget,
184 GdkEventFocus *event);
185 static gint gtk_clist_focus_out (GtkWidget *widget,
186 GdkEventFocus *event);
187 static gint gtk_clist_focus (GtkContainer *container,
188 GtkDirectionType direction);
189 static void gtk_clist_style_set (GtkWidget *widget,
190 GtkStyle *previous_style);
191 static void gtk_clist_parent_set (GtkWidget *widget,
192 GtkWidget *previous_parent);
194 /* GtkContainer Methods */
195 static void gtk_clist_set_focus_child (GtkContainer *container,
197 static void gtk_clist_forall (GtkContainer *container,
198 gboolean include_internals,
199 GtkCallback callback,
200 gpointer callback_data);
203 static void toggle_row (GtkCList *clist,
207 static void real_select_row (GtkCList *clist,
211 static void real_unselect_row (GtkCList *clist,
215 static void update_extended_selection (GtkCList *clist,
217 static GList *selection_find (GtkCList *clist,
219 GList *row_list_element);
220 static void real_select_all (GtkCList *clist);
221 static void real_unselect_all (GtkCList *clist);
222 static void move_vertical (GtkCList *clist,
225 static void move_horizontal (GtkCList *clist,
227 static void real_undo_selection (GtkCList *clist);
228 static void fake_unselect_all (GtkCList *clist,
230 static void fake_toggle_row (GtkCList *clist,
232 static void resync_selection (GtkCList *clist,
234 static void sync_selection (GtkCList *clist,
237 static void set_anchor (GtkCList *clist,
241 static void start_selection (GtkCList *clist);
242 static void end_selection (GtkCList *clist);
243 static void toggle_add_mode (GtkCList *clist);
244 static void toggle_focus_row (GtkCList *clist);
245 static void move_focus_row (GtkCList *clist,
246 GtkScrollType scroll_type,
248 static void scroll_horizontal (GtkCList *clist,
249 GtkScrollType scroll_type,
251 static void scroll_vertical (GtkCList *clist,
252 GtkScrollType scroll_type,
254 static void extend_selection (GtkCList *clist,
255 GtkScrollType scroll_type,
257 gboolean auto_start_selection);
258 static gint get_selection_info (GtkCList *clist,
265 static void draw_xor_line (GtkCList *clist);
266 static gint new_column_width (GtkCList *clist,
269 static void column_auto_resize (GtkCList *clist,
270 GtkCListRow *clist_row,
273 static void real_resize_column (GtkCList *clist,
276 static void abort_column_resize (GtkCList *clist);
277 static void cell_size_request (GtkCList *clist,
278 GtkCListRow *clist_row,
280 GtkRequisition *requisition);
283 static void column_button_create (GtkCList *clist,
285 static void column_button_clicked (GtkWidget *widget,
289 static void adjust_adjustments (GtkCList *clist,
290 gboolean block_resize);
291 static void check_exposures (GtkCList *clist);
292 static void vadjustment_changed (GtkAdjustment *adjustment,
294 static void vadjustment_value_changed (GtkAdjustment *adjustment,
296 static void hadjustment_changed (GtkAdjustment *adjustment,
298 static void hadjustment_value_changed (GtkAdjustment *adjustment,
302 static void get_cell_style (GtkCList *clist,
303 GtkCListRow *clist_row,
309 static gint draw_cell_pixmap (GdkWindow *window,
310 GdkRectangle *clip_rectangle,
318 static void draw_row (GtkCList *clist,
321 GtkCListRow *clist_row);
322 static void draw_rows (GtkCList *clist,
325 /* Size Allocation / Requisition */
326 static void size_allocate_title_buttons (GtkCList *clist);
327 static void size_allocate_columns (GtkCList *clist);
328 static gint list_requisition_width (GtkCList *clist);
330 /* Memory Allocation/Distruction Routines */
331 static GtkCListColumn *columns_new (GtkCList *clist);
332 static void column_title_new (GtkCList *clist,
335 static void columns_delete (GtkCList *clist);
336 static GtkCListRow *row_new (GtkCList *clist);
337 static void row_delete (GtkCList *clist,
338 GtkCListRow *clist_row);
339 static void set_cell_contents (GtkCList *clist,
340 GtkCListRow *clist_row,
347 static gint real_insert_row (GtkCList *clist,
350 static void real_remove_row (GtkCList *clist,
352 static void real_clear (GtkCList *clist);
355 static gint default_compare (GtkCList *clist,
358 static void real_sort_list (GtkCList *clist);
359 static GList *gtk_clist_merge (GtkCList *clist,
362 static GList *gtk_clist_mergesort (GtkCList *clist,
366 static gboolean title_focus (GtkCList *clist,
368 static void gtk_clist_set_arg (GtkObject *object,
371 static void gtk_clist_get_arg (GtkObject *object,
376 static GtkContainerClass *parent_class = NULL;
377 static guint clist_signals[LAST_SIGNAL] = {0};
381 gtk_clist_get_type (void)
383 static GtkType clist_type = 0;
387 GtkTypeInfo clist_info =
391 sizeof (GtkCListClass),
392 (GtkClassInitFunc) gtk_clist_class_init,
393 (GtkObjectInitFunc) gtk_clist_init,
394 /* reserved_1 */ NULL,
395 /* reserved_2 */ NULL,
396 (GtkClassInitFunc) NULL,
399 clist_type = gtk_type_unique (GTK_TYPE_CONTAINER, &clist_info);
406 gtk_clist_class_init (GtkCListClass *klass)
408 GtkObjectClass *object_class;
409 GtkWidgetClass *widget_class;
410 GtkContainerClass *container_class;
412 object_class = (GtkObjectClass *) klass;
413 widget_class = (GtkWidgetClass *) klass;
414 container_class = (GtkContainerClass *) klass;
416 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
418 gtk_object_add_arg_type ("GtkCList::hadjustment",
422 gtk_object_add_arg_type ("GtkCList::vadjustment",
427 clist_signals[SELECT_ROW] =
428 gtk_signal_new ("select_row",
431 GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
432 gtk_marshal_NONE__INT_INT_POINTER,
437 clist_signals[UNSELECT_ROW] =
438 gtk_signal_new ("unselect_row",
441 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
442 gtk_marshal_NONE__INT_INT_POINTER,
443 GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_GDK_EVENT);
444 clist_signals[CLICK_COLUMN] =
445 gtk_signal_new ("click_column",
448 GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
449 gtk_marshal_NONE__INT,
450 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
451 clist_signals[RESIZE_COLUMN] =
452 gtk_signal_new ("resize_column",
455 GTK_SIGNAL_OFFSET (GtkCListClass, resize_column),
456 gtk_marshal_NONE__INT_INT,
457 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
459 clist_signals[TOGGLE_FOCUS_ROW] =
460 gtk_signal_new ("toggle_focus_row",
461 GTK_RUN_LAST | GTK_RUN_ACTION,
463 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_focus_row),
464 gtk_marshal_NONE__NONE,
466 clist_signals[SELECT_ALL] =
467 gtk_signal_new ("select_all",
468 GTK_RUN_LAST | GTK_RUN_ACTION,
470 GTK_SIGNAL_OFFSET (GtkCListClass, select_all),
471 gtk_marshal_NONE__NONE,
473 clist_signals[UNSELECT_ALL] =
474 gtk_signal_new ("unselect_all",
475 GTK_RUN_LAST | GTK_RUN_ACTION,
477 GTK_SIGNAL_OFFSET (GtkCListClass, unselect_all),
478 gtk_marshal_NONE__NONE,
480 clist_signals[UNDO_SELECTION] =
481 gtk_signal_new ("undo_selection",
482 GTK_RUN_LAST | GTK_RUN_ACTION,
484 GTK_SIGNAL_OFFSET (GtkCListClass, undo_selection),
485 gtk_marshal_NONE__NONE,
487 clist_signals[START_SELECTION] =
488 gtk_signal_new ("start_selection",
489 GTK_RUN_LAST | GTK_RUN_ACTION,
491 GTK_SIGNAL_OFFSET (GtkCListClass, start_selection),
492 gtk_marshal_NONE__NONE,
494 clist_signals[END_SELECTION] =
495 gtk_signal_new ("end_selection",
496 GTK_RUN_LAST | GTK_RUN_ACTION,
498 GTK_SIGNAL_OFFSET (GtkCListClass, end_selection),
499 gtk_marshal_NONE__NONE,
501 clist_signals[TOGGLE_ADD_MODE] =
502 gtk_signal_new ("toggle_add_mode",
503 GTK_RUN_LAST | GTK_RUN_ACTION,
505 GTK_SIGNAL_OFFSET (GtkCListClass, toggle_add_mode),
506 gtk_marshal_NONE__NONE,
508 clist_signals[EXTEND_SELECTION] =
509 gtk_signal_new ("extend_selection",
510 GTK_RUN_LAST | GTK_RUN_ACTION,
512 GTK_SIGNAL_OFFSET (GtkCListClass, extend_selection),
513 gtk_marshal_NONE__ENUM_FLOAT_BOOL,
515 GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT, GTK_TYPE_BOOL);
516 clist_signals[SCROLL_VERTICAL] =
517 gtk_signal_new ("scroll_vertical",
518 GTK_RUN_LAST | GTK_RUN_ACTION,
520 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_vertical),
521 gtk_marshal_NONE__ENUM_FLOAT,
522 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
523 clist_signals[SCROLL_HORIZONTAL] =
524 gtk_signal_new ("scroll_horizontal",
525 GTK_RUN_LAST | GTK_RUN_ACTION,
527 GTK_SIGNAL_OFFSET (GtkCListClass, scroll_horizontal),
528 gtk_marshal_NONE__ENUM_FLOAT,
529 GTK_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_FLOAT);
530 clist_signals[ABORT_COLUMN_RESIZE] =
531 gtk_signal_new ("abort_column_resize",
532 GTK_RUN_LAST | GTK_RUN_ACTION,
534 GTK_SIGNAL_OFFSET (GtkCListClass, abort_column_resize),
535 gtk_marshal_NONE__NONE,
539 gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
541 object_class->set_arg = gtk_clist_set_arg;
542 object_class->get_arg = gtk_clist_get_arg;
543 object_class->destroy = gtk_clist_destroy;
544 object_class->finalize = gtk_clist_finalize;
546 widget_class->realize = gtk_clist_realize;
547 widget_class->unrealize = gtk_clist_unrealize;
548 widget_class->map = gtk_clist_map;
549 widget_class->unmap = gtk_clist_unmap;
550 widget_class->draw = gtk_clist_draw;
551 widget_class->button_press_event = gtk_clist_button_press;
552 widget_class->button_release_event = gtk_clist_button_release;
553 widget_class->motion_notify_event = gtk_clist_motion;
554 widget_class->expose_event = gtk_clist_expose;
555 widget_class->size_request = gtk_clist_size_request;
556 widget_class->size_allocate = gtk_clist_size_allocate;
557 widget_class->key_press_event = gtk_clist_key_press;
558 widget_class->focus_in_event = gtk_clist_focus_in;
559 widget_class->focus_out_event = gtk_clist_focus_out;
560 widget_class->draw_focus = gtk_clist_draw_focus;
561 widget_class->style_set = gtk_clist_style_set;
562 widget_class->parent_set = gtk_clist_parent_set;
564 /* container_class->add = NULL; use the default GtkContainerClass warning */
565 /* container_class->remove=NULL; use the default GtkContainerClass warning */
567 container_class->forall = gtk_clist_forall;
568 container_class->focus = gtk_clist_focus;
569 container_class->set_focus_child = gtk_clist_set_focus_child;
571 klass->select_row = real_select_row;
572 klass->unselect_row = real_unselect_row;
573 klass->undo_selection = real_undo_selection;
574 klass->resync_selection = resync_selection;
575 klass->selection_find = selection_find;
576 klass->click_column = NULL;
577 klass->resize_column = real_resize_column;
578 klass->draw_row = draw_row;
579 klass->insert_row = real_insert_row;
580 klass->remove_row = real_remove_row;
581 klass->clear = real_clear;
582 klass->sort_list = real_sort_list;
583 klass->select_all = real_select_all;
584 klass->unselect_all = real_unselect_all;
585 klass->fake_unselect_all = fake_unselect_all;
586 klass->scroll_horizontal = scroll_horizontal;
587 klass->scroll_vertical = scroll_vertical;
588 klass->extend_selection = extend_selection;
589 klass->toggle_focus_row = toggle_focus_row;
590 klass->toggle_add_mode = toggle_add_mode;
591 klass->start_selection = start_selection;
592 klass->end_selection = end_selection;
593 klass->abort_column_resize = abort_column_resize;
594 klass->set_cell_contents = set_cell_contents;
595 klass->cell_size_request = cell_size_request;
598 GtkBindingSet *binding_set;
600 binding_set = gtk_binding_set_by_class (klass);
601 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
602 "scroll_vertical", 2,
603 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
604 GTK_TYPE_FLOAT, 0.0);
605 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
606 "scroll_vertical", 2,
607 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
608 GTK_TYPE_FLOAT, 0.0);
609 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
610 "scroll_vertical", 2,
611 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
612 GTK_TYPE_FLOAT, 0.0);
613 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
614 "scroll_vertical", 2,
615 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
616 GTK_TYPE_FLOAT, 0.0);
617 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
618 "scroll_vertical", 2,
619 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
620 GTK_TYPE_FLOAT, 0.0);
621 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
622 "scroll_vertical", 2,
623 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
624 GTK_TYPE_FLOAT, 1.0);
626 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
627 "extend_selection", 3,
628 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
629 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
630 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
631 "extend_selection", 3,
632 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
633 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
634 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
635 "extend_selection", 3,
636 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
637 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
638 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
639 "extend_selection", 3,
640 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
641 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
642 gtk_binding_entry_add_signal (binding_set, GDK_Home,
643 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
644 "extend_selection", 3,
645 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
646 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
647 gtk_binding_entry_add_signal (binding_set, GDK_End,
648 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
649 "extend_selection", 3,
650 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
651 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
653 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
654 "scroll_horizontal", 2,
655 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
656 GTK_TYPE_FLOAT, 0.0);
657 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
658 "scroll_horizontal", 2,
659 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
660 GTK_TYPE_FLOAT, 0.0);
661 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
662 "scroll_horizontal", 2,
663 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
664 GTK_TYPE_FLOAT, 0.0);
665 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
666 "scroll_horizontal", 2,
667 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
668 GTK_TYPE_FLOAT, 1.0);
670 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
671 "undo_selection", 0);
672 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
673 "abort_column_resize", 0);
674 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
675 "toggle_focus_row", 0);
676 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
677 "toggle_add_mode", 0);
678 gtk_binding_entry_add_signal (binding_set, '/', GDK_CONTROL_MASK,
680 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
682 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
683 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
685 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
686 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
688 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
689 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
692 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
693 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
700 GtkBindingSet *binding_set;
702 binding_set = gtk_binding_set_by_class (klass);
703 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
704 "scroll_vertical", 2,
705 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
706 GTK_TYPE_FLOAT, 0.0);
707 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
708 "scroll_vertical", 2,
709 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
710 GTK_TYPE_FLOAT, 0.0);
711 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
712 "scroll_vertical", 2,
713 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
714 GTK_TYPE_FLOAT, 0.0);
715 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
716 "scroll_vertical", 2,
717 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
718 GTK_TYPE_FLOAT, 0.0);
719 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
720 "scroll_vertical", 2,
721 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
722 GTK_TYPE_FLOAT, 0.0);
723 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
724 "scroll_vertical", 2,
725 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
728 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
729 "extend_selection", 3,
730 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
731 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
732 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
733 "extend_selection", 3,
734 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
735 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
736 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
737 "extend_selection", 3,
738 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
739 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
740 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
741 "extend_selection", 3,
742 GTK_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
743 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
744 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
745 "extend_selection", 3,
746 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
747 GTK_TYPE_FLOAT, 0.0, GTK_TYPE_BOOL, TRUE);
748 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
749 "extend_selection", 3,
750 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
751 GTK_TYPE_FLOAT, 1.0, GTK_TYPE_BOOL, TRUE);
753 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
754 "scroll_horizontal", 2,
755 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
756 GTK_TYPE_FLOAT, 0.0);
757 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
758 "scroll_horizontal", 2,
759 GTK_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
760 GTK_TYPE_FLOAT, 0.0);
761 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
762 "scroll_horizontal", 2,
763 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
764 GTK_TYPE_FLOAT, 0.0);
765 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
766 "scroll_horizontal", 2,
767 GTK_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
768 GTK_TYPE_FLOAT, 0.0);
769 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
770 "scroll_horizontal", 2,
771 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
772 GTK_TYPE_FLOAT, 0.0);
773 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
774 "sroll_horizontal", 2,
775 GTK_TYPE_ENUM, GTK_SCROLL_JUMP,
776 GTK_TYPE_FLOAT, 1.0);
778 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
779 "undo_selection", 0);
780 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
781 "abort_column_resize", 0);
782 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
783 "toggle_focus_row", 0);
784 gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
785 "toggle_add_mode", 0);
786 gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0,
788 gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0,
790 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
797 gtk_clist_set_arg (GtkObject *object,
802 GtkAdjustment *adjustment;
804 clist = GTK_CLIST (object);
808 case ARG_HADJUSTMENT:
809 adjustment = GTK_VALUE_POINTER (*arg);
810 gtk_clist_set_hadjustment (clist, adjustment);
812 case ARG_VADJUSTMENT:
813 adjustment = GTK_VALUE_POINTER (*arg);
814 gtk_clist_set_vadjustment (clist, adjustment);
822 gtk_clist_get_arg (GtkObject *object,
828 clist = GTK_CLIST (object);
832 case ARG_HADJUSTMENT:
833 GTK_VALUE_POINTER (*arg) = clist->hadjustment;
835 case ARG_VADJUSTMENT:
836 GTK_VALUE_POINTER (*arg) = clist->vadjustment;
839 arg->type = GTK_TYPE_INVALID;
845 gtk_clist_init (GtkCList *clist)
849 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
850 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
852 clist->row_mem_chunk = NULL;
853 clist->cell_mem_chunk = NULL;
856 clist->row_center_offset = 0;
857 clist->row_height = 0;
858 clist->row_list = NULL;
859 clist->row_list_end = NULL;
863 clist->title_window = NULL;
864 clist->column_title_area.x = 0;
865 clist->column_title_area.y = 0;
866 clist->column_title_area.width = 1;
867 clist->column_title_area.height = 1;
869 clist->clist_window = NULL;
870 clist->clist_window_width = 1;
871 clist->clist_window_height = 1;
876 clist->shadow_type = GTK_SHADOW_IN;
877 clist->vadjustment = NULL;
878 clist->hadjustment = NULL;
880 clist->cursor_drag = NULL;
881 clist->xor_gc = NULL;
886 clist->selection_mode = GTK_SELECTION_SINGLE;
887 clist->selection = NULL;
888 clist->selection_end = NULL;
889 clist->undo_selection = NULL;
890 clist->undo_unselection = NULL;
892 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
893 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
894 clist->focus_row = -1;
895 clist->undo_anchor = -1;
898 clist->anchor_state = GTK_STATE_SELECTED;
899 clist->drag_pos = -1;
903 clist->compare = default_compare;
904 clist->sort_type = GTK_SORT_ASCENDING;
905 clist->sort_column = 0;
910 gtk_clist_construct (GtkCList *clist,
916 g_return_if_fail (clist != NULL);
917 g_return_if_fail (GTK_IS_CLIST (clist));
918 g_return_if_fail (GTK_CLIST_CONSTRUCTED (clist) == FALSE);
920 GTK_CLIST_SET_FLAG (clist, CLIST_CONSTRUCTED);
922 /* initalize memory chunks, if this has not been done by any
923 * possibly derived widget
925 if (!clist->row_mem_chunk)
926 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
927 sizeof (GtkCListRow),
928 sizeof (GtkCListRow) *
932 if (!clist->cell_mem_chunk)
933 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
934 sizeof (GtkCell) * columns,
935 sizeof (GtkCell) * columns *
939 /* set number of columns, allocate memory */
940 clist->columns = columns;
941 clist->column = columns_new (clist);
943 /* there needs to be at least one column button
944 * because there is alot of code that will break if it
946 column_button_create (clist, 0);
950 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
951 for (i = 0; i < columns; i++)
952 gtk_clist_set_column_title (clist, i, titles[i]);
956 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
960 /* GTKCLIST PUBLIC INTERFACE
962 * gtk_clist_new_with_titles
963 * gtk_clist_set_hadjustment
964 * gtk_clist_set_vadjustment
965 * gtk_clist_get_hadjustment
966 * gtk_clist_get_vadjustment
967 * gtk_clist_set_shadow_type
968 * gtk_clist_set_border *** deprecated function ***
969 * gtk_clist_set_selection_mode
970 * gtk_clist_set_policy
975 gtk_clist_new (gint columns)
977 return gtk_clist_new_with_titles (columns, NULL);
981 gtk_clist_new_with_titles (gint columns,
986 widget = gtk_type_new (GTK_TYPE_CLIST);
987 gtk_clist_construct (GTK_CLIST (widget), columns, titles);
992 gtk_clist_set_hadjustment (GtkCList *clist,
993 GtkAdjustment *adjustment)
995 GtkAdjustment *old_adjustment;
997 g_return_if_fail (clist != NULL);
998 g_return_if_fail (GTK_IS_CLIST (clist));
1000 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1002 if (clist->hadjustment == adjustment)
1005 old_adjustment = clist->hadjustment;
1007 if (clist->hadjustment)
1009 gtk_signal_disconnect_by_data (GTK_OBJECT (clist->hadjustment), clist);
1010 gtk_object_unref (GTK_OBJECT (clist->hadjustment));
1013 clist->hadjustment = adjustment;
1015 if (clist->hadjustment)
1017 gtk_object_ref (GTK_OBJECT (clist->hadjustment));
1018 gtk_object_sink (GTK_OBJECT (clist->hadjustment));
1020 gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "changed",
1021 (GtkSignalFunc) hadjustment_changed,
1023 gtk_signal_connect (GTK_OBJECT (clist->hadjustment), "value_changed",
1024 (GtkSignalFunc) hadjustment_value_changed,
1028 if (!clist->hadjustment || !old_adjustment)
1029 gtk_widget_queue_resize (GTK_WIDGET (clist));
1033 gtk_clist_get_hadjustment (GtkCList *clist)
1035 g_return_val_if_fail (clist != NULL, NULL);
1036 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1038 return clist->hadjustment;
1042 gtk_clist_set_vadjustment (GtkCList *clist,
1043 GtkAdjustment *adjustment)
1045 GtkAdjustment *old_adjustment;
1047 g_return_if_fail (clist != NULL);
1048 g_return_if_fail (GTK_IS_CLIST (clist));
1050 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1052 if (clist->vadjustment == adjustment)
1055 old_adjustment = clist->vadjustment;
1057 if (clist->vadjustment)
1059 gtk_signal_disconnect_by_data (GTK_OBJECT (clist->vadjustment), clist);
1060 gtk_object_unref (GTK_OBJECT (clist->vadjustment));
1063 clist->vadjustment = adjustment;
1065 if (clist->vadjustment)
1067 gtk_object_ref (GTK_OBJECT (clist->vadjustment));
1068 gtk_object_sink (GTK_OBJECT (clist->vadjustment));
1070 gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "changed",
1071 (GtkSignalFunc) vadjustment_changed,
1073 gtk_signal_connect (GTK_OBJECT (clist->vadjustment), "value_changed",
1074 (GtkSignalFunc) vadjustment_value_changed,
1078 if (!clist->vadjustment || !old_adjustment)
1079 gtk_widget_queue_resize (GTK_WIDGET (clist));
1083 gtk_clist_get_vadjustment (GtkCList *clist)
1085 g_return_val_if_fail (clist != NULL, NULL);
1086 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1088 return clist->vadjustment;
1092 gtk_clist_set_shadow_type (GtkCList *clist,
1095 g_return_if_fail (clist != NULL);
1096 g_return_if_fail (GTK_IS_CLIST (clist));
1098 clist->shadow_type = type;
1100 if (GTK_WIDGET_VISIBLE (clist))
1101 gtk_widget_queue_resize (GTK_WIDGET (clist));
1104 /* deprecated function, use gtk_clist_set_shadow_type instead. */
1106 gtk_clist_set_border (GtkCList *clist,
1107 GtkShadowType border)
1109 gtk_clist_set_shadow_type (clist, border);
1113 gtk_clist_set_selection_mode (GtkCList *clist,
1114 GtkSelectionMode mode)
1116 g_return_if_fail (clist != NULL);
1117 g_return_if_fail (GTK_IS_CLIST (clist));
1119 if (mode == clist->selection_mode)
1122 clist->selection_mode = mode;
1124 clist->anchor_state = GTK_STATE_SELECTED;
1125 clist->drag_pos = -1;
1126 clist->undo_anchor = clist->focus_row;
1128 g_list_free (clist->undo_selection);
1129 g_list_free (clist->undo_unselection);
1130 clist->undo_selection = NULL;
1131 clist->undo_unselection = NULL;
1135 case GTK_SELECTION_MULTIPLE:
1136 case GTK_SELECTION_EXTENDED:
1138 case GTK_SELECTION_BROWSE:
1139 case GTK_SELECTION_SINGLE:
1140 gtk_clist_unselect_all (clist);
1146 gtk_clist_set_policy (GtkCList *clist,
1147 GtkPolicyType vscrollbar_policy,
1148 GtkPolicyType hscrollbar_policy)
1150 g_return_if_fail (clist != NULL);
1151 g_return_if_fail (GTK_IS_CLIST (clist));
1155 gtk_clist_freeze (GtkCList *clist)
1157 g_return_if_fail (clist != NULL);
1158 g_return_if_fail (GTK_IS_CLIST (clist));
1160 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
1164 gtk_clist_thaw (GtkCList *clist)
1166 g_return_if_fail (clist != NULL);
1167 g_return_if_fail (GTK_IS_CLIST (clist));
1169 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
1170 adjust_adjustments (clist, FALSE);
1171 draw_rows (clist, NULL);
1174 /* PUBLIC COLUMN FUNCTIONS
1175 * gtk_clist_column_titles_show
1176 * gtk_clist_column_titles_hide
1177 * gtk_clist_column_title_active
1178 * gtk_clist_column_title_passive
1179 * gtk_clist_column_titles_active
1180 * gtk_clist_column_titles_passive
1181 * gtk_clist_set_column_title
1182 * gtk_clist_set_column_widget
1183 * gtk_clist_set_column_justification
1184 * gtk_clist_set_column_visibility
1185 * gtk_clist_set_column_resizeable
1186 * gtk_clist_set_column_auto_resize
1187 * gtk_clist_optimal_column_width
1188 * gtk_clist_set_column_width
1189 * gtk_clist_set_column_min_width
1190 * gtk_clist_set_column_max_width
1193 gtk_clist_column_titles_show (GtkCList *clist)
1195 g_return_if_fail (clist != NULL);
1196 g_return_if_fail (GTK_IS_CLIST (clist));
1198 if (!GTK_CLIST_SHOW_TITLES (clist))
1200 GTK_CLIST_SET_FLAG (clist, CLIST_SHOW_TITLES);
1201 if (clist->title_window)
1202 gdk_window_show (clist->title_window);
1203 gtk_widget_queue_resize (GTK_WIDGET (clist));
1208 gtk_clist_column_titles_hide (GtkCList *clist)
1210 g_return_if_fail (clist != NULL);
1211 g_return_if_fail (GTK_IS_CLIST (clist));
1213 if (GTK_CLIST_SHOW_TITLES (clist))
1215 GTK_CLIST_UNSET_FLAG (clist, CLIST_SHOW_TITLES);
1216 if (clist->title_window)
1217 gdk_window_hide (clist->title_window);
1218 gtk_widget_queue_resize (GTK_WIDGET (clist));
1223 gtk_clist_column_title_active (GtkCList *clist,
1226 g_return_if_fail (clist != NULL);
1227 g_return_if_fail (GTK_IS_CLIST (clist));
1229 if (column < 0 || column >= clist->columns)
1232 if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1233 !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1235 GTK_WIDGET_SET_FLAGS (clist->column[column].button,
1236 GTK_SENSITIVE | GTK_CAN_FOCUS);
1237 if (GTK_WIDGET_VISIBLE (clist))
1238 gtk_widget_queue_draw (clist->column[column].button);
1243 gtk_clist_column_title_passive (GtkCList *clist,
1246 g_return_if_fail (clist != NULL);
1247 g_return_if_fail (GTK_IS_CLIST (clist));
1249 if (column < 0 || column >= clist->columns)
1252 if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
1253 GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
1255 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button,
1256 GTK_SENSITIVE | GTK_CAN_FOCUS);
1257 if (GTK_WIDGET_VISIBLE (clist))
1258 gtk_widget_queue_draw (clist->column[column].button);
1263 gtk_clist_column_titles_active (GtkCList *clist)
1267 g_return_if_fail (clist != NULL);
1268 g_return_if_fail (GTK_IS_CLIST (clist));
1270 for (i = 0; i < clist->columns; i++)
1271 if (clist->column[i].button)
1272 gtk_clist_column_title_active (clist, i);
1276 gtk_clist_column_titles_passive (GtkCList *clist)
1280 g_return_if_fail (clist != NULL);
1281 g_return_if_fail (GTK_IS_CLIST (clist));
1283 for (i = 0; i < clist->columns; i++)
1284 if (clist->column[i].button)
1285 gtk_clist_column_title_passive (clist, i);
1289 gtk_clist_set_column_title (GtkCList *clist,
1293 gint new_button = 0;
1294 GtkWidget *old_widget;
1295 GtkWidget *alignment = NULL;
1298 g_return_if_fail (clist != NULL);
1299 g_return_if_fail (GTK_IS_CLIST (clist));
1301 if (column < 0 || column >= clist->columns)
1304 /* if the column button doesn't currently exist,
1305 * it has to be created first */
1306 if (!clist->column[column].button)
1308 column_button_create (clist, column);
1312 column_title_new (clist, column, title);
1314 /* remove and destroy the old widget */
1315 old_widget = GTK_BIN (clist->column[column].button)->child;
1317 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1319 /* create new alignment based no column justification */
1320 switch (clist->column[column].justification)
1322 case GTK_JUSTIFY_LEFT:
1323 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1326 case GTK_JUSTIFY_RIGHT:
1327 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1330 case GTK_JUSTIFY_CENTER:
1331 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1334 case GTK_JUSTIFY_FILL:
1335 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1339 label = gtk_label_new (clist->column[column].title);
1340 gtk_container_add (GTK_CONTAINER (alignment), label);
1341 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1342 gtk_widget_show (label);
1343 gtk_widget_show (alignment);
1345 /* if this button didn't previously exist, then the
1346 * column button positions have to be re-computed */
1347 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1348 size_allocate_title_buttons (clist);
1352 gtk_clist_set_column_widget (GtkCList *clist,
1356 gint new_button = 0;
1357 GtkWidget *old_widget;
1359 g_return_if_fail (clist != NULL);
1360 g_return_if_fail (GTK_IS_CLIST (clist));
1362 if (column < 0 || column >= clist->columns)
1365 /* if the column button doesn't currently exist,
1366 * it has to be created first */
1367 if (!clist->column[column].button)
1369 column_button_create (clist, column);
1373 column_title_new (clist, column, NULL);
1375 /* remove and destroy the old widget */
1376 old_widget = GTK_BIN (clist->column[column].button)->child;
1378 gtk_container_remove (GTK_CONTAINER (clist->column[column].button),
1381 /* add and show the widget */
1384 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1385 gtk_widget_show (widget);
1388 /* if this button didn't previously exist, then the
1389 * column button positions have to be re-computed */
1390 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1391 size_allocate_title_buttons (clist);
1395 gtk_clist_set_column_justification (GtkCList *clist,
1397 GtkJustification justification)
1399 GtkWidget *alignment;
1401 g_return_if_fail (clist != NULL);
1402 g_return_if_fail (GTK_IS_CLIST (clist));
1404 if (column < 0 || column >= clist->columns)
1407 clist->column[column].justification = justification;
1409 /* change the alinment of the button title if it's not a
1411 if (clist->column[column].title)
1413 alignment = GTK_BIN (clist->column[column].button)->child;
1415 switch (clist->column[column].justification)
1417 case GTK_JUSTIFY_LEFT:
1418 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1421 case GTK_JUSTIFY_RIGHT:
1422 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1425 case GTK_JUSTIFY_CENTER:
1426 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1429 case GTK_JUSTIFY_FILL:
1430 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1438 if (!GTK_CLIST_FROZEN (clist))
1439 draw_rows (clist, NULL);
1443 gtk_clist_set_column_visibility (GtkCList *clist,
1447 g_return_if_fail (clist != NULL);
1448 g_return_if_fail (GTK_IS_CLIST (clist));
1450 if (column < 0 || column >= clist->columns)
1452 if (clist->column[column].visible == visible)
1455 /* don't hide last visible column */
1459 gint vis_columns = 0;
1461 for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
1462 if (clist->column[i].visible)
1465 if (vis_columns < 2)
1469 clist->column[column].visible = visible;
1471 gtk_widget_show (clist->column[column].button);
1473 gtk_widget_hide (clist->column[column].button);
1477 gtk_clist_set_column_resizeable (GtkCList *clist,
1481 g_return_if_fail (clist != NULL);
1482 g_return_if_fail (GTK_IS_CLIST (clist));
1484 if (column < 0 || column >= clist->columns)
1486 if (clist->column[column].resizeable == resizeable)
1489 clist->column[column].resizeable = resizeable;
1491 clist->column[column].auto_resize = FALSE;
1493 if (GTK_WIDGET_VISIBLE (clist))
1494 size_allocate_title_buttons (clist);
1498 gtk_clist_set_column_auto_resize (GtkCList *clist,
1500 gboolean auto_resize)
1502 g_return_if_fail (clist != NULL);
1503 g_return_if_fail (GTK_IS_CLIST (clist));
1505 if (column < 0 || column >= clist->columns)
1507 if (clist->column[column].auto_resize == auto_resize)
1510 clist->column[column].auto_resize = auto_resize;
1513 clist->column[column].resizeable = FALSE;
1514 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1518 width = gtk_clist_optimal_column_width (clist, column);
1519 gtk_clist_set_column_width (clist, column, width);
1523 if (GTK_WIDGET_VISIBLE (clist))
1524 size_allocate_title_buttons (clist);
1528 gtk_clist_optimal_column_width (GtkCList *clist,
1531 GtkRequisition requisition;
1535 g_return_val_if_fail (clist != NULL, 0);
1536 g_return_val_if_fail (GTK_CLIST (clist), 0);
1538 if (column < 0 || column > clist->columns)
1541 for (list = clist->row_list; list; list = list->next)
1543 GTK_CLIST_CLASS_FW (clist)->cell_size_request
1544 (clist, GTK_CLIST_ROW (list), column, &requisition);
1545 width = MAX (width, requisition.width);
1552 gtk_clist_set_column_width (GtkCList *clist,
1556 g_return_if_fail (clist != NULL);
1557 g_return_if_fail (GTK_IS_CLIST (clist));
1559 if (column < 0 || column >= clist->columns)
1562 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN],
1567 gtk_clist_set_column_min_width (GtkCList *clist,
1571 g_return_if_fail (clist != NULL);
1572 g_return_if_fail (GTK_IS_CLIST (clist));
1574 if (column < 0 || column >= clist->columns)
1576 if (clist->column[column].min_width == min_width)
1579 if (clist->column[column].max_width >= 0 &&
1580 clist->column[column].max_width < min_width)
1581 clist->column[column].min_width = clist->column[column].max_width;
1583 clist->column[column].min_width = min_width;
1585 if (clist->column[column].area.width < clist->column[column].min_width)
1586 gtk_clist_set_column_width (clist, column,clist->column[column].min_width);
1590 gtk_clist_set_column_max_width (GtkCList *clist,
1594 g_return_if_fail (clist != NULL);
1595 g_return_if_fail (GTK_IS_CLIST (clist));
1597 if (column < 0 || column >= clist->columns)
1599 if (clist->column[column].max_width == max_width)
1602 if (clist->column[column].min_width >= 0 && max_width >= 0 &&
1603 clist->column[column].min_width > max_width)
1604 clist->column[column].max_width = clist->column[column].min_width;
1606 clist->column[column].max_width = max_width;
1608 if (clist->column[column].area.width > clist->column[column].max_width)
1609 gtk_clist_set_column_width (clist, column,clist->column[column].max_width);
1612 /* PRIVATE COLUMN FUNCTIONS
1613 * column_auto_resize
1614 * real_resize_column
1615 * abort_column_resize
1616 * size_allocate_title_buttons
1617 * size_allocate_columns
1618 * list_requisition_width
1620 * column_button_create
1621 * column_button_clicked
1624 column_auto_resize (GtkCList *clist,
1625 GtkCListRow *clist_row,
1629 /* resize column if needed for auto_resize */
1630 GtkRequisition requisition;
1632 if (!clist->column[column].auto_resize ||
1633 GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1636 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
1637 column, &requisition);
1639 if (requisition.width > clist->column[column].width)
1641 if (clist->column[column].max_width < 0)
1642 gtk_clist_set_column_width (clist, column, requisition.width);
1643 else if (clist->column[column].max_width >
1644 clist->column[column].width)
1645 gtk_clist_set_column_width (clist, column,
1646 MIN (requisition.width,
1647 clist->column[column].max_width));
1649 else if (requisition.width < old_width &&
1650 old_width == clist->column[column].width)
1655 /* run a "gtk_clist_optimal_column_width" but break, if
1656 * the column doesn't shrink */
1658 for (list = clist->row_list; list; list = list->next)
1660 GTK_CLIST_CLASS_FW (clist)->cell_size_request
1661 (clist, GTK_CLIST_ROW (list), column, &requisition);
1662 new_width = MAX (new_width, requisition.width);
1663 if (new_width == clist->column[column].width)
1666 if (new_width < clist->column[column].width)
1667 gtk_clist_set_column_width
1668 (clist, column, MAX (new_width, clist->column[column].min_width));
1673 real_resize_column (GtkCList *clist,
1677 g_return_if_fail (clist != NULL);
1678 g_return_if_fail (GTK_IS_CLIST (clist));
1680 if (column < 0 || column >= clist->columns)
1683 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1684 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1685 if (clist->column[column].max_width >= 0 &&
1686 width > clist->column[column].max_width)
1687 width = clist->column[column].max_width;
1689 clist->column[column].width = width;
1690 clist->column[column].width_set = TRUE;
1692 /* FIXME: this is quite expensive to do if the widget hasn't
1693 * been size_allocated yet, and pointless. Should
1696 size_allocate_columns (clist);
1697 size_allocate_title_buttons (clist);
1699 if (!GTK_CLIST_FROZEN (clist))
1701 adjust_adjustments (clist, FALSE);
1702 draw_rows (clist, NULL);
1707 abort_column_resize (GtkCList *clist)
1709 g_return_if_fail (clist != NULL);
1710 g_return_if_fail (GTK_IS_CLIST (clist));
1712 if (!GTK_CLIST_IN_DRAG (clist))
1715 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
1716 gtk_grab_remove (GTK_WIDGET (clist));
1717 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1718 clist->drag_pos = -1;
1720 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
1721 draw_xor_line (clist);
1723 if (GTK_CLIST_ADD_MODE (clist))
1725 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
1726 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
1731 size_allocate_title_buttons (GtkCList *clist)
1733 GtkAllocation button_allocation;
1735 gint last_button = 0;
1738 if (!GTK_WIDGET_REALIZED (clist))
1741 button_allocation.x = clist->hoffset;
1742 button_allocation.y = 0;
1743 button_allocation.width = 0;
1744 button_allocation.height = clist->column_title_area.height;
1746 /* find last visible column */
1747 for (last_column = clist->columns - 1; last_column >= 0; last_column--)
1748 if (clist->column[last_column].visible)
1751 for (i = 0; i < last_column; i++)
1753 if (!clist->column[i].visible)
1755 last_button = i + 1;
1756 gdk_window_hide (clist->column[i].window);
1760 button_allocation.width += (clist->column[i].area.width +
1761 CELL_SPACING + 2 * COLUMN_INSET);
1763 if (!clist->column[i + 1].button)
1765 gdk_window_hide (clist->column[i].window);
1769 gtk_widget_size_allocate (clist->column[last_button].button,
1770 &button_allocation);
1771 button_allocation.x += button_allocation.width;
1772 button_allocation.width = 0;
1774 if (clist->column[last_button].resizeable)
1776 gdk_window_show (clist->column[last_button].window);
1777 gdk_window_move_resize (clist->column[last_button].window,
1778 button_allocation.x - (DRAG_WIDTH / 2),
1780 clist->column_title_area.height);
1783 gdk_window_hide (clist->column[last_button].window);
1785 last_button = i + 1;
1788 button_allocation.width += (clist->column[last_column].area.width +
1789 2 * (CELL_SPACING + COLUMN_INSET));
1790 gtk_widget_size_allocate (clist->column[last_button].button,
1791 &button_allocation);
1793 if (clist->column[last_button].resizeable)
1795 button_allocation.x += button_allocation.width;
1797 gdk_window_show (clist->column[last_button].window);
1798 gdk_window_move_resize (clist->column[last_button].window,
1799 button_allocation.x - (DRAG_WIDTH / 2),
1800 0, DRAG_WIDTH, clist->column_title_area.height);
1803 gdk_window_hide (clist->column[last_button].window);
1807 size_allocate_columns (GtkCList *clist)
1809 gint xoffset = CELL_SPACING + COLUMN_INSET;
1813 /* find last visible column and calculate correct column width */
1814 for (last_column = clist->columns - 1;
1815 last_column >= 0 && !clist->column[last_column].visible; last_column--);
1817 if (last_column < 0)
1820 for (i = 0; i <= last_column; i++)
1822 if (!clist->column[i].visible)
1824 clist->column[i].area.x = xoffset;
1825 if (clist->column[i].width_set)
1827 clist->column[i].area.width = clist->column[i].width;
1828 xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET);
1830 else if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[i].button)
1832 clist->column[i].area.width =
1833 clist->column[i].button->requisition.width -
1834 (CELL_SPACING + (2 * COLUMN_INSET));
1835 xoffset += clist->column[i].button->requisition.width;
1839 clist->column[last_column].area.width = clist->column[last_column].area.width
1840 + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset);
1844 list_requisition_width (GtkCList *clist)
1846 gint width = CELL_SPACING;
1849 for (i = clist->columns - 1; i >= 0 && !clist->column[i].visible; i--)
1854 if (!clist->column[i].visible)
1857 if (clist->column[i].width_set)
1858 width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
1859 else if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[i].button)
1860 width += clist->column[i].button->requisition.width;
1866 /* this function returns the new width of the column being resized given
1867 * the column and x position of the cursor; the x cursor position is passed
1868 * in as a pointer and automagicly corrected if it's beyond min/max limits */
1870 new_column_width (GtkCList *clist,
1874 gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness;
1879 /* first translate the x position from widget->window
1880 * to clist->clist_window */
1881 cx = *x - xthickness;
1883 /* calculate new column width making sure it doesn't end up
1884 * less than the minimum width */
1885 dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
1886 (column < clist->columns - 1) * CELL_SPACING);
1889 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1891 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1893 *x = cx + xthickness;
1895 else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
1896 width > clist->column[column].max_width)
1898 width = clist->column[column].max_width;
1899 cx = dx + clist->column[column].max_width;
1900 *x = cx + xthickness;
1903 if (cx < 0 || cx > clist->clist_window_width)
1910 column_button_create (GtkCList *clist,
1915 button = clist->column[column].button = gtk_button_new ();
1917 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
1918 gtk_widget_set_parent_window (clist->column[column].button,
1919 clist->title_window);
1920 gtk_widget_set_parent (button, GTK_WIDGET (clist));
1922 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1923 (GtkSignalFunc) column_button_clicked,
1926 gtk_widget_show (button);
1930 column_button_clicked (GtkWidget *widget,
1936 g_return_if_fail (widget != NULL);
1937 g_return_if_fail (GTK_IS_CLIST (data));
1939 clist = GTK_CLIST (data);
1941 /* find the column who's button was pressed */
1942 for (i = 0; i < clist->columns; i++)
1943 if (clist->column[i].button == widget)
1946 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
1950 gtk_clist_set_row_height (GtkCList *clist,
1953 g_return_if_fail (clist != NULL);
1954 g_return_if_fail (GTK_IS_CLIST (clist));
1957 clist->row_height = height;
1961 GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET);
1963 if (GTK_WIDGET_REALIZED (clist))
1967 font = GTK_WIDGET (clist)->style->font;
1968 clist->row_center_offset = (((height + font->ascent - font->descent - 1)
1972 if (!GTK_CLIST_FROZEN (clist))
1974 adjust_adjustments (clist, FALSE);
1975 draw_rows (clist, NULL);
1980 gtk_clist_moveto (GtkCList *clist,
1986 g_return_if_fail (clist != NULL);
1987 g_return_if_fail (GTK_IS_CLIST (clist));
1989 if (row < -1 || row >= clist->rows)
1991 if (column < -1 || column >= clist->columns)
1994 row_align = CLAMP (row_align, 0, 1);
1995 col_align = CLAMP (col_align, 0, 1);
1997 /* adjust horizontal scrollbar */
1998 if (clist->hadjustment && column >= 0)
2002 x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
2003 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
2004 CELL_SPACING - clist->column[column].area.width)));
2006 gtk_adjustment_set_value (clist->hadjustment, 0.0);
2007 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
2008 gtk_adjustment_set_value
2009 (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width);
2011 gtk_adjustment_set_value (clist->hadjustment, x);
2014 /* adjust vertical scrollbar */
2015 if (clist->vadjustment && row >= 0)
2016 move_vertical (clist, row, row_align);
2019 /* PUBLIC CELL FUNCTIONS
2020 * gtk_clist_get_cell_type
2021 * gtk_clist_set_text
2022 * gtk_clist_get_text
2023 * gtk_clist_set_pixmap
2024 * gtk_clist_get_pixmap
2025 * gtk_clist_set_pixtext
2026 * gtk_clist_get_pixtext
2027 * gtk_clist_set_shift
2030 gtk_clist_get_cell_type (GtkCList *clist,
2034 GtkCListRow *clist_row;
2036 g_return_val_if_fail (clist != NULL, -1);
2037 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2039 if (row < 0 || row >= clist->rows)
2041 if (column < 0 || column >= clist->columns)
2044 clist_row = (g_list_nth (clist->row_list, row))->data;
2046 return clist_row->cell[column].type;
2050 gtk_clist_set_text (GtkCList *clist,
2055 GtkCListRow *clist_row;
2057 g_return_if_fail (clist != NULL);
2058 g_return_if_fail (GTK_IS_CLIST (clist));
2060 if (row < 0 || row >= clist->rows)
2062 if (column < 0 || column >= clist->columns)
2065 clist_row = (g_list_nth (clist->row_list, row))->data;
2067 /* if text is null, then the cell is empty */
2068 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2069 (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL);
2071 /* redraw the list if it's not frozen */
2072 if (!GTK_CLIST_FROZEN (clist))
2074 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2075 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2080 gtk_clist_get_text (GtkCList *clist,
2085 GtkCListRow *clist_row;
2087 g_return_val_if_fail (clist != NULL, 0);
2088 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2090 if (row < 0 || row >= clist->rows)
2092 if (column < 0 || column >= clist->columns)
2095 clist_row = (g_list_nth (clist->row_list, row))->data;
2097 if (clist_row->cell[column].type != GTK_CELL_TEXT)
2101 *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
2107 gtk_clist_set_pixmap (GtkCList *clist,
2113 GtkCListRow *clist_row;
2115 g_return_if_fail (clist != NULL);
2116 g_return_if_fail (GTK_IS_CLIST (clist));
2118 if (row < 0 || row >= clist->rows)
2120 if (column < 0 || column >= clist->columns)
2123 clist_row = (g_list_nth (clist->row_list, row))->data;
2125 gdk_pixmap_ref (pixmap);
2127 if (mask) gdk_pixmap_ref (mask);
2129 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2130 (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask);
2132 /* redraw the list if it's not frozen */
2133 if (!GTK_CLIST_FROZEN (clist))
2135 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2136 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2141 gtk_clist_get_pixmap (GtkCList *clist,
2147 GtkCListRow *clist_row;
2149 g_return_val_if_fail (clist != NULL, 0);
2150 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2152 if (row < 0 || row >= clist->rows)
2154 if (column < 0 || column >= clist->columns)
2157 clist_row = (g_list_nth (clist->row_list, row))->data;
2159 if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
2164 *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
2165 /* mask can be NULL */
2166 *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
2173 gtk_clist_set_pixtext (GtkCList *clist,
2181 GtkCListRow *clist_row;
2183 g_return_if_fail (clist != NULL);
2184 g_return_if_fail (GTK_IS_CLIST (clist));
2186 if (row < 0 || row >= clist->rows)
2188 if (column < 0 || column >= clist->columns)
2191 clist_row = (g_list_nth (clist->row_list, row))->data;
2193 gdk_pixmap_ref (pixmap);
2194 if (mask) gdk_pixmap_ref (mask);
2195 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2196 (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask);
2198 /* redraw the list if it's not frozen */
2199 if (!GTK_CLIST_FROZEN (clist))
2201 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2202 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2207 gtk_clist_get_pixtext (GtkCList *clist,
2215 GtkCListRow *clist_row;
2217 g_return_val_if_fail (clist != NULL, 0);
2218 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2220 if (row < 0 || row >= clist->rows)
2222 if (column < 0 || column >= clist->columns)
2225 clist_row = (g_list_nth (clist->row_list, row))->data;
2227 if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
2231 *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
2233 *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
2235 *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
2237 /* mask can be NULL */
2238 *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
2244 gtk_clist_set_shift (GtkCList *clist,
2250 GtkRequisition requisition;
2251 GtkCListRow *clist_row;
2253 g_return_if_fail (clist != NULL);
2254 g_return_if_fail (GTK_IS_CLIST (clist));
2256 if (row < 0 || row >= clist->rows)
2258 if (column < 0 || column >= clist->columns)
2261 clist_row = (g_list_nth (clist->row_list, row))->data;
2263 if (clist->column[column].auto_resize &&
2264 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2265 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2266 column, &requisition);
2268 clist_row->cell[column].vertical = vertical;
2269 clist_row->cell[column].horizontal = horizontal;
2271 column_auto_resize (clist, clist_row, column, requisition.width);
2273 if (!GTK_CLIST_FROZEN (clist)
2274 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2275 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2278 /* PRIVATE CELL FUNCTIONS
2283 set_cell_contents (GtkCList *clist,
2284 GtkCListRow *clist_row,
2292 GtkRequisition requisition;
2294 g_return_if_fail (clist != NULL);
2295 g_return_if_fail (GTK_IS_CLIST (clist));
2296 g_return_if_fail (clist_row != NULL);
2298 if (clist->column[column].auto_resize &&
2299 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2300 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2301 column, &requisition);
2303 switch (clist_row->cell[column].type)
2305 case GTK_CELL_EMPTY:
2308 g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
2310 case GTK_CELL_PIXMAP:
2311 gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
2312 if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
2313 gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
2315 case GTK_CELL_PIXTEXT:
2316 g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
2317 gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
2318 if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
2319 gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
2321 case GTK_CELL_WIDGET:
2328 clist_row->cell[column].type = GTK_CELL_EMPTY;
2335 clist_row->cell[column].type = GTK_CELL_TEXT;
2336 GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2339 case GTK_CELL_PIXMAP:
2342 clist_row->cell[column].type = GTK_CELL_PIXMAP;
2343 GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
2344 /* We set the mask even if it is NULL */
2345 GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
2348 case GTK_CELL_PIXTEXT:
2351 clist_row->cell[column].type = GTK_CELL_PIXTEXT;
2352 GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2353 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2354 GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
2355 GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
2362 column_auto_resize (clist, clist_row, column, requisition.width);
2366 cell_size_request (GtkCList *clist,
2367 GtkCListRow *clist_row,
2369 GtkRequisition *requisition)
2375 g_return_if_fail (clist != NULL);
2376 g_return_if_fail (GTK_IS_CLIST (clist));
2377 g_return_if_fail (requisition != NULL);
2379 get_cell_style (clist, clist_row, GTK_STATE_PRELIGHT, column, &style,
2382 switch (clist_row->cell[column].type)
2385 requisition->width =
2386 gdk_string_width (style->font,
2387 GTK_CELL_TEXT (clist_row->cell[column])->text);
2388 requisition->height = style->font->ascent + style->font->descent;
2390 case GTK_CELL_PIXTEXT:
2391 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap,
2393 requisition->width = width +
2394 GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing +
2395 gdk_string_width (style->font,
2396 GTK_CELL_TEXT (clist_row->cell[column])->text);
2398 requisition->height = MAX (style->font->ascent + style->font->descent,
2401 case GTK_CELL_PIXMAP:
2402 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap,
2404 requisition->width = width;
2405 requisition->height = height;
2408 requisition->width = 0;
2409 requisition->height = 0;
2413 requisition->width += clist_row->cell[column].horizontal;
2414 requisition->height += clist_row->cell[column].vertical;
2417 /* PUBLIC INSERT/REMOVE ROW FUNCTIONS
2425 gtk_clist_prepend (GtkCList *clist,
2428 g_return_val_if_fail (clist != NULL, -1);
2429 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2430 g_return_val_if_fail (text != NULL, -1);
2432 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text);
2436 gtk_clist_append (GtkCList *clist,
2439 g_return_val_if_fail (clist != NULL, -1);
2440 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2441 g_return_val_if_fail (text != NULL, -1);
2443 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text);
2447 gtk_clist_insert (GtkCList *clist,
2451 g_return_val_if_fail (clist != NULL, -1);
2452 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2453 g_return_val_if_fail (text != NULL, -1);
2455 if (row < 0 || row > clist->rows)
2458 return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text);
2462 gtk_clist_remove (GtkCList *clist,
2465 GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row);
2469 gtk_clist_clear (GtkCList *clist)
2471 g_return_if_fail (clist != NULL);
2472 g_return_if_fail (GTK_IS_CLIST (clist));
2474 GTK_CLIST_CLASS_FW (clist)->clear (clist);
2477 /* PRIVATE INSERT/REMOVE ROW FUNCTIONS
2484 real_insert_row (GtkCList *clist,
2489 GtkCListRow *clist_row;
2491 g_return_val_if_fail (clist != NULL, -1);
2492 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2493 g_return_val_if_fail (text != NULL, -1);
2495 /* return if out of bounds */
2496 if (row < 0 || row > clist->rows)
2499 /* create the row */
2500 clist_row = row_new (clist);
2502 /* set the text in the row's columns */
2503 for (i = 0; i < clist->columns; i++)
2505 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
2506 (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL);
2510 clist->row_list = g_list_append (clist->row_list, clist_row);
2511 clist->row_list_end = clist->row_list;
2515 if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */
2520 work = clist->row_list;
2522 if (clist->sort_type == GTK_SORT_ASCENDING)
2524 while (row < clist->rows &&
2525 clist->compare (clist, clist_row,
2526 GTK_CLIST_ROW (work)) > 0)
2534 while (row < clist->rows &&
2535 clist->compare (clist, clist_row,
2536 GTK_CLIST_ROW (work)) < 0)
2544 /* reset the row end pointer if we're inserting at the end of the list */
2545 if (row == clist->rows)
2546 clist->row_list_end = (g_list_append (clist->row_list_end,
2549 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
2554 if (row < ROW_FROM_YPIXEL (clist, 0))
2555 clist->voffset -= (clist->row_height + CELL_SPACING);
2557 /* syncronize the selection list */
2558 sync_selection (clist, row, SYNC_INSERT);
2560 /* redraw the list if it isn't frozen */
2561 if (!GTK_CLIST_FROZEN (clist))
2563 adjust_adjustments (clist, FALSE);
2565 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2566 draw_rows (clist, NULL);
2573 real_remove_row (GtkCList *clist,
2576 gint was_visible, was_selected;
2578 GtkCListRow *clist_row;
2580 g_return_if_fail (clist != NULL);
2581 g_return_if_fail (GTK_IS_CLIST (clist));
2583 /* return if out of bounds */
2584 if (row < 0 || row > (clist->rows - 1))
2587 was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
2590 /* get the row we're going to delete */
2591 list = g_list_nth (clist->row_list, row);
2592 clist_row = list->data;
2594 /* if we're removing a selected row, we have to make sure
2595 * it's properly unselected, and then sync up the clist->selected
2596 * list to reflect the deincrimented indexies of rows after the
2598 if (clist_row->state == GTK_STATE_SELECTED)
2599 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
2602 /* reset the row end pointer if we're removing at the
2603 * end of the list */
2605 clist->row_list = g_list_remove (clist->row_list, clist_row);
2607 if (row == clist->rows)
2608 clist->row_list_end = list->prev;
2609 /*if (clist->focus_row >=0 &&
2610 (row <= clist->focus_row || clist->focus_row >= clist->rows))
2611 clist->focus_row--;*/
2613 if (row < ROW_FROM_YPIXEL (clist, 0))
2614 clist->voffset += clist->row_height + CELL_SPACING;
2616 sync_selection (clist, row, SYNC_REMOVE);
2618 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
2619 clist->selection_mode == GTK_SELECTION_EXTENDED) && !clist->selection)
2620 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2621 clist->focus_row, -1, NULL);
2624 row_delete (clist, clist_row);
2626 /* redraw the row if it isn't frozen */
2627 if (!GTK_CLIST_FROZEN (clist))
2629 adjust_adjustments (clist, FALSE);
2632 draw_rows (clist, NULL);
2637 real_clear (GtkCList *clist)
2643 g_return_if_fail (clist != NULL);
2644 g_return_if_fail (GTK_IS_CLIST (clist));
2646 /* free up the selection list */
2647 g_list_free (clist->selection);
2648 g_list_free (clist->undo_selection);
2649 g_list_free (clist->undo_unselection);
2651 clist->selection = NULL;
2652 clist->selection_end = NULL;
2653 clist->undo_selection = NULL;
2654 clist->undo_unselection = NULL;
2656 clist->focus_row = -1;
2658 clist->undo_anchor = -1;
2659 clist->anchor_state = GTK_STATE_SELECTED;
2660 clist->drag_pos = -1;
2662 /* remove all the rows */
2663 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
2664 free_list = clist->row_list;
2665 clist->row_list = NULL;
2666 clist->row_list_end = NULL;
2668 for (list = free_list; list; list = list->next)
2669 row_delete (clist, GTK_CLIST_ROW (list));
2670 g_list_free (free_list);
2671 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
2672 for (i = 0; i < clist->columns; i++)
2673 if (clist->column[i].auto_resize && clist->column[i].width > 0)
2674 gtk_clist_set_column_width (clist, i, 0);
2676 /* zero-out the scrollbars */
2677 if (clist->vadjustment)
2679 gtk_adjustment_set_value (clist->vadjustment, 0.0);
2680 if (!GTK_CLIST_FROZEN (clist))
2681 gtk_clist_thaw (clist);
2684 gtk_widget_queue_resize (GTK_WIDGET (clist));
2687 /* PUBLIC ROW FUNCTIONS
2688 * gtk_clist_set_row_data
2689 * gtk_clist_set_row_data_full
2690 * gtk_clist_get_row_data
2691 * gtk_clist_find_row_from_data
2692 * gtk_clist_swap_rows
2693 * gtk_clist_row_is_visible
2694 * gtk_clist_set_foreground
2695 * gtk_clist_set_background
2698 gtk_clist_set_row_data (GtkCList *clist,
2702 gtk_clist_set_row_data_full (clist, row, data, NULL);
2706 gtk_clist_set_row_data_full (GtkCList *clist,
2709 GtkDestroyNotify destroy)
2711 GtkCListRow *clist_row;
2713 g_return_if_fail (clist != NULL);
2714 g_return_if_fail (GTK_IS_CLIST (clist));
2716 if (row < 0 || row > (clist->rows - 1))
2719 clist_row = (g_list_nth (clist->row_list, row))->data;
2720 clist_row->data = data;
2721 clist_row->destroy = destroy;
2725 gtk_clist_get_row_data (GtkCList *clist,
2728 GtkCListRow *clist_row;
2730 g_return_val_if_fail (clist != NULL, NULL);
2731 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2733 if (row < 0 || row > (clist->rows - 1))
2736 clist_row = (g_list_nth (clist->row_list, row))->data;
2737 return clist_row->data;
2741 gtk_clist_find_row_from_data (GtkCList *clist,
2747 g_return_val_if_fail (clist != NULL, -1);
2748 g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
2750 for (n = 0, list = clist->row_list; list; n++, list = list->next)
2751 if (GTK_CLIST_ROW (list)->data == data)
2758 gtk_clist_swap_rows (GtkCList *clist,
2763 GList *list, *link1, *link2;
2766 g_return_if_fail (clist != NULL);
2767 g_return_if_fail (GTK_IS_CLIST (clist));
2769 if (GTK_CLIST_AUTO_SORT (clist))
2772 if (row1 < 0 || row1 > (clist->rows - 1))
2775 if (row2 < 0 || row2 > (clist->rows - 1))
2778 first = MIN (row1, row2);
2779 last = MAX (row1, row2);
2781 link1 = g_list_nth (clist->row_list, first);
2782 link2 = g_list_nth (link1, row2 - row1);
2785 link1->data = link2->data;
2788 list = clist->selection;
2791 if (GPOINTER_TO_INT (list->data) == row1)
2792 list->data = GINT_TO_POINTER (row2);
2794 if (GPOINTER_TO_INT (list->data) == row2)
2795 list->data = GINT_TO_POINTER (row1);
2800 if (!GTK_CLIST_FROZEN (clist))
2802 if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE)
2803 GTK_CLIST_CLASS_FW (clist)->draw_row
2804 (clist, NULL, row1, GTK_CLIST_ROW (link2));
2806 if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE)
2807 GTK_CLIST_CLASS_FW (clist)->draw_row
2808 (clist, NULL, row2, GTK_CLIST_ROW (link1));
2813 gtk_clist_row_is_visible (GtkCList *clist,
2818 g_return_val_if_fail (clist != NULL, 0);
2819 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
2821 if (row < 0 || row >= clist->rows)
2822 return GTK_VISIBILITY_NONE;
2824 if (clist->row_height == 0)
2825 return GTK_VISIBILITY_NONE;
2827 if (row < ROW_FROM_YPIXEL (clist, 0))
2828 return GTK_VISIBILITY_NONE;
2830 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
2831 return GTK_VISIBILITY_NONE;
2833 top = ROW_TOP_YPIXEL (clist, row);
2836 || ((top + clist->row_height) >= clist->clist_window_height))
2837 return GTK_VISIBILITY_PARTIAL;
2839 return GTK_VISIBILITY_FULL;
2843 gtk_clist_set_foreground (GtkCList *clist,
2847 GtkCListRow *clist_row;
2849 g_return_if_fail (clist != NULL);
2850 g_return_if_fail (GTK_IS_CLIST (clist));
2852 if (row < 0 || row >= clist->rows)
2855 clist_row = (g_list_nth (clist->row_list, row))->data;
2859 clist_row->foreground = *color;
2860 clist_row->fg_set = TRUE;
2861 if (GTK_WIDGET_REALIZED (clist))
2862 gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
2863 &clist_row->foreground);
2866 clist_row->fg_set = FALSE;
2868 if (!GTK_CLIST_FROZEN (clist)
2869 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2870 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2874 gtk_clist_set_background (GtkCList *clist,
2878 GtkCListRow *clist_row;
2880 g_return_if_fail (clist != NULL);
2881 g_return_if_fail (GTK_IS_CLIST (clist));
2883 if (row < 0 || row >= clist->rows)
2886 clist_row = (g_list_nth (clist->row_list, row))->data;
2890 clist_row->background = *color;
2891 clist_row->bg_set = TRUE;
2892 if (GTK_WIDGET_REALIZED (clist))
2893 gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)),
2894 &clist_row->background);
2897 clist_row->bg_set = FALSE;
2899 if (!GTK_CLIST_FROZEN (clist)
2900 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
2901 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2904 /* PUBLIC ROW/CELL STYLE FUNCTIONS
2905 * gtk_clist_set_cell_style
2906 * gtk_clist_get_cell_style
2907 * gtk_clist_set_row_style
2908 * gtk_clist_get_row_style
2911 gtk_clist_set_cell_style (GtkCList *clist,
2916 GtkRequisition requisition;
2917 GtkCListRow *clist_row;
2919 g_return_if_fail (clist != NULL);
2920 g_return_if_fail (GTK_IS_CLIST (clist));
2922 if (row < 0 || row >= clist->rows)
2924 if (column < 0 || column >= clist->columns)
2927 clist_row = (g_list_nth (clist->row_list, row))->data;
2929 if (clist_row->cell[column].style == style)
2932 if (clist->column[column].auto_resize &&
2933 !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2934 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
2935 column, &requisition);
2937 if (clist_row->cell[column].style)
2939 if (GTK_WIDGET_REALIZED (clist))
2940 gtk_style_detach (clist_row->cell[column].style);
2941 gtk_style_unref (clist_row->cell[column].style);
2944 clist_row->cell[column].style = style;
2946 if (clist_row->cell[column].style)
2948 gtk_style_ref (clist_row->cell[column].style);
2950 if (GTK_WIDGET_REALIZED (clist))
2951 clist_row->cell[column].style =
2952 gtk_style_attach (clist_row->cell[column].style,
2953 clist->clist_window);
2956 column_auto_resize (clist, clist_row, column, requisition.width);
2958 /* redraw the list if it's not frozen */
2959 if (!GTK_CLIST_FROZEN (clist))
2961 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2962 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
2967 gtk_clist_get_cell_style (GtkCList *clist,
2971 GtkCListRow *clist_row;
2973 g_return_val_if_fail (clist != NULL, NULL);
2974 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
2976 if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns)
2979 clist_row = (g_list_nth (clist->row_list, row))->data;
2981 return clist_row->cell[column].style;
2985 gtk_clist_set_row_style (GtkCList *clist,
2989 GtkRequisition requisition;
2990 GtkCListRow *clist_row;
2994 g_return_if_fail (clist != NULL);
2995 g_return_if_fail (GTK_IS_CLIST (clist));
2997 if (row < 0 || row >= clist->rows)
3000 clist_row = (g_list_nth (clist->row_list, row))->data;
3002 if (clist_row->style == style)
3005 old_width = g_new (gint, clist->columns);
3007 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
3009 for (i = 0; i < clist->columns; i++)
3010 if (clist->column[i].auto_resize)
3012 GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row,
3014 old_width[i] = requisition.width;
3018 if (clist_row->style)
3020 if (GTK_WIDGET_REALIZED (clist))
3021 gtk_style_detach (clist_row->style);
3022 gtk_style_unref (clist_row->style);
3025 clist_row->style = style;
3027 if (clist_row->style)
3029 gtk_style_ref (clist_row->style);
3031 if (GTK_WIDGET_REALIZED (clist))
3032 clist_row->style = gtk_style_attach (clist_row->style,
3033 clist->clist_window);
3036 if (GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
3038 for (i = 0; i < clist->columns; i++)
3039 if (clist->column[i].auto_resize)
3040 column_auto_resize (clist, clist_row, i, old_width[i]);
3045 /* redraw the list if it's not frozen */
3046 if (!GTK_CLIST_FROZEN (clist))
3048 if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3049 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
3054 gtk_clist_get_row_style (GtkCList *clist,
3057 GtkCListRow *clist_row;
3059 g_return_val_if_fail (clist != NULL, NULL);
3060 g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
3062 if (row < 0 || row >= clist->rows)
3065 clist_row = (g_list_nth (clist->row_list, row))->data;
3067 return clist_row->style;
3070 /* PUBLIC SELECTION FUNCTIONS
3071 * gtk_clist_set_selectable
3072 * gtk_clist_get_selectable
3073 * gtk_clist_select_row
3074 * gtk_clist_unselect_row
3075 * gtk_clist_select_all
3076 * gtk_clist_unselect_all
3077 * gtk_clist_undo_selection
3080 gtk_clist_set_selectable (GtkCList *clist,
3082 gboolean selectable)
3084 GtkCListRow *clist_row;
3086 g_return_if_fail (clist != NULL);
3087 g_return_if_fail (GTK_IS_CLIST (clist));
3089 if (row < 0 || row >= clist->rows)
3092 clist_row = (g_list_nth (clist->row_list, row))->data;
3094 if (selectable == clist_row->selectable)
3097 clist_row->selectable = selectable;
3099 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
3101 if (clist->anchor >= 0 &&
3102 clist->selection_mode == GTK_SELECTION_EXTENDED)
3104 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)))
3106 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
3107 gtk_grab_remove (GTK_WIDGET (clist));
3108 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3111 gtk_timeout_remove (clist->htimer);
3116 gtk_timeout_remove (clist->vtimer);
3120 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3122 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3128 gtk_clist_get_selectable (GtkCList *clist,
3131 g_return_val_if_fail (clist != NULL, FALSE);
3132 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
3134 if (row < 0 || row >= clist->rows)
3137 return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable;
3141 gtk_clist_select_row (GtkCList *clist,
3145 g_return_if_fail (clist != NULL);
3146 g_return_if_fail (GTK_IS_CLIST (clist));
3148 if (row < 0 || row >= clist->rows)
3150 if (column < -1 || column >= clist->columns)
3153 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3158 gtk_clist_unselect_row (GtkCList *clist,
3162 g_return_if_fail (clist != NULL);
3163 g_return_if_fail (GTK_IS_CLIST (clist));
3165 if (row < 0 || row >= clist->rows)
3167 if (column < -1 || column >= clist->columns)
3170 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3175 gtk_clist_select_all (GtkCList *clist)
3177 g_return_if_fail (clist != NULL);
3178 g_return_if_fail (GTK_IS_CLIST (clist));
3180 GTK_CLIST_CLASS_FW (clist)->select_all (clist);
3184 gtk_clist_unselect_all (GtkCList *clist)
3186 g_return_if_fail (clist != NULL);
3187 g_return_if_fail (GTK_IS_CLIST (clist));
3189 GTK_CLIST_CLASS_FW (clist)->unselect_all (clist);
3193 gtk_clist_undo_selection (GtkCList *clist)
3195 g_return_if_fail (clist != NULL);
3196 g_return_if_fail (GTK_IS_CLIST (clist));
3198 if (clist->selection_mode == GTK_SELECTION_EXTENDED &&
3199 (clist->undo_selection || clist->undo_unselection))
3200 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]);
3203 /* PRIVATE SELECTION FUNCTIONS
3214 * real_undo_selection
3217 * update_extended_selection
3224 selection_find (GtkCList *clist,
3226 GList *row_list_element)
3228 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
3232 toggle_row (GtkCList *clist,
3237 GtkCListRow *clist_row;
3239 switch (clist->selection_mode)
3241 case GTK_SELECTION_EXTENDED:
3242 case GTK_SELECTION_MULTIPLE:
3243 case GTK_SELECTION_SINGLE:
3244 clist_row = g_list_nth (clist->row_list, row)->data;
3245 if (clist_row->state == GTK_STATE_SELECTED)
3247 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3248 row, column, event);
3251 case GTK_SELECTION_BROWSE:
3252 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3253 row, column, event);
3259 fake_toggle_row (GtkCList *clist,
3264 if (!(work = g_list_nth (clist->row_list, row))||
3265 !GTK_CLIST_ROW (work)->selectable)
3268 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL)
3269 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
3271 clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
3273 if (!GTK_CLIST_FROZEN (clist) &&
3274 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3275 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
3276 GTK_CLIST_ROW (work));
3280 toggle_focus_row (GtkCList *clist)
3282 g_return_if_fail (clist != 0);
3283 g_return_if_fail (GTK_IS_CLIST (clist));
3285 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3286 clist->focus_row < 0 || clist->focus_row >= clist->rows)
3289 switch (clist->selection_mode)
3291 case GTK_SELECTION_SINGLE:
3292 case GTK_SELECTION_MULTIPLE:
3293 toggle_row (clist, clist->focus_row, 0, NULL);
3295 case GTK_SELECTION_EXTENDED:
3296 g_list_free (clist->undo_selection);
3297 g_list_free (clist->undo_unselection);
3298 clist->undo_selection = NULL;
3299 clist->undo_unselection = NULL;
3301 clist->anchor = clist->focus_row;
3302 clist->drag_pos = clist->focus_row;
3303 clist->undo_anchor = clist->focus_row;
3305 if (GTK_CLIST_ADD_MODE (clist))
3306 fake_toggle_row (clist, clist->focus_row);
3308 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row);
3310 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3318 toggle_add_mode (GtkCList *clist)
3320 g_return_if_fail (clist != 0);
3321 g_return_if_fail (GTK_IS_CLIST (clist));
3323 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3324 clist->selection_mode != GTK_SELECTION_EXTENDED)
3327 gtk_clist_draw_focus (GTK_WIDGET (clist));
3328 if (!GTK_CLIST_ADD_MODE (clist))
3330 GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE);
3331 gdk_gc_set_line_attributes (clist->xor_gc, 1,
3332 GDK_LINE_ON_OFF_DASH, 0, 0);
3333 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
3337 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
3338 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
3339 clist->anchor_state = GTK_STATE_SELECTED;
3341 gtk_clist_draw_focus (GTK_WIDGET (clist));
3345 real_select_row (GtkCList *clist,
3350 GtkCListRow *clist_row;
3353 gboolean row_selected;
3355 g_return_if_fail (clist != NULL);
3356 g_return_if_fail (GTK_IS_CLIST (clist));
3358 if (row < 0 || row > (clist->rows - 1))
3361 switch (clist->selection_mode)
3363 case GTK_SELECTION_SINGLE:
3364 case GTK_SELECTION_BROWSE:
3366 row_selected = FALSE;
3367 list = clist->selection;
3371 sel_row = GPOINTER_TO_INT (list->data);
3375 row_selected = TRUE;
3377 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3378 sel_row, column, event);
3388 clist_row = (g_list_nth (clist->row_list, row))->data;
3390 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
3393 clist_row->state = GTK_STATE_SELECTED;
3394 if (!clist->selection)
3396 clist->selection = g_list_append (clist->selection,
3397 GINT_TO_POINTER (row));
3398 clist->selection_end = clist->selection;
3401 clist->selection_end =
3402 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
3404 if (!GTK_CLIST_FROZEN (clist)
3405 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3406 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
3410 real_unselect_row (GtkCList *clist,
3415 GtkCListRow *clist_row;
3417 g_return_if_fail (clist != NULL);
3418 g_return_if_fail (GTK_IS_CLIST (clist));
3420 if (row < 0 || row > (clist->rows - 1))
3423 clist_row = (g_list_nth (clist->row_list, row))->data;
3425 if (clist_row->state == GTK_STATE_SELECTED)
3427 clist_row->state = GTK_STATE_NORMAL;
3429 if (clist->selection_end &&
3430 clist->selection_end->data == GINT_TO_POINTER (row))
3431 clist->selection_end = clist->selection_end->prev;
3433 clist->selection = g_list_remove (clist->selection,
3434 GINT_TO_POINTER (row));
3436 if (!GTK_CLIST_FROZEN (clist)
3437 && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3438 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row);
3443 real_select_all (GtkCList *clist)
3448 g_return_if_fail (clist != NULL);
3449 g_return_if_fail (GTK_IS_CLIST (clist));
3451 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3454 switch (clist->selection_mode)
3456 case GTK_SELECTION_SINGLE:
3457 case GTK_SELECTION_BROWSE:
3460 case GTK_SELECTION_EXTENDED:
3461 g_list_free (clist->undo_selection);
3462 g_list_free (clist->undo_unselection);
3463 clist->undo_selection = NULL;
3464 clist->undo_unselection = NULL;
3467 ((GtkCListRow *) (clist->row_list->data))->state !=
3469 fake_toggle_row (clist, 0);
3471 clist->anchor_state = GTK_STATE_SELECTED;
3473 clist->drag_pos = 0;
3474 clist->undo_anchor = clist->focus_row;
3475 update_extended_selection (clist, clist->rows);
3476 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3479 case GTK_SELECTION_MULTIPLE:
3480 for (i = 0, list = clist->row_list; list; i++, list = list->next)
3482 if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL)
3483 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3491 real_unselect_all (GtkCList *clist)
3496 g_return_if_fail (clist != NULL);
3497 g_return_if_fail (GTK_IS_CLIST (clist));
3499 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3502 switch (clist->selection_mode)
3504 case GTK_SELECTION_BROWSE:
3505 if (clist->focus_row >= 0)
3507 gtk_signal_emit (GTK_OBJECT (clist),
3508 clist_signals[SELECT_ROW],
3509 clist->focus_row, -1, NULL);
3513 case GTK_SELECTION_EXTENDED:
3514 g_list_free (clist->undo_selection);
3515 g_list_free (clist->undo_unselection);
3516 clist->undo_selection = NULL;
3517 clist->undo_unselection = NULL;
3520 clist->drag_pos = -1;
3521 clist->undo_anchor = clist->focus_row;
3527 list = clist->selection;
3530 i = GPOINTER_TO_INT (list->data);
3532 gtk_signal_emit (GTK_OBJECT (clist),
3533 clist_signals[UNSELECT_ROW], i, -1, NULL);
3538 fake_unselect_all (GtkCList *clist,
3545 if (row >= 0 && (work = g_list_nth (clist->row_list, row)))
3547 if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL &&
3548 GTK_CLIST_ROW (work)->selectable)
3550 GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED;
3552 if (!GTK_CLIST_FROZEN (clist) &&
3553 gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3554 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
3555 GTK_CLIST_ROW (work));
3559 clist->undo_selection = clist->selection;
3560 clist->selection = NULL;
3561 clist->selection_end = NULL;
3563 for (list = clist->undo_selection; list; list = list->next)
3565 if ((i = GPOINTER_TO_INT (list->data)) == row ||
3566 !(work = g_list_nth (clist->row_list, i)))
3569 GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL;
3570 if (!GTK_CLIST_FROZEN (clist) &&
3571 gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
3572 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i,
3573 GTK_CLIST_ROW (work));
3578 real_undo_selection (GtkCList *clist)
3582 g_return_if_fail (clist != NULL);
3583 g_return_if_fail (GTK_IS_CLIST (clist));
3585 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3586 clist->selection_mode != GTK_SELECTION_EXTENDED)
3589 if (clist->anchor >= 0)
3590 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3592 if (!(clist->undo_selection || clist->undo_unselection))
3594 gtk_clist_unselect_all (clist);
3598 for (work = clist->undo_selection; work; work = work->next)
3599 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3600 GPOINTER_TO_INT (work->data), -1, NULL);
3602 for (work = clist->undo_unselection; work; work = work->next)
3603 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
3604 GPOINTER_TO_INT (work->data), -1, NULL);
3606 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
3608 gtk_clist_draw_focus (GTK_WIDGET (clist));
3609 clist->focus_row = clist->undo_anchor;
3610 gtk_clist_draw_focus (GTK_WIDGET (clist));
3613 clist->focus_row = clist->undo_anchor;
3615 clist->undo_anchor = -1;
3617 g_list_free (clist->undo_selection);
3618 g_list_free (clist->undo_unselection);
3619 clist->undo_selection = NULL;
3620 clist->undo_unselection = NULL;
3622 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3623 clist->clist_window_height)
3624 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3625 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3626 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3630 set_anchor (GtkCList *clist,
3635 g_return_if_fail (clist != NULL);
3636 g_return_if_fail (GTK_IS_CLIST (clist));
3638 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0)
3641 g_list_free (clist->undo_selection);
3642 g_list_free (clist->undo_unselection);
3643 clist->undo_selection = NULL;
3644 clist->undo_unselection = NULL;
3647 fake_toggle_row (clist, anchor);
3650 GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor);
3651 clist->anchor_state = GTK_STATE_SELECTED;
3654 clist->anchor = anchor;
3655 clist->drag_pos = anchor;
3656 clist->undo_anchor = undo_anchor;
3660 resync_selection (GtkCList *clist,
3666 gboolean thaw = FALSE;
3668 GtkCListRow *clist_row;
3670 if (clist->anchor < 0)
3673 if (!GTK_CLIST_FROZEN (clist))
3675 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
3679 i = MIN (clist->anchor, clist->drag_pos);
3680 e = MAX (clist->anchor, clist->drag_pos);
3682 if (clist->undo_selection)
3684 list = clist->selection;
3685 clist->selection = clist->undo_selection;
3686 clist->selection_end = g_list_last (clist->selection);
3687 clist->undo_selection = list;
3688 list = clist->selection;
3691 row = GPOINTER_TO_INT (list->data);
3693 if (row < i || row > e)
3695 clist_row = g_list_nth (clist->row_list, row)->data;
3696 if (clist_row->selectable)
3698 clist_row->state = GTK_STATE_SELECTED;
3699 gtk_signal_emit (GTK_OBJECT (clist),
3700 clist_signals[UNSELECT_ROW],
3702 clist->undo_selection = g_list_prepend
3703 (clist->undo_selection, GINT_TO_POINTER (row));
3709 for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next)
3710 if (GTK_CLIST_ROW (list)->selectable)
3712 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
3714 if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL)
3716 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
3717 gtk_signal_emit (GTK_OBJECT (clist),
3718 clist_signals[UNSELECT_ROW], i, -1, event);
3719 clist->undo_selection = g_list_prepend (clist->undo_selection,
3720 GINT_TO_POINTER (i));
3723 else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
3725 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
3726 clist->undo_unselection = g_list_prepend (clist->undo_unselection,
3727 GINT_TO_POINTER (i));
3731 for (list = clist->undo_unselection; list; list = list->next)
3732 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
3733 GPOINTER_TO_INT (list->data), -1, event);
3736 clist->drag_pos = -1;
3739 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
3743 update_extended_selection (GtkCList *clist,
3753 gint y1 = clist->clist_window_height;
3754 gint y2 = clist->clist_window_height;
3759 if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1)
3764 if (row >= clist->rows)
3765 row = clist->rows - 1;
3767 /* extending downwards */
3768 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
3770 s2 = clist->drag_pos + 1;
3773 /* extending upwards */
3774 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
3777 e2 = clist->drag_pos - 1;
3779 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
3781 e1 = clist->drag_pos;
3782 /* row and drag_pos on different sides of anchor :
3783 take back the selection between anchor and drag_pos,
3784 select between anchor and row */
3785 if (row < clist->anchor)
3787 s1 = clist->anchor + 1;
3789 e2 = clist->anchor - 1;
3791 /* take back the selection between anchor and drag_pos */
3795 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
3797 s1 = clist->drag_pos;
3798 /* row and drag_pos on different sides of anchor :
3799 take back the selection between anchor and drag_pos,
3800 select between anchor and row */
3801 if (row > clist->anchor)
3803 e1 = clist->anchor - 1;
3804 s2 = clist->anchor + 1;
3807 /* take back the selection between anchor and drag_pos */
3812 clist->drag_pos = row;
3815 area.width = clist->clist_window_width;
3817 /* restore the elements between s1 and e1 */
3820 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
3821 i++, list = list->next)
3822 if (GTK_CLIST_ROW (list)->selectable)
3824 if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list))
3825 GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED;
3827 GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL;
3830 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
3832 if (top + clist->row_height <= 0)
3835 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
3836 draw_rows (clist, &area);
3837 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3839 else if (top >= clist->clist_window_height)
3841 area.y = ROW_TOP_YPIXEL (clist, s1) - 1;
3842 area.height = clist->clist_window_height - area.y;
3843 draw_rows (clist, &area);
3844 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3847 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3848 else if (top + clist->row_height > clist->clist_window_height)
3849 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3851 y1 = ROW_TOP_YPIXEL (clist, s1) - 1;
3852 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
3855 /* extend the selection between s2 and e2 */
3858 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
3859 i++, list = list->next)
3860 if (GTK_CLIST_ROW (list)->selectable &&
3861 GTK_CLIST_ROW (list)->state != clist->anchor_state)
3862 GTK_CLIST_ROW (list)->state = clist->anchor_state;
3864 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
3866 if (top + clist->row_height <= 0)
3869 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
3870 draw_rows (clist, &area);
3871 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3873 else if (top >= clist->clist_window_height)
3875 area.y = ROW_TOP_YPIXEL (clist, s2) - 1;
3876 area.height = clist->clist_window_height - area.y;
3877 draw_rows (clist, &area);
3878 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3881 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3882 else if (top + clist->row_height > clist->clist_window_height)
3883 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3885 y2 = ROW_TOP_YPIXEL (clist, s2) - 1;
3886 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
3889 area.y = MAX (0, MIN (y1, y2));
3890 if (area.y > clist->clist_window_height)
3892 area.height = MIN (clist->clist_window_height, h1 + h2);
3893 if (s1 >= 0 && s2 >= 0)
3894 area.height += (clist->row_height + CELL_SPACING);
3895 draw_rows (clist, &area);
3899 start_selection (GtkCList *clist)
3901 g_return_if_fail (clist != NULL);
3902 g_return_if_fail (GTK_IS_CLIST (clist));
3904 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
3907 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
3912 end_selection (GtkCList *clist)
3914 g_return_if_fail (clist != NULL);
3915 g_return_if_fail (GTK_IS_CLIST (clist));
3917 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) ||
3918 clist->anchor == -1)
3921 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3925 extend_selection (GtkCList *clist,
3926 GtkScrollType scroll_type,
3928 gboolean auto_start_selection)
3930 g_return_if_fail (clist != NULL);
3931 g_return_if_fail (GTK_IS_CLIST (clist));
3933 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) ||
3934 clist->selection_mode != GTK_SELECTION_EXTENDED)
3937 if (auto_start_selection)
3938 set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row,
3940 else if (clist->anchor == -1)
3943 move_focus_row (clist, scroll_type, position);
3945 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
3946 clist->clist_window_height)
3947 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
3948 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
3949 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
3951 update_extended_selection (clist, clist->focus_row);
3955 sync_selection (GtkCList *clist,
3962 if (mode == SYNC_INSERT)
3967 if (clist->focus_row >= row)
3969 if (d > 0 || clist->focus_row > row)
3970 clist->focus_row += d;
3971 if (clist->focus_row == -1 && clist->rows >= 1)
3972 clist->focus_row = 0;
3973 else if (clist->focus_row >= clist->rows)
3974 clist->focus_row = clist->rows - 1;
3977 if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1)
3978 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
3980 g_list_free (clist->undo_selection);
3981 g_list_free (clist->undo_unselection);
3982 clist->undo_selection = NULL;
3983 clist->undo_unselection = NULL;
3986 clist->drag_pos = -1;
3987 clist->undo_anchor = clist->focus_row;
3989 list = clist->selection;
3993 if (GPOINTER_TO_INT (list->data) >= row)
3994 list->data = ((gchar*) list->data) + d;
4001 * gtk_clist_finalize
4004 gtk_clist_destroy (GtkObject *object)
4009 g_return_if_fail (object != NULL);
4010 g_return_if_fail (GTK_IS_CLIST (object));
4012 clist = GTK_CLIST (object);
4014 /* freeze the list */
4015 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
4017 /* get rid of all the rows */
4018 gtk_clist_clear (clist);
4020 /* Since we don't have a _remove method, unparent the children
4021 * instead of destroying them so the focus will be unset properly.
4022 * (For other containers, the _remove method takes care of the
4023 * unparent) The destroy will happen when the refcount drops
4027 /* unref adjustments */
4028 if (clist->hadjustment)
4030 gtk_object_unref (GTK_OBJECT (clist->hadjustment));
4031 clist->hadjustment = NULL;
4033 if (clist->vadjustment)
4035 gtk_object_unref (GTK_OBJECT (clist->vadjustment));
4036 clist->vadjustment = NULL;
4041 gtk_timeout_remove (clist->htimer);
4046 gtk_timeout_remove (clist->vtimer);
4050 /* destroy the column buttons */
4051 for (i = 0; i < clist->columns; i++)
4052 if (clist->column[i].button)
4054 gtk_widget_unparent (clist->column[i].button);
4055 clist->column[i].button = NULL;
4058 if (GTK_OBJECT_CLASS (parent_class)->destroy)
4059 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
4063 gtk_clist_finalize (GtkObject *object)
4067 g_return_if_fail (object != NULL);
4068 g_return_if_fail (GTK_IS_CLIST (object));
4070 clist = GTK_CLIST (object);
4072 columns_delete (clist);
4074 g_mem_chunk_destroy (clist->cell_mem_chunk);
4075 g_mem_chunk_destroy (clist->row_mem_chunk);
4077 if (GTK_OBJECT_CLASS (parent_class)->finalize)
4078 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
4083 * gtk_clist_unrealize
4088 * gtk_clist_style_set
4089 * gtk_clist_parent_set
4090 * gtk_clist_key_press
4091 * gtk_clist_button_press
4092 * gtk_clist_button_release
4094 * gtk_clist_size_request
4095 * gtk_clist_size_allocate
4098 gtk_clist_realize (GtkWidget *widget)
4101 GdkWindowAttr attributes;
4103 GtkCListRow *clist_row;
4105 gint attributes_mask;
4110 g_return_if_fail (widget != NULL);
4111 g_return_if_fail (GTK_IS_CLIST (widget));
4113 clist = GTK_CLIST (widget);
4115 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
4117 border_width = GTK_CONTAINER (widget)->border_width;
4119 attributes.window_type = GDK_WINDOW_CHILD;
4120 attributes.x = widget->allocation.x + border_width;
4121 attributes.y = widget->allocation.y + border_width;
4122 attributes.width = widget->allocation.width - border_width * 2;
4123 attributes.height = widget->allocation.height - border_width * 2;
4124 attributes.wclass = GDK_INPUT_OUTPUT;
4125 attributes.visual = gtk_widget_get_visual (widget);
4126 attributes.colormap = gtk_widget_get_colormap (widget);
4127 attributes.event_mask = gtk_widget_get_events (widget);
4128 attributes.event_mask |= (GDK_EXPOSURE_MASK |
4129 GDK_BUTTON_PRESS_MASK |
4130 GDK_BUTTON_RELEASE_MASK |
4131 GDK_KEY_PRESS_MASK |
4132 GDK_KEY_RELEASE_MASK);
4133 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
4136 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
4137 &attributes, attributes_mask);
4138 gdk_window_set_user_data (widget->window, clist);
4140 widget->style = gtk_style_attach (widget->style, widget->window);
4142 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
4144 /* column-title window */
4146 attributes.x = clist->column_title_area.x;
4147 attributes.y = clist->column_title_area.y;
4148 attributes.width = clist->column_title_area.width;
4149 attributes.height = clist->column_title_area.height;
4151 clist->title_window = gdk_window_new (widget->window, &attributes,
4153 gdk_window_set_user_data (clist->title_window, clist);
4155 gtk_style_set_background (widget->style, clist->title_window,
4157 gdk_window_show (clist->title_window);
4159 /* set things up so column buttons are drawn in title window */
4160 for (i = 0; i < clist->columns; i++)
4161 if (clist->column[i].button)
4162 gtk_widget_set_parent_window (clist->column[i].button,
4163 clist->title_window);
4166 attributes.x = (clist->internal_allocation.x +
4167 widget->style->klass->xthickness);
4168 attributes.y = (clist->internal_allocation.y +
4169 widget->style->klass->ythickness +
4170 clist->column_title_area.height);
4171 attributes.width = clist->clist_window_width;
4172 attributes.height = clist->clist_window_height;
4174 clist->clist_window = gdk_window_new (widget->window, &attributes,
4176 gdk_window_set_user_data (clist->clist_window, clist);
4178 gdk_window_set_background (clist->clist_window,
4179 &widget->style->bg[GTK_STATE_PRELIGHT]);
4180 gdk_window_show (clist->clist_window);
4181 gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
4182 &clist->clist_window_height);
4184 /* create resize windows */
4185 attributes.wclass = GDK_INPUT_ONLY;
4186 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
4187 GDK_BUTTON_RELEASE_MASK |
4188 GDK_POINTER_MOTION_MASK |
4189 GDK_POINTER_MOTION_HINT_MASK |
4190 GDK_KEY_PRESS_MASK);
4191 attributes_mask = GDK_WA_CURSOR;
4192 attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
4193 clist->cursor_drag = attributes.cursor;
4195 attributes.x = LIST_WIDTH (clist) + 1;
4197 attributes.width = 0;
4198 attributes.height = 0;
4200 for (i = 0; i < clist->columns; i++)
4202 clist->column[i].window = gdk_window_new (clist->title_window,
4203 &attributes, attributes_mask);
4204 gdk_window_set_user_data (clist->column[i].window, clist);
4207 /* This is slightly less efficient than creating them with the
4208 * right size to begin with, but easier
4210 size_allocate_title_buttons (clist);
4213 clist->fg_gc = gdk_gc_new (widget->window);
4214 clist->bg_gc = gdk_gc_new (widget->window);
4216 /* We'll use this gc to do scrolling as well */
4217 gdk_gc_set_exposures (clist->fg_gc, TRUE);
4219 values.foreground = widget->style->white;
4220 values.function = GDK_XOR;
4221 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
4222 clist->xor_gc = gdk_gc_new_with_values (widget->window,
4228 /* attach optional row/cell styles, allocate foreground/background colors */
4229 list = clist->row_list;
4230 for (i = 0; i < clist->rows; i++)
4232 clist_row = list->data;
4235 if (clist_row->style)
4236 clist_row->style = gtk_style_attach (clist_row->style,
4237 clist->clist_window);
4239 if (clist_row->fg_set || clist_row->bg_set)
4241 GdkColormap *colormap;
4243 colormap = gtk_widget_get_colormap (widget);
4244 if (clist_row->fg_set)
4245 gdk_color_alloc (colormap, &clist_row->foreground);
4246 if (clist_row->bg_set)
4247 gdk_color_alloc (colormap, &clist_row->background);
4250 for (j = 0; j < clist->columns; j++)
4251 if (clist_row->cell[j].style)
4252 clist_row->cell[j].style =
4253 gtk_style_attach (clist_row->cell[j].style, clist->clist_window);
4258 gtk_clist_unrealize (GtkWidget *widget)
4263 g_return_if_fail (widget != NULL);
4264 g_return_if_fail (GTK_IS_CLIST (widget));
4266 clist = GTK_CLIST (widget);
4268 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
4270 /* detach optional row/cell styles */
4272 if (GTK_WIDGET_REALIZED (widget))
4274 GtkCListRow *clist_row;
4278 list = clist->row_list;
4279 for (i = 0; i < clist->rows; i++)
4281 clist_row = list->data;
4284 if (clist_row->style)
4285 gtk_style_detach (clist_row->style);
4286 for (j = 0; j < clist->columns; j++)
4287 if (clist_row->cell[j].style)
4288 gtk_style_detach (clist_row->cell[j].style);
4292 gdk_cursor_destroy (clist->cursor_drag);
4293 gdk_gc_destroy (clist->xor_gc);
4294 gdk_gc_destroy (clist->fg_gc);
4295 gdk_gc_destroy (clist->bg_gc);
4297 for (i = 0; i < clist->columns; i++)
4298 if (clist->column[i].window)
4300 gdk_window_set_user_data (clist->column[i].window, NULL);
4301 gdk_window_destroy (clist->column[i].window);
4302 clist->column[i].window = NULL;
4305 gdk_window_set_user_data (clist->clist_window, NULL);
4306 gdk_window_destroy (clist->clist_window);
4307 clist->clist_window = NULL;
4309 gdk_window_set_user_data (clist->title_window, NULL);
4310 gdk_window_destroy (clist->title_window);
4311 clist->title_window = NULL;
4313 clist->cursor_drag = NULL;
4314 clist->xor_gc = NULL;
4315 clist->fg_gc = NULL;
4316 clist->bg_gc = NULL;
4318 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
4319 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
4323 gtk_clist_map (GtkWidget *widget)
4328 g_return_if_fail (widget != NULL);
4329 g_return_if_fail (GTK_IS_CLIST (widget));
4331 clist = GTK_CLIST (widget);
4333 if (!GTK_WIDGET_MAPPED (widget))
4335 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
4337 gdk_window_show (widget->window);
4338 gdk_window_show (clist->title_window);
4339 gdk_window_show (clist->clist_window);
4341 /* map column buttons */
4342 for (i = 0; i < clist->columns; i++)
4343 if (clist->column[i].button &&
4344 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
4345 !GTK_WIDGET_MAPPED (clist->column[i].button))
4346 gtk_widget_map (clist->column[i].button);
4348 /* map resize windows AFTER column buttons (above) */
4349 for (i = 0; i < clist->columns; i++)
4350 if (clist->column[i].window && clist->column[i].button)
4351 gdk_window_show (clist->column[i].window);
4353 /* unfreeze the list */
4354 GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
4359 gtk_clist_unmap (GtkWidget *widget)
4364 g_return_if_fail (widget != NULL);
4365 g_return_if_fail (GTK_IS_CLIST (widget));
4367 clist = GTK_CLIST (widget);
4369 if (GTK_WIDGET_MAPPED (widget))
4371 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
4373 for (i = 0; i < clist->columns; i++)
4374 if (clist->column[i].window)
4375 gdk_window_hide (clist->column[i].window);
4377 gdk_window_hide (clist->clist_window);
4378 gdk_window_hide (clist->title_window);
4379 gdk_window_hide (widget->window);
4381 /* unmap column buttons */
4382 for (i = 0; i < clist->columns; i++)
4383 if (clist->column[i].button &&
4384 GTK_WIDGET_MAPPED (clist->column[i].button))
4385 gtk_widget_unmap (clist->column[i].button);
4387 /* freeze the list */
4388 GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
4393 gtk_clist_draw (GtkWidget *widget,
4398 GdkRectangle child_area;
4401 g_return_if_fail (widget != NULL);
4402 g_return_if_fail (GTK_IS_CLIST (widget));
4403 g_return_if_fail (area != NULL);
4405 if (GTK_WIDGET_DRAWABLE (widget))
4407 clist = GTK_CLIST (widget);
4408 border_width = GTK_CONTAINER (widget)->border_width;
4410 gdk_window_clear_area (widget->window,
4411 area->x - border_width,
4412 area->y - border_width,
4413 area->width, area->height);
4415 /* draw list shadow/border */
4416 gtk_draw_shadow (widget->style, widget->window,
4417 GTK_STATE_NORMAL, clist->shadow_type,
4419 clist->clist_window_width +
4420 (2 * widget->style->klass->xthickness),
4421 clist->clist_window_height +
4422 (2 * widget->style->klass->ythickness) +
4423 clist->column_title_area.height);
4425 gdk_window_clear_area (clist->clist_window, 0, 0, -1, -1);
4426 draw_rows (clist, NULL);
4428 for (i = 0; i < clist->columns; i++)
4430 if (!clist->column[i].visible)
4432 if (clist->column[i].button &&
4433 gtk_widget_intersect(clist->column[i].button, area, &child_area))
4434 gtk_widget_draw (clist->column[i].button, &child_area);
4440 gtk_clist_expose (GtkWidget *widget,
4441 GdkEventExpose *event)
4445 g_return_val_if_fail (widget != NULL, FALSE);
4446 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4447 g_return_val_if_fail (event != NULL, FALSE);
4449 if (GTK_WIDGET_DRAWABLE (widget))
4451 clist = GTK_CLIST (widget);
4454 if (event->window == widget->window)
4455 gtk_draw_shadow (widget->style, widget->window,
4456 GTK_STATE_NORMAL, clist->shadow_type,
4458 clist->clist_window_width +
4459 (2 * widget->style->klass->xthickness),
4460 clist->clist_window_height +
4461 (2 * widget->style->klass->ythickness) +
4462 clist->column_title_area.height);
4464 /* exposure events on the list */
4465 if (event->window == clist->clist_window)
4466 draw_rows (clist, &event->area);
4473 gtk_clist_style_set (GtkWidget *widget,
4474 GtkStyle *previous_style)
4478 g_return_if_fail (widget != NULL);
4479 g_return_if_fail (GTK_IS_CLIST (widget));
4481 if (GTK_WIDGET_CLASS (parent_class)->style_set)
4482 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
4484 clist = GTK_CLIST (widget);
4486 /* Fill in data after widget has correct style */
4488 /* text properties */
4489 if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
4491 clist->row_height = (widget->style->font->ascent +
4492 widget->style->font->descent + 1);
4493 clist->row_center_offset = widget->style->font->ascent + 1.5;
4496 clist->row_center_offset = 1.5 + (clist->row_height +
4497 widget->style->font->ascent -
4498 widget->style->font->descent - 1) / 2;
4501 if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
4506 for (i = 0; i < clist->columns; i++)
4507 if (clist->column[i].auto_resize)
4509 width = gtk_clist_optimal_column_width (clist, i);
4510 if (width != clist->column[i].width)
4511 gtk_clist_set_column_width (clist, i, width);
4517 gtk_clist_parent_set (GtkWidget *widget,
4518 GtkWidget *previous_parent)
4522 g_return_if_fail (widget != NULL);
4523 g_return_if_fail (GTK_IS_WIDGET (widget));
4525 clist = GTK_CLIST (widget);
4527 /* create adjustments */
4528 /* if (!clist->hadjustment)
4529 gtk_clist_set_hadjustment (clist, NULL);
4530 if (!clist->vadjustment)
4531 gtk_clist_set_vadjustment (clist, NULL);*/
4535 gtk_clist_key_press (GtkWidget *widget,
4538 g_return_val_if_fail (widget != NULL, FALSE);
4539 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4540 g_return_val_if_fail (event != NULL, FALSE);
4542 if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
4543 GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
4546 switch (event->keyval)
4549 case GDK_ISO_Left_Tab:
4550 if (event->state & GDK_SHIFT_MASK)
4551 return gtk_container_focus (GTK_CONTAINER (widget),
4552 GTK_DIR_TAB_BACKWARD);
4554 return gtk_container_focus (GTK_CONTAINER (widget),
4555 GTK_DIR_TAB_FORWARD);
4563 gtk_clist_button_press (GtkWidget *widget,
4564 GdkEventButton *event)
4573 g_return_val_if_fail (widget != NULL, FALSE);
4574 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4575 g_return_val_if_fail (event != NULL, FALSE);
4577 clist = GTK_CLIST (widget);
4579 /* we don't handle button 2 and 3 */
4580 if (event->button != 1)
4583 /* selections on the list */
4584 if (event->window == clist->clist_window)
4589 if (get_selection_info (clist, x, y, &row, &column))
4591 gint old_row = clist->focus_row;
4593 if (clist->focus_row == -1)
4596 if (event->type == GDK_BUTTON_PRESS)
4598 GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
4599 gdk_pointer_grab (clist->clist_window, FALSE,
4600 GDK_POINTER_MOTION_HINT_MASK |
4601 GDK_BUTTON1_MOTION_MASK |
4602 GDK_BUTTON_RELEASE_MASK,
4603 NULL, NULL, event->time);
4604 gtk_grab_add (widget);
4606 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget))
4608 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
4609 gtk_grab_remove (widget);
4610 gdk_pointer_ungrab (event->time);
4613 if (GTK_CLIST_ADD_MODE (clist))
4615 GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
4616 if (GTK_WIDGET_HAS_FOCUS (widget))
4618 gtk_clist_draw_focus (widget);
4619 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4620 GDK_LINE_SOLID, 0, 0);
4621 clist->focus_row = row;
4622 gtk_clist_draw_focus (widget);
4626 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4627 GDK_LINE_SOLID, 0, 0);
4628 clist->focus_row = row;
4631 else if (row != clist->focus_row)
4633 if (GTK_WIDGET_HAS_FOCUS (widget))
4635 gtk_clist_draw_focus (widget);
4636 clist->focus_row = row;
4637 gtk_clist_draw_focus (widget);
4640 clist->focus_row = row;
4643 if (!GTK_WIDGET_HAS_FOCUS (widget))
4644 gtk_widget_grab_focus (widget);
4646 switch (clist->selection_mode)
4648 case GTK_SELECTION_SINGLE:
4649 case GTK_SELECTION_MULTIPLE:
4650 if (event->type != GDK_BUTTON_PRESS)
4651 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4652 row, column, event);
4654 clist->anchor = row;
4656 case GTK_SELECTION_BROWSE:
4657 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
4658 row, column, event);
4660 case GTK_SELECTION_EXTENDED:
4661 if (event->type != GDK_BUTTON_PRESS)
4663 if (clist->anchor != -1)
4665 update_extended_selection (clist, clist->focus_row);
4666 GTK_CLIST_CLASS_FW (clist)->resync_selection
4667 (clist, (GdkEvent *) event);
4669 gtk_signal_emit (GTK_OBJECT (clist),
4670 clist_signals[SELECT_ROW],
4671 row, column, event);
4675 if (event->state & GDK_CONTROL_MASK)
4677 if (event->state & GDK_SHIFT_MASK)
4679 if (clist->anchor < 0)
4681 g_list_free (clist->undo_selection);
4682 g_list_free (clist->undo_unselection);
4683 clist->undo_selection = NULL;
4684 clist->undo_unselection = NULL;
4685 clist->anchor = old_row;
4686 clist->drag_pos = old_row;
4687 clist->undo_anchor = old_row;
4689 update_extended_selection (clist, clist->focus_row);
4693 if (clist->anchor == -1)
4694 set_anchor (clist, TRUE, row, old_row);
4696 update_extended_selection (clist, clist->focus_row);
4701 if (event->state & GDK_SHIFT_MASK)
4703 set_anchor (clist, FALSE, old_row, old_row);
4704 update_extended_selection (clist, clist->focus_row);
4708 if (clist->anchor == -1)
4709 set_anchor (clist, FALSE, row, old_row);
4711 update_extended_selection (clist, clist->focus_row);
4721 /* press on resize windows */
4722 for (i = 0; i < clist->columns; i++)
4723 if (clist->column[i].resizeable && clist->column[i].window &&
4724 event->window == clist->column[i].window)
4726 gdk_pointer_grab (clist->column[i].window, FALSE,
4727 GDK_POINTER_MOTION_HINT_MASK |
4728 GDK_BUTTON1_MOTION_MASK |
4729 GDK_BUTTON_RELEASE_MASK,
4730 NULL, NULL, event->time);
4731 gtk_grab_add (widget);
4732 GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG);
4734 if (!GTK_WIDGET_HAS_FOCUS (widget))
4735 gtk_widget_grab_focus (widget);
4737 clist->drag_pos = i;
4738 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
4739 clist->column[i].area.width + CELL_SPACING);
4741 if (GTK_CLIST_ADD_MODE (clist))
4742 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
4743 draw_xor_line (clist);
4751 gtk_clist_button_release (GtkWidget *widget,
4752 GdkEventButton *event)
4756 g_return_val_if_fail (widget != NULL, FALSE);
4757 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4758 g_return_val_if_fail (event != NULL, FALSE);
4760 clist = GTK_CLIST (widget);
4762 /* we don't handle button 2 and 3 */
4763 if (event->button != 1)
4766 /* release on resize windows */
4767 if (GTK_CLIST_IN_DRAG (clist))
4773 i = clist->drag_pos;
4774 clist->drag_pos = -1;
4776 GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG);
4777 gtk_widget_get_pointer (widget, &x, NULL);
4778 gtk_grab_remove (widget);
4779 gdk_pointer_ungrab (event->time);
4781 if (clist->x_drag >= 0)
4782 draw_xor_line (clist);
4784 if (GTK_CLIST_ADD_MODE (clist))
4786 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4787 GDK_LINE_ON_OFF_DASH, 0, 0);
4788 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
4791 width = new_column_width (clist, i, &x);
4792 gtk_clist_set_column_width (clist, i, width);
4796 if (GTK_CLIST_DRAG_SELECTION (clist))
4801 GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION);
4802 gtk_grab_remove (widget);
4803 gdk_pointer_ungrab (event->time);
4806 gtk_timeout_remove (clist->htimer);
4811 gtk_timeout_remove (clist->vtimer);
4814 switch (clist->selection_mode)
4816 case GTK_SELECTION_EXTENDED:
4817 if (!(event->state & GDK_SHIFT_MASK) ||
4818 event->x < 0 || event->x >= clist->clist_window_width ||
4819 event->y < 0 || event->y >= clist->clist_window_height)
4820 GTK_CLIST_CLASS_FW (clist)->resync_selection
4821 (clist, (GdkEvent *) event);
4824 case GTK_SELECTION_SINGLE:
4825 case GTK_SELECTION_MULTIPLE:
4826 if (get_selection_info (clist, event->x, event->y, &row, &column))
4828 if (clist->anchor == clist->focus_row)
4829 toggle_row (clist, row, column, (GdkEvent *) event);
4843 horizontal_timeout (GtkCList *clist)
4846 GdkEventMotion event;
4847 GdkModifierType mask;
4849 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
4852 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
4859 gtk_clist_motion (GTK_WIDGET (clist), &event);
4865 vertical_timeout (GtkCList *clist)
4868 GdkEventMotion event;
4869 GdkModifierType mask;
4871 g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE);
4874 gdk_window_get_pointer (clist->clist_window, &x, &y, &mask);
4881 gtk_clist_motion (GTK_WIDGET (clist), &event);
4887 move_vertical (GtkCList *clist,
4893 if (!clist->vadjustment)
4896 value = (ROW_TOP_YPIXEL (clist, row) - clist->voffset -
4897 align * (clist->clist_window_height - clist->row_height) +
4898 (2 * align - 1) * CELL_SPACING);
4900 if (value + clist->vadjustment->page_size > clist->vadjustment->upper)
4901 value = clist->vadjustment->upper - clist->vadjustment->page_size;
4903 gtk_adjustment_set_value(clist->vadjustment, value);
4907 move_horizontal (GtkCList *clist,
4912 if (!clist->hadjustment)
4915 value = CLAMP (clist->hadjustment->value + diff, 0.0,
4916 clist->hadjustment->upper - clist->hadjustment->page_size);
4917 gtk_adjustment_set_value(clist->hadjustment, value);
4921 gtk_clist_motion (GtkWidget *widget,
4922 GdkEventMotion *event)
4930 g_return_val_if_fail (widget != NULL, FALSE);
4931 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
4933 clist = GTK_CLIST (widget);
4934 if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)))
4937 if (GTK_CLIST_IN_DRAG (clist))
4939 if (event->is_hint || event->window != widget->window)
4940 gtk_widget_get_pointer (widget, &x, NULL);
4944 new_width = new_column_width (clist, clist->drag_pos, &x);
4945 if (x != clist->x_drag)
4947 /* x_drag < 0 indicates that the xor line is already invisible */
4948 if (clist->x_drag >= 0)
4949 draw_xor_line (clist);
4953 if (clist->x_drag >= 0)
4954 draw_xor_line (clist);
4957 if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
4958 clist->column[clist->drag_pos].min_width + 1))
4960 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
4961 gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0);
4964 if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
4965 new_width >= clist->column[clist->drag_pos].max_width)
4967 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
4968 clist->clist_window_width && x < 0)
4969 move_horizontal (clist,
4970 COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
4971 new_width - clist->clist_window_width +
4972 COLUMN_INSET + CELL_SPACING);
4977 if (event->is_hint || event->window != clist->clist_window)
4978 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
4980 /* horizontal autoscrolling */
4981 if (clist->hadjustment && LIST_WIDTH (clist) > clist->clist_window_width &&
4982 (x < 0 || x >= clist->clist_window_width))
4987 clist->htimer = gtk_timeout_add
4988 (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist);
4990 if (!((x < 0 && clist->hadjustment->value == 0) ||
4991 (x >= clist->clist_window_width &&
4992 clist->hadjustment->value ==
4993 LIST_WIDTH (clist) - clist->clist_window_width)))
4996 move_horizontal (clist, -1 + (x/2));
4998 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
5002 if (GTK_CLIST_IN_DRAG (clist))
5005 /* vertical autoscrolling */
5006 row = ROW_FROM_YPIXEL (clist, y);
5008 /* don't scroll on last pixel row if it's a cell spacing */
5009 if (y == clist->clist_window_height - 1 &&
5010 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
5013 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
5014 (y < 0 || y >= clist->clist_window_height))
5019 clist->vtimer = gtk_timeout_add (SCROLL_TIME,
5020 (GtkFunction) vertical_timeout, clist);
5022 if (GTK_CLIST_DRAG_SELECTION (clist))
5024 if ((y < 0 && clist->focus_row == 0) ||
5025 (y >= clist->clist_window_height &&
5026 clist->focus_row == clist->rows-1))
5031 row = CLAMP (row, 0, clist->rows - 1);
5033 if (GTK_CLIST_DRAG_SELECTION (clist))
5035 if (row == clist->focus_row)
5038 gtk_clist_draw_focus (widget);
5039 clist->focus_row = row;
5040 gtk_clist_draw_focus (widget);
5042 switch (clist->selection_mode)
5044 case GTK_SELECTION_BROWSE:
5045 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
5046 clist->focus_row, -1, event);
5048 case GTK_SELECTION_EXTENDED:
5049 update_extended_selection (clist, clist->focus_row);
5056 if (ROW_TOP_YPIXEL(clist, row) < 0)
5057 move_vertical (clist, row, 0);
5058 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
5059 clist->clist_window_height)
5060 move_vertical (clist, row, 1);
5066 gtk_clist_size_request (GtkWidget *widget,
5067 GtkRequisition *requisition)
5072 g_return_if_fail (widget != NULL);
5073 g_return_if_fail (GTK_IS_CLIST (widget));
5074 g_return_if_fail (requisition != NULL);
5076 clist = GTK_CLIST (widget);
5078 requisition->width = 0;
5079 requisition->height = 0;
5081 /* compute the size of the column title (title) area */
5082 clist->column_title_area.height = 0;
5083 if (GTK_CLIST_SHOW_TITLES (clist))
5084 for (i = 0; i < clist->columns; i++)
5085 if (clist->column[i].button)
5087 gtk_widget_size_request (clist->column[i].button,
5088 &clist->column[i].button->requisition);
5089 clist->column_title_area.height =
5090 MAX (clist->column_title_area.height,
5091 clist->column[i].button->requisition.height);
5094 requisition->width += (widget->style->klass->xthickness +
5095 GTK_CONTAINER (widget)->border_width) * 2;
5096 requisition->height += (clist->column_title_area.height +
5097 (widget->style->klass->ythickness +
5098 GTK_CONTAINER (widget)->border_width) * 2);
5100 if (!clist->hadjustment)
5101 requisition->width += list_requisition_width (clist);
5102 if (!clist->vadjustment)
5103 requisition->height += LIST_HEIGHT (clist);
5107 gtk_clist_size_allocate (GtkWidget *widget,
5108 GtkAllocation *allocation)
5111 GtkAllocation clist_allocation;
5114 g_return_if_fail (widget != NULL);
5115 g_return_if_fail (GTK_IS_CLIST (widget));
5116 g_return_if_fail (allocation != NULL);
5118 clist = GTK_CLIST (widget);
5119 widget->allocation = *allocation;
5120 border_width = GTK_CONTAINER (widget)->border_width;
5122 if (GTK_WIDGET_REALIZED (widget))
5124 gdk_window_move_resize (widget->window,
5125 allocation->x + border_width,
5126 allocation->y + border_width,
5127 allocation->width - border_width * 2,
5128 allocation->height - border_width * 2);
5131 /* use internal allocation structure for all the math
5132 * because it's easier than always subtracting the container
5134 clist->internal_allocation.x = 0;
5135 clist->internal_allocation.y = 0;
5136 clist->internal_allocation.width = MAX (1, allocation->width -
5138 clist->internal_allocation.height = MAX (1, allocation->height -
5141 /* allocate clist window assuming no scrollbars */
5142 clist_allocation.x = (clist->internal_allocation.x +
5143 widget->style->klass->xthickness);
5144 clist_allocation.y = (clist->internal_allocation.y +
5145 widget->style->klass->ythickness +
5146 clist->column_title_area.height);
5147 clist_allocation.width = MAX (1, clist->internal_allocation.width -
5148 (2 * widget->style->klass->xthickness));
5149 clist_allocation.height = MAX (1, clist->internal_allocation.height -
5150 (2 * widget->style->klass->ythickness) -
5151 clist->column_title_area.height);
5153 clist->clist_window_width = clist_allocation.width;
5154 clist->clist_window_height = clist_allocation.height;
5156 if (GTK_WIDGET_REALIZED (widget))
5158 gdk_window_move_resize (clist->clist_window,
5161 clist_allocation.width,
5162 clist_allocation.height);
5165 /* position the window which holds the column title buttons */
5166 clist->column_title_area.x = widget->style->klass->xthickness;
5167 clist->column_title_area.y = widget->style->klass->ythickness;
5168 clist->column_title_area.width = clist_allocation.width;
5170 if (GTK_WIDGET_REALIZED (widget))
5172 gdk_window_move_resize (clist->title_window,
5173 clist->column_title_area.x,
5174 clist->column_title_area.y,
5175 clist->column_title_area.width,
5176 clist->column_title_area.height);
5179 /* column button allocation */
5180 size_allocate_columns (clist);
5181 size_allocate_title_buttons (clist);
5183 adjust_adjustments (clist, TRUE);
5190 gtk_clist_forall (GtkContainer *container,
5191 gboolean include_internals,
5192 GtkCallback callback,
5193 gpointer callback_data)
5198 g_return_if_fail (container != NULL);
5199 g_return_if_fail (GTK_IS_CLIST (container));
5200 g_return_if_fail (callback != NULL);
5202 if (!include_internals)
5205 clist = GTK_CLIST (container);
5207 /* callback for the column buttons */
5208 for (i = 0; i < clist->columns; i++)
5209 if (clist->column[i].button)
5210 (*callback) (clist->column[i].button, callback_data);
5213 /* PRIVATE DRAWING FUNCTIONS
5221 get_cell_style (GtkCList *clist,
5222 GtkCListRow *clist_row,
5229 if (clist_row->cell[column].style)
5232 *style = clist_row->cell[column].style;
5234 *fg_gc = clist_row->cell[column].style->fg_gc[state];
5236 *bg_gc = clist_row->cell[column].style->bg_gc[state];
5238 else if (clist_row->style)
5241 *style = clist_row->style;
5243 *fg_gc = clist_row->style->fg_gc[state];
5245 *bg_gc = clist_row->style->bg_gc[state];
5250 *style = GTK_WIDGET (clist)->style;
5252 *fg_gc = GTK_WIDGET (clist)->style->fg_gc[state];
5254 *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
5256 if (state != GTK_STATE_SELECTED)
5258 if (fg_gc && clist_row->fg_set)
5259 *fg_gc = clist->fg_gc;
5260 if (bg_gc && clist_row->bg_set)
5261 *bg_gc = clist->bg_gc;
5267 draw_cell_pixmap (GdkWindow *window,
5268 GdkRectangle *clip_rectangle,
5282 gdk_gc_set_clip_mask (fg_gc, mask);
5283 gdk_gc_set_clip_origin (fg_gc, x, y);
5286 if (x < clip_rectangle->x)
5288 xsrc = clip_rectangle->x - x;
5290 x = clip_rectangle->x;
5292 if (x + width > clip_rectangle->x + clip_rectangle->width)
5293 width = clip_rectangle->x + clip_rectangle->width - x;
5295 if (y < clip_rectangle->y)
5297 ysrc = clip_rectangle->y - y;
5299 y = clip_rectangle->y;
5301 if (y + height > clip_rectangle->y + clip_rectangle->height)
5302 height = clip_rectangle->y + clip_rectangle->height - y;
5304 gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
5305 gdk_gc_set_clip_origin (fg_gc, 0, 0);
5307 return x + MAX (width, 0);
5311 draw_row (GtkCList *clist,
5314 GtkCListRow *clist_row)
5318 GdkRectangle row_rectangle;
5319 GdkRectangle cell_rectangle;
5320 GdkRectangle clip_rectangle;
5321 GdkRectangle intersect_rectangle;
5325 g_return_if_fail (clist != NULL);
5327 /* bail now if we arn't drawable yet */
5328 if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows)
5331 widget = GTK_WIDGET (clist);
5333 /* if the function is passed the pointer to the row instead of null,
5334 * it avoids this expensive lookup */
5336 clist_row = (g_list_nth (clist->row_list, row))->data;
5338 /* rectangle of the entire row */
5339 row_rectangle.x = 0;
5340 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
5341 row_rectangle.width = clist->clist_window_width;
5342 row_rectangle.height = clist->row_height;
5344 /* rectangle of the cell spacing above the row */
5345 cell_rectangle.x = 0;
5346 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
5347 cell_rectangle.width = row_rectangle.width;
5348 cell_rectangle.height = CELL_SPACING;
5350 /* rectangle used to clip drawing operations, it's y and height
5351 * positions only need to be set once, so we set them once here.
5352 * the x and width are set withing the drawing loop below once per
5354 clip_rectangle.y = row_rectangle.y;
5355 clip_rectangle.height = row_rectangle.height;
5357 if (clist_row->state == GTK_STATE_NORMAL)
5359 state = GTK_STATE_PRELIGHT;
5360 if (clist_row->fg_set)
5361 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
5362 if (clist_row->bg_set)
5363 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
5366 state = clist_row->state;
5368 /* draw the cell borders and background */
5371 rect = &intersect_rectangle;
5372 if (gdk_rectangle_intersect (area, &cell_rectangle,
5373 &intersect_rectangle))
5374 gdk_draw_rectangle (clist->clist_window,
5375 widget->style->base_gc[GTK_STATE_NORMAL],
5377 intersect_rectangle.x,
5378 intersect_rectangle.y,
5379 intersect_rectangle.width,
5380 intersect_rectangle.height);
5382 /* the last row has to clear it's bottom cell spacing too */
5383 if (clist_row == clist->row_list_end->data)
5385 cell_rectangle.y += clist->row_height + CELL_SPACING;
5387 if (gdk_rectangle_intersect (area, &cell_rectangle,
5388 &intersect_rectangle))
5389 gdk_draw_rectangle (clist->clist_window,
5390 widget->style->base_gc[GTK_STATE_NORMAL],
5392 intersect_rectangle.x,
5393 intersect_rectangle.y,
5394 intersect_rectangle.width,
5395 intersect_rectangle.height);
5398 if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle))
5404 rect = &clip_rectangle;
5405 gdk_draw_rectangle (clist->clist_window,
5406 widget->style->base_gc[GTK_STATE_NORMAL],
5410 cell_rectangle.width,
5411 cell_rectangle.height);
5413 /* the last row has to clear it's bottom cell spacing too */
5414 if (clist_row == clist->row_list_end->data)
5416 cell_rectangle.y += clist->row_height + CELL_SPACING;
5418 gdk_draw_rectangle (clist->clist_window,
5419 widget->style->base_gc[GTK_STATE_NORMAL],
5423 cell_rectangle.width,
5424 cell_rectangle.height);
5428 /* iterate and draw all the columns (row cells) and draw their contents */
5429 for (i = 0; i < clist->columns; i++)
5439 gint row_center_offset;
5441 if (!clist->column[i].visible)
5444 get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
5446 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
5447 clip_rectangle.width = clist->column[i].area.width;
5449 /* calculate clipping region clipping region */
5450 clip_rectangle.x -= COLUMN_INSET + CELL_SPACING;
5451 clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING +
5452 (i + 1 == clist->columns) * CELL_SPACING);
5454 if (area && !gdk_rectangle_intersect (area, &clip_rectangle,
5455 &intersect_rectangle))
5458 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
5459 rect->x, rect->y, rect->width, rect->height);
5461 clip_rectangle.x += COLUMN_INSET + CELL_SPACING;
5462 clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING +
5463 (i + 1 == clist->columns) * CELL_SPACING);
5465 /* calculate real width for column justification */
5468 switch (clist_row->cell[i].type)
5471 width = gdk_string_width (style->font,
5472 GTK_CELL_TEXT (clist_row->cell[i])->text);
5474 case GTK_CELL_PIXMAP:
5475 gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
5476 &pixmap_width, &height);
5477 width = pixmap_width;
5479 case GTK_CELL_PIXTEXT:
5480 gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
5481 &pixmap_width, &height);
5482 width = (pixmap_width +
5483 GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing +
5484 gdk_string_width (style->font,
5486 (clist_row->cell[i])->text));
5493 switch (clist->column[i].justification)
5495 case GTK_JUSTIFY_LEFT:
5496 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
5498 case GTK_JUSTIFY_RIGHT:
5499 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5500 clip_rectangle.width - width);
5502 case GTK_JUSTIFY_CENTER:
5503 case GTK_JUSTIFY_FILL:
5504 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5505 (clip_rectangle.width / 2) - (width / 2));
5509 /* Draw Text and/or Pixmap */
5510 switch (clist_row->cell[i].type)
5512 case GTK_CELL_PIXMAP:
5513 draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
5514 GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
5515 GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
5517 clip_rectangle.y + clist_row->cell[i].vertical +
5518 (clip_rectangle.height - height) / 2,
5519 pixmap_width, height);
5521 case GTK_CELL_PIXTEXT:
5523 draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
5524 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
5525 GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
5527 clip_rectangle.y + clist_row->cell[i].vertical+
5528 (clip_rectangle.height - height) / 2,
5529 pixmap_width, height);
5530 offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
5532 if (style != GTK_WIDGET (clist)->style)
5533 row_center_offset = (((clist->row_height - style->font->ascent -
5534 style->font->descent - 1) / 2) + 1.5 +
5535 style->font->ascent);
5537 row_center_offset = clist->row_center_offset;
5539 gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
5540 gdk_draw_string (clist->clist_window, style->font, fg_gc,
5542 row_rectangle.y + row_center_offset +
5543 clist_row->cell[i].vertical,
5544 (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ?
5545 GTK_CELL_PIXTEXT (clist_row->cell[i])->text :
5546 GTK_CELL_TEXT (clist_row->cell[i])->text);
5547 gdk_gc_set_clip_rectangle (fg_gc, NULL);
5554 /* draw focus rectangle */
5555 if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
5558 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5559 row_rectangle.x, row_rectangle.y,
5560 row_rectangle.width - 1, row_rectangle.height - 1);
5561 else if (gdk_rectangle_intersect (area, &row_rectangle,
5562 &intersect_rectangle))
5564 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
5565 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5566 row_rectangle.x, row_rectangle.y,
5567 row_rectangle.width - 1,
5568 row_rectangle.height - 1);
5569 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
5575 draw_rows (GtkCList *clist,
5579 GtkCListRow *clist_row;
5584 g_return_if_fail (clist != NULL);
5585 g_return_if_fail (GTK_IS_CLIST (clist));
5587 if (clist->row_height == 0 ||
5588 !GTK_WIDGET_DRAWABLE (clist))
5593 first_row = ROW_FROM_YPIXEL (clist, area->y);
5594 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
5598 first_row = ROW_FROM_YPIXEL (clist, 0);
5599 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
5602 /* this is a small special case which exposes the bottom cell line
5603 * on the last row -- it might go away if I change the wall the cell
5604 * spacings are drawn
5606 if (clist->rows == first_row)
5609 list = g_list_nth (clist->row_list, first_row);
5613 clist_row = list->data;
5619 GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row);
5624 gdk_window_clear_area (clist->clist_window,
5625 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
5629 draw_xor_line (GtkCList *clist)
5633 g_return_if_fail (clist != NULL);
5635 widget = GTK_WIDGET (clist);
5637 gdk_draw_line (widget->window, clist->xor_gc,
5639 widget->style->klass->ythickness,
5641 clist->column_title_area.height +
5642 clist->clist_window_height + 1);
5645 /* get cell from coordinates
5646 * get_selection_info
5647 * gtk_clist_get_selection_info
5650 get_selection_info (GtkCList *clist,
5658 g_return_val_if_fail (clist != NULL, 0);
5659 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
5661 /* bounds checking, return false if the user clicked
5662 * on a blank area */
5663 trow = ROW_FROM_YPIXEL (clist, y);
5664 if (trow >= clist->rows)
5670 tcol = COLUMN_FROM_XPIXEL (clist, x);
5671 if (tcol >= clist->columns)
5681 gtk_clist_get_selection_info (GtkCList *clist,
5687 g_return_val_if_fail (clist != NULL, 0);
5688 g_return_val_if_fail (GTK_IS_CLIST (clist), 0);
5689 return get_selection_info (clist, x, y, row, column);
5696 * adjust_adjustments
5697 * vadjustment_changed
5698 * hadjustment_changed
5699 * vadjustment_value_changed
5700 * hadjustment_value_changed
5704 adjust_adjustments (GtkCList *clist,
5705 gboolean block_resize)
5707 if (clist->vadjustment)
5709 clist->vadjustment->page_size = clist->clist_window_height;
5710 clist->vadjustment->page_increment = clist->clist_window_height / 2;
5711 clist->vadjustment->step_increment = clist->row_height;
5712 clist->vadjustment->lower = 0;
5713 clist->vadjustment->upper = LIST_HEIGHT (clist);
5715 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
5717 clist->vadjustment->value = MAX (0, (LIST_HEIGHT (clist) -
5718 clist->clist_window_height));
5719 gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment),
5722 gtk_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), "changed");
5725 if (clist->hadjustment)
5727 clist->hadjustment->page_size = clist->clist_window_width;
5728 clist->hadjustment->page_increment = clist->clist_window_width / 2;
5729 clist->hadjustment->step_increment = 10;
5730 clist->hadjustment->lower = 0;
5731 clist->hadjustment->upper = LIST_WIDTH (clist);
5733 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
5735 clist->hadjustment->value = MAX (0, (LIST_WIDTH (clist) -
5736 clist->clist_window_width));
5737 gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment),
5740 gtk_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), "changed");
5743 if (!block_resize && (!clist->vadjustment || !clist->hadjustment))
5747 widget = GTK_WIDGET (clist);
5748 gtk_widget_size_request (widget, &widget->requisition);
5750 if ((!clist->hadjustment &&
5751 widget->requisition.width != widget->allocation.width) ||
5752 (!clist->vadjustment &&
5753 widget->requisition.height != widget->allocation.height))
5754 gtk_widget_queue_resize (widget);
5759 vadjustment_changed (GtkAdjustment *adjustment,
5764 g_return_if_fail (adjustment != NULL);
5765 g_return_if_fail (data != NULL);
5767 clist = GTK_CLIST (data);
5771 hadjustment_changed (GtkAdjustment *adjustment,
5776 g_return_if_fail (adjustment != NULL);
5777 g_return_if_fail (data != NULL);
5779 clist = GTK_CLIST (data);
5783 vadjustment_value_changed (GtkAdjustment *adjustment,
5790 g_return_if_fail (adjustment != NULL);
5791 g_return_if_fail (data != NULL);
5792 g_return_if_fail (GTK_IS_CLIST (data));
5794 clist = GTK_CLIST (data);
5796 if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->vadjustment)
5799 value = adjustment->value;
5801 if (value > -clist->voffset)
5804 diff = value + clist->voffset;
5806 /* we have to re-draw the whole screen here... */
5807 if (diff >= clist->clist_window_height)
5809 clist->voffset = -value;
5810 draw_rows (clist, NULL);
5814 if ((diff != 0) && (diff != clist->clist_window_height))
5815 gdk_window_copy_area (clist->clist_window, clist->fg_gc,
5816 0, 0, clist->clist_window, 0, diff,
5817 clist->clist_window_width,
5818 clist->clist_window_height - diff);
5821 area.y = clist->clist_window_height - diff;
5822 area.width = clist->clist_window_width;
5828 diff = -clist->voffset - value;
5830 /* we have to re-draw the whole screen here... */
5831 if (diff >= clist->clist_window_height)
5833 clist->voffset = -value;
5834 draw_rows (clist, NULL);
5838 if ((diff != 0) && (diff != clist->clist_window_height))
5839 gdk_window_copy_area (clist->clist_window, clist->fg_gc,
5840 0, diff, clist->clist_window, 0, 0,
5841 clist->clist_window_width,
5842 clist->clist_window_height - diff);
5846 area.width = clist->clist_window_width;
5850 clist->voffset = -value;
5851 if ((diff != 0) && (diff != clist->clist_window_height))
5852 check_exposures (clist);
5854 draw_rows (clist, &area);
5858 hadjustment_value_changed (GtkAdjustment *adjustment,
5868 g_return_if_fail (adjustment != NULL);
5869 g_return_if_fail (data != NULL);
5870 g_return_if_fail (GTK_IS_CLIST (data));
5872 clist = GTK_CLIST (data);
5874 if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->hadjustment)
5877 value = adjustment->value;
5879 /* move the column buttons and resize windows */
5880 for (i = 0; i < clist->columns; i++)
5882 if (clist->column[i].button)
5884 clist->column[i].button->allocation.x -= value + clist->hoffset;
5886 if (clist->column[i].button->window)
5888 gdk_window_move (clist->column[i].button->window,
5889 clist->column[i].button->allocation.x,
5890 clist->column[i].button->allocation.y);
5892 if (clist->column[i].window)
5893 gdk_window_move (clist->column[i].window,
5894 clist->column[i].button->allocation.x +
5895 clist->column[i].button->allocation.width -
5896 (DRAG_WIDTH / 2), 0);
5901 if (value > -clist->hoffset)
5904 diff = value + clist->hoffset;
5906 clist->hoffset = -value;
5908 /* we have to re-draw the whole screen here... */
5909 if (diff >= clist->clist_window_width)
5911 draw_rows (clist, NULL);
5915 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5916 GTK_CLIST_ADD_MODE (clist))
5918 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
5920 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
5921 clist->clist_window_width - 1,
5922 clist->row_height - 1);
5924 gdk_window_copy_area (clist->clist_window,
5927 clist->clist_window,
5930 clist->clist_window_width - diff,
5931 clist->clist_window_height);
5933 area.x = clist->clist_window_width - diff;
5938 if (!(diff = -clist->hoffset - value))
5941 clist->hoffset = -value;
5943 /* we have to re-draw the whole screen here... */
5944 if (diff >= clist->clist_window_width)
5946 draw_rows (clist, NULL);
5950 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) &&
5951 GTK_CLIST_ADD_MODE (clist))
5953 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
5955 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
5956 clist->clist_window_width - 1,
5957 clist->row_height - 1);
5960 gdk_window_copy_area (clist->clist_window,
5963 clist->clist_window,
5966 clist->clist_window_width - diff,
5967 clist->clist_window_height);
5974 area.height = clist->clist_window_height;
5976 check_exposures (clist);
5978 if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist))
5980 if (GTK_CLIST_ADD_MODE (clist))
5984 focus_row = clist->focus_row;
5985 clist->focus_row = -1;
5986 draw_rows (clist, &area);
5987 clist->focus_row = focus_row;
5989 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
5990 FALSE, 0, y, clist->clist_window_width - 1,
5991 clist->row_height - 1);
6001 x0 = clist->clist_window_width - 1;
6010 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
6011 gdk_draw_line (clist->clist_window, clist->xor_gc,
6012 x0, y + 1, x0, y + clist->row_height - 2);
6013 gdk_draw_line (clist->clist_window, clist->xor_gc,
6014 x1, y + 1, x1, y + clist->row_height - 2);
6018 draw_rows (clist, &area);
6022 check_exposures (GtkCList *clist)
6026 if (!GTK_WIDGET_REALIZED (clist))
6029 /* Make sure graphics expose events are processed before scrolling
6031 while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
6033 gtk_widget_event (GTK_WIDGET (clist), event);
6034 if (event->expose.count == 0)
6036 gdk_event_free (event);
6039 gdk_event_free (event);
6044 * Memory Allocation/Distruction Routines for GtkCList stuctures
6053 static GtkCListColumn *
6054 columns_new (GtkCList *clist)
6056 GtkCListColumn *column;
6059 column = g_new (GtkCListColumn, clist->columns);
6061 for (i = 0; i < clist->columns; i++)
6063 column[i].area.x = 0;
6064 column[i].area.y = 0;
6065 column[i].area.width = 0;
6066 column[i].area.height = 0;
6067 column[i].title = NULL;
6068 column[i].button = NULL;
6069 column[i].window = NULL;
6070 column[i].width = 0;
6071 column[i].min_width = -1;
6072 column[i].max_width = -1;
6073 column[i].visible = TRUE;
6074 column[i].width_set = FALSE;
6075 column[i].resizeable = TRUE;
6076 column[i].auto_resize = FALSE;
6077 column[i].justification = GTK_JUSTIFY_LEFT;
6084 column_title_new (GtkCList *clist,
6088 if (clist->column[column].title)
6089 g_free (clist->column[column].title);
6091 clist->column[column].title = g_strdup (title);
6095 columns_delete (GtkCList *clist)
6099 for (i = 0; i < clist->columns; i++)
6100 if (clist->column[i].title)
6101 g_free (clist->column[i].title);
6103 g_free (clist->column);
6106 static GtkCListRow *
6107 row_new (GtkCList *clist)
6110 GtkCListRow *clist_row;
6112 clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
6113 clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
6115 for (i = 0; i < clist->columns; i++)
6117 clist_row->cell[i].type = GTK_CELL_EMPTY;
6118 clist_row->cell[i].vertical = 0;
6119 clist_row->cell[i].horizontal = 0;
6120 clist_row->cell[i].style = NULL;
6123 clist_row->fg_set = FALSE;
6124 clist_row->bg_set = FALSE;
6125 clist_row->style = NULL;
6126 clist_row->selectable = TRUE;
6127 clist_row->state = GTK_STATE_NORMAL;
6128 clist_row->data = NULL;
6129 clist_row->destroy = NULL;
6135 row_delete (GtkCList *clist,
6136 GtkCListRow *clist_row)
6140 for (i = 0; i < clist->columns; i++)
6142 GTK_CLIST_CLASS_FW (clist)->set_cell_contents
6143 (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
6144 if (clist_row->cell[i].style)
6146 if (GTK_WIDGET_REALIZED (clist))
6147 gtk_style_detach (clist_row->cell[i].style);
6148 gtk_style_unref (clist_row->cell[i].style);
6152 if (clist_row->style)
6154 if (GTK_WIDGET_REALIZED (clist))
6155 gtk_style_detach (clist_row->style);
6156 gtk_style_unref (clist_row->style);
6159 if (clist_row->destroy)
6160 clist_row->destroy (clist_row->data);
6162 g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
6163 g_mem_chunk_free (clist->row_mem_chunk, clist_row);
6168 * gtk_clist_draw_focus
6169 * gtk_clist_focus_in
6170 * gtk_clist_focus_out
6171 * gtk_clist_set_focus_child
6175 gtk_clist_focus (GtkContainer *container,
6176 GtkDirectionType direction)
6179 GtkWidget *focus_child;
6182 g_return_val_if_fail (container != NULL, FALSE);
6183 g_return_val_if_fail (GTK_IS_CLIST (container), FALSE);
6185 if (!GTK_WIDGET_SENSITIVE (container))
6188 clist = GTK_CLIST (container);
6189 focus_child = container->focus_child;
6190 old_row = clist->focus_row;
6196 if (GTK_CLIST_CHILD_HAS_FOCUS (clist))
6198 if (title_focus (clist, direction))
6200 gtk_container_set_focus_child (container, NULL);
6203 gtk_widget_grab_focus (GTK_WIDGET (container));
6206 case GTK_DIR_TAB_FORWARD:
6207 if (GTK_CLIST_CHILD_HAS_FOCUS (clist))
6209 gboolean tf = FALSE;
6211 if (((focus_child && direction == GTK_DIR_DOWN) ||
6212 !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD)))
6215 if (clist->focus_row < 0)
6217 clist->focus_row = 0;
6219 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6220 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6222 gtk_signal_emit (GTK_OBJECT (clist),
6223 clist_signals[SELECT_ROW],
6224 clist->focus_row, -1, NULL);
6226 gtk_widget_grab_focus (GTK_WIDGET (container));
6234 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6237 case GTK_DIR_TAB_BACKWARD:
6239 GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows)
6241 if (clist->focus_row < 0)
6243 clist->focus_row = 0;
6244 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6245 clist->selection_mode == GTK_SELECTION_EXTENDED) &&
6247 gtk_signal_emit (GTK_OBJECT (clist),
6248 clist_signals[SELECT_ROW],
6249 clist->focus_row, -1, NULL);
6251 gtk_widget_grab_focus (GTK_WIDGET (container));
6255 GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS);
6257 if (title_focus (clist, direction))
6265 gtk_container_set_focus_child (container, NULL);
6270 gtk_clist_draw_focus (GtkWidget *widget)
6274 g_return_if_fail (widget != NULL);
6275 g_return_if_fail (GTK_IS_CLIST (widget));
6277 if (!GTK_WIDGET_DRAWABLE (widget))
6280 clist = GTK_CLIST (widget);
6281 if (clist->focus_row >= 0)
6282 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
6283 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
6284 clist->clist_window_width - 1,
6285 clist->row_height - 1);
6289 gtk_clist_focus_in (GtkWidget *widget,
6290 GdkEventFocus *event)
6294 g_return_val_if_fail (widget != NULL, FALSE);
6295 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
6296 g_return_val_if_fail (event != NULL, FALSE);
6298 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
6299 GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS);
6301 clist = GTK_CLIST (widget);
6303 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
6304 clist->selection == NULL && clist->focus_row > -1)
6308 list = g_list_nth (clist->row_list, clist->focus_row);
6309 if (list && GTK_CLIST_ROW (list)->selectable)
6310 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6311 clist->focus_row, -1, event);
6313 gtk_widget_draw_focus (widget);
6316 gtk_widget_draw_focus (widget);
6322 gtk_clist_focus_out (GtkWidget *widget,
6323 GdkEventFocus *event)
6327 g_return_val_if_fail (widget != NULL, FALSE);
6328 g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
6329 g_return_val_if_fail (event != NULL, FALSE);
6331 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
6332 gtk_widget_draw_focus (widget);
6334 clist = GTK_CLIST (widget);
6336 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6337 GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event);
6343 gtk_clist_set_focus_child (GtkContainer *container,
6346 g_return_if_fail (container != NULL);
6347 g_return_if_fail (GTK_IS_CLIST (container));
6351 g_return_if_fail (GTK_IS_WIDGET (child));
6352 GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS);
6355 parent_class->set_focus_child (container, child);
6359 title_focus (GtkCList *clist,
6362 GtkWidget *focus_child;
6363 gboolean return_val = FALSE;
6368 if (!GTK_CLIST_SHOW_TITLES (clist))
6371 focus_child = GTK_CONTAINER (clist)->focus_child;
6375 case GTK_DIR_TAB_BACKWARD:
6377 if (!focus_child || !GTK_CLIST_CHILD_HAS_FOCUS (clist))
6379 if (dir == GTK_DIR_UP)
6380 i = COLUMN_FROM_XPIXEL (clist, 0);
6382 i = clist->columns - 1;
6383 focus_child = clist->column[i].button;
6384 dir = GTK_DIR_TAB_FORWARD;
6393 i = clist->columns - 1;
6394 focus_child = clist->column[i].button;
6401 focus_child = clist->column[i].button;
6407 while (i < clist->columns)
6409 if (clist->column[i].button == focus_child)
6411 if (clist->column[i].button &&
6412 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
6413 GTK_IS_CONTAINER (clist->column[i].button) &&
6414 !GTK_WIDGET_HAS_FOCUS (clist->column[i].button))
6415 if (gtk_container_focus
6416 (GTK_CONTAINER (clist->column[i].button), dir))
6421 if (!return_val && dir == GTK_DIR_UP)
6432 while (j >= 0 && j < clist->columns)
6434 if (clist->column[j].button &&
6435 GTK_WIDGET_VISIBLE (clist->column[j].button))
6437 if (GTK_IS_CONTAINER (clist->column[j].button) &&
6439 (GTK_CONTAINER (clist->column[j].button), dir))
6444 else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button))
6446 gtk_widget_grab_focus (clist->column[j].button);
6456 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
6457 gtk_clist_moveto (clist, -1, j, 0, 0);
6458 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
6459 clist->clist_window_width)
6461 if (j == clist->columns-1)
6462 gtk_clist_moveto (clist, -1, j, 0, 0);
6464 gtk_clist_moveto (clist, -1, j, 0, 1);
6470 /* SCROLLING FUNCTIONS
6476 move_focus_row (GtkCList *clist,
6477 GtkScrollType scroll_type,
6482 g_return_if_fail (clist != 0);
6483 g_return_if_fail (GTK_IS_CLIST (clist));
6485 widget = GTK_WIDGET (clist);
6487 switch (scroll_type)
6489 case GTK_SCROLL_STEP_BACKWARD:
6490 if (clist->focus_row <= 0)
6492 gtk_clist_draw_focus (widget);
6494 gtk_clist_draw_focus (widget);
6496 case GTK_SCROLL_STEP_FORWARD:
6497 if (clist->focus_row >= clist->rows - 1)
6499 gtk_clist_draw_focus (widget);
6501 gtk_clist_draw_focus (widget);
6503 case GTK_SCROLL_PAGE_BACKWARD:
6504 if (clist->focus_row <= 0)
6506 gtk_clist_draw_focus (widget);
6507 clist->focus_row = MAX (0, clist->focus_row -
6508 (2 * clist->clist_window_height -
6509 clist->row_height - CELL_SPACING) /
6510 (2 * (clist->row_height + CELL_SPACING)));
6511 gtk_clist_draw_focus (widget);
6513 case GTK_SCROLL_PAGE_FORWARD:
6514 if (clist->focus_row >= clist->rows - 1)
6516 gtk_clist_draw_focus (widget);
6517 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
6518 (2 * clist->clist_window_height -
6519 clist->row_height - CELL_SPACING) /
6520 (2 * (clist->row_height + CELL_SPACING)));
6521 gtk_clist_draw_focus (widget);
6523 case GTK_SCROLL_JUMP:
6524 if (position >= 0 && position <= 1)
6526 gtk_clist_draw_focus (widget);
6527 clist->focus_row = position * (clist->rows - 1);
6528 gtk_clist_draw_focus (widget);
6537 scroll_horizontal (GtkCList *clist,
6538 GtkScrollType scroll_type,
6543 g_return_if_fail (clist != 0);
6544 g_return_if_fail (GTK_IS_CLIST (clist));
6546 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6549 switch (scroll_type)
6551 case GTK_SCROLL_STEP_BACKWARD:
6552 column = COLUMN_FROM_XPIXEL (clist, 0);
6553 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
6557 case GTK_SCROLL_STEP_FORWARD:
6558 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
6561 if (COLUMN_LEFT_XPIXEL (clist, column) +
6562 clist->column[column].area.width +
6563 CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
6564 column < clist->columns - 1)
6567 case GTK_SCROLL_PAGE_BACKWARD:
6568 case GTK_SCROLL_PAGE_FORWARD:
6570 case GTK_SCROLL_JUMP:
6571 if (position >= 0 && position <= 1)
6572 column = position * (clist->columns - 1);
6580 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
6581 gtk_clist_moveto (clist, -1, column, 0, 0);
6582 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
6583 + clist->column[column].area.width > clist->clist_window_width)
6585 if (column == clist->columns - 1)
6586 gtk_clist_moveto (clist, -1, column, 0, 0);
6588 gtk_clist_moveto (clist, -1, column, 0, 1);
6593 scroll_vertical (GtkCList *clist,
6594 GtkScrollType scroll_type,
6599 g_return_if_fail (clist != NULL);
6600 g_return_if_fail (GTK_IS_CLIST (clist));
6602 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6605 switch (clist->selection_mode)
6607 case GTK_SELECTION_EXTENDED:
6608 if (clist->anchor >= 0)
6610 case GTK_SELECTION_BROWSE:
6612 old_focus_row = clist->focus_row;
6613 move_focus_row (clist, scroll_type, position);
6615 if (old_focus_row != clist->focus_row)
6617 if (clist->selection_mode == GTK_SELECTION_BROWSE)
6618 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
6619 old_focus_row, -1, NULL);
6620 else if (!GTK_CLIST_ADD_MODE (clist))
6622 gtk_clist_unselect_all (clist);
6623 clist->undo_anchor = old_focus_row;
6627 switch (gtk_clist_row_is_visible (clist, clist->focus_row))
6629 case GTK_VISIBILITY_NONE:
6630 if (old_focus_row != clist->focus_row &&
6631 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
6632 GTK_CLIST_ADD_MODE (clist)))
6633 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6634 clist->focus_row, -1, NULL);
6635 switch (scroll_type)
6637 case GTK_SCROLL_STEP_BACKWARD:
6638 case GTK_SCROLL_PAGE_BACKWARD:
6639 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6641 case GTK_SCROLL_STEP_FORWARD:
6642 case GTK_SCROLL_PAGE_FORWARD:
6643 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6645 case GTK_SCROLL_JUMP:
6646 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
6652 case GTK_VISIBILITY_PARTIAL:
6653 switch (scroll_type)
6655 case GTK_SCROLL_STEP_BACKWARD:
6656 case GTK_SCROLL_PAGE_BACKWARD:
6657 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6659 case GTK_SCROLL_STEP_FORWARD:
6660 case GTK_SCROLL_PAGE_FORWARD:
6661 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6663 case GTK_SCROLL_JUMP:
6664 gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0);
6670 if (old_focus_row != clist->focus_row &&
6671 !(clist->selection_mode == GTK_SELECTION_EXTENDED &&
6672 GTK_CLIST_ADD_MODE (clist)))
6673 gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
6674 clist->focus_row, -1, NULL);
6679 move_focus_row (clist, scroll_type, position);
6681 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
6682 clist->clist_window_height)
6683 gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
6684 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
6685 gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
6690 /* PUBLIC SORTING FUNCTIONS
6692 * gtk_clist_set_compare_func
6693 * gtk_clist_set_auto_sort
6694 * gtk_clist_set_sort_type
6695 * gtk_clist_set_sort_column
6698 gtk_clist_sort (GtkCList *clist)
6700 g_return_if_fail (clist != NULL);
6701 g_return_if_fail (GTK_IS_CLIST (clist));
6703 GTK_CLIST_CLASS_FW (clist)->sort_list (clist);
6707 gtk_clist_set_compare_func (GtkCList *clist,
6708 GtkCListCompareFunc cmp_func)
6710 g_return_if_fail (clist != NULL);
6711 g_return_if_fail (GTK_IS_CLIST (clist));
6713 clist->compare = (cmp_func) ? cmp_func : default_compare;
6717 gtk_clist_set_auto_sort (GtkCList *clist,
6720 g_return_if_fail (clist != NULL);
6721 g_return_if_fail (GTK_IS_CLIST (clist));
6723 if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort)
6724 GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT);
6725 else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort)
6727 GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT);
6728 gtk_clist_sort (clist);
6733 gtk_clist_set_sort_type (GtkCList *clist,
6734 GtkSortType sort_type)
6736 g_return_if_fail (clist != NULL);
6737 g_return_if_fail (GTK_IS_CLIST (clist));
6739 clist->sort_type = sort_type;
6743 gtk_clist_set_sort_column (GtkCList *clist,
6746 g_return_if_fail (clist != NULL);
6747 g_return_if_fail (GTK_IS_CLIST (clist));
6749 if (column < 0 || column >= clist->columns)
6752 clist->sort_column = column;
6755 /* PRIVATE SORTING FUNCTIONS
6759 * gtk_clist_mergesort
6762 default_compare (GtkCList *clist,
6769 GtkCListRow *row1 = (GtkCListRow *) ptr1;
6770 GtkCListRow *row2 = (GtkCListRow *) ptr2;
6772 switch (row1->cell[clist->sort_column].type)
6775 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
6777 case GTK_CELL_PIXTEXT:
6778 text1 = GTK_CELL_PIXTEXT (row1->cell[clist->sort_column])->text;
6784 switch (row2->cell[clist->sort_column].type)
6787 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
6789 case GTK_CELL_PIXTEXT:
6790 text2 = GTK_CELL_PIXTEXT (row2->cell[clist->sort_column])->text;
6797 return (text1 != NULL);
6802 return strcmp (text1, text2);
6806 real_sort_list (GtkCList *clist)
6811 gboolean thaw = FALSE;
6813 g_return_if_fail (clist != NULL);
6814 g_return_if_fail (GTK_IS_CLIST (clist));
6816 if (clist->rows <= 1)
6819 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))
6822 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED)
6824 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
6825 g_list_free (clist->undo_selection);
6826 g_list_free (clist->undo_unselection);
6827 clist->undo_selection = NULL;
6828 clist->undo_unselection = NULL;
6831 if (!GTK_CLIST_FROZEN (clist))
6833 gtk_clist_freeze (clist);
6837 clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows);
6839 work = clist->selection;
6841 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
6843 if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED)
6845 work->data = GINT_TO_POINTER (i);
6849 if (i == clist->rows - 1)
6850 clist->row_list_end = list;
6854 gtk_clist_thaw (clist);
6858 gtk_clist_merge (GtkCList *clist,
6859 GList *a, /* first list to merge */
6860 GList *b) /* second list to merge */
6862 GList z = { 0 }; /* auxiliary node */
6888 cmp = clist->compare (clist, GTK_CLIST_ROW (a), GTK_CLIST_ROW (b));
6889 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
6890 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
6912 gtk_clist_mergesort (GtkCList *clist,
6913 GList *list, /* the list to sort */
6914 gint num) /* the list's length */
6925 /* move "half" to the middle */
6927 for (i = 0; i < num / 2; i++)
6930 /* cut the list in two */
6931 half->prev->next = NULL;
6934 /* recursively sort both lists */
6935 return gtk_clist_merge (clist,
6936 gtk_clist_mergesort (clist, list, num / 2),
6937 gtk_clist_mergesort (clist, half, num - num / 2));