1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #undef GTK_DISABLE_DEPRECATED
29 #include <string.h> /* memset */
32 #include "gtklistitem.h"
34 #include "gtksignal.h"
36 #include "gtkmarshalers.h"
50 #define SCROLL_TIME 100
52 /*** GtkList Methods ***/
53 static void gtk_list_class_init (GtkListClass *klass);
54 static void gtk_list_init (GtkList *list);
55 static void gtk_list_set_arg (GtkObject *object,
58 static void gtk_list_get_arg (GtkObject *object,
61 /*** GtkObject Methods ***/
62 static void gtk_list_dispose (GObject *object);
64 /*** GtkWidget Methods ***/
65 static void gtk_list_size_request (GtkWidget *widget,
66 GtkRequisition *requisition);
67 static void gtk_list_size_allocate (GtkWidget *widget,
68 GtkAllocation *allocation);
69 static void gtk_list_realize (GtkWidget *widget);
70 static void gtk_list_unmap (GtkWidget *widget);
71 static void gtk_list_style_set (GtkWidget *widget,
72 GtkStyle *previous_style);
73 static gint gtk_list_motion_notify (GtkWidget *widget,
74 GdkEventMotion *event);
75 static gint gtk_list_button_press (GtkWidget *widget,
76 GdkEventButton *event);
77 static gint gtk_list_button_release (GtkWidget *widget,
78 GdkEventButton *event);
80 static gboolean gtk_list_focus (GtkWidget *widget,
81 GtkDirectionType direction);
83 /*** GtkContainer Methods ***/
84 static void gtk_list_add (GtkContainer *container,
86 static void gtk_list_remove (GtkContainer *container,
88 static void gtk_list_forall (GtkContainer *container,
89 gboolean include_internals,
91 gpointer callback_data);
92 static GtkType gtk_list_child_type (GtkContainer *container);
93 static void gtk_list_set_focus_child (GtkContainer *container,
96 /*** GtkList Private Functions ***/
97 static void gtk_list_move_focus_child (GtkList *list,
98 GtkScrollType scroll_type,
100 static gint gtk_list_horizontal_timeout (GtkWidget *list);
101 static gint gtk_list_vertical_timeout (GtkWidget *list);
102 static void gtk_list_remove_items_internal (GtkList *list,
106 /*** GtkList Selection Methods ***/
107 static void gtk_real_list_select_child (GtkList *list,
109 static void gtk_real_list_unselect_child (GtkList *list,
112 /*** GtkList Selection Functions ***/
113 static void gtk_list_set_anchor (GtkList *list,
116 GtkWidget *undo_focus_child);
117 static void gtk_list_fake_unselect_all (GtkList *list,
119 static void gtk_list_fake_toggle_row (GtkList *list,
121 static void gtk_list_update_extended_selection (GtkList *list,
123 static void gtk_list_reset_extended_selection (GtkList *list);
125 /*** GtkListItem Signal Functions ***/
126 static void gtk_list_signal_drag_begin (GtkWidget *widget,
127 GdkDragContext *context,
129 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
131 static void gtk_list_signal_select_all (GtkListItem *list_item,
133 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
135 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
137 static void gtk_list_signal_start_selection (GtkListItem *list_item,
139 static void gtk_list_signal_end_selection (GtkListItem *list_item,
141 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
142 GtkScrollType scroll_type,
144 gboolean auto_start_selection,
146 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
147 GtkScrollType scroll_type,
150 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
151 GtkScrollType scroll_type,
154 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
156 static void gtk_list_signal_item_select (GtkListItem *list_item,
158 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
160 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
164 static void gtk_list_drag_begin (GtkWidget *widget,
165 GdkDragContext *context);
168 static GtkContainerClass *parent_class = NULL;
169 static guint list_signals[LAST_SIGNAL] = { 0 };
171 static const gchar vadjustment_key[] = "gtk-vadjustment";
172 static guint vadjustment_key_id = 0;
173 static const gchar hadjustment_key[] = "gtk-hadjustment";
174 static guint hadjustment_key_id = 0;
177 gtk_list_get_type (void)
179 static GtkType list_type = 0;
183 static const GtkTypeInfo list_info =
187 sizeof (GtkListClass),
188 (GtkClassInitFunc) gtk_list_class_init,
189 (GtkObjectInitFunc) gtk_list_init,
190 /* reserved_1 */ NULL,
191 /* reserved_2 */ NULL,
192 (GtkClassInitFunc) NULL,
195 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
202 gtk_list_class_init (GtkListClass *class)
204 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
205 GtkObjectClass *object_class;
206 GtkWidgetClass *widget_class;
207 GtkContainerClass *container_class;
209 object_class = (GtkObjectClass*) class;
210 widget_class = (GtkWidgetClass*) class;
211 container_class = (GtkContainerClass*) class;
213 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
215 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
216 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
218 gobject_class->dispose = gtk_list_dispose;
221 object_class->set_arg = gtk_list_set_arg;
222 object_class->get_arg = gtk_list_get_arg;
224 widget_class->unmap = gtk_list_unmap;
225 widget_class->style_set = gtk_list_style_set;
226 widget_class->realize = gtk_list_realize;
227 widget_class->button_press_event = gtk_list_button_press;
228 widget_class->button_release_event = gtk_list_button_release;
229 widget_class->motion_notify_event = gtk_list_motion_notify;
230 widget_class->size_request = gtk_list_size_request;
231 widget_class->size_allocate = gtk_list_size_allocate;
232 widget_class->drag_begin = gtk_list_drag_begin;
233 widget_class->focus = gtk_list_focus;
235 container_class->add = gtk_list_add;
236 container_class->remove = gtk_list_remove;
237 container_class->forall = gtk_list_forall;
238 container_class->child_type = gtk_list_child_type;
239 container_class->set_focus_child = gtk_list_set_focus_child;
241 class->selection_changed = NULL;
242 class->select_child = gtk_real_list_select_child;
243 class->unselect_child = gtk_real_list_unselect_child;
245 list_signals[SELECTION_CHANGED] =
246 gtk_signal_new ("selection_changed",
248 GTK_CLASS_TYPE (object_class),
249 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
250 _gtk_marshal_VOID__VOID,
252 list_signals[SELECT_CHILD] =
253 gtk_signal_new ("select_child",
255 GTK_CLASS_TYPE (object_class),
256 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
257 _gtk_marshal_VOID__OBJECT,
260 list_signals[UNSELECT_CHILD] =
261 gtk_signal_new ("unselect_child",
263 GTK_CLASS_TYPE (object_class),
264 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
265 _gtk_marshal_VOID__OBJECT,
269 gtk_object_add_arg_type ("GtkList::selection_mode",
270 GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
275 gtk_list_init (GtkList *list)
277 list->children = NULL;
278 list->selection = NULL;
280 list->undo_selection = NULL;
281 list->undo_unselection = NULL;
283 list->last_focus_child = NULL;
284 list->undo_focus_child = NULL;
291 list->anchor_state = GTK_STATE_SELECTED;
293 list->selection_mode = GTK_SELECTION_SINGLE;
294 list->drag_selection = FALSE;
295 list->add_mode = FALSE;
299 gtk_list_set_arg (GtkObject *object,
303 GtkList *list = GTK_LIST (object);
307 case ARG_SELECTION_MODE:
308 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
314 gtk_list_get_arg (GtkObject *object,
318 GtkList *list = GTK_LIST (object);
322 case ARG_SELECTION_MODE:
323 GTK_VALUE_ENUM (*arg) = list->selection_mode;
326 arg->type = GTK_TYPE_INVALID;
334 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
338 /* Private GtkObject Methods :
343 gtk_list_dispose (GObject *object)
345 gtk_list_clear_items (GTK_LIST (object), 0, -1);
347 G_OBJECT_CLASS (parent_class)->dispose (object);
351 /* Private GtkWidget Methods :
353 * gtk_list_size_request
354 * gtk_list_size_allocate
357 * gtk_list_motion_notify
358 * gtk_list_button_press
359 * gtk_list_button_release
362 gtk_list_size_request (GtkWidget *widget,
363 GtkRequisition *requisition)
369 g_return_if_fail (GTK_IS_LIST (widget));
370 g_return_if_fail (requisition != NULL);
372 list = GTK_LIST (widget);
373 requisition->width = 0;
374 requisition->height = 0;
376 children = list->children;
379 child = children->data;
380 children = children->next;
382 if (GTK_WIDGET_VISIBLE (child))
384 GtkRequisition child_requisition;
386 gtk_widget_size_request (child, &child_requisition);
388 requisition->width = MAX (requisition->width,
389 child_requisition.width);
390 requisition->height += child_requisition.height;
394 requisition->width += GTK_CONTAINER (list)->border_width * 2;
395 requisition->height += GTK_CONTAINER (list)->border_width * 2;
397 requisition->width = MAX (requisition->width, 1);
398 requisition->height = MAX (requisition->height, 1);
402 gtk_list_size_allocate (GtkWidget *widget,
403 GtkAllocation *allocation)
407 GtkAllocation child_allocation;
410 g_return_if_fail (GTK_IS_LIST (widget));
411 g_return_if_fail (allocation != NULL);
413 list = GTK_LIST (widget);
415 widget->allocation = *allocation;
416 if (GTK_WIDGET_REALIZED (widget))
417 gdk_window_move_resize (widget->window,
418 allocation->x, allocation->y,
419 allocation->width, allocation->height);
423 child_allocation.x = GTK_CONTAINER (list)->border_width;
424 child_allocation.y = GTK_CONTAINER (list)->border_width;
425 child_allocation.width = MAX (1, (gint)allocation->width -
426 child_allocation.x * 2);
428 children = list->children;
432 child = children->data;
433 children = children->next;
435 if (GTK_WIDGET_VISIBLE (child))
437 GtkRequisition child_requisition;
438 gtk_widget_get_child_requisition (child, &child_requisition);
440 child_allocation.height = child_requisition.height;
442 gtk_widget_size_allocate (child, &child_allocation);
444 child_allocation.y += child_allocation.height;
451 gtk_list_realize (GtkWidget *widget)
453 GdkWindowAttr attributes;
454 gint attributes_mask;
456 g_return_if_fail (GTK_IS_LIST (widget));
458 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
460 attributes.window_type = GDK_WINDOW_CHILD;
461 attributes.x = widget->allocation.x;
462 attributes.y = widget->allocation.y;
463 attributes.width = widget->allocation.width;
464 attributes.height = widget->allocation.height;
465 attributes.wclass = GDK_INPUT_OUTPUT;
466 attributes.visual = gtk_widget_get_visual (widget);
467 attributes.colormap = gtk_widget_get_colormap (widget);
468 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
470 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
472 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
473 &attributes, attributes_mask);
474 gdk_window_set_user_data (widget->window, widget);
476 widget->style = gtk_style_attach (widget->style, widget->window);
477 gdk_window_set_background (widget->window,
478 &widget->style->base[GTK_STATE_NORMAL]);
482 list_has_grab (GtkList *list)
484 return (GTK_WIDGET_HAS_GRAB (list) &&
485 gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (list))));
490 gtk_list_unmap (GtkWidget *widget)
494 g_return_if_fail (GTK_IS_LIST (widget));
496 if (!GTK_WIDGET_MAPPED (widget))
499 list = GTK_LIST (widget);
501 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
503 if (list_has_grab (list))
505 gtk_list_end_drag_selection (list);
507 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_MULTIPLE)
508 gtk_list_end_selection (list);
511 gdk_window_hide (widget->window);
515 gtk_list_motion_notify (GtkWidget *widget,
516 GdkEventMotion *event)
519 GtkWidget *item = NULL;
521 GtkContainer *container;
529 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
530 g_return_val_if_fail (event != NULL, FALSE);
532 list = GTK_LIST (widget);
534 if (!list->drag_selection || !list->children)
537 container = GTK_CONTAINER (widget);
539 if (event->is_hint || event->window != widget->window)
540 gdk_window_get_pointer (widget->window, &x, &y, NULL);
547 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
549 /* horizontal autoscrolling */
550 if (adj && widget->allocation.width > adj->page_size &&
551 (x < adj->value || x >= adj->value + adj->page_size))
553 if (list->htimer == 0)
555 list->htimer = g_timeout_add
556 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
558 if (!((x < adj->value && adj->value <= 0) ||
559 (x > adj->value + adj->page_size &&
560 adj->value >= adj->upper - adj->page_size)))
565 value = adj->value + (x - adj->value) / 2 - 1;
567 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
569 gtk_adjustment_set_value (adj,
571 adj->upper - adj->page_size));
579 /* vertical autoscrolling */
580 for (work = list->children; work; length++, work = work->next)
584 item = GTK_WIDGET (work->data);
585 if (item->allocation.y > y ||
586 (item->allocation.y <= y &&
587 item->allocation.y + item->allocation.height > y))
591 if (work->data == container->focus_child)
598 if (list->vtimer != 0)
601 if (!((y < 0 && focus_row == 0) ||
602 (y > widget->allocation.height && focus_row >= length - 1)))
603 list->vtimer = g_timeout_add (SCROLL_TIME,
604 (GtkFunction) gtk_list_vertical_timeout,
607 if (row != focus_row)
608 gtk_widget_grab_focus (item);
610 switch (list->selection_mode)
612 case GTK_SELECTION_BROWSE:
613 gtk_list_select_child (list, item);
615 case GTK_SELECTION_MULTIPLE:
616 gtk_list_update_extended_selection (list, row);
626 gtk_list_button_press (GtkWidget *widget,
627 GdkEventButton *event)
632 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
633 g_return_val_if_fail (event != NULL, FALSE);
635 if (event->button != 1)
638 list = GTK_LIST (widget);
639 item = gtk_get_event_widget ((GdkEvent*) event);
641 while (item && !GTK_IS_LIST_ITEM (item))
644 if (item && (item->parent == widget))
649 if (event->type == GDK_BUTTON_PRESS)
651 gtk_grab_add (widget);
652 list->drag_selection = TRUE;
654 else if (list_has_grab (list))
655 gtk_list_end_drag_selection (list);
657 if (!GTK_WIDGET_HAS_FOCUS(item))
658 gtk_widget_grab_focus (item);
662 list->add_mode = FALSE;
663 gtk_widget_queue_draw (item);
666 switch (list->selection_mode)
668 case GTK_SELECTION_SINGLE:
669 if (event->type != GDK_BUTTON_PRESS)
670 gtk_list_select_child (list, item);
672 list->undo_focus_child = item;
675 case GTK_SELECTION_BROWSE:
678 case GTK_SELECTION_MULTIPLE:
679 focus_row = g_list_index (list->children, item);
681 if (list->last_focus_child)
682 last_focus_row = g_list_index (list->children,
683 list->last_focus_child);
686 last_focus_row = focus_row;
687 list->last_focus_child = item;
690 if (event->type != GDK_BUTTON_PRESS)
692 if (list->anchor >= 0)
694 gtk_list_update_extended_selection (list, focus_row);
695 gtk_list_end_selection (list);
697 gtk_list_select_child (list, item);
701 if (event->state & GDK_CONTROL_MASK)
703 if (event->state & GDK_SHIFT_MASK)
705 if (list->anchor < 0)
707 g_list_free (list->undo_selection);
708 g_list_free (list->undo_unselection);
709 list->undo_selection = NULL;
710 list->undo_unselection = NULL;
712 list->anchor = last_focus_row;
713 list->drag_pos = last_focus_row;
714 list->undo_focus_child = list->last_focus_child;
716 gtk_list_update_extended_selection (list, focus_row);
720 if (list->anchor < 0)
721 gtk_list_set_anchor (list, TRUE,
722 focus_row, list->last_focus_child);
724 gtk_list_update_extended_selection (list, focus_row);
729 if (event->state & GDK_SHIFT_MASK)
731 gtk_list_set_anchor (list, FALSE,
732 last_focus_row, list->last_focus_child);
733 gtk_list_update_extended_selection (list, focus_row);
737 if (list->anchor < 0)
738 gtk_list_set_anchor (list, FALSE, focus_row,
739 list->last_focus_child);
741 gtk_list_update_extended_selection (list, focus_row);
755 gtk_list_button_release (GtkWidget *widget,
756 GdkEventButton *event)
761 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
762 g_return_val_if_fail (event != NULL, FALSE);
764 list = GTK_LIST (widget);
766 /* we don't handle button 2 and 3 */
767 if (event->button != 1)
770 if (list->drag_selection)
772 gtk_list_end_drag_selection (list);
774 switch (list->selection_mode)
776 case GTK_SELECTION_MULTIPLE:
777 if (!(event->state & GDK_SHIFT_MASK))
778 gtk_list_end_selection (list);
781 case GTK_SELECTION_SINGLE:
783 item = gtk_get_event_widget ((GdkEvent*) event);
785 while (item && !GTK_IS_LIST_ITEM (item))
788 if (item && item->parent == widget)
790 if (list->undo_focus_child == item)
791 gtk_list_toggle_row (list, item);
793 list->undo_focus_child = NULL;
807 gtk_list_style_set (GtkWidget *widget,
808 GtkStyle *previous_style)
810 g_return_if_fail (widget != NULL);
812 if (previous_style && GTK_WIDGET_REALIZED (widget))
813 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
816 /* GtkContainer Methods :
820 * gtk_list_child_type
821 * gtk_list_set_focus_child
825 gtk_list_add (GtkContainer *container,
830 g_return_if_fail (GTK_IS_LIST (container));
831 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
833 item_list = g_list_alloc ();
834 item_list->data = widget;
836 gtk_list_append_items (GTK_LIST (container), item_list);
840 gtk_list_remove (GtkContainer *container,
845 g_return_if_fail (GTK_IS_LIST (container));
846 g_return_if_fail (widget != NULL);
847 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
849 item_list = g_list_alloc ();
850 item_list->data = widget;
852 gtk_list_remove_items (GTK_LIST (container), item_list);
854 g_list_free (item_list);
858 gtk_list_forall (GtkContainer *container,
859 gboolean include_internals,
860 GtkCallback callback,
861 gpointer callback_data)
867 g_return_if_fail (GTK_IS_LIST (container));
868 g_return_if_fail (callback != NULL);
870 list = GTK_LIST (container);
871 children = list->children;
875 child = children->data;
876 children = children->next;
878 (* callback) (child, callback_data);
883 gtk_list_child_type (GtkContainer *container)
885 return GTK_TYPE_LIST_ITEM;
889 gtk_list_set_focus_child (GtkContainer *container,
894 g_return_if_fail (GTK_IS_LIST (container));
897 g_return_if_fail (GTK_IS_WIDGET (child));
899 list = GTK_LIST (container);
901 if (child != container->focus_child)
903 if (container->focus_child)
905 list->last_focus_child = container->focus_child;
906 gtk_widget_unref (container->focus_child);
908 container->focus_child = child;
909 if (container->focus_child)
910 gtk_widget_ref (container->focus_child);
913 /* check for v adjustment */
914 if (container->focus_child)
916 GtkAdjustment *adjustment;
918 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
921 gtk_adjustment_clamp_page (adjustment,
922 container->focus_child->allocation.y,
923 (container->focus_child->allocation.y +
924 container->focus_child->allocation.height));
925 switch (list->selection_mode)
927 case GTK_SELECTION_BROWSE:
928 gtk_list_select_child (list, child);
930 case GTK_SELECTION_MULTIPLE:
931 if (!list->last_focus_child && !list->add_mode)
933 list->undo_focus_child = list->last_focus_child;
934 gtk_list_unselect_all (list);
935 gtk_list_select_child (list, child);
945 gtk_list_focus (GtkWidget *widget,
946 GtkDirectionType direction)
948 gint return_val = FALSE;
949 GtkContainer *container;
951 container = GTK_CONTAINER (widget);
953 if (container->focus_child == NULL ||
954 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
956 if (GTK_LIST (container)->last_focus_child)
957 gtk_container_set_focus_child
958 (container, GTK_LIST (container)->last_focus_child);
960 if (GTK_WIDGET_CLASS (parent_class)->focus)
961 return_val = GTK_WIDGET_CLASS (parent_class)->focus (widget,
969 list = GTK_LIST (container);
970 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
971 gtk_list_end_selection (list);
973 if (container->focus_child)
974 list->last_focus_child = container->focus_child;
981 /* Public GtkList Methods :
983 * gtk_list_insert_items
984 * gtk_list_append_items
985 * gtk_list_prepend_items
986 * gtk_list_remove_items
987 * gtk_list_remove_items_no_unref
988 * gtk_list_clear_items
990 * gtk_list_child_position
993 gtk_list_insert_items (GtkList *list,
1002 g_return_if_fail (GTK_IS_LIST (list));
1007 gtk_list_end_drag_selection (list);
1008 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1009 gtk_list_end_selection (list);
1014 widget = tmp_list->data;
1015 tmp_list = tmp_list->next;
1017 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1018 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1019 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1021 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1022 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1024 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1025 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1027 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1028 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1030 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1031 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1033 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1034 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1036 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1037 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1039 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1040 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1042 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1043 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1045 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1046 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1048 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1049 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1051 gtk_signal_connect (GTK_OBJECT (widget), "select",
1052 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1054 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1055 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1057 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1058 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1063 nchildren = g_list_length (list->children);
1064 if ((position < 0) || (position > nchildren))
1065 position = nchildren;
1067 if (position == nchildren)
1071 tmp_list = g_list_last (list->children);
1072 tmp_list->next = items;
1073 items->prev = tmp_list;
1077 list->children = items;
1082 tmp_list = g_list_nth (list->children, position);
1083 last = g_list_last (items);
1086 tmp_list->prev->next = items;
1087 last->next = tmp_list;
1088 items->prev = tmp_list->prev;
1089 tmp_list->prev = last;
1091 if (tmp_list == list->children)
1092 list->children = items;
1095 if (list->children && !list->selection &&
1096 (list->selection_mode == GTK_SELECTION_BROWSE))
1098 widget = list->children->data;
1099 gtk_list_select_child (list, widget);
1104 gtk_list_append_items (GtkList *list,
1107 g_return_if_fail (GTK_IS_LIST (list));
1109 gtk_list_insert_items (list, items, -1);
1113 gtk_list_prepend_items (GtkList *list,
1116 g_return_if_fail (GTK_IS_LIST (list));
1118 gtk_list_insert_items (list, items, 0);
1122 gtk_list_remove_items (GtkList *list,
1125 gtk_list_remove_items_internal (list, items, FALSE);
1129 gtk_list_remove_items_no_unref (GtkList *list,
1132 gtk_list_remove_items_internal (list, items, TRUE);
1136 gtk_list_clear_items (GtkList *list,
1140 GtkContainer *container;
1142 GtkWidget *new_focus_child = NULL;
1147 gboolean grab_focus = FALSE;
1149 g_return_if_fail (GTK_IS_LIST (list));
1151 nchildren = g_list_length (list->children);
1156 if ((end < 0) || (end > nchildren))
1162 container = GTK_CONTAINER (list);
1164 gtk_list_end_drag_selection (list);
1165 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1167 if (list->anchor >= 0)
1168 gtk_list_end_selection (list);
1170 gtk_list_reset_extended_selection (list);
1173 start_list = g_list_nth (list->children, start);
1174 end_list = g_list_nth (list->children, end);
1176 if (start_list->prev)
1177 start_list->prev->next = end_list;
1178 if (end_list && end_list->prev)
1179 end_list->prev->next = NULL;
1181 end_list->prev = start_list->prev;
1182 if (start_list == list->children)
1183 list->children = end_list;
1185 if (container->focus_child)
1187 if (g_list_find (start_list, container->focus_child))
1189 if (start_list->prev)
1190 new_focus_child = start_list->prev->data;
1191 else if (list->children)
1192 new_focus_child = list->children->data;
1194 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1199 tmp_list = start_list;
1202 widget = tmp_list->data;
1203 tmp_list = tmp_list->next;
1205 gtk_widget_ref (widget);
1207 if (widget->state == GTK_STATE_SELECTED)
1208 gtk_list_unselect_child (list, widget);
1210 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1211 gtk_widget_unparent (widget);
1213 if (widget == list->undo_focus_child)
1214 list->undo_focus_child = NULL;
1215 if (widget == list->last_focus_child)
1216 list->last_focus_child = NULL;
1218 gtk_widget_unref (widget);
1221 g_list_free (start_list);
1223 if (new_focus_child)
1226 gtk_widget_grab_focus (new_focus_child);
1227 else if (container->focus_child)
1228 gtk_container_set_focus_child (container, new_focus_child);
1230 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1231 list->selection_mode == GTK_SELECTION_MULTIPLE) && !list->selection)
1233 list->last_focus_child = new_focus_child;
1234 gtk_list_select_child (list, new_focus_child);
1238 if (GTK_WIDGET_VISIBLE (list))
1239 gtk_widget_queue_resize (GTK_WIDGET (list));
1243 gtk_list_child_position (GtkList *list,
1249 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1250 g_return_val_if_fail (child != NULL, -1);
1253 children = list->children;
1257 if (child == GTK_WIDGET (children->data))
1261 children = children->next;
1268 /* Private GtkList Insert/Remove Item Functions:
1270 * gtk_list_remove_items_internal
1273 gtk_list_remove_items_internal (GtkList *list,
1278 GtkWidget *new_focus_child;
1279 GtkWidget *old_focus_child;
1280 GtkContainer *container;
1283 gboolean grab_focus = FALSE;
1285 g_return_if_fail (GTK_IS_LIST (list));
1290 container = GTK_CONTAINER (list);
1292 gtk_list_end_drag_selection (list);
1293 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1295 if (list->anchor >= 0)
1296 gtk_list_end_selection (list);
1298 gtk_list_reset_extended_selection (list);
1304 widget = tmp_list->data;
1305 tmp_list = tmp_list->next;
1307 if (widget->state == GTK_STATE_SELECTED)
1308 gtk_list_unselect_child (list, widget);
1311 if (container->focus_child)
1313 old_focus_child = new_focus_child = container->focus_child;
1314 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1318 old_focus_child = new_focus_child = list->last_focus_child;
1323 widget = tmp_list->data;
1324 tmp_list = tmp_list->next;
1326 gtk_widget_ref (widget);
1328 gtk_widget_ref (widget);
1330 if (widget == new_focus_child)
1332 work = g_list_find (list->children, widget);
1337 new_focus_child = work->next->data;
1338 else if (list->children != work && work->prev)
1339 new_focus_child = work->prev->data;
1341 new_focus_child = NULL;
1345 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1346 list->children = g_list_remove (list->children, widget);
1347 gtk_widget_unparent (widget);
1349 if (widget == list->undo_focus_child)
1350 list->undo_focus_child = NULL;
1351 if (widget == list->last_focus_child)
1352 list->last_focus_child = NULL;
1354 gtk_widget_unref (widget);
1357 if (new_focus_child && new_focus_child != old_focus_child)
1360 gtk_widget_grab_focus (new_focus_child);
1361 else if (container->focus_child)
1362 gtk_container_set_focus_child (container, new_focus_child);
1364 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1366 list->last_focus_child = new_focus_child;
1367 gtk_list_select_child (list, new_focus_child);
1371 if (GTK_WIDGET_VISIBLE (list))
1372 gtk_widget_queue_resize (GTK_WIDGET (list));
1376 /* Public GtkList Selection Methods :
1378 * gtk_list_set_selection_mode
1379 * gtk_list_select_item
1380 * gtk_list_unselect_item
1381 * gtk_list_select_child
1382 * gtk_list_unselect_child
1383 * gtk_list_select_all
1384 * gtk_list_unselect_all
1385 * gtk_list_extend_selection
1386 * gtk_list_end_drag_selection
1387 * gtk_list_start_selection
1388 * gtk_list_end_selection
1389 * gtk_list_toggle_row
1390 * gtk_list_toggle_focus_row
1391 * gtk_list_toggle_add_mode
1392 * gtk_list_undo_selection
1395 gtk_list_set_selection_mode (GtkList *list,
1396 GtkSelectionMode mode)
1398 g_return_if_fail (GTK_IS_LIST (list));
1400 if (list->selection_mode == mode)
1403 list->selection_mode = mode;
1407 case GTK_SELECTION_SINGLE:
1408 case GTK_SELECTION_BROWSE:
1409 gtk_list_unselect_all (list);
1417 gtk_list_select_item (GtkList *list,
1422 g_return_if_fail (GTK_IS_LIST (list));
1424 tmp_list = g_list_nth (list->children, item);
1426 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1430 gtk_list_unselect_item (GtkList *list,
1435 g_return_if_fail (GTK_IS_LIST (list));
1437 tmp_list = g_list_nth (list->children, item);
1439 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1443 gtk_list_select_child (GtkList *list,
1446 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1450 gtk_list_unselect_child (GtkList *list,
1453 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1457 gtk_list_select_all (GtkList *list)
1459 GtkContainer *container;
1461 g_return_if_fail (GTK_IS_LIST (list));
1463 if (!list->children)
1466 if (list_has_grab (list))
1467 gtk_list_end_drag_selection (list);
1469 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1470 gtk_list_end_selection (list);
1472 container = GTK_CONTAINER (list);
1474 switch (list->selection_mode)
1476 case GTK_SELECTION_BROWSE:
1477 if (container->focus_child)
1479 gtk_list_select_child (list, container->focus_child);
1483 case GTK_SELECTION_MULTIPLE:
1484 g_list_free (list->undo_selection);
1485 g_list_free (list->undo_unselection);
1486 list->undo_selection = NULL;
1487 list->undo_unselection = NULL;
1489 if (list->children &&
1490 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1491 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1493 list->anchor_state = GTK_STATE_SELECTED;
1496 list->undo_focus_child = container->focus_child;
1497 gtk_list_update_extended_selection (list, g_list_length(list->children));
1498 gtk_list_end_selection (list);
1506 gtk_list_unselect_all (GtkList *list)
1508 GtkContainer *container;
1512 g_return_if_fail (GTK_IS_LIST (list));
1514 if (!list->children)
1517 if (list_has_grab (list))
1518 gtk_list_end_drag_selection (list);
1520 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1521 gtk_list_end_selection (list);
1523 container = GTK_CONTAINER (list);
1525 switch (list->selection_mode)
1527 case GTK_SELECTION_BROWSE:
1528 if (container->focus_child)
1530 gtk_list_select_child (list, container->focus_child);
1534 case GTK_SELECTION_MULTIPLE:
1535 gtk_list_reset_extended_selection (list);
1541 work = list->selection;
1547 gtk_list_unselect_child (list, item);
1552 gtk_list_extend_selection (GtkList *list,
1553 GtkScrollType scroll_type,
1555 gboolean auto_start_selection)
1557 GtkContainer *container;
1559 g_return_if_fail (GTK_IS_LIST (list));
1561 if (list_has_grab (list) ||
1562 list->selection_mode != GTK_SELECTION_MULTIPLE)
1565 container = GTK_CONTAINER (list);
1567 if (auto_start_selection)
1571 focus_row = g_list_index (list->children, container->focus_child);
1572 gtk_list_set_anchor (list, list->add_mode, focus_row,
1573 container->focus_child);
1575 else if (list->anchor < 0)
1578 gtk_list_move_focus_child (list, scroll_type, position);
1579 gtk_list_update_extended_selection
1580 (list, g_list_index (list->children, container->focus_child));
1584 gtk_list_end_drag_selection (GtkList *list)
1586 g_return_if_fail (GTK_IS_LIST (list));
1588 list->drag_selection = FALSE;
1589 if (GTK_WIDGET_HAS_GRAB (list))
1590 gtk_grab_remove (GTK_WIDGET (list));
1594 g_source_remove (list->htimer);
1599 g_source_remove (list->vtimer);
1605 gtk_list_start_selection (GtkList *list)
1607 GtkContainer *container;
1610 g_return_if_fail (GTK_IS_LIST (list));
1612 if (list_has_grab (list))
1615 container = GTK_CONTAINER (list);
1617 if ((focus_row = g_list_index (list->selection, container->focus_child))
1619 gtk_list_set_anchor (list, list->add_mode,
1620 focus_row, container->focus_child);
1624 gtk_list_end_selection (GtkList *list)
1633 g_return_if_fail (GTK_IS_LIST (list));
1635 if (list_has_grab (list) || list->anchor < 0)
1638 i = MIN (list->anchor, list->drag_pos);
1639 e = MAX (list->anchor, list->drag_pos);
1641 top_down = (list->anchor < list->drag_pos);
1644 list->drag_pos = -1;
1646 if (list->undo_selection)
1648 work = list->selection;
1649 list->selection = list->undo_selection;
1650 list->undo_selection = work;
1651 work = list->selection;
1656 item_index = g_list_index (list->children, item);
1657 if (item_index < i || item_index > e)
1659 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1660 gtk_list_unselect_child (list, item);
1661 list->undo_selection = g_list_prepend (list->undo_selection,
1669 for (work = g_list_nth (list->children, i); i <= e;
1670 i++, work = work->next)
1673 if (g_list_find (list->selection, item))
1675 if (item->state == GTK_STATE_NORMAL)
1677 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1678 gtk_list_unselect_child (list, item);
1679 list->undo_selection = g_list_prepend (list->undo_selection,
1683 else if (item->state == GTK_STATE_SELECTED)
1685 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1686 list->undo_unselection = g_list_prepend (list->undo_unselection,
1693 for (work = g_list_nth (list->children, e); i <= e;
1694 e--, work = work->prev)
1697 if (g_list_find (list->selection, item))
1699 if (item->state == GTK_STATE_NORMAL)
1701 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1702 gtk_list_unselect_child (list, item);
1703 list->undo_selection = g_list_prepend (list->undo_selection,
1707 else if (item->state == GTK_STATE_SELECTED)
1709 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1710 list->undo_unselection = g_list_prepend (list->undo_unselection,
1716 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1717 gtk_list_select_child (list, GTK_WIDGET (work->data));
1723 gtk_list_toggle_row (GtkList *list,
1726 g_return_if_fail (GTK_IS_LIST (list));
1727 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1729 switch (list->selection_mode)
1731 case GTK_SELECTION_MULTIPLE:
1732 case GTK_SELECTION_SINGLE:
1733 if (item->state == GTK_STATE_SELECTED)
1735 gtk_list_unselect_child (list, item);
1738 case GTK_SELECTION_BROWSE:
1739 gtk_list_select_child (list, item);
1745 gtk_list_toggle_focus_row (GtkList *list)
1747 GtkContainer *container;
1750 g_return_if_fail (list != 0);
1751 g_return_if_fail (GTK_IS_LIST (list));
1753 container = GTK_CONTAINER (list);
1755 if (list_has_grab (list) || !container->focus_child)
1758 switch (list->selection_mode)
1760 case GTK_SELECTION_SINGLE:
1761 gtk_list_toggle_row (list, container->focus_child);
1763 case GTK_SELECTION_MULTIPLE:
1764 if ((focus_row = g_list_index (list->children, container->focus_child))
1768 g_list_free (list->undo_selection);
1769 g_list_free (list->undo_unselection);
1770 list->undo_selection = NULL;
1771 list->undo_unselection = NULL;
1773 list->anchor = focus_row;
1774 list->drag_pos = focus_row;
1775 list->undo_focus_child = container->focus_child;
1778 gtk_list_fake_toggle_row (list, container->focus_child);
1780 gtk_list_fake_unselect_all (list, container->focus_child);
1782 gtk_list_end_selection (list);
1790 gtk_list_toggle_add_mode (GtkList *list)
1792 GtkContainer *container;
1794 g_return_if_fail (list != 0);
1795 g_return_if_fail (GTK_IS_LIST (list));
1797 if (list_has_grab (list) ||
1798 list->selection_mode != GTK_SELECTION_MULTIPLE)
1801 container = GTK_CONTAINER (list);
1805 list->add_mode = FALSE;
1806 list->anchor_state = GTK_STATE_SELECTED;
1809 list->add_mode = TRUE;
1811 if (container->focus_child)
1812 gtk_widget_queue_draw (container->focus_child);
1816 gtk_list_undo_selection (GtkList *list)
1820 g_return_if_fail (GTK_IS_LIST (list));
1822 if (list->selection_mode != GTK_SELECTION_MULTIPLE ||
1823 list_has_grab (list))
1826 if (list->anchor >= 0)
1827 gtk_list_end_selection (list);
1829 if (!(list->undo_selection || list->undo_unselection))
1831 gtk_list_unselect_all (list);
1835 for (work = list->undo_selection; work; work = work->next)
1836 gtk_list_select_child (list, GTK_WIDGET (work->data));
1838 for (work = list->undo_unselection; work; work = work->next)
1839 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1841 if (list->undo_focus_child)
1843 GtkContainer *container;
1845 container = GTK_CONTAINER (list);
1847 if (container->focus_child &&
1848 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1849 gtk_widget_grab_focus (list->undo_focus_child);
1851 gtk_container_set_focus_child (container, list->undo_focus_child);
1854 list->undo_focus_child = NULL;
1856 g_list_free (list->undo_selection);
1857 g_list_free (list->undo_unselection);
1858 list->undo_selection = NULL;
1859 list->undo_unselection = NULL;
1863 /* Private GtkList Selection Methods :
1865 * gtk_real_list_select_child
1866 * gtk_real_list_unselect_child
1869 gtk_real_list_select_child (GtkList *list,
1872 g_return_if_fail (GTK_IS_LIST (list));
1873 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1875 switch (child->state)
1877 case GTK_STATE_SELECTED:
1878 case GTK_STATE_INSENSITIVE:
1881 gtk_list_item_select (GTK_LIST_ITEM (child));
1887 gtk_real_list_unselect_child (GtkList *list,
1890 g_return_if_fail (GTK_IS_LIST (list));
1891 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1893 if (child->state == GTK_STATE_SELECTED)
1894 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1898 /* Private GtkList Selection Functions :
1900 * gtk_list_set_anchor
1901 * gtk_list_fake_unselect_all
1902 * gtk_list_fake_toggle_row
1903 * gtk_list_update_extended_selection
1904 * gtk_list_reset_extended_selection
1907 gtk_list_set_anchor (GtkList *list,
1910 GtkWidget *undo_focus_child)
1914 g_return_if_fail (GTK_IS_LIST (list));
1916 if (list->selection_mode != GTK_SELECTION_MULTIPLE || list->anchor >= 0)
1919 g_list_free (list->undo_selection);
1920 g_list_free (list->undo_unselection);
1921 list->undo_selection = NULL;
1922 list->undo_unselection = NULL;
1924 if ((work = g_list_nth (list->children, anchor)))
1927 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1930 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1931 list->anchor_state = GTK_STATE_SELECTED;
1935 list->anchor = anchor;
1936 list->drag_pos = anchor;
1937 list->undo_focus_child = undo_focus_child;
1941 gtk_list_fake_unselect_all (GtkList *list,
1946 if (item && item->state == GTK_STATE_NORMAL)
1947 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1949 list->undo_selection = list->selection;
1950 list->selection = NULL;
1952 for (work = list->undo_selection; work; work = work->next)
1953 if (work->data != item)
1954 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1958 gtk_list_fake_toggle_row (GtkList *list,
1964 if (item->state == GTK_STATE_NORMAL)
1966 list->anchor_state = GTK_STATE_SELECTED;
1967 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1971 list->anchor_state = GTK_STATE_NORMAL;
1972 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1977 gtk_list_update_extended_selection (GtkList *list,
1991 length = g_list_length (list->children);
1995 if (list->selection_mode != GTK_SELECTION_MULTIPLE || !list->anchor < 0)
1998 /* extending downwards */
1999 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2001 s2 = list->drag_pos + 1;
2004 /* extending upwards */
2005 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2008 e2 = list->drag_pos - 1;
2010 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2012 e1 = list->drag_pos;
2013 /* row and drag_pos on different sides of anchor :
2014 take back the selection between anchor and drag_pos,
2015 select between anchor and row */
2016 if (row < list->anchor)
2018 s1 = list->anchor + 1;
2020 e2 = list->anchor - 1;
2022 /* take back the selection between anchor and drag_pos */
2026 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2028 s1 = list->drag_pos;
2029 /* row and drag_pos on different sides of anchor :
2030 take back the selection between anchor and drag_pos,
2031 select between anchor and row */
2032 if (row > list->anchor)
2034 e1 = list->anchor - 1;
2035 s2 = list->anchor + 1;
2038 /* take back the selection between anchor and drag_pos */
2043 list->drag_pos = row;
2045 /* restore the elements between s1 and e1 */
2048 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2049 i++, work = work->next)
2051 if (g_list_find (list->selection, work->data))
2052 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2054 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2058 /* extend the selection between s2 and e2 */
2061 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2062 i++, work = work->next)
2063 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2064 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2069 gtk_list_reset_extended_selection (GtkList *list)
2071 g_return_if_fail (list != 0);
2072 g_return_if_fail (GTK_IS_LIST (list));
2074 g_list_free (list->undo_selection);
2075 g_list_free (list->undo_unselection);
2076 list->undo_selection = NULL;
2077 list->undo_unselection = NULL;
2080 list->drag_pos = -1;
2081 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2084 /* Public GtkList Scroll Methods :
2086 * gtk_list_scroll_horizontal
2087 * gtk_list_scroll_vertical
2090 gtk_list_scroll_horizontal (GtkList *list,
2091 GtkScrollType scroll_type,
2096 g_return_if_fail (list != 0);
2097 g_return_if_fail (GTK_IS_LIST (list));
2099 if (list_has_grab (list))
2103 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2106 switch (scroll_type)
2108 case GTK_SCROLL_STEP_UP:
2109 case GTK_SCROLL_STEP_BACKWARD:
2110 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2111 adj->upper - adj->page_size);
2113 case GTK_SCROLL_STEP_DOWN:
2114 case GTK_SCROLL_STEP_FORWARD:
2115 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2116 adj->upper - adj->page_size);
2118 case GTK_SCROLL_PAGE_UP:
2119 case GTK_SCROLL_PAGE_BACKWARD:
2120 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2121 adj->upper - adj->page_size);
2123 case GTK_SCROLL_PAGE_DOWN:
2124 case GTK_SCROLL_PAGE_FORWARD:
2125 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2126 adj->upper - adj->page_size);
2128 case GTK_SCROLL_JUMP:
2129 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2130 adj->lower, adj->upper - adj->page_size);
2135 gtk_adjustment_value_changed (adj);
2139 gtk_list_scroll_vertical (GtkList *list,
2140 GtkScrollType scroll_type,
2143 g_return_if_fail (GTK_IS_LIST (list));
2145 if (list_has_grab (list))
2148 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
2150 GtkContainer *container;
2152 if (list->anchor >= 0)
2155 container = GTK_CONTAINER (list);
2156 list->undo_focus_child = container->focus_child;
2157 gtk_list_move_focus_child (list, scroll_type, position);
2158 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2160 gtk_list_unselect_all (list);
2161 gtk_list_select_child (list, container->focus_child);
2165 gtk_list_move_focus_child (list, scroll_type, position);
2169 /* Private GtkList Scroll/Focus Functions :
2171 * gtk_list_move_focus_child
2172 * gtk_list_horizontal_timeout
2173 * gtk_list_vertical_timeout
2176 gtk_list_move_focus_child (GtkList *list,
2177 GtkScrollType scroll_type,
2180 GtkContainer *container;
2186 g_return_if_fail (list != 0);
2187 g_return_if_fail (GTK_IS_LIST (list));
2189 container = GTK_CONTAINER (list);
2191 if (container->focus_child)
2192 work = g_list_find (list->children, container->focus_child);
2194 work = list->children;
2199 switch (scroll_type)
2201 case GTK_SCROLL_STEP_BACKWARD:
2204 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2206 case GTK_SCROLL_STEP_FORWARD:
2209 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2211 case GTK_SCROLL_PAGE_BACKWARD:
2216 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2220 gboolean correct = FALSE;
2222 new_value = adj->value;
2224 if (item->allocation.y <= adj->value)
2226 new_value = MAX (item->allocation.y + item->allocation.height
2227 - adj->page_size, adj->lower);
2231 if (item->allocation.y > new_value)
2232 for (; work; work = work->prev)
2234 item = GTK_WIDGET (work->data);
2235 if (item->allocation.y <= new_value &&
2236 item->allocation.y + item->allocation.height > new_value)
2240 for (; work; work = work->next)
2242 item = GTK_WIDGET (work->data);
2243 if (item->allocation.y <= new_value &&
2244 item->allocation.y + item->allocation.height > new_value)
2248 if (correct && work && work->next && item->allocation.y < new_value)
2249 item = work->next->data;
2252 item = list->children->data;
2254 gtk_widget_grab_focus (item);
2256 case GTK_SCROLL_PAGE_FORWARD:
2261 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2265 gboolean correct = FALSE;
2267 new_value = adj->value;
2269 if (item->allocation.y + item->allocation.height >=
2270 adj->value + adj->page_size)
2272 new_value = item->allocation.y;
2276 new_value = MIN (new_value + adj->page_size, adj->upper);
2278 if (item->allocation.y > new_value)
2279 for (; work; work = work->prev)
2281 item = GTK_WIDGET (work->data);
2282 if (item->allocation.y <= new_value &&
2283 item->allocation.y + item->allocation.height > new_value)
2287 for (; work; work = work->next)
2289 item = GTK_WIDGET (work->data);
2290 if (item->allocation.y <= new_value &&
2291 item->allocation.y + item->allocation.height > new_value)
2295 if (correct && work && work->prev &&
2296 item->allocation.y + item->allocation.height - 1 > new_value)
2297 item = work->prev->data;
2300 item = g_list_last (work)->data;
2302 gtk_widget_grab_focus (item);
2304 case GTK_SCROLL_JUMP:
2305 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2307 for (item = NULL, work = list->children; work; work =work->next)
2309 item = GTK_WIDGET (work->data);
2310 if (item->allocation.y <= new_value &&
2311 item->allocation.y + item->allocation.height > new_value)
2315 gtk_widget_grab_focus (item);
2323 do_fake_motion (GtkWidget *list)
2325 GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
2327 event->motion.send_event = TRUE;
2329 gtk_list_motion_notify (list, (GdkEventMotion *)event);
2330 gdk_event_free (event);
2334 gtk_list_horizontal_timeout (GtkWidget *list)
2336 GDK_THREADS_ENTER ();
2338 GTK_LIST (list)->htimer = 0;
2339 do_fake_motion (list);
2341 GDK_THREADS_LEAVE ();
2347 gtk_list_vertical_timeout (GtkWidget *list)
2349 GDK_THREADS_ENTER ();
2351 GTK_LIST (list)->vtimer = 0;
2352 do_fake_motion (list);
2354 GDK_THREADS_LEAVE ();
2360 /* Private GtkListItem Signal Functions :
2362 * gtk_list_signal_toggle_focus_row
2363 * gtk_list_signal_select_all
2364 * gtk_list_signal_unselect_all
2365 * gtk_list_signal_undo_selection
2366 * gtk_list_signal_start_selection
2367 * gtk_list_signal_end_selection
2368 * gtk_list_signal_extend_selection
2369 * gtk_list_signal_scroll_horizontal
2370 * gtk_list_signal_scroll_vertical
2371 * gtk_list_signal_toggle_add_mode
2372 * gtk_list_signal_item_select
2373 * gtk_list_signal_item_deselect
2374 * gtk_list_signal_item_toggle
2377 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2380 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2381 g_return_if_fail (GTK_IS_LIST (list));
2383 gtk_list_toggle_focus_row (list);
2387 gtk_list_signal_select_all (GtkListItem *list_item,
2390 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2391 g_return_if_fail (GTK_IS_LIST (list));
2393 gtk_list_select_all (list);
2397 gtk_list_signal_unselect_all (GtkListItem *list_item,
2400 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2401 g_return_if_fail (GTK_IS_LIST (list));
2403 gtk_list_unselect_all (list);
2407 gtk_list_signal_undo_selection (GtkListItem *list_item,
2410 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2411 g_return_if_fail (GTK_IS_LIST (list));
2413 gtk_list_undo_selection (list);
2417 gtk_list_signal_start_selection (GtkListItem *list_item,
2420 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2421 g_return_if_fail (GTK_IS_LIST (list));
2423 gtk_list_start_selection (list);
2427 gtk_list_signal_end_selection (GtkListItem *list_item,
2430 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2431 g_return_if_fail (GTK_IS_LIST (list));
2433 gtk_list_end_selection (list);
2437 gtk_list_signal_extend_selection (GtkListItem *list_item,
2438 GtkScrollType scroll_type,
2440 gboolean auto_start_selection,
2443 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2444 g_return_if_fail (GTK_IS_LIST (list));
2446 gtk_list_extend_selection (list, scroll_type, position,
2447 auto_start_selection);
2451 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2452 GtkScrollType scroll_type,
2456 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2457 g_return_if_fail (GTK_IS_LIST (list));
2459 gtk_list_scroll_horizontal (list, scroll_type, position);
2463 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2464 GtkScrollType scroll_type,
2468 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2469 g_return_if_fail (GTK_IS_LIST (list));
2471 gtk_list_scroll_vertical (list, scroll_type, position);
2475 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2478 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2479 g_return_if_fail (GTK_IS_LIST (list));
2481 gtk_list_toggle_add_mode (list);
2485 gtk_list_signal_item_select (GtkListItem *list_item,
2492 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2493 g_return_if_fail (GTK_IS_LIST (list));
2495 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2498 switch (list->selection_mode)
2500 case GTK_SELECTION_SINGLE:
2501 case GTK_SELECTION_BROWSE:
2503 selection = list->selection;
2507 tmp_list = selection;
2508 selection = selection->next;
2510 if (tmp_list->data == list_item)
2511 sel_list = tmp_list;
2513 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2518 list->selection = g_list_prepend (list->selection, list_item);
2519 gtk_widget_ref (GTK_WIDGET (list_item));
2521 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2523 case GTK_SELECTION_MULTIPLE:
2524 if (list->anchor >= 0)
2530 gtk_list_signal_item_deselect (GtkListItem *list_item,
2535 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2536 g_return_if_fail (GTK_IS_LIST (list));
2538 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2541 node = g_list_find (list->selection, list_item);
2545 list->selection = g_list_remove_link (list->selection, node);
2546 g_list_free_1 (node);
2547 gtk_widget_unref (GTK_WIDGET (list_item));
2548 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2553 gtk_list_signal_item_toggle (GtkListItem *list_item,
2556 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2557 g_return_if_fail (GTK_IS_LIST (list));
2559 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
2560 list->selection_mode == GTK_SELECTION_MULTIPLE) &&
2561 GTK_WIDGET (list_item)->state == GTK_STATE_NORMAL)
2563 gtk_widget_set_state (GTK_WIDGET (list_item), GTK_STATE_SELECTED);
2567 switch (GTK_WIDGET (list_item)->state)
2569 case GTK_STATE_SELECTED:
2570 gtk_list_signal_item_select (list_item, list);
2572 case GTK_STATE_NORMAL:
2573 gtk_list_signal_item_deselect (list_item, list);
2581 gtk_list_signal_drag_begin (GtkWidget *widget,
2582 GdkDragContext *context,
2585 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2586 g_return_if_fail (GTK_IS_LIST (list));
2588 gtk_list_drag_begin (GTK_WIDGET (list), context);
2592 gtk_list_drag_begin (GtkWidget *widget,
2593 GdkDragContext *context)
2597 g_return_if_fail (GTK_IS_LIST (widget));
2598 g_return_if_fail (context != NULL);
2600 list = GTK_LIST (widget);
2602 if (list->drag_selection)
2604 gtk_list_end_drag_selection (list);
2606 switch (list->selection_mode)
2608 case GTK_SELECTION_MULTIPLE:
2609 gtk_list_end_selection (list);
2611 case GTK_SELECTION_SINGLE:
2612 list->undo_focus_child = NULL;