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
30 #include <string.h> /* memset */
33 #include "gtklistitem.h"
35 #include "gtksignal.h"
37 #include "gtkmarshalers.h"
53 #define SCROLL_TIME 100
55 /*** GtkList Methods ***/
56 static void gtk_list_class_init (GtkListClass *klass);
57 static void gtk_list_init (GtkList *list);
58 static void gtk_list_set_arg (GtkObject *object,
61 static void gtk_list_get_arg (GtkObject *object,
64 /*** GtkObject Methods ***/
65 static void gtk_list_dispose (GObject *object);
67 /*** GtkWidget Methods ***/
68 static void gtk_list_size_request (GtkWidget *widget,
69 GtkRequisition *requisition);
70 static void gtk_list_size_allocate (GtkWidget *widget,
71 GtkAllocation *allocation);
72 static void gtk_list_realize (GtkWidget *widget);
73 static void gtk_list_unmap (GtkWidget *widget);
74 static void gtk_list_style_set (GtkWidget *widget,
75 GtkStyle *previous_style);
76 static gint gtk_list_motion_notify (GtkWidget *widget,
77 GdkEventMotion *event);
78 static gint gtk_list_button_press (GtkWidget *widget,
79 GdkEventButton *event);
80 static gint gtk_list_button_release (GtkWidget *widget,
81 GdkEventButton *event);
83 static gboolean gtk_list_focus (GtkWidget *widget,
84 GtkDirectionType direction);
86 /*** GtkContainer Methods ***/
87 static void gtk_list_add (GtkContainer *container,
89 static void gtk_list_remove (GtkContainer *container,
91 static void gtk_list_forall (GtkContainer *container,
92 gboolean include_internals,
94 gpointer callback_data);
95 static GtkType gtk_list_child_type (GtkContainer *container);
96 static void gtk_list_set_focus_child (GtkContainer *container,
99 /*** GtkList Private Functions ***/
100 static void gtk_list_move_focus_child (GtkList *list,
101 GtkScrollType scroll_type,
103 static gint gtk_list_horizontal_timeout (GtkWidget *list);
104 static gint gtk_list_vertical_timeout (GtkWidget *list);
105 static void gtk_list_remove_items_internal (GtkList *list,
109 /*** GtkList Selection Methods ***/
110 static void gtk_real_list_select_child (GtkList *list,
112 static void gtk_real_list_unselect_child (GtkList *list,
115 /*** GtkList Selection Functions ***/
116 static void gtk_list_set_anchor (GtkList *list,
119 GtkWidget *undo_focus_child);
120 static void gtk_list_fake_unselect_all (GtkList *list,
122 static void gtk_list_fake_toggle_row (GtkList *list,
124 static void gtk_list_update_extended_selection (GtkList *list,
126 static void gtk_list_reset_extended_selection (GtkList *list);
128 /*** GtkListItem Signal Functions ***/
129 static void gtk_list_signal_drag_begin (GtkWidget *widget,
130 GdkDragContext *context,
132 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
134 static void gtk_list_signal_select_all (GtkListItem *list_item,
136 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
138 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
140 static void gtk_list_signal_start_selection (GtkListItem *list_item,
142 static void gtk_list_signal_end_selection (GtkListItem *list_item,
144 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
145 GtkScrollType scroll_type,
147 gboolean auto_start_selection,
149 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
150 GtkScrollType scroll_type,
153 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
154 GtkScrollType scroll_type,
157 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
159 static void gtk_list_signal_item_select (GtkListItem *list_item,
161 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
163 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
167 static void gtk_list_drag_begin (GtkWidget *widget,
168 GdkDragContext *context);
171 static GtkContainerClass *parent_class = NULL;
172 static guint list_signals[LAST_SIGNAL] = { 0 };
174 static const gchar vadjustment_key[] = "gtk-vadjustment";
175 static guint vadjustment_key_id = 0;
176 static const gchar hadjustment_key[] = "gtk-hadjustment";
177 static guint hadjustment_key_id = 0;
180 gtk_list_get_type (void)
182 static GtkType list_type = 0;
186 static const GtkTypeInfo list_info =
190 sizeof (GtkListClass),
191 (GtkClassInitFunc) gtk_list_class_init,
192 (GtkObjectInitFunc) gtk_list_init,
193 /* reserved_1 */ NULL,
194 /* reserved_2 */ NULL,
195 (GtkClassInitFunc) NULL,
199 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
206 gtk_list_class_init (GtkListClass *class)
208 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
209 GtkObjectClass *object_class;
210 GtkWidgetClass *widget_class;
211 GtkContainerClass *container_class;
213 object_class = (GtkObjectClass*) class;
214 widget_class = (GtkWidgetClass*) class;
215 container_class = (GtkContainerClass*) class;
217 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
219 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
220 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
222 gobject_class->dispose = gtk_list_dispose;
225 object_class->set_arg = gtk_list_set_arg;
226 object_class->get_arg = gtk_list_get_arg;
228 widget_class->unmap = gtk_list_unmap;
229 widget_class->style_set = gtk_list_style_set;
230 widget_class->realize = gtk_list_realize;
231 widget_class->button_press_event = gtk_list_button_press;
232 widget_class->button_release_event = gtk_list_button_release;
233 widget_class->motion_notify_event = gtk_list_motion_notify;
234 widget_class->size_request = gtk_list_size_request;
235 widget_class->size_allocate = gtk_list_size_allocate;
236 widget_class->drag_begin = gtk_list_drag_begin;
237 widget_class->focus = gtk_list_focus;
239 container_class->add = gtk_list_add;
240 container_class->remove = gtk_list_remove;
241 container_class->forall = gtk_list_forall;
242 container_class->child_type = gtk_list_child_type;
243 container_class->set_focus_child = gtk_list_set_focus_child;
245 class->selection_changed = NULL;
246 class->select_child = gtk_real_list_select_child;
247 class->unselect_child = gtk_real_list_unselect_child;
249 list_signals[SELECTION_CHANGED] =
250 gtk_signal_new (I_("selection-changed"),
252 GTK_CLASS_TYPE (object_class),
253 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
254 _gtk_marshal_VOID__VOID,
256 list_signals[SELECT_CHILD] =
257 gtk_signal_new (I_("select_child"),
259 GTK_CLASS_TYPE (object_class),
260 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
261 _gtk_marshal_VOID__OBJECT,
264 list_signals[UNSELECT_CHILD] =
265 gtk_signal_new (I_("unselect_child"),
267 GTK_CLASS_TYPE (object_class),
268 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
269 _gtk_marshal_VOID__OBJECT,
273 gtk_object_add_arg_type ("GtkList::selection-mode",
274 GTK_TYPE_SELECTION_MODE,
275 GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
280 gtk_list_init (GtkList *list)
282 list->children = NULL;
283 list->selection = NULL;
285 list->undo_selection = NULL;
286 list->undo_unselection = NULL;
288 list->last_focus_child = NULL;
289 list->undo_focus_child = NULL;
296 list->anchor_state = GTK_STATE_SELECTED;
298 list->selection_mode = GTK_SELECTION_SINGLE;
299 list->drag_selection = FALSE;
300 list->add_mode = FALSE;
304 gtk_list_set_arg (GtkObject *object,
308 GtkList *list = GTK_LIST (object);
312 case ARG_SELECTION_MODE:
313 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
319 gtk_list_get_arg (GtkObject *object,
323 GtkList *list = GTK_LIST (object);
327 case ARG_SELECTION_MODE:
328 GTK_VALUE_ENUM (*arg) = list->selection_mode;
331 arg->type = GTK_TYPE_INVALID;
339 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
343 /* Private GtkObject Methods :
348 gtk_list_dispose (GObject *object)
350 gtk_list_clear_items (GTK_LIST (object), 0, -1);
352 G_OBJECT_CLASS (parent_class)->dispose (object);
356 /* Private GtkWidget Methods :
358 * gtk_list_size_request
359 * gtk_list_size_allocate
362 * gtk_list_motion_notify
363 * gtk_list_button_press
364 * gtk_list_button_release
367 gtk_list_size_request (GtkWidget *widget,
368 GtkRequisition *requisition)
374 g_return_if_fail (GTK_IS_LIST (widget));
375 g_return_if_fail (requisition != NULL);
377 list = GTK_LIST (widget);
378 requisition->width = 0;
379 requisition->height = 0;
381 children = list->children;
384 child = children->data;
385 children = children->next;
387 if (GTK_WIDGET_VISIBLE (child))
389 GtkRequisition child_requisition;
391 gtk_widget_size_request (child, &child_requisition);
393 requisition->width = MAX (requisition->width,
394 child_requisition.width);
395 requisition->height += child_requisition.height;
399 requisition->width += GTK_CONTAINER (list)->border_width * 2;
400 requisition->height += GTK_CONTAINER (list)->border_width * 2;
402 requisition->width = MAX (requisition->width, 1);
403 requisition->height = MAX (requisition->height, 1);
407 gtk_list_size_allocate (GtkWidget *widget,
408 GtkAllocation *allocation)
412 GtkAllocation child_allocation;
415 g_return_if_fail (GTK_IS_LIST (widget));
416 g_return_if_fail (allocation != NULL);
418 list = GTK_LIST (widget);
420 widget->allocation = *allocation;
421 if (GTK_WIDGET_REALIZED (widget))
422 gdk_window_move_resize (widget->window,
423 allocation->x, allocation->y,
424 allocation->width, allocation->height);
428 child_allocation.x = GTK_CONTAINER (list)->border_width;
429 child_allocation.y = GTK_CONTAINER (list)->border_width;
430 child_allocation.width = MAX (1, (gint)allocation->width -
431 child_allocation.x * 2);
433 children = list->children;
437 child = children->data;
438 children = children->next;
440 if (GTK_WIDGET_VISIBLE (child))
442 GtkRequisition child_requisition;
443 gtk_widget_get_child_requisition (child, &child_requisition);
445 child_allocation.height = child_requisition.height;
447 gtk_widget_size_allocate (child, &child_allocation);
449 child_allocation.y += child_allocation.height;
456 gtk_list_realize (GtkWidget *widget)
458 GdkWindowAttr attributes;
459 gint attributes_mask;
461 g_return_if_fail (GTK_IS_LIST (widget));
463 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
465 attributes.window_type = GDK_WINDOW_CHILD;
466 attributes.x = widget->allocation.x;
467 attributes.y = widget->allocation.y;
468 attributes.width = widget->allocation.width;
469 attributes.height = widget->allocation.height;
470 attributes.wclass = GDK_INPUT_OUTPUT;
471 attributes.visual = gtk_widget_get_visual (widget);
472 attributes.colormap = gtk_widget_get_colormap (widget);
473 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
475 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
477 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
478 &attributes, attributes_mask);
479 gdk_window_set_user_data (widget->window, widget);
481 widget->style = gtk_style_attach (widget->style, widget->window);
482 gdk_window_set_background (widget->window,
483 &widget->style->base[GTK_STATE_NORMAL]);
487 list_has_grab (GtkList *list)
489 return (GTK_WIDGET_HAS_GRAB (list) &&
490 gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (list))));
495 gtk_list_unmap (GtkWidget *widget)
499 g_return_if_fail (GTK_IS_LIST (widget));
501 if (!GTK_WIDGET_MAPPED (widget))
504 list = GTK_LIST (widget);
506 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
508 if (list_has_grab (list))
510 gtk_list_end_drag_selection (list);
512 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_MULTIPLE)
513 gtk_list_end_selection (list);
516 gdk_window_hide (widget->window);
520 gtk_list_motion_notify (GtkWidget *widget,
521 GdkEventMotion *event)
524 GtkWidget *item = NULL;
526 GtkContainer *container;
534 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
535 g_return_val_if_fail (event != NULL, FALSE);
537 list = GTK_LIST (widget);
539 if (!list->drag_selection || !list->children)
542 container = GTK_CONTAINER (widget);
544 if (event->is_hint || event->window != widget->window)
545 gdk_window_get_pointer (widget->window, &x, &y, NULL);
552 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
554 /* horizontal autoscrolling */
555 if (adj && widget->allocation.width > adj->page_size &&
556 (x < adj->value || x >= adj->value + adj->page_size))
558 if (list->htimer == 0)
560 list->htimer = gdk_threads_add_timeout
561 (SCROLL_TIME, (GSourceFunc) gtk_list_horizontal_timeout, widget);
563 if (!((x < adj->value && adj->value <= 0) ||
564 (x > adj->value + adj->page_size &&
565 adj->value >= adj->upper - adj->page_size)))
570 value = adj->value + (x - adj->value) / 2 - 1;
572 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
574 gtk_adjustment_set_value (adj,
576 adj->upper - adj->page_size));
584 /* vertical autoscrolling */
585 for (work = list->children; work; length++, work = work->next)
589 item = GTK_WIDGET (work->data);
590 if (item->allocation.y > y ||
591 (item->allocation.y <= y &&
592 item->allocation.y + item->allocation.height > y))
596 if (work->data == container->focus_child)
603 if (list->vtimer != 0)
606 if (!((y < 0 && focus_row == 0) ||
607 (y > widget->allocation.height && focus_row >= length - 1)))
608 list->vtimer = gdk_threads_add_timeout (SCROLL_TIME,
609 (GSourceFunc) gtk_list_vertical_timeout,
612 if (row != focus_row)
613 gtk_widget_grab_focus (item);
615 switch (list->selection_mode)
617 case GTK_SELECTION_BROWSE:
618 gtk_list_select_child (list, item);
620 case GTK_SELECTION_MULTIPLE:
621 gtk_list_update_extended_selection (list, row);
631 gtk_list_button_press (GtkWidget *widget,
632 GdkEventButton *event)
637 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
638 g_return_val_if_fail (event != NULL, FALSE);
640 if (event->button != 1)
643 list = GTK_LIST (widget);
644 item = gtk_get_event_widget ((GdkEvent*) event);
646 while (item && !GTK_IS_LIST_ITEM (item))
649 if (item && (item->parent == widget))
654 if (event->type == GDK_BUTTON_PRESS)
656 gtk_grab_add (widget);
657 list->drag_selection = TRUE;
659 else if (list_has_grab (list))
660 gtk_list_end_drag_selection (list);
662 if (!GTK_WIDGET_HAS_FOCUS(item))
663 gtk_widget_grab_focus (item);
667 list->add_mode = FALSE;
668 gtk_widget_queue_draw (item);
671 switch (list->selection_mode)
673 case GTK_SELECTION_SINGLE:
674 if (event->type != GDK_BUTTON_PRESS)
675 gtk_list_select_child (list, item);
677 list->undo_focus_child = item;
680 case GTK_SELECTION_BROWSE:
683 case GTK_SELECTION_MULTIPLE:
684 focus_row = g_list_index (list->children, item);
686 if (list->last_focus_child)
687 last_focus_row = g_list_index (list->children,
688 list->last_focus_child);
691 last_focus_row = focus_row;
692 list->last_focus_child = item;
695 if (event->type != GDK_BUTTON_PRESS)
697 if (list->anchor >= 0)
699 gtk_list_update_extended_selection (list, focus_row);
700 gtk_list_end_selection (list);
702 gtk_list_select_child (list, item);
706 if (event->state & GDK_CONTROL_MASK)
708 if (event->state & GDK_SHIFT_MASK)
710 if (list->anchor < 0)
712 g_list_free (list->undo_selection);
713 g_list_free (list->undo_unselection);
714 list->undo_selection = NULL;
715 list->undo_unselection = NULL;
717 list->anchor = last_focus_row;
718 list->drag_pos = last_focus_row;
719 list->undo_focus_child = list->last_focus_child;
721 gtk_list_update_extended_selection (list, focus_row);
725 if (list->anchor < 0)
726 gtk_list_set_anchor (list, TRUE,
727 focus_row, list->last_focus_child);
729 gtk_list_update_extended_selection (list, focus_row);
734 if (event->state & GDK_SHIFT_MASK)
736 gtk_list_set_anchor (list, FALSE,
737 last_focus_row, list->last_focus_child);
738 gtk_list_update_extended_selection (list, focus_row);
742 if (list->anchor < 0)
743 gtk_list_set_anchor (list, FALSE, focus_row,
744 list->last_focus_child);
746 gtk_list_update_extended_selection (list, focus_row);
760 gtk_list_button_release (GtkWidget *widget,
761 GdkEventButton *event)
766 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
767 g_return_val_if_fail (event != NULL, FALSE);
769 list = GTK_LIST (widget);
771 /* we don't handle button 2 and 3 */
772 if (event->button != 1)
775 if (list->drag_selection)
777 gtk_list_end_drag_selection (list);
779 switch (list->selection_mode)
781 case GTK_SELECTION_MULTIPLE:
782 if (!(event->state & GDK_SHIFT_MASK))
783 gtk_list_end_selection (list);
786 case GTK_SELECTION_SINGLE:
788 item = gtk_get_event_widget ((GdkEvent*) event);
790 while (item && !GTK_IS_LIST_ITEM (item))
793 if (item && item->parent == widget)
795 if (list->undo_focus_child == item)
796 gtk_list_toggle_row (list, item);
798 list->undo_focus_child = NULL;
812 gtk_list_style_set (GtkWidget *widget,
813 GtkStyle *previous_style)
815 g_return_if_fail (widget != NULL);
817 if (previous_style && GTK_WIDGET_REALIZED (widget))
818 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
821 /* GtkContainer Methods :
825 * gtk_list_child_type
826 * gtk_list_set_focus_child
830 gtk_list_add (GtkContainer *container,
835 g_return_if_fail (GTK_IS_LIST (container));
836 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
838 item_list = g_list_alloc ();
839 item_list->data = widget;
841 gtk_list_append_items (GTK_LIST (container), item_list);
845 gtk_list_remove (GtkContainer *container,
850 g_return_if_fail (GTK_IS_LIST (container));
851 g_return_if_fail (widget != NULL);
852 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
854 item_list = g_list_alloc ();
855 item_list->data = widget;
857 gtk_list_remove_items (GTK_LIST (container), item_list);
859 g_list_free (item_list);
863 gtk_list_forall (GtkContainer *container,
864 gboolean include_internals,
865 GtkCallback callback,
866 gpointer callback_data)
872 g_return_if_fail (GTK_IS_LIST (container));
873 g_return_if_fail (callback != NULL);
875 list = GTK_LIST (container);
876 children = list->children;
880 child = children->data;
881 children = children->next;
883 (* callback) (child, callback_data);
888 gtk_list_child_type (GtkContainer *container)
890 return GTK_TYPE_LIST_ITEM;
894 gtk_list_set_focus_child (GtkContainer *container,
899 g_return_if_fail (GTK_IS_LIST (container));
902 g_return_if_fail (GTK_IS_WIDGET (child));
904 list = GTK_LIST (container);
906 if (child != container->focus_child)
908 if (container->focus_child)
910 list->last_focus_child = container->focus_child;
911 gtk_widget_unref (container->focus_child);
913 container->focus_child = child;
914 if (container->focus_child)
915 gtk_widget_ref (container->focus_child);
918 /* check for v adjustment */
919 if (container->focus_child)
921 GtkAdjustment *adjustment;
923 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
926 gtk_adjustment_clamp_page (adjustment,
927 container->focus_child->allocation.y,
928 (container->focus_child->allocation.y +
929 container->focus_child->allocation.height));
930 switch (list->selection_mode)
932 case GTK_SELECTION_BROWSE:
933 gtk_list_select_child (list, child);
935 case GTK_SELECTION_MULTIPLE:
936 if (!list->last_focus_child && !list->add_mode)
938 list->undo_focus_child = list->last_focus_child;
939 gtk_list_unselect_all (list);
940 gtk_list_select_child (list, child);
950 gtk_list_focus (GtkWidget *widget,
951 GtkDirectionType direction)
953 gint return_val = FALSE;
954 GtkContainer *container;
956 container = GTK_CONTAINER (widget);
958 if (container->focus_child == NULL ||
959 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
961 if (GTK_LIST (container)->last_focus_child)
962 gtk_container_set_focus_child
963 (container, GTK_LIST (container)->last_focus_child);
965 if (GTK_WIDGET_CLASS (parent_class)->focus)
966 return_val = GTK_WIDGET_CLASS (parent_class)->focus (widget,
974 list = GTK_LIST (container);
975 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
976 gtk_list_end_selection (list);
978 if (container->focus_child)
979 list->last_focus_child = container->focus_child;
986 /* Public GtkList Methods :
988 * gtk_list_insert_items
989 * gtk_list_append_items
990 * gtk_list_prepend_items
991 * gtk_list_remove_items
992 * gtk_list_remove_items_no_unref
993 * gtk_list_clear_items
995 * gtk_list_child_position
998 gtk_list_insert_items (GtkList *list,
1007 g_return_if_fail (GTK_IS_LIST (list));
1012 gtk_list_end_drag_selection (list);
1013 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1014 gtk_list_end_selection (list);
1019 widget = tmp_list->data;
1020 tmp_list = tmp_list->next;
1022 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1023 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1024 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1026 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1027 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1029 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1030 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1032 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1033 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1035 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1036 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1038 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1039 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1041 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1042 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1044 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1045 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1047 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1048 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1050 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1051 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1053 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1054 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1056 gtk_signal_connect (GTK_OBJECT (widget), "select",
1057 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1059 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1060 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1062 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1063 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1068 nchildren = g_list_length (list->children);
1069 if ((position < 0) || (position > nchildren))
1070 position = nchildren;
1072 if (position == nchildren)
1076 tmp_list = g_list_last (list->children);
1077 tmp_list->next = items;
1078 items->prev = tmp_list;
1082 list->children = items;
1087 tmp_list = g_list_nth (list->children, position);
1088 last = g_list_last (items);
1091 tmp_list->prev->next = items;
1092 last->next = tmp_list;
1093 items->prev = tmp_list->prev;
1094 tmp_list->prev = last;
1096 if (tmp_list == list->children)
1097 list->children = items;
1100 if (list->children && !list->selection &&
1101 (list->selection_mode == GTK_SELECTION_BROWSE))
1103 widget = list->children->data;
1104 gtk_list_select_child (list, widget);
1109 gtk_list_append_items (GtkList *list,
1112 g_return_if_fail (GTK_IS_LIST (list));
1114 gtk_list_insert_items (list, items, -1);
1118 gtk_list_prepend_items (GtkList *list,
1121 g_return_if_fail (GTK_IS_LIST (list));
1123 gtk_list_insert_items (list, items, 0);
1127 gtk_list_remove_items (GtkList *list,
1130 gtk_list_remove_items_internal (list, items, FALSE);
1134 gtk_list_remove_items_no_unref (GtkList *list,
1137 gtk_list_remove_items_internal (list, items, TRUE);
1141 gtk_list_clear_items (GtkList *list,
1145 GtkContainer *container;
1147 GtkWidget *new_focus_child = NULL;
1152 gboolean grab_focus = FALSE;
1154 g_return_if_fail (GTK_IS_LIST (list));
1156 nchildren = g_list_length (list->children);
1161 if ((end < 0) || (end > nchildren))
1167 container = GTK_CONTAINER (list);
1169 gtk_list_end_drag_selection (list);
1170 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1172 if (list->anchor >= 0)
1173 gtk_list_end_selection (list);
1175 gtk_list_reset_extended_selection (list);
1178 start_list = g_list_nth (list->children, start);
1179 end_list = g_list_nth (list->children, end);
1181 if (start_list->prev)
1182 start_list->prev->next = end_list;
1183 if (end_list && end_list->prev)
1184 end_list->prev->next = NULL;
1186 end_list->prev = start_list->prev;
1187 if (start_list == list->children)
1188 list->children = end_list;
1190 if (container->focus_child)
1192 if (g_list_find (start_list, container->focus_child))
1194 if (start_list->prev)
1195 new_focus_child = start_list->prev->data;
1196 else if (list->children)
1197 new_focus_child = list->children->data;
1199 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1204 tmp_list = start_list;
1207 widget = tmp_list->data;
1208 tmp_list = tmp_list->next;
1210 gtk_widget_ref (widget);
1212 if (widget->state == GTK_STATE_SELECTED)
1213 gtk_list_unselect_child (list, widget);
1215 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1216 gtk_widget_unparent (widget);
1218 if (widget == list->undo_focus_child)
1219 list->undo_focus_child = NULL;
1220 if (widget == list->last_focus_child)
1221 list->last_focus_child = NULL;
1223 gtk_widget_unref (widget);
1226 g_list_free (start_list);
1228 if (new_focus_child)
1231 gtk_widget_grab_focus (new_focus_child);
1232 else if (container->focus_child)
1233 gtk_container_set_focus_child (container, new_focus_child);
1235 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1236 list->selection_mode == GTK_SELECTION_MULTIPLE) && !list->selection)
1238 list->last_focus_child = new_focus_child;
1239 gtk_list_select_child (list, new_focus_child);
1243 if (GTK_WIDGET_VISIBLE (list))
1244 gtk_widget_queue_resize (GTK_WIDGET (list));
1248 gtk_list_child_position (GtkList *list,
1254 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1255 g_return_val_if_fail (child != NULL, -1);
1258 children = list->children;
1262 if (child == GTK_WIDGET (children->data))
1266 children = children->next;
1273 /* Private GtkList Insert/Remove Item Functions:
1275 * gtk_list_remove_items_internal
1278 gtk_list_remove_items_internal (GtkList *list,
1283 GtkWidget *new_focus_child;
1284 GtkWidget *old_focus_child;
1285 GtkContainer *container;
1288 gboolean grab_focus = FALSE;
1290 g_return_if_fail (GTK_IS_LIST (list));
1295 container = GTK_CONTAINER (list);
1297 gtk_list_end_drag_selection (list);
1298 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1300 if (list->anchor >= 0)
1301 gtk_list_end_selection (list);
1303 gtk_list_reset_extended_selection (list);
1309 widget = tmp_list->data;
1310 tmp_list = tmp_list->next;
1312 if (widget->state == GTK_STATE_SELECTED)
1313 gtk_list_unselect_child (list, widget);
1316 if (container->focus_child)
1318 old_focus_child = new_focus_child = container->focus_child;
1319 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1323 old_focus_child = new_focus_child = list->last_focus_child;
1328 widget = tmp_list->data;
1329 tmp_list = tmp_list->next;
1331 gtk_widget_ref (widget);
1333 gtk_widget_ref (widget);
1335 if (widget == new_focus_child)
1337 work = g_list_find (list->children, widget);
1342 new_focus_child = work->next->data;
1343 else if (list->children != work && work->prev)
1344 new_focus_child = work->prev->data;
1346 new_focus_child = NULL;
1350 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1351 list->children = g_list_remove (list->children, widget);
1352 gtk_widget_unparent (widget);
1354 if (widget == list->undo_focus_child)
1355 list->undo_focus_child = NULL;
1356 if (widget == list->last_focus_child)
1357 list->last_focus_child = NULL;
1359 gtk_widget_unref (widget);
1362 if (new_focus_child && new_focus_child != old_focus_child)
1365 gtk_widget_grab_focus (new_focus_child);
1366 else if (container->focus_child)
1367 gtk_container_set_focus_child (container, new_focus_child);
1369 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1371 list->last_focus_child = new_focus_child;
1372 gtk_list_select_child (list, new_focus_child);
1376 if (GTK_WIDGET_VISIBLE (list))
1377 gtk_widget_queue_resize (GTK_WIDGET (list));
1381 /* Public GtkList Selection Methods :
1383 * gtk_list_set_selection_mode
1384 * gtk_list_select_item
1385 * gtk_list_unselect_item
1386 * gtk_list_select_child
1387 * gtk_list_unselect_child
1388 * gtk_list_select_all
1389 * gtk_list_unselect_all
1390 * gtk_list_extend_selection
1391 * gtk_list_end_drag_selection
1392 * gtk_list_start_selection
1393 * gtk_list_end_selection
1394 * gtk_list_toggle_row
1395 * gtk_list_toggle_focus_row
1396 * gtk_list_toggle_add_mode
1397 * gtk_list_undo_selection
1400 gtk_list_set_selection_mode (GtkList *list,
1401 GtkSelectionMode mode)
1403 g_return_if_fail (GTK_IS_LIST (list));
1405 if (list->selection_mode == mode)
1408 list->selection_mode = mode;
1412 case GTK_SELECTION_SINGLE:
1413 case GTK_SELECTION_BROWSE:
1414 gtk_list_unselect_all (list);
1422 gtk_list_select_item (GtkList *list,
1427 g_return_if_fail (GTK_IS_LIST (list));
1429 tmp_list = g_list_nth (list->children, item);
1431 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1435 gtk_list_unselect_item (GtkList *list,
1440 g_return_if_fail (GTK_IS_LIST (list));
1442 tmp_list = g_list_nth (list->children, item);
1444 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1448 gtk_list_select_child (GtkList *list,
1451 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1455 gtk_list_unselect_child (GtkList *list,
1458 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1462 gtk_list_select_all (GtkList *list)
1464 GtkContainer *container;
1466 g_return_if_fail (GTK_IS_LIST (list));
1468 if (!list->children)
1471 if (list_has_grab (list))
1472 gtk_list_end_drag_selection (list);
1474 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1475 gtk_list_end_selection (list);
1477 container = GTK_CONTAINER (list);
1479 switch (list->selection_mode)
1481 case GTK_SELECTION_BROWSE:
1482 if (container->focus_child)
1484 gtk_list_select_child (list, container->focus_child);
1488 case GTK_SELECTION_MULTIPLE:
1489 g_list_free (list->undo_selection);
1490 g_list_free (list->undo_unselection);
1491 list->undo_selection = NULL;
1492 list->undo_unselection = NULL;
1494 if (list->children &&
1495 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1496 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1498 list->anchor_state = GTK_STATE_SELECTED;
1501 list->undo_focus_child = container->focus_child;
1502 gtk_list_update_extended_selection (list, g_list_length(list->children));
1503 gtk_list_end_selection (list);
1511 gtk_list_unselect_all (GtkList *list)
1513 GtkContainer *container;
1517 g_return_if_fail (GTK_IS_LIST (list));
1519 if (!list->children)
1522 if (list_has_grab (list))
1523 gtk_list_end_drag_selection (list);
1525 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1526 gtk_list_end_selection (list);
1528 container = GTK_CONTAINER (list);
1530 switch (list->selection_mode)
1532 case GTK_SELECTION_BROWSE:
1533 if (container->focus_child)
1535 gtk_list_select_child (list, container->focus_child);
1539 case GTK_SELECTION_MULTIPLE:
1540 gtk_list_reset_extended_selection (list);
1546 work = list->selection;
1552 gtk_list_unselect_child (list, item);
1557 gtk_list_extend_selection (GtkList *list,
1558 GtkScrollType scroll_type,
1560 gboolean auto_start_selection)
1562 GtkContainer *container;
1564 g_return_if_fail (GTK_IS_LIST (list));
1566 if (list_has_grab (list) ||
1567 list->selection_mode != GTK_SELECTION_MULTIPLE)
1570 container = GTK_CONTAINER (list);
1572 if (auto_start_selection)
1576 focus_row = g_list_index (list->children, container->focus_child);
1577 gtk_list_set_anchor (list, list->add_mode, focus_row,
1578 container->focus_child);
1580 else if (list->anchor < 0)
1583 gtk_list_move_focus_child (list, scroll_type, position);
1584 gtk_list_update_extended_selection
1585 (list, g_list_index (list->children, container->focus_child));
1589 gtk_list_end_drag_selection (GtkList *list)
1591 g_return_if_fail (GTK_IS_LIST (list));
1593 list->drag_selection = FALSE;
1594 if (GTK_WIDGET_HAS_GRAB (list))
1595 gtk_grab_remove (GTK_WIDGET (list));
1599 g_source_remove (list->htimer);
1604 g_source_remove (list->vtimer);
1610 gtk_list_start_selection (GtkList *list)
1612 GtkContainer *container;
1615 g_return_if_fail (GTK_IS_LIST (list));
1617 if (list_has_grab (list))
1620 container = GTK_CONTAINER (list);
1622 if ((focus_row = g_list_index (list->selection, container->focus_child))
1624 gtk_list_set_anchor (list, list->add_mode,
1625 focus_row, container->focus_child);
1629 gtk_list_end_selection (GtkList *list)
1638 g_return_if_fail (GTK_IS_LIST (list));
1640 if (list_has_grab (list) || list->anchor < 0)
1643 i = MIN (list->anchor, list->drag_pos);
1644 e = MAX (list->anchor, list->drag_pos);
1646 top_down = (list->anchor < list->drag_pos);
1649 list->drag_pos = -1;
1651 if (list->undo_selection)
1653 work = list->selection;
1654 list->selection = list->undo_selection;
1655 list->undo_selection = work;
1656 work = list->selection;
1661 item_index = g_list_index (list->children, item);
1662 if (item_index < i || item_index > e)
1664 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1665 gtk_list_unselect_child (list, item);
1666 list->undo_selection = g_list_prepend (list->undo_selection,
1674 for (work = g_list_nth (list->children, i); i <= e;
1675 i++, work = work->next)
1678 if (g_list_find (list->selection, item))
1680 if (item->state == GTK_STATE_NORMAL)
1682 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1683 gtk_list_unselect_child (list, item);
1684 list->undo_selection = g_list_prepend (list->undo_selection,
1688 else if (item->state == GTK_STATE_SELECTED)
1690 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1691 list->undo_unselection = g_list_prepend (list->undo_unselection,
1698 for (work = g_list_nth (list->children, e); i <= e;
1699 e--, work = work->prev)
1702 if (g_list_find (list->selection, item))
1704 if (item->state == GTK_STATE_NORMAL)
1706 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1707 gtk_list_unselect_child (list, item);
1708 list->undo_selection = g_list_prepend (list->undo_selection,
1712 else if (item->state == GTK_STATE_SELECTED)
1714 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1715 list->undo_unselection = g_list_prepend (list->undo_unselection,
1721 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1722 gtk_list_select_child (list, GTK_WIDGET (work->data));
1728 gtk_list_toggle_row (GtkList *list,
1731 g_return_if_fail (GTK_IS_LIST (list));
1732 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1734 switch (list->selection_mode)
1736 case GTK_SELECTION_MULTIPLE:
1737 case GTK_SELECTION_SINGLE:
1738 if (item->state == GTK_STATE_SELECTED)
1740 gtk_list_unselect_child (list, item);
1743 case GTK_SELECTION_BROWSE:
1744 gtk_list_select_child (list, item);
1750 gtk_list_toggle_focus_row (GtkList *list)
1752 GtkContainer *container;
1755 g_return_if_fail (list != 0);
1756 g_return_if_fail (GTK_IS_LIST (list));
1758 container = GTK_CONTAINER (list);
1760 if (list_has_grab (list) || !container->focus_child)
1763 switch (list->selection_mode)
1765 case GTK_SELECTION_SINGLE:
1766 gtk_list_toggle_row (list, container->focus_child);
1768 case GTK_SELECTION_MULTIPLE:
1769 if ((focus_row = g_list_index (list->children, container->focus_child))
1773 g_list_free (list->undo_selection);
1774 g_list_free (list->undo_unselection);
1775 list->undo_selection = NULL;
1776 list->undo_unselection = NULL;
1778 list->anchor = focus_row;
1779 list->drag_pos = focus_row;
1780 list->undo_focus_child = container->focus_child;
1783 gtk_list_fake_toggle_row (list, container->focus_child);
1785 gtk_list_fake_unselect_all (list, container->focus_child);
1787 gtk_list_end_selection (list);
1795 gtk_list_toggle_add_mode (GtkList *list)
1797 GtkContainer *container;
1799 g_return_if_fail (list != 0);
1800 g_return_if_fail (GTK_IS_LIST (list));
1802 if (list_has_grab (list) ||
1803 list->selection_mode != GTK_SELECTION_MULTIPLE)
1806 container = GTK_CONTAINER (list);
1810 list->add_mode = FALSE;
1811 list->anchor_state = GTK_STATE_SELECTED;
1814 list->add_mode = TRUE;
1816 if (container->focus_child)
1817 gtk_widget_queue_draw (container->focus_child);
1821 gtk_list_undo_selection (GtkList *list)
1825 g_return_if_fail (GTK_IS_LIST (list));
1827 if (list->selection_mode != GTK_SELECTION_MULTIPLE ||
1828 list_has_grab (list))
1831 if (list->anchor >= 0)
1832 gtk_list_end_selection (list);
1834 if (!(list->undo_selection || list->undo_unselection))
1836 gtk_list_unselect_all (list);
1840 for (work = list->undo_selection; work; work = work->next)
1841 gtk_list_select_child (list, GTK_WIDGET (work->data));
1843 for (work = list->undo_unselection; work; work = work->next)
1844 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1846 if (list->undo_focus_child)
1848 GtkContainer *container;
1850 container = GTK_CONTAINER (list);
1852 if (container->focus_child &&
1853 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1854 gtk_widget_grab_focus (list->undo_focus_child);
1856 gtk_container_set_focus_child (container, list->undo_focus_child);
1859 list->undo_focus_child = NULL;
1861 g_list_free (list->undo_selection);
1862 g_list_free (list->undo_unselection);
1863 list->undo_selection = NULL;
1864 list->undo_unselection = NULL;
1868 /* Private GtkList Selection Methods :
1870 * gtk_real_list_select_child
1871 * gtk_real_list_unselect_child
1874 gtk_real_list_select_child (GtkList *list,
1877 g_return_if_fail (GTK_IS_LIST (list));
1878 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1880 switch (child->state)
1882 case GTK_STATE_SELECTED:
1883 case GTK_STATE_INSENSITIVE:
1886 gtk_list_item_select (GTK_LIST_ITEM (child));
1892 gtk_real_list_unselect_child (GtkList *list,
1895 g_return_if_fail (GTK_IS_LIST (list));
1896 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1898 if (child->state == GTK_STATE_SELECTED)
1899 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1903 /* Private GtkList Selection Functions :
1905 * gtk_list_set_anchor
1906 * gtk_list_fake_unselect_all
1907 * gtk_list_fake_toggle_row
1908 * gtk_list_update_extended_selection
1909 * gtk_list_reset_extended_selection
1912 gtk_list_set_anchor (GtkList *list,
1915 GtkWidget *undo_focus_child)
1919 g_return_if_fail (GTK_IS_LIST (list));
1921 if (list->selection_mode != GTK_SELECTION_MULTIPLE || list->anchor >= 0)
1924 g_list_free (list->undo_selection);
1925 g_list_free (list->undo_unselection);
1926 list->undo_selection = NULL;
1927 list->undo_unselection = NULL;
1929 if ((work = g_list_nth (list->children, anchor)))
1932 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1935 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1936 list->anchor_state = GTK_STATE_SELECTED;
1940 list->anchor = anchor;
1941 list->drag_pos = anchor;
1942 list->undo_focus_child = undo_focus_child;
1946 gtk_list_fake_unselect_all (GtkList *list,
1951 if (item && item->state == GTK_STATE_NORMAL)
1952 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1954 list->undo_selection = list->selection;
1955 list->selection = NULL;
1957 for (work = list->undo_selection; work; work = work->next)
1958 if (work->data != item)
1959 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1963 gtk_list_fake_toggle_row (GtkList *list,
1969 if (item->state == GTK_STATE_NORMAL)
1971 list->anchor_state = GTK_STATE_SELECTED;
1972 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1976 list->anchor_state = GTK_STATE_NORMAL;
1977 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1982 gtk_list_update_extended_selection (GtkList *list,
1996 length = g_list_length (list->children);
2000 if (list->selection_mode != GTK_SELECTION_MULTIPLE || !list->anchor < 0)
2003 /* extending downwards */
2004 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2006 s2 = list->drag_pos + 1;
2009 /* extending upwards */
2010 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2013 e2 = list->drag_pos - 1;
2015 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2017 e1 = list->drag_pos;
2018 /* row and drag_pos on different sides of anchor :
2019 take back the selection between anchor and drag_pos,
2020 select between anchor and row */
2021 if (row < list->anchor)
2023 s1 = list->anchor + 1;
2025 e2 = list->anchor - 1;
2027 /* take back the selection between anchor and drag_pos */
2031 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2033 s1 = list->drag_pos;
2034 /* row and drag_pos on different sides of anchor :
2035 take back the selection between anchor and drag_pos,
2036 select between anchor and row */
2037 if (row > list->anchor)
2039 e1 = list->anchor - 1;
2040 s2 = list->anchor + 1;
2043 /* take back the selection between anchor and drag_pos */
2048 list->drag_pos = row;
2050 /* restore the elements between s1 and e1 */
2053 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2054 i++, work = work->next)
2056 if (g_list_find (list->selection, work->data))
2057 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2059 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2063 /* extend the selection between s2 and e2 */
2066 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2067 i++, work = work->next)
2068 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2069 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2074 gtk_list_reset_extended_selection (GtkList *list)
2076 g_return_if_fail (list != 0);
2077 g_return_if_fail (GTK_IS_LIST (list));
2079 g_list_free (list->undo_selection);
2080 g_list_free (list->undo_unselection);
2081 list->undo_selection = NULL;
2082 list->undo_unselection = NULL;
2085 list->drag_pos = -1;
2086 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2089 /* Public GtkList Scroll Methods :
2091 * gtk_list_scroll_horizontal
2092 * gtk_list_scroll_vertical
2095 gtk_list_scroll_horizontal (GtkList *list,
2096 GtkScrollType scroll_type,
2101 g_return_if_fail (list != 0);
2102 g_return_if_fail (GTK_IS_LIST (list));
2104 if (list_has_grab (list))
2108 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2111 switch (scroll_type)
2113 case GTK_SCROLL_STEP_UP:
2114 case GTK_SCROLL_STEP_BACKWARD:
2115 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2116 adj->upper - adj->page_size);
2118 case GTK_SCROLL_STEP_DOWN:
2119 case GTK_SCROLL_STEP_FORWARD:
2120 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2121 adj->upper - adj->page_size);
2123 case GTK_SCROLL_PAGE_UP:
2124 case GTK_SCROLL_PAGE_BACKWARD:
2125 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2126 adj->upper - adj->page_size);
2128 case GTK_SCROLL_PAGE_DOWN:
2129 case GTK_SCROLL_PAGE_FORWARD:
2130 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2131 adj->upper - adj->page_size);
2133 case GTK_SCROLL_JUMP:
2134 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2135 adj->lower, adj->upper - adj->page_size);
2140 gtk_adjustment_value_changed (adj);
2144 gtk_list_scroll_vertical (GtkList *list,
2145 GtkScrollType scroll_type,
2148 g_return_if_fail (GTK_IS_LIST (list));
2150 if (list_has_grab (list))
2153 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
2155 GtkContainer *container;
2157 if (list->anchor >= 0)
2160 container = GTK_CONTAINER (list);
2161 list->undo_focus_child = container->focus_child;
2162 gtk_list_move_focus_child (list, scroll_type, position);
2163 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2165 gtk_list_unselect_all (list);
2166 gtk_list_select_child (list, container->focus_child);
2170 gtk_list_move_focus_child (list, scroll_type, position);
2174 /* Private GtkList Scroll/Focus Functions :
2176 * gtk_list_move_focus_child
2177 * gtk_list_horizontal_timeout
2178 * gtk_list_vertical_timeout
2181 gtk_list_move_focus_child (GtkList *list,
2182 GtkScrollType scroll_type,
2185 GtkContainer *container;
2191 g_return_if_fail (list != 0);
2192 g_return_if_fail (GTK_IS_LIST (list));
2194 container = GTK_CONTAINER (list);
2196 if (container->focus_child)
2197 work = g_list_find (list->children, container->focus_child);
2199 work = list->children;
2204 switch (scroll_type)
2206 case GTK_SCROLL_STEP_BACKWARD:
2209 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2211 case GTK_SCROLL_STEP_FORWARD:
2214 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2216 case GTK_SCROLL_PAGE_BACKWARD:
2221 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2225 gboolean correct = FALSE;
2227 new_value = adj->value;
2229 if (item->allocation.y <= adj->value)
2231 new_value = MAX (item->allocation.y + item->allocation.height
2232 - adj->page_size, adj->lower);
2236 if (item->allocation.y > new_value)
2237 for (; work; work = work->prev)
2239 item = GTK_WIDGET (work->data);
2240 if (item->allocation.y <= new_value &&
2241 item->allocation.y + item->allocation.height > new_value)
2245 for (; work; work = work->next)
2247 item = GTK_WIDGET (work->data);
2248 if (item->allocation.y <= new_value &&
2249 item->allocation.y + item->allocation.height > new_value)
2253 if (correct && work && work->next && item->allocation.y < new_value)
2254 item = work->next->data;
2257 item = list->children->data;
2259 gtk_widget_grab_focus (item);
2261 case GTK_SCROLL_PAGE_FORWARD:
2266 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2270 gboolean correct = FALSE;
2272 new_value = adj->value;
2274 if (item->allocation.y + item->allocation.height >=
2275 adj->value + adj->page_size)
2277 new_value = item->allocation.y;
2281 new_value = MIN (new_value + adj->page_size, adj->upper);
2283 if (item->allocation.y > new_value)
2284 for (; work; work = work->prev)
2286 item = GTK_WIDGET (work->data);
2287 if (item->allocation.y <= new_value &&
2288 item->allocation.y + item->allocation.height > new_value)
2292 for (; work; work = work->next)
2294 item = GTK_WIDGET (work->data);
2295 if (item->allocation.y <= new_value &&
2296 item->allocation.y + item->allocation.height > new_value)
2300 if (correct && work && work->prev &&
2301 item->allocation.y + item->allocation.height - 1 > new_value)
2302 item = work->prev->data;
2305 item = g_list_last (work)->data;
2307 gtk_widget_grab_focus (item);
2309 case GTK_SCROLL_JUMP:
2310 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2312 for (item = NULL, work = list->children; work; work =work->next)
2314 item = GTK_WIDGET (work->data);
2315 if (item->allocation.y <= new_value &&
2316 item->allocation.y + item->allocation.height > new_value)
2320 gtk_widget_grab_focus (item);
2328 do_fake_motion (GtkWidget *list)
2330 GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
2332 event->motion.send_event = TRUE;
2334 gtk_list_motion_notify (list, (GdkEventMotion *)event);
2335 gdk_event_free (event);
2339 gtk_list_horizontal_timeout (GtkWidget *list)
2341 GTK_LIST (list)->htimer = 0;
2342 do_fake_motion (list);
2348 gtk_list_vertical_timeout (GtkWidget *list)
2350 GTK_LIST (list)->vtimer = 0;
2351 do_fake_motion (list);
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;
2617 #define __GTK_LIST_C__
2618 #include "gtkaliasdef.c"