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>
40 /* length of button_actions array */
43 /* the number rows memchunk expands at a time */
44 #define CMCLIST_OPTIMUM_SIZE 64
46 /* the width of the column resize windows */
49 /* minimum allowed width of a column */
50 #define COLUMN_MIN_WIDTH 5
52 /* this defigns the base grid spacing */
53 #define CELL_SPACING 1
55 /* added the horizontal space at the beginning and end of a row*/
56 #define COLUMN_INSET 3
58 /* used for auto-scrolling */
59 #define SCROLL_TIME 100
61 /* gives the top pixel of the given row in context of
62 * the clist's voffset */
63 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
64 (((row) + 1) * CELL_SPACING) + \
67 /* returns the row index from a y pixel location in the
68 * context of the clist's voffset */
69 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
70 ((clist)->row_height + CELL_SPACING))
72 /* gives the left pixel of the given column in context of
73 * the clist's hoffset */
74 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
77 /* returns the column index from a x pixel location in the
78 * context of the clist's hoffset */
80 COLUMN_FROM_XPIXEL (GtkCMCList * clist,
85 for (i = 0; i < clist->columns; i++)
86 if (clist->column[i].visible)
88 cx = clist->column[i].area.x + clist->hoffset;
90 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
91 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
99 /* returns the top pixel of the given row in the context of
101 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
103 /* returns the left pixel of the given column in the context of
105 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
107 /* returns the total height of the list */
108 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
109 (CELL_SPACING * ((clist)->rows + 1)))
112 /* returns the total width of the list */
114 LIST_WIDTH (GtkCMCList * clist)
118 for (last_column = clist->columns - 1;
119 last_column >= 0 && !clist->column[last_column].visible; last_column--);
121 if (last_column >= 0)
122 return (clist->column[last_column].area.x +
123 clist->column[last_column].area.width +
124 COLUMN_INSET + CELL_SPACING);
128 /* returns the GList item for the nth row */
129 #define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
130 (clist)->row_list_end : \
131 g_list_nth ((clist)->row_list, (row)))
134 /* redraw the list if it's not frozen */
135 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
136 #define CLIST_REFRESH(clist) G_STMT_START { \
137 if (CLIST_UNFROZEN (clist)) \
138 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
178 #if GTK_CHECK_VERSION(3, 0, 0)
182 ARG_HADJUSTMENT_POLICY,
183 ARG_VADJUSTMENT_POLICY
187 /* GtkCMCList Methods */
188 static void gtk_cmclist_class_init (GtkCMCListClass *klass);
189 static void gtk_cmclist_init (GtkCMCList *clist);
190 static GObject* gtk_cmclist_constructor (GType type,
191 guint n_construct_properties,
192 GObjectConstructParam *construct_params);
194 /* GtkObject Methods */
195 #if !GTK_CHECK_VERSION(3, 0, 0)
196 static void gtk_cmclist_destroy (GtkObject *object);
198 static void gtk_cmclist_destroy (GtkWidget *object);
200 static void gtk_cmclist_finalize (GObject *object);
201 static void gtk_cmclist_set_arg (GObject *object,
205 static void gtk_cmclist_get_arg (GObject *object,
210 /* GtkWidget Methods */
211 #if !GTK_CHECK_VERSION(3, 0, 0)
212 static void gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist,
213 GtkAdjustment *hadjustment,
214 GtkAdjustment *vadjustment);
216 static void gtk_cmclist_realize (GtkWidget *widget);
217 static void gtk_cmclist_unrealize (GtkWidget *widget);
218 static void gtk_cmclist_map (GtkWidget *widget);
219 static void gtk_cmclist_unmap (GtkWidget *widget);
220 #if !GTK_CHECK_VERSION(3, 0, 0)
221 static gint gtk_cmclist_expose (GtkWidget *widget,
222 GdkEventExpose *event);
224 static gint gtk_cmclist_expose (GtkWidget *widget,
227 static gint gtk_cmclist_button_press (GtkWidget *widget,
228 GdkEventButton *event);
229 static gint gtk_cmclist_button_release (GtkWidget *widget,
230 GdkEventButton *event);
231 static gint gtk_cmclist_motion (GtkWidget *widget,
232 GdkEventMotion *event);
233 #if GTK_CHECK_VERSION(3, 0, 0)
234 static void gtk_cmclist_get_preferred_height (GtkWidget *widget,
235 gint *minimal_height,
236 gint *natural_height);
237 static void gtk_cmclist_get_preferred_width (GtkWidget *widget,
239 gint *natural_width);
241 static void gtk_cmclist_size_request (GtkWidget *widget,
242 GtkRequisition *requisition);
243 static void gtk_cmclist_size_allocate (GtkWidget *widget,
244 GtkAllocation *allocation);
245 static void gtk_cmclist_undraw_focus (GtkWidget *widget);
246 static void gtk_cmclist_draw_focus (GtkWidget *widget);
247 static gint gtk_cmclist_focus_in (GtkWidget *widget,
248 GdkEventFocus *event);
249 static gint gtk_cmclist_focus_out (GtkWidget *widget,
250 GdkEventFocus *event);
251 static gint gtk_cmclist_focus (GtkWidget *widget,
252 GtkDirectionType direction);
253 static void gtk_cmclist_set_focus_child (GtkContainer *container,
255 static void gtk_cmclist_style_set (GtkWidget *widget,
256 GtkStyle *previous_style);
257 static void gtk_cmclist_drag_begin (GtkWidget *widget,
258 GdkDragContext *context);
259 static gint gtk_cmclist_drag_motion (GtkWidget *widget,
260 GdkDragContext *context,
264 static void gtk_cmclist_drag_leave (GtkWidget *widget,
265 GdkDragContext *context,
267 static void gtk_cmclist_drag_end (GtkWidget *widget,
268 GdkDragContext *context);
269 static gboolean gtk_cmclist_drag_drop (GtkWidget *widget,
270 GdkDragContext *context,
274 static void gtk_cmclist_drag_data_get (GtkWidget *widget,
275 GdkDragContext *context,
276 GtkSelectionData *selection_data,
279 static void gtk_cmclist_drag_data_received (GtkWidget *widget,
280 GdkDragContext *context,
283 GtkSelectionData *selection_data,
287 /* GtkContainer Methods */
288 static void gtk_cmclist_forall (GtkContainer *container,
289 gboolean include_internals,
290 GtkCallback callback,
291 gpointer callback_data);
294 static void toggle_row (GtkCMCList *clist,
298 static void real_select_row (GtkCMCList *clist,
302 static void real_unselect_row (GtkCMCList *clist,
306 static void update_extended_selection (GtkCMCList *clist,
308 static GList *selection_find (GtkCMCList *clist,
310 GList *row_list_element);
311 static void real_select_all (GtkCMCList *clist);
312 static void real_unselect_all (GtkCMCList *clist);
313 static void move_vertical (GtkCMCList *clist,
316 static void move_horizontal (GtkCMCList *clist,
318 static void real_undo_selection (GtkCMCList *clist);
319 static void fake_unselect_all (GtkCMCList *clist,
321 static void fake_toggle_row (GtkCMCList *clist,
323 static void resync_selection (GtkCMCList *clist,
325 static void sync_selection (GtkCMCList *clist,
328 static void set_anchor (GtkCMCList *clist,
332 static void start_selection (GtkCMCList *clist);
333 static void end_selection (GtkCMCList *clist);
334 static void toggle_add_mode (GtkCMCList *clist);
335 static void toggle_focus_row (GtkCMCList *clist);
336 static void extend_selection (GtkCMCList *clist,
337 GtkScrollType scroll_type,
339 gboolean auto_start_selection);
340 static gint get_selection_info (GtkCMCList *clist,
347 static void move_focus_row (GtkCMCList *clist,
348 GtkScrollType scroll_type,
350 static void scroll_horizontal (GtkCMCList *clist,
351 GtkScrollType scroll_type,
353 static void scroll_vertical (GtkCMCList *clist,
354 GtkScrollType scroll_type,
356 static void move_horizontal (GtkCMCList *clist,
358 static void move_vertical (GtkCMCList *clist,
361 static gint horizontal_timeout (GtkCMCList *clist);
362 static gint vertical_timeout (GtkCMCList *clist);
363 static void remove_grab (GtkCMCList *clist);
367 static void draw_xor_line (GtkCMCList *clist);
368 static gint new_column_width (GtkCMCList *clist,
371 static void column_auto_resize (GtkCMCList *clist,
372 GtkCMCListRow *clist_row,
375 static void real_resize_column (GtkCMCList *clist,
378 static void abort_column_resize (GtkCMCList *clist);
379 static void cell_size_request (GtkCMCList *clist,
380 GtkCMCListRow *clist_row,
382 GtkRequisition *requisition);
385 static void column_button_create (GtkCMCList *clist,
387 static void column_button_clicked (GtkWidget *widget,
391 static void adjust_adjustments (GtkCMCList *clist,
392 gboolean block_resize);
393 static void vadjustment_value_changed (GtkAdjustment *adjustment,
395 static void hadjustment_value_changed (GtkAdjustment *adjustment,
399 static void get_cell_style (GtkCMCList *clist,
400 GtkCMCListRow *clist_row,
404 static gint draw_cell_pixbuf (GdkWindow *window,
405 GdkRectangle *clip_rectangle,
412 static void draw_row (GtkCMCList *clist,
415 GtkCMCListRow *clist_row);
416 static void draw_rows (GtkCMCList *clist,
418 static void clist_refresh (GtkCMCList *clist);
420 /* Size Allocation / Requisition */
421 static void size_allocate_title_buttons (GtkCMCList *clist);
422 static void size_allocate_columns (GtkCMCList *clist,
423 gboolean block_resize);
424 static gint list_requisition_width (GtkCMCList *clist);
426 /* Memory Allocation/Distruction Routines */
427 static GtkCMCListColumn *columns_new (GtkCMCList *clist);
428 static void column_title_new (GtkCMCList *clist,
431 static void columns_delete (GtkCMCList *clist);
432 static GtkCMCListRow *row_new (GtkCMCList *clist);
433 static void row_delete (GtkCMCList *clist,
434 GtkCMCListRow *clist_row);
435 static void set_cell_contents (GtkCMCList *clist,
436 GtkCMCListRow *clist_row,
442 static gint real_insert_row (GtkCMCList *clist,
445 static void real_remove_row (GtkCMCList *clist,
447 static void real_clear (GtkCMCList *clist);
450 static gint default_compare (GtkCMCList *clist,
453 static void real_sort_list (GtkCMCList *clist);
454 static GList *gtk_cmclist_merge (GtkCMCList *clist,
457 static GList *gtk_cmclist_mergesort (GtkCMCList *clist,
461 static gboolean title_focus_in (GtkCMCList *clist,
463 static gboolean title_focus_move (GtkCMCList *clist,
466 static void real_row_move (GtkCMCList *clist,
469 static gint column_title_passive_func (GtkWidget *widget,
472 static void drag_dest_cell (GtkCMCList *clist,
475 GtkCMCListDestInfo *dest_info);
479 static guint clist_signals[LAST_SIGNAL] = {0};
481 static const GtkTargetEntry clist_target_table = { "gtk-clist-drag-reorder", 0, 0};
483 #if !GTK_CHECK_VERSION(3, 0, 0)
484 static gpointer gtk_cmclist_parent_class = NULL;
487 gtk_cmclist_get_type (void)
489 static GType clist_type = 0;
493 static const GTypeInfo clist_info =
495 sizeof (GtkCMCListClass),
497 (GBaseInitFunc) NULL,
498 (GBaseFinalizeFunc) NULL,
500 (GClassInitFunc) gtk_cmclist_class_init,
501 (GClassFinalizeFunc) NULL,
502 NULL, /* class_data */
506 (GInstanceInitFunc) gtk_cmclist_init,
508 clist_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkCMCList", &clist_info, (GTypeFlags)0);
514 G_DEFINE_TYPE_WITH_CODE (GtkCMCList, gtk_cmclist, GTK_TYPE_CONTAINER,
515 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE,
520 gtk_cmclist_class_init (GtkCMCListClass *klass)
522 GObjectClass *object_class = G_OBJECT_CLASS (klass);
523 #if !GTK_CHECK_VERSION(3, 0, 0)
524 GtkObjectClass *gtk_object_class;
526 GtkWidgetClass *widget_class;
527 GtkContainerClass *container_class;
528 GtkBindingSet *binding_set;
530 object_class->constructor = gtk_cmclist_constructor;
532 #if !GTK_CHECK_VERSION(3, 0, 0)
533 gtk_object_class = (GtkObjectClass *) klass;
535 widget_class = (GtkWidgetClass *) klass;
536 container_class = (GtkContainerClass *) klass;
538 #if !GTK_CHECK_VERSION(3, 0, 0)
539 gtk_cmclist_parent_class = g_type_class_peek (GTK_TYPE_CONTAINER);
542 object_class->finalize = gtk_cmclist_finalize;
543 #if !GTK_CHECK_VERSION(3, 0, 0)
544 gtk_object_class->destroy = gtk_cmclist_destroy;
546 widget_class->destroy = gtk_cmclist_destroy;
548 object_class->set_property = gtk_cmclist_set_arg;
549 object_class->get_property = gtk_cmclist_get_arg;
552 widget_class->realize = gtk_cmclist_realize;
553 widget_class->unrealize = gtk_cmclist_unrealize;
554 widget_class->map = gtk_cmclist_map;
555 widget_class->unmap = gtk_cmclist_unmap;
556 widget_class->button_press_event = gtk_cmclist_button_press;
557 widget_class->button_release_event = gtk_cmclist_button_release;
558 widget_class->motion_notify_event = gtk_cmclist_motion;
559 #if !GTK_CHECK_VERSION(3, 0, 0)
560 widget_class->expose_event = gtk_cmclist_expose;
562 widget_class->draw = gtk_cmclist_expose;
564 #if !GTK_CHECK_VERSION(3, 0, 0)
565 widget_class->size_request = gtk_cmclist_size_request;
567 widget_class->get_preferred_width = gtk_cmclist_get_preferred_width;
568 widget_class->get_preferred_height = gtk_cmclist_get_preferred_height;
570 widget_class->size_allocate = gtk_cmclist_size_allocate;
571 widget_class->focus_in_event = gtk_cmclist_focus_in;
572 widget_class->focus_out_event = gtk_cmclist_focus_out;
573 widget_class->style_set = gtk_cmclist_style_set;
574 widget_class->drag_begin = gtk_cmclist_drag_begin;
575 widget_class->drag_end = gtk_cmclist_drag_end;
576 widget_class->drag_motion = gtk_cmclist_drag_motion;
577 widget_class->drag_leave = gtk_cmclist_drag_leave;
578 widget_class->drag_drop = gtk_cmclist_drag_drop;
579 widget_class->drag_data_get = gtk_cmclist_drag_data_get;
580 widget_class->drag_data_received = gtk_cmclist_drag_data_received;
581 widget_class->focus = gtk_cmclist_focus;
583 /* container_class->add = NULL; use the default GtkContainerClass warning */
584 /* container_class->remove=NULL; use the default GtkContainerClass warning */
586 container_class->forall = gtk_cmclist_forall;
587 container_class->set_focus_child = gtk_cmclist_set_focus_child;
589 #if !GTK_CHECK_VERSION(3, 0, 0)
590 klass->set_scroll_adjustments = gtk_cmclist_set_scroll_adjustments;
592 klass->refresh = clist_refresh;
593 klass->select_row = real_select_row;
594 klass->unselect_row = real_unselect_row;
595 klass->row_move = real_row_move;
596 klass->undo_selection = real_undo_selection;
597 klass->resync_selection = resync_selection;
598 klass->selection_find = selection_find;
599 klass->click_column = NULL;
600 klass->resize_column = real_resize_column;
601 klass->draw_row = draw_row;
602 klass->insert_row = real_insert_row;
603 klass->remove_row = real_remove_row;
604 klass->clear = real_clear;
605 klass->sort_list = real_sort_list;
606 klass->select_all = real_select_all;
607 klass->unselect_all = real_unselect_all;
608 klass->fake_unselect_all = fake_unselect_all;
609 klass->scroll_horizontal = scroll_horizontal;
610 klass->scroll_vertical = scroll_vertical;
611 klass->extend_selection = extend_selection;
612 klass->toggle_focus_row = toggle_focus_row;
613 klass->toggle_add_mode = toggle_add_mode;
614 klass->start_selection = start_selection;
615 klass->end_selection = end_selection;
616 klass->abort_column_resize = abort_column_resize;
617 klass->set_cell_contents = set_cell_contents;
618 klass->cell_size_request = cell_size_request;
620 g_object_class_install_property (object_class,
622 g_param_spec_uint ("n-columns",
628 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
629 g_object_class_install_property (object_class,
631 g_param_spec_enum ("shadow-type",
634 GTK_TYPE_SHADOW_TYPE, 0,
636 g_object_class_install_property (object_class,
638 g_param_spec_enum ("selection-mode",
641 GTK_TYPE_SELECTION_MODE, 0,
643 g_object_class_install_property (object_class,
645 g_param_spec_uint ("row-height",
652 g_object_class_install_property (object_class,
654 g_param_spec_boolean ("reorderable",
659 g_object_class_install_property (object_class,
661 g_param_spec_boolean ("titles-active",
666 g_object_class_install_property (object_class,
668 g_param_spec_boolean ("use-drag-icons",
673 g_object_class_install_property (object_class,
675 g_param_spec_enum ("sort-type",
678 GTK_TYPE_SORT_TYPE, 0,
680 #if !GTK_CHECK_VERSION(3, 0, 0)
681 widget_class->set_scroll_adjustments_signal =
682 g_signal_new ("set_scroll_adjustments",
683 G_TYPE_FROM_CLASS (object_class),
685 G_STRUCT_OFFSET (GtkCMCListClass, set_scroll_adjustments),
687 claws_marshal_VOID__OBJECT_OBJECT,
689 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
691 /* Scrollable interface properties */
692 g_object_class_override_property (object_class, ARG_HADJUSTMENT, "hadjustment");
693 g_object_class_override_property (object_class, ARG_VADJUSTMENT, "vadjustment");
694 g_object_class_override_property (object_class, ARG_HADJUSTMENT_POLICY, "hscroll-policy");
695 g_object_class_override_property (object_class, ARG_VADJUSTMENT_POLICY, "vscroll-policy");
698 clist_signals[SELECT_ROW] =
699 g_signal_new ("select_row",
700 G_TYPE_FROM_CLASS (object_class),
702 G_STRUCT_OFFSET (GtkCMCListClass, select_row),
704 claws_marshal_VOID__INT_INT_BOXED,
708 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
709 clist_signals[UNSELECT_ROW] =
710 g_signal_new ("unselect_row",
711 G_TYPE_FROM_CLASS (object_class),
713 G_STRUCT_OFFSET (GtkCMCListClass, unselect_row),
715 claws_marshal_VOID__INT_INT_BOXED,
720 clist_signals[ROW_MOVE] =
721 g_signal_new ("row_move",
722 G_TYPE_FROM_CLASS (object_class),
724 G_STRUCT_OFFSET (GtkCMCListClass, row_move),
726 claws_marshal_VOID__INT_INT,
727 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
728 clist_signals[CLICK_COLUMN] =
729 g_signal_new ("click_column",
730 G_TYPE_FROM_CLASS (object_class),
732 G_STRUCT_OFFSET (GtkCMCListClass, click_column),
734 claws_marshal_VOID__INT,
735 G_TYPE_NONE, 1, G_TYPE_INT);
736 clist_signals[RESIZE_COLUMN] =
737 g_signal_new ("resize_column",
738 G_TYPE_FROM_CLASS (object_class),
740 G_STRUCT_OFFSET (GtkCMCListClass, resize_column),
742 claws_marshal_VOID__INT_INT,
743 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
745 clist_signals[TOGGLE_FOCUS_ROW] =
746 g_signal_new ("toggle_focus_row",
747 G_TYPE_FROM_CLASS (object_class),
748 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
749 G_STRUCT_OFFSET (GtkCMCListClass, toggle_focus_row),
751 claws_marshal_VOID__VOID,
753 clist_signals[SELECT_ALL] =
754 g_signal_new ("select_all",
755 G_TYPE_FROM_CLASS (object_class),
756 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
757 G_STRUCT_OFFSET (GtkCMCListClass, select_all),
759 claws_marshal_VOID__VOID,
761 clist_signals[UNSELECT_ALL] =
762 g_signal_new ("unselect_all",
763 G_TYPE_FROM_CLASS (object_class),
764 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
765 G_STRUCT_OFFSET (GtkCMCListClass, unselect_all),
767 claws_marshal_VOID__VOID,
769 clist_signals[UNDO_SELECTION] =
770 g_signal_new ("undo_selection",
771 G_TYPE_FROM_CLASS (object_class),
772 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
773 G_STRUCT_OFFSET (GtkCMCListClass, undo_selection),
775 claws_marshal_VOID__VOID,
777 clist_signals[START_SELECTION] =
778 g_signal_new ("start_selection",
779 G_TYPE_FROM_CLASS (object_class),
780 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
781 G_STRUCT_OFFSET (GtkCMCListClass, start_selection),
783 claws_marshal_VOID__VOID,
785 clist_signals[END_SELECTION] =
786 g_signal_new ("end_selection",
787 G_TYPE_FROM_CLASS (object_class),
788 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
789 G_STRUCT_OFFSET (GtkCMCListClass, end_selection),
791 claws_marshal_VOID__VOID,
793 clist_signals[TOGGLE_ADD_MODE] =
794 g_signal_new ("toggle_add_mode",
795 G_TYPE_FROM_CLASS (object_class),
796 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
797 G_STRUCT_OFFSET (GtkCMCListClass, toggle_add_mode),
799 claws_marshal_VOID__VOID,
801 clist_signals[EXTEND_SELECTION] =
802 g_signal_new ("extend_selection",
803 G_TYPE_FROM_CLASS (object_class),
804 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
805 G_STRUCT_OFFSET (GtkCMCListClass, extend_selection),
807 claws_marshal_VOID__ENUM_FLOAT_BOOLEAN,
808 G_TYPE_NONE, 3, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT, G_TYPE_BOOLEAN);
809 clist_signals[SCROLL_VERTICAL] =
810 g_signal_new ("scroll_vertical",
811 G_TYPE_FROM_CLASS (object_class),
812 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
813 G_STRUCT_OFFSET (GtkCMCListClass, scroll_vertical),
815 claws_marshal_VOID__ENUM_FLOAT,
816 G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT);
817 clist_signals[SCROLL_HORIZONTAL] =
818 g_signal_new ("scroll_horizontal",
819 G_TYPE_FROM_CLASS (object_class),
820 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
821 G_STRUCT_OFFSET (GtkCMCListClass, scroll_horizontal),
823 claws_marshal_VOID__ENUM_FLOAT,
824 G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT);
825 clist_signals[ABORT_COLUMN_RESIZE] =
826 g_signal_new ("abort_column_resize",
827 G_TYPE_FROM_CLASS (object_class),
828 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
829 G_STRUCT_OFFSET (GtkCMCListClass, abort_column_resize),
831 claws_marshal_VOID__VOID,
834 binding_set = gtk_binding_set_by_class (klass);
835 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, 0,
836 "scroll_vertical", 2,
837 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
839 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up, 0,
840 "scroll_vertical", 2,
841 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
843 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, 0,
844 "scroll_vertical", 2,
845 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
847 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down, 0,
848 "scroll_vertical", 2,
849 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
851 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, 0,
852 "scroll_vertical", 2,
853 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
855 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Up, 0,
856 "scroll_vertical", 2,
857 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
859 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, 0,
860 "scroll_vertical", 2,
861 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
863 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Down, 0,
864 "scroll_vertical", 2,
865 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
867 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK,
868 "scroll_vertical", 2,
869 G_TYPE_ENUM, GTK_SCROLL_JUMP,
871 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK,
872 "scroll_vertical", 2,
873 G_TYPE_ENUM, GTK_SCROLL_JUMP,
875 gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, GDK_CONTROL_MASK,
876 "scroll_vertical", 2,
877 G_TYPE_ENUM, GTK_SCROLL_JUMP,
879 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK,
880 "scroll_vertical", 2,
881 G_TYPE_ENUM, GTK_SCROLL_JUMP,
884 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, GDK_SHIFT_MASK,
885 "extend_selection", 3,
886 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
887 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
888 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up, GDK_SHIFT_MASK,
889 "extend_selection", 3,
890 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
891 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
892 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, GDK_SHIFT_MASK,
893 "extend_selection", 3,
894 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
895 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
896 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down, GDK_SHIFT_MASK,
897 "extend_selection", 3,
898 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
899 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
900 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, GDK_SHIFT_MASK,
901 "extend_selection", 3,
902 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
903 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
904 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Up, GDK_SHIFT_MASK,
905 "extend_selection", 3,
906 G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
907 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
908 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, GDK_SHIFT_MASK,
909 "extend_selection", 3,
910 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
911 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
912 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Down, GDK_SHIFT_MASK,
913 "extend_selection", 3,
914 G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
915 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
916 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home,
917 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
918 "extend_selection", 3,
919 G_TYPE_ENUM, GTK_SCROLL_JUMP,
920 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
921 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home,
922 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
923 "extend_selection", 3,
924 G_TYPE_ENUM, GTK_SCROLL_JUMP,
925 G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE);
926 gtk_binding_entry_add_signal (binding_set, GDK_KEY_End,
927 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
928 "extend_selection", 3,
929 G_TYPE_ENUM, GTK_SCROLL_JUMP,
930 G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE);
931 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End,
932 GDK_SHIFT_MASK | GDK_CONTROL_MASK,
933 "extend_selection", 3,
934 G_TYPE_ENUM, GTK_SCROLL_JUMP,
935 G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE);
938 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0,
939 "scroll_horizontal", 2,
940 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
942 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0,
943 "scroll_horizontal", 2,
944 G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
947 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0,
948 "scroll_horizontal", 2,
949 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
951 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0,
952 "scroll_horizontal", 2,
953 G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
956 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, 0,
957 "scroll_horizontal", 2,
958 G_TYPE_ENUM, GTK_SCROLL_JUMP,
960 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, 0,
961 "scroll_horizontal", 2,
962 G_TYPE_ENUM, GTK_SCROLL_JUMP,
965 gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, 0,
966 "scroll_horizontal", 2,
967 G_TYPE_ENUM, GTK_SCROLL_JUMP,
970 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, 0,
971 "scroll_horizontal", 2,
972 G_TYPE_ENUM, GTK_SCROLL_JUMP,
975 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
976 "undo_selection", 0);
977 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
978 "abort_column_resize", 0);
979 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
980 "toggle_focus_row", 0);
981 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
982 "toggle_focus_row", 0);
983 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK,
984 "toggle_add_mode", 0);
985 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
986 "toggle_add_mode", 0);
987 gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK,
989 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, GDK_CONTROL_MASK,
991 gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK,
993 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Shift_L,
994 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
996 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Shift_R,
997 GDK_RELEASE_MASK | GDK_SHIFT_MASK,
999 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Shift_L,
1000 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
1002 "end_selection", 0);
1003 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Shift_R,
1004 GDK_RELEASE_MASK | GDK_SHIFT_MASK |
1006 "end_selection", 0);
1010 gtk_cmclist_set_arg (GObject *object,
1012 const GValue *value,
1017 clist = GTK_CMCLIST (object);
1021 case ARG_N_COLUMNS: /* only set at construction time */
1022 clist->columns = MAX (1, g_value_get_uint (value));
1024 case ARG_SHADOW_TYPE:
1025 gtk_cmclist_set_shadow_type (clist, g_value_get_enum (value));
1027 case ARG_SELECTION_MODE:
1028 gtk_cmclist_set_selection_mode (clist, g_value_get_enum (value));
1030 case ARG_ROW_HEIGHT:
1031 gtk_cmclist_set_row_height (clist, g_value_get_uint (value));
1033 case ARG_REORDERABLE:
1034 gtk_cmclist_set_reorderable (clist, g_value_get_boolean (value));
1036 case ARG_TITLES_ACTIVE:
1037 if (g_value_get_boolean (value))
1038 gtk_cmclist_column_titles_active (clist);
1040 gtk_cmclist_column_titles_passive (clist);
1042 case ARG_USE_DRAG_ICONS:
1043 gtk_cmclist_set_use_drag_icons (clist, g_value_get_boolean (value));
1046 gtk_cmclist_set_sort_type (clist, g_value_get_enum (value));
1048 #if GTK_CHECK_VERSION(3, 0, 0)
1049 case ARG_HADJUSTMENT:
1050 gtk_cmclist_set_hadjustment (clist, g_value_get_object (value));
1052 case ARG_VADJUSTMENT:
1053 gtk_cmclist_set_vadjustment (clist, g_value_get_object (value));
1055 case ARG_HADJUSTMENT_POLICY:
1056 case ARG_VADJUSTMENT_POLICY:
1063 gtk_cmclist_get_arg (GObject *object,
1070 clist = GTK_CMCLIST (object);
1077 g_value_set_uint(value, clist->columns);
1079 case ARG_SHADOW_TYPE:
1080 g_value_set_enum(value, clist->shadow_type);
1082 case ARG_SELECTION_MODE:
1083 g_value_set_enum(value, clist->selection_mode);
1085 case ARG_ROW_HEIGHT:
1086 g_value_set_uint(value, GTK_CMCLIST_ROW_HEIGHT_SET(clist) ? clist->row_height : 0);
1088 case ARG_REORDERABLE:
1089 g_value_set_boolean(value, GTK_CMCLIST_REORDERABLE (clist));
1091 case ARG_TITLES_ACTIVE:
1092 g_value_set_boolean(value, TRUE);
1093 for (i = 0; i < clist->columns; i++)
1094 if (clist->column[i].button &&
1095 !gtk_widget_get_sensitive (clist->column[i].button))
1097 g_value_set_boolean(value, FALSE);
1101 case ARG_USE_DRAG_ICONS:
1102 g_value_set_boolean(value, GTK_CMCLIST_USE_DRAG_ICONS (clist));
1105 g_value_set_enum(value, clist->sort_type);
1107 #if GTK_CHECK_VERSION(3, 0, 0)
1108 case ARG_HADJUSTMENT:
1109 g_value_set_object(value, gtk_cmclist_get_hadjustment(clist));
1111 case ARG_VADJUSTMENT:
1112 g_value_set_object(value, gtk_cmclist_get_vadjustment(clist));
1114 case ARG_HADJUSTMENT_POLICY:
1115 case ARG_VADJUSTMENT_POLICY:
1116 g_value_set_enum(value, GTK_SCROLL_NATURAL);
1120 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1126 gtk_cmclist_init (GtkCMCList *clist)
1130 gtkut_widget_set_has_window (GTK_WIDGET(clist), TRUE);
1131 gtkut_widget_set_can_focus (GTK_WIDGET(clist), TRUE);
1132 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_DRAW_DRAG_LINE);
1133 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
1135 clist->freeze_count = 0;
1138 clist->row_height = 0;
1139 clist->row_list = NULL;
1140 clist->row_list_end = NULL;
1144 clist->title_window = NULL;
1145 clist->column_title_area.x = 0;
1146 clist->column_title_area.y = 0;
1147 clist->column_title_area.width = 1;
1148 clist->column_title_area.height = 1;
1150 clist->clist_window = NULL;
1151 clist->clist_window_width = 1;
1152 clist->clist_window_height = 1;
1157 clist->shadow_type = GTK_SHADOW_IN;
1158 clist->vadjustment = NULL;
1159 clist->hadjustment = NULL;
1161 clist->button_actions[0] = GTK_CMBUTTON_SELECTS | GTK_CMBUTTON_DRAGS;
1162 clist->button_actions[1] = GTK_CMBUTTON_IGNORED;
1163 clist->button_actions[2] = GTK_CMBUTTON_IGNORED;
1164 clist->button_actions[3] = GTK_CMBUTTON_IGNORED;
1165 clist->button_actions[4] = GTK_CMBUTTON_IGNORED;
1167 clist->cursor_drag = NULL;
1170 clist->selection_mode = GTK_SELECTION_SINGLE;
1171 clist->selection = NULL;
1172 clist->selection_end = NULL;
1173 clist->undo_selection = NULL;
1174 clist->undo_unselection = NULL;
1176 clist->focus_row = -1;
1177 clist->focus_header_column = -1;
1178 clist->undo_anchor = -1;
1181 clist->anchor_state = GTK_STATE_SELECTED;
1182 clist->drag_pos = -1;
1186 clist->click_cell.row = -1;
1187 clist->click_cell.column = -1;
1189 clist->compare = default_compare;
1190 clist->sort_type = GTK_SORT_ASCENDING;
1191 clist->sort_column = 0;
1193 clist->drag_highlight_row = -1;
1198 gtk_cmclist_constructor (GType type,
1199 guint n_construct_properties,
1200 GObjectConstructParam *construct_properties)
1202 GObject *object = G_OBJECT_CLASS (gtk_cmclist_parent_class)->constructor (type,
1203 n_construct_properties,
1204 construct_properties);
1205 GtkCMCList *clist = GTK_CMCLIST (object);
1207 /* allocate memory for columns */
1208 clist->column = columns_new (clist);
1210 /* there needs to be at least one column button
1211 * because there is alot of code that will break if it
1214 column_button_create (clist, 0);
1219 /* GTKCLIST PUBLIC INTERFACE
1221 * gtk_cmclist_new_with_titles
1222 * gtk_cmclist_set_hadjustment
1223 * gtk_cmclist_set_vadjustment
1224 * gtk_cmclist_get_hadjustment
1225 * gtk_cmclist_get_vadjustment
1226 * gtk_cmclist_set_shadow_type
1227 * gtk_cmclist_set_selection_mode
1228 * gtk_cmclist_freeze
1232 gtk_cmclist_new (gint columns)
1234 return gtk_cmclist_new_with_titles (columns, NULL);
1238 gtk_cmclist_new_with_titles (gint columns,
1243 clist = g_object_new (GTK_TYPE_CMCLIST,
1244 "n_columns", columns,
1250 for (i = 0; i < clist->columns; i++)
1251 gtk_cmclist_set_column_title (clist, i, titles[i]);
1252 gtk_cmclist_column_titles_show (clist);
1255 gtk_cmclist_column_titles_hide (clist);
1257 return GTK_WIDGET (clist);
1261 gtk_cmclist_set_hadjustment (GtkCMCList *clist,
1262 GtkAdjustment *adjustment)
1264 GtkAdjustment *old_adjustment;
1266 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1268 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1270 if (clist->hadjustment == adjustment)
1273 old_adjustment = clist->hadjustment;
1275 if (clist->hadjustment)
1277 g_signal_handlers_disconnect_matched(G_OBJECT (clist->hadjustment), G_SIGNAL_MATCH_DATA,
1280 g_object_unref (G_OBJECT (clist->hadjustment));
1283 clist->hadjustment = adjustment;
1285 if (clist->hadjustment)
1287 g_object_ref_sink (clist->hadjustment);
1288 g_signal_connect (G_OBJECT (clist->hadjustment), "value_changed",
1289 G_CALLBACK( hadjustment_value_changed),
1293 if (!clist->hadjustment || !old_adjustment)
1294 gtk_widget_queue_resize (GTK_WIDGET (clist));
1298 gtk_cmclist_get_hadjustment (GtkCMCList *clist)
1300 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1302 return clist->hadjustment;
1306 gtk_cmclist_set_vadjustment (GtkCMCList *clist,
1307 GtkAdjustment *adjustment)
1309 GtkAdjustment *old_adjustment;
1311 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1313 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1315 if (clist->vadjustment == adjustment)
1318 old_adjustment = clist->vadjustment;
1320 if (clist->vadjustment)
1322 g_signal_handlers_disconnect_matched(G_OBJECT (clist->vadjustment), G_SIGNAL_MATCH_DATA,
1324 g_object_unref (G_OBJECT (clist->vadjustment));
1327 clist->vadjustment = adjustment;
1329 if (clist->vadjustment)
1331 g_object_ref_sink (clist->vadjustment);
1333 g_signal_connect (G_OBJECT (clist->vadjustment), "value_changed",
1334 G_CALLBACK(vadjustment_value_changed),
1338 if (!clist->vadjustment || !old_adjustment)
1339 gtk_widget_queue_resize (GTK_WIDGET (clist));
1343 gtk_cmclist_get_vadjustment (GtkCMCList *clist)
1345 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1347 return clist->vadjustment;
1350 #if !GTK_CHECK_VERSION(3, 0, 0)
1352 gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist,
1353 GtkAdjustment *hadjustment,
1354 GtkAdjustment *vadjustment)
1356 if (clist->hadjustment != hadjustment)
1357 gtk_cmclist_set_hadjustment (clist, hadjustment);
1358 if (clist->vadjustment != vadjustment)
1359 gtk_cmclist_set_vadjustment (clist, vadjustment);
1364 gtk_cmclist_set_shadow_type (GtkCMCList *clist,
1367 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1369 clist->shadow_type = type;
1371 if (gtk_widget_get_visible (GTK_WIDGET(clist)))
1372 gtk_widget_queue_resize (GTK_WIDGET (clist));
1376 gtk_cmclist_set_selection_mode (GtkCMCList *clist,
1377 GtkSelectionMode mode)
1379 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1380 cm_return_if_fail (mode != GTK_SELECTION_NONE);
1382 if (mode == clist->selection_mode)
1385 clist->selection_mode = mode;
1387 clist->anchor_state = GTK_STATE_SELECTED;
1388 clist->drag_pos = -1;
1389 clist->undo_anchor = clist->focus_row;
1391 g_list_free (clist->undo_selection);
1392 g_list_free (clist->undo_unselection);
1393 clist->undo_selection = NULL;
1394 clist->undo_unselection = NULL;
1398 case GTK_SELECTION_MULTIPLE:
1400 case GTK_SELECTION_BROWSE:
1401 case GTK_SELECTION_SINGLE:
1402 gtk_cmclist_unselect_all (clist);
1405 /* Someone set it by hand */
1406 g_assert_not_reached ();
1411 gtk_cmclist_freeze (GtkCMCList *clist)
1413 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1415 clist->freeze_count++;
1419 gtk_cmclist_thaw (GtkCMCList *clist)
1421 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1423 if (clist->freeze_count)
1425 clist->freeze_count--;
1426 CLIST_REFRESH (clist);
1430 /* PUBLIC COLUMN FUNCTIONS
1431 * gtk_cmclist_column_titles_show
1432 * gtk_cmclist_column_titles_hide
1433 * gtk_cmclist_column_title_active
1434 * gtk_cmclist_column_title_passive
1435 * gtk_cmclist_column_titles_active
1436 * gtk_cmclist_column_titles_passive
1437 * gtk_cmclist_set_column_title
1438 * gtk_cmclist_get_column_title
1439 * gtk_cmclist_set_column_widget
1440 * gtk_cmclist_set_column_justification
1441 * gtk_cmclist_set_column_visibility
1442 * gtk_cmclist_set_column_resizeable
1443 * gtk_cmclist_set_column_auto_resize
1444 * gtk_cmclist_optimal_column_width
1445 * gtk_cmclist_set_column_width
1446 * gtk_cmclist_set_column_min_width
1447 * gtk_cmclist_set_column_max_width
1450 gtk_cmclist_column_titles_show (GtkCMCList *clist)
1452 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1454 if (!GTK_CMCLIST_SHOW_TITLES(clist))
1456 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_SHOW_TITLES);
1457 if (clist->title_window)
1458 gdk_window_show (clist->title_window);
1459 gtk_widget_queue_resize (GTK_WIDGET (clist));
1464 gtk_cmclist_column_titles_hide (GtkCMCList *clist)
1466 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1468 if (GTK_CMCLIST_SHOW_TITLES(clist))
1470 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_SHOW_TITLES);
1471 if (clist->title_window)
1472 gdk_window_hide (clist->title_window);
1473 gtk_widget_queue_resize (GTK_WIDGET (clist));
1478 gtk_cmclist_column_title_active (GtkCMCList *clist,
1481 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1483 if (column < 0 || column >= clist->columns)
1485 if (!clist->column[column].button || !clist->column[column].button_passive)
1488 clist->column[column].button_passive = FALSE;
1490 g_signal_handlers_disconnect_matched(G_OBJECT (clist->column[column].button), G_SIGNAL_MATCH_FUNC,
1491 0, 0, 0, column_title_passive_func, 0);
1493 gtkut_widget_set_can_focus (clist->column[column].button, TRUE);
1494 if (gtk_widget_get_visible (GTK_WIDGET(clist)))
1495 gtk_widget_queue_draw (clist->column[column].button);
1499 gtk_cmclist_column_title_passive (GtkCMCList *clist,
1502 GtkToggleButton *button;
1504 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1506 if (column < 0 || column >= clist->columns)
1508 if (!clist->column[column].button || clist->column[column].button_passive)
1511 button = GTK_TOGGLE_BUTTON (clist->column[column].button);
1513 clist->column[column].button_passive = TRUE;
1515 if (gtk_toggle_button_get_active(button))
1516 g_signal_connect(G_OBJECT (clist->column[column].button),
1517 "button-release-event",
1518 G_CALLBACK(column_title_passive_func),
1520 if (gtk_widget_is_focus(gtk_bin_get_child(GTK_BIN(button))))
1521 g_signal_connect(G_OBJECT (clist->column[column].button),
1522 "leave-notify-event",
1523 G_CALLBACK(column_title_passive_func),
1526 g_signal_connect (G_OBJECT (clist->column[column].button), "event",
1527 G_CALLBACK(column_title_passive_func), NULL);
1529 gtkut_widget_set_can_focus (clist->column[column].button, FALSE);
1530 if (gtk_widget_get_visible (GTK_WIDGET(clist)))
1531 gtk_widget_queue_draw (clist->column[column].button);
1535 gtk_cmclist_column_titles_active (GtkCMCList *clist)
1539 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1541 for (i = 0; i < clist->columns; i++)
1542 gtk_cmclist_column_title_active (clist, i);
1546 gtk_cmclist_column_titles_passive (GtkCMCList *clist)
1550 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1552 for (i = 0; i < clist->columns; i++)
1553 gtk_cmclist_column_title_passive (clist, i);
1557 gtk_cmclist_set_column_title (GtkCMCList *clist,
1561 gint new_button = 0;
1562 GtkWidget *old_widget;
1563 GtkWidget *alignment = NULL;
1566 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1568 if (column < 0 || column >= clist->columns)
1571 /* if the column button doesn't currently exist,
1572 * it has to be created first */
1573 if (!clist->column[column].button)
1575 column_button_create (clist, column);
1579 column_title_new (clist, column, title);
1581 /* remove and destroy the old widget */
1582 old_widget = gtk_bin_get_child (GTK_BIN (clist->column[column].button));
1584 gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
1586 /* create new alignment based no column justification */
1587 switch (clist->column[column].justification)
1589 case GTK_JUSTIFY_LEFT:
1590 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1593 case GTK_JUSTIFY_RIGHT:
1594 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1597 case GTK_JUSTIFY_CENTER:
1598 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1601 case GTK_JUSTIFY_FILL:
1602 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1606 gtk_widget_push_composite_child ();
1607 label = gtk_label_new (clist->column[column].title);
1608 gtk_widget_pop_composite_child ();
1609 gtk_container_add (GTK_CONTAINER (alignment), label);
1610 gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
1611 gtk_widget_show (label);
1612 gtk_widget_show (alignment);
1614 /* if this button didn't previously exist, then the
1615 * column button positions have to be re-computed */
1616 if (gtk_widget_get_visible (GTK_WIDGET(clist)) && new_button)
1617 size_allocate_title_buttons (clist);
1621 gtk_cmclist_get_column_title (GtkCMCList *clist,
1624 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1626 if (column < 0 || column >= clist->columns)
1629 return clist->column[column].title;
1633 gtk_cmclist_set_column_widget (GtkCMCList *clist,
1637 gint new_button = 0;
1638 GtkWidget *old_widget;
1640 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1642 if (column < 0 || column >= clist->columns)
1645 /* if the column button doesn't currently exist,
1646 * it has to be created first */
1647 if (!clist->column[column].button)
1649 column_button_create (clist, column);
1653 column_title_new (clist, column, NULL);
1655 /* remove and destroy the old widget */
1656 old_widget = gtk_bin_get_child (GTK_BIN (clist->column[column].button));
1658 gtk_container_remove (GTK_CONTAINER (clist->column[column].button),
1661 /* add and show the widget */
1664 gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
1665 gtk_widget_show (widget);
1668 /* if this button didn't previously exist, then the
1669 * column button positions have to be re-computed */
1670 if (gtk_widget_get_visible (GTK_WIDGET(clist)) && new_button)
1671 size_allocate_title_buttons (clist);
1675 gtk_cmclist_get_column_widget (GtkCMCList *clist,
1678 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
1680 if (column < 0 || column >= clist->columns)
1683 if (clist->column[column].button)
1684 return gtk_bin_get_child (GTK_BIN (clist->column[column].button));
1690 gtk_cmclist_set_column_justification (GtkCMCList *clist,
1692 GtkJustification justification)
1694 GtkWidget *alignment;
1696 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1698 if (column < 0 || column >= clist->columns)
1701 clist->column[column].justification = justification;
1703 /* change the alinment of the button title if it's not a
1705 if (clist->column[column].title)
1707 alignment = gtk_bin_get_child (GTK_BIN (clist->column[column].button));
1709 switch (clist->column[column].justification)
1711 case GTK_JUSTIFY_LEFT:
1712 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
1715 case GTK_JUSTIFY_RIGHT:
1716 gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
1719 case GTK_JUSTIFY_CENTER:
1720 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1723 case GTK_JUSTIFY_FILL:
1724 gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
1732 if (CLIST_UNFROZEN (clist))
1733 draw_rows (clist, NULL);
1737 gtk_cmclist_set_column_visibility (GtkCMCList *clist,
1741 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1743 if (column < 0 || column >= clist->columns)
1745 if (clist->column[column].visible == visible)
1748 /* don't hide last visible column */
1752 gint vis_columns = 0;
1754 for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++)
1755 if (clist->column[i].visible)
1758 if (vis_columns < 2)
1762 clist->column[column].visible = visible;
1764 if (clist->column[column].button)
1767 gtk_widget_show (clist->column[column].button);
1769 gtk_widget_hide (clist->column[column].button);
1772 gtk_widget_queue_resize (GTK_WIDGET(clist));
1776 gtk_cmclist_set_column_resizeable (GtkCMCList *clist,
1778 gboolean resizeable)
1780 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1782 if (column < 0 || column >= clist->columns)
1784 if (clist->column[column].resizeable == resizeable)
1787 clist->column[column].resizeable = resizeable;
1789 clist->column[column].auto_resize = FALSE;
1791 if (gtk_widget_get_visible (GTK_WIDGET(clist)))
1792 size_allocate_title_buttons (clist);
1796 gtk_cmclist_set_column_auto_resize (GtkCMCList *clist,
1798 gboolean auto_resize)
1800 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1802 if (column < 0 || column >= clist->columns)
1804 if (clist->column[column].auto_resize == auto_resize)
1807 clist->column[column].auto_resize = auto_resize;
1810 clist->column[column].resizeable = FALSE;
1811 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1815 width = gtk_cmclist_optimal_column_width (clist, column);
1816 gtk_cmclist_set_column_width (clist, column, width);
1820 if (gtk_widget_get_visible (GTK_WIDGET(clist)))
1821 size_allocate_title_buttons (clist);
1825 gtk_cmclist_columns_autosize (GtkCMCList *clist)
1830 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
1832 gtk_cmclist_freeze (clist);
1834 for (i = 0; i < clist->columns; i++)
1836 gtk_cmclist_set_column_width (clist, i,
1837 gtk_cmclist_optimal_column_width (clist, i));
1839 width += clist->column[i].width;
1842 gtk_cmclist_thaw (clist);
1847 gtk_cmclist_optimal_column_width (GtkCMCList *clist,
1850 GtkRequisition requisition;
1854 cm_return_val_if_fail (GTK_CMCLIST (clist), 0);
1856 if (column < 0 || column >= clist->columns)
1859 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button)
1861 gtk_widget_get_requisition (clist->column[column].button, &requisition);
1862 width = requisition.width
1864 (CELL_SPACING + (2 * COLUMN_INSET)))
1871 for (list = clist->row_list; list; list = list->next)
1873 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1874 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
1875 width = MAX (width, requisition.width);
1882 gtk_cmclist_set_column_width (GtkCMCList *clist,
1886 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1888 if (column < 0 || column >= clist->columns)
1891 g_signal_emit (G_OBJECT (clist), clist_signals[RESIZE_COLUMN], 0,
1896 gtk_cmclist_set_column_min_width (GtkCMCList *clist,
1900 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1902 if (column < 0 || column >= clist->columns)
1904 if (clist->column[column].min_width == min_width)
1907 if (clist->column[column].max_width >= 0 &&
1908 clist->column[column].max_width < min_width)
1909 clist->column[column].min_width = clist->column[column].max_width;
1911 clist->column[column].min_width = min_width;
1913 if (clist->column[column].area.width < clist->column[column].min_width)
1914 gtk_cmclist_set_column_width (clist, column,clist->column[column].min_width);
1918 gtk_cmclist_set_column_max_width (GtkCMCList *clist,
1922 cm_return_if_fail (GTK_IS_CMCLIST (clist));
1924 if (column < 0 || column >= clist->columns)
1926 if (clist->column[column].max_width == max_width)
1929 if (clist->column[column].min_width >= 0 && max_width >= 0 &&
1930 clist->column[column].min_width > max_width)
1931 clist->column[column].max_width = clist->column[column].min_width;
1933 clist->column[column].max_width = max_width;
1935 if (clist->column[column].area.width > clist->column[column].max_width)
1936 gtk_cmclist_set_column_width (clist, column,clist->column[column].max_width);
1939 /* PRIVATE COLUMN FUNCTIONS
1940 * column_auto_resize
1941 * real_resize_column
1942 * abort_column_resize
1943 * size_allocate_title_buttons
1944 * size_allocate_columns
1945 * list_requisition_width
1947 * column_button_create
1948 * column_button_clicked
1949 * column_title_passive_func
1952 column_auto_resize (GtkCMCList *clist,
1953 GtkCMCListRow *clist_row,
1957 /* resize column if needed for auto_resize */
1958 GtkRequisition requisition;
1960 if (!clist->column[column].auto_resize ||
1961 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1965 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
1966 column, &requisition);
1968 requisition.width = 0;
1970 if (requisition.width > clist->column[column].width)
1971 gtk_cmclist_set_column_width (clist, column, requisition.width);
1972 else if (requisition.width < old_width &&
1973 old_width == clist->column[column].width)
1978 /* run a "gtk_cmclist_optimal_column_width" but break, if
1979 * the column doesn't shrink */
1980 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button)
1982 gtk_widget_get_requisition (clist->column[column].button, &requisition);
1983 new_width = (requisition.width -
1984 (CELL_SPACING + (2 * COLUMN_INSET)));
1989 for (list = clist->row_list; list; list = list->next)
1991 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1992 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
1993 new_width = MAX (new_width, requisition.width);
1994 if (new_width == clist->column[column].width)
1997 if (new_width < clist->column[column].width)
1998 gtk_cmclist_set_column_width
1999 (clist, column, MAX (new_width, clist->column[column].min_width));
2004 real_resize_column (GtkCMCList *clist,
2008 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2010 if (column < 0 || column >= clist->columns)
2013 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
2014 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
2015 if (clist->column[column].max_width >= 0 &&
2016 width > clist->column[column].max_width)
2017 width = clist->column[column].max_width;
2019 clist->column[column].width = width;
2020 clist->column[column].width_set = TRUE;
2022 /* FIXME: this is quite expensive to do if the widget hasn't
2023 * been size_allocated yet, and pointless. Should
2026 size_allocate_columns (clist, TRUE);
2027 size_allocate_title_buttons (clist);
2029 CLIST_REFRESH (clist);
2033 abort_column_resize (GtkCMCList *clist)
2035 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2037 if (!GTK_CMCLIST_IN_DRAG(clist))
2040 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG);
2041 gtk_grab_remove (GTK_WIDGET (clist));
2042 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
2044 clist->drag_pos = -1;
2046 if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1)
2047 clist_refresh(clist);
2051 size_allocate_title_buttons (GtkCMCList *clist)
2053 GtkAllocation button_allocation;
2055 gint last_button = 0;
2058 if (!gtk_widget_get_realized (GTK_WIDGET(clist)))
2061 button_allocation.x = clist->hoffset;
2062 button_allocation.y = 0;
2063 button_allocation.width = 0;
2064 button_allocation.height = clist->column_title_area.height;
2066 /* find last visible column */
2067 for (last_column = clist->columns - 1; last_column >= 0; last_column--)
2068 if (clist->column[last_column].visible)
2071 for (i = 0; i < last_column; i++)
2073 if (!clist->column[i].visible)
2075 last_button = i + 1;
2076 gdk_window_hide (clist->column[i].window);
2080 button_allocation.width += (clist->column[i].area.width +
2081 CELL_SPACING + 2 * COLUMN_INSET);
2083 if (!clist->column[i + 1].button)
2085 gdk_window_hide (clist->column[i].window);
2089 gtk_widget_size_allocate (clist->column[last_button].button,
2090 &button_allocation);
2091 button_allocation.x += button_allocation.width;
2092 button_allocation.width = 0;
2094 if (clist->column[last_button].resizeable)
2096 gdk_window_show (clist->column[last_button].window);
2097 gdk_window_move_resize (clist->column[last_button].window,
2098 button_allocation.x - (DRAG_WIDTH / 2),
2100 clist->column_title_area.height);
2103 gdk_window_hide (clist->column[last_button].window);
2105 last_button = i + 1;
2108 button_allocation.width += (clist->column[last_column].area.width +
2109 2 * (CELL_SPACING + COLUMN_INSET));
2110 gtk_widget_size_allocate (clist->column[last_button].button,
2111 &button_allocation);
2113 if (clist->column[last_button].resizeable)
2115 button_allocation.x += button_allocation.width;
2117 gdk_window_show (clist->column[last_button].window);
2118 gdk_window_move_resize (clist->column[last_button].window,
2119 button_allocation.x - (DRAG_WIDTH / 2),
2120 0, DRAG_WIDTH, clist->column_title_area.height);
2123 gdk_window_hide (clist->column[last_button].window);
2127 size_allocate_columns (GtkCMCList *clist,
2128 gboolean block_resize)
2130 GtkRequisition requisition;
2131 gint xoffset = CELL_SPACING + COLUMN_INSET;
2135 /* find last visible column and calculate correct column width */
2136 for (last_column = clist->columns - 1;
2137 last_column >= 0 && !clist->column[last_column].visible; last_column--);
2139 if (last_column < 0)
2142 for (i = 0; i <= last_column; i++)
2144 if (!clist->column[i].visible)
2146 clist->column[i].area.x = xoffset;
2147 if (clist->column[i].width_set)
2149 if (!block_resize && GTK_CMCLIST_SHOW_TITLES(clist) &&
2150 clist->column[i].auto_resize && clist->column[i].button)
2154 gtk_widget_get_requisition (clist->column[i].button, &requisition);
2155 width = (requisition.width -
2156 (CELL_SPACING + (2 * COLUMN_INSET)));
2158 if (width > clist->column[i].width)
2159 gtk_cmclist_set_column_width (clist, i, width);
2162 clist->column[i].area.width = clist->column[i].width;
2163 xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET);
2165 else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2167 gtk_widget_get_requisition (clist->column[i].button, &requisition);
2168 clist->column[i].area.width =
2170 (CELL_SPACING + (2 * COLUMN_INSET));
2171 xoffset += requisition.width;
2175 clist->column[last_column].area.width = clist->column[last_column].area.width
2176 + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset);
2180 list_requisition_width (GtkCMCList *clist)
2182 GtkRequisition requisition;
2183 gint width = CELL_SPACING;
2186 for (i = clist->columns - 1; i >= 0; i--)
2188 if (!clist->column[i].visible)
2191 if (clist->column[i].width_set)
2192 width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET);
2193 else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2195 gtk_widget_get_requisition (clist->column[i].button, &requisition);
2196 width += requisition.width;
2203 /* this function returns the new width of the column being resized given
2204 * the column and x position of the cursor; the x cursor position is passed
2205 * in as a pointer and automagicly corrected if it's beyond min/max limits */
2207 new_column_width (GtkCMCList *clist,
2211 gint xthickness = gtk_widget_get_style (GTK_WIDGET (clist))->xthickness;
2217 /* first translate the x position from widget->window
2218 * to clist->clist_window */
2219 cx = *x - xthickness;
2221 for (last_column = clist->columns - 1;
2222 last_column >= 0 && !clist->column[last_column].visible; last_column--);
2224 /* calculate new column width making sure it doesn't end up
2225 * less than the minimum width */
2226 dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET +
2227 (column < last_column) * CELL_SPACING);
2230 if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width))
2232 width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width);
2234 *x = cx + xthickness;
2236 else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH &&
2237 width > clist->column[column].max_width)
2239 width = clist->column[column].max_width;
2240 cx = dx + clist->column[column].max_width;
2241 *x = cx + xthickness;
2244 if (cx < 0 || cx > clist->clist_window_width)
2251 column_button_create (GtkCMCList *clist,
2256 gtk_widget_push_composite_child ();
2257 button = clist->column[column].button = gtk_button_new ();
2258 GtkRcStyle *style = gtk_rc_style_new();
2259 style->ythickness = 0;
2260 gtk_widget_modify_style(clist->column[column].button, style);
2261 g_object_unref(style);
2262 gtk_container_set_border_width(GTK_CONTAINER(button), 0);
2263 gtk_widget_pop_composite_child ();
2265 if (gtk_widget_get_realized (GTK_WIDGET(clist)) && clist->title_window)
2266 gtk_widget_set_parent_window (clist->column[column].button,
2267 clist->title_window);
2268 gtk_widget_set_parent (button, GTK_WIDGET (clist));
2270 g_signal_connect (G_OBJECT (button), "clicked",
2271 G_CALLBACK(column_button_clicked),
2273 gtk_widget_show (button);
2277 column_button_clicked (GtkWidget *widget,
2283 cm_return_if_fail (widget != NULL);
2284 cm_return_if_fail (GTK_IS_CMCLIST (data));
2286 clist = GTK_CMCLIST (data);
2288 /* find the column who's button was pressed */
2289 for (i = 0; i < clist->columns; i++)
2290 if (clist->column[i].button == widget)
2293 g_signal_emit (G_OBJECT (clist), clist_signals[CLICK_COLUMN], 0, i);
2297 column_title_passive_func (GtkWidget *widget,
2301 cm_return_val_if_fail (event != NULL, FALSE);
2303 switch (event->type)
2305 case GDK_MOTION_NOTIFY:
2306 case GDK_BUTTON_PRESS:
2307 case GDK_2BUTTON_PRESS:
2308 case GDK_3BUTTON_PRESS:
2309 case GDK_BUTTON_RELEASE:
2310 case GDK_ENTER_NOTIFY:
2311 case GDK_LEAVE_NOTIFY:
2320 /* PUBLIC CELL FUNCTIONS
2321 * gtk_cmclist_get_cell_type
2322 * gtk_cmclist_set_text
2323 * gtk_cmclist_get_text
2324 * gtk_cmclist_set_pixbuf
2325 * gtk_cmclist_get_pixbuf
2326 * gtk_cmclist_set_pixtext
2327 * gtk_cmclist_get_pixtext
2328 * gtk_cmclist_set_shift
2331 gtk_cmclist_get_cell_type (GtkCMCList *clist,
2335 GtkCMCListRow *clist_row;
2337 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2339 if (row < 0 || row >= clist->rows)
2341 if (column < 0 || column >= clist->columns)
2344 clist_row = ROW_ELEMENT (clist, row)->data;
2346 return clist_row->cell[column].type;
2350 gtk_cmclist_set_text (GtkCMCList *clist,
2355 GtkCMCListRow *clist_row;
2357 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2359 if (row < 0 || row >= clist->rows)
2361 if (column < 0 || column >= clist->columns)
2364 clist_row = ROW_ELEMENT (clist, row)->data;
2366 /* if text is null, then the cell is empty */
2367 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2368 (clist, clist_row, column, GTK_CMCELL_TEXT, text, 0, NULL);
2370 /* redraw the list if it's not frozen */
2371 if (CLIST_UNFROZEN (clist))
2373 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2374 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2379 gtk_cmclist_get_text (GtkCMCList *clist,
2384 GtkCMCListRow *clist_row;
2386 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2388 if (row < 0 || row >= clist->rows)
2390 if (column < 0 || column >= clist->columns)
2393 clist_row = ROW_ELEMENT (clist, row)->data;
2395 if (clist_row->cell[column].type != GTK_CMCELL_TEXT)
2399 *text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2405 gtk_cmclist_set_pixbuf (GtkCMCList *clist,
2410 GtkCMCListRow *clist_row;
2412 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2414 if (row < 0 || row >= clist->rows)
2416 if (column < 0 || column >= clist->columns)
2419 clist_row = ROW_ELEMENT (clist, row)->data;
2421 g_object_ref (pixbuf);
2423 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2424 (clist, clist_row, column, GTK_CMCELL_PIXBUF, NULL, 0, pixbuf);
2426 /* redraw the list if it's not frozen */
2427 if (CLIST_UNFROZEN (clist))
2429 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2430 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2435 gtk_cmclist_get_pixbuf (GtkCMCList *clist,
2440 GtkCMCListRow *clist_row;
2442 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2444 if (row < 0 || row >= clist->rows)
2446 if (column < 0 || column >= clist->columns)
2449 clist_row = ROW_ELEMENT (clist, row)->data;
2451 if (clist_row->cell[column].type != GTK_CMCELL_PIXBUF)
2456 *pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2463 gtk_cmclist_set_pixtext (GtkCMCList *clist,
2470 GtkCMCListRow *clist_row;
2472 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2474 if (row < 0 || row >= clist->rows)
2476 if (column < 0 || column >= clist->columns)
2479 clist_row = ROW_ELEMENT (clist, row)->data;
2481 g_object_ref (pixbuf);
2482 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2483 (clist, clist_row, column, GTK_CMCELL_PIXTEXT, text, spacing, pixbuf);
2485 /* redraw the list if it's not frozen */
2486 if (CLIST_UNFROZEN (clist))
2488 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2489 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2494 gtk_cmclist_get_pixtext (GtkCMCList *clist,
2501 GtkCMCListRow *clist_row;
2503 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
2505 if (row < 0 || row >= clist->rows)
2507 if (column < 0 || column >= clist->columns)
2510 clist_row = ROW_ELEMENT (clist, row)->data;
2512 if (clist_row->cell[column].type != GTK_CMCELL_PIXTEXT)
2516 *text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2518 *spacing = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2520 *pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2526 gtk_cmclist_set_shift (GtkCMCList *clist,
2532 GtkRequisition requisition = { 0 };
2533 GtkCMCListRow *clist_row;
2535 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2537 if (row < 0 || row >= clist->rows)
2539 if (column < 0 || column >= clist->columns)
2542 clist_row = ROW_ELEMENT (clist, row)->data;
2544 if (clist->column[column].auto_resize &&
2545 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2546 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2547 column, &requisition);
2549 clist_row->cell[column].vertical = vertical;
2550 clist_row->cell[column].horizontal = horizontal;
2552 column_auto_resize (clist, clist_row, column, requisition.width);
2554 if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2555 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
2558 /* PRIVATE CELL FUNCTIONS
2563 set_cell_contents (GtkCMCList *clist,
2564 GtkCMCListRow *clist_row,
2571 GtkRequisition requisition;
2572 gchar *old_text = NULL;
2573 GdkPixbuf *old_pixbuf = NULL;
2575 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2576 cm_return_if_fail (clist_row != NULL);
2578 if (clist->column[column].auto_resize &&
2579 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2580 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2581 column, &requisition);
2583 switch (clist_row->cell[column].type)
2585 case GTK_CMCELL_EMPTY:
2587 case GTK_CMCELL_TEXT:
2588 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2590 case GTK_CMCELL_PIXBUF:
2591 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2593 case GTK_CMCELL_PIXTEXT:
2594 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2595 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2597 case GTK_CMCELL_WIDGET:
2604 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2606 /* Note that pixbuf and mask were already ref'ed by the caller
2610 case GTK_CMCELL_TEXT:
2613 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2614 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2617 case GTK_CMCELL_PIXBUF:
2620 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2621 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2624 case GTK_CMCELL_PIXTEXT:
2627 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2628 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2629 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2630 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2637 if (clist->column[column].auto_resize &&
2638 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2639 column_auto_resize (clist, clist_row, column, requisition.width);
2643 g_object_unref (old_pixbuf);
2647 _gtk_cmclist_create_cell_layout (GtkCMCList *clist,
2648 GtkCMCListRow *clist_row,
2651 PangoLayout *layout;
2656 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style);
2659 cell = &clist_row->cell[column];
2662 case GTK_CMCELL_TEXT:
2663 case GTK_CMCELL_PIXTEXT:
2664 text = ((cell->type == GTK_CMCELL_PIXTEXT) ?
2665 GTK_CMCELL_PIXTEXT (*cell)->text :
2666 GTK_CMCELL_TEXT (*cell)->text);
2671 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
2672 ((cell->type == GTK_CMCELL_PIXTEXT) ?
2673 GTK_CMCELL_PIXTEXT (*cell)->text :
2674 GTK_CMCELL_TEXT (*cell)->text));
2675 pango_layout_set_font_description (layout, style->font_desc);
2685 cell_size_request (GtkCMCList *clist,
2686 GtkCMCListRow *clist_row,
2688 GtkRequisition *requisition)
2692 PangoLayout *layout;
2693 PangoRectangle logical_rect;
2695 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2696 cm_return_if_fail (requisition != NULL);
2698 layout = _gtk_cmclist_create_cell_layout (clist, clist_row, column);
2701 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2703 requisition->width = logical_rect.width;
2704 requisition->height = logical_rect.height;
2706 g_object_unref (G_OBJECT (layout));
2710 requisition->width = 0;
2711 requisition->height = 0;
2714 if (layout && clist_row->cell[column].type == GTK_CMCELL_PIXTEXT)
2715 requisition->width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2717 switch (clist_row->cell[column].type)
2719 case GTK_CMCELL_PIXTEXT:
2720 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2721 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2722 requisition->width += width;
2723 requisition->height = MAX (requisition->height, height);
2725 case GTK_CMCELL_PIXBUF:
2726 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2727 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2728 requisition->width += width;
2729 requisition->height = MAX (requisition->height, height);
2736 requisition->width += clist_row->cell[column].horizontal;
2737 requisition->height += clist_row->cell[column].vertical;
2740 /* PUBLIC INSERT/REMOVE ROW FUNCTIONS
2741 * gtk_cmclist_prepend
2742 * gtk_cmclist_append
2743 * gtk_cmclist_insert
2744 * gtk_cmclist_remove
2748 gtk_cmclist_prepend (GtkCMCList *clist,
2751 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2752 cm_return_val_if_fail (text != NULL, -1);
2754 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, 0, text);
2758 gtk_cmclist_append (GtkCMCList *clist,
2761 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2762 cm_return_val_if_fail (text != NULL, -1);
2764 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, clist->rows, text);
2768 gtk_cmclist_insert (GtkCMCList *clist,
2772 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2773 cm_return_val_if_fail (text != NULL, -1);
2775 if (row < 0 || row > clist->rows)
2778 return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, row, text);
2782 gtk_cmclist_remove (GtkCMCList *clist,
2785 GTK_CMCLIST_GET_CLASS (clist)->remove_row (clist, row);
2789 gtk_cmclist_clear (GtkCMCList *clist)
2791 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2793 GTK_CMCLIST_GET_CLASS (clist)->clear (clist);
2796 /* PRIVATE INSERT/REMOVE ROW FUNCTIONS
2803 real_insert_row (GtkCMCList *clist,
2808 GtkCMCListRow *clist_row;
2810 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
2811 cm_return_val_if_fail (text != NULL, -1);
2813 /* return if out of bounds */
2814 if (row < 0 || row > clist->rows)
2817 /* create the row */
2818 clist_row = row_new (clist);
2820 /* set the text in the row's columns */
2821 for (i = 0; i < clist->columns; i++)
2823 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2824 (clist, clist_row, i, GTK_CMCELL_TEXT, text[i], 0, NULL);
2828 clist->row_list = g_list_append (clist->row_list, clist_row);
2829 clist->row_list_end = clist->row_list;
2833 if (GTK_CMCLIST_AUTO_SORT(clist)) /* override insertion pos */
2838 work = clist->row_list;
2840 if (clist->sort_type == GTK_SORT_ASCENDING)
2842 while (row < clist->rows &&
2843 clist->compare (clist, clist_row,
2844 GTK_CMCLIST_ROW (work)) > 0)
2852 while (row < clist->rows &&
2853 clist->compare (clist, clist_row,
2854 GTK_CMCLIST_ROW (work)) < 0)
2862 /* reset the row end pointer if we're inserting at the end of the list */
2863 if (row == clist->rows)
2864 clist->row_list_end = (g_list_append (clist->row_list_end,
2867 clist->row_list = g_list_insert (clist->row_list, clist_row, row);
2872 if (row < ROW_FROM_YPIXEL (clist, 0))
2873 clist->voffset -= (clist->row_height + CELL_SPACING);
2875 /* syncronize the selection list */
2876 sync_selection (clist, row, SYNC_INSERT);
2878 if (clist->rows == 1)
2880 clist->focus_row = 0;
2881 if (clist->selection_mode == GTK_SELECTION_BROWSE)
2882 gtk_cmclist_select_row (clist, 0, -1);
2885 /* redraw the list if it isn't frozen */
2886 if (CLIST_UNFROZEN (clist))
2888 adjust_adjustments (clist, FALSE);
2890 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
2891 draw_rows (clist, NULL);
2898 real_remove_row (GtkCMCList *clist,
2903 GtkCMCListRow *clist_row;
2905 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2907 /* return if out of bounds */
2908 if (row < 0 || row > (clist->rows - 1))
2911 was_visible = (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE);
2913 /* get the row we're going to delete */
2914 list = ROW_ELEMENT (clist, row);
2915 g_assert (list != NULL);
2916 clist_row = list->data;
2918 /* if we're removing a selected row, we have to make sure
2919 * it's properly unselected, and then sync up the clist->selected
2920 * list to reflect the deincrimented indexies of rows after the
2922 if (clist_row->state == GTK_STATE_SELECTED)
2923 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
2926 sync_selection (clist, row, SYNC_REMOVE);
2928 /* reset the row end pointer if we're removing at the end of the list */
2930 if (clist->row_list == list)
2931 clist->row_list = g_list_next (list);
2932 if (clist->row_list_end == list)
2933 clist->row_list_end = g_list_previous (list);
2934 list = g_list_remove (list, clist_row);
2936 if (row < ROW_FROM_YPIXEL (clist, 0))
2937 clist->voffset += clist->row_height + CELL_SPACING;
2939 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
2940 clist->focus_row >= 0)
2941 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
2942 clist->focus_row, -1, NULL);
2945 row_delete (clist, clist_row);
2947 /* redraw the row if it isn't frozen */
2948 if (CLIST_UNFROZEN (clist))
2950 adjust_adjustments (clist, FALSE);
2953 draw_rows (clist, NULL);
2958 real_clear (GtkCMCList *clist)
2962 GtkRequisition requisition;
2965 cm_return_if_fail (GTK_IS_CMCLIST (clist));
2967 /* free up the selection list */
2968 g_list_free (clist->selection);
2969 g_list_free (clist->undo_selection);
2970 g_list_free (clist->undo_unselection);
2972 clist->selection = NULL;
2973 clist->selection_end = NULL;
2974 clist->undo_selection = NULL;
2975 clist->undo_unselection = NULL;
2977 clist->focus_row = -1;
2979 clist->undo_anchor = -1;
2980 clist->anchor_state = GTK_STATE_SELECTED;
2981 clist->drag_pos = -1;
2983 /* remove all the rows */
2984 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
2985 free_list = clist->row_list;
2986 clist->row_list = NULL;
2987 clist->row_list_end = NULL;
2989 for (list = free_list; list; list = list->next)
2990 row_delete (clist, GTK_CMCLIST_ROW (list));
2991 g_list_free (free_list);
2992 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
2993 for (i = 0; i < clist->columns; i++)
2994 if (clist->column[i].auto_resize)
2996 if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button)
2998 gtk_widget_get_requisition (clist->column[i].button, &requisition);
2999 gtk_cmclist_set_column_width
3000 (clist, i, (requisition.width -
3001 (CELL_SPACING + (2 * COLUMN_INSET))));
3004 gtk_cmclist_set_column_width (clist, i, 0);
3006 /* zero-out the scrollbars */
3007 if (clist->vadjustment)
3009 gtk_adjustment_set_value (clist->vadjustment, 0.0);
3010 CLIST_REFRESH (clist);
3013 gtk_widget_queue_resize (GTK_WIDGET (clist));
3017 real_row_move (GtkCMCList *clist,
3021 GtkCMCListRow *clist_row;
3026 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3028 if (GTK_CMCLIST_AUTO_SORT(clist))
3031 if (source_row < 0 || source_row >= clist->rows ||
3032 dest_row < 0 || dest_row >= clist->rows ||
3033 source_row == dest_row)
3036 gtk_cmclist_freeze (clist);
3038 /* unlink source row */
3039 clist_row = ROW_ELEMENT (clist, source_row)->data;
3040 if (source_row == clist->rows - 1)
3041 clist->row_list_end = clist->row_list_end->prev;
3042 clist->row_list = g_list_remove (clist->row_list, clist_row);
3045 /* relink source row */
3046 clist->row_list = g_list_insert (clist->row_list, clist_row, dest_row);
3047 if (dest_row == clist->rows)
3048 clist->row_list_end = clist->row_list_end->next;
3051 /* sync selection */
3052 if (source_row > dest_row)
3065 for (list = clist->selection; list; list = list->next)
3067 if (list->data == GINT_TO_POINTER (source_row))
3068 list->data = GINT_TO_POINTER (dest_row);
3069 else if (first <= GPOINTER_TO_INT (list->data) &&
3070 last >= GPOINTER_TO_INT (list->data))
3071 list->data = GINT_TO_POINTER (GPOINTER_TO_INT (list->data) + d);
3074 if (clist->focus_row == source_row)
3075 clist->focus_row = dest_row;
3076 else if (clist->focus_row > first)
3077 clist->focus_row += d;
3079 gtk_cmclist_thaw (clist);
3082 /* PUBLIC ROW FUNCTIONS
3083 * gtk_cmclist_moveto
3084 * gtk_cmclist_set_row_height
3085 * gtk_cmclist_set_row_data
3086 * gtk_cmclist_set_row_data_full
3087 * gtk_cmclist_get_row_data
3088 * gtk_cmclist_find_row_from_data
3089 * gtk_cmclist_swap_rows
3090 * gtk_cmclist_row_move
3091 * gtk_cmclist_row_is_visible
3092 * gtk_cmclist_set_foreground
3093 * gtk_cmclist_set_background
3096 gtk_cmclist_moveto (GtkCMCList *clist,
3102 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3104 if (row < -1 || row >= clist->rows)
3106 if (column < -1 || column >= clist->columns)
3109 row_align = CLAMP (row_align, 0, 1);
3110 col_align = CLAMP (col_align, 0, 1);
3112 /* adjust horizontal scrollbar */
3113 if (clist->hadjustment && column >= 0)
3117 x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET -
3118 (col_align * (clist->clist_window_width - 2 * COLUMN_INSET -
3119 CELL_SPACING - clist->column[column].area.width)));
3121 gtk_adjustment_set_value (clist->hadjustment, 0.0);
3122 else if (x > LIST_WIDTH (clist) - clist->clist_window_width)
3123 gtk_adjustment_set_value
3124 (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width);
3126 gtk_adjustment_set_value (clist->hadjustment, x);
3129 /* adjust vertical scrollbar */
3130 if (clist->vadjustment && row >= 0)
3131 move_vertical (clist, row, row_align);
3135 gtk_cmclist_set_row_height (GtkCMCList *clist,
3141 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3143 widget = GTK_WIDGET (clist);
3145 style = gtk_widget_get_style (widget);
3149 clist->row_height = height;
3150 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET);
3154 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET);
3155 clist->row_height = 0;
3158 if (style->font_desc)
3160 PangoContext *context = gtk_widget_get_pango_context (widget);
3161 PangoFontMetrics *metrics;
3163 metrics = pango_context_get_metrics (context,
3165 pango_context_get_language (context));
3167 if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist))
3169 clist->row_height = (pango_font_metrics_get_ascent (metrics) +
3170 pango_font_metrics_get_descent (metrics));
3171 clist->row_height = PANGO_PIXELS (clist->row_height) + 1;
3174 pango_font_metrics_unref (metrics);
3177 CLIST_REFRESH (clist);
3181 gtk_cmclist_set_row_data (GtkCMCList *clist,
3185 gtk_cmclist_set_row_data_full (clist, row, data, NULL);
3189 gtk_cmclist_set_row_data_full (GtkCMCList *clist,
3192 GDestroyNotify destroy)
3194 GtkCMCListRow *clist_row;
3196 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3198 if (row < 0 || row > (clist->rows - 1))
3201 clist_row = ROW_ELEMENT (clist, row)->data;
3203 if (clist_row->destroy)
3204 clist_row->destroy (clist_row->data);
3206 clist_row->data = data;
3207 clist_row->destroy = destroy;
3211 gtk_cmclist_get_row_data (GtkCMCList *clist,
3214 GtkCMCListRow *clist_row;
3216 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3218 if (row < 0 || row > (clist->rows - 1))
3221 clist_row = ROW_ELEMENT (clist, row)->data;
3222 return clist_row->data;
3226 gtk_cmclist_find_row_from_data (GtkCMCList *clist,
3232 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), -1);
3234 for (n = 0, list = clist->row_list; list; n++, list = list->next)
3235 if (GTK_CMCLIST_ROW (list)->data == data)
3242 gtk_cmclist_swap_rows (GtkCMCList *clist,
3248 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3249 cm_return_if_fail (row1 != row2);
3251 if (GTK_CMCLIST_AUTO_SORT(clist))
3254 gtk_cmclist_freeze (clist);
3256 first = MIN (row1, row2);
3257 last = MAX (row1, row2);
3259 gtk_cmclist_row_move (clist, last, first);
3260 gtk_cmclist_row_move (clist, first + 1, last);
3262 gtk_cmclist_thaw (clist);
3266 gtk_cmclist_row_move (GtkCMCList *clist,
3270 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3272 if (GTK_CMCLIST_AUTO_SORT(clist))
3275 if (source_row < 0 || source_row >= clist->rows ||
3276 dest_row < 0 || dest_row >= clist->rows ||
3277 source_row == dest_row)
3280 g_signal_emit (G_OBJECT (clist), clist_signals[ROW_MOVE], 0,
3281 source_row, dest_row);
3285 gtk_cmclist_row_is_visible (GtkCMCList *clist,
3290 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), 0);
3292 if (row < 0 || row >= clist->rows)
3293 return GTK_VISIBILITY_NONE;
3295 if (clist->row_height == 0)
3296 return GTK_VISIBILITY_NONE;
3298 if (row < ROW_FROM_YPIXEL (clist, 0))
3299 return GTK_VISIBILITY_NONE;
3301 if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
3302 return GTK_VISIBILITY_NONE;
3304 top = ROW_TOP_YPIXEL (clist, row);
3307 || ((top + clist->row_height) >= clist->clist_window_height))
3308 return GTK_VISIBILITY_PARTIAL;
3310 return GTK_VISIBILITY_FULL;
3314 gtk_cmclist_set_foreground (GtkCMCList *clist,
3316 const GdkColor *color)
3318 GtkCMCListRow *clist_row;
3320 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3322 if (row < 0 || row >= clist->rows)
3325 clist_row = ROW_ELEMENT (clist, row)->data;
3329 clist_row->foreground = *color;
3330 clist_row->fg_set = TRUE;
3331 #if !GTK_CHECK_VERSION(3, 0, 0)
3332 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3333 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)),
3334 &clist_row->foreground, TRUE, TRUE);
3338 clist_row->fg_set = FALSE;
3340 if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3341 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3345 gtk_cmclist_set_background (GtkCMCList *clist,
3347 const GdkColor *color)
3349 GtkCMCListRow *clist_row;
3351 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3353 if (row < 0 || row >= clist->rows)
3356 clist_row = ROW_ELEMENT (clist, row)->data;
3360 clist_row->background = *color;
3361 clist_row->bg_set = TRUE;
3362 #if !GTK_CHECK_VERSION(3, 0, 0)
3363 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3364 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)),
3365 &clist_row->background, TRUE, TRUE);
3369 clist_row->bg_set = FALSE;
3371 if (CLIST_UNFROZEN (clist)
3372 && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE))
3373 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3376 /* PUBLIC ROW/CELL STYLE FUNCTIONS
3377 * gtk_cmclist_set_cell_style
3378 * gtk_cmclist_get_cell_style
3379 * gtk_cmclist_set_row_style
3380 * gtk_cmclist_get_row_style
3383 gtk_cmclist_set_cell_style (GtkCMCList *clist,
3388 GtkRequisition requisition = { 0 };
3389 GtkCMCListRow *clist_row;
3391 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3393 if (row < 0 || row >= clist->rows)
3395 if (column < 0 || column >= clist->columns)
3398 clist_row = ROW_ELEMENT (clist, row)->data;
3400 if (clist_row->cell[column].style == style)
3403 if (clist->column[column].auto_resize &&
3404 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3405 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
3406 column, &requisition);
3408 if (clist_row->cell[column].style)
3410 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3411 gtk_style_detach (clist_row->cell[column].style);
3412 g_object_unref (clist_row->cell[column].style);
3415 clist_row->cell[column].style = style;
3417 if (clist_row->cell[column].style)
3419 g_object_ref (clist_row->cell[column].style);
3421 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3422 clist_row->cell[column].style =
3423 gtk_style_attach (clist_row->cell[column].style,
3424 clist->clist_window);
3427 column_auto_resize (clist, clist_row, column, requisition.width);
3429 /* redraw the list if it's not frozen */
3430 if (CLIST_UNFROZEN (clist))
3432 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3433 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3438 gtk_cmclist_get_cell_style (GtkCMCList *clist,
3442 GtkCMCListRow *clist_row;
3444 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3446 if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns)
3449 clist_row = ROW_ELEMENT (clist, row)->data;
3451 return clist_row->cell[column].style;
3455 gtk_cmclist_set_row_style (GtkCMCList *clist,
3459 GtkRequisition requisition;
3460 GtkCMCListRow *clist_row;
3464 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3466 if (row < 0 || row >= clist->rows)
3469 clist_row = ROW_ELEMENT (clist, row)->data;
3471 if (clist_row->style == style)
3474 old_width = g_new (gint, clist->columns);
3476 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3478 for (i = 0; i < clist->columns; i++)
3479 if (clist->column[i].auto_resize)
3481 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
3483 old_width[i] = requisition.width;
3487 if (clist_row->style)
3489 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3490 gtk_style_detach (clist_row->style);
3491 g_object_unref (clist_row->style);
3494 clist_row->style = style;
3496 if (clist_row->style)
3498 g_object_ref (clist_row->style);
3500 if (gtk_widget_get_realized (GTK_WIDGET(clist)))
3501 clist_row->style = gtk_style_attach (clist_row->style,
3502 clist->clist_window);
3505 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3506 for (i = 0; i < clist->columns; i++)
3507 column_auto_resize (clist, clist_row, i, old_width[i]);
3511 /* redraw the list if it's not frozen */
3512 if (CLIST_UNFROZEN (clist))
3514 if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
3515 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row);
3520 gtk_cmclist_get_row_style (GtkCMCList *clist,
3523 GtkCMCListRow *clist_row;
3525 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL);
3527 if (row < 0 || row >= clist->rows)
3530 clist_row = ROW_ELEMENT (clist, row)->data;
3532 return clist_row->style;
3535 /* PUBLIC SELECTION FUNCTIONS
3536 * gtk_cmclist_set_selectable
3537 * gtk_cmclist_get_selectable
3538 * gtk_cmclist_select_row
3539 * gtk_cmclist_unselect_row
3540 * gtk_cmclist_select_all
3541 * gtk_cmclist_unselect_all
3542 * gtk_cmclist_undo_selection
3545 gtk_cmclist_set_selectable (GtkCMCList *clist,
3547 gboolean selectable)
3549 GtkCMCListRow *clist_row;
3551 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3553 if (row < 0 || row >= clist->rows)
3556 clist_row = ROW_ELEMENT (clist, row)->data;
3558 if (selectable == clist_row->selectable)
3561 clist_row->selectable = selectable;
3563 if (!selectable && clist_row->state == GTK_STATE_SELECTED)
3565 if (clist->anchor >= 0 &&
3566 clist->selection_mode == GTK_SELECTION_MULTIPLE)
3568 clist->drag_button = 0;
3569 remove_grab (clist);
3570 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3572 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,
3578 gtk_cmclist_get_selectable (GtkCMCList *clist,
3581 cm_return_val_if_fail (GTK_IS_CMCLIST (clist), FALSE);
3583 if (row < 0 || row >= clist->rows)
3586 return GTK_CMCLIST_ROW (ROW_ELEMENT (clist, row))->selectable;
3590 gtk_cmclist_select_row (GtkCMCList *clist,
3594 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3596 if (row < 0 || row >= clist->rows)
3598 if (column < -1 || column >= clist->columns)
3601 g_signal_emit (G_OBJECT (clist), clist_signals[SELECT_ROW], 0,
3606 gtk_cmclist_unselect_row (GtkCMCList *clist,
3610 cm_return_if_fail (GTK_IS_CMCLIST (clist));
3612 if (row < 0 || row >= clist->rows)
3614 if (column < -1 || column >= clist->columns)
3617 g_signal_emit (G_OBJECT (clist), clist_signals[UNSELECT_ROW], 0,