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 #include <string.h> /* memset */
30 #include "gtklistitem.h"
32 #include "gtksignal.h"
34 #include "gtkmarshalers.h"
48 #define SCROLL_TIME 100
50 /*** GtkList Methods ***/
51 static void gtk_list_class_init (GtkListClass *klass);
52 static void gtk_list_init (GtkList *list);
53 static void gtk_list_set_arg (GtkObject *object,
56 static void gtk_list_get_arg (GtkObject *object,
59 /*** GtkObject Methods ***/
60 static void gtk_list_dispose (GObject *object);
62 /*** GtkWidget Methods ***/
63 static void gtk_list_size_request (GtkWidget *widget,
64 GtkRequisition *requisition);
65 static void gtk_list_size_allocate (GtkWidget *widget,
66 GtkAllocation *allocation);
67 static void gtk_list_realize (GtkWidget *widget);
68 static void gtk_list_unmap (GtkWidget *widget);
69 static void gtk_list_style_set (GtkWidget *widget,
70 GtkStyle *previous_style);
71 static gint gtk_list_motion_notify (GtkWidget *widget,
72 GdkEventMotion *event);
73 static gint gtk_list_button_press (GtkWidget *widget,
74 GdkEventButton *event);
75 static gint gtk_list_button_release (GtkWidget *widget,
76 GdkEventButton *event);
78 static gboolean gtk_list_focus (GtkWidget *widget,
79 GtkDirectionType direction);
81 /*** GtkContainer Methods ***/
82 static void gtk_list_add (GtkContainer *container,
84 static void gtk_list_remove (GtkContainer *container,
86 static void gtk_list_forall (GtkContainer *container,
87 gboolean include_internals,
89 gpointer callback_data);
90 static GtkType gtk_list_child_type (GtkContainer *container);
91 static void gtk_list_set_focus_child (GtkContainer *container,
94 /*** GtkList Private Functions ***/
95 static void gtk_list_move_focus_child (GtkList *list,
96 GtkScrollType scroll_type,
98 static gint gtk_list_horizontal_timeout (GtkWidget *list);
99 static gint gtk_list_vertical_timeout (GtkWidget *list);
100 static void gtk_list_remove_items_internal (GtkList *list,
104 /*** GtkList Selection Methods ***/
105 static void gtk_real_list_select_child (GtkList *list,
107 static void gtk_real_list_unselect_child (GtkList *list,
110 /*** GtkList Selection Functions ***/
111 static void gtk_list_set_anchor (GtkList *list,
114 GtkWidget *undo_focus_child);
115 static void gtk_list_fake_unselect_all (GtkList *list,
117 static void gtk_list_fake_toggle_row (GtkList *list,
119 static void gtk_list_update_extended_selection (GtkList *list,
121 static void gtk_list_reset_extended_selection (GtkList *list);
123 /*** GtkListItem Signal Functions ***/
124 static void gtk_list_signal_drag_begin (GtkWidget *widget,
125 GdkDragContext *context,
127 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
129 static void gtk_list_signal_select_all (GtkListItem *list_item,
131 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
133 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
135 static void gtk_list_signal_start_selection (GtkListItem *list_item,
137 static void gtk_list_signal_end_selection (GtkListItem *list_item,
139 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
140 GtkScrollType scroll_type,
142 gboolean auto_start_selection,
144 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
145 GtkScrollType scroll_type,
148 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
149 GtkScrollType scroll_type,
152 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
154 static void gtk_list_signal_item_select (GtkListItem *list_item,
156 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
158 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
162 static void gtk_list_drag_begin (GtkWidget *widget,
163 GdkDragContext *context);
166 static GtkContainerClass *parent_class = NULL;
167 static guint list_signals[LAST_SIGNAL] = { 0 };
169 static const gchar *vadjustment_key = "gtk-vadjustment";
170 static guint vadjustment_key_id = 0;
171 static const gchar *hadjustment_key = "gtk-hadjustment";
172 static guint hadjustment_key_id = 0;
175 gtk_list_get_type (void)
177 static GtkType list_type = 0;
181 static const GtkTypeInfo list_info =
185 sizeof (GtkListClass),
186 (GtkClassInitFunc) gtk_list_class_init,
187 (GtkObjectInitFunc) gtk_list_init,
188 /* reserved_1 */ NULL,
189 /* reserved_2 */ NULL,
190 (GtkClassInitFunc) NULL,
193 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
200 gtk_list_class_init (GtkListClass *class)
202 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
203 GtkObjectClass *object_class;
204 GtkWidgetClass *widget_class;
205 GtkContainerClass *container_class;
207 object_class = (GtkObjectClass*) class;
208 widget_class = (GtkWidgetClass*) class;
209 container_class = (GtkContainerClass*) class;
211 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
213 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
214 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
216 gobject_class->dispose = gtk_list_dispose;
219 object_class->set_arg = gtk_list_set_arg;
220 object_class->get_arg = gtk_list_get_arg;
222 widget_class->unmap = gtk_list_unmap;
223 widget_class->style_set = gtk_list_style_set;
224 widget_class->realize = gtk_list_realize;
225 widget_class->button_press_event = gtk_list_button_press;
226 widget_class->button_release_event = gtk_list_button_release;
227 widget_class->motion_notify_event = gtk_list_motion_notify;
228 widget_class->size_request = gtk_list_size_request;
229 widget_class->size_allocate = gtk_list_size_allocate;
230 widget_class->drag_begin = gtk_list_drag_begin;
231 widget_class->focus = gtk_list_focus;
233 container_class->add = gtk_list_add;
234 container_class->remove = gtk_list_remove;
235 container_class->forall = gtk_list_forall;
236 container_class->child_type = gtk_list_child_type;
237 container_class->set_focus_child = gtk_list_set_focus_child;
239 class->selection_changed = NULL;
240 class->select_child = gtk_real_list_select_child;
241 class->unselect_child = gtk_real_list_unselect_child;
243 list_signals[SELECTION_CHANGED] =
244 gtk_signal_new ("selection_changed",
246 GTK_CLASS_TYPE (object_class),
247 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
248 _gtk_marshal_VOID__VOID,
250 list_signals[SELECT_CHILD] =
251 gtk_signal_new ("select_child",
253 GTK_CLASS_TYPE (object_class),
254 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
255 _gtk_marshal_VOID__OBJECT,
258 list_signals[UNSELECT_CHILD] =
259 gtk_signal_new ("unselect_child",
261 GTK_CLASS_TYPE (object_class),
262 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
263 _gtk_marshal_VOID__OBJECT,
267 gtk_object_add_arg_type ("GtkList::selection_mode",
268 GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
273 gtk_list_init (GtkList *list)
275 list->children = NULL;
276 list->selection = NULL;
278 list->undo_selection = NULL;
279 list->undo_unselection = NULL;
281 list->last_focus_child = NULL;
282 list->undo_focus_child = NULL;
289 list->anchor_state = GTK_STATE_SELECTED;
291 list->selection_mode = GTK_SELECTION_SINGLE;
292 list->drag_selection = FALSE;
293 list->add_mode = FALSE;
297 gtk_list_set_arg (GtkObject *object,
301 GtkList *list = GTK_LIST (object);
305 case ARG_SELECTION_MODE:
306 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
312 gtk_list_get_arg (GtkObject *object,
316 GtkList *list = GTK_LIST (object);
320 case ARG_SELECTION_MODE:
321 GTK_VALUE_ENUM (*arg) = list->selection_mode;
324 arg->type = GTK_TYPE_INVALID;
332 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
336 /* Private GtkObject Methods :
341 gtk_list_dispose (GObject *object)
343 gtk_list_clear_items (GTK_LIST (object), 0, -1);
345 G_OBJECT_CLASS (parent_class)->dispose (object);
349 /* Private GtkWidget Methods :
351 * gtk_list_size_request
352 * gtk_list_size_allocate
355 * gtk_list_motion_notify
356 * gtk_list_button_press
357 * gtk_list_button_release
360 gtk_list_size_request (GtkWidget *widget,
361 GtkRequisition *requisition)
367 g_return_if_fail (GTK_IS_LIST (widget));
368 g_return_if_fail (requisition != NULL);
370 list = GTK_LIST (widget);
371 requisition->width = 0;
372 requisition->height = 0;
374 children = list->children;
377 child = children->data;
378 children = children->next;
380 if (GTK_WIDGET_VISIBLE (child))
382 GtkRequisition child_requisition;
384 gtk_widget_size_request (child, &child_requisition);
386 requisition->width = MAX (requisition->width,
387 child_requisition.width);
388 requisition->height += child_requisition.height;
392 requisition->width += GTK_CONTAINER (list)->border_width * 2;
393 requisition->height += GTK_CONTAINER (list)->border_width * 2;
395 requisition->width = MAX (requisition->width, 1);
396 requisition->height = MAX (requisition->height, 1);
400 gtk_list_size_allocate (GtkWidget *widget,
401 GtkAllocation *allocation)
405 GtkAllocation child_allocation;
408 g_return_if_fail (GTK_IS_LIST (widget));
409 g_return_if_fail (allocation != NULL);
411 list = GTK_LIST (widget);
413 widget->allocation = *allocation;
414 if (GTK_WIDGET_REALIZED (widget))
415 gdk_window_move_resize (widget->window,
416 allocation->x, allocation->y,
417 allocation->width, allocation->height);
421 child_allocation.x = GTK_CONTAINER (list)->border_width;
422 child_allocation.y = GTK_CONTAINER (list)->border_width;
423 child_allocation.width = MAX (1, (gint)allocation->width -
424 child_allocation.x * 2);
426 children = list->children;
430 child = children->data;
431 children = children->next;
433 if (GTK_WIDGET_VISIBLE (child))
435 GtkRequisition child_requisition;
436 gtk_widget_get_child_requisition (child, &child_requisition);
438 child_allocation.height = child_requisition.height;
440 gtk_widget_size_allocate (child, &child_allocation);
442 child_allocation.y += child_allocation.height;
449 gtk_list_realize (GtkWidget *widget)
451 GdkWindowAttr attributes;
452 gint attributes_mask;
454 g_return_if_fail (GTK_IS_LIST (widget));
456 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
458 attributes.window_type = GDK_WINDOW_CHILD;
459 attributes.x = widget->allocation.x;
460 attributes.y = widget->allocation.y;
461 attributes.width = widget->allocation.width;
462 attributes.height = widget->allocation.height;
463 attributes.wclass = GDK_INPUT_OUTPUT;
464 attributes.visual = gtk_widget_get_visual (widget);
465 attributes.colormap = gtk_widget_get_colormap (widget);
466 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
468 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
470 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
471 &attributes, attributes_mask);
472 gdk_window_set_user_data (widget->window, widget);
474 widget->style = gtk_style_attach (widget->style, widget->window);
475 gdk_window_set_background (widget->window,
476 &widget->style->base[GTK_STATE_NORMAL]);
480 gtk_list_unmap (GtkWidget *widget)
484 g_return_if_fail (GTK_IS_LIST (widget));
486 if (!GTK_WIDGET_MAPPED (widget))
489 list = GTK_LIST (widget);
491 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
493 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
495 gtk_list_end_drag_selection (list);
497 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_MULTIPLE)
498 gtk_list_end_selection (list);
501 gdk_window_hide (widget->window);
505 gtk_list_motion_notify (GtkWidget *widget,
506 GdkEventMotion *event)
509 GtkWidget *item = NULL;
511 GtkContainer *container;
519 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
520 g_return_val_if_fail (event != NULL, FALSE);
522 list = GTK_LIST (widget);
524 if (!list->drag_selection || !list->children)
527 container = GTK_CONTAINER (widget);
529 if (event->is_hint || event->window != widget->window)
530 gdk_window_get_pointer (widget->window, &x, &y, NULL);
537 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
539 /* horizontal autoscrolling */
540 if (adj && widget->allocation.width > adj->page_size &&
541 (x < adj->value || x >= adj->value + adj->page_size))
543 if (list->htimer == 0)
545 list->htimer = gtk_timeout_add
546 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
548 if (!((x < adj->value && adj->value <= 0) ||
549 (x > adj->value + adj->page_size &&
550 adj->value >= adj->upper - adj->page_size)))
555 value = adj->value + (x - adj->value) / 2 - 1;
557 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
559 gtk_adjustment_set_value (adj,
561 adj->upper - adj->page_size));
569 /* vertical autoscrolling */
570 for (work = list->children; work; length++, work = work->next)
574 item = GTK_WIDGET (work->data);
575 if (item->allocation.y > y ||
576 (item->allocation.y <= y &&
577 item->allocation.y + item->allocation.height > y))
581 if (work->data == container->focus_child)
588 if (list->vtimer != 0)
591 if (!((y < 0 && focus_row == 0) ||
592 (y > widget->allocation.height && focus_row >= length - 1)))
593 list->vtimer = gtk_timeout_add (SCROLL_TIME,
594 (GtkFunction) gtk_list_vertical_timeout,
597 if (row != focus_row)
598 gtk_widget_grab_focus (item);
600 switch (list->selection_mode)
602 case GTK_SELECTION_BROWSE:
603 gtk_list_select_child (list, item);
605 case GTK_SELECTION_MULTIPLE:
606 gtk_list_update_extended_selection (list, row);
616 gtk_list_button_press (GtkWidget *widget,
617 GdkEventButton *event)
622 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
623 g_return_val_if_fail (event != NULL, FALSE);
625 if (event->button != 1)
628 list = GTK_LIST (widget);
629 item = gtk_get_event_widget ((GdkEvent*) event);
631 while (item && !GTK_IS_LIST_ITEM (item))
634 if (item && (item->parent == widget))
639 if (event->type == GDK_BUTTON_PRESS)
641 gtk_grab_add (widget);
642 list->drag_selection = TRUE;
644 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
645 gtk_list_end_drag_selection (list);
647 if (!GTK_WIDGET_HAS_FOCUS(item))
648 gtk_widget_grab_focus (item);
652 list->add_mode = FALSE;
653 gtk_widget_queue_draw (item);
656 switch (list->selection_mode)
658 case GTK_SELECTION_SINGLE:
659 if (event->type != GDK_BUTTON_PRESS)
660 gtk_list_select_child (list, item);
662 list->undo_focus_child = item;
665 case GTK_SELECTION_BROWSE:
668 case GTK_SELECTION_MULTIPLE:
669 focus_row = g_list_index (list->children, item);
671 if (list->last_focus_child)
672 last_focus_row = g_list_index (list->children,
673 list->last_focus_child);
676 last_focus_row = focus_row;
677 list->last_focus_child = item;
680 if (event->type != GDK_BUTTON_PRESS)
682 if (list->anchor >= 0)
684 gtk_list_update_extended_selection (list, focus_row);
685 gtk_list_end_selection (list);
687 gtk_list_select_child (list, item);
691 if (event->state & GDK_CONTROL_MASK)
693 if (event->state & GDK_SHIFT_MASK)
695 if (list->anchor < 0)
697 g_list_free (list->undo_selection);
698 g_list_free (list->undo_unselection);
699 list->undo_selection = NULL;
700 list->undo_unselection = NULL;
702 list->anchor = last_focus_row;
703 list->drag_pos = last_focus_row;
704 list->undo_focus_child = list->last_focus_child;
706 gtk_list_update_extended_selection (list, focus_row);
710 if (list->anchor < 0)
711 gtk_list_set_anchor (list, TRUE,
712 focus_row, list->last_focus_child);
714 gtk_list_update_extended_selection (list, focus_row);
719 if (event->state & GDK_SHIFT_MASK)
721 gtk_list_set_anchor (list, FALSE,
722 last_focus_row, list->last_focus_child);
723 gtk_list_update_extended_selection (list, focus_row);
727 if (list->anchor < 0)
728 gtk_list_set_anchor (list, FALSE, focus_row,
729 list->last_focus_child);
731 gtk_list_update_extended_selection (list, focus_row);
745 gtk_list_button_release (GtkWidget *widget,
746 GdkEventButton *event)
751 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
752 g_return_val_if_fail (event != NULL, FALSE);
754 list = GTK_LIST (widget);
756 /* we don't handle button 2 and 3 */
757 if (event->button != 1)
760 if (list->drag_selection)
762 gtk_list_end_drag_selection (list);
764 switch (list->selection_mode)
766 case GTK_SELECTION_MULTIPLE:
767 if (!(event->state & GDK_SHIFT_MASK))
768 gtk_list_end_selection (list);
771 case GTK_SELECTION_SINGLE:
773 item = gtk_get_event_widget ((GdkEvent*) event);
775 while (item && !GTK_IS_LIST_ITEM (item))
778 if (item && item->parent == widget)
780 if (list->undo_focus_child == item)
781 gtk_list_toggle_row (list, item);
783 list->undo_focus_child = NULL;
797 gtk_list_style_set (GtkWidget *widget,
798 GtkStyle *previous_style)
800 g_return_if_fail (widget != NULL);
802 if (previous_style && GTK_WIDGET_REALIZED (widget))
803 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
806 /* GtkContainer Methods :
810 * gtk_list_child_type
811 * gtk_list_set_focus_child
815 gtk_list_add (GtkContainer *container,
820 g_return_if_fail (GTK_IS_LIST (container));
821 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
823 item_list = g_list_alloc ();
824 item_list->data = widget;
826 gtk_list_append_items (GTK_LIST (container), item_list);
830 gtk_list_remove (GtkContainer *container,
835 g_return_if_fail (GTK_IS_LIST (container));
836 g_return_if_fail (widget != NULL);
837 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
839 item_list = g_list_alloc ();
840 item_list->data = widget;
842 gtk_list_remove_items (GTK_LIST (container), item_list);
844 g_list_free (item_list);
848 gtk_list_forall (GtkContainer *container,
849 gboolean include_internals,
850 GtkCallback callback,
851 gpointer callback_data)
857 g_return_if_fail (GTK_IS_LIST (container));
858 g_return_if_fail (callback != NULL);
860 list = GTK_LIST (container);
861 children = list->children;
865 child = children->data;
866 children = children->next;
868 (* callback) (child, callback_data);
873 gtk_list_child_type (GtkContainer *container)
875 return GTK_TYPE_LIST_ITEM;
879 gtk_list_set_focus_child (GtkContainer *container,
884 g_return_if_fail (GTK_IS_LIST (container));
887 g_return_if_fail (GTK_IS_WIDGET (child));
889 list = GTK_LIST (container);
891 if (child != container->focus_child)
893 if (container->focus_child)
895 list->last_focus_child = container->focus_child;
896 gtk_widget_unref (container->focus_child);
898 container->focus_child = child;
899 if (container->focus_child)
900 gtk_widget_ref (container->focus_child);
903 /* check for v adjustment */
904 if (container->focus_child)
906 GtkAdjustment *adjustment;
908 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
911 gtk_adjustment_clamp_page (adjustment,
912 container->focus_child->allocation.y,
913 (container->focus_child->allocation.y +
914 container->focus_child->allocation.height));
915 switch (list->selection_mode)
917 case GTK_SELECTION_BROWSE:
918 gtk_list_select_child (list, child);
920 case GTK_SELECTION_MULTIPLE:
921 if (!list->last_focus_child && !list->add_mode)
923 list->undo_focus_child = list->last_focus_child;
924 gtk_list_unselect_all (list);
925 gtk_list_select_child (list, child);
935 gtk_list_focus (GtkWidget *widget,
936 GtkDirectionType direction)
938 gint return_val = FALSE;
939 GtkContainer *container;
941 container = GTK_CONTAINER (widget);
943 if (container->focus_child == NULL ||
944 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
946 if (GTK_LIST (container)->last_focus_child)
947 gtk_container_set_focus_child
948 (container, GTK_LIST (container)->last_focus_child);
950 if (GTK_WIDGET_CLASS (parent_class)->focus)
951 return_val = GTK_WIDGET_CLASS (parent_class)->focus (widget,
959 list = GTK_LIST (container);
960 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
961 gtk_list_end_selection (list);
963 if (container->focus_child)
964 list->last_focus_child = container->focus_child;
971 /* Public GtkList Methods :
973 * gtk_list_insert_items
974 * gtk_list_append_items
975 * gtk_list_prepend_items
976 * gtk_list_remove_items
977 * gtk_list_remove_items_no_unref
978 * gtk_list_clear_items
980 * gtk_list_child_position
983 gtk_list_insert_items (GtkList *list,
992 g_return_if_fail (GTK_IS_LIST (list));
997 gtk_list_end_drag_selection (list);
998 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
999 gtk_list_end_selection (list);
1004 widget = tmp_list->data;
1005 tmp_list = tmp_list->next;
1007 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1008 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1009 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1011 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1012 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1014 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1015 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1017 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1018 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1020 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1021 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1023 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1024 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1026 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1027 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1029 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1030 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1032 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1033 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1035 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1036 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1038 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1039 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1041 gtk_signal_connect (GTK_OBJECT (widget), "select",
1042 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1044 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1045 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1047 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1048 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1053 nchildren = g_list_length (list->children);
1054 if ((position < 0) || (position > nchildren))
1055 position = nchildren;
1057 if (position == nchildren)
1061 tmp_list = g_list_last (list->children);
1062 tmp_list->next = items;
1063 items->prev = tmp_list;
1067 list->children = items;
1072 tmp_list = g_list_nth (list->children, position);
1073 last = g_list_last (items);
1076 tmp_list->prev->next = items;
1077 last->next = tmp_list;
1078 items->prev = tmp_list->prev;
1079 tmp_list->prev = last;
1081 if (tmp_list == list->children)
1082 list->children = items;
1085 if (list->children && !list->selection &&
1086 (list->selection_mode == GTK_SELECTION_BROWSE))
1088 widget = list->children->data;
1089 gtk_list_select_child (list, widget);
1094 gtk_list_append_items (GtkList *list,
1097 g_return_if_fail (GTK_IS_LIST (list));
1099 gtk_list_insert_items (list, items, -1);
1103 gtk_list_prepend_items (GtkList *list,
1106 g_return_if_fail (GTK_IS_LIST (list));
1108 gtk_list_insert_items (list, items, 0);
1112 gtk_list_remove_items (GtkList *list,
1115 gtk_list_remove_items_internal (list, items, FALSE);
1119 gtk_list_remove_items_no_unref (GtkList *list,
1122 gtk_list_remove_items_internal (list, items, TRUE);
1126 gtk_list_clear_items (GtkList *list,
1130 GtkContainer *container;
1132 GtkWidget *new_focus_child = NULL;
1137 gboolean grab_focus = FALSE;
1139 g_return_if_fail (GTK_IS_LIST (list));
1141 nchildren = g_list_length (list->children);
1146 if ((end < 0) || (end > nchildren))
1152 container = GTK_CONTAINER (list);
1154 gtk_list_end_drag_selection (list);
1155 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1157 if (list->anchor >= 0)
1158 gtk_list_end_selection (list);
1160 gtk_list_reset_extended_selection (list);
1163 start_list = g_list_nth (list->children, start);
1164 end_list = g_list_nth (list->children, end);
1166 if (start_list->prev)
1167 start_list->prev->next = end_list;
1168 if (end_list && end_list->prev)
1169 end_list->prev->next = NULL;
1171 end_list->prev = start_list->prev;
1172 if (start_list == list->children)
1173 list->children = end_list;
1175 if (container->focus_child)
1177 if (g_list_find (start_list, container->focus_child))
1179 if (start_list->prev)
1180 new_focus_child = start_list->prev->data;
1181 else if (list->children)
1182 new_focus_child = list->children->data;
1184 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1189 tmp_list = start_list;
1192 widget = tmp_list->data;
1193 tmp_list = tmp_list->next;
1195 gtk_widget_ref (widget);
1197 if (widget->state == GTK_STATE_SELECTED)
1198 gtk_list_unselect_child (list, widget);
1200 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1201 gtk_widget_unparent (widget);
1203 if (widget == list->undo_focus_child)
1204 list->undo_focus_child = NULL;
1205 if (widget == list->last_focus_child)
1206 list->last_focus_child = NULL;
1208 gtk_widget_unref (widget);
1211 g_list_free (start_list);
1213 if (new_focus_child)
1216 gtk_widget_grab_focus (new_focus_child);
1217 else if (container->focus_child)
1218 gtk_container_set_focus_child (container, new_focus_child);
1220 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1221 list->selection_mode == GTK_SELECTION_MULTIPLE) && !list->selection)
1223 list->last_focus_child = new_focus_child;
1224 gtk_list_select_child (list, new_focus_child);
1228 if (GTK_WIDGET_VISIBLE (list))
1229 gtk_widget_queue_resize (GTK_WIDGET (list));
1233 gtk_list_child_position (GtkList *list,
1239 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1240 g_return_val_if_fail (child != NULL, -1);
1243 children = list->children;
1247 if (child == GTK_WIDGET (children->data))
1251 children = children->next;
1258 /* Private GtkList Insert/Remove Item Functions:
1260 * gtk_list_remove_items_internal
1263 gtk_list_remove_items_internal (GtkList *list,
1268 GtkWidget *new_focus_child;
1269 GtkWidget *old_focus_child;
1270 GtkContainer *container;
1273 gboolean grab_focus = FALSE;
1275 g_return_if_fail (GTK_IS_LIST (list));
1280 container = GTK_CONTAINER (list);
1282 gtk_list_end_drag_selection (list);
1283 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1285 if (list->anchor >= 0)
1286 gtk_list_end_selection (list);
1288 gtk_list_reset_extended_selection (list);
1294 widget = tmp_list->data;
1295 tmp_list = tmp_list->next;
1297 if (widget->state == GTK_STATE_SELECTED)
1298 gtk_list_unselect_child (list, widget);
1301 if (container->focus_child)
1303 old_focus_child = new_focus_child = container->focus_child;
1304 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1308 old_focus_child = new_focus_child = list->last_focus_child;
1313 widget = tmp_list->data;
1314 tmp_list = tmp_list->next;
1316 gtk_widget_ref (widget);
1318 gtk_widget_ref (widget);
1320 if (widget == new_focus_child)
1322 work = g_list_find (list->children, widget);
1327 new_focus_child = work->next->data;
1328 else if (list->children != work && work->prev)
1329 new_focus_child = work->prev->data;
1331 new_focus_child = NULL;
1335 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1336 list->children = g_list_remove (list->children, widget);
1337 gtk_widget_unparent (widget);
1339 if (widget == list->undo_focus_child)
1340 list->undo_focus_child = NULL;
1341 if (widget == list->last_focus_child)
1342 list->last_focus_child = NULL;
1344 gtk_widget_unref (widget);
1347 if (new_focus_child && new_focus_child != old_focus_child)
1350 gtk_widget_grab_focus (new_focus_child);
1351 else if (container->focus_child)
1352 gtk_container_set_focus_child (container, new_focus_child);
1354 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1356 list->last_focus_child = new_focus_child;
1357 gtk_list_select_child (list, new_focus_child);
1361 if (GTK_WIDGET_VISIBLE (list))
1362 gtk_widget_queue_resize (GTK_WIDGET (list));
1366 /* Public GtkList Selection Methods :
1368 * gtk_list_set_selection_mode
1369 * gtk_list_select_item
1370 * gtk_list_unselect_item
1371 * gtk_list_select_child
1372 * gtk_list_unselect_child
1373 * gtk_list_select_all
1374 * gtk_list_unselect_all
1375 * gtk_list_extend_selection
1376 * gtk_list_end_drag_selection
1377 * gtk_list_start_selection
1378 * gtk_list_end_selection
1379 * gtk_list_toggle_row
1380 * gtk_list_toggle_focus_row
1381 * gtk_list_toggle_add_mode
1382 * gtk_list_undo_selection
1385 gtk_list_set_selection_mode (GtkList *list,
1386 GtkSelectionMode mode)
1388 g_return_if_fail (GTK_IS_LIST (list));
1390 if (list->selection_mode == mode)
1393 list->selection_mode = mode;
1397 case GTK_SELECTION_SINGLE:
1398 case GTK_SELECTION_BROWSE:
1399 gtk_list_unselect_all (list);
1407 gtk_list_select_item (GtkList *list,
1412 g_return_if_fail (GTK_IS_LIST (list));
1414 tmp_list = g_list_nth (list->children, item);
1416 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1420 gtk_list_unselect_item (GtkList *list,
1425 g_return_if_fail (GTK_IS_LIST (list));
1427 tmp_list = g_list_nth (list->children, item);
1429 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1433 gtk_list_select_child (GtkList *list,
1436 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1440 gtk_list_unselect_child (GtkList *list,
1443 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1447 gtk_list_select_all (GtkList *list)
1449 GtkContainer *container;
1451 g_return_if_fail (GTK_IS_LIST (list));
1453 if (!list->children)
1456 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1457 gtk_list_end_drag_selection (list);
1459 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1460 gtk_list_end_selection (list);
1462 container = GTK_CONTAINER (list);
1464 switch (list->selection_mode)
1466 case GTK_SELECTION_BROWSE:
1467 if (container->focus_child)
1469 gtk_list_select_child (list, container->focus_child);
1473 case GTK_SELECTION_MULTIPLE:
1474 g_list_free (list->undo_selection);
1475 g_list_free (list->undo_unselection);
1476 list->undo_selection = NULL;
1477 list->undo_unselection = NULL;
1479 if (list->children &&
1480 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1481 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1483 list->anchor_state = GTK_STATE_SELECTED;
1486 list->undo_focus_child = container->focus_child;
1487 gtk_list_update_extended_selection (list, g_list_length(list->children));
1488 gtk_list_end_selection (list);
1496 gtk_list_unselect_all (GtkList *list)
1498 GtkContainer *container;
1502 g_return_if_fail (GTK_IS_LIST (list));
1504 if (!list->children)
1507 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1508 gtk_list_end_drag_selection (list);
1510 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1511 gtk_list_end_selection (list);
1513 container = GTK_CONTAINER (list);
1515 switch (list->selection_mode)
1517 case GTK_SELECTION_BROWSE:
1518 if (container->focus_child)
1520 gtk_list_select_child (list, container->focus_child);
1524 case GTK_SELECTION_MULTIPLE:
1525 gtk_list_reset_extended_selection (list);
1531 work = list->selection;
1537 gtk_list_unselect_child (list, item);
1542 gtk_list_extend_selection (GtkList *list,
1543 GtkScrollType scroll_type,
1545 gboolean auto_start_selection)
1547 GtkContainer *container;
1549 g_return_if_fail (GTK_IS_LIST (list));
1551 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1552 list->selection_mode != GTK_SELECTION_MULTIPLE)
1555 container = GTK_CONTAINER (list);
1557 if (auto_start_selection)
1561 focus_row = g_list_index (list->children, container->focus_child);
1562 gtk_list_set_anchor (list, list->add_mode, focus_row,
1563 container->focus_child);
1565 else if (list->anchor < 0)
1568 gtk_list_move_focus_child (list, scroll_type, position);
1569 gtk_list_update_extended_selection
1570 (list, g_list_index (list->children, container->focus_child));
1574 gtk_list_end_drag_selection (GtkList *list)
1576 g_return_if_fail (GTK_IS_LIST (list));
1578 list->drag_selection = FALSE;
1579 if (GTK_WIDGET_HAS_GRAB (list))
1580 gtk_grab_remove (GTK_WIDGET (list));
1584 gtk_timeout_remove (list->htimer);
1589 gtk_timeout_remove (list->vtimer);
1595 gtk_list_start_selection (GtkList *list)
1597 GtkContainer *container;
1600 g_return_if_fail (GTK_IS_LIST (list));
1602 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1605 container = GTK_CONTAINER (list);
1607 if ((focus_row = g_list_index (list->selection, container->focus_child))
1609 gtk_list_set_anchor (list, list->add_mode,
1610 focus_row, container->focus_child);
1614 gtk_list_end_selection (GtkList *list)
1623 g_return_if_fail (GTK_IS_LIST (list));
1625 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1629 i = MIN (list->anchor, list->drag_pos);
1630 e = MAX (list->anchor, list->drag_pos);
1632 top_down = (list->anchor < list->drag_pos);
1635 list->drag_pos = -1;
1637 if (list->undo_selection)
1639 work = list->selection;
1640 list->selection = list->undo_selection;
1641 list->undo_selection = work;
1642 work = list->selection;
1647 item_index = g_list_index (list->children, item);
1648 if (item_index < i || item_index > e)
1650 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1651 gtk_list_unselect_child (list, item);
1652 list->undo_selection = g_list_prepend (list->undo_selection,
1660 for (work = g_list_nth (list->children, i); i <= e;
1661 i++, work = work->next)
1664 if (g_list_find (list->selection, item))
1666 if (item->state == GTK_STATE_NORMAL)
1668 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1669 gtk_list_unselect_child (list, item);
1670 list->undo_selection = g_list_prepend (list->undo_selection,
1674 else if (item->state == GTK_STATE_SELECTED)
1676 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1677 list->undo_unselection = g_list_prepend (list->undo_unselection,
1684 for (work = g_list_nth (list->children, e); i <= e;
1685 e--, work = work->prev)
1688 if (g_list_find (list->selection, item))
1690 if (item->state == GTK_STATE_NORMAL)
1692 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1693 gtk_list_unselect_child (list, item);
1694 list->undo_selection = g_list_prepend (list->undo_selection,
1698 else if (item->state == GTK_STATE_SELECTED)
1700 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1701 list->undo_unselection = g_list_prepend (list->undo_unselection,
1707 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1708 gtk_list_select_child (list, GTK_WIDGET (work->data));
1714 gtk_list_toggle_row (GtkList *list,
1717 g_return_if_fail (GTK_IS_LIST (list));
1718 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1720 switch (list->selection_mode)
1722 case GTK_SELECTION_MULTIPLE:
1723 case GTK_SELECTION_SINGLE:
1724 if (item->state == GTK_STATE_SELECTED)
1726 gtk_list_unselect_child (list, item);
1729 case GTK_SELECTION_BROWSE:
1730 gtk_list_select_child (list, item);
1736 gtk_list_toggle_focus_row (GtkList *list)
1738 GtkContainer *container;
1741 g_return_if_fail (list != 0);
1742 g_return_if_fail (GTK_IS_LIST (list));
1744 container = GTK_CONTAINER (list);
1746 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1747 !container->focus_child)
1750 switch (list->selection_mode)
1752 case GTK_SELECTION_SINGLE:
1753 gtk_list_toggle_row (list, container->focus_child);
1755 case GTK_SELECTION_MULTIPLE:
1756 if ((focus_row = g_list_index (list->children, container->focus_child))
1760 g_list_free (list->undo_selection);
1761 g_list_free (list->undo_unselection);
1762 list->undo_selection = NULL;
1763 list->undo_unselection = NULL;
1765 list->anchor = focus_row;
1766 list->drag_pos = focus_row;
1767 list->undo_focus_child = container->focus_child;
1770 gtk_list_fake_toggle_row (list, container->focus_child);
1772 gtk_list_fake_unselect_all (list, container->focus_child);
1774 gtk_list_end_selection (list);
1782 gtk_list_toggle_add_mode (GtkList *list)
1784 GtkContainer *container;
1786 g_return_if_fail (list != 0);
1787 g_return_if_fail (GTK_IS_LIST (list));
1789 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1790 list->selection_mode != GTK_SELECTION_MULTIPLE)
1793 container = GTK_CONTAINER (list);
1797 list->add_mode = FALSE;
1798 list->anchor_state = GTK_STATE_SELECTED;
1801 list->add_mode = TRUE;
1803 if (container->focus_child)
1804 gtk_widget_queue_draw (container->focus_child);
1808 gtk_list_undo_selection (GtkList *list)
1812 g_return_if_fail (GTK_IS_LIST (list));
1814 if (list->selection_mode != GTK_SELECTION_MULTIPLE ||
1815 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1818 if (list->anchor >= 0)
1819 gtk_list_end_selection (list);
1821 if (!(list->undo_selection || list->undo_unselection))
1823 gtk_list_unselect_all (list);
1827 for (work = list->undo_selection; work; work = work->next)
1828 gtk_list_select_child (list, GTK_WIDGET (work->data));
1830 for (work = list->undo_unselection; work; work = work->next)
1831 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1833 if (list->undo_focus_child)
1835 GtkContainer *container;
1837 container = GTK_CONTAINER (list);
1839 if (container->focus_child &&
1840 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1841 gtk_widget_grab_focus (list->undo_focus_child);
1843 gtk_container_set_focus_child (container, list->undo_focus_child);
1846 list->undo_focus_child = NULL;
1848 g_list_free (list->undo_selection);
1849 g_list_free (list->undo_unselection);
1850 list->undo_selection = NULL;
1851 list->undo_unselection = NULL;
1855 /* Private GtkList Selection Methods :
1857 * gtk_real_list_select_child
1858 * gtk_real_list_unselect_child
1861 gtk_real_list_select_child (GtkList *list,
1864 g_return_if_fail (GTK_IS_LIST (list));
1865 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1867 switch (child->state)
1869 case GTK_STATE_SELECTED:
1870 case GTK_STATE_INSENSITIVE:
1873 gtk_list_item_select (GTK_LIST_ITEM (child));
1879 gtk_real_list_unselect_child (GtkList *list,
1882 g_return_if_fail (GTK_IS_LIST (list));
1883 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1885 if (child->state == GTK_STATE_SELECTED)
1886 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1890 /* Private GtkList Selection Functions :
1892 * gtk_list_set_anchor
1893 * gtk_list_fake_unselect_all
1894 * gtk_list_fake_toggle_row
1895 * gtk_list_update_extended_selection
1896 * gtk_list_reset_extended_selection
1899 gtk_list_set_anchor (GtkList *list,
1902 GtkWidget *undo_focus_child)
1906 g_return_if_fail (GTK_IS_LIST (list));
1908 if (list->selection_mode != GTK_SELECTION_MULTIPLE || list->anchor >= 0)
1911 g_list_free (list->undo_selection);
1912 g_list_free (list->undo_unselection);
1913 list->undo_selection = NULL;
1914 list->undo_unselection = NULL;
1916 if ((work = g_list_nth (list->children, anchor)))
1919 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1922 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1923 list->anchor_state = GTK_STATE_SELECTED;
1927 list->anchor = anchor;
1928 list->drag_pos = anchor;
1929 list->undo_focus_child = undo_focus_child;
1933 gtk_list_fake_unselect_all (GtkList *list,
1938 if (item && item->state == GTK_STATE_NORMAL)
1939 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1941 list->undo_selection = list->selection;
1942 list->selection = NULL;
1944 for (work = list->undo_selection; work; work = work->next)
1945 if (work->data != item)
1946 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1950 gtk_list_fake_toggle_row (GtkList *list,
1956 if (item->state == GTK_STATE_NORMAL)
1958 list->anchor_state = GTK_STATE_SELECTED;
1959 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1963 list->anchor_state = GTK_STATE_NORMAL;
1964 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1969 gtk_list_update_extended_selection (GtkList *list,
1983 length = g_list_length (list->children);
1987 if (list->selection_mode != GTK_SELECTION_MULTIPLE || !list->anchor < 0)
1990 /* extending downwards */
1991 if (row > list->drag_pos && list->anchor <= list->drag_pos)
1993 s2 = list->drag_pos + 1;
1996 /* extending upwards */
1997 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2000 e2 = list->drag_pos - 1;
2002 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2004 e1 = list->drag_pos;
2005 /* row and drag_pos on different sides of anchor :
2006 take back the selection between anchor and drag_pos,
2007 select between anchor and row */
2008 if (row < list->anchor)
2010 s1 = list->anchor + 1;
2012 e2 = list->anchor - 1;
2014 /* take back the selection between anchor and drag_pos */
2018 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2020 s1 = list->drag_pos;
2021 /* row and drag_pos on different sides of anchor :
2022 take back the selection between anchor and drag_pos,
2023 select between anchor and row */
2024 if (row > list->anchor)
2026 e1 = list->anchor - 1;
2027 s2 = list->anchor + 1;
2030 /* take back the selection between anchor and drag_pos */
2035 list->drag_pos = row;
2037 /* restore the elements between s1 and e1 */
2040 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2041 i++, work = work->next)
2043 if (g_list_find (list->selection, work->data))
2044 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2046 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2050 /* extend the selection between s2 and e2 */
2053 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2054 i++, work = work->next)
2055 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2056 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2061 gtk_list_reset_extended_selection (GtkList *list)
2063 g_return_if_fail (list != 0);
2064 g_return_if_fail (GTK_IS_LIST (list));
2066 g_list_free (list->undo_selection);
2067 g_list_free (list->undo_unselection);
2068 list->undo_selection = NULL;
2069 list->undo_unselection = NULL;
2072 list->drag_pos = -1;
2073 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2076 /* Public GtkList Scroll Methods :
2078 * gtk_list_scroll_horizontal
2079 * gtk_list_scroll_vertical
2082 gtk_list_scroll_horizontal (GtkList *list,
2083 GtkScrollType scroll_type,
2088 g_return_if_fail (list != 0);
2089 g_return_if_fail (GTK_IS_LIST (list));
2091 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2095 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2098 switch (scroll_type)
2100 case GTK_SCROLL_STEP_UP:
2101 case GTK_SCROLL_STEP_BACKWARD:
2102 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2103 adj->upper - adj->page_size);
2105 case GTK_SCROLL_STEP_DOWN:
2106 case GTK_SCROLL_STEP_FORWARD:
2107 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2108 adj->upper - adj->page_size);
2110 case GTK_SCROLL_PAGE_UP:
2111 case GTK_SCROLL_PAGE_BACKWARD:
2112 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2113 adj->upper - adj->page_size);
2115 case GTK_SCROLL_PAGE_DOWN:
2116 case GTK_SCROLL_PAGE_FORWARD:
2117 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2118 adj->upper - adj->page_size);
2120 case GTK_SCROLL_JUMP:
2121 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2122 adj->lower, adj->upper - adj->page_size);
2127 gtk_adjustment_value_changed (adj);
2131 gtk_list_scroll_vertical (GtkList *list,
2132 GtkScrollType scroll_type,
2135 g_return_if_fail (GTK_IS_LIST (list));
2137 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2140 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
2142 GtkContainer *container;
2144 if (list->anchor >= 0)
2147 container = GTK_CONTAINER (list);
2148 list->undo_focus_child = container->focus_child;
2149 gtk_list_move_focus_child (list, scroll_type, position);
2150 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2152 gtk_list_unselect_all (list);
2153 gtk_list_select_child (list, container->focus_child);
2157 gtk_list_move_focus_child (list, scroll_type, position);
2161 /* Private GtkList Scroll/Focus Functions :
2163 * gtk_list_move_focus_child
2164 * gtk_list_horizontal_timeout
2165 * gtk_list_vertical_timeout
2168 gtk_list_move_focus_child (GtkList *list,
2169 GtkScrollType scroll_type,
2172 GtkContainer *container;
2178 g_return_if_fail (list != 0);
2179 g_return_if_fail (GTK_IS_LIST (list));
2181 container = GTK_CONTAINER (list);
2183 if (container->focus_child)
2184 work = g_list_find (list->children, container->focus_child);
2186 work = list->children;
2191 switch (scroll_type)
2193 case GTK_SCROLL_STEP_BACKWARD:
2196 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2198 case GTK_SCROLL_STEP_FORWARD:
2201 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2203 case GTK_SCROLL_PAGE_BACKWARD:
2208 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2212 gboolean correct = FALSE;
2214 new_value = adj->value;
2216 if (item->allocation.y <= adj->value)
2218 new_value = MAX (item->allocation.y + item->allocation.height
2219 - adj->page_size, adj->lower);
2223 if (item->allocation.y > new_value)
2224 for (; work; work = work->prev)
2226 item = GTK_WIDGET (work->data);
2227 if (item->allocation.y <= new_value &&
2228 item->allocation.y + item->allocation.height > new_value)
2232 for (; work; work = work->next)
2234 item = GTK_WIDGET (work->data);
2235 if (item->allocation.y <= new_value &&
2236 item->allocation.y + item->allocation.height > new_value)
2240 if (correct && work && work->next && item->allocation.y < new_value)
2241 item = work->next->data;
2244 item = list->children->data;
2246 gtk_widget_grab_focus (item);
2248 case GTK_SCROLL_PAGE_FORWARD:
2253 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2257 gboolean correct = FALSE;
2259 new_value = adj->value;
2261 if (item->allocation.y + item->allocation.height >=
2262 adj->value + adj->page_size)
2264 new_value = item->allocation.y;
2268 new_value = MIN (new_value + adj->page_size, adj->upper);
2270 if (item->allocation.y > new_value)
2271 for (; work; work = work->prev)
2273 item = GTK_WIDGET (work->data);
2274 if (item->allocation.y <= new_value &&
2275 item->allocation.y + item->allocation.height > new_value)
2279 for (; work; work = work->next)
2281 item = GTK_WIDGET (work->data);
2282 if (item->allocation.y <= new_value &&
2283 item->allocation.y + item->allocation.height > new_value)
2287 if (correct && work && work->prev &&
2288 item->allocation.y + item->allocation.height - 1 > new_value)
2289 item = work->prev->data;
2292 item = g_list_last (work)->data;
2294 gtk_widget_grab_focus (item);
2296 case GTK_SCROLL_JUMP:
2297 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2299 for (item = NULL, work = list->children; work; work =work->next)
2301 item = GTK_WIDGET (work->data);
2302 if (item->allocation.y <= new_value &&
2303 item->allocation.y + item->allocation.height > new_value)
2307 gtk_widget_grab_focus (item);
2315 gtk_list_horizontal_timeout (GtkWidget *list)
2317 GdkEventMotion event;
2319 memset (&event, 0, sizeof (event));
2321 GDK_THREADS_ENTER ();
2323 GTK_LIST (list)->htimer = 0;
2325 event.type = GDK_MOTION_NOTIFY;
2326 event.send_event = TRUE;
2328 gtk_list_motion_notify (list, &event);
2330 GDK_THREADS_LEAVE ();
2336 gtk_list_vertical_timeout (GtkWidget *list)
2338 GdkEventMotion event;
2340 memset (&event, 0, sizeof (event));
2342 GDK_THREADS_ENTER ();
2344 GTK_LIST (list)->vtimer = 0;
2346 event.type = GDK_MOTION_NOTIFY;
2347 event.send_event = TRUE;
2349 gtk_list_motion_notify (list, &event);
2351 GDK_THREADS_LEAVE ();
2357 /* Private GtkListItem Signal Functions :
2359 * gtk_list_signal_toggle_focus_row
2360 * gtk_list_signal_select_all
2361 * gtk_list_signal_unselect_all
2362 * gtk_list_signal_undo_selection
2363 * gtk_list_signal_start_selection
2364 * gtk_list_signal_end_selection
2365 * gtk_list_signal_extend_selection
2366 * gtk_list_signal_scroll_horizontal
2367 * gtk_list_signal_scroll_vertical
2368 * gtk_list_signal_toggle_add_mode
2369 * gtk_list_signal_item_select
2370 * gtk_list_signal_item_deselect
2371 * gtk_list_signal_item_toggle
2374 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2377 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2378 g_return_if_fail (GTK_IS_LIST (list));
2380 gtk_list_toggle_focus_row (list);
2384 gtk_list_signal_select_all (GtkListItem *list_item,
2387 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2388 g_return_if_fail (GTK_IS_LIST (list));
2390 gtk_list_select_all (list);
2394 gtk_list_signal_unselect_all (GtkListItem *list_item,
2397 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2398 g_return_if_fail (GTK_IS_LIST (list));
2400 gtk_list_unselect_all (list);
2404 gtk_list_signal_undo_selection (GtkListItem *list_item,
2407 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2408 g_return_if_fail (GTK_IS_LIST (list));
2410 gtk_list_undo_selection (list);
2414 gtk_list_signal_start_selection (GtkListItem *list_item,
2417 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2418 g_return_if_fail (GTK_IS_LIST (list));
2420 gtk_list_start_selection (list);
2424 gtk_list_signal_end_selection (GtkListItem *list_item,
2427 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2428 g_return_if_fail (GTK_IS_LIST (list));
2430 gtk_list_end_selection (list);
2434 gtk_list_signal_extend_selection (GtkListItem *list_item,
2435 GtkScrollType scroll_type,
2437 gboolean auto_start_selection,
2440 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2441 g_return_if_fail (GTK_IS_LIST (list));
2443 gtk_list_extend_selection (list, scroll_type, position,
2444 auto_start_selection);
2448 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2449 GtkScrollType scroll_type,
2453 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2454 g_return_if_fail (GTK_IS_LIST (list));
2456 gtk_list_scroll_horizontal (list, scroll_type, position);
2460 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2461 GtkScrollType scroll_type,
2465 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2466 g_return_if_fail (GTK_IS_LIST (list));
2468 gtk_list_scroll_vertical (list, scroll_type, position);
2472 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2475 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2476 g_return_if_fail (GTK_IS_LIST (list));
2478 gtk_list_toggle_add_mode (list);
2482 gtk_list_signal_item_select (GtkListItem *list_item,
2489 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2490 g_return_if_fail (GTK_IS_LIST (list));
2492 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2495 switch (list->selection_mode)
2497 case GTK_SELECTION_SINGLE:
2498 case GTK_SELECTION_BROWSE:
2500 selection = list->selection;
2504 tmp_list = selection;
2505 selection = selection->next;
2507 if (tmp_list->data == list_item)
2508 sel_list = tmp_list;
2510 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2515 list->selection = g_list_prepend (list->selection, list_item);
2516 gtk_widget_ref (GTK_WIDGET (list_item));
2518 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2520 case GTK_SELECTION_MULTIPLE:
2521 if (list->anchor >= 0)
2527 gtk_list_signal_item_deselect (GtkListItem *list_item,
2532 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2533 g_return_if_fail (GTK_IS_LIST (list));
2535 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2538 node = g_list_find (list->selection, list_item);
2542 list->selection = g_list_remove_link (list->selection, node);
2543 g_list_free_1 (node);
2544 gtk_widget_unref (GTK_WIDGET (list_item));
2545 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2550 gtk_list_signal_item_toggle (GtkListItem *list_item,
2553 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2554 g_return_if_fail (GTK_IS_LIST (list));
2556 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
2557 list->selection_mode == GTK_SELECTION_MULTIPLE) &&
2558 GTK_WIDGET (list_item)->state == GTK_STATE_NORMAL)
2560 gtk_widget_set_state (GTK_WIDGET (list_item), GTK_STATE_SELECTED);
2564 switch (GTK_WIDGET (list_item)->state)
2566 case GTK_STATE_SELECTED:
2567 gtk_list_signal_item_select (list_item, list);
2569 case GTK_STATE_NORMAL:
2570 gtk_list_signal_item_deselect (list_item, list);
2578 gtk_list_signal_drag_begin (GtkWidget *widget,
2579 GdkDragContext *context,
2582 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2583 g_return_if_fail (GTK_IS_LIST (list));
2585 gtk_list_drag_begin (GTK_WIDGET (list), context);
2589 gtk_list_drag_begin (GtkWidget *widget,
2590 GdkDragContext *context)
2594 g_return_if_fail (GTK_IS_LIST (widget));
2595 g_return_if_fail (context != NULL);
2597 list = GTK_LIST (widget);
2599 if (list->drag_selection)
2601 gtk_list_end_drag_selection (list);
2603 switch (list->selection_mode)
2605 case GTK_SELECTION_MULTIPLE:
2606 gtk_list_end_selection (list);
2608 case GTK_SELECTION_SINGLE:
2609 list->undo_focus_child = NULL;