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 Lesser 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 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser 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 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #include "claws-marshal.h"
35 #include "gtkcmclist.h"
36 #include <gdk/gdkkeysyms.h>
39 #if !GTK_CHECK_VERSION(2,10,0)
40 #define gdk_atom_intern_static_string(str) gdk_atom_intern(str, FALSE)
43 /* length of button_actions array */
46 /* the number rows memchunk expands at a time */
47 #define CMCLIST_OPTIMUM_SIZE 64
49 /* the width of the column resize windows */
52 /* minimum allowed width of a column */
53 #define COLUMN_MIN_WIDTH 5
55 /* this defigns the base grid spacing */
56 #define CELL_SPACING 1
58 /* added the horizontal space at the beginning and end of a row*/
59 #define COLUMN_INSET 3
61 /* used for auto-scrolling */
62 #define SCROLL_TIME 100
64 /* gives the top pixel of the given row in context of
65 * the clist's voffset */
66 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
67 (((row) + 1) * CELL_SPACING) + \
70 /* returns the row index from a y pixel location in the
71 * context of the clist's voffset */
72 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
73 ((clist)->row_height + CELL_SPACING))
75 /* gives the left pixel of the given column in context of
76 * the clist's hoffset */
77 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
80 /* returns the column index from a x pixel location in the
81 * context of the clist's hoffset */
83 COLUMN_FROM_XPIXEL (GtkCMCList * clist,
88 for (i = 0; i < clist->columns; i++)
89 if (clist->column[i].visible)
91 cx = clist->column[i].area.x + clist->hoffset;
93 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
94 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
102 /* returns the top pixel of the given row in the context of
104 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
106 /* returns the left pixel of the given column in the context of
108 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
110 /* returns the total height of the list */
111 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
112 (CELL_SPACING * ((clist)->rows + 1)))
115 /* returns the total width of the list */
117 LIST_WIDTH (GtkCMCList * clist)
121 for (last_column = clist->columns - 1;
122 last_column >= 0 && !clist->column[last_column].visible; last_column--);
124 if (last_column >= 0)
125 return (clist->column[last_column].area.x +
126 clist->column[last_column].area.width +
127 COLUMN_INSET + CELL_SPACING);
131 /* returns the GList item for the nth row */
132 #define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
133 (clist)->row_list_end : \
134 g_list_nth ((clist)->row_list, (row)))
137 /* redraw the list if it's not frozen */
138 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
139 #define CLIST_REFRESH(clist) G_STMT_START { \
140 if (CLIST_UNFROZEN (clist)) \
141 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
183 /* GtkCMCList Methods */
184 static void gtk_cmclist_class_init (GtkCMCListClass *klass);
185 static void gtk_cmclist_init (GtkCMCList *clist);
186 static GObject* gtk_cmclist_constructor (GType type,
187 guint n_construct_properties,
188 GObjectConstructParam *construct_params);
190 /* GtkObject Methods */
191 static void gtk_cmclist_destroy (GtkObject *object);
192 static void gtk_cmclist_finalize (GObject *object);
193 static void gtk_cmclist_set_arg (GObject *object,
197 static void gtk_cmclist_get_arg (GObject *object,
202 /* GtkWidget Methods */
203 static void gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist,
204 GtkAdjustment *hadjustment,
205 GtkAdjustment *vadjustment);
206 static void gtk_cmclist_realize (GtkWidget *widget);
207 static void gtk_cmclist_unrealize (GtkWidget *widget);
208 static void gtk_cmclist_map (GtkWidget *widget);
209 static void gtk_cmclist_unmap (GtkWidget *widget);
210 static gint gtk_cmclist_expose (GtkWidget *widget,
211 GdkEventExpose *event);
212 static gint gtk_cmclist_button_press (GtkWidget *widget,
213 GdkEventButton *event);
214 static gint gtk_cmclist_button_release (GtkWidget *widget,
215 GdkEventButton *event);
216 static gint gtk_cmclist_motion (GtkWidget *widget,
217 GdkEventMotion *event);
218 static void gtk_cmclist_size_request (GtkWidget *widget,
219 GtkRequisition *requisition);
220 static void gtk_cmclist_size_allocate (GtkWidget *widget,
221 GtkAllocation *allocation);
222 static void gtk_cmclist_draw_focus (GtkWidget *widget);
223 static gint gtk_cmclist_focus_in (GtkWidget *widget,
224 GdkEventFocus *event);
225 static gint gtk_cmclist_focus_out (GtkWidget *widget,
226 GdkEventFocus *event);
227 static gint gtk_cmclist_focus (GtkWidget *widget,
228 GtkDirectionType direction);
229 static void gtk_cmclist_set_focus_child (GtkContainer *container,
231 static void gtk_cmclist_style_set (GtkWidget *widget,
232 GtkStyle *previous_style);
233 static void gtk_cmclist_drag_begin (GtkWidget *widget,
234 GdkDragContext *context);
235 static gint gtk_cmclist_drag_motion (GtkWidget *widget,
236 GdkDragContext *context,
240 static void gtk_cmclist_drag_leave (GtkWidget *widget,
241 GdkDragContext *context,
243 static void gtk_cmclist_drag_end (GtkWidget *widget,
244 GdkDragContext *context);
245 static gboolean gtk_cmclist_drag_drop (GtkWidget *widget,
246 GdkDragContext *context,
250 static void gtk_cmclist_drag_data_get (GtkWidget *widget,
251 GdkDragContext *context,
252 GtkSelectionData *selection_data,
255 static void gtk_cmclist_drag_data_received (GtkWidget *widget,
256 GdkDragContext *context,
259 GtkSelectionData *selection_data,
263 /* GtkContainer Methods */
264 static void gtk_cmclist_forall (GtkContainer *container,
265 gboolean include_internals,
266 GtkCallback callback,
267 gpointer callback_data);
270 static void toggle_row (GtkCMCList *clist,
274 static void real_select_row (GtkCMCList *clist,
278 static void real_unselect_row (GtkCMCList *clist,
282 static void update_extended_selection (GtkCMCList *clist,
284 static GList *selection_find (GtkCMCList *clist,
286 GList *row_list_element);
287 static void real_select_all (GtkCMCList *clist);
288 static void real_unselect_all (GtkCMCList *clist);
289 static void move_vertical (GtkCMCList *clist,
292 static void move_horizontal (GtkCMCList *clist,
294 static void real_undo_selection (GtkCMCList *clist);
295 static void fake_unselect_all (GtkCMCList *clist,
297 static void fake_toggle_row (GtkCMCList *clist,
299 static void resync_selection (GtkCMCList *clist,
301 static void sync_selection (GtkCMCList *clist,
304 static void set_anchor (GtkCMCList *clist,
308 static void start_selection (GtkCMCList *clist);
309 static void end_selection (GtkCMCList *clist);
310 static void toggle_add_mode (GtkCMCList *clist);
311 static void toggle_focus_row (GtkCMCList *clist);
312 static void extend_selection (GtkCMCList *clist,
313 GtkScrollType scroll_type,
315 gboolean auto_start_selection);
316 static gint get_selection_info (GtkCMCList *clist,
323 static void move_focus_row (GtkCMCList *clist,
324 GtkScrollType scroll_type,
326 static void scroll_horizontal (GtkCMCList *clist,
327 GtkScrollType scroll_type,
329 static void scroll_vertical (GtkCMCList *clist,
330 GtkScrollType scroll_type,
332 static void move_horizontal (GtkCMCList *clist,
334 static void move_vertical (GtkCMCList *clist,
337 static gint horizontal_timeout (GtkCMCList *clist);
338 static gint vertical_timeout (GtkCMCList *clist);
339 static void remove_grab (GtkCMCList *clist);
343 static void draw_xor_line (GtkCMCList *clist);
344 static gint new_column_width (GtkCMCList *clist,
347 static void column_auto_resize (GtkCMCList *clist,
348 GtkCMCListRow *clist_row,
351 static void real_resize_column (GtkCMCList *clist,
354 static void abort_column_resize (GtkCMCList *clist);
355 static void cell_size_request (GtkCMCList *clist,
356 GtkCMCListRow *clist_row,
358 GtkRequisition *requisition);
361 static void column_button_create (GtkCMCList *clist,
363 static void column_button_clicked (GtkWidget *widget,
367 static void adjust_adjustments (GtkCMCList *clist,
368 gboolean block_resize);
369 static void vadjustment_changed (GtkAdjustment *adjustment,
371 static void vadjustment_value_changed (GtkAdjustment *adjustment,
373 static void hadjustment_changed (GtkAdjustment *adjustment,
375 static void hadjustment_value_changed (GtkAdjustment *adjustment,
379 static void get_cell_style (GtkCMCList *clist,
380 GtkCMCListRow *clist_row,
386 static gint draw_cell_pixbuf (GdkWindow *window,
387 GdkRectangle *clip_rectangle,
394 static void draw_row (GtkCMCList *clist,
397 GtkCMCListRow *clist_row);
398 static void draw_rows (GtkCMCList *clist,
400 static void clist_refresh (GtkCMCList *clist);
401 static void draw_drag_highlight (GtkCMCList *clist,
402 GtkCMCListRow *dest_row,
403 gint dest_row_number,
404 GtkCMCListDragPos drag_pos);
406 /* Size Allocation / Requisition */
407 static void size_allocate_title_buttons (GtkCMCList *clist);
408 static void size_allocate_columns (GtkCMCList *clist,
409 gboolean block_resize);
410 static gint list_requisition_width (GtkCMCList *clist);
412 /* Memory Allocation/Distruction Routines */
413 static GtkCMCListColumn *columns_new (GtkCMCList *clist);
414 static void column_title_new (GtkCMCList *clist,
417 static void columns_delete (GtkCMCList *clist);
418 static GtkCMCListRow *row_new (GtkCMCList *clist);
419 static void row_delete (GtkCMCList *clist,
420 GtkCMCListRow *clist_row);
421 static void set_cell_contents (GtkCMCList *clist,
422 GtkCMCListRow *clist_row,
428 static gint real_insert_row (GtkCMCList *clist,
431 static void real_remove_row (GtkCMCList *clist,
433 static void real_clear (GtkCMCList *clist);
436 static gint default_compare (GtkCMCList *clist,
439 static void real_sort_list (GtkCMCList *clist);
440 static GList *gtk_cmclist_merge (GtkCMCList *clist,
443 static GList *gtk_cmclist_mergesort (GtkCMCList *clist,
447 static gboolean title_focus_in (GtkCMCList *clist,
449 static gboolean title_focus_move (GtkCMCList *clist,
452 static void real_row_move (GtkCMCList *clist,
455 static gint column_title_passive_func (GtkWidget *widget,
458 static void drag_dest_cell (GtkCMCList *clist,
461 GtkCMCListDestInfo *dest_info);
465 static GtkContainerClass *parent_class = NULL;
466 static guint clist_signals[LAST_SIGNAL] = {0};
468 static const GtkTargetEntry clist_target_table = { "gtk-clist-drag-reorder", 0, 0};
471 gtk_cmclist_get_type (void)
473 static GType clist_type = 0;
477 static const GTypeInfo clist_info =
479 sizeof (GtkCMCListClass),
481 (GBaseInitFunc) NULL,
482 (GBaseFinalizeFunc) NULL,
484 (GClassInitFunc) gtk_cmclist_class_init,
485 (GClassFinalizeFunc) NULL,
486 NULL, /* class_data */
490 (GInstanceInitFunc) gtk_cmclist_init,
492 clist_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkCMCList", &clist_info, (GTypeFlags)0);
499 gtk_cmclist_class_init (GtkCMCListClass *klass)
501 GObjectClass *object_class = G_OBJECT_CLASS (klass);
502 GtkObjectClass *gtk_object_class;
503 GtkWidgetClass *widget_class;
504 GtkContainerClass *container_class;
505 GtkBindingSet *binding_set;
507 object_class->constructor = gtk_cmclist_constructor;
509 gtk_object_class = (GtkObjectClass *) klass;
510 widget_class = (GtkWidgetClass *) klass;
511 container_class = (GtkContainerClass *) klass;
513 parent_class = g_type_class_peek (GTK_TYPE_CONTAINER);
515 object_class->finalize = gtk_cmclist_finalize;
516 gtk_object_class->destroy = gtk_cmclist_destroy;
517 object_class->set_property = gtk_cmclist_set_arg;
518 object_class->get_property = gtk_cmclist_get_arg;
521 widget_class->realize = gtk_cmclist_realize;
522 widget_class->unrealize = gtk_cmclist_unrealize;
523 widget_class->map = gtk_cmclist_map;
524 widget_class->unmap = gtk_cmclist_unmap;
525 widget_class->button_press_event = gtk_cmclist_button_press;
526 widget_class->button_release_event = gtk_cmclist_button_release;
527 widget_class->motion_notify_event = gtk_cmclist_motion;
528 widget_class->expose_event = gtk_cmclist_expose;
529 widget_class->size_request = gtk_cmclist_size_request;
530 widget_class->size_allocate = gtk_cmclist_size_allocate;
531 widget_class->focus_in_event = gtk_cmclist_focus_in;
532 widget_class->focus_out_event = gtk_cmclist_focus_out;
533 widget_class->style_set = gtk_cmclist_style_set;
534 widget_class->drag_begin = gtk_cmclist_drag_begin;
535 widget_class->drag_end = gtk_cmclist_drag_end;
536 widget_class->drag_motion = gtk_cmclist_drag_motion;
537 widget_class->drag_leave = gtk_cmclist_drag_leave;
538 widget_class->drag_drop = gtk_cmclist_drag_drop;
539 widget_class->drag_data_get = gtk_cmclist_drag_data_get;
540 widget_class->drag_data_received = gtk_cmclist_drag_data_received;
541 widget_class->focus = gtk_cmclist_focus;
543 /* container_class->add = NULL; use the default GtkContainerClass warning */
544 /* container_class->remove=NULL; use the default GtkContainerClass warning */
546 container_class->forall = gtk_cmclist_forall;
547 container_class->set_focus_child = gtk_cmclist_set_focus_child;
549 klass->set_scroll_adjustments = gtk_cmclist_set_scroll_adjustments;
550 klass->refresh = clist_refresh;
551 klass->select_row = real_select_row;
552 klass->unselect_row = real_unselect_row;
553 klass->row_move = real_row_move;
554 klass->undo_selection = real_undo_selection;
555 klass->resync_selection = resync_selection;
556 klass->selection_find = selection_find;
557 klass->click_column = NULL;
558 klass->resize_column = real_resize_column;
559 klass->draw_row = draw_row;
560 klass->draw_drag_highlight = draw_drag_highlight;
561 klass->insert_row = real_insert_row;
562 klass->remove_row = real_remove_row;
563 klass->clear = real_clear;
564 klass->sort_list = real_sort_list;
565 klass->select_all = real_select_all;
566 klass->unselect_all = real_unselect_all;
567 klass->fake_unselect_all = fake_unselect_all;
568 klass->scroll_horizontal = scroll_horizontal;
569 klass->scroll_vertical = scroll_vertical;
570 klass->extend_selection = extend_selection;
571 klass->toggle_focus_row = toggle_focus_row;
572 klass->toggle_add_mode = toggle_add_mode;
573 klass->start_selection = start_selection;
574 klass->end_selection = end_selection;
575 klass->abort_column_resize = abort_column_resize;
576 klass->set_cell_contents = set_cell_contents;
577 klass->cell_size_request = cell_size_request;
579 g_object_class_install_property (object_class,
581 g_param_spec_uint ("n-columns",
587 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
588 g_object_class_install_property (object_class,
590 g_param_spec_enum ("shadow-type",
593 GTK_TYPE_SHADOW_TYPE, 0,
595 g_object_class_install_property (object_class,
597 g_param_spec_enum ("selection-mode",
600 GTK_TYPE_SELECTION_MODE, 0,
602 g_object_class_install_property (object_class,
604 g_param_spec_uint ("row-height",
611 g_object_class_install_property (object_class,
613 g_param_spec_boolean ("reorderable",
618 g_object_class_install_property (object_class,
620 g_param_spec_boolean ("titles-active",
625 g_object_class_install_property (object_class,
627 g_param_spec_boolean ("use-drag-icons",
632 g_object_class_install_property (object_class,
634 g_param_spec_enum ("sort-type",
637 GTK_TYPE_SORT_TYPE, 0,
639 widget_class->set_scroll_adjustments_signal =
640 g_signal_new ("set_scroll_adjustments",
641 G_TYPE_FROM_CLASS (object_class),
643 G_STRUCT_OFFSET (GtkCMCListClass, set_scroll_adjustments),
645 claws_marshal_VOID__OBJECT_OBJECT,
647 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
649 clist_signals[SELECT_ROW] =
650 g_signal_new ("select_row",
651 G_TYPE_FROM_CLASS (object_class),
653 G_STRUCT_OFFSET (GtkCMCListClass, select_row),
655 claws_marshal_VOID__INT_INT_BOXED,
659 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
660 clist_signals[UNSELECT_ROW] =
661 g_signal_new ("unselect_row",
662 G_TYPE_FROM_CLASS (object_class),
664 G_STRUCT_OFFSET (GtkCMCListClass, unselect_row),
666 claws_marshal_VOID__INT_INT_BOXED,
671 clist_signals[ROW_MOVE] =
672 g_signal_new ("row_move",
673 G_TYPE_FROM_CLASS (object_class),
675 G_STRUCT_OFFSET (GtkCMCListClass, row_move),
677 claws_marshal_VOID__INT_INT,
678 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
679 clist_signals[CLICK_COLUMN] =
680 g_signal_new ("click_column",
681 G_TYPE_FROM_CLASS (object_class),
683 G_STRUCT_OFFSET (GtkCMCListClass, click_column),
685 claws_marshal_VOID__INT,
686 G_TYPE_NONE, 1, G_TYPE_INT);
687 clist_signals[RESIZE_COLUMN] =
688 g_signal_new ("resize_column",
689 G_TYPE_FROM_CLASS (object_class),
691 G_STRUCT_OFFSET (GtkCMCListClass, resize_column),
693 claws_marshal_VOID__INT_INT,
694 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
696 clist_signals[TOGGLE_FOCUS_ROW] =
697 g_signal_new ("toggle_focus_row",
698 G_TYPE_FROM_CLASS (object_class),
699 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
700 G_STRUCT_OFFSET (GtkCMCListClass, toggle_focus_row),
702 claws_marshal_VOID__VOID,
704 clist_signals[SELECT_ALL] =
705 g_signal_new ("select_all",
706 G_TYPE_FROM_CLASS (object_class),
707 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
708 G_STRUCT_OFFSET (GtkCMCListClass, select_all),
710 claws_marshal_VOID__VOID,
712 clist_signals[UNSELECT_ALL] =
713 g_signal_new ("unselect_all",
714 G_TYPE_FROM_CLASS (object_class),
715 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
716 G_STRUCT_OFFSET (GtkCMCListClass, unselect_all),
718 claws_marshal_VOID__VOID,
720 clist_signals[UNDO_SELECTION] =
721 g_signal_new ("undo_selection",
722 G_TYPE_FROM_CLASS (object_class),
723 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
724 G_STRUCT_OFFSET (GtkCMCListClass, undo_selection),
726 claws_marshal_VOID__VOID,
728 clist_signals[START_SELECTION] =
729 g_signal_new ("start_selection",
730 G_TYPE_FROM_CLASS (object_class),
731 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
732 G_STRUCT_OFFSET (GtkCMCListClass, start_selection),
734 claws_marshal_VOID__VOID,
736 clist_signals[END_SELECTION] =
737 g_signal_new ("end_selection",
738 G_TYPE_FROM_CLASS (object_class),
739 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
740 G_STRUCT_OFFSET (GtkCMCListClass, end_selection),
742 claws_marshal_VOID__VOID,
744 clist_signals[TOGGLE_ADD_MODE] =
745 g_signal_new ("toggle_add_mode",
746 G_TYPE_FROM_CLASS (object_class),
747 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
748 G_STRUCT_OFFSET (GtkCMCListClass, toggle_add_mode),
750 claws_marshal_VOID__VOID,
752 clist_signals[EXTEND_SELECTION] =
753 g_signal_new ("extend_selection",
754 G_TYPE_FROM_CLASS (object_class),
755 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
756 G_STRUCT_OFFSET (GtkCMCListClass, extend_selection),
758 claws_marshal_VOID__ENUM_FLOAT_BOOLEAN,
759 G_TYPE_NONE, 3, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT, G_TYPE_BOOLEAN);
760 clist_signals[SCROLL_VERTICAL] =
761 g_signal_new ("scroll_vertical",
762 G_TYPE_FROM_CLASS (object_class),
763 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
764 G_STRUCT_OFFSET (GtkCMCListClass, scroll_vertical),
766 claws_marshal_VOID__ENUM_FLOAT,
767 G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT);
768 clist_signals[SCROLL_HORIZONTAL] =
769 g_signal_new ("scroll_horizontal",
770 G_TYPE_FROM_CLASS (object_class),
771 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
772 G_STRUCT_OFFSET (GtkCMCListClass, scroll_horizontal),
774 claws_marshal_VOID__ENUM_FLOAT,
775 G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT);
776 clist_signals[ABORT_COLUMN_RESIZE] =
777 g_signal_new ("abort_column_resize",
778 G_TYPE_FROM_CLASS (object_class),
779 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
780 G_STRUCT_OFFSET (GtkCMCListClass, abort_column_resize),
782 claws_marshal_VOID__VOID,
785 binding_set = gtk_binding_set_by_class (klass);
786 gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
787 "scroll_vertical", 2,
788 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
790 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
791 "scroll_vertical", 2,
792 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
794 gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
795 "scroll_vertical", 2,
796 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
798 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
799 "scroll_vertical", 2,
800 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
802 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
803 "scroll_vertical", 2,
804 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
806 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
807 "scroll_vertical", 2,
808 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
810 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
811 "scroll_vertical", 2,
812 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
814 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
815 "scroll_vertical", 2,
816 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
818 gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
819 "scroll_vertical", 2,
820 G_TYPE_ENUM, GTK_SCROLL_JUMP,
822 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
823 "scroll_vertical", 2,
824 G_TYPE_ENUM, GTK_SCROLL_JUMP,
826 gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
827 "scroll_vertical", 2,
828 G_TYPE_ENUM, GTK_SCROLL_JUMP,
830 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
831 "scroll_vertical", 2,
832 G_TYPE_ENUM, GTK_SCROLL_JUMP,
835 gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK,
836 "extend_selection", 3,
837 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
838 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
839 gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, GDK_SHIFT_MASK,
840 "extend_selection", 3,
841 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
842 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
843 gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK,
844 "extend_selection", 3,
845 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
846 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
847 gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, GDK_SHIFT_MASK,
848 "extend_selection", 3,
849 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
850 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
851 gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK,
852 "extend_selection", 3,
853 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
854 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
855 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, GDK_SHIFT_MASK,
856 "extend_selection", 3,
857 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
858 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
859 gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK,
860 "extend_selection", 3,
861 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
862 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
863 gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, GDK_SHIFT_MASK,
864 "extend_selection", 3,
865 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
866 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
867 gtk_binding_entry_add_signal (binding_set, GDK_Home,
868 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
869 "extend_selection", 3,
870 G_TYPE_ENUM, GTK_SCROLL_JUMP,
871 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
872 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home,
873 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
874 "extend_selection", 3,
875 G_TYPE_ENUM, GTK_SCROLL_JUMP,
876 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
877 gtk_binding_entry_add_signal (binding_set, GDK_End,
878 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
879 "extend_selection", 3,
880 G_TYPE_ENUM, GTK_SCROLL_JUMP,
881 G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE);
882 gtk_binding_entry_add_signal (binding_set, GDK_KP_End,
883 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
884 "extend_selection", 3,
885 G_TYPE_ENUM, GTK_SCROLL_JUMP,
886 G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE);
889 gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
890 "scroll_horizontal", 2,
891 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
893 gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
894 "scroll_horizontal", 2,
895 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
898 gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
899 "scroll_horizontal", 2,
900 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
902 gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
903 "scroll_horizontal", 2,
904 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
907 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
908 "scroll_horizontal", 2,
909 G_TYPE_ENUM, GTK_SCROLL_JUMP,
911 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
912 "scroll_horizontal", 2,
913 G_TYPE_ENUM, GTK_SCROLL_JUMP,
916 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
917 "scroll_horizontal", 2,
918 G_TYPE_ENUM, GTK_SCROLL_JUMP,
921 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
922 "scroll_horizontal", 2,
923 G_TYPE_ENUM, GTK_SCROLL_JUMP,
926 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
927 "undo_selection", 0);
928 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
929 "abort_column_resize", 0);
930 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
931 "toggle_focus_row", 0);
932 gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
933 "toggle_focus_row", 0);
934 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK,
935 "toggle_add_mode", 0);
936 gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK,
937 "toggle_add_mode", 0);
938 gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
940 gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, GDK_CONTROL_MASK,
942 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
944 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
945 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
947 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
948 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
950 gtk_binding_entry_add_signal (binding_set, GDK_Shift_L,
951 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
954 gtk_binding_entry_add_signal (binding_set, GDK_Shift_R,
955 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
961 gtk_cmclist_set_arg (GObject *object,
968 clist = GTK_CMCLIST (object);
972 case ARG_N_COLUMNS: /* only set at construction time */
973 clist->columns = MAX (1, g_value_get_uint (value));
975 case ARG_SHADOW_TYPE:
976 gtk_cmclist_set_shadow_type (clist, g_value_get_enum (value));
978 case ARG_SELECTION_MODE:
979 gtk_cmclist_set_selection_mode (clist, g_value_get_enum (value));
982 gtk_cmclist_set_row_height (clist, g_value_get_uint (value));
984 case ARG_REORDERABLE:
985 gtk_cmclist_set_reorderable (clist, g_value_get_boolean (value));
987 case ARG_TITLES_ACTIVE:
988 if (g_value_get_boolean (value))
989 gtk_cmclist_column_titles_active (clist);
991 gtk_cmclist_column_titles_passive (clist);
993 case ARG_USE_DRAG_ICONS:
994 gtk_cmclist_set_use_drag_icons (clist, g_value_get_boolean (value));
997 gtk_cmclist_set_sort_type (clist, g_value_get_enum (value));
1003 gtk_cmclist_get_arg (GObject *object,
1010 clist = GTK_CMCLIST (object);
1017 g_value_set_uint(value, clist->columns);
1019 case ARG_SHADOW_TYPE:
1020 g_value_set_enum(value, clist->shadow_type);
1022 case ARG_SELECTION_MODE:
1023 g_value_set_enum(value, clist->selection_mode);
1025 case ARG_ROW_HEIGHT:
1026 g_value_set_uint(value, GTK_CMCLIST_ROW_HEIGHT_SET(clist) ? clist->row_height : 0);
1028 case ARG_REORDERABLE:
1029 g_value_set_boolean(value, GTK_CMCLIST_REORDERABLE (clist));
1031 case ARG_TITLES_ACTIVE:
1032 g_value_set_boolean(value, TRUE);
1033 for (i = 0; i < clist->columns; i++)
1034 if (clist->column[i].button &&
1035 !GTK_WIDGET_SENSITIVE (clist->column[i].button))
1037 g_value_set_boolean(value, FALSE);
1041 case ARG_USE_DRAG_ICONS:
1042 g_value_set_boolean(value, GTK_CMCLIST_USE_DRAG_ICONS (clist));
1045 g_value_set_enum(value, clist->sort_type);
1048 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1054 gtk_cmclist_init (GtkCMCList *clist)
1058 GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
1059 GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS);
1060 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_DRAW_DRAG_LINE);
1061 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
1064 #if !GLIB_CHECK_VERSION(2,10,0)
1065 clist->row_mem_chunk = NULL;
1066 clist->cell_mem_chunk = NULL;
1069 clist->freeze_count = 0;
1072 clist->row_height = 0;
1073 clist->row_list = NULL;
1074 clist->row_list_end = NULL;
1078 clist->title_window = NULL;
1079 clist->column_title_area.x = 0;
1080 clist->column_title_area.y = 0;
1081 clist->column_title_area.width = 1;
1082 clist->column_title_area.height = 1;
1084 clist->clist_window = NULL;
1085 clist->clist_window_width = 1;
1086 clist->clist_window_height = 1;
1091 clist->shadow_type = GTK_SHADOW_IN;
1092 clist->vadjustment = NULL;
1093 clist->hadjustment = NULL;
1095 clist->button_actions[0] = GTK_CMBUTTON_SELECTS | GTK_CMBUTTON_DRAGS;
1096 clist->button_actions[1] = GTK_CMBUTTON_IGNORED;
1097 clist->button_actions[2] = GTK_CMBUTTON_IGNORED;
1098 clist->button_actions[3] = GTK_CMBUTTON_IGNORED;
1099 clist->button_actions[4] = GTK_CMBUTTON_IGNORED;
1101 clist->cursor_drag = NULL;
1102 clist->xor_gc = NULL;
1103 clist->fg_gc = NULL;
1104 clist->bg_gc = NULL;
1107 clist->selection_mode = GTK_SELECTION_SINGLE;
1108 clist->selection = NULL;
1109 clist->selection_end = NULL;
1110 clist->undo_selection = NULL;
1111 clist->undo_unselection = NULL;
1113 clist->focus_row = -1;
1114 clist->focus_header_column = -1;
1115 clist->undo_anchor = -1;
1118 clist->anchor_state = GTK_STATE_SELECTED;
1119 clist->drag_pos = -1;
1123 clist->click_cell.row = -1;
1124 clist->click_cell.column = -1;
1126 clist->compare = default_compare;
1127 clist->sort_type = GTK_SORT_ASCENDING;
1128 clist->sort_column = 0;
1130 clist->drag_highlight_row = -1;
1135 gtk_cmclist_constructor (GType type,
1136 guint n_construct_properties,
1137 GObjectConstructParam *construct_properties)
1139 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
1140 n_construct_properties,
1141 construct_properties);
1142 GtkCMCList *clist = GTK_CMCLIST (object);
1144 #if !GLIB_CHECK_VERSION(2,10,0)
1145 if (!clist->row_mem_chunk)
1146 clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
1147 sizeof (GtkCMCListRow),
1148 sizeof (GtkCMCListRow) *
1149 CMCLIST_OPTIMUM_SIZE,
1152 if (!clist->cell_mem_chunk)
1153 clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
1154 sizeof (GtkCMCell) * clist->columns,
1155 sizeof (GtkCMCell) * clist->columns *
1156 CMCLIST_OPTIMUM_SIZE,
1160 /* allocate memory for columns */
1161 clist->column = columns_new (clist);
1163 /* there needs to be at least one column button
1164 * because there is alot of code that will break if it
1167 column_button_create (clist, 0);
1172 /* GTKCLIST PUBLIC INTERFACE
1174 * gtk_cmclist_new_with_titles
1175 * gtk_cmclist_set_hadjustment
1176 * gtk_cmclist_set_vadjustment
1177 * gtk_cmclist_get_hadjustment
1178 * gtk_cmclist_get_vadjustment
1179 * gtk_cmclist_set_shadow_type
1180 * gtk_cmclist_set_selection_mode
1181 * gtk_cmclist_freeze
1185 gtk_cmclist_new (gint columns)
1187 return gtk_cmclist_new_with_titles (columns, NULL);
1191 gtk_cmclist_new_with_titles (gint columns,
1196 clist = g_object_new (GTK_TYPE_CMCLIST,
1197 "n_columns", columns,
1203 for (i = 0; i < clist->columns; i++)
1204 gtk_cmclist_set_column_title (clist, i, titles[i]);
1205 gtk_cmclist_column_titles_show (clist);
1208 gtk_cmclist_column_titles_hide (clist);
1210 return GTK_WIDGET (clist);
1214 gtk_cmclist_set_hadjustment (GtkCMCList *clist,
1215 GtkAdjustment *adjustment)
1217 GtkAdjustment *old_adjustment;
1219 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1221 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1223 if (clist->hadjustment == adjustment)
1226 old_adjustment = clist->hadjustment;
1228 if (clist->hadjustment)
1230 g_signal_handlers_disconnect_matched(G_OBJECT (clist->hadjustment), G_SIGNAL_MATCH_DATA,
1233 g_object_unref (G_OBJECT (clist->hadjustment));
1236 clist->hadjustment = adjustment;
1238 if (clist->hadjustment)
1240 #if GLIB_CHECK_VERSION(2,10,0)
1241 g_object_ref_sink (clist->hadjustment);
1243 gtk_object_ref (G_OBJECT (clist->hadjustment));
1244 gtk_object_sink (G_OBJECT (clist->hadjustment));
1246 g_signal_connect (G_OBJECT (clist->hadjustment), "changed",
1247 G_CALLBACK( hadjustment_changed),
1249 g_signal_connect (G_OBJECT (clist->hadjustment), "value_changed",
1250 G_CALLBACK( hadjustment_value_changed),
1254 if (!clist->hadjustment || !old_adjustment)
1255 gtk_widget_queue_resize (GTK_WIDGET (clist));
1259 gtk_cmclist_get_hadjustment (GtkCMCList *clist)
1261 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1263 return clist->hadjustment;
1267 gtk_cmclist_set_vadjustment (GtkCMCList *clist,
1268 GtkAdjustment *adjustment)
1270 GtkAdjustment *old_adjustment;
1272 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1274 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1276 if (clist->vadjustment == adjustment)
1279 old_adjustment = clist->vadjustment;
1281 if (clist->vadjustment)
1283 g_signal_handlers_disconnect_matched(G_OBJECT (clist->vadjustment), G_SIGNAL_MATCH_DATA,
1285 g_object_unref (G_OBJECT (clist->vadjustment));
1288 clist->vadjustment = adjustment;
1290 if (clist->vadjustment)
1292 #if GLIB_CHECK_VERSION(2,10,0)
1293 g_object_ref_sink (clist->vadjustment);
1295 gtk_object_ref (G_OBJECT (clist->vadjustment));
1296 gtk_object_sink (G_OBJECT (clist->vadjustment));
1299 g_signal_connect (G_OBJECT (clist->vadjustment), "changed",
1300 G_CALLBACK(vadjustment_changed),
1302 g_signal_connect (G_OBJECT (clist->vadjustment), "value_changed",
1303 G_CALLBACK(vadjustment_value_changed),
1307 if (!clist->vadjustment || !old_adjustment)
1308 gtk_widget_queue_resize (GTK_WIDGET (clist));
1312 gtk_cmclist_get_vadjustment (GtkCMCList *clist)
1314 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1316 return clist->vadjustment;
1320 gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist,
1321 GtkAdjustment *hadjustment,
1322 GtkAdjustment *vadjustment)
1324 if (clist->hadjustment != hadjustment)
1325 gtk_cmclist_set_hadjustment (clist, hadjustment);
1326 if (clist->vadjustment != vadjustment)
1327 gtk_cmclist_set_vadjustment (clist, vadjustment);
1331 gtk_cmclist_set_shadow_type (GtkCMCList *clist,
1334 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1336 clist->shadow_type = type;
1338 if (GTK_WIDGET_VISIBLE (clist))
1339 gtk_widget_queue_resize (GTK_WIDGET (clist));
1343 gtk_cmclist_set_selection_mode (GtkCMCList *clist,
1344 GtkSelectionMode mode)
1346 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1347 cm_return_if_fail (mode != GTK_SELECTION_NONE);
1349 if (mode == clist->selection_mode)
1352 clist->selection_mode = mode;
1354 clist->anchor_state = GTK_STATE_SELECTED;
1355 clist->drag_pos = -1;
1356 clist->undo_anchor = clist->focus_row;
1358 g_list_free (clist->undo_selection);
1359 g_list_free (clist->undo_unselection);
1360 clist->undo_selection = NULL;
1361 clist->undo_unselection = NULL;
1365 case GTK_SELECTION_MULTIPLE:
1367 case GTK_SELECTION_BROWSE:
1368 case GTK_SELECTION_SINGLE:
1369 gtk_cmclist_unselect_all (clist);
1372 /* Someone set it by hand */
1373 g_assert_not_reached ();
1378 gtk_cmclist_freeze (GtkCMCList *clist)
1380 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1382 clist->freeze_count++;
1386 gtk_cmclist_thaw (GtkCMCList *clist)
1388 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1390 if (clist->freeze_count)
1392 clist->freeze_count--;
1393 CLIST_REFRESH (clist);
1397 /* PUBLIC COLUMN FUNCTIONS
1398 * gtk_cmclist_column_titles_show
1399 * gtk_cmclist_column_titles_hide
1400 * gtk_cmclist_column_title_active
1401 * gtk_cmclist_column_title_passive
1402 * gtk_cmclist_column_titles_active
1403 * gtk_cmclist_column_titles_passive
1404 * gtk_cmclist_set_column_title
1405 * gtk_cmclist_get_column_title
1406 * gtk_cmclist_set_column_widget
1407 * gtk_cmclist_set_column_justification
1408 * gtk_cmclist_set_column_visibility
1409 * gtk_cmclist_set_column_resizeable
1410 * gtk_cmclist_set_column_auto_resize
1411 * gtk_cmclist_optimal_column_width
1412 * gtk_cmclist_set_column_width
1413 * gtk_cmclist_set_column_min_width
1414 * gtk_cmclist_set_column_max_width
1417 gtk_cmclist_column_titles_show (GtkCMCList *clist)
1419 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1421 if (!GTK_CMCLIST_SHOW_TITLES(clist))
1423 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_SHOW_TITLES);
1424 if (clist->title_window)
1425 gdk_window_show (clist->title_window);
1426 gtk_widget_queue_resize (GTK_WIDGET (clist));
1431 gtk_cmclist_column_titles_hide (GtkCMCList *clist)
1433 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1435 if (GTK_CMCLIST_SHOW_TITLES(clist))
1437 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_SHOW_TITLES);
1438 if (clist->title_window)
1439 gdk_window_hide (clist->title_window);
1440 gtk_widget_queue_resize (GTK_WIDGET (clist));
1445 gtk_cmclist_column_title_active (GtkCMCList *clist,
1448 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1450 if (column < 0 || column >= clist->columns)
1452 if (!clist->column[column].button || !clist->column[column].button_passive)
1455 clist->column[column].button_passive = FALSE;
1457 g_signal_handlers_disconnect_matched(G_OBJECT (clist->column[column].button), G_SIGNAL_MATCH_FUNC,
1458 0, 0, 0, column_title_passive_func, 0);
1460 GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS);
1461 if (GTK_WIDGET_VISIBLE (clist))
1462 gtk_widget_queue_draw (clist->column[column].button);
1466 gtk_cmclist_column_title_passive (GtkCMCList *clist,
1471 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1473 if (column < 0 || column >= clist->columns)
1475 if (!clist->column[column].button || clist->column[column].button_passive)
1478 button = GTK_BUTTON (clist->column[column].button);
1480 clist->column[column].button_passive = TRUE;
1482 if (button->button_down)
1483 gtk_button_released (button);
1484 if (button->in_button)
1485 gtk_button_leave (button);
1487 g_signal_connect (G_OBJECT (clist->column[column].button), "event",
1488 G_CALLBACK(column_title_passive_func), NULL);
1490 GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS);
1491 if (GTK_WIDGET_VISIBLE (clist))
1492 gtk_widget_queue_draw (clist->column[column].button);
1496 gtk_cmclist_column_titles_active (GtkCMCList *clist)
1500 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1502 for (i = 0; i < clist->columns; i++)
1503 gtk_cmclist_column_title_active (clist, i);
1507 gtk_cmclist_column_titles_passive (GtkCMCList *clist)
1511 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1513 for (i = 0; i < clist->columns; i++)
1514 gtk_cmclist_column_title_passive (clist, i);
1518 gtk_cmclist_set_column_title (GtkCMCList *clist,
1522 gint new_button = 0;
1523 GtkWidget *old_widget;
1524 GtkWidget *alignment = NULL;
1527 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1529 if (column < 0 || column >= clist->columns)
1532 /* if the column button doesn't currently exist,
1533 * it has to be created first */
1534 if (!clist->column[column].button)
1536 column_button_create (clist, column);
1540 column_title_new (clist, column, title);
1542 /* remove and destroy the old widget */
1543 old_widget = GTK_BIN (clist->column[column].button)->child;
1545 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1547 /* create new alignment based no column justification */
1548 switch (clist->column[column].justification)
1550 case GTK_JUSTIFY_LEFT:
1551 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1554 case GTK_JUSTIFY_RIGHT:
1555 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1558 case GTK_JUSTIFY_CENTER:
1559 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1562 case GTK_JUSTIFY_FILL:
1563 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1567 gtk_widget_push_composite_child ();
1568 label = gtk_label_new (clist->column[column].title);
1569 gtk_widget_pop_composite_child ();
1570 gtk_container_add (GTK_CONTAINER (alignment), label);
1571 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1572 gtk_widget_show (label);
1573 gtk_widget_show (alignment);
1575 /* if this button didn't previously exist, then the
1576 * column button positions have to be re-computed */
1577 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1578 size_allocate_title_buttons (clist);
1582 gtk_cmclist_get_column_title (GtkCMCList *clist,
1585 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1587 if (column < 0 || column >= clist->columns)
1590 return clist->column[column].title;
1594 gtk_cmclist_set_column_widget (GtkCMCList *clist,
1598 gint new_button = 0;
1599 GtkWidget *old_widget;
1601 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1603 if (column < 0 || column >= clist->columns)
1606 /* if the column button doesn't currently exist,
1607 * it has to be created first */
1608 if (!clist->column[column].button)
1610 column_button_create (clist, column);
1614 column_title_new (clist, column, NULL);
1616 /* remove and destroy the old widget */
1617 old_widget = GTK_BIN (clist->column[column].button)->child;
1619 gtk_container_remove (GTK_CONTAINER (clist->column[column].button),
1622 /* add and show the widget */
1625 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1626 gtk_widget_show (widget);
1629 /* if this button didn't previously exist, then the
1630 * column button positions have to be re-computed */
1631 if (GTK_WIDGET_VISIBLE (clist) && new_button)
1632 size_allocate_title_buttons (clist);
1636 gtk_cmclist_get_column_widget (GtkCMCList *clist,
1639 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1641 if (column < 0 || column >= clist->columns)
1644 if (clist->column[column].button)
1645 return GTK_BIN (clist->column[column].button)->child;
1651 gtk_cmclist_set_column_justification (GtkCMCList *clist,
1653 GtkJustification justification)
1655 GtkWidget *alignment;
1657 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1659 if (column < 0 || column >= clist->columns)
1662 clist->column[column].justification = justification;
1664 /* change the alinment of the button title if it's not a
1666 if (clist->column[column].title)
1668 alignment = GTK_BIN (clist->column[column].button)->child;
1670 switch (clist->column[column].justification)
1672 case GTK_JUSTIFY_LEFT:
1673 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1676 case GTK_JUSTIFY_RIGHT:
1677 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1680 case GTK_JUSTIFY_CENTER:
1681 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1684 case GTK_JUSTIFY_FILL:
1685 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1693 if (CLIST_UNFROZEN (clist))
1694 draw_rows (clist, NULL);
1698 gtk_cmclist_set_column_visibility (GtkCMCList *clist,
1702 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1704 if (column < 0 || column >= clist->columns)
1706 if (clist->column[column].visible == visible)
1709 /* don't hide last visible column */
1713 gint vis_columns = 0;
1715 for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
1716 if (clist->column[i].visible)
1719 if (vis_columns < 2)
1723 clist->column[column].visible = visible;
1725 if (clist->column[column].button)
1728 gtk_widget_show (clist->column[column].button);
1730 gtk_widget_hide (clist->column[column].button);
1733 gtk_widget_queue_resize (GTK_WIDGET(clist));
1737 gtk_cmclist_set_column_resizeable (GtkCMCList *clist,
1739 gboolean resizeable)
1741 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1743 if (column < 0 || column >= clist->columns)
1745 if (clist->column[column].resizeable == resizeable)
1748 clist->column[column].resizeable = resizeable;
1750 clist->column[column].auto_resize = FALSE;
1752 if (GTK_WIDGET_VISIBLE (clist))
1753 size_allocate_title_buttons (clist);
1757 gtk_cmclist_set_column_auto_resize (GtkCMCList *clist,
1759 gboolean auto_resize)
1761 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1763 if (column < 0 || column >= clist->columns)
1765 if (clist->column[column].auto_resize == auto_resize)
1768 clist->column[column].auto_resize = auto_resize;
1771 clist->column[column].resizeable = FALSE;
1772 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1776 width = gtk_cmclist_optimal_column_width (clist, column);
1777 gtk_cmclist_set_column_width (clist, column, width);
1781 if (GTK_WIDGET_VISIBLE (clist))
1782 size_allocate_title_buttons (clist);
1786 gtk_cmclist_columns_autosize (GtkCMCList *clist)
1791 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
1793 gtk_cmclist_freeze (clist);
1795 for (i = 0; i < clist->columns; i++)
1797 gtk_cmclist_set_column_width (clist, i,
1798 gtk_cmclist_optimal_column_width (clist, i));
1800 width += clist->column[i].width;
1803 gtk_cmclist_thaw (clist);
1808 gtk_cmclist_optimal_column_width (GtkCMCList *clist,
1811 GtkRequisition requisition;
1815 cm_return_val_if_fail (GTK_CMCLIST (clist), 0);
1817 if (column < 0 || column >= clist->columns)
1820 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button)
1821 width = (clist->column[column].button->requisition.width)
1823 (CELL_SPACING + (2 * COLUMN_INSET)))
1829 for (list = clist->row_list; list; list = list->next)
1831 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1832 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
1833 width = MAX (width, requisition.width);
1840 gtk_cmclist_set_column_width (GtkCMCList *clist,
1844 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1846 if (column < 0 || column >= clist->columns)
1849 g_signal_emit (G_OBJECT (clist), clist_signals[RESIZE_COLUMN], 0,
1854 gtk_cmclist_set_column_min_width (GtkCMCList *clist,
1858 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1860 if (column < 0 || column >= clist->columns)
1862 if (clist->column[column].min_width == min_width)
1865 if (clist->column[column].max_width >= 0 &&
1866 clist->column[column].max_width < min_width)
1867 clist->column[column].min_width = clist->column[column].max_width;
1869 clist->column[column].min_width = min_width;
1871 if (clist->column[column].area.width < clist->column[column].min_width)
1872 gtk_cmclist_set_column_width (clist, column,clist->column[column].min_width);
1876 gtk_cmclist_set_column_max_width (GtkCMCList *clist,
1880 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1882 if (column < 0 || column >= clist->columns)
1884 if (clist->column[column].max_width == max_width)
1887 if (clist->column[column].min_width >= 0 && max_width >= 0 &&
1888 clist->column[column].min_width > max_width)
1889 clist->column[column].max_width = clist->column[column].min_width;
1891 clist->column[column].max_width = max_width;
1893 if (clist->column[column].area.width > clist->column[column].max_width)
1894 gtk_cmclist_set_column_width (clist, column,clist->column[column].max_width);
1897 /* PRIVATE COLUMN FUNCTIONS
1898 * column_auto_resize
1899 * real_resize_column
1900 * abort_column_resize
1901 * size_allocate_title_buttons
1902 * size_allocate_columns
1903 * list_requisition_width
1905 * column_button_create
1906 * column_button_clicked
1907 * column_title_passive_func
1910 column_auto_resize (GtkCMCList *clist,
1911 GtkCMCListRow *clist_row,
1915 /* resize column if needed for auto_resize */
1916 GtkRequisition requisition;
1918 if (!clist->column[column].auto_resize ||
1919 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1923 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
1924 column, &requisition);
1926 requisition.width = 0;
1928 if (requisition.width > clist->column[column].width)
1929 gtk_cmclist_set_column_width (clist, column, requisition.width);
1930 else if (requisition.width < old_width &&
1931 old_width == clist->column[column].width)
1936 /* run a "gtk_cmclist_optimal_column_width" but break, if
1937 * the column doesn't shrink */
1938 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button)
1939 new_width = (clist->column[column].button->requisition.width -
1940 (CELL_SPACING + (2 * COLUMN_INSET)));
1944 for (list = clist->row_list; list; list = list->next)
1946 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1947 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
1948 new_width = MAX (new_width, requisition.width);
1949 if (new_width == clist->column[column].width)
1952 if (new_width < clist->column[column].width)
1953 gtk_cmclist_set_column_width
1954 (clist, column, MAX (new_width, clist->column[column].min_width));
1959 real_resize_column (GtkCMCList *clist,
1963 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1965 if (column < 0 || column >= clist->columns)
1968 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
1969 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
1970 if (clist->column[column].max_width >= 0 &&
1971 width > clist->column[column].max_width)
1972 width = clist->column[column].max_width;
1974 clist->column[column].width = width;
1975 clist->column[column].width_set = TRUE;
1977 /* FIXME: this is quite expensive to do if the widget hasn't
1978 * been size_allocated yet, and pointless. Should
1981 size_allocate_columns (clist, TRUE);
1982 size_allocate_title_buttons (clist);
1984 CLIST_REFRESH (clist);
1988 abort_column_resize (GtkCMCList *clist)
1990 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1992 if (!GTK_CMCLIST_IN_DRAG(clist))
1995 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG);
1996 gtk_grab_remove (GTK_WIDGET (clist));
1997 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
1999 clist->drag_pos = -1;
2001 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
2002 draw_xor_line (clist);
2004 if (GTK_CMCLIST_ADD_MODE(clist))
2006 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0);
2007 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
2012 size_allocate_title_buttons (GtkCMCList *clist)
2014 GtkAllocation button_allocation;
2016 gint last_button = 0;
2019 if (!GTK_WIDGET_REALIZED (clist))
2022 button_allocation.x = clist->hoffset;
2023 button_allocation.y = 0;
2024 button_allocation.width = 0;
2025 button_allocation.height = clist->column_title_area.height;
2027 /* find last visible column */
2028 for (last_column = clist->columns - 1; last_column >= 0; last_column--)
2029 if (clist->column[last_column].visible)
2032 for (i = 0; i < last_column; i++)
2034 if (!clist->column[i].visible)
2036 last_button = i + 1;
2037 gdk_window_hide (clist->column[i].window);
2041 button_allocation.width += (clist->column[i].area.width +
2042 CELL_SPACING + 2 * COLUMN_INSET);
2044 if (!clist->column[i + 1].button)
2046 gdk_window_hide (clist->column[i].window);
2050 gtk_widget_size_allocate (clist->column[last_button].button,
2051 &button_allocation);
2052 button_allocation.x += button_allocation.width;
2053 button_allocation.width = 0;
2055 if (clist->column[last_button].resizeable)
2057 gdk_window_show (clist->column[last_button].window);
2058 gdk_window_move_resize (clist->column[last_button].window,
2059 button_allocation.x - (DRAG_WIDTH / 2),
2061 clist->column_title_area.height);
2064 gdk_window_hide (clist->column[last_button].window);
2066 last_button = i + 1;
2069 button_allocation.width += (clist->column[last_column].area.width +
2070 2 * (CELL_SPACING + COLUMN_INSET));
2071 gtk_widget_size_allocate (clist->column[last_button].button,
2072 &button_allocation);
2074 if (clist->column[last_button].resizeable)
2076 button_allocation.x += button_allocation.width;
2078 gdk_window_show (clist->column[last_button].window);
2079 gdk_window_move_resize (clist->column[last_button].window,
2080 button_allocation.x - (DRAG_WIDTH / 2),
2081 0, DRAG_WIDTH, clist->column_title_area.height);
2084 gdk_window_hide (clist->column[last_button].window);
2088 size_allocate_columns (GtkCMCList *clist,
2089 gboolean block_resize)
2091 gint xoffset = CELL_SPACING + COLUMN_INSET;
2095 /* find last visible column and calculate correct column width */
2096 for (last_column = clist->columns - 1;
2097 last_column >= 0 && !clist->column[last_column].visible; last_column--);
2099 if (last_column < 0)
2102 for (i = 0; i <= last_column; i++)
2104 if (!clist->column[i].visible)
2106 clist->column[i].area.x = xoffset;
2107 if (clist->column[i].width_set)
2109 if (!block_resize && GTK_CMCLIST_SHOW_TITLES(clist) &&
2110 clist->column[i].auto_resize && clist->column[i].button)
2114 width = (clist->column[i].button->requisition.width -
2115 (CELL_SPACING + (2 * COLUMN_INSET)));
2117 if (width > clist->column[i].width)
2118 gtk_cmclist_set_column_width (clist, i, width);
2121 clist->column[i].area.width = clist->column[i].width;
2122 xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET);
2124 else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2126 clist->column[i].area.width =
2127 clist->column[i].button->requisition.width -
2128 (CELL_SPACING + (2 * COLUMN_INSET));
2129 xoffset += clist->column[i].button->requisition.width;
2133 clist->column[last_column].area.width = clist->column[last_column].area.width
2134 + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset);
2138 list_requisition_width (GtkCMCList *clist)
2140 gint width = CELL_SPACING;
2143 for (i = clist->columns - 1; i >= 0; i--)
2145 if (!clist->column[i].visible)
2148 if (clist->column[i].width_set)
2149 width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
2150 else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2151 width += clist->column[i].button->requisition.width;
2157 /* this function returns the new width of the column being resized given
2158 * the column and x position of the cursor; the x cursor position is passed
2159 * in as a pointer and automagicly corrected if it's beyond min/max limits */
2161 new_column_width (GtkCMCList *clist,
2165 gint xthickness = GTK_WIDGET (clist)->style->xthickness;
2171 /* first translate the x position from widget->window
2172 * to clist->clist_window */
2173 cx = *x - xthickness;
2175 for (last_column = clist->columns - 1;
2176 last_column >= 0 && !clist->column[last_column].visible; last_column--);
2178 /* calculate new column width making sure it doesn't end up
2179 * less than the minimum width */
2180 dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
2181 (column < last_column) * CELL_SPACING);
2184 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
2186 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
2188 *x = cx + xthickness;
2190 else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
2191 width > clist->column[column].max_width)
2193 width = clist->column[column].max_width;
2194 cx = dx + clist->column[column].max_width;
2195 *x = cx + xthickness;
2198 if (cx < 0 || cx > clist->clist_window_width)
2205 column_button_create (GtkCMCList *clist,
2210 gtk_widget_push_composite_child ();
2211 button = clist->column[column].button = gtk_button_new ();
2212 GtkRcStyle *style = gtk_rc_style_new();
2213 style->ythickness = 0;
2214 gtk_widget_modify_style(clist->column[column].button, style);
2215 g_object_unref(style);
2216 gtk_container_set_border_width(GTK_CONTAINER(button), 0);
2217 gtk_widget_pop_composite_child ();
2219 if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
2220 gtk_widget_set_parent_window (clist->column[column].button,
2221 clist->title_window);
2222 gtk_widget_set_parent (button, GTK_WIDGET (clist));
2224 g_signal_connect (G_OBJECT (button), "clicked",
2225 G_CALLBACK(column_button_clicked),
2227 gtk_widget_show (button);
2231 column_button_clicked (GtkWidget *widget,
2237 cm_return_if_fail (widget != NULL);
2238 cm_return_if_fail (GTK_IS_CMCLIST (data));
2240 clist = GTK_CMCLIST (data);
2242 /* find the column who's button was pressed */
2243 for (i = 0; i < clist->columns; i++)
2244 if (clist->column[i].button == widget)
2247 g_signal_emit (G_OBJECT (clist), clist_signals[CLICK_COLUMN], 0, i);
2251 column_title_passive_func (GtkWidget *widget,
2255 cm_return_val_if_fail (event != NULL, FALSE);
2257 switch (event->type)
2259 case GDK_MOTION_NOTIFY:
2260 case GDK_BUTTON_PRESS:
2261 case GDK_2BUTTON_PRESS:
2262 case GDK_3BUTTON_PRESS:
2263 case GDK_BUTTON_RELEASE:
2264 case GDK_ENTER_NOTIFY:
2265 case GDK_LEAVE_NOTIFY:
2274 /* PUBLIC CELL FUNCTIONS
2275 * gtk_cmclist_get_cell_type
2276 * gtk_cmclist_set_text
2277 * gtk_cmclist_get_text
2278 * gtk_cmclist_set_pixbuf
2279 * gtk_cmclist_get_pixbuf
2280 * gtk_cmclist_set_pixtext
2281 * gtk_cmclist_get_pixtext
2282 * gtk_cmclist_set_shift
2285 gtk_cmclist_get_cell_type (GtkCMCList *clist,
2289 GtkCMCListRow *clist_row;
2291 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2293 if (row < 0 || row >= clist->rows)
2295 if (column < 0 || column >= clist->columns)
2298 clist_row = ROW_ELEMENT (clist, row)->data;
2300 return clist_row->cell[column].type;
2304 gtk_cmclist_set_text (GtkCMCList *clist,
2309 GtkCMCListRow *clist_row;
2311 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2313 if (row < 0 || row >= clist->rows)
2315 if (column < 0 || column >= clist->columns)
2318 clist_row = ROW_ELEMENT (clist, row)->data;
2320 /* if text is null, then the cell is empty */
2321 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2322 (clist, clist_row, column, GTK_CMCELL_TEXT, text, 0, NULL);
2324 /* redraw the list if it's not frozen */
2325 if (CLIST_UNFROZEN (clist))
2327 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2328 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2333 gtk_cmclist_get_text (GtkCMCList *clist,
2338 GtkCMCListRow *clist_row;
2340 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2342 if (row < 0 || row >= clist->rows)
2344 if (column < 0 || column >= clist->columns)
2347 clist_row = ROW_ELEMENT (clist, row)->data;
2349 if (clist_row->cell[column].type != GTK_CMCELL_TEXT)
2353 *text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2359 gtk_cmclist_set_pixbuf (GtkCMCList *clist,
2364 GtkCMCListRow *clist_row;
2366 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2368 if (row < 0 || row >= clist->rows)
2370 if (column < 0 || column >= clist->columns)
2373 clist_row = ROW_ELEMENT (clist, row)->data;
2375 g_object_ref (pixbuf);
2377 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2378 (clist, clist_row, column, GTK_CMCELL_PIXBUF, NULL, 0, pixbuf);
2380 /* redraw the list if it's not frozen */
2381 if (CLIST_UNFROZEN (clist))
2383 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2384 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2389 gtk_cmclist_get_pixbuf (GtkCMCList *clist,
2394 GtkCMCListRow *clist_row;
2396 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2398 if (row < 0 || row >= clist->rows)
2400 if (column < 0 || column >= clist->columns)
2403 clist_row = ROW_ELEMENT (clist, row)->data;
2405 if (clist_row->cell[column].type != GTK_CMCELL_PIXBUF)
2410 *pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2417 gtk_cmclist_set_pixtext (GtkCMCList *clist,
2424 GtkCMCListRow *clist_row;
2426 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2428 if (row < 0 || row >= clist->rows)
2430 if (column < 0 || column >= clist->columns)
2433 clist_row = ROW_ELEMENT (clist, row)->data;
2435 g_object_ref (pixbuf);
2436 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2437 (clist, clist_row, column, GTK_CMCELL_PIXTEXT, text, spacing, pixbuf);
2439 /* redraw the list if it's not frozen */
2440 if (CLIST_UNFROZEN (clist))
2442 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2443 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2448 gtk_cmclist_get_pixtext (GtkCMCList *clist,
2455 GtkCMCListRow *clist_row;
2457 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2459 if (row < 0 || row >= clist->rows)
2461 if (column < 0 || column >= clist->columns)
2464 clist_row = ROW_ELEMENT (clist, row)->data;
2466 if (clist_row->cell[column].type != GTK_CMCELL_PIXTEXT)
2470 *text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2472 *spacing = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2474 *pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2480 gtk_cmclist_set_shift (GtkCMCList *clist,
2486 GtkRequisition requisition = { 0 };
2487 GtkCMCListRow *clist_row;
2489 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2491 if (row < 0 || row >= clist->rows)
2493 if (column < 0 || column >= clist->columns)
2496 clist_row = ROW_ELEMENT (clist, row)->data;
2498 if (clist->column[column].auto_resize &&
2499 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2500 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2501 column, &requisition);
2503 clist_row->cell[column].vertical = vertical;
2504 clist_row->cell[column].horizontal = horizontal;
2506 column_auto_resize (clist, clist_row, column, requisition.width);
2508 if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2509 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2512 /* PRIVATE CELL FUNCTIONS
2517 set_cell_contents (GtkCMCList *clist,
2518 GtkCMCListRow *clist_row,
2525 GtkRequisition requisition;
2526 gchar *old_text = NULL;
2527 GdkPixbuf *old_pixbuf = NULL;
2529 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2530 cm_return_if_fail (clist_row != NULL);
2532 if (clist->column[column].auto_resize &&
2533 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2534 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2535 column, &requisition);
2537 switch (clist_row->cell[column].type)
2539 case GTK_CMCELL_EMPTY:
2541 case GTK_CMCELL_TEXT:
2542 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2544 case GTK_CMCELL_PIXBUF:
2545 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2547 case GTK_CMCELL_PIXTEXT:
2548 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2549 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2551 case GTK_CMCELL_WIDGET:
2558 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2560 /* Note that pixbuf and mask were already ref'ed by the caller
2564 case GTK_CMCELL_TEXT:
2567 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2568 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2571 case GTK_CMCELL_PIXBUF:
2574 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2575 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2578 case GTK_CMCELL_PIXTEXT:
2581 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2582 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2583 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2584 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2591 if (clist->column[column].auto_resize &&
2592 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2593 column_auto_resize (clist, clist_row, column, requisition.width);
2597 g_object_unref (old_pixbuf);
2601 _gtk_cmclist_create_cell_layout (GtkCMCList *clist,
2602 GtkCMCListRow *clist_row,
2605 PangoLayout *layout;
2610 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style,
2614 cell = &clist_row->cell[column];
2617 case GTK_CMCELL_TEXT:
2618 case GTK_CMCELL_PIXTEXT:
2619 text = ((cell->type == GTK_CMCELL_PIXTEXT) ?
2620 GTK_CMCELL_PIXTEXT (*cell)->text :
2621 GTK_CMCELL_TEXT (*cell)->text);
2626 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
2627 ((cell->type == GTK_CMCELL_PIXTEXT) ?
2628 GTK_CMCELL_PIXTEXT (*cell)->text :
2629 GTK_CMCELL_TEXT (*cell)->text));
2630 pango_layout_set_font_description (layout, style->font_desc);
2640 cell_size_request (GtkCMCList *clist,
2641 GtkCMCListRow *clist_row,
2643 GtkRequisition *requisition)
2647 PangoLayout *layout;
2648 PangoRectangle logical_rect;
2650 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2651 cm_return_if_fail (requisition != NULL);
2653 layout = _gtk_cmclist_create_cell_layout (clist, clist_row, column);
2656 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2658 requisition->width = logical_rect.width;
2659 requisition->height = logical_rect.height;
2661 g_object_unref (G_OBJECT (layout));
2665 requisition->width = 0;
2666 requisition->height = 0;
2669 if (layout && clist_row->cell[column].type == GTK_CMCELL_PIXTEXT)
2670 requisition->width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2672 switch (clist_row->cell[column].type)
2674 case GTK_CMCELL_PIXTEXT:
2675 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2676 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2677 requisition->width += width;
2678 requisition->height = MAX (requisition->height, height);
2680 case GTK_CMCELL_PIXBUF:
2681 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2682 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2683 requisition->width += width;
2684 requisition->height = MAX (requisition->height, height);
2691 requisition->width += clist_row->cell[column].horizontal;
2692 requisition->height += clist_row->cell[column].vertical;
2695 /* PUBLIC INSERT/REMOVE ROW FUNCTIONS
2696 * gtk_cmclist_prepend
2697 * gtk_cmclist_append
2698 * gtk_cmclist_insert
2699 * gtk_cmclist_remove
2703 gtk_cmclist_prepend (GtkCMCList *clist,
2706 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2707 cm_return_val_if_fail (text != NULL, -1);
2709 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, 0, text);
2713 gtk_cmclist_append (GtkCMCList *clist,
2716 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2717 cm_return_val_if_fail (text != NULL, -1);
2719 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, clist->rows, text);
2723 gtk_cmclist_insert (GtkCMCList *clist,
2727 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2728 cm_return_val_if_fail (text != NULL, -1);
2730 if (row < 0 || row > clist->rows)
2733 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, row, text);
2737 gtk_cmclist_remove (GtkCMCList *clist,
2740 GTK_CMCLIST_GET_CLASS (clist)->remove_row (clist, row);
2744 gtk_cmclist_clear (GtkCMCList *clist)
2746 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2748 GTK_CMCLIST_GET_CLASS (clist)->clear (clist);
2751 /* PRIVATE INSERT/REMOVE ROW FUNCTIONS
2758 real_insert_row (GtkCMCList *clist,
2763 GtkCMCListRow *clist_row;
2765 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2766 cm_return_val_if_fail (text != NULL, -1);
2768 /* return if out of bounds */
2769 if (row < 0 || row > clist->rows)
2772 /* create the row */
2773 clist_row = row_new (clist);
2775 /* set the text in the row's columns */
2776 for (i = 0; i < clist->columns; i++)
2778 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2779 (clist, clist_row, i, GTK_CMCELL_TEXT, text[i], 0, NULL);
2783 clist->row_list = g_list_append (clist->row_list, clist_row);
2784 clist->row_list_end = clist->row_list;
2788 if (GTK_CMCLIST_AUTO_SORT(clist)) /* override insertion pos */
2793 work = clist->row_list;
2795 if (clist->sort_type == GTK_SORT_ASCENDING)
2797 while (row < clist->rows &&
2798 clist->compare (clist, clist_row,
2799 GTK_CMCLIST_ROW (work)) > 0)
2807 while (row < clist->rows &&
2808 clist->compare (clist, clist_row,
2809 GTK_CMCLIST_ROW (work)) < 0)
2817 /* reset the row end pointer if we're inserting at the end of the list */
2818 if (row == clist->rows)
2819 clist->row_list_end = (g_list_append (clist->row_list_end,
2822 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
2827 if (row < ROW_FROM_YPIXEL (clist, 0))
2828 clist->voffset -= (clist->row_height + CELL_SPACING);
2830 /* syncronize the selection list */
2831 sync_selection (clist, row, SYNC_INSERT);
2833 if (clist->rows == 1)
2835 clist->focus_row = 0;
2836 if (clist->selection_mode == GTK_SELECTION_BROWSE)
2837 gtk_cmclist_select_row (clist, 0, -1);
2840 /* redraw the list if it isn't frozen */
2841 if (CLIST_UNFROZEN (clist))
2843 adjust_adjustments (clist, FALSE);
2845 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2846 draw_rows (clist, NULL);
2853 real_remove_row (GtkCMCList *clist,
2858 GtkCMCListRow *clist_row;
2860 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2862 /* return if out of bounds */
2863 if (row < 0 || row > (clist->rows - 1))
2866 was_visible = (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
2868 /* get the row we're going to delete */
2869 list = ROW_ELEMENT (clist, row);
2870 g_assert (list != NULL);
2871 clist_row = list->data;
2873 /* if we're removing a selected row, we have to make sure
2874 * it's properly unselected, and then sync up the clist->selected
2875 * list to reflect the deincrimented indexies of rows after the
2877 if (clist_row->state == GTK_STATE_SELECTED)
2878 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
2881 sync_selection (clist, row, SYNC_REMOVE);
2883 /* reset the row end pointer if we're removing at the end of the list */
2885 if (clist->row_list == list)
2886 clist->row_list = g_list_next (list);
2887 if (clist->row_list_end == list)
2888 clist->row_list_end = g_list_previous (list);
2889 list = g_list_remove (list, clist_row);
2891 if (row < ROW_FROM_YPIXEL (clist, 0))
2892 clist->voffset += clist->row_height + CELL_SPACING;
2894 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
2895 clist->focus_row >= 0)
2896 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
2897 clist->focus_row, -1, NULL);
2900 row_delete (clist, clist_row);
2902 /* redraw the row if it isn't frozen */
2903 if (CLIST_UNFROZEN (clist))
2905 adjust_adjustments (clist, FALSE);
2908 draw_rows (clist, NULL);
2913 real_clear (GtkCMCList *clist)
2919 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2921 /* free up the selection list */
2922 g_list_free (clist->selection);
2923 g_list_free (clist->undo_selection);
2924 g_list_free (clist->undo_unselection);
2926 clist->selection = NULL;
2927 clist->selection_end = NULL;
2928 clist->undo_selection = NULL;
2929 clist->undo_unselection = NULL;
2931 clist->focus_row = -1;
2933 clist->undo_anchor = -1;
2934 clist->anchor_state = GTK_STATE_SELECTED;
2935 clist->drag_pos = -1;
2937 /* remove all the rows */
2938 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
2939 free_list = clist->row_list;
2940 clist->row_list = NULL;
2941 clist->row_list_end = NULL;
2943 for (list = free_list; list; list = list->next)
2944 row_delete (clist, GTK_CMCLIST_ROW (list));
2945 g_list_free (free_list);
2946 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
2947 for (i = 0; i < clist->columns; i++)
2948 if (clist->column[i].auto_resize)
2950 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2951 gtk_cmclist_set_column_width
2952 (clist, i, (clist->column[i].button->requisition.width -
2953 (CELL_SPACING + (2 * COLUMN_INSET))));
2955 gtk_cmclist_set_column_width (clist, i, 0);
2957 /* zero-out the scrollbars */
2958 if (clist->vadjustment)
2960 gtk_adjustment_set_value (clist->vadjustment, 0.0);
2961 CLIST_REFRESH (clist);
2964 gtk_widget_queue_resize (GTK_WIDGET (clist));
2968 real_row_move (GtkCMCList *clist,
2972 GtkCMCListRow *clist_row;
2977 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2979 if (GTK_CMCLIST_AUTO_SORT(clist))
2982 if (source_row < 0 || source_row >= clist->rows ||
2983 dest_row < 0 || dest_row >= clist->rows ||
2984 source_row == dest_row)
2987 gtk_cmclist_freeze (clist);
2989 /* unlink source row */
2990 clist_row = ROW_ELEMENT (clist, source_row)->data;
2991 if (source_row == clist->rows - 1)
2992 clist->row_list_end = clist->row_list_end->prev;
2993 clist->row_list = g_list_remove (clist->row_list, clist_row);
2996 /* relink source row */
2997 clist->row_list = g_list_insert (clist->row_list, clist_row, dest_row);
2998 if (dest_row == clist->rows)
2999 clist->row_list_end = clist->row_list_end->next;
3002 /* sync selection */
3003 if (source_row > dest_row)
3016 for (list = clist->selection; list; list = list->next)
3018 if (list->data == GINT_TO_POINTER (source_row))
3019 list->data = GINT_TO_POINTER (dest_row);
3020 else if (first <= GPOINTER_TO_INT (list->data) &&
3021 last >= GPOINTER_TO_INT (list->data))
3022 list->data = GINT_TO_POINTER (GPOINTER_TO_INT (list->data) + d);
3025 if (clist->focus_row == source_row)
3026 clist->focus_row = dest_row;
3027 else if (clist->focus_row > first)
3028 clist->focus_row += d;
3030 gtk_cmclist_thaw (clist);
3033 /* PUBLIC ROW FUNCTIONS
3034 * gtk_cmclist_moveto
3035 * gtk_cmclist_set_row_height
3036 * gtk_cmclist_set_row_data
3037 * gtk_cmclist_set_row_data_full
3038 * gtk_cmclist_get_row_data
3039 * gtk_cmclist_find_row_from_data
3040 * gtk_cmclist_swap_rows
3041 * gtk_cmclist_row_move
3042 * gtk_cmclist_row_is_visible
3043 * gtk_cmclist_set_foreground
3044 * gtk_cmclist_set_background
3047 gtk_cmclist_moveto (GtkCMCList *clist,
3053 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3055 if (row < -1 || row >= clist->rows)
3057 if (column < -1 || column >= clist->columns)
3060 row_align = CLAMP (row_align, 0, 1);
3061 col_align = CLAMP (col_align, 0, 1);
3063 /* adjust horizontal scrollbar */
3064 if (clist->hadjustment && column >= 0)
3068 x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
3069 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
3070 CELL_SPACING - clist->column[column].area.width)));
3072 gtk_adjustment_set_value (clist->hadjustment, 0.0);
3073 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
3074 gtk_adjustment_set_value
3075 (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width);
3077 gtk_adjustment_set_value (clist->hadjustment, x);
3080 /* adjust vertical scrollbar */
3081 if (clist->vadjustment && row >= 0)
3082 move_vertical (clist, row, row_align);
3086 gtk_cmclist_set_row_height (GtkCMCList *clist,
3091 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3093 widget = GTK_WIDGET (clist);
3097 clist->row_height = height;
3098 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET);
3102 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET);
3103 clist->row_height = 0;
3106 if (widget->style->font_desc)
3108 PangoContext *context = gtk_widget_get_pango_context (widget);
3109 PangoFontMetrics *metrics;
3111 metrics = pango_context_get_metrics (context,
3112 widget->style->font_desc,
3113 pango_context_get_language (context));
3115 if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist))
3117 clist->row_height = (pango_font_metrics_get_ascent (metrics) +
3118 pango_font_metrics_get_descent (metrics));
3119 clist->row_height = PANGO_PIXELS (clist->row_height);
3122 pango_font_metrics_unref (metrics);
3125 CLIST_REFRESH (clist);
3129 gtk_cmclist_set_row_data (GtkCMCList *clist,
3133 gtk_cmclist_set_row_data_full (clist, row, data, NULL);
3137 gtk_cmclist_set_row_data_full (GtkCMCList *clist,
3140 GDestroyNotify destroy)
3142 GtkCMCListRow *clist_row;
3144 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3146 if (row < 0 || row > (clist->rows - 1))
3149 clist_row = ROW_ELEMENT (clist, row)->data;
3151 if (clist_row->destroy)
3152 clist_row->destroy (clist_row->data);
3154 clist_row->data = data;
3155 clist_row->destroy = destroy;
3159 gtk_cmclist_get_row_data (GtkCMCList *clist,
3162 GtkCMCListRow *clist_row;
3164 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3166 if (row < 0 || row > (clist->rows - 1))
3169 clist_row = ROW_ELEMENT (clist, row)->data;
3170 return clist_row->data;
3174 gtk_cmclist_find_row_from_data (GtkCMCList *clist,
3180 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
3182 for (n = 0, list = clist->row_list; list; n++, list = list->next)
3183 if (GTK_CMCLIST_ROW (list)->data == data)
3190 gtk_cmclist_swap_rows (GtkCMCList *clist,
3196 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3197 cm_return_if_fail (row1 != row2);
3199 if (GTK_CMCLIST_AUTO_SORT(clist))
3202 gtk_cmclist_freeze (clist);
3204 first = MIN (row1, row2);
3205 last = MAX (row1, row2);
3207 gtk_cmclist_row_move (clist, last, first);
3208 gtk_cmclist_row_move (clist, first + 1, last);
3210 gtk_cmclist_thaw (clist);
3214 gtk_cmclist_row_move (GtkCMCList *clist,
3218 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3220 if (GTK_CMCLIST_AUTO_SORT(clist))
3223 if (source_row < 0 || source_row >= clist->rows ||
3224 dest_row < 0 || dest_row >= clist->rows ||
3225 source_row == dest_row)
3228 g_signal_emit (G_OBJECT (clist), clist_signals[ROW_MOVE], 0,
3229 source_row, dest_row);
3233 gtk_cmclist_row_is_visible (GtkCMCList *clist,
3238 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
3240 if (row < 0 || row >= clist->rows)
3241 return GTK_VISIBILITY_NONE;
3243 if (clist->row_height == 0)
3244 return GTK_VISIBILITY_NONE;
3246 if (row < ROW_FROM_YPIXEL (clist, 0))
3247 return GTK_VISIBILITY_NONE;
3249 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
3250 return GTK_VISIBILITY_NONE;
3252 top = ROW_TOP_YPIXEL (clist, row);
3255 || ((top + clist->row_height) >= clist->clist_window_height))
3256 return GTK_VISIBILITY_PARTIAL;
3258 return GTK_VISIBILITY_FULL;
3262 gtk_cmclist_set_foreground (GtkCMCList *clist,
3264 const GdkColor *color)
3266 GtkCMCListRow *clist_row;
3268 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3270 if (row < 0 || row >= clist->rows)
3273 clist_row = ROW_ELEMENT (clist, row)->data;
3277 clist_row->foreground = *color;
3278 clist_row->fg_set = TRUE;
3279 if (GTK_WIDGET_REALIZED (clist))
3280 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)),
3281 &clist_row->foreground, TRUE, TRUE);
3284 clist_row->fg_set = FALSE;
3286 if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3287 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3291 gtk_cmclist_set_background (GtkCMCList *clist,
3293 const GdkColor *color)
3295 GtkCMCListRow *clist_row;
3297 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3299 if (row < 0 || row >= clist->rows)
3302 clist_row = ROW_ELEMENT (clist, row)->data;
3306 clist_row->background = *color;
3307 clist_row->bg_set = TRUE;
3308 if (GTK_WIDGET_REALIZED (clist))
3309 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)),
3310 &clist_row->background, TRUE, TRUE);
3313 clist_row->bg_set = FALSE;
3315 if (CLIST_UNFROZEN (clist)
3316 && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3317 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3320 /* PUBLIC ROW/CELL STYLE FUNCTIONS
3321 * gtk_cmclist_set_cell_style
3322 * gtk_cmclist_get_cell_style
3323 * gtk_cmclist_set_row_style
3324 * gtk_cmclist_get_row_style
3327 gtk_cmclist_set_cell_style (GtkCMCList *clist,
3332 GtkRequisition requisition = { 0 };
3333 GtkCMCListRow *clist_row;
3335 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3337 if (row < 0 || row >= clist->rows)
3339 if (column < 0 || column >= clist->columns)
3342 clist_row = ROW_ELEMENT (clist, row)->data;
3344 if (clist_row->cell[column].style == style)
3347 if (clist->column[column].auto_resize &&
3348 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3349 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
3350 column, &requisition);
3352 if (clist_row->cell[column].style)
3354 if (GTK_WIDGET_REALIZED (clist))
3355 gtk_style_detach (clist_row->cell[column].style);
3356 g_object_unref (clist_row->cell[column].style);
3359 clist_row->cell[column].style = style;
3361 if (clist_row->cell[column].style)
3363 g_object_ref (clist_row->cell[column].style);
3365 if (GTK_WIDGET_REALIZED (clist))
3366 clist_row->cell[column].style =
3367 gtk_style_attach (clist_row->cell[column].style,
3368 clist->clist_window);
3371 column_auto_resize (clist, clist_row, column, requisition.width);
3373 /* redraw the list if it's not frozen */
3374 if (CLIST_UNFROZEN (clist))
3376 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3377 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3382 gtk_cmclist_get_cell_style (GtkCMCList *clist,
3386 GtkCMCListRow *clist_row;
3388 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3390 if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns)
3393 clist_row = ROW_ELEMENT (clist, row)->data;
3395 return clist_row->cell[column].style;
3399 gtk_cmclist_set_row_style (GtkCMCList *clist,
3403 GtkRequisition requisition;
3404 GtkCMCListRow *clist_row;
3408 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3410 if (row < 0 || row >= clist->rows)
3413 clist_row = ROW_ELEMENT (clist, row)->data;
3415 if (clist_row->style == style)
3418 old_width = g_new (gint, clist->columns);
3420 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3422 for (i = 0; i < clist->columns; i++)
3423 if (clist->column[i].auto_resize)
3425 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
3427 old_width[i] = requisition.width;
3431 if (clist_row->style)
3433 if (GTK_WIDGET_REALIZED (clist))
3434 gtk_style_detach (clist_row->style);
3435 g_object_unref (clist_row->style);
3438 clist_row->style = style;
3440 if (clist_row->style)
3442 g_object_ref (clist_row->style);
3444 if (GTK_WIDGET_REALIZED (clist))
3445 clist_row->style = gtk_style_attach (clist_row->style,
3446 clist->clist_window);
3449 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3450 for (i = 0; i < clist->columns; i++)
3451 column_auto_resize (clist, clist_row, i, old_width[i]);
3455 /* redraw the list if it's not frozen */
3456 if (CLIST_UNFROZEN (clist))
3458 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3459 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3464 gtk_cmclist_get_row_style (GtkCMCList *clist,
3467 GtkCMCListRow *clist_row;
3469 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3471 if (row < 0 || row >= clist->rows)
3474 clist_row = ROW_ELEMENT (clist, row)->data;
3476 return clist_row->style;
3479 /* PUBLIC SELECTION FUNCTIONS
3480 * gtk_cmclist_set_selectable
3481 * gtk_cmclist_get_selectable
3482 * gtk_cmclist_select_row
3483 * gtk_cmclist_unselect_row
3484 * gtk_cmclist_select_all
3485 * gtk_cmclist_unselect_all
3486 * gtk_cmclist_undo_selection
3489 gtk_cmclist_set_selectable (GtkCMCList *clist,
3491 gboolean selectable)
3493 GtkCMCListRow *clist_row;
3495 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3497 if (row < 0 || row >= clist->rows)
3500 clist_row = ROW_ELEMENT (clist, row)->data;
3502 if (selectable == clist_row->selectable)
3505 clist_row->selectable = selectable;
3507 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
3509 if (clist->anchor >= 0 &&
3510 clist->selection_mode == GTK_SELECTION_MULTIPLE)
3512 clist->drag_button = 0;
3513 remove_grab (clist);
3514 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3516 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3522 gtk_cmclist_get_selectable (GtkCMCList *clist,
3525 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), FALSE);
3527 if (row < 0 || row >= clist->rows)
3530 return GTK_CMCLIST_ROW (ROW_ELEMENT (clist, row))->selectable;
3534 gtk_cmclist_select_row (GtkCMCList *clist,
3538 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3540 if (row < 0 || row >= clist->rows)
3542 if (column < -1 || column >= clist->columns)
3545 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
3550 gtk_cmclist_unselect_row (GtkCMCList *clist,
3554 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3556 if (row < 0 || row >= clist->rows)
3558 if (column < -1 || column >= clist->columns)
3561 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3566 gtk_cmclist_select_all (GtkCMCList *clist)
3568 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3570 GTK_CMCLIST_GET_CLASS (clist)->select_all (clist);
3574 gtk_cmclist_unselect_all (GtkCMCList *clist)
3576 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3578 GTK_CMCLIST_GET_CLASS (clist)->unselect_all (clist);
3582 gtk_cmclist_undo_selection (GtkCMCList *clist)
3584 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3586 if (clist->selection_mode == GTK_SELECTION_MULTIPLE &&
3587 (clist->undo_selection || clist->undo_unselection))
3588 g_signal_emit (G_OBJECT (clist), clist_signals[UNDO_SELECTION], 0);
3591 /* PRIVATE SELECTION FUNCTIONS
3602 * real_undo_selection
3605 * update_extended_selection
3612 selection_find (GtkCMCList *clist,
3614 GList *row_list_element)
3616 return g_list_find (clist->selection, GINT_TO_POINTER (row_number));
3620 toggle_row (GtkCMCList *clist,
3625 GtkCMCListRow *clist_row;
3627 switch (clist->selection_mode)
3629 case GTK_SELECTION_MULTIPLE:
3630 case GTK_SELECTION_SINGLE:
3631 clist_row = ROW_ELEMENT (clist, row)->data;
3636 if (clist_row->state == GTK_STATE_SELECTED)
3638 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3639 row, column, event);
3642 case GTK_SELECTION_BROWSE:
3643 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
3644 row, column, event);
3647 g_assert_not_reached ();
3652 fake_toggle_row (GtkCMCList *clist,
3657 work = ROW_ELEMENT (clist, row);
3659 if (!work || !GTK_CMCLIST_ROW (work)->selectable)
3662 if (GTK_CMCLIST_ROW (work)->state == GTK_STATE_NORMAL)
3663 clist->anchor_state = GTK_CMCLIST_ROW (work)->state = GTK_STATE_SELECTED;
3665 clist->anchor_state = GTK_CMCLIST_ROW (work)->state = GTK_STATE_NORMAL;
3667 if (CLIST_UNFROZEN (clist) &&
3668 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3669 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
3670 GTK_CMCLIST_ROW (work));
3674 clist_has_grab (GtkCMCList *clist)
3676 return (GTK_WIDGET_HAS_GRAB (clist) &&
3677 gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))));
3681 toggle_focus_row (GtkCMCList *clist)
3683 cm_return_if_fail (clist != 0);
3684 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3686 if (clist_has_grab (clist) ||
3687 clist->focus_row < 0 || clist->focus_row >= clist->rows)
3690 switch (clist->selection_mode)
3692 case GTK_SELECTION_SINGLE:
3693 toggle_row (clist, clist->focus_row, 0, NULL);
3695 case GTK_SELECTION_MULTIPLE:
3696 g_list_free (clist->undo_selection);
3697 g_list_free (clist->undo_unselection);
3698 clist->undo_selection = NULL;
3699 clist->undo_unselection = NULL;
3701 clist->anchor = clist->focus_row;
3702 clist->drag_pos = clist->focus_row;
3703 clist->undo_anchor = clist->focus_row;
3705 if (GTK_CMCLIST_ADD_MODE(clist))
3706 fake_toggle_row (clist, clist->focus_row);
3708 GTK_CMCLIST_GET_CLASS (clist)->fake_unselect_all (clist,clist->focus_row);
3710 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3718 toggle_add_mode (GtkCMCList *clist)
3720 cm_return_if_fail (clist != 0);
3721 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3723 if (clist_has_grab (clist) ||
3724 clist->selection_mode != GTK_SELECTION_MULTIPLE)
3727 gtk_cmclist_draw_focus (GTK_WIDGET (clist));
3728 if (!GTK_CMCLIST_ADD_MODE(clist))
3730 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_ADD_MODE);
3731 gdk_gc_set_line_attributes (clist->xor_gc, 1,
3732 GDK_LINE_ON_OFF_DASH, 0, 0);
3733 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
3737 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ADD_MODE);
3738 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
3739 clist->anchor_state = GTK_STATE_SELECTED;
3741 gtk_cmclist_draw_focus (GTK_WIDGET (clist));
3745 real_select_row (GtkCMCList *clist,
3750 GtkCMCListRow *clist_row;
3753 gboolean row_selected;
3755 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3757 if (row < 0 || row > (clist->rows - 1))
3760 switch (clist->selection_mode)
3762 case GTK_SELECTION_SINGLE:
3763 case GTK_SELECTION_BROWSE:
3765 row_selected = FALSE;
3766 list = clist->selection;
3770 sel_row = GPOINTER_TO_INT (list->data);
3774 row_selected = TRUE;
3776 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3777 sel_row, column, event);
3787 clist_row = ROW_ELEMENT (clist, row)->data;
3789 if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable)
3792 clist_row->state = GTK_STATE_SELECTED;
3793 if (!clist->selection)
3795 clist->selection = g_list_append (clist->selection,
3796 GINT_TO_POINTER (row));
3797 clist->selection_end = clist->selection;
3800 clist->selection_end =
3801 g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next;
3803 if (CLIST_UNFROZEN (clist)
3804 && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3805 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3809 real_unselect_row (GtkCMCList *clist,
3814 GtkCMCListRow *clist_row;
3816 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3818 if (row < 0 || row > (clist->rows - 1))
3821 clist_row = ROW_ELEMENT (clist, row)->data;
3823 if (clist_row->state == GTK_STATE_SELECTED)
3825 clist_row->state = GTK_STATE_NORMAL;
3827 if (clist->selection_end &&
3828 clist->selection_end->data == GINT_TO_POINTER (row))
3829 clist->selection_end = clist->selection_end->prev;
3831 clist->selection = g_list_remove (clist->selection,
3832 GINT_TO_POINTER (row));
3834 if (CLIST_UNFROZEN (clist)
3835 && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3836 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3841 real_select_all (GtkCMCList *clist)
3843 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3845 if (clist_has_grab (clist))
3848 switch (clist->selection_mode)
3850 case GTK_SELECTION_SINGLE:
3851 case GTK_SELECTION_BROWSE:
3854 case GTK_SELECTION_MULTIPLE:
3855 g_list_free (clist->undo_selection);
3856 g_list_free (clist->undo_unselection);
3857 clist->undo_selection = NULL;
3858 clist->undo_unselection = NULL;
3861 ((GtkCMCListRow *) (clist->row_list->data))->state !=
3863 fake_toggle_row (clist, 0);
3865 clist->anchor_state = GTK_STATE_SELECTED;
3867 clist->drag_pos = 0;
3868 clist->undo_anchor = clist->focus_row;
3869 update_extended_selection (clist, clist->rows);
3870 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3873 g_assert_not_reached ();
3878 real_unselect_all (GtkCMCList *clist)
3883 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3885 if (clist_has_grab (clist))
3888 switch (clist->selection_mode)
3890 case GTK_SELECTION_BROWSE:
3891 if (clist->focus_row >= 0)
3893 g_signal_emit (G_OBJECT (clist),
3894 clist_signals[SELECT_ROW], 0,
3895 clist->focus_row, -1, NULL);
3899 case GTK_SELECTION_MULTIPLE:
3900 g_list_free (clist->undo_selection);
3901 g_list_free (clist->undo_unselection);
3902 clist->undo_selection = NULL;
3903 clist->undo_unselection = NULL;
3906 clist->drag_pos = -1;
3907 clist->undo_anchor = clist->focus_row;
3913 list = clist->selection;
3916 i = GPOINTER_TO_INT (list->data);
3918 g_signal_emit (G_OBJECT (clist),
3919 clist_signals[UNSELECT_ROW], 0, i, -1, NULL);
3924 fake_unselect_all (GtkCMCList *clist,
3931 if (row >= 0 && (work = ROW_ELEMENT (clist, row)))
3933 if (GTK_CMCLIST_ROW (work)->state == GTK_STATE_NORMAL &&
3934 GTK_CMCLIST_ROW (work)->selectable)
3936 GTK_CMCLIST_ROW (work)->state = GTK_STATE_SELECTED;
3938 if (CLIST_UNFROZEN (clist) &&
3939 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3940 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
3941 GTK_CMCLIST_ROW (work));
3945 clist->undo_selection = clist->selection;
3946 clist->selection = NULL;
3947 clist->selection_end = NULL;
3949 for (list = clist->undo_selection; list; list = list->next)
3951 if ((i = GPOINTER_TO_INT (list->data)) == row ||
3952 !(work = g_list_nth (clist->row_list, i)))
3955 GTK_CMCLIST_ROW (work)->state = GTK_STATE_NORMAL;
3956 if (CLIST_UNFROZEN (clist) &&
3957 gtk_cmclist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE)
3958 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, i,
3959 GTK_CMCLIST_ROW (work));
3964 real_undo_selection (GtkCMCList *clist)
3968 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3970 if (clist_has_grab (clist) ||
3971 clist->selection_mode != GTK_SELECTION_MULTIPLE)
3974 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3976 if (!(clist->undo_selection || clist->undo_unselection))
3978 gtk_cmclist_unselect_all (clist);
3982 for (work = clist->undo_selection; work; work = work->next)
3983 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
3984 GPOINTER_TO_INT (work->data), -1, NULL);
3986 for (work = clist->undo_unselection; work; work = work->next)
3988 /* g_print ("unselect %d\n",GPOINTER_TO_INT (work->data)); */
3989 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3990 GPOINTER_TO_INT (work->data), -1, NULL);
3993 if (GTK_WIDGET_HAS_FOCUS(clist) && clist->focus_row != clist->undo_anchor)
3995 gtk_cmclist_draw_focus (GTK_WIDGET (clist));
3996 clist->focus_row = clist->undo_anchor;
3997 gtk_cmclist_draw_focus (GTK_WIDGET (clist));
4000 clist->focus_row = clist->undo_anchor;
4002 clist->undo_anchor = -1;
4004 g_list_free (clist->undo_selection);
4005 g_list_free (clist->undo_unselection);
4006 clist->undo_selection = NULL;
4007 clist->undo_unselection = NULL;
4009 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
4010 clist->clist_window_height)
4011 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4012 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
4013 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4017 set_anchor (GtkCMCList *clist,
4022 cm_return_if_fail (GTK_IS_CMCLIST (clist));
4024 if (clist->selection_mode != GTK_SELECTION_MULTIPLE || clist->anchor >= 0)
4027 g_list_free (clist->undo_selection);
4028 g_list_free (clist->undo_unselection);
4029 clist->undo_selection = NULL;
4030 clist->undo_unselection = NULL;
4033 fake_toggle_row (clist, anchor);
4036 GTK_CMCLIST_GET_CLASS (clist)->fake_unselect_all (clist, anchor);
4037 clist->anchor_state = GTK_STATE_SELECTED;
4040 clist->anchor = anchor;
4041 clist->drag_pos = anchor;
4042 clist->undo_anchor = undo_anchor;
4046 resync_selection (GtkCMCList *clist,
4053 GtkCMCListRow *clist_row;
4055 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
4058 if (clist->anchor < 0 || clist->drag_pos < 0)
4061 gtk_cmclist_freeze (clist);
4063 i = MIN (clist->anchor, clist->drag_pos);
4064 e = MAX (clist->anchor, clist->drag_pos);
4066 if (clist->undo_selection)
4068 list = clist->selection;
4069 clist->selection = clist->undo_selection;
4070 clist->selection_end = g_list_last (clist->selection);
4071 clist->undo_selection = list;
4072 list = clist->selection;
4075 row = GPOINTER_TO_INT (list->data);
4077 if (row < i || row > e)
4079 clist_row = g_list_nth (clist->row_list, row)->data;
4080 if (clist_row->selectable)
4082 clist_row->state = GTK_STATE_SELECTED;
4083 g_signal_emit (G_OBJECT (clist),
4084 clist_signals[UNSELECT_ROW], 0,
4086 clist->undo_selection = g_list_prepend
4087 (clist->undo_selection, GINT_TO_POINTER (row));
4093 if (clist->anchor < clist->drag_pos)
4095 for (list = g_list_nth (clist->row_list, i); i <= e;
4096 i++, list = list->next)
4097 if (GTK_CMCLIST_ROW (list)->selectable)
4099 if (g_list_find (clist->selection, GINT_TO_POINTER(i)))
4101 if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_NORMAL)
4103 GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED;
4104 g_signal_emit (G_OBJECT (clist),
4105 clist_signals[UNSELECT_ROW], 0,
4107 clist->undo_selection =
4108 g_list_prepend (clist->undo_selection,
4109 GINT_TO_POINTER (i));
4112 else if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED)
4114 GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL;
4115 clist->undo_unselection =
4116 g_list_prepend (clist->undo_unselection,
4117 GINT_TO_POINTER (i));
4123 for (list = g_list_nth (clist->row_list, e); i <= e;
4124 e--, list = list->prev)
4125 if (GTK_CMCLIST_ROW (list)->selectable)
4127 if (g_list_find (clist->selection, GINT_TO_POINTER(e)))
4129 if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_NORMAL)
4131 GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED;
4132 g_signal_emit (G_OBJECT (clist),
4133 clist_signals[UNSELECT_ROW], 0,
4135 clist->undo_selection =
4136 g_list_prepend (clist->undo_selection,
4137 GINT_TO_POINTER (e));
4140 else if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED)
4142 GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL;
4143 clist->undo_unselection =
4144 g_list_prepend (clist->undo_unselection,
4145 GINT_TO_POINTER (e));
4150 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
4151 for (list = clist->undo_unselection; list; list = list->next)
4152 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
4153 GPOINTER_TO_INT (list->data), -1, event);
4156 clist->drag_pos = -1;
4158 gtk_cmclist_thaw (clist);
4162 update_extended_selection (GtkCMCList *clist,
4172 gint y1 = clist->clist_window_height;
4173 gint y2 = clist->clist_window_height;
4178 if (clist->selection_mode != GTK_SELECTION_MULTIPLE || clist->anchor == -1)
4183 if (row >= clist->rows)
4184 row = clist->rows - 1;
4186 /* extending downwards */
4187 if (row > clist->drag_pos && clist->anchor <= clist->drag_pos)
4189 s2 = clist->drag_pos + 1;
4192 /* extending upwards */
4193 else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos)
4196 e2 = clist->drag_pos - 1;
4198 else if (row < clist->drag_pos && clist->anchor < clist->drag_pos)
4200 e1 = clist->drag_pos;
4201 /* row and drag_pos on different sides of anchor :
4202 take back the selection between anchor and drag_pos,
4203 select between anchor and row */
4204 if (row < clist->anchor)
4206 s1 = clist->anchor + 1;
4208 e2 = clist->anchor - 1;
4210 /* take back the selection between anchor and drag_pos */
4214 else if (row > clist->drag_pos && clist->anchor > clist->drag_pos)
4216 s1 = clist->drag_pos;
4217 /* row and drag_pos on different sides of anchor :
4218 take back the selection between anchor and drag_pos,
4219 select between anchor and row */
4220 if (row > clist->anchor)
4222 e1 = clist->anchor - 1;
4223 s2 = clist->anchor + 1;
4226 /* take back the selection between anchor and drag_pos */
4231 clist->drag_pos = row;
4234 area.width = clist->clist_window_width;
4236 /* restore the elements between s1 and e1 */
4239 for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1;
4240 i++, list = list->next)
4241 if (GTK_CMCLIST_ROW (list)->selectable)
4243 if (GTK_CMCLIST_GET_CLASS (clist)->selection_find (clist, i, list))
4244 GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED;
4246 GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL;
4249 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
4251 if (top + clist->row_height <= 0)
4254 area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height;
4255 draw_rows (clist, &area);
4256 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4258 else if (top >= clist->clist_window_height)
4260 area.y = ROW_TOP_YPIXEL (clist, s1) - 1;
4261 area.height = clist->clist_window_height - area.y;
4262 draw_rows (clist, &area);
4263 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4266 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4267 else if (top + clist->row_height > clist->clist_window_height)
4268 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4270 y1 = ROW_TOP_YPIXEL (clist, s1) - 1;
4271 h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING);
4274 /* extend the selection between s2 and e2 */
4277 for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2;
4278 i++, list = list->next)
4279 if (GTK_CMCLIST_ROW (list)->selectable &&
4280 GTK_CMCLIST_ROW (list)->state != clist->anchor_state)
4281 GTK_CMCLIST_ROW (list)->state = clist->anchor_state;
4283 top = ROW_TOP_YPIXEL (clist, clist->focus_row);
4285 if (top + clist->row_height <= 0)
4288 area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height;
4289 draw_rows (clist, &area);
4290 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4292 else if (top >= clist->clist_window_height)
4294 area.y = ROW_TOP_YPIXEL (clist, s2) - 1;
4295 area.height = clist->clist_window_height - area.y;
4296 draw_rows (clist, &area);
4297 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4300 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4301 else if (top + clist->row_height > clist->clist_window_height)
4302 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4304 y2 = ROW_TOP_YPIXEL (clist, s2) - 1;
4305 h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING);
4308 area.y = MAX (0, MIN (y1, y2));
4309 if (area.y > clist->clist_window_height)
4311 area.height = MIN (clist->clist_window_height, h1 + h2);
4312 if (s1 >= 0 && s2 >= 0)
4313 area.height += (clist->row_height + CELL_SPACING);
4314 draw_rows (clist, &area);
4318 start_selection (GtkCMCList *clist)
4320 cm_return_if_fail (GTK_IS_CMCLIST (clist));
4322 if (clist_has_grab (clist))
4325 set_anchor (clist, GTK_CMCLIST_ADD_MODE(clist), clist->focus_row,
4330 end_selection (GtkCMCList *clist)
4332 cm_return_if_fail (GTK_IS_CMCLIST (clist));
4334 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4335 GTK_WIDGET_HAS_FOCUS (clist))
4338 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4342 extend_selection (GtkCMCList *clist,
4343 GtkScrollType scroll_type,
4345 gboolean auto_start_selection)
4347 cm_return_if_fail (GTK_IS_CMCLIST (clist));
4349 if (clist_has_grab (clist) ||
4350 clist->selection_mode != GTK_SELECTION_MULTIPLE)
4353 if (auto_start_selection)
4354 set_anchor (clist, GTK_CMCLIST_ADD_MODE(clist), clist->focus_row,
4356 else if (clist->anchor == -1)
4359 move_focus_row (clist, scroll_type, position);
4361 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
4362 clist->clist_window_height)
4363 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
4364 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
4365 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
4367 update_extended_selection (clist, clist->focus_row);
4371 sync_selection (GtkCMCList *clist,
4378 if (mode == SYNC_INSERT)
4383 if (clist->focus_row >= row)
4385 if (d > 0 || clist->focus_row > row)
4386 clist->focus_row += d;
4387 if (clist->focus_row == -1 && clist->rows >= 1)
4388 clist->focus_row = 0;
4389 else if (d < 0 && clist->focus_row >= clist->rows - 1)
4390 clist->focus_row = clist->rows - 2;
4391 else if (clist->focus_row >= clist->rows) /* Paranoia */
4392 clist->focus_row = clist->rows - 1;
4395 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4397 g_list_free (clist->undo_selection);
4398 g_list_free (clist->undo_unselection);
4399 clist->undo_selection = NULL;
4400 clist->undo_unselection = NULL;
4403 clist->drag_pos = -1;
4404 clist->undo_anchor = clist->focus_row;
4406 list = clist->selection;
4410 if (GPOINTER_TO_INT (list->data) >= row)
4411 list->data = ((gchar*) list->data) + d;
4417 * gtk_cmclist_destroy
4418 * gtk_cmclist_finalize
4421 gtk_cmclist_destroy (GtkObject *object)
4426 cm_return_if_fail (GTK_IS_CMCLIST (object));
4428 clist = GTK_CMCLIST (object);
4430 /* freeze the list */
4431 clist->freeze_count++;
4433 /* get rid of all the rows */
4434 gtk_cmclist_clear (clist);
4436 /* Since we don't have a _remove method, unparent the children
4437 * instead of destroying them so the focus will be unset properly.
4438 * (For other containers, the _remove method takes care of the
4439 * unparent) The destroy will happen when the refcount drops
4443 /* unref adjustments */
4444 if (clist->hadjustment)
4446 g_signal_handlers_disconnect_matched(G_OBJECT (clist->hadjustment), G_SIGNAL_MATCH_DATA,
4448 g_object_unref (G_OBJECT (clist->hadjustment));
4449 clist->hadjustment = NULL;
4451 if (clist->vadjustment)
4453 g_signal_handlers_disconnect_matched(G_OBJECT (clist->vadjustment), G_SIGNAL_MATCH_DATA,
4455 g_object_unref (G_OBJECT (clist->vadjustment));
4456 clist->vadjustment = NULL;
4459 remove_grab (clist);
4461 /* destroy the column buttons */
4462 for (i = 0; i < clist->columns; i++)
4463 if (clist->column[i].button)
4465 gtk_widget_unparent (clist->column[i].button);
4466 clist->column[i].button = NULL;
4469 if (GTK_OBJECT_CLASS (parent_class)->destroy)
4470 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
4474 gtk_cmclist_finalize (GObject *object)
4478 cm_return_if_fail (GTK_IS_CMCLIST (object));
4480 clist = GTK_CMCLIST (object);
4482 columns_delete (clist);
4484 #if !GLIB_CHECK_VERSION(2,10,0)
4485 g_mem_chunk_destroy (clist->cell_mem_chunk);
4486 g_mem_chunk_destroy (clist->row_mem_chunk);
4488 G_OBJECT_CLASS (parent_class)->finalize (object);
4492 * gtk_cmclist_realize
4493 * gtk_cmclist_unrealize
4496 * gtk_cmclist_expose
4497 * gtk_cmclist_style_set
4498 * gtk_cmclist_button_press
4499 * gtk_cmclist_button_release
4500 * gtk_cmclist_motion
4501 * gtk_cmclist_size_request
4502 * gtk_cmclist_size_allocate
4505 gtk_cmclist_realize (GtkWidget *widget)
4508 GdkWindowAttr attributes;
4510 GtkCMCListRow *clist_row;
4512 gint attributes_mask;
4517 cm_return_if_fail (GTK_IS_CMCLIST (widget));
4519 clist = GTK_CMCLIST (widget);
4521 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
4523 border_width = GTK_CONTAINER (widget)->border_width;
4525 attributes.window_type = GDK_WINDOW_CHILD;
4526 attributes.x = widget->allocation.x + border_width;
4527 attributes.y = widget->allocation.y + border_width;
4528 attributes.width = widget->allocation.width - border_width * 2;
4529 attributes.height = widget->allocation.height - border_width * 2;
4530 attributes.wclass = GDK_INPUT_OUTPUT;
4531 attributes.visual = gtk_widget_get_visual (widget);
4532 attributes.colormap = gtk_widget_get_colormap (widget);
4533 attributes.event_mask = gtk_widget_get_events (widget);
4534 attributes.event_mask |= (GDK_EXPOSURE_MASK |
4535 GDK_BUTTON_PRESS_MASK |
4536 GDK_BUTTON_RELEASE_MASK |
4537 GDK_KEY_RELEASE_MASK);
4538 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
4541 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
4542 &attributes, attributes_mask);
4543 gdk_window_set_user_data (widget->window, clist);
4545 widget->style = gtk_style_attach (widget->style, widget->window);
4547 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
4549 /* column-title window */
4551 attributes.x = clist->column_title_area.x;
4552 attributes.y = clist->column_title_area.y;
4553 attributes.width = clist->column_title_area.width;
4554 attributes.height = clist->column_title_area.height;
4556 clist->title_window = gdk_window_new (widget->window, &attributes,
4558 gdk_window_set_user_data (clist->title_window, clist);
4560 gtk_style_set_background (widget->style, clist->title_window,
4562 gdk_window_show (clist->title_window);
4564 /* set things up so column buttons are drawn in title window */
4565 for (i = 0; i < clist->columns; i++)
4566 if (clist->column[i].button)
4567 gtk_widget_set_parent_window (clist->column[i].button,
4568 clist->title_window);
4571 attributes.x = (clist->internal_allocation.x +
4572 widget->style->xthickness);
4573 attributes.y = (clist->internal_allocation.y +
4574 widget->style->ythickness +
4575 clist->column_title_area.height);
4576 attributes.width = clist->clist_window_width;
4577 attributes.height = clist->clist_window_height;
4579 clist->clist_window = gdk_window_new (widget->window, &attributes,
4581 gdk_window_set_user_data (clist->clist_window, clist);
4583 gdk_window_set_background (clist->clist_window,
4584 &widget->style->base[GTK_STATE_NORMAL]);
4585 gdk_window_show (clist->clist_window);
4586 gdk_drawable_get_size (clist->clist_window, &clist->clist_window_width,
4587 &clist->clist_window_height);
4589 /* create resize windows */
4590 attributes.wclass = GDK_INPUT_ONLY;
4591 attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
4592 GDK_BUTTON_RELEASE_MASK |
4593 GDK_POINTER_MOTION_MASK |
4594 GDK_POINTER_MOTION_HINT_MASK);
4595 attributes_mask = GDK_WA_CURSOR;
4596 attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
4597 GDK_SB_H_DOUBLE_ARROW);
4598 clist->cursor_drag = attributes.cursor;
4600 attributes.x = LIST_WIDTH (clist) + 1;
4602 attributes.width = 0;
4603 attributes.height = 0;
4605 for (i = 0; i < clist->columns; i++)
4607 clist->column[i].window = gdk_window_new (clist->title_window,
4608 &attributes, attributes_mask);
4609 gdk_window_set_user_data (clist->column[i].window, clist);
4612 /* This is slightly less efficient than creating them with the
4613 * right size to begin with, but easier
4615 size_allocate_title_buttons (clist);
4618 clist->fg_gc = gdk_gc_new (widget->window);
4619 clist->bg_gc = gdk_gc_new (widget->window);
4621 /* We'll use this gc to do scrolling as well */
4622 gdk_gc_set_exposures (clist->fg_gc, TRUE);
4624 values.foreground = (widget->style->white.pixel==0 ?
4625 widget->style->black:widget->style->white);
4626 values.function = GDK_XOR;
4627 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
4628 clist->xor_gc = gdk_gc_new_with_values (widget->window,
4634 /* attach optional row/cell styles, allocate foreground/background colors */
4635 list = clist->row_list;
4636 for (i = 0; i < clist->rows; i++)
4638 clist_row = list->data;
4641 if (clist_row->style)
4642 clist_row->style = gtk_style_attach (clist_row->style,
4643 clist->clist_window);
4645 if (clist_row->fg_set || clist_row->bg_set)
4647 GdkColormap *colormap;
4649 colormap = gtk_widget_get_colormap (widget);
4650 if (clist_row->fg_set)
4651 gdk_colormap_alloc_color (colormap, &clist_row->foreground, TRUE, TRUE);
4652 if (clist_row->bg_set)
4653 gdk_colormap_alloc_color (colormap, &clist_row->background, TRUE, TRUE);
4656 for (j = 0; j < clist->columns; j++)
4657 if (clist_row->cell[j].style)
4658 clist_row->cell[j].style =
4659 gtk_style_attach (clist_row->cell[j].style, clist->clist_window);
4664 gtk_cmclist_unrealize (GtkWidget *widget)
4669 cm_return_if_fail (GTK_IS_CMCLIST (widget));
4671 clist = GTK_CMCLIST (widget);
4673 /* freeze the list */
4674 clist->freeze_count++;
4676 if (GTK_WIDGET_MAPPED (widget))
4677 gtk_cmclist_unmap (widget);
4679 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
4681 /* detach optional row/cell styles */
4682 if (GTK_WIDGET_REALIZED (widget))
4684 GtkCMCListRow *clist_row;
4688 list = clist->row_list;
4689 for (i = 0; i < clist->rows; i++)
4691 clist_row = list->data;
4694 if (clist_row->style)
4695 gtk_style_detach (clist_row->style);
4696 for (j = 0; j < clist->columns; j++)
4697 if (clist_row->cell[j].style)
4698 gtk_style_detach (clist_row->cell[j].style);
4702 gdk_cursor_unref (clist->cursor_drag);
4703 g_object_unref (clist->xor_gc);
4704 g_object_unref (clist->fg_gc);
4705 g_object_unref (clist->bg_gc);
4707 for (i = 0; i < clist->columns; i++)
4709 if (clist->column[i].button)
4710 gtk_widget_unrealize (clist->column[i].button);
4711 if (clist->column[i].window)
4713 gdk_window_set_user_data (clist->column[i].window, NULL);
4714 gdk_window_destroy (clist->column[i].window);
4715 clist->column[i].window = NULL;
4719 gdk_window_set_user_data (clist->clist_window, NULL);
4720 gdk_window_destroy (clist->clist_window);
4721 clist->clist_window = NULL;
4723 gdk_window_set_user_data (clist->title_window, NULL);
4724 gdk_window_destroy (clist->title_window);
4725 clist->title_window = NULL;
4727 clist->cursor_drag = NULL;
4728 clist->xor_gc = NULL;
4729 clist->fg_gc = NULL;
4730 clist->bg_gc = NULL;
4732 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
4733 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
4737 gtk_cmclist_map (GtkWidget *widget)
4742 cm_return_if_fail (GTK_IS_CMCLIST (widget));
4744 clist = GTK_CMCLIST (widget);
4746 if (!GTK_WIDGET_MAPPED (widget))
4748 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
4750 /* map column buttons */
4751 for (i = 0; i < clist->columns; i++)
4753 if (clist->column[i].button &&
4754 GTK_WIDGET_VISIBLE (clist->column[i].button) &&
4755 !GTK_WIDGET_MAPPED (clist->column[i].button))
4756 gtk_widget_map (clist->column[i].button);
4759 for (i = 0; i < clist->columns; i++)
4760 if (clist->column[i].window && clist->column[i].button)
4762 gdk_window_raise (clist->column[i].window);
4763 gdk_window_show (clist->column[i].window);
4766 gdk_window_show (clist->title_window);
4767 gdk_window_show (clist->clist_window);
4768 gdk_window_show (widget->window);
4770 /* unfreeze the list */
4771 clist->freeze_count = 0;
4776 gtk_cmclist_unmap (GtkWidget *widget)
4781 cm_return_if_fail (GTK_IS_CMCLIST (widget));
4783 clist = GTK_CMCLIST (widget);
4785 if (GTK_WIDGET_MAPPED (widget))
4787 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
4789 if (clist_has_grab (clist))
4791 remove_grab (clist);
4793 GTK_CMCLIST_GET_CLASS (widget)->resync_selection (clist, NULL);
4795 clist->click_cell.row = -1;
4796 clist->click_cell.column = -1;
4797 clist->drag_button = 0;
4799 if (GTK_CMCLIST_IN_DRAG(clist))
4803 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG);
4804 drag_data = g_object_get_data (G_OBJECT (clist),
4807 g_signal_handlers_unblock_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA,
4808 0, 0, 0, 0, drag_data);
4812 for (i = 0; i < clist->columns; i++)
4813 if (clist->column[i].window)
4814 gdk_window_hide (clist->column[i].window);
4816 gdk_window_hide (clist->clist_window);
4817 gdk_window_hide (clist->title_window);
4818 gdk_window_hide (widget->window);
4820 /* unmap column buttons */
4821 for (i = 0; i < clist->columns; i++)
4822 if (clist->column[i].button &&
4823 GTK_WIDGET_MAPPED (clist->column[i].button))
4824 gtk_widget_unmap (clist->column[i].button);
4826 /* freeze the list */
4827 clist->freeze_count++;
4832 gtk_cmclist_expose (GtkWidget *widget,
4833 GdkEventExpose *event)
4837 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
4838 cm_return_val_if_fail (event != NULL, FALSE);
4840 if (GTK_WIDGET_DRAWABLE (widget))
4842 clist = GTK_CMCLIST (widget);
4845 if (event->window == widget->window)
4846 gtk_paint_shadow (widget->style, widget->window,
4847 GTK_STATE_NORMAL, clist->shadow_type,
4850 clist->clist_window_width +
4851 (2 * widget->style->xthickness),
4852 clist->clist_window_height +
4853 (2 * widget->style->ythickness) +
4854 clist->column_title_area.height);
4856 /* exposure events on the list */
4857 if (event->window == clist->clist_window)
4858 draw_rows (clist, &event->area);
4860 if (event->window == clist->clist_window &&
4861 clist->drag_highlight_row >= 0)
4862 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
4863 (clist, g_list_nth (clist->row_list,
4864 clist->drag_highlight_row)->data,
4865 clist->drag_highlight_row, clist->drag_highlight_pos);
4867 if (event->window == clist->title_window)
4871 for (i = 0; i < clist->columns; i++)
4873 if (clist->column[i].button) {
4874 gtk_container_propagate_expose (GTK_CONTAINER (clist),
4875 clist->column[i].button,
4886 gtk_cmclist_style_set (GtkWidget *widget,
4887 GtkStyle *previous_style)
4891 cm_return_if_fail (GTK_IS_CMCLIST (widget));
4893 if (GTK_WIDGET_CLASS (parent_class)->style_set)
4894 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
4896 clist = GTK_CMCLIST (widget);
4898 if (GTK_WIDGET_REALIZED (widget))
4900 gtk_style_set_background (widget->style, widget->window, widget->state);
4901 gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_NORMAL);
4902 gdk_window_set_background (clist->clist_window, &widget->style->base[GTK_STATE_NORMAL]);
4905 /* Fill in data after widget has correct style */
4907 /* text properties */
4908 if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist))
4909 /* Reset clist->row_height */
4910 gtk_cmclist_set_row_height (clist, 0);
4913 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4918 for (i = 0; i < clist->columns; i++)
4919 if (clist->column[i].auto_resize)
4921 width = gtk_cmclist_optimal_column_width (clist, i);
4922 if (width != clist->column[i].width)
4923 gtk_cmclist_set_column_width (clist, i, width);
4929 gtk_cmclist_button_press (GtkWidget *widget,
4930 GdkEventButton *event)
4938 gint button_actions;
4940 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
4941 cm_return_val_if_fail (event != NULL, FALSE);
4943 clist = GTK_CMCLIST (widget);
4945 button_actions = clist->button_actions[event->button - 1];
4947 if (button_actions == GTK_CMBUTTON_IGNORED)
4950 /* selections on the list */
4951 if (event->window == clist->clist_window)
4956 if (get_selection_info (clist, x, y, &row, &column))
4958 gint old_row = clist->focus_row;
4960 if (clist->focus_row == -1)
4963 if (event->type == GDK_BUTTON_PRESS)
4965 GdkEventMask mask = ((1 << (4 + event->button)) |
4966 GDK_POINTER_MOTION_HINT_MASK |
4967 GDK_BUTTON_RELEASE_MASK);
4969 if (gdk_pointer_grab (clist->clist_window, FALSE, mask,
4970 NULL, NULL, event->time))
4972 gtk_grab_add (widget);
4974 clist->click_cell.row = row;
4975 clist->click_cell.column = column;
4976 clist->drag_button = event->button;
4980 clist->click_cell.row = -1;
4981 clist->click_cell.column = -1;
4983 clist->drag_button = 0;
4984 remove_grab (clist);
4987 if (button_actions & GTK_CMBUTTON_SELECTS)
4989 if (GTK_CMCLIST_ADD_MODE(clist))
4991 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ADD_MODE);
4992 if (GTK_WIDGET_HAS_FOCUS(widget))
4994 gtk_cmclist_draw_focus (widget);
4995 gdk_gc_set_line_attributes (clist->xor_gc, 1,
4996 GDK_LINE_SOLID, 0, 0);
4997 clist->focus_row = row;
4998 gtk_cmclist_draw_focus (widget);
5002 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5003 GDK_LINE_SOLID, 0, 0);
5004 clist->focus_row = row;
5007 else if (row != clist->focus_row)
5009 if (GTK_WIDGET_HAS_FOCUS(widget))
5011 gtk_cmclist_draw_focus (widget);
5012 clist->focus_row = row;
5013 gtk_cmclist_draw_focus (widget);
5016 clist->focus_row = row;
5020 if (!GTK_WIDGET_HAS_FOCUS(widget))
5021 gtk_widget_grab_focus (widget);
5023 if (button_actions & GTK_CMBUTTON_SELECTS)
5025 switch (clist->selection_mode)
5027 case GTK_SELECTION_SINGLE:
5028 if (event->type != GDK_BUTTON_PRESS)
5030 g_signal_emit (G_OBJECT (clist),
5031 clist_signals[SELECT_ROW], 0,
5032 row, column, event);
5036 clist->anchor = row;
5038 case GTK_SELECTION_BROWSE:
5039 g_signal_emit (G_OBJECT (clist),
5040 clist_signals[SELECT_ROW], 0,
5041 row, column, event);
5043 case GTK_SELECTION_MULTIPLE:
5044 if (event->type != GDK_BUTTON_PRESS)
5046 if (clist->anchor != -1)
5048 update_extended_selection (clist, clist->focus_row);
5049 GTK_CMCLIST_GET_CLASS (clist)->resync_selection
5050 (clist, (GdkEvent *) event);
5052 g_signal_emit (G_OBJECT (clist),
5053 clist_signals[SELECT_ROW], 0,
5054 row, column, event);
5058 if (event->state & GDK_CONTROL_MASK)
5060 if (event->state & GDK_SHIFT_MASK)
5062 if (clist->anchor < 0)
5064 g_list_free (clist->undo_selection);
5065 g_list_free (clist->undo_unselection);
5066 clist->undo_selection = NULL;
5067 clist->undo_unselection = NULL;
5068 clist->anchor = old_row;
5069 clist->drag_pos = old_row;
5070 clist->undo_anchor = old_row;
5072 update_extended_selection (clist, clist->focus_row);
5076 if (clist->anchor == -1)
5077 set_anchor (clist, TRUE, row, old_row);
5079 update_extended_selection (clist,
5085 if (event->state & GDK_SHIFT_MASK)
5087 set_anchor (clist, FALSE, old_row, old_row);
5088 update_extended_selection (clist, clist->focus_row);
5092 if (clist->anchor == -1)
5093 set_anchor (clist, FALSE, row, old_row);
5095 update_extended_selection (clist, clist->focus_row);
5105 /* press on resize windows */
5106 for (i = 0; i < clist->columns; i++)
5107 if (clist->column[i].resizeable && clist->column[i].window &&
5108 event->window == clist->column[i].window)
5112 if (gdk_pointer_grab (clist->column[i].window, FALSE,
5113 GDK_POINTER_MOTION_HINT_MASK |
5114 GDK_BUTTON1_MOTION_MASK |
5115 GDK_BUTTON_RELEASE_MASK,
5116 NULL, NULL, event->time))
5119 gtk_grab_add (widget);
5120 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_IN_DRAG);
5122 /* block attached dnd signal handler */
5123 drag_data = g_object_get_data (G_OBJECT (clist), "gtk-site-data");
5125 g_signal_handlers_block_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA,
5126 0, 0, 0, 0, drag_data);
5128 if (!GTK_WIDGET_HAS_FOCUS(widget))
5129 gtk_widget_grab_focus (widget);
5131 clist->drag_pos = i;
5132 clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET +
5133 clist->column[i].area.width + CELL_SPACING);
5135 if (GTK_CMCLIST_ADD_MODE(clist))
5136 gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0);
5137 draw_xor_line (clist);
5146 gtk_cmclist_button_release (GtkWidget *widget,
5147 GdkEventButton *event)
5150 gint button_actions;
5152 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
5153 cm_return_val_if_fail (event != NULL, FALSE);
5155 clist = GTK_CMCLIST (widget);
5157 button_actions = clist->button_actions[event->button - 1];
5158 if (button_actions == GTK_CMBUTTON_IGNORED)
5161 /* release on resize windows */
5162 if (GTK_CMCLIST_IN_DRAG(clist))
5169 i = clist->drag_pos;
5170 clist->drag_pos = -1;
5172 /* unblock attached dnd signal handler */
5173 drag_data = g_object_get_data (G_OBJECT (clist), "gtk-site-data");
5175 g_signal_handlers_unblock_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA,
5176 0, 0, 0, 0, drag_data);
5178 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG);
5179 gtk_widget_get_pointer (widget, &x, NULL);
5180 gtk_grab_remove (widget);
5181 gdk_display_pointer_ungrab (gtk_widget_get_display (widget), event->time);
5183 if (clist->x_drag >= 0)
5184 draw_xor_line (clist);
5186 if (GTK_CMCLIST_ADD_MODE(clist))
5188 gdk_gc_set_line_attributes (clist->xor_gc, 1,
5189 GDK_LINE_ON_OFF_DASH, 0, 0);
5190 gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2);
5193 width = new_column_width (clist, i, &x);
5194 gtk_cmclist_set_column_width (clist, i, width);
5199 if (clist->drag_button == event->button)
5204 clist->drag_button = 0;
5205 clist->click_cell.row = -1;
5206 clist->click_cell.column = -1;
5208 remove_grab (clist);
5210 if (button_actions & GTK_CMBUTTON_SELECTS)
5212 switch (clist->selection_mode)
5214 case GTK_SELECTION_MULTIPLE:
5215 if (!(event->state & GDK_SHIFT_MASK) ||
5216 !GTK_WIDGET_CAN_FOCUS (widget) ||
5217 event->x < 0 || event->x >= clist->clist_window_width ||
5218 event->y < 0 || event->y >= clist->clist_window_height)
5219 GTK_CMCLIST_GET_CLASS (clist)->resync_selection
5220 (clist, (GdkEvent *) event);
5222 case GTK_SELECTION_SINGLE:
5223 if (get_selection_info (clist, event->x, event->y,
5226 if (row >= 0 && row < clist->rows && clist->anchor == row)
5227 toggle_row (clist, row, column, (GdkEvent *) event);
5243 gtk_cmclist_motion (GtkWidget *widget,
5244 GdkEventMotion *event)
5251 gint button_actions = 0;
5253 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
5255 clist = GTK_CMCLIST (widget);
5256 if (!clist_has_grab (clist))
5259 if (clist->drag_button > 0)
5260 button_actions = clist->button_actions[clist->drag_button - 1];
5262 if (GTK_CMCLIST_IN_DRAG(clist))
5264 if (event->is_hint || event->window != widget->window)
5265 gtk_widget_get_pointer (widget, &x, NULL);
5269 new_width = new_column_width (clist, clist->drag_pos, &x);
5270 if (x != clist->x_drag)
5272 /* x_drag < 0 indicates that the xor line is already invisible */
5273 if (clist->x_drag >= 0)
5274 draw_xor_line (clist);
5278 if (clist->x_drag >= 0)
5279 draw_xor_line (clist);
5282 if (new_width <= MAX (COLUMN_MIN_WIDTH + 1,
5283 clist->column[clist->drag_pos].min_width + 1))
5285 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0)
5286 gtk_cmclist_moveto (clist, -1, clist->drag_pos, 0, 0);
5289 if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH &&
5290 new_width >= clist->column[clist->drag_pos].max_width)
5292 if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width >
5293 clist->clist_window_width && x < 0)
5294 move_horizontal (clist,
5295 COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) +
5296 new_width - clist->clist_window_width +
5297 COLUMN_INSET + CELL_SPACING);
5302 if (event->is_hint || event->window != clist->clist_window)
5303 gdk_window_get_pointer (clist->clist_window, &x, &y, NULL);
5310 if (GTK_CMCLIST_REORDERABLE(clist) && button_actions & GTK_CMBUTTON_DRAGS)
5312 /* delayed drag start */
5313 if (event->window == clist->clist_window &&
5314 clist->click_cell.row >= 0 && clist->click_cell.column >= 0 &&
5315 (y < 0 || y >= clist->clist_window_height ||
5316 x < 0 || x >= clist->clist_window_width ||
5317 y < ROW_TOP_YPIXEL (clist, clist->click_cell.row) ||
5318 y >= (ROW_TOP_YPIXEL (clist, clist->click_cell.row) +
5319 clist->row_height) ||
5320 x < COLUMN_LEFT_XPIXEL (clist, clist->click_cell.column) ||
5321 x >= (COLUMN_LEFT_XPIXEL(clist, clist->click_cell.column) +
5322 clist->column[clist->click_cell.column].area.width)))
5324 GtkTargetList *target_list;
5326 target_list = gtk_target_list_new (&clist_target_table, 1);
5327 gtk_drag_begin (widget, target_list, GDK_ACTION_MOVE,
5328 clist->drag_button, (GdkEvent *)event);
5334 /* horizontal autoscrolling */
5335 if (clist->hadjustment && LIST_WIDTH (clist) > clist->clist_window_width &&
5336 (x < 0 || x >= clist->clist_window_width))
5341 #if GTK_CHECK_VERSION(2,12,0)
5342 clist->htimer = gdk_threads_add_timeout
5343 (SCROLL_TIME, (GSourceFunc) horizontal_timeout, clist);
5345 clist->htimer = g_timeout_add
5346 (SCROLL_TIME, (GSourceFunc) horizontal_timeout, clist);
5348 if (!((x < 0 && clist->hadjustment->value == 0) ||
5349 (x >= clist->clist_window_width &&
5350 clist->hadjustment->value ==
5351 LIST_WIDTH (clist) - clist->clist_window_width)))
5354 move_horizontal (clist, -1 + (x/2));
5356 move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2);
5360 if (GTK_CMCLIST_IN_DRAG(clist))
5363 /* vertical autoscrolling */
5364 row = ROW_FROM_YPIXEL (clist, y);
5366 /* don't scroll on last pixel row if it's a cell spacing */
5367 if (y == clist->clist_window_height - 1 &&
5368 y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height)
5371 if (LIST_HEIGHT (clist) > clist->clist_window_height &&
5372 (y < 0 || y >= clist->clist_window_height))
5376 #if GTK_CHECK_VERSION(2,12,0)
5377 clist->vtimer = gdk_threads_add_timeout (SCROLL_TIME,
5378 (GSourceFunc) vertical_timeout, clist);
5380 clist->vtimer = g_timeout_add (SCROLL_TIME,
5381 (GSourceFunc) vertical_timeout, clist);
5383 if (clist->drag_button &&
5384 ((y < 0 && clist->focus_row == 0) ||
5385 (y >= clist->clist_window_height &&
5386 clist->focus_row == clist->rows - 1)))
5390 row = CLAMP (row, 0, clist->rows - 1);
5392 if (button_actions & GTK_CMBUTTON_SELECTS &
5393 !g_object_get_data (G_OBJECT (widget), "gtk-site-data"))
5395 if (row == clist->focus_row)
5398 gtk_cmclist_draw_focus (widget);
5399 clist->focus_row = row;
5400 gtk_cmclist_draw_focus (widget);
5402 switch (clist->selection_mode)
5404 case GTK_SELECTION_BROWSE:
5405 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
5406 clist->focus_row, -1, event);
5408 case GTK_SELECTION_MULTIPLE:
5409 update_extended_selection (clist, clist->focus_row);
5416 if (ROW_TOP_YPIXEL(clist, row) < 0)
5417 move_vertical (clist, row, 0);
5418 else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height >
5419 clist->clist_window_height)
5420 move_vertical (clist, row, 1);
5426 gtk_cmclist_size_request (GtkWidget *widget,
5427 GtkRequisition *requisition)
5431 gint font_height = 0;
5432 cm_return_if_fail (GTK_IS_CMCLIST (widget));
5433 cm_return_if_fail (requisition != NULL);
5435 clist = GTK_CMCLIST (widget);
5437 requisition->width = 0;
5438 requisition->height = 0;
5440 /* compute the size of the column title (title) area */
5441 clist->column_title_area.height = 0;
5442 if (GTK_CMCLIST_SHOW_TITLES(clist)) {
5443 font_height = (pango_font_description_get_size((GTK_WIDGET(clist)->style)->font_desc)/PANGO_SCALE)*2+4;
5444 for (i = 0; i < clist->columns; i++)
5445 if (clist->column[i].button)
5447 GtkRequisition child_requisition;
5449 gtk_widget_size_request (clist->column[i].button,
5450 &child_requisition);
5451 clist->column_title_area.height =
5452 MAX (clist->column_title_area.height,
5453 child_requisition.height);
5455 //clist->column_title_area.height = font_height;
5457 requisition->width += (widget->style->xthickness +
5458 GTK_CONTAINER (widget)->border_width) * 2;
5459 requisition->height += (clist->column_title_area.height +
5460 (widget->style->ythickness +
5461 GTK_CONTAINER (widget)->border_width) * 2);
5463 /* if (!clist->hadjustment) */
5464 requisition->width += list_requisition_width (clist);
5465 /* if (!clist->vadjustment) */
5466 requisition->height += LIST_HEIGHT (clist);
5470 gtk_cmclist_size_allocate (GtkWidget *widget,
5471 GtkAllocation *allocation)
5474 GtkAllocation clist_allocation;
5477 cm_return_if_fail (GTK_IS_CMCLIST (widget));
5478 cm_return_if_fail (allocation != NULL);
5480 clist = GTK_CMCLIST (widget);
5481 widget->allocation = *allocation;
5482 border_width = GTK_CONTAINER (widget)->border_width;
5484 if (GTK_WIDGET_REALIZED (widget))
5486 gdk_window_move_resize (widget->window,
5487 allocation->x + border_width,
5488 allocation->y + border_width,
5489 allocation->width - border_width * 2,
5490 allocation->height - border_width * 2);
5493 /* use internal allocation structure for all the math
5494 * because it's easier than always subtracting the container
5496 clist->internal_allocation.x = 0;
5497 clist->internal_allocation.y = 0;
5498 clist->internal_allocation.width = MAX (1, (gint)allocation->width -
5500 clist->internal_allocation.height = MAX (1, (gint)allocation->height -
5503 /* allocate clist window assuming no scrollbars */
5504 clist_allocation.x = (clist->internal_allocation.x +
5505 widget->style->xthickness);
5506 clist_allocation.y = (clist->internal_allocation.y +
5507 widget->style->ythickness +
5508 clist->column_title_area.height);
5509 clist_allocation.width = MAX (1, (gint)clist->internal_allocation.width -
5510 (2 * (gint)widget->style->xthickness));
5511 clist_allocation.height = MAX (1, (gint)clist->internal_allocation.height -
5512 (2 * (gint)widget->style->ythickness) -
5513 (gint)clist->column_title_area.height);
5515 clist->clist_window_width = clist_allocation.width;
5516 clist->clist_window_height = clist_allocation.height;
5518 if (GTK_WIDGET_REALIZED (widget))
5520 gdk_window_move_resize (clist->clist_window,
5523 clist_allocation.width,
5524 clist_allocation.height);
5527 /* position the window which holds the column title buttons */
5528 clist->column_title_area.x = widget->style->xthickness;
5529 clist->column_title_area.y = widget->style->ythickness;
5530 clist->column_title_area.width = clist_allocation.width;
5532 if (GTK_WIDGET_REALIZED (widget))
5534 gdk_window_move_resize (clist->title_window,
5535 clist->column_title_area.x,
5536 clist->column_title_area.y,
5537 clist->column_title_area.width,
5538 clist->column_title_area.height);
5541 /* column button allocation */
5542 size_allocate_columns (clist, FALSE);
5543 size_allocate_title_buttons (clist);
5545 adjust_adjustments (clist, TRUE);
5549 * gtk_cmclist_forall
5552 gtk_cmclist_forall (GtkContainer *container,
5553 gboolean include_internals,
5554 GtkCallback callback,
5555 gpointer callback_data)
5560 cm_return_if_fail (GTK_IS_CMCLIST (container));
5561 cm_return_if_fail (callback != NULL);
5563 if (!include_internals)
5566 clist = GTK_CMCLIST (container);
5568 /* callback for the column buttons */
5569 for (i = 0; i < clist->columns; i++)
5570 if (clist->column[i].button)
5571 (*callback) (clist->column[i].button, callback_data);
5574 /* PRIVATE DRAWING FUNCTIONS
5583 get_cell_style (GtkCMCList *clist,
5584 GtkCMCListRow *clist_row,
5593 if ((state == GTK_STATE_NORMAL) &&
5594 (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE))
5595 fg_state = GTK_STATE_INSENSITIVE;
5599 if (clist_row->cell[column].style)
5602 *style = clist_row->cell[column].style;
5604 *fg_gc = clist_row->cell[column].style->fg_gc[fg_state];
5606 if (state == GTK_STATE_SELECTED)
5607 *bg_gc = clist_row->cell[column].style->bg_gc[state];
5609 *bg_gc = clist_row->cell[column].style->base_gc[state];
5612 else if (clist_row->style)
5615 *style = clist_row->style;
5617 *fg_gc = clist_row->style->fg_gc[fg_state];
5619 if (state == GTK_STATE_SELECTED)
5620 *bg_gc = clist_row->style->bg_gc[state];
5622 *bg_gc = clist_row->style->base_gc[state];
5628 *style = GTK_WIDGET (clist)->style;
5630 *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state];
5632 if (state == GTK_STATE_SELECTED)
5633 *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
5635 *bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
5638 if (state != GTK_STATE_SELECTED)
5640 if (fg_gc && clist_row->fg_set)
5641 *fg_gc = clist->fg_gc;
5642 if (bg_gc && clist_row->bg_set)
5643 *bg_gc = clist->bg_gc;
5649 draw_cell_pixbuf (GdkWindow *window,
5650 GdkRectangle *clip_rectangle,
5661 gdk_gc_set_clip_origin (fg_gc, x, y);
5663 if (x < clip_rectangle->x)
5665 xsrc = clip_rectangle->x - x;
5667 x = clip_rectangle->x;
5669 if (x + width > clip_rectangle->x + clip_rectangle->width)
5670 width = clip_rectangle->x + clip_rectangle->width - x;
5672 if (y < clip_rectangle->y)
5674 ysrc = clip_rectangle->y - y;
5676 y = clip_rectangle->y;
5678 if (y + height > clip_rectangle->y + clip_rectangle->height)
5679 height = clip_rectangle->y + clip_rectangle->height - y;
5681 gdk_draw_pixbuf (window, fg_gc, pixbuf, xsrc, ysrc, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0);
5682 gdk_gc_set_clip_origin (fg_gc, 0, 0);
5684 return x + MAX (width, 0);
5688 draw_row (GtkCMCList *clist,
5691 GtkCMCListRow *clist_row)
5695 GdkRectangle row_rectangle;
5696 GdkRectangle cell_rectangle;
5697 GdkRectangle clip_rectangle;
5698 GdkRectangle intersect_rectangle;
5703 cm_return_if_fail (clist != NULL);
5705 /* bail now if we arn't drawable yet */
5706 if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows)
5709 widget = GTK_WIDGET (clist);
5711 /* if the function is passed the pointer to the row instead of null,
5712 * it avoids this expensive lookup */
5714 clist_row = ROW_ELEMENT (clist, row)->data;
5716 /* rectangle of the entire row */
5717 row_rectangle.x = 0;
5718 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
5719 row_rectangle.width = clist->clist_window_width;
5720 row_rectangle.height = clist->row_height;
5722 /* rectangle of the cell spacing above the row */
5723 cell_rectangle.x = 0;
5724 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
5725 cell_rectangle.width = row_rectangle.width;
5726 cell_rectangle.height = CELL_SPACING;
5728 /* rectangle used to clip drawing operations, its y and height
5729 * positions only need to be set once, so we set them once here.
5730 * the x and width are set withing the drawing loop below once per
5732 clip_rectangle.y = row_rectangle.y;
5733 clip_rectangle.height = row_rectangle.height;
5735 if (clist_row->state == GTK_STATE_NORMAL)
5737 if (clist_row->fg_set)
5738 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
5739 if (clist_row->bg_set)
5740 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
5743 state = clist_row->state;
5745 /* draw the cell borders and background */
5748 rect = &intersect_rectangle;
5749 if (gdk_rectangle_intersect (area, &cell_rectangle,
5750 &intersect_rectangle))
5751 gdk_draw_rectangle (clist->clist_window,
5752 widget->style->base_gc[GTK_STATE_NORMAL],
5754 intersect_rectangle.x,
5755 intersect_rectangle.y,
5756 intersect_rectangle.width,
5757 intersect_rectangle.height);
5759 /* the last row has to clear its bottom cell spacing too */
5760 if (clist_row == clist->row_list_end->data)
5762 cell_rectangle.y += clist->row_height + CELL_SPACING;
5764 if (gdk_rectangle_intersect (area, &cell_rectangle,
5765 &intersect_rectangle))
5766 gdk_draw_rectangle (clist->clist_window,
5767 widget->style->base_gc[GTK_STATE_NORMAL],
5769 intersect_rectangle.x,
5770 intersect_rectangle.y,
5771 intersect_rectangle.width,
5772 intersect_rectangle.height);
5775 if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle))
5781 rect = &clip_rectangle;
5782 gdk_draw_rectangle (clist->clist_window,
5783 widget->style->base_gc[GTK_STATE_NORMAL],
5787 cell_rectangle.width,
5788 cell_rectangle.height);
5790 /* the last row has to clear its bottom cell spacing too */
5791 if (clist_row == clist->row_list_end->data)
5793 cell_rectangle.y += clist->row_height + CELL_SPACING;
5795 gdk_draw_rectangle (clist->clist_window,
5796 widget->style->base_gc[GTK_STATE_NORMAL],
5800 cell_rectangle.width,
5801 cell_rectangle.height);
5805 for (last_column = clist->columns - 1;
5806 last_column >= 0 && !clist->column[last_column].visible; last_column--)
5809 /* iterate and draw all the columns (row cells) and draw their contents */
5810 for (i = 0; i < clist->columns; i++)
5815 PangoLayout *layout;
5816 PangoRectangle logical_rect;
5823 if (!clist->column[i].visible)
5826 get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
5828 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
5829 clip_rectangle.width = clist->column[i].area.width;
5831 /* calculate clipping region clipping region */
5832 clip_rectangle.x -= COLUMN_INSET + CELL_SPACING;
5833 clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING +
5834 (i == last_column) * CELL_SPACING);
5836 if (area && !gdk_rectangle_intersect (area, &clip_rectangle,
5837 &intersect_rectangle))
5840 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
5841 rect->x, rect->y, rect->width, rect->height);
5843 clip_rectangle.x += COLUMN_INSET + CELL_SPACING;
5844 clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING +
5845 (i == last_column) * CELL_SPACING);
5848 /* calculate real width for column justification */
5850 layout = _gtk_cmclist_create_cell_layout (clist, clist_row, i);
5853 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
5854 width = logical_rect.width;
5862 switch (clist_row->cell[i].type)
5864 case GTK_CMCELL_PIXBUF:
5865 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
5866 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
5867 width += pixbuf_width;
5869 case GTK_CMCELL_PIXTEXT:
5870 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
5871 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
5872 width += pixbuf_width + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
5878 switch (clist->column[i].justification)
5880 case GTK_JUSTIFY_LEFT:
5881 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
5883 case GTK_JUSTIFY_RIGHT:
5884 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5885 clip_rectangle.width - width);
5887 case GTK_JUSTIFY_CENTER:
5888 case GTK_JUSTIFY_FILL:
5889 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
5890 (clip_rectangle.width / 2) - (width / 2));
5894 /* Draw Text and/or Pixbuf */
5895 switch (clist_row->cell[i].type)
5897 case GTK_CMCELL_PIXBUF:
5898 draw_cell_pixbuf (clist->clist_window, &clip_rectangle, fg_gc,
5899 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf,
5901 clip_rectangle.y + clist_row->cell[i].vertical +
5902 (clip_rectangle.height - height) / 2,
5903 pixbuf_width, height);
5905 case GTK_CMCELL_PIXTEXT:
5907 draw_cell_pixbuf (clist->clist_window, &clip_rectangle, fg_gc,
5908 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
5910 clip_rectangle.y + clist_row->cell[i].vertical+
5911 (clip_rectangle.height - height) / 2,
5912 pixbuf_width, height);
5913 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
5916 case GTK_CMCELL_TEXT:
5919 gint row_center_offset = (clist->row_height - logical_rect.height - 1) / 2;
5921 gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
5922 gdk_draw_layout (clist->clist_window, fg_gc,
5924 row_rectangle.y + row_center_offset + clist_row->cell[i].vertical,
5926 g_object_unref (G_OBJECT (layout));
5927 gdk_gc_set_clip_rectangle (fg_gc, NULL);
5935 /* draw focus rectangle */
5936 if (clist->focus_row == row &&
5937 GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS(widget))
5940 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5941 row_rectangle.x, row_rectangle.y,
5942 row_rectangle.width - 1, row_rectangle.height - 1);
5943 else if (gdk_rectangle_intersect (area, &row_rectangle,
5944 &intersect_rectangle))
5946 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
5947 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
5948 row_rectangle.x, row_rectangle.y,
5949 row_rectangle.width - 1,
5950 row_rectangle.height - 1);
5951 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
5957 draw_rows (GtkCMCList *clist,
5961 GtkCMCListRow *clist_row;
5966 cm_return_if_fail (GTK_IS_CMCLIST (clist));
5968 if (clist->row_height == 0 ||
5969 !GTK_WIDGET_DRAWABLE (clist))
5974 first_row = ROW_FROM_YPIXEL (clist, area->y);
5975 last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
5979 first_row = ROW_FROM_YPIXEL (clist, 0);
5980 last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
5983 /* this is a small special case which exposes the bottom cell line
5984 * on the last row -- it might go away if I change the wall the cell
5985 * spacings are drawn
5987 if (clist->rows == first_row)
5990 list = ROW_ELEMENT (clist, first_row);
5994 clist_row = list->data;
6000 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, area, i, clist_row);
6005 gdk_window_clear_area (clist->clist_window, 0,
6006 ROW_TOP_YPIXEL (clist, i), 0, 0);
6010 draw_xor_line (GtkCMCList *clist)
6014 cm_return_if_fail (clist != NULL);
6016 widget = GTK_WIDGET (clist);
6018 gdk_draw_line (widget->window, clist->xor_gc,
6020 widget->style->ythickness,
6022 clist->column_title_area.height +
6023 clist->clist_window_height + 1);
6027 clist_refresh (GtkCMCList *clist)
6029 cm_return_if_fail (GTK_IS_CMCLIST (clist));
6031 if (CLIST_UNFROZEN (clist))
6033 adjust_adjustments (clist, FALSE);
6034 draw_rows (clist, NULL);
6038 /* get cell from coordinates
6039 * get_selection_info
6040 * gtk_cmclist_get_selection_info
6043 get_selection_info (GtkCMCList *clist,
6051 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
6053 /* bounds checking, return false if the user clicked
6054 * on a blank area */
6055 trow = ROW_FROM_YPIXEL (clist, y);
6056 if (trow >= clist->rows)
6062 tcol = COLUMN_FROM_XPIXEL (clist, x);
6063 if (tcol >= clist->columns)
6073 gtk_cmclist_get_selection_info (GtkCMCList *clist,
6079 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
6080 return get_selection_info (clist, x, y, row, column);
6083 /* PRIVATE ADJUSTMENT FUNCTIONS
6084 * adjust_adjustments
6085 * vadjustment_changed
6086 * hadjustment_changed
6087 * vadjustment_value_changed
6088 * hadjustment_value_changed
6092 adjust_adjustments (GtkCMCList *clist,
6093 gboolean block_resize)
6095 if (clist->vadjustment)
6097 clist->vadjustment->page_size = clist->clist_window_height;
6098 clist->vadjustment->step_increment = clist->row_height;
6099 clist->vadjustment->page_increment =
6100 MAX (clist->vadjustment->page_size - clist->vadjustment->step_increment,
6101 clist->vadjustment->page_size / 2);
6102 clist->vadjustment->lower = 0;
6103 clist->vadjustment->upper = LIST_HEIGHT (clist);
6105 if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist) ||
6106 (clist->voffset + (gint)clist->vadjustment->value) != 0)
6108 clist->vadjustment->value = MAX (0, (LIST_HEIGHT (clist) -
6109 clist->clist_window_height));
6110 g_signal_emit_by_name (G_OBJECT (clist->vadjustment),
6113 g_signal_emit_by_name (G_OBJECT (clist->vadjustment), "changed");
6116 if (clist->hadjustment)
6118 clist->hadjustment->page_size = clist->clist_window_width;
6119 clist->hadjustment->step_increment = 10;
6120 clist->hadjustment->page_increment =
6121 MAX (clist->hadjustment->page_size - clist->hadjustment->step_increment,
6122 clist->hadjustment->page_size / 2);
6123 clist->hadjustment->lower = 0;
6124 clist->hadjustment->upper = LIST_WIDTH (clist);
6126 if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist) ||
6127 (clist->hoffset + (gint)clist->hadjustment->value) != 0)
6129 clist->hadjustment->value = MAX (0, (LIST_WIDTH (clist) -
6130 clist->clist_window_width));
6131 g_signal_emit_by_name (G_OBJECT (clist->hadjustment),
6134 g_signal_emit_by_name (G_OBJECT (clist->hadjustment), "changed");
6137 if (!block_resize && (!clist->vadjustment || !clist->hadjustment))
6140 GtkRequisition requisition;
6142 widget = GTK_WIDGET (clist);
6143 gtk_widget_size_request (widget, &requisition);
6145 if ((!clist->hadjustment &&
6146 requisition.width != widget->allocation.width) ||
6147 (!clist->vadjustment &&
6148 requisition.height != widget->allocation.height))
6149 gtk_widget_queue_resize (widget);
6154 vadjustment_changed (GtkAdjustment *adjustment,
6159 cm_return_if_fail (adjustment != NULL);
6160 cm_return_if_fail (data != NULL);
6162 clist = GTK_CMCLIST (data);
6166 hadjustment_changed (GtkAdjustment *adjustment,
6171 cm_return_if_fail (adjustment != NULL);
6172 cm_return_if_fail (data != NULL);
6174 clist = GTK_CMCLIST (data);
6178 vadjustment_value_changed (GtkAdjustment *adjustment,
6184 cm_return_if_fail (adjustment != NULL);
6185 cm_return_if_fail (GTK_IS_CMCLIST (data));
6187 clist = GTK_CMCLIST (data);
6189 if (adjustment != clist->vadjustment)
6192 value = -adjustment->value;
6193 dy = value - clist->voffset;
6194 clist->voffset = value;
6196 if (GTK_WIDGET_DRAWABLE (clist))
6198 gdk_window_scroll (clist->clist_window, 0, dy);
6199 gdk_window_process_updates (clist->clist_window, FALSE);
6211 /* The window to which widget->window is relative */
6212 #define ALLOCATION_WINDOW(widget) \
6213 (GTK_WIDGET_NO_WINDOW (widget) ? \
6214 (widget)->window : \
6215 gdk_window_get_parent ((widget)->window))
6218 adjust_allocation_recurse (GtkWidget *widget,
6221 ScrollData *scroll_data = data;
6223 if (!GTK_WIDGET_REALIZED (widget))
6225 if (GTK_WIDGET_VISIBLE (widget))
6227 GdkRectangle tmp_rectangle = widget->allocation;
6228 tmp_rectangle.x += scroll_data->dx;
6230 gtk_widget_size_allocate (widget, &tmp_rectangle);
6235 if (ALLOCATION_WINDOW (widget) == scroll_data->window)
6237 widget->allocation.x += scroll_data->dx;
6239 if (GTK_IS_CONTAINER (widget))
6240 gtk_container_forall (GTK_CONTAINER (widget),
6241 adjust_allocation_recurse,
6248 adjust_allocation (GtkWidget *widget,
6251 ScrollData scroll_data;
6253 if (GTK_WIDGET_REALIZED (widget))
6254 scroll_data.window = ALLOCATION_WINDOW (widget);
6256 scroll_data.window = NULL;
6258 scroll_data.dx = dx;
6260 adjust_allocation_recurse (widget, &scroll_data);
6264 hadjustment_value_changed (GtkAdjustment *adjustment,
6268 GtkContainer *container;
6275 cm_return_if_fail (adjustment != NULL);
6276 cm_return_if_fail (GTK_IS_CMCLIST (data));
6278 clist = GTK_CMCLIST (data);
6279 container = GTK_CONTAINER (data);
6281 if (adjustment != clist->hadjustment)
6284 value = adjustment->value;
6286 dx = -value - clist->hoffset;
6288 if (GTK_WIDGET_REALIZED (clist))
6289 gdk_window_scroll (clist->title_window, dx, 0);
6291 /* adjust the column button's allocations */
6292 for (i = 0; i < clist->columns; i++)
6293 if (clist->column[i].button)
6294 adjust_allocation (clist->column[i].button, dx);
6296 clist->hoffset = -value;
6298 if (GTK_WIDGET_DRAWABLE (clist))
6300 if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) &&
6301 !container->focus_child && GTK_CMCLIST_ADD_MODE(clist))
6303 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
6305 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
6306 clist->clist_window_width - 1,
6307 clist->row_height - 1);
6310 gdk_window_scroll (clist->clist_window, dx, 0);
6311 gdk_window_process_updates (clist->clist_window, FALSE);
6313 if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) &&
6314 !container->focus_child)
6316 if (GTK_CMCLIST_ADD_MODE(clist))
6320 focus_row = clist->focus_row;
6321 clist->focus_row = -1;
6322 draw_rows (clist, &area);
6323 clist->focus_row = focus_row;
6325 gdk_draw_rectangle (clist->clist_window, clist->xor_gc,
6326 FALSE, 0, y, clist->clist_window_width - 1,
6327 clist->row_height - 1);
6330 else if (ABS(dx) < clist->clist_window_width - 1)
6337 x0 = clist->clist_window_width - 1;
6343 x1 = clist->clist_window_width - 1 + dx;
6346 y = ROW_TOP_YPIXEL (clist, clist->focus_row);
6347 gdk_draw_line (clist->clist_window, clist->xor_gc,
6348 x0, y + 1, x0, y + clist->row_height - 2);
6349 gdk_draw_line (clist->clist_window, clist->xor_gc,
6350 x1, y + 1, x1, y + clist->row_height - 2);
6357 * Memory Allocation/Distruction Routines for GtkCMCList stuctures
6366 static GtkCMCListColumn *
6367 columns_new (GtkCMCList *clist)
6369 GtkCMCListColumn *column;
6372 column = g_new (GtkCMCListColumn, clist->columns);
6374 for (i = 0; i < clist->columns; i++)
6376 column[i].area.x = 0;
6377 column[i].area.y = 0;
6378 column[i].area.width = 0;
6379 column[i].area.height = 0;
6380 column[i].title = NULL;
6381 column[i].button = NULL;
6382 column[i].window = NULL;
6383 column[i].width = 0;
6384 column[i].min_width = -1;
6385 column[i].max_width = -1;
6386 column[i].visible = TRUE;
6387 column[i].width_set = FALSE;
6388 column[i].resizeable = TRUE;
6389 column[i].auto_resize = FALSE;
6390 column[i].button_passive = FALSE;
6391 column[i].justification = GTK_JUSTIFY_LEFT;
6398 column_title_new (GtkCMCList *clist,
6402 g_free (clist->column[column].title);
6404 clist->column[column].title = g_strdup (title);
6408 columns_delete (GtkCMCList *clist)
6412 for (i = 0; i < clist->columns; i++)
6413 g_free (clist->column[i].title);
6415 g_free (clist->column);
6418 static GtkCMCListRow *
6419 row_new (GtkCMCList *clist)
6422 GtkCMCListRow *clist_row;
6424 #if GLIB_CHECK_VERSION(2,10,0)
6425 clist_row = g_slice_new (GtkCMCListRow);
6426 clist_row->cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
6428 clist_row = g_chunk_new (GtkCMCListRow, (GMemChunk *)clist->row_mem_chunk);
6429 clist_row->cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk);
6432 for (i = 0; i < clist->columns; i++)
6434 clist_row->cell[i].type = GTK_CMCELL_EMPTY;
6435 clist_row->cell[i].vertical = 0;
6436 clist_row->cell[i].horizontal = 0;
6437 clist_row->cell[i].style = NULL;
6440 clist_row->fg_set = FALSE;
6441 clist_row->bg_set = FALSE;
6442 clist_row->style = NULL;
6443 clist_row->selectable = TRUE;
6444 clist_row->state = GTK_STATE_NORMAL;
6445 clist_row->data = NULL;
6446 clist_row->destroy = NULL;
6452 row_delete (GtkCMCList *clist,
6453 GtkCMCListRow *clist_row)
6457 for (i = 0; i < clist->columns; i++)
6459 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
6460 (clist, clist_row, i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
6461 if (clist_row->cell[i].style)
6463 if (GTK_WIDGET_REALIZED (clist))
6464 gtk_style_detach (clist_row->cell[i].style);
6465 g_object_unref (clist_row->cell[i].style);
6469 if (clist_row->style)
6471 if (GTK_WIDGET_REALIZED (clist))
6472 gtk_style_detach (clist_row->style);
6473 g_object_unref (clist_row->style);
6476 if (clist_row->destroy)
6477 clist_row->destroy (clist_row->data);
6479 #if GLIB_CHECK_VERSION(2,10,0)
6480 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, clist_row->cell);
6481 g_slice_free (GtkCMCListRow, clist_row);
6483 g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, clist_row->cell);
6484 g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, clist_row);
6489 * gtk_cmclist_focus_content_area
6491 * gtk_cmclist_draw_focus
6492 * gtk_cmclist_focus_in
6493 * gtk_cmclist_focus_out
6497 gtk_cmclist_focus_content_area (GtkCMCList *clist)
6499 if (clist->focus_row < 0)
6501 clist->focus_row = 0;
6503 if ((clist->selection_mode == GTK_SELECTION_BROWSE ||
6504 clist->selection_mode == GTK_SELECTION_MULTIPLE) &&
6506 g_signal_emit (G_OBJECT (clist),
6507 clist_signals[SELECT_ROW], 0,
6508 clist->focus_row, -1, NULL);
6510 gtk_widget_grab_focus (GTK_WIDGET (clist));
6514 gtk_cmclist_focus (GtkWidget *widget,
6515 GtkDirectionType direction)
6517 GtkCMCList *clist = GTK_CMCLIST (widget);
6518 GtkWidget *focus_child;
6519 gboolean is_current_focus;
6521 if (!GTK_WIDGET_IS_SENSITIVE (widget))
6524 focus_child = GTK_CONTAINER (widget)->focus_child;
6526 is_current_focus = gtk_widget_is_focus (GTK_WIDGET (clist));
6529 gtk_widget_child_focus (focus_child, direction))
6538 if (title_focus_move (clist, direction))
6541 else if (!is_current_focus)
6543 gtk_cmclist_focus_content_area (clist);
6548 case GTK_DIR_TAB_FORWARD:
6549 if (!focus_child && !is_current_focus)
6551 if (title_focus_in (clist, direction))
6555 if (!is_current_focus && clist->rows)
6557 gtk_cmclist_focus_content_area (clist);
6562 case GTK_DIR_TAB_BACKWARD:
6563 if (!focus_child && is_current_focus)
6565 if (title_focus_in (clist, direction))
6569 if (!is_current_focus && !focus_child && clist->rows)
6571 gtk_cmclist_focus_content_area (clist);
6583 gtk_cmclist_set_focus_child (GtkContainer *container,
6586 GtkCMCList *clist = GTK_CMCLIST (container);
6589 for (i = 0; i < clist->columns; i++)
6590 if (clist->column[i].button == child)
6591 clist->focus_header_column = i;
6593 parent_class->set_focus_child (container, child);
6597 gtk_cmclist_draw_focus (GtkWidget *widget)
6601 cm_return_if_fail (GTK_IS_CMCLIST (widget));
6603 if (!GTK_WIDGET_DRAWABLE (widget) || !GTK_WIDGET_CAN_FOCUS (widget))
6606 clist = GTK_CMCLIST (widget);
6607 if (clist->focus_row >= 0)
6608 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
6609 0, ROW_TOP_YPIXEL(clist, clist->focus_row),
6610 clist->clist_window_width - 1,
6611 clist->row_height - 1);
6615 gtk_cmclist_focus_in (GtkWidget *widget,
6616 GdkEventFocus *event)
6618 GtkCMCList *clist = GTK_CMCLIST (widget);
6620 if (clist->selection_mode == GTK_SELECTION_BROWSE &&
6621 clist->selection == NULL && clist->focus_row > -1)
6625 list = g_list_nth (clist->row_list, clist->focus_row);
6626 if (list && GTK_CMCLIST_ROW (list)->selectable)
6627 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
6628 clist->focus_row, -1, event);
6630 gtk_cmclist_draw_focus (widget);
6633 gtk_cmclist_draw_focus (widget);
6639 gtk_cmclist_focus_out (GtkWidget *widget,
6640 GdkEventFocus *event)
6642 GtkCMCList *clist = GTK_CMCLIST (widget);
6644 gtk_cmclist_draw_focus (widget);
6646 GTK_CMCLIST_GET_CLASS (widget)->resync_selection (clist, (GdkEvent *) event);
6652 focus_column (GtkCMCList *clist, gint column, gint dir)
6654 GtkWidget *child = clist->column[column].button;
6656 if (gtk_widget_child_focus (child, dir))
6660 else if (GTK_WIDGET_CAN_FOCUS (child))
6662 gtk_widget_grab_focus (child);
6669 /* Focus moved onto the headers. Focus first focusable and visible child.
6670 * (FIXME: focus the last focused child if visible)
6673 title_focus_in (GtkCMCList *clist, gint dir)
6678 if (!GTK_CMCLIST_SHOW_TITLES (clist))
6681 /* Check last focused column */
6682 if (clist->focus_header_column != -1)
6684 i = clist->focus_header_column;
6686 left = COLUMN_LEFT_XPIXEL (clist, i);
6687 right = left + clist->column[i].area.width;
6689 if (left >= 0 && right <= clist->clist_window_width)
6691 if (focus_column (clist, i, dir))
6696 /* Check fully visible columns */
6697 for (i = 0 ; i < clist->columns ; i++)
6699 left = COLUMN_LEFT_XPIXEL (clist, i);
6700 right = left + clist->column[i].area.width;
6702 if (left >= 0 && right <= clist->clist_window_width)
6704 if (focus_column (clist, i, dir))
6709 /* Check partially visible columns */
6710 for (i = 0 ; i < clist->columns ; i++)
6712 left = COLUMN_LEFT_XPIXEL (clist, i);
6713 right = left + clist->column[i].area.width;
6715 if ((left < 0 && right > 0) ||
6716 (left < clist->clist_window_width && right > clist->clist_window_width))
6718 if (focus_column (clist, i, dir))
6726 /* Move the focus right or left within the title buttons, scrolling
6727 * as necessary to keep the focused child visible.
6730 title_focus_move (GtkCMCList *clist,
6733 GtkWidget *focus_child;
6734 gboolean return_val = FALSE;
6739 if (!GTK_CMCLIST_SHOW_TITLES(clist))
6742 focus_child = GTK_CONTAINER (clist)->focus_child;
6743 g_assert (focus_child);
6745 /* Movement direction within headers
6757 for (i = 0; i < clist->columns; i++)
6758 if (clist->column[i].button == focus_child)
6761 g_assert (i != -1); /* Have a starting column */
6764 while (!return_val && j >= 0 && j < clist->columns)
6766 if (clist->column[j].button &&
6767 GTK_WIDGET_VISIBLE (clist->column[j].button))
6769 if (focus_column (clist, j, dir))
6778 /* If we didn't find it, wrap around and keep looking
6782 j = d > 0 ? 0 : clist->columns - 1;
6784 while (!return_val && j != i)
6786 if (clist->column[j].button &&
6787 GTK_WIDGET_VISIBLE (clist->column[j].button))
6789 if (focus_column (clist, j, dir))
6799 /* Scroll horizontally so focused column is visible
6803 if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET)
6804 gtk_cmclist_moveto (clist, -1, j, 0, 0);
6805 else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width >
6806 clist->clist_window_width)
6810 for (last_column = clist->columns - 1;
6811 last_column >= 0 && !clist->column[last_column].visible; last_column--);
6813 if (j == last_column)
6814 gtk_cmclist_moveto (clist, -1, j, 0, 0);
6816 gtk_cmclist_moveto (clist, -1, j, 0, 1);
6819 return TRUE; /* Even if we didn't find a new one, we can keep the
6820 * focus in the same place.
6824 /* PRIVATE SCROLLING FUNCTIONS
6830 * horizontal_timeout
6835 move_focus_row (GtkCMCList *clist,
6836 GtkScrollType scroll_type,
6841 cm_return_if_fail (clist != 0);
6842 cm_return_if_fail (GTK_IS_CMCLIST (clist));
6844 widget = GTK_WIDGET (clist);
6846 switch (scroll_type)
6848 case GTK_SCROLL_STEP_UP:
6849 case GTK_SCROLL_STEP_BACKWARD:
6850 if (clist->focus_row <= 0)
6852 gtk_cmclist_draw_focus (widget);
6854 gtk_cmclist_draw_focus (widget);
6857 case GTK_SCROLL_STEP_DOWN:
6858 case GTK_SCROLL_STEP_FORWARD:
6859 if (clist->focus_row >= clist->rows - 1)
6861 gtk_cmclist_draw_focus (widget);
6863 gtk_cmclist_draw_focus (widget);
6865 case GTK_SCROLL_PAGE_UP:
6866 case GTK_SCROLL_PAGE_BACKWARD:
6867 if (clist->focus_row <= 0)
6869 gtk_cmclist_draw_focus (widget);
6870 clist->focus_row = MAX (0, clist->focus_row -
6871 (2 * clist->clist_window_height -
6872 clist->row_height - CELL_SPACING) /
6873 (2 * (clist->row_height + CELL_SPACING)));
6874 gtk_cmclist_draw_focus (widget);
6876 case GTK_SCROLL_PAGE_DOWN:
6877 case GTK_SCROLL_PAGE_FORWARD:
6878 if (clist->focus_row >= clist->rows - 1)
6880 gtk_cmclist_draw_focus (widget);
6881 clist->focus_row = MIN (clist->rows - 1, clist->focus_row +
6882 (2 * clist->clist_window_height -
6883 clist->row_height - CELL_SPACING) /
6884 (2 * (clist->row_height + CELL_SPACING)));
6885 gtk_cmclist_draw_focus (widget);
6887 case GTK_SCROLL_JUMP:
6888 if (position >= 0 && position <= 1)
6890 gtk_cmclist_draw_focus (widget);
6891 clist->focus_row = position * (clist->rows - 1);
6892 gtk_cmclist_draw_focus (widget);
6901 scroll_horizontal (GtkCMCList *clist,
6902 GtkScrollType scroll_type,
6908 cm_return_if_fail (clist != 0);
6909 cm_return_if_fail (GTK_IS_CMCLIST (clist));
6911 if (clist_has_grab (clist))
6914 for (last_column = clist->columns - 1;
6915 last_column >= 0 && !clist->column[last_column].visible; last_column--)
6918 switch (scroll_type)
6920 case GTK_SCROLL_STEP_BACKWARD:
6921 column = COLUMN_FROM_XPIXEL (clist, 0);
6922 if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0
6926 case GTK_SCROLL_STEP_FORWARD:
6927 column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width);
6930 if (COLUMN_LEFT_XPIXEL (clist, column) +
6931 clist->column[column].area.width +
6932 CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width &&
6933 column < last_column)
6936 case GTK_SCROLL_PAGE_BACKWARD:
6937 case GTK_SCROLL_PAGE_FORWARD:
6939 case GTK_SCROLL_JUMP:
6940 if (position >= 0 && position <= 1)
6942 gint vis_columns = 0;
6945 for (i = 0; i <= last_column; i++)
6946 if (clist->column[i].visible)
6949 column = position * vis_columns;
6951 for (i = 0; i <= last_column && column > 0; i++)
6952 if (clist->column[i].visible)
6964 if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET)
6965 gtk_cmclist_moveto (clist, -1, column, 0, 0);
6966 else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1
6967 + clist->column[column].area.width > clist->clist_window_width)
6969 if (column == last_column)
6970 gtk_cmclist_moveto (clist, -1, column, 0, 0);
6972 gtk_cmclist_moveto (clist, -1, column, 0, 1);
6977 scroll_vertical (GtkCMCList *clist,
6978 GtkScrollType scroll_type,
6983 cm_return_if_fail (GTK_IS_CMCLIST (clist));
6985 if (clist_has_grab (clist))
6988 switch (clist->selection_mode)
6990 case GTK_SELECTION_MULTIPLE:
6991 if (clist->anchor >= 0)
6993 case GTK_SELECTION_BROWSE:
6995 old_focus_row = clist->focus_row;
6996 move_focus_row (clist, scroll_type, position);
6998 if (old_focus_row != clist->focus_row)
7000 if (clist->selection_mode == GTK_SELECTION_BROWSE)
7001 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
7002 old_focus_row, -1, NULL);
7003 else if (!GTK_CMCLIST_ADD_MODE(clist))
7005 gtk_cmclist_unselect_all (clist);
7006 clist->undo_anchor = old_focus_row;
7010 switch (gtk_cmclist_row_is_visible (clist, clist->focus_row))
7012 case GTK_VISIBILITY_NONE:
7013 if (old_focus_row != clist->focus_row &&
7014 !(clist->selection_mode == GTK_SELECTION_MULTIPLE &&
7015 GTK_CMCLIST_ADD_MODE(clist)))
7016 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
7017 clist->focus_row, -1, NULL);
7018 switch (scroll_type)
7020 case GTK_SCROLL_PAGE_UP:
7021 case GTK_SCROLL_STEP_UP:
7022 case GTK_SCROLL_STEP_BACKWARD:
7023 case GTK_SCROLL_PAGE_BACKWARD:
7024 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
7026 case GTK_SCROLL_PAGE_DOWN:
7027 case GTK_SCROLL_STEP_DOWN:
7028 case GTK_SCROLL_STEP_FORWARD:
7029 case GTK_SCROLL_PAGE_FORWARD:
7030 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
7032 case GTK_SCROLL_JUMP:
7033 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0.5, 0);
7039 case GTK_VISIBILITY_PARTIAL:
7040 switch (scroll_type)
7042 case GTK_SCROLL_STEP_BACKWARD:
7043 case GTK_SCROLL_PAGE_BACKWARD:
7044 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
7046 case GTK_SCROLL_STEP_FORWARD:
7047 case GTK_SCROLL_PAGE_FORWARD:
7048 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
7050 case GTK_SCROLL_JUMP:
7051 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0.5, 0);
7057 if (old_focus_row != clist->focus_row &&
7058 !(clist->selection_mode == GTK_SELECTION_MULTIPLE &&
7059 GTK_CMCLIST_ADD_MODE(clist)))
7060 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
7061 clist->focus_row, -1, NULL);
7066 move_focus_row (clist, scroll_type, position);
7068 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
7069 clist->clist_window_height)
7070 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
7071 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
7072 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
7078 move_horizontal (GtkCMCList *clist,
7083 if (!clist->hadjustment)
7086 value = CLAMP (clist->hadjustment->value + diff, 0.0,
7087 clist->hadjustment->upper - clist->hadjustment->page_size);
7088 gtk_adjustment_set_value (clist->hadjustment, value);
7092 move_vertical (GtkCMCList *clist,
7098 if (!clist->vadjustment)
7101 value = (ROW_TOP_YPIXEL (clist, row) - clist->voffset -
7102 align * (clist->clist_window_height - clist->row_height) +
7103 (2 * align - 1) * CELL_SPACING);
7105 if (value + clist->vadjustment->page_size > clist->vadjustment->upper)
7106 value = clist->vadjustment->upper - clist->vadjustment->page_size;
7108 gtk_adjustment_set_value (clist->vadjustment, value);
7112 do_fake_motion (GtkWidget *widget)
7114 GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
7116 event->motion.send_event = TRUE;
7118 gtk_cmclist_motion (widget, (GdkEventMotion *)event);
7119 gdk_event_free (event);
7123 horizontal_timeout (GtkCMCList *clist)
7126 do_fake_motion (GTK_WIDGET (clist));
7132 vertical_timeout (GtkCMCList *clist)
7135 do_fake_motion (GTK_WIDGET (clist));
7141 remove_grab (GtkCMCList *clist)
7143 GtkWidget *widget = GTK_WIDGET (clist);
7145 if (GTK_WIDGET_HAS_GRAB (clist))
7147 GdkDisplay *display = gtk_widget_get_display (widget);
7149 gtk_grab_remove (widget);
7150 if (gdk_display_pointer_is_grabbed (display))
7151 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
7156 g_source_remove (clist->htimer);
7162 g_source_remove (clist->vtimer);
7167 /* PUBLIC SORTING FUNCTIONS
7169 * gtk_cmclist_set_compare_func
7170 * gtk_cmclist_set_auto_sort
7171 * gtk_cmclist_set_sort_type
7172 * gtk_cmclist_set_sort_column
7175 gtk_cmclist_sort (GtkCMCList *clist)
7177 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7179 GTK_CMCLIST_GET_CLASS (clist)->sort_list (clist);
7183 gtk_cmclist_set_compare_func (GtkCMCList *clist,
7184 GtkCMCListCompareFunc cmp_func)
7186 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7188 clist->compare = (cmp_func) ? cmp_func : default_compare;
7192 gtk_cmclist_set_auto_sort (GtkCMCList *clist,
7195 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7197 if (GTK_CMCLIST_AUTO_SORT(clist) && !auto_sort)
7198 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_SORT);
7199 else if (!GTK_CMCLIST_AUTO_SORT(clist) && auto_sort)
7201 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_SORT);
7202 gtk_cmclist_sort (clist);
7207 gtk_cmclist_set_sort_type (GtkCMCList *clist,
7208 GtkSortType sort_type)
7210 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7212 clist->sort_type = sort_type;
7216 gtk_cmclist_set_sort_column (GtkCMCList *clist,
7219 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7221 if (column < 0 || column >= clist->columns)
7224 clist->sort_column = column;
7227 /* PRIVATE SORTING FUNCTIONS
7231 * gtk_cmclist_mergesort
7234 default_compare (GtkCMCList *clist,
7241 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
7242 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
7244 switch (row1->cell[clist->sort_column].type)
7246 case GTK_CMCELL_TEXT:
7247 text1 = GTK_CMCELL_TEXT (row1->cell[clist->sort_column])->text;
7249 case GTK_CMCELL_PIXTEXT:
7250 text1 = GTK_CMCELL_PIXTEXT (row1->cell[clist->sort_column])->text;
7256 switch (row2->cell[clist->sort_column].type)
7258 case GTK_CMCELL_TEXT:
7259 text2 = GTK_CMCELL_TEXT (row2->cell[clist->sort_column])->text;
7261 case GTK_CMCELL_PIXTEXT:
7262 text2 = GTK_CMCELL_PIXTEXT (row2->cell[clist->sort_column])->text;
7269 return (text1 != NULL);
7274 return strcmp (text1, text2);
7278 real_sort_list (GtkCMCList *clist)
7284 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7286 if (clist->rows <= 1)
7289 if (clist_has_grab (clist))
7292 gtk_cmclist_freeze (clist);
7294 if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_MULTIPLE)
7296 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
7297 g_list_free (clist->undo_selection);
7298 g_list_free (clist->undo_unselection);
7299 clist->undo_selection = NULL;
7300 clist->undo_unselection = NULL;
7303 clist->row_list = gtk_cmclist_mergesort (clist, clist->row_list, clist->rows);
7305 work = clist->selection;
7307 for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next)
7309 if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED)
7311 work->data = GINT_TO_POINTER (i);
7315 if (i == clist->rows - 1)
7316 clist->row_list_end = list;
7319 gtk_cmclist_thaw (clist);
7323 gtk_cmclist_merge (GtkCMCList *clist,
7324 GList *a, /* first list to merge */
7325 GList *b) /* second list to merge */
7327 GList z = { 0 }; /* auxiliary node */
7353 cmp = clist->compare (clist, GTK_CMCLIST_ROW (a), GTK_CMCLIST_ROW (b));
7354 if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) ||
7355 (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) ||
7373 z.next->prev = NULL;
7378 gtk_cmclist_mergesort (GtkCMCList *clist,
7379 GList *list, /* the list to sort */
7380 gint num) /* the list's length */
7391 /* move "half" to the middle */
7393 for (i = 0; i < num / 2; i++)
7396 /* cut the list in two */
7397 half->prev->next = NULL;
7400 /* recursively sort both lists */
7401 return gtk_cmclist_merge (clist,
7402 gtk_cmclist_mergesort (clist, list, num / 2),
7403 gtk_cmclist_mergesort (clist, half, num - num / 2));
7407 /************************/
7410 drag_source_info_destroy (gpointer data)
7412 GtkCMCListCellInfo *info = data;
7418 drag_dest_info_destroy (gpointer data)
7420 GtkCMCListDestInfo *info = data;
7426 drag_dest_cell (GtkCMCList *clist,
7429 GtkCMCListDestInfo *dest_info)
7433 widget = GTK_WIDGET (clist);
7435 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
7437 y -= (GTK_CONTAINER (clist)->border_width +
7438 widget->style->ythickness +
7439 clist->column_title_area.height);
7441 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
7442 if (dest_info->cell.row >= clist->rows)
7444 dest_info->cell.row = clist->rows - 1;
7445 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
7447 if (dest_info->cell.row < -1)
7448 dest_info->cell.row = -1;
7450 x -= GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
7452 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
7454 if (dest_info->cell.row >= 0)
7459 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
7461 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist))
7463 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
7464 h = clist->row_height / 4;
7466 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
7468 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
7469 h = clist->row_height / 2;
7472 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
7475 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
7476 else if (clist->row_height - y_delta < h)
7477 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
7483 gtk_cmclist_drag_begin (GtkWidget *widget,
7484 GdkDragContext *context)
7487 GtkCMCListCellInfo *info;
7489 cm_return_if_fail (GTK_IS_CMCLIST (widget));
7490 cm_return_if_fail (context != NULL);
7492 clist = GTK_CMCLIST (widget);
7494 clist->drag_button = 0;
7495 remove_grab (clist);
7497 switch (clist->selection_mode)
7499 case GTK_SELECTION_MULTIPLE:
7500 update_extended_selection (clist, clist->focus_row);
7501 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
7503 case GTK_SELECTION_SINGLE:
7505 case GTK_SELECTION_BROWSE:
7508 g_assert_not_reached ();
7511 info = g_dataset_get_data (context, "gtk-clist-drag-source");
7515 info = g_new (GtkCMCListCellInfo, 1);
7517 if (clist->click_cell.row < 0)
7518 clist->click_cell.row = 0;
7519 else if (clist->click_cell.row >= clist->rows)
7520 clist->click_cell.row = clist->rows - 1;
7521 info->row = clist->click_cell.row;
7522 info->column = clist->click_cell.column;
7524 g_dataset_set_data_full (context, "gtk-clist-drag-source", info,
7525 drag_source_info_destroy);
7528 if (GTK_CMCLIST_USE_DRAG_ICONS (clist))
7529 gtk_drag_set_icon_default (context);
7533 gtk_cmclist_drag_end (GtkWidget *widget,
7534 GdkDragContext *context)
7538 cm_return_if_fail (GTK_IS_CMCLIST (widget));
7539 cm_return_if_fail (context != NULL);
7541 clist = GTK_CMCLIST (widget);
7543 clist->click_cell.row = -1;
7544 clist->click_cell.column = -1;
7548 gtk_cmclist_drag_leave (GtkWidget *widget,
7549 GdkDragContext *context,
7553 GtkCMCListDestInfo *dest_info;
7555 cm_return_if_fail (GTK_IS_CMCLIST (widget));
7556 cm_return_if_fail (context != NULL);
7558 clist = GTK_CMCLIST (widget);
7560 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
7564 if (dest_info->cell.row >= 0 &&
7565 GTK_CMCLIST_REORDERABLE(clist) &&
7566 gtk_drag_get_source_widget (context) == widget)
7569 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7571 list = context->targets;
7574 if (atom == GDK_POINTER_TO_ATOM (list->data))
7576 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
7578 g_list_nth (clist->row_list, dest_info->cell.row)->data,
7579 dest_info->cell.row, dest_info->insert_pos);
7580 clist->drag_highlight_row = -1;
7586 g_dataset_remove_data (context, "gtk-clist-drag-dest");
7591 gtk_cmclist_drag_motion (GtkWidget *widget,
7592 GdkDragContext *context,
7598 GtkCMCListDestInfo new_info;
7599 GtkCMCListDestInfo *dest_info;
7601 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
7603 clist = GTK_CMCLIST (widget);
7605 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
7609 dest_info = g_new (GtkCMCListDestInfo, 1);
7611 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
7612 dest_info->cell.row = -1;
7613 dest_info->cell.column = -1;
7615 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
7616 drag_dest_info_destroy);
7619 drag_dest_cell (clist, x, y, &new_info);
7621 if (GTK_CMCLIST_REORDERABLE (clist))
7624 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7626 list = context->targets;
7629 if (atom == GDK_POINTER_TO_ATOM (list->data))
7636 if (gtk_drag_get_source_widget (context) != widget ||
7637 new_info.insert_pos == GTK_CMCLIST_DRAG_NONE ||
7638 new_info.cell.row == clist->click_cell.row ||
7639 (new_info.cell.row == clist->click_cell.row - 1 &&
7640 new_info.insert_pos == GTK_CMCLIST_DRAG_AFTER) ||
7641 (new_info.cell.row == clist->click_cell.row + 1 &&
7642 new_info.insert_pos == GTK_CMCLIST_DRAG_BEFORE))
7644 if (dest_info->cell.row < 0)
7646 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
7652 if (new_info.cell.row != dest_info->cell.row ||
7653 (new_info.cell.row == dest_info->cell.row &&
7654 dest_info->insert_pos != new_info.insert_pos))
7656 if (dest_info->cell.row >= 0)
7657 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
7658 (clist, g_list_nth (clist->row_list,
7659 dest_info->cell.row)->data,
7660 dest_info->cell.row, dest_info->insert_pos);
7662 dest_info->insert_pos = new_info.insert_pos;
7663 dest_info->cell.row = new_info.cell.row;
7664 dest_info->cell.column = new_info.cell.column;
7666 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
7667 (clist, g_list_nth (clist->row_list,
7668 dest_info->cell.row)->data,
7669 dest_info->cell.row, dest_info->insert_pos);
7671 clist->drag_highlight_row = dest_info->cell.row;
7672 clist->drag_highlight_pos = dest_info->insert_pos;
7674 gdk_drag_status (context, context->suggested_action, time);
7680 dest_info->insert_pos = new_info.insert_pos;
7681 dest_info->cell.row = new_info.cell.row;
7682 dest_info->cell.column = new_info.cell.column;
7687 gtk_cmclist_drag_drop (GtkWidget *widget,
7688 GdkDragContext *context,
7693 cm_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE);
7694 cm_return_val_if_fail (context != NULL, FALSE);
7696 if (GTK_CMCLIST_REORDERABLE (widget) &&
7697 gtk_drag_get_source_widget (context) == widget)
7700 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7702 list = context->targets;
7705 if (atom == GDK_POINTER_TO_ATOM (list->data))
7714 gtk_cmclist_drag_data_received (GtkWidget *widget,
7715 GdkDragContext *context,
7718 GtkSelectionData *selection_data,
7724 cm_return_if_fail (GTK_IS_CMCLIST (widget));
7725 cm_return_if_fail (context != NULL);
7726 cm_return_if_fail (selection_data != NULL);
7728 clist = GTK_CMCLIST (widget);
7730 if (GTK_CMCLIST_REORDERABLE (clist) &&
7731 gtk_drag_get_source_widget (context) == widget &&
7732 selection_data->target ==
7733 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
7734 selection_data->format == 8 &&
7735 selection_data->length == sizeof (GtkCMCListCellInfo))
7737 GtkCMCListCellInfo *source_info;
7739 source_info = (GtkCMCListCellInfo *)(selection_data->data);
7742 GtkCMCListDestInfo dest_info;
7744 drag_dest_cell (clist, x, y, &dest_info);
7746 if (dest_info.insert_pos == GTK_CMCLIST_DRAG_AFTER)
7747 dest_info.cell.row++;
7748 if (source_info->row < dest_info.cell.row)
7749 dest_info.cell.row--;
7750 if (dest_info.cell.row != source_info->row)
7751 gtk_cmclist_row_move (clist, source_info->row, dest_info.cell.row);
7753 g_dataset_remove_data (context, "gtk-clist-drag-dest");
7759 gtk_cmclist_drag_data_get (GtkWidget *widget,
7760 GdkDragContext *context,
7761 GtkSelectionData *selection_data,
7765 cm_return_if_fail (GTK_IS_CMCLIST (widget));
7766 cm_return_if_fail (context != NULL);
7767 cm_return_if_fail (selection_data != NULL);
7769 if (selection_data->target == gdk_atom_intern_static_string ("gtk-clist-drag-reorder"))
7771 GtkCMCListCellInfo *info;
7773 info = g_dataset_get_data (context, "gtk-clist-drag-source");
7777 GtkCMCListCellInfo ret_info;
7779 ret_info.row = info->row;
7780 ret_info.column = info->column;
7782 gtk_selection_data_set (selection_data, selection_data->target,
7783 8, (guchar *) &ret_info,
7784 sizeof (GtkCMCListCellInfo));
7790 draw_drag_highlight (GtkCMCList *clist,
7791 GtkCMCListRow *dest_row,
7792 gint dest_row_number,
7793 GtkCMCListDragPos drag_pos)
7797 y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
7801 case GTK_CMCLIST_DRAG_NONE:
7803 case GTK_CMCLIST_DRAG_AFTER:
7804 y += clist->row_height + 1;
7805 case GTK_CMCLIST_DRAG_BEFORE:
7806 gdk_draw_line (clist->clist_window, clist->xor_gc,
7807 0, y, clist->clist_window_width, y);
7809 case GTK_CMCLIST_DRAG_INTO:
7810 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y,
7811 clist->clist_window_width - 1, clist->row_height);
7817 gtk_cmclist_set_reorderable (GtkCMCList *clist,
7818 gboolean reorderable)
7822 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7824 if ((GTK_CMCLIST_REORDERABLE(clist) != 0) == reorderable)
7827 widget = GTK_WIDGET (clist);
7831 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_REORDERABLE);
7832 gtk_drag_dest_set (widget,
7833 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
7834 &clist_target_table, 1, GDK_ACTION_MOVE);
7838 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_REORDERABLE);
7839 gtk_drag_dest_unset (GTK_WIDGET (clist));
7844 gtk_cmclist_set_use_drag_icons (GtkCMCList *clist,
7847 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7850 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
7852 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
7856 gtk_cmclist_set_button_actions (GtkCMCList *clist,
7858 guint8 button_actions)
7860 cm_return_if_fail (GTK_IS_CMCLIST (clist));
7862 if (button < MAX_BUTTON)
7864 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) ||
7865 GTK_WIDGET_HAS_GRAB (clist))
7867 remove_grab (clist);
7868 clist->drag_button = 0;
7871 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
7873 clist->button_actions[button] = button_actions;