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"
52 #define SCROLL_TIME 100
54 /*** GtkList Methods ***/
55 static void gtk_list_class_init (GtkListClass *klass);
56 static void gtk_list_init (GtkList *list);
57 static void gtk_list_set_arg (GtkObject *object,
60 static void gtk_list_get_arg (GtkObject *object,
63 /*** GtkObject Methods ***/
64 static void gtk_list_dispose (GObject *object);
66 /*** GtkWidget Methods ***/
67 static void gtk_list_size_request (GtkWidget *widget,
68 GtkRequisition *requisition);
69 static void gtk_list_size_allocate (GtkWidget *widget,
70 GtkAllocation *allocation);
71 static void gtk_list_realize (GtkWidget *widget);
72 static void gtk_list_unmap (GtkWidget *widget);
73 static void gtk_list_style_set (GtkWidget *widget,
74 GtkStyle *previous_style);
75 static gint gtk_list_motion_notify (GtkWidget *widget,
76 GdkEventMotion *event);
77 static gint gtk_list_button_press (GtkWidget *widget,
78 GdkEventButton *event);
79 static gint gtk_list_button_release (GtkWidget *widget,
80 GdkEventButton *event);
82 static gboolean gtk_list_focus (GtkWidget *widget,
83 GtkDirectionType direction);
85 /*** GtkContainer Methods ***/
86 static void gtk_list_add (GtkContainer *container,
88 static void gtk_list_remove (GtkContainer *container,
90 static void gtk_list_forall (GtkContainer *container,
91 gboolean include_internals,
93 gpointer callback_data);
94 static GtkType gtk_list_child_type (GtkContainer *container);
95 static void gtk_list_set_focus_child (GtkContainer *container,
98 /*** GtkList Private Functions ***/
99 static void gtk_list_move_focus_child (GtkList *list,
100 GtkScrollType scroll_type,
102 static gint gtk_list_horizontal_timeout (GtkWidget *list);
103 static gint gtk_list_vertical_timeout (GtkWidget *list);
104 static void gtk_list_remove_items_internal (GtkList *list,
108 /*** GtkList Selection Methods ***/
109 static void gtk_real_list_select_child (GtkList *list,
111 static void gtk_real_list_unselect_child (GtkList *list,
114 /*** GtkList Selection Functions ***/
115 static void gtk_list_set_anchor (GtkList *list,
118 GtkWidget *undo_focus_child);
119 static void gtk_list_fake_unselect_all (GtkList *list,
121 static void gtk_list_fake_toggle_row (GtkList *list,
123 static void gtk_list_update_extended_selection (GtkList *list,
125 static void gtk_list_reset_extended_selection (GtkList *list);
127 /*** GtkListItem Signal Functions ***/
128 static void gtk_list_signal_drag_begin (GtkWidget *widget,
129 GdkDragContext *context,
131 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
133 static void gtk_list_signal_select_all (GtkListItem *list_item,
135 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
137 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
139 static void gtk_list_signal_start_selection (GtkListItem *list_item,
141 static void gtk_list_signal_end_selection (GtkListItem *list_item,
143 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
144 GtkScrollType scroll_type,
146 gboolean auto_start_selection,
148 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
149 GtkScrollType scroll_type,
152 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
153 GtkScrollType scroll_type,
156 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
158 static void gtk_list_signal_item_select (GtkListItem *list_item,
160 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
162 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
166 static void gtk_list_drag_begin (GtkWidget *widget,
167 GdkDragContext *context);
170 static GtkContainerClass *parent_class = NULL;
171 static guint list_signals[LAST_SIGNAL] = { 0 };
173 static const gchar vadjustment_key[] = "gtk-vadjustment";
174 static guint vadjustment_key_id = 0;
175 static const gchar hadjustment_key[] = "gtk-hadjustment";
176 static guint hadjustment_key_id = 0;
179 gtk_list_get_type (void)
181 static GtkType list_type = 0;
185 static const GtkTypeInfo list_info =
189 sizeof (GtkListClass),
190 (GtkClassInitFunc) gtk_list_class_init,
191 (GtkObjectInitFunc) gtk_list_init,
192 /* reserved_1 */ NULL,
193 /* reserved_2 */ NULL,
194 (GtkClassInitFunc) NULL,
197 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
204 gtk_list_class_init (GtkListClass *class)
206 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
207 GtkObjectClass *object_class;
208 GtkWidgetClass *widget_class;
209 GtkContainerClass *container_class;
211 object_class = (GtkObjectClass*) class;
212 widget_class = (GtkWidgetClass*) class;
213 container_class = (GtkContainerClass*) class;
215 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
217 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
218 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
220 gobject_class->dispose = gtk_list_dispose;
223 object_class->set_arg = gtk_list_set_arg;
224 object_class->get_arg = gtk_list_get_arg;
226 widget_class->unmap = gtk_list_unmap;
227 widget_class->style_set = gtk_list_style_set;
228 widget_class->realize = gtk_list_realize;
229 widget_class->button_press_event = gtk_list_button_press;
230 widget_class->button_release_event = gtk_list_button_release;
231 widget_class->motion_notify_event = gtk_list_motion_notify;
232 widget_class->size_request = gtk_list_size_request;
233 widget_class->size_allocate = gtk_list_size_allocate;
234 widget_class->drag_begin = gtk_list_drag_begin;
235 widget_class->focus = gtk_list_focus;
237 container_class->add = gtk_list_add;
238 container_class->remove = gtk_list_remove;
239 container_class->forall = gtk_list_forall;
240 container_class->child_type = gtk_list_child_type;
241 container_class->set_focus_child = gtk_list_set_focus_child;
243 class->selection_changed = NULL;
244 class->select_child = gtk_real_list_select_child;
245 class->unselect_child = gtk_real_list_unselect_child;
247 list_signals[SELECTION_CHANGED] =
248 gtk_signal_new ("selection_changed",
250 GTK_CLASS_TYPE (object_class),
251 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
252 _gtk_marshal_VOID__VOID,
254 list_signals[SELECT_CHILD] =
255 gtk_signal_new ("select_child",
257 GTK_CLASS_TYPE (object_class),
258 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
259 _gtk_marshal_VOID__OBJECT,
262 list_signals[UNSELECT_CHILD] =
263 gtk_signal_new ("unselect_child",
265 GTK_CLASS_TYPE (object_class),
266 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
267 _gtk_marshal_VOID__OBJECT,
271 gtk_object_add_arg_type ("GtkList::selection-mode",
272 GTK_TYPE_SELECTION_MODE,
273 GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
278 gtk_list_init (GtkList *list)
280 list->children = NULL;
281 list->selection = NULL;
283 list->undo_selection = NULL;
284 list->undo_unselection = NULL;
286 list->last_focus_child = NULL;
287 list->undo_focus_child = NULL;
294 list->anchor_state = GTK_STATE_SELECTED;
296 list->selection_mode = GTK_SELECTION_SINGLE;
297 list->drag_selection = FALSE;
298 list->add_mode = FALSE;
302 gtk_list_set_arg (GtkObject *object,
306 GtkList *list = GTK_LIST (object);
310 case ARG_SELECTION_MODE:
311 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
317 gtk_list_get_arg (GtkObject *object,
321 GtkList *list = GTK_LIST (object);
325 case ARG_SELECTION_MODE:
326 GTK_VALUE_ENUM (*arg) = list->selection_mode;
329 arg->type = GTK_TYPE_INVALID;
337 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
341 /* Private GtkObject Methods :
346 gtk_list_dispose (GObject *object)
348 gtk_list_clear_items (GTK_LIST (object), 0, -1);
350 G_OBJECT_CLASS (parent_class)->dispose (object);
354 /* Private GtkWidget Methods :
356 * gtk_list_size_request
357 * gtk_list_size_allocate
360 * gtk_list_motion_notify
361 * gtk_list_button_press
362 * gtk_list_button_release
365 gtk_list_size_request (GtkWidget *widget,
366 GtkRequisition *requisition)
372 g_return_if_fail (GTK_IS_LIST (widget));
373 g_return_if_fail (requisition != NULL);
375 list = GTK_LIST (widget);
376 requisition->width = 0;
377 requisition->height = 0;
379 children = list->children;
382 child = children->data;
383 children = children->next;
385 if (GTK_WIDGET_VISIBLE (child))
387 GtkRequisition child_requisition;
389 gtk_widget_size_request (child, &child_requisition);
391 requisition->width = MAX (requisition->width,
392 child_requisition.width);
393 requisition->height += child_requisition.height;
397 requisition->width += GTK_CONTAINER (list)->border_width * 2;
398 requisition->height += GTK_CONTAINER (list)->border_width * 2;
400 requisition->width = MAX (requisition->width, 1);
401 requisition->height = MAX (requisition->height, 1);
405 gtk_list_size_allocate (GtkWidget *widget,
406 GtkAllocation *allocation)
410 GtkAllocation child_allocation;
413 g_return_if_fail (GTK_IS_LIST (widget));
414 g_return_if_fail (allocation != NULL);
416 list = GTK_LIST (widget);
418 widget->allocation = *allocation;
419 if (GTK_WIDGET_REALIZED (widget))
420 gdk_window_move_resize (widget->window,
421 allocation->x, allocation->y,
422 allocation->width, allocation->height);
426 child_allocation.x = GTK_CONTAINER (list)->border_width;
427 child_allocation.y = GTK_CONTAINER (list)->border_width;
428 child_allocation.width = MAX (1, (gint)allocation->width -
429 child_allocation.x * 2);
431 children = list->children;
435 child = children->data;
436 children = children->next;
438 if (GTK_WIDGET_VISIBLE (child))
440 GtkRequisition child_requisition;
441 gtk_widget_get_child_requisition (child, &child_requisition);
443 child_allocation.height = child_requisition.height;
445 gtk_widget_size_allocate (child, &child_allocation);
447 child_allocation.y += child_allocation.height;
454 gtk_list_realize (GtkWidget *widget)
456 GdkWindowAttr attributes;
457 gint attributes_mask;
459 g_return_if_fail (GTK_IS_LIST (widget));
461 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
463 attributes.window_type = GDK_WINDOW_CHILD;
464 attributes.x = widget->allocation.x;
465 attributes.y = widget->allocation.y;
466 attributes.width = widget->allocation.width;
467 attributes.height = widget->allocation.height;
468 attributes.wclass = GDK_INPUT_OUTPUT;
469 attributes.visual = gtk_widget_get_visual (widget);
470 attributes.colormap = gtk_widget_get_colormap (widget);
471 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
473 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
475 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
476 &attributes, attributes_mask);
477 gdk_window_set_user_data (widget->window, widget);
479 widget->style = gtk_style_attach (widget->style, widget->window);
480 gdk_window_set_background (widget->window,
481 &widget->style->base[GTK_STATE_NORMAL]);
485 list_has_grab (GtkList *list)
487 return (GTK_WIDGET_HAS_GRAB (list) &&
488 gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (list))));
493 gtk_list_unmap (GtkWidget *widget)
497 g_return_if_fail (GTK_IS_LIST (widget));
499 if (!GTK_WIDGET_MAPPED (widget))
502 list = GTK_LIST (widget);
504 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
506 if (list_has_grab (list))
508 gtk_list_end_drag_selection (list);
510 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_MULTIPLE)
511 gtk_list_end_selection (list);
514 gdk_window_hide (widget->window);
518 gtk_list_motion_notify (GtkWidget *widget,
519 GdkEventMotion *event)
522 GtkWidget *item = NULL;
524 GtkContainer *container;
532 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
533 g_return_val_if_fail (event != NULL, FALSE);
535 list = GTK_LIST (widget);
537 if (!list->drag_selection || !list->children)
540 container = GTK_CONTAINER (widget);
542 if (event->is_hint || event->window != widget->window)
543 gdk_window_get_pointer (widget->window, &x, &y, NULL);
550 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
552 /* horizontal autoscrolling */
553 if (adj && widget->allocation.width > adj->page_size &&
554 (x < adj->value || x >= adj->value + adj->page_size))
556 if (list->htimer == 0)
558 list->htimer = g_timeout_add
559 (SCROLL_TIME, (GSourceFunc) gtk_list_horizontal_timeout, widget);
561 if (!((x < adj->value && adj->value <= 0) ||
562 (x > adj->value + adj->page_size &&
563 adj->value >= adj->upper - adj->page_size)))
568 value = adj->value + (x - adj->value) / 2 - 1;
570 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
572 gtk_adjustment_set_value (adj,
574 adj->upper - adj->page_size));
582 /* vertical autoscrolling */
583 for (work = list->children; work; length++, work = work->next)
587 item = GTK_WIDGET (work->data);
588 if (item->allocation.y > y ||
589 (item->allocation.y <= y &&
590 item->allocation.y + item->allocation.height > y))
594 if (work->data == container->focus_child)
601 if (list->vtimer != 0)
604 if (!((y < 0 && focus_row == 0) ||
605 (y > widget->allocation.height && focus_row >= length - 1)))
606 list->vtimer = g_timeout_add (SCROLL_TIME,
607 (GSourceFunc) gtk_list_vertical_timeout,
610 if (row != focus_row)
611 gtk_widget_grab_focus (item);
613 switch (list->selection_mode)
615 case GTK_SELECTION_BROWSE:
616 gtk_list_select_child (list, item);
618 case GTK_SELECTION_MULTIPLE:
619 gtk_list_update_extended_selection (list, row);
629 gtk_list_button_press (GtkWidget *widget,
630 GdkEventButton *event)
635 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
636 g_return_val_if_fail (event != NULL, FALSE);
638 if (event->button != 1)
641 list = GTK_LIST (widget);
642 item = gtk_get_event_widget ((GdkEvent*) event);
644 while (item && !GTK_IS_LIST_ITEM (item))
647 if (item && (item->parent == widget))
652 if (event->type == GDK_BUTTON_PRESS)
654 gtk_grab_add (widget);
655 list->drag_selection = TRUE;
657 else if (list_has_grab (list))
658 gtk_list_end_drag_selection (list);
660 if (!GTK_WIDGET_HAS_FOCUS(item))
661 gtk_widget_grab_focus (item);
665 list->add_mode = FALSE;
666 gtk_widget_queue_draw (item);
669 switch (list->selection_mode)
671 case GTK_SELECTION_SINGLE:
672 if (event->type != GDK_BUTTON_PRESS)
673 gtk_list_select_child (list, item);
675 list->undo_focus_child = item;
678 case GTK_SELECTION_BROWSE:
681 case GTK_SELECTION_MULTIPLE:
682 focus_row = g_list_index (list->children, item);
684 if (list->last_focus_child)
685 last_focus_row = g_list_index (list->children,
686 list->last_focus_child);
689 last_focus_row = focus_row;
690 list->last_focus_child = item;
693 if (event->type != GDK_BUTTON_PRESS)
695 if (list->anchor >= 0)
697 gtk_list_update_extended_selection (list, focus_row);
698 gtk_list_end_selection (list);
700 gtk_list_select_child (list, item);
704 if (event->state & GDK_CONTROL_MASK)
706 if (event->state & GDK_SHIFT_MASK)
708 if (list->anchor < 0)
710 g_list_free (list->undo_selection);
711 g_list_free (list->undo_unselection);
712 list->undo_selection = NULL;
713 list->undo_unselection = NULL;
715 list->anchor = last_focus_row;
716 list->drag_pos = last_focus_row;
717 list->undo_focus_child = list->last_focus_child;
719 gtk_list_update_extended_selection (list, focus_row);
723 if (list->anchor < 0)
724 gtk_list_set_anchor (list, TRUE,
725 focus_row, list->last_focus_child);
727 gtk_list_update_extended_selection (list, focus_row);
732 if (event->state & GDK_SHIFT_MASK)
734 gtk_list_set_anchor (list, FALSE,
735 last_focus_row, list->last_focus_child);
736 gtk_list_update_extended_selection (list, focus_row);
740 if (list->anchor < 0)
741 gtk_list_set_anchor (list, FALSE, focus_row,
742 list->last_focus_child);
744 gtk_list_update_extended_selection (list, focus_row);
758 gtk_list_button_release (GtkWidget *widget,
759 GdkEventButton *event)
764 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
765 g_return_val_if_fail (event != NULL, FALSE);
767 list = GTK_LIST (widget);
769 /* we don't handle button 2 and 3 */
770 if (event->button != 1)
773 if (list->drag_selection)
775 gtk_list_end_drag_selection (list);
777 switch (list->selection_mode)
779 case GTK_SELECTION_MULTIPLE:
780 if (!(event->state & GDK_SHIFT_MASK))
781 gtk_list_end_selection (list);
784 case GTK_SELECTION_SINGLE:
786 item = gtk_get_event_widget ((GdkEvent*) event);
788 while (item && !GTK_IS_LIST_ITEM (item))
791 if (item && item->parent == widget)
793 if (list->undo_focus_child == item)
794 gtk_list_toggle_row (list, item);
796 list->undo_focus_child = NULL;
810 gtk_list_style_set (GtkWidget *widget,
811 GtkStyle *previous_style)
813 g_return_if_fail (widget != NULL);
815 if (previous_style && GTK_WIDGET_REALIZED (widget))
816 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
819 /* GtkContainer Methods :
823 * gtk_list_child_type
824 * gtk_list_set_focus_child
828 gtk_list_add (GtkContainer *container,
833 g_return_if_fail (GTK_IS_LIST (container));
834 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
836 item_list = g_list_alloc ();
837 item_list->data = widget;
839 gtk_list_append_items (GTK_LIST (container), item_list);
843 gtk_list_remove (GtkContainer *container,
848 g_return_if_fail (GTK_IS_LIST (container));
849 g_return_if_fail (widget != NULL);
850 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
852 item_list = g_list_alloc ();
853 item_list->data = widget;
855 gtk_list_remove_items (GTK_LIST (container), item_list);
857 g_list_free (item_list);
861 gtk_list_forall (GtkContainer *container,
862 gboolean include_internals,
863 GtkCallback callback,
864 gpointer callback_data)
870 g_return_if_fail (GTK_IS_LIST (container));
871 g_return_if_fail (callback != NULL);
873 list = GTK_LIST (container);
874 children = list->children;
878 child = children->data;
879 children = children->next;
881 (* callback) (child, callback_data);
886 gtk_list_child_type (GtkContainer *container)
888 return GTK_TYPE_LIST_ITEM;
892 gtk_list_set_focus_child (GtkContainer *container,
897 g_return_if_fail (GTK_IS_LIST (container));
900 g_return_if_fail (GTK_IS_WIDGET (child));
902 list = GTK_LIST (container);
904 if (child != container->focus_child)
906 if (container->focus_child)
908 list->last_focus_child = container->focus_child;
909 gtk_widget_unref (container->focus_child);
911 container->focus_child = child;
912 if (container->focus_child)
913 gtk_widget_ref (container->focus_child);
916 /* check for v adjustment */
917 if (container->focus_child)
919 GtkAdjustment *adjustment;
921 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
924 gtk_adjustment_clamp_page (adjustment,
925 container->focus_child->allocation.y,
926 (container->focus_child->allocation.y +
927 container->focus_child->allocation.height));
928 switch (list->selection_mode)
930 case GTK_SELECTION_BROWSE:
931 gtk_list_select_child (list, child);
933 case GTK_SELECTION_MULTIPLE:
934 if (!list->last_focus_child && !list->add_mode)
936 list->undo_focus_child = list->last_focus_child;
937 gtk_list_unselect_all (list);
938 gtk_list_select_child (list, child);
948 gtk_list_focus (GtkWidget *widget,
949 GtkDirectionType direction)
951 gint return_val = FALSE;
952 GtkContainer *container;
954 container = GTK_CONTAINER (widget);
956 if (container->focus_child == NULL ||
957 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
959 if (GTK_LIST (container)->last_focus_child)
960 gtk_container_set_focus_child
961 (container, GTK_LIST (container)->last_focus_child);
963 if (GTK_WIDGET_CLASS (parent_class)->focus)
964 return_val = GTK_WIDGET_CLASS (parent_class)->focus (widget,
972 list = GTK_LIST (container);
973 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
974 gtk_list_end_selection (list);
976 if (container->focus_child)
977 list->last_focus_child = container->focus_child;
984 /* Public GtkList Methods :
986 * gtk_list_insert_items
987 * gtk_list_append_items
988 * gtk_list_prepend_items
989 * gtk_list_remove_items
990 * gtk_list_remove_items_no_unref
991 * gtk_list_clear_items
993 * gtk_list_child_position
996 gtk_list_insert_items (GtkList *list,
1005 g_return_if_fail (GTK_IS_LIST (list));
1010 gtk_list_end_drag_selection (list);
1011 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1012 gtk_list_end_selection (list);
1017 widget = tmp_list->data;
1018 tmp_list = tmp_list->next;
1020 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1021 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1022 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1024 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1025 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1027 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1028 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1030 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1031 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1033 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1034 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1036 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1037 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1039 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1040 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1042 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1043 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1045 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1046 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1048 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1049 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1051 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1052 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1054 gtk_signal_connect (GTK_OBJECT (widget), "select",
1055 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1057 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1058 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1060 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1061 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1066 nchildren = g_list_length (list->children);
1067 if ((position < 0) || (position > nchildren))
1068 position = nchildren;
1070 if (position == nchildren)
1074 tmp_list = g_list_last (list->children);
1075 tmp_list->next = items;
1076 items->prev = tmp_list;
1080 list->children = items;
1085 tmp_list = g_list_nth (list->children, position);
1086 last = g_list_last (items);
1089 tmp_list->prev->next = items;
1090 last->next = tmp_list;
1091 items->prev = tmp_list->prev;
1092 tmp_list->prev = last;
1094 if (tmp_list == list->children)
1095 list->children = items;
1098 if (list->children && !list->selection &&
1099 (list->selection_mode == GTK_SELECTION_BROWSE))
1101 widget = list->children->data;
1102 gtk_list_select_child (list, widget);
1107 gtk_list_append_items (GtkList *list,
1110 g_return_if_fail (GTK_IS_LIST (list));
1112 gtk_list_insert_items (list, items, -1);
1116 gtk_list_prepend_items (GtkList *list,
1119 g_return_if_fail (GTK_IS_LIST (list));
1121 gtk_list_insert_items (list, items, 0);
1125 gtk_list_remove_items (GtkList *list,
1128 gtk_list_remove_items_internal (list, items, FALSE);
1132 gtk_list_remove_items_no_unref (GtkList *list,
1135 gtk_list_remove_items_internal (list, items, TRUE);
1139 gtk_list_clear_items (GtkList *list,
1143 GtkContainer *container;
1145 GtkWidget *new_focus_child = NULL;
1150 gboolean grab_focus = FALSE;
1152 g_return_if_fail (GTK_IS_LIST (list));
1154 nchildren = g_list_length (list->children);
1159 if ((end < 0) || (end > nchildren))
1165 container = GTK_CONTAINER (list);
1167 gtk_list_end_drag_selection (list);
1168 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1170 if (list->anchor >= 0)
1171 gtk_list_end_selection (list);
1173 gtk_list_reset_extended_selection (list);
1176 start_list = g_list_nth (list->children, start);
1177 end_list = g_list_nth (list->children, end);
1179 if (start_list->prev)
1180 start_list->prev->next = end_list;
1181 if (end_list && end_list->prev)
1182 end_list->prev->next = NULL;
1184 end_list->prev = start_list->prev;
1185 if (start_list == list->children)
1186 list->children = end_list;
1188 if (container->focus_child)
1190 if (g_list_find (start_list, container->focus_child))
1192 if (start_list->prev)
1193 new_focus_child = start_list->prev->data;
1194 else if (list->children)
1195 new_focus_child = list->children->data;
1197 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1202 tmp_list = start_list;
1205 widget = tmp_list->data;
1206 tmp_list = tmp_list->next;
1208 gtk_widget_ref (widget);
1210 if (widget->state == GTK_STATE_SELECTED)
1211 gtk_list_unselect_child (list, widget);
1213 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1214 gtk_widget_unparent (widget);
1216 if (widget == list->undo_focus_child)
1217 list->undo_focus_child = NULL;
1218 if (widget == list->last_focus_child)
1219 list->last_focus_child = NULL;
1221 gtk_widget_unref (widget);
1224 g_list_free (start_list);
1226 if (new_focus_child)
1229 gtk_widget_grab_focus (new_focus_child);
1230 else if (container->focus_child)
1231 gtk_container_set_focus_child (container, new_focus_child);
1233 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1234 list->selection_mode == GTK_SELECTION_MULTIPLE) && !list->selection)
1236 list->last_focus_child = new_focus_child;
1237 gtk_list_select_child (list, new_focus_child);
1241 if (GTK_WIDGET_VISIBLE (list))
1242 gtk_widget_queue_resize (GTK_WIDGET (list));
1246 gtk_list_child_position (GtkList *list,
1252 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1253 g_return_val_if_fail (child != NULL, -1);
1256 children = list->children;
1260 if (child == GTK_WIDGET (children->data))
1264 children = children->next;
1271 /* Private GtkList Insert/Remove Item Functions:
1273 * gtk_list_remove_items_internal
1276 gtk_list_remove_items_internal (GtkList *list,
1281 GtkWidget *new_focus_child;
1282 GtkWidget *old_focus_child;
1283 GtkContainer *container;
1286 gboolean grab_focus = FALSE;
1288 g_return_if_fail (GTK_IS_LIST (list));
1293 container = GTK_CONTAINER (list);
1295 gtk_list_end_drag_selection (list);
1296 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1298 if (list->anchor >= 0)
1299 gtk_list_end_selection (list);
1301 gtk_list_reset_extended_selection (list);
1307 widget = tmp_list->data;
1308 tmp_list = tmp_list->next;
1310 if (widget->state == GTK_STATE_SELECTED)
1311 gtk_list_unselect_child (list, widget);
1314 if (container->focus_child)
1316 old_focus_child = new_focus_child = container->focus_child;
1317 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1321 old_focus_child = new_focus_child = list->last_focus_child;
1326 widget = tmp_list->data;
1327 tmp_list = tmp_list->next;
1329 gtk_widget_ref (widget);
1331 gtk_widget_ref (widget);
1333 if (widget == new_focus_child)
1335 work = g_list_find (list->children, widget);
1340 new_focus_child = work->next->data;
1341 else if (list->children != work && work->prev)
1342 new_focus_child = work->prev->data;
1344 new_focus_child = NULL;
1348 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1349 list->children = g_list_remove (list->children, widget);
1350 gtk_widget_unparent (widget);
1352 if (widget == list->undo_focus_child)
1353 list->undo_focus_child = NULL;
1354 if (widget == list->last_focus_child)
1355 list->last_focus_child = NULL;
1357 gtk_widget_unref (widget);
1360 if (new_focus_child && new_focus_child != old_focus_child)
1363 gtk_widget_grab_focus (new_focus_child);
1364 else if (container->focus_child)
1365 gtk_container_set_focus_child (container, new_focus_child);
1367 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1369 list->last_focus_child = new_focus_child;
1370 gtk_list_select_child (list, new_focus_child);
1374 if (GTK_WIDGET_VISIBLE (list))
1375 gtk_widget_queue_resize (GTK_WIDGET (list));
1379 /* Public GtkList Selection Methods :
1381 * gtk_list_set_selection_mode
1382 * gtk_list_select_item
1383 * gtk_list_unselect_item
1384 * gtk_list_select_child
1385 * gtk_list_unselect_child
1386 * gtk_list_select_all
1387 * gtk_list_unselect_all
1388 * gtk_list_extend_selection
1389 * gtk_list_end_drag_selection
1390 * gtk_list_start_selection
1391 * gtk_list_end_selection
1392 * gtk_list_toggle_row
1393 * gtk_list_toggle_focus_row
1394 * gtk_list_toggle_add_mode
1395 * gtk_list_undo_selection
1398 gtk_list_set_selection_mode (GtkList *list,
1399 GtkSelectionMode mode)
1401 g_return_if_fail (GTK_IS_LIST (list));
1403 if (list->selection_mode == mode)
1406 list->selection_mode = mode;
1410 case GTK_SELECTION_SINGLE:
1411 case GTK_SELECTION_BROWSE:
1412 gtk_list_unselect_all (list);
1420 gtk_list_select_item (GtkList *list,
1425 g_return_if_fail (GTK_IS_LIST (list));
1427 tmp_list = g_list_nth (list->children, item);
1429 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1433 gtk_list_unselect_item (GtkList *list,
1438 g_return_if_fail (GTK_IS_LIST (list));
1440 tmp_list = g_list_nth (list->children, item);
1442 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1446 gtk_list_select_child (GtkList *list,
1449 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1453 gtk_list_unselect_child (GtkList *list,
1456 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1460 gtk_list_select_all (GtkList *list)
1462 GtkContainer *container;
1464 g_return_if_fail (GTK_IS_LIST (list));
1466 if (!list->children)
1469 if (list_has_grab (list))
1470 gtk_list_end_drag_selection (list);
1472 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1473 gtk_list_end_selection (list);
1475 container = GTK_CONTAINER (list);
1477 switch (list->selection_mode)
1479 case GTK_SELECTION_BROWSE:
1480 if (container->focus_child)
1482 gtk_list_select_child (list, container->focus_child);
1486 case GTK_SELECTION_MULTIPLE:
1487 g_list_free (list->undo_selection);
1488 g_list_free (list->undo_unselection);
1489 list->undo_selection = NULL;
1490 list->undo_unselection = NULL;
1492 if (list->children &&
1493 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1494 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1496 list->anchor_state = GTK_STATE_SELECTED;
1499 list->undo_focus_child = container->focus_child;
1500 gtk_list_update_extended_selection (list, g_list_length(list->children));
1501 gtk_list_end_selection (list);
1509 gtk_list_unselect_all (GtkList *list)
1511 GtkContainer *container;
1515 g_return_if_fail (GTK_IS_LIST (list));
1517 if (!list->children)
1520 if (list_has_grab (list))
1521 gtk_list_end_drag_selection (list);
1523 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1524 gtk_list_end_selection (list);
1526 container = GTK_CONTAINER (list);
1528 switch (list->selection_mode)
1530 case GTK_SELECTION_BROWSE:
1531 if (container->focus_child)
1533 gtk_list_select_child (list, container->focus_child);
1537 case GTK_SELECTION_MULTIPLE:
1538 gtk_list_reset_extended_selection (list);
1544 work = list->selection;
1550 gtk_list_unselect_child (list, item);
1555 gtk_list_extend_selection (GtkList *list,
1556 GtkScrollType scroll_type,
1558 gboolean auto_start_selection)
1560 GtkContainer *container;
1562 g_return_if_fail (GTK_IS_LIST (list));
1564 if (list_has_grab (list) ||
1565 list->selection_mode != GTK_SELECTION_MULTIPLE)
1568 container = GTK_CONTAINER (list);
1570 if (auto_start_selection)
1574 focus_row = g_list_index (list->children, container->focus_child);
1575 gtk_list_set_anchor (list, list->add_mode, focus_row,
1576 container->focus_child);
1578 else if (list->anchor < 0)
1581 gtk_list_move_focus_child (list, scroll_type, position);
1582 gtk_list_update_extended_selection
1583 (list, g_list_index (list->children, container->focus_child));
1587 gtk_list_end_drag_selection (GtkList *list)
1589 g_return_if_fail (GTK_IS_LIST (list));
1591 list->drag_selection = FALSE;
1592 if (GTK_WIDGET_HAS_GRAB (list))
1593 gtk_grab_remove (GTK_WIDGET (list));
1597 g_source_remove (list->htimer);
1602 g_source_remove (list->vtimer);
1608 gtk_list_start_selection (GtkList *list)
1610 GtkContainer *container;
1613 g_return_if_fail (GTK_IS_LIST (list));
1615 if (list_has_grab (list))
1618 container = GTK_CONTAINER (list);
1620 if ((focus_row = g_list_index (list->selection, container->focus_child))
1622 gtk_list_set_anchor (list, list->add_mode,
1623 focus_row, container->focus_child);
1627 gtk_list_end_selection (GtkList *list)
1636 g_return_if_fail (GTK_IS_LIST (list));
1638 if (list_has_grab (list) || list->anchor < 0)
1641 i = MIN (list->anchor, list->drag_pos);
1642 e = MAX (list->anchor, list->drag_pos);
1644 top_down = (list->anchor < list->drag_pos);
1647 list->drag_pos = -1;
1649 if (list->undo_selection)
1651 work = list->selection;
1652 list->selection = list->undo_selection;
1653 list->undo_selection = work;
1654 work = list->selection;
1659 item_index = g_list_index (list->children, item);
1660 if (item_index < i || item_index > e)
1662 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1663 gtk_list_unselect_child (list, item);
1664 list->undo_selection = g_list_prepend (list->undo_selection,
1672 for (work = g_list_nth (list->children, i); i <= e;
1673 i++, work = work->next)
1676 if (g_list_find (list->selection, item))
1678 if (item->state == GTK_STATE_NORMAL)
1680 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1681 gtk_list_unselect_child (list, item);
1682 list->undo_selection = g_list_prepend (list->undo_selection,
1686 else if (item->state == GTK_STATE_SELECTED)
1688 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1689 list->undo_unselection = g_list_prepend (list->undo_unselection,
1696 for (work = g_list_nth (list->children, e); i <= e;
1697 e--, work = work->prev)
1700 if (g_list_find (list->selection, item))
1702 if (item->state == GTK_STATE_NORMAL)
1704 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1705 gtk_list_unselect_child (list, item);
1706 list->undo_selection = g_list_prepend (list->undo_selection,
1710 else if (item->state == GTK_STATE_SELECTED)
1712 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1713 list->undo_unselection = g_list_prepend (list->undo_unselection,
1719 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1720 gtk_list_select_child (list, GTK_WIDGET (work->data));
1726 gtk_list_toggle_row (GtkList *list,
1729 g_return_if_fail (GTK_IS_LIST (list));
1730 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1732 switch (list->selection_mode)
1734 case GTK_SELECTION_MULTIPLE:
1735 case GTK_SELECTION_SINGLE:
1736 if (item->state == GTK_STATE_SELECTED)
1738 gtk_list_unselect_child (list, item);
1741 case GTK_SELECTION_BROWSE:
1742 gtk_list_select_child (list, item);
1748 gtk_list_toggle_focus_row (GtkList *list)
1750 GtkContainer *container;
1753 g_return_if_fail (list != 0);
1754 g_return_if_fail (GTK_IS_LIST (list));
1756 container = GTK_CONTAINER (list);
1758 if (list_has_grab (list) || !container->focus_child)
1761 switch (list->selection_mode)
1763 case GTK_SELECTION_SINGLE:
1764 gtk_list_toggle_row (list, container->focus_child);
1766 case GTK_SELECTION_MULTIPLE:
1767 if ((focus_row = g_list_index (list->children, container->focus_child))
1771 g_list_free (list->undo_selection);
1772 g_list_free (list->undo_unselection);
1773 list->undo_selection = NULL;
1774 list->undo_unselection = NULL;
1776 list->anchor = focus_row;
1777 list->drag_pos = focus_row;
1778 list->undo_focus_child = container->focus_child;
1781 gtk_list_fake_toggle_row (list, container->focus_child);
1783 gtk_list_fake_unselect_all (list, container->focus_child);
1785 gtk_list_end_selection (list);
1793 gtk_list_toggle_add_mode (GtkList *list)
1795 GtkContainer *container;
1797 g_return_if_fail (list != 0);
1798 g_return_if_fail (GTK_IS_LIST (list));
1800 if (list_has_grab (list) ||
1801 list->selection_mode != GTK_SELECTION_MULTIPLE)
1804 container = GTK_CONTAINER (list);
1808 list->add_mode = FALSE;
1809 list->anchor_state = GTK_STATE_SELECTED;
1812 list->add_mode = TRUE;
1814 if (container->focus_child)
1815 gtk_widget_queue_draw (container->focus_child);
1819 gtk_list_undo_selection (GtkList *list)
1823 g_return_if_fail (GTK_IS_LIST (list));
1825 if (list->selection_mode != GTK_SELECTION_MULTIPLE ||
1826 list_has_grab (list))
1829 if (list->anchor >= 0)
1830 gtk_list_end_selection (list);
1832 if (!(list->undo_selection || list->undo_unselection))
1834 gtk_list_unselect_all (list);
1838 for (work = list->undo_selection; work; work = work->next)
1839 gtk_list_select_child (list, GTK_WIDGET (work->data));
1841 for (work = list->undo_unselection; work; work = work->next)
1842 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1844 if (list->undo_focus_child)
1846 GtkContainer *container;
1848 container = GTK_CONTAINER (list);
1850 if (container->focus_child &&
1851 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1852 gtk_widget_grab_focus (list->undo_focus_child);
1854 gtk_container_set_focus_child (container, list->undo_focus_child);
1857 list->undo_focus_child = NULL;
1859 g_list_free (list->undo_selection);
1860 g_list_free (list->undo_unselection);
1861 list->undo_selection = NULL;
1862 list->undo_unselection = NULL;
1866 /* Private GtkList Selection Methods :
1868 * gtk_real_list_select_child
1869 * gtk_real_list_unselect_child
1872 gtk_real_list_select_child (GtkList *list,
1875 g_return_if_fail (GTK_IS_LIST (list));
1876 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1878 switch (child->state)
1880 case GTK_STATE_SELECTED:
1881 case GTK_STATE_INSENSITIVE:
1884 gtk_list_item_select (GTK_LIST_ITEM (child));
1890 gtk_real_list_unselect_child (GtkList *list,
1893 g_return_if_fail (GTK_IS_LIST (list));
1894 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1896 if (child->state == GTK_STATE_SELECTED)
1897 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1901 /* Private GtkList Selection Functions :
1903 * gtk_list_set_anchor
1904 * gtk_list_fake_unselect_all
1905 * gtk_list_fake_toggle_row
1906 * gtk_list_update_extended_selection
1907 * gtk_list_reset_extended_selection
1910 gtk_list_set_anchor (GtkList *list,
1913 GtkWidget *undo_focus_child)
1917 g_return_if_fail (GTK_IS_LIST (list));
1919 if (list->selection_mode != GTK_SELECTION_MULTIPLE || list->anchor >= 0)
1922 g_list_free (list->undo_selection);
1923 g_list_free (list->undo_unselection);
1924 list->undo_selection = NULL;
1925 list->undo_unselection = NULL;
1927 if ((work = g_list_nth (list->children, anchor)))
1930 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1933 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1934 list->anchor_state = GTK_STATE_SELECTED;
1938 list->anchor = anchor;
1939 list->drag_pos = anchor;
1940 list->undo_focus_child = undo_focus_child;
1944 gtk_list_fake_unselect_all (GtkList *list,
1949 if (item && item->state == GTK_STATE_NORMAL)
1950 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1952 list->undo_selection = list->selection;
1953 list->selection = NULL;
1955 for (work = list->undo_selection; work; work = work->next)
1956 if (work->data != item)
1957 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1961 gtk_list_fake_toggle_row (GtkList *list,
1967 if (item->state == GTK_STATE_NORMAL)
1969 list->anchor_state = GTK_STATE_SELECTED;
1970 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1974 list->anchor_state = GTK_STATE_NORMAL;
1975 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1980 gtk_list_update_extended_selection (GtkList *list,
1994 length = g_list_length (list->children);
1998 if (list->selection_mode != GTK_SELECTION_MULTIPLE || !list->anchor < 0)
2001 /* extending downwards */
2002 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2004 s2 = list->drag_pos + 1;
2007 /* extending upwards */
2008 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2011 e2 = list->drag_pos - 1;
2013 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2015 e1 = list->drag_pos;
2016 /* row and drag_pos on different sides of anchor :
2017 take back the selection between anchor and drag_pos,
2018 select between anchor and row */
2019 if (row < list->anchor)
2021 s1 = list->anchor + 1;
2023 e2 = list->anchor - 1;
2025 /* take back the selection between anchor and drag_pos */
2029 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2031 s1 = list->drag_pos;
2032 /* row and drag_pos on different sides of anchor :
2033 take back the selection between anchor and drag_pos,
2034 select between anchor and row */
2035 if (row > list->anchor)
2037 e1 = list->anchor - 1;
2038 s2 = list->anchor + 1;
2041 /* take back the selection between anchor and drag_pos */
2046 list->drag_pos = row;
2048 /* restore the elements between s1 and e1 */
2051 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2052 i++, work = work->next)
2054 if (g_list_find (list->selection, work->data))
2055 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2057 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2061 /* extend the selection between s2 and e2 */
2064 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2065 i++, work = work->next)
2066 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2067 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2072 gtk_list_reset_extended_selection (GtkList *list)
2074 g_return_if_fail (list != 0);
2075 g_return_if_fail (GTK_IS_LIST (list));
2077 g_list_free (list->undo_selection);
2078 g_list_free (list->undo_unselection);
2079 list->undo_selection = NULL;
2080 list->undo_unselection = NULL;
2083 list->drag_pos = -1;
2084 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2087 /* Public GtkList Scroll Methods :
2089 * gtk_list_scroll_horizontal
2090 * gtk_list_scroll_vertical
2093 gtk_list_scroll_horizontal (GtkList *list,
2094 GtkScrollType scroll_type,
2099 g_return_if_fail (list != 0);
2100 g_return_if_fail (GTK_IS_LIST (list));
2102 if (list_has_grab (list))
2106 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2109 switch (scroll_type)
2111 case GTK_SCROLL_STEP_UP:
2112 case GTK_SCROLL_STEP_BACKWARD:
2113 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2114 adj->upper - adj->page_size);
2116 case GTK_SCROLL_STEP_DOWN:
2117 case GTK_SCROLL_STEP_FORWARD:
2118 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2119 adj->upper - adj->page_size);
2121 case GTK_SCROLL_PAGE_UP:
2122 case GTK_SCROLL_PAGE_BACKWARD:
2123 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2124 adj->upper - adj->page_size);
2126 case GTK_SCROLL_PAGE_DOWN:
2127 case GTK_SCROLL_PAGE_FORWARD:
2128 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2129 adj->upper - adj->page_size);
2131 case GTK_SCROLL_JUMP:
2132 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2133 adj->lower, adj->upper - adj->page_size);
2138 gtk_adjustment_value_changed (adj);
2142 gtk_list_scroll_vertical (GtkList *list,
2143 GtkScrollType scroll_type,
2146 g_return_if_fail (GTK_IS_LIST (list));
2148 if (list_has_grab (list))
2151 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
2153 GtkContainer *container;
2155 if (list->anchor >= 0)
2158 container = GTK_CONTAINER (list);
2159 list->undo_focus_child = container->focus_child;
2160 gtk_list_move_focus_child (list, scroll_type, position);
2161 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2163 gtk_list_unselect_all (list);
2164 gtk_list_select_child (list, container->focus_child);
2168 gtk_list_move_focus_child (list, scroll_type, position);
2172 /* Private GtkList Scroll/Focus Functions :
2174 * gtk_list_move_focus_child
2175 * gtk_list_horizontal_timeout
2176 * gtk_list_vertical_timeout
2179 gtk_list_move_focus_child (GtkList *list,
2180 GtkScrollType scroll_type,
2183 GtkContainer *container;
2189 g_return_if_fail (list != 0);
2190 g_return_if_fail (GTK_IS_LIST (list));
2192 container = GTK_CONTAINER (list);
2194 if (container->focus_child)
2195 work = g_list_find (list->children, container->focus_child);
2197 work = list->children;
2202 switch (scroll_type)
2204 case GTK_SCROLL_STEP_BACKWARD:
2207 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2209 case GTK_SCROLL_STEP_FORWARD:
2212 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2214 case GTK_SCROLL_PAGE_BACKWARD:
2219 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2223 gboolean correct = FALSE;
2225 new_value = adj->value;
2227 if (item->allocation.y <= adj->value)
2229 new_value = MAX (item->allocation.y + item->allocation.height
2230 - adj->page_size, adj->lower);
2234 if (item->allocation.y > new_value)
2235 for (; work; work = work->prev)
2237 item = GTK_WIDGET (work->data);
2238 if (item->allocation.y <= new_value &&
2239 item->allocation.y + item->allocation.height > new_value)
2243 for (; work; work = work->next)
2245 item = GTK_WIDGET (work->data);
2246 if (item->allocation.y <= new_value &&
2247 item->allocation.y + item->allocation.height > new_value)
2251 if (correct && work && work->next && item->allocation.y < new_value)
2252 item = work->next->data;
2255 item = list->children->data;
2257 gtk_widget_grab_focus (item);
2259 case GTK_SCROLL_PAGE_FORWARD:
2264 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2268 gboolean correct = FALSE;
2270 new_value = adj->value;
2272 if (item->allocation.y + item->allocation.height >=
2273 adj->value + adj->page_size)
2275 new_value = item->allocation.y;
2279 new_value = MIN (new_value + adj->page_size, adj->upper);
2281 if (item->allocation.y > new_value)
2282 for (; work; work = work->prev)
2284 item = GTK_WIDGET (work->data);
2285 if (item->allocation.y <= new_value &&
2286 item->allocation.y + item->allocation.height > new_value)
2290 for (; work; work = work->next)
2292 item = GTK_WIDGET (work->data);
2293 if (item->allocation.y <= new_value &&
2294 item->allocation.y + item->allocation.height > new_value)
2298 if (correct && work && work->prev &&
2299 item->allocation.y + item->allocation.height - 1 > new_value)
2300 item = work->prev->data;
2303 item = g_list_last (work)->data;
2305 gtk_widget_grab_focus (item);
2307 case GTK_SCROLL_JUMP:
2308 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2310 for (item = NULL, work = list->children; work; work =work->next)
2312 item = GTK_WIDGET (work->data);
2313 if (item->allocation.y <= new_value &&
2314 item->allocation.y + item->allocation.height > new_value)
2318 gtk_widget_grab_focus (item);
2326 do_fake_motion (GtkWidget *list)
2328 GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
2330 event->motion.send_event = TRUE;
2332 gtk_list_motion_notify (list, (GdkEventMotion *)event);
2333 gdk_event_free (event);
2337 gtk_list_horizontal_timeout (GtkWidget *list)
2339 GDK_THREADS_ENTER ();
2341 GTK_LIST (list)->htimer = 0;
2342 do_fake_motion (list);
2344 GDK_THREADS_LEAVE ();
2350 gtk_list_vertical_timeout (GtkWidget *list)
2352 GDK_THREADS_ENTER ();
2354 GTK_LIST (list)->vtimer = 0;
2355 do_fake_motion (list);
2357 GDK_THREADS_LEAVE ();
2363 /* Private GtkListItem Signal Functions :
2365 * gtk_list_signal_toggle_focus_row
2366 * gtk_list_signal_select_all
2367 * gtk_list_signal_unselect_all
2368 * gtk_list_signal_undo_selection
2369 * gtk_list_signal_start_selection
2370 * gtk_list_signal_end_selection
2371 * gtk_list_signal_extend_selection
2372 * gtk_list_signal_scroll_horizontal
2373 * gtk_list_signal_scroll_vertical
2374 * gtk_list_signal_toggle_add_mode
2375 * gtk_list_signal_item_select
2376 * gtk_list_signal_item_deselect
2377 * gtk_list_signal_item_toggle
2380 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2383 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2384 g_return_if_fail (GTK_IS_LIST (list));
2386 gtk_list_toggle_focus_row (list);
2390 gtk_list_signal_select_all (GtkListItem *list_item,
2393 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2394 g_return_if_fail (GTK_IS_LIST (list));
2396 gtk_list_select_all (list);
2400 gtk_list_signal_unselect_all (GtkListItem *list_item,
2403 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2404 g_return_if_fail (GTK_IS_LIST (list));
2406 gtk_list_unselect_all (list);
2410 gtk_list_signal_undo_selection (GtkListItem *list_item,
2413 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2414 g_return_if_fail (GTK_IS_LIST (list));
2416 gtk_list_undo_selection (list);
2420 gtk_list_signal_start_selection (GtkListItem *list_item,
2423 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2424 g_return_if_fail (GTK_IS_LIST (list));
2426 gtk_list_start_selection (list);
2430 gtk_list_signal_end_selection (GtkListItem *list_item,
2433 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2434 g_return_if_fail (GTK_IS_LIST (list));
2436 gtk_list_end_selection (list);
2440 gtk_list_signal_extend_selection (GtkListItem *list_item,
2441 GtkScrollType scroll_type,
2443 gboolean auto_start_selection,
2446 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2447 g_return_if_fail (GTK_IS_LIST (list));
2449 gtk_list_extend_selection (list, scroll_type, position,
2450 auto_start_selection);
2454 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2455 GtkScrollType scroll_type,
2459 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2460 g_return_if_fail (GTK_IS_LIST (list));
2462 gtk_list_scroll_horizontal (list, scroll_type, position);
2466 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2467 GtkScrollType scroll_type,
2471 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2472 g_return_if_fail (GTK_IS_LIST (list));
2474 gtk_list_scroll_vertical (list, scroll_type, position);
2478 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2481 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2482 g_return_if_fail (GTK_IS_LIST (list));
2484 gtk_list_toggle_add_mode (list);
2488 gtk_list_signal_item_select (GtkListItem *list_item,
2495 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2496 g_return_if_fail (GTK_IS_LIST (list));
2498 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2501 switch (list->selection_mode)
2503 case GTK_SELECTION_SINGLE:
2504 case GTK_SELECTION_BROWSE:
2506 selection = list->selection;
2510 tmp_list = selection;
2511 selection = selection->next;
2513 if (tmp_list->data == list_item)
2514 sel_list = tmp_list;
2516 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2521 list->selection = g_list_prepend (list->selection, list_item);
2522 gtk_widget_ref (GTK_WIDGET (list_item));
2524 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2526 case GTK_SELECTION_MULTIPLE:
2527 if (list->anchor >= 0)
2533 gtk_list_signal_item_deselect (GtkListItem *list_item,
2538 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2539 g_return_if_fail (GTK_IS_LIST (list));
2541 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2544 node = g_list_find (list->selection, list_item);
2548 list->selection = g_list_remove_link (list->selection, node);
2549 g_list_free_1 (node);
2550 gtk_widget_unref (GTK_WIDGET (list_item));
2551 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2556 gtk_list_signal_item_toggle (GtkListItem *list_item,
2559 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2560 g_return_if_fail (GTK_IS_LIST (list));
2562 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
2563 list->selection_mode == GTK_SELECTION_MULTIPLE) &&
2564 GTK_WIDGET (list_item)->state == GTK_STATE_NORMAL)
2566 gtk_widget_set_state (GTK_WIDGET (list_item), GTK_STATE_SELECTED);
2570 switch (GTK_WIDGET (list_item)->state)
2572 case GTK_STATE_SELECTED:
2573 gtk_list_signal_item_select (list_item, list);
2575 case GTK_STATE_NORMAL:
2576 gtk_list_signal_item_deselect (list_item, list);
2584 gtk_list_signal_drag_begin (GtkWidget *widget,
2585 GdkDragContext *context,
2588 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2589 g_return_if_fail (GTK_IS_LIST (list));
2591 gtk_list_drag_begin (GTK_WIDGET (list), context);
2595 gtk_list_drag_begin (GtkWidget *widget,
2596 GdkDragContext *context)
2600 g_return_if_fail (GTK_IS_LIST (widget));
2601 g_return_if_fail (context != NULL);
2603 list = GTK_LIST (widget);
2605 if (list->drag_selection)
2607 gtk_list_end_drag_selection (list);
2609 switch (list->selection_mode)
2611 case GTK_SELECTION_MULTIPLE:
2612 gtk_list_end_selection (list);
2614 case GTK_SELECTION_SINGLE:
2615 list->undo_focus_child = NULL;
2623 #define __GTK_LIST_C__
2624 #include "gtkaliasdef.c"