1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include <string.h> /* memset */
30 #include "gtklistitem.h"
32 #include "gtksignal.h"
34 #include "gtkmarshalers.h"
48 #define SCROLL_TIME 100
50 /*** GtkList Methods ***/
51 static void gtk_list_class_init (GtkListClass *klass);
52 static void gtk_list_init (GtkList *list);
53 static void gtk_list_set_arg (GtkObject *object,
56 static void gtk_list_get_arg (GtkObject *object,
59 /*** GtkObject Methods ***/
60 static void gtk_list_dispose (GObject *object);
62 /*** GtkWidget Methods ***/
63 static void gtk_list_size_request (GtkWidget *widget,
64 GtkRequisition *requisition);
65 static void gtk_list_size_allocate (GtkWidget *widget,
66 GtkAllocation *allocation);
67 static void gtk_list_realize (GtkWidget *widget);
68 static void gtk_list_unmap (GtkWidget *widget);
69 static void gtk_list_style_set (GtkWidget *widget,
70 GtkStyle *previous_style);
71 static gint gtk_list_motion_notify (GtkWidget *widget,
72 GdkEventMotion *event);
73 static gint gtk_list_button_press (GtkWidget *widget,
74 GdkEventButton *event);
75 static gint gtk_list_button_release (GtkWidget *widget,
76 GdkEventButton *event);
78 static gboolean gtk_list_focus (GtkWidget *widget,
79 GtkDirectionType direction);
81 /*** GtkContainer Methods ***/
82 static void gtk_list_add (GtkContainer *container,
84 static void gtk_list_remove (GtkContainer *container,
86 static void gtk_list_forall (GtkContainer *container,
87 gboolean include_internals,
89 gpointer callback_data);
90 static GtkType gtk_list_child_type (GtkContainer *container);
91 static void gtk_list_set_focus_child (GtkContainer *container,
94 /*** GtkList Private Functions ***/
95 static void gtk_list_move_focus_child (GtkList *list,
96 GtkScrollType scroll_type,
98 static gint gtk_list_horizontal_timeout (GtkWidget *list);
99 static gint gtk_list_vertical_timeout (GtkWidget *list);
100 static void gtk_list_remove_items_internal (GtkList *list,
104 /*** GtkList Selection Methods ***/
105 static void gtk_real_list_select_child (GtkList *list,
107 static void gtk_real_list_unselect_child (GtkList *list,
110 /*** GtkList Selection Functions ***/
111 static void gtk_list_set_anchor (GtkList *list,
114 GtkWidget *undo_focus_child);
115 static void gtk_list_fake_unselect_all (GtkList *list,
117 static void gtk_list_fake_toggle_row (GtkList *list,
119 static void gtk_list_update_extended_selection (GtkList *list,
121 static void gtk_list_reset_extended_selection (GtkList *list);
123 /*** GtkListItem Signal Functions ***/
124 static void gtk_list_signal_drag_begin (GtkWidget *widget,
125 GdkDragContext *context,
127 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
129 static void gtk_list_signal_select_all (GtkListItem *list_item,
131 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
133 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
135 static void gtk_list_signal_start_selection (GtkListItem *list_item,
137 static void gtk_list_signal_end_selection (GtkListItem *list_item,
139 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
140 GtkScrollType scroll_type,
142 gboolean auto_start_selection,
144 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
145 GtkScrollType scroll_type,
148 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
149 GtkScrollType scroll_type,
152 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
154 static void gtk_list_signal_item_select (GtkListItem *list_item,
156 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
158 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
162 static void gtk_list_drag_begin (GtkWidget *widget,
163 GdkDragContext *context);
166 static GtkContainerClass *parent_class = NULL;
167 static guint list_signals[LAST_SIGNAL] = { 0 };
169 static const gchar *vadjustment_key = "gtk-vadjustment";
170 static guint vadjustment_key_id = 0;
171 static const gchar *hadjustment_key = "gtk-hadjustment";
172 static guint hadjustment_key_id = 0;
175 gtk_list_get_type (void)
177 static GtkType list_type = 0;
181 static const GtkTypeInfo list_info =
185 sizeof (GtkListClass),
186 (GtkClassInitFunc) gtk_list_class_init,
187 (GtkObjectInitFunc) gtk_list_init,
188 /* reserved_1 */ NULL,
189 /* reserved_2 */ NULL,
190 (GtkClassInitFunc) NULL,
193 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
200 gtk_list_class_init (GtkListClass *class)
202 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
203 GtkObjectClass *object_class;
204 GtkWidgetClass *widget_class;
205 GtkContainerClass *container_class;
207 object_class = (GtkObjectClass*) class;
208 widget_class = (GtkWidgetClass*) class;
209 container_class = (GtkContainerClass*) class;
211 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
213 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
214 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
216 gobject_class->dispose = gtk_list_dispose;
219 object_class->set_arg = gtk_list_set_arg;
220 object_class->get_arg = gtk_list_get_arg;
222 widget_class->unmap = gtk_list_unmap;
223 widget_class->style_set = gtk_list_style_set;
224 widget_class->realize = gtk_list_realize;
225 widget_class->button_press_event = gtk_list_button_press;
226 widget_class->button_release_event = gtk_list_button_release;
227 widget_class->motion_notify_event = gtk_list_motion_notify;
228 widget_class->size_request = gtk_list_size_request;
229 widget_class->size_allocate = gtk_list_size_allocate;
230 widget_class->drag_begin = gtk_list_drag_begin;
231 widget_class->focus = gtk_list_focus;
233 container_class->add = gtk_list_add;
234 container_class->remove = gtk_list_remove;
235 container_class->forall = gtk_list_forall;
236 container_class->child_type = gtk_list_child_type;
237 container_class->set_focus_child = gtk_list_set_focus_child;
239 class->selection_changed = NULL;
240 class->select_child = gtk_real_list_select_child;
241 class->unselect_child = gtk_real_list_unselect_child;
243 list_signals[SELECTION_CHANGED] =
244 gtk_signal_new ("selection_changed",
246 GTK_CLASS_TYPE (object_class),
247 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
248 _gtk_marshal_VOID__VOID,
250 list_signals[SELECT_CHILD] =
251 gtk_signal_new ("select_child",
253 GTK_CLASS_TYPE (object_class),
254 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
255 _gtk_marshal_VOID__OBJECT,
258 list_signals[UNSELECT_CHILD] =
259 gtk_signal_new ("unselect_child",
261 GTK_CLASS_TYPE (object_class),
262 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
263 _gtk_marshal_VOID__OBJECT,
267 gtk_object_add_arg_type ("GtkList::selection_mode",
268 GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
273 gtk_list_init (GtkList *list)
275 list->children = NULL;
276 list->selection = NULL;
278 list->undo_selection = NULL;
279 list->undo_unselection = NULL;
281 list->last_focus_child = NULL;
282 list->undo_focus_child = NULL;
289 list->anchor_state = GTK_STATE_SELECTED;
291 list->selection_mode = GTK_SELECTION_SINGLE;
292 list->drag_selection = FALSE;
293 list->add_mode = FALSE;
297 gtk_list_set_arg (GtkObject *object,
301 GtkList *list = GTK_LIST (object);
305 case ARG_SELECTION_MODE:
306 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
312 gtk_list_get_arg (GtkObject *object,
316 GtkList *list = GTK_LIST (object);
320 case ARG_SELECTION_MODE:
321 GTK_VALUE_ENUM (*arg) = list->selection_mode;
324 arg->type = GTK_TYPE_INVALID;
332 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
336 /* Private GtkObject Methods :
341 gtk_list_dispose (GObject *object)
343 gtk_list_clear_items (GTK_LIST (object), 0, -1);
345 G_OBJECT_CLASS (parent_class)->dispose (object);
349 /* Private GtkWidget Methods :
351 * gtk_list_size_request
352 * gtk_list_size_allocate
355 * gtk_list_motion_notify
356 * gtk_list_button_press
357 * gtk_list_button_release
360 gtk_list_size_request (GtkWidget *widget,
361 GtkRequisition *requisition)
367 g_return_if_fail (GTK_IS_LIST (widget));
368 g_return_if_fail (requisition != NULL);
370 list = GTK_LIST (widget);
371 requisition->width = 0;
372 requisition->height = 0;
374 children = list->children;
377 child = children->data;
378 children = children->next;
380 if (GTK_WIDGET_VISIBLE (child))
382 GtkRequisition child_requisition;
384 gtk_widget_size_request (child, &child_requisition);
386 requisition->width = MAX (requisition->width,
387 child_requisition.width);
388 requisition->height += child_requisition.height;
392 requisition->width += GTK_CONTAINER (list)->border_width * 2;
393 requisition->height += GTK_CONTAINER (list)->border_width * 2;
395 requisition->width = MAX (requisition->width, 1);
396 requisition->height = MAX (requisition->height, 1);
400 gtk_list_size_allocate (GtkWidget *widget,
401 GtkAllocation *allocation)
405 GtkAllocation child_allocation;
408 g_return_if_fail (GTK_IS_LIST (widget));
409 g_return_if_fail (allocation != NULL);
411 list = GTK_LIST (widget);
413 widget->allocation = *allocation;
414 if (GTK_WIDGET_REALIZED (widget))
415 gdk_window_move_resize (widget->window,
416 allocation->x, allocation->y,
417 allocation->width, allocation->height);
421 child_allocation.x = GTK_CONTAINER (list)->border_width;
422 child_allocation.y = GTK_CONTAINER (list)->border_width;
423 child_allocation.width = MAX (1, (gint)allocation->width -
424 child_allocation.x * 2);
426 children = list->children;
430 child = children->data;
431 children = children->next;
433 if (GTK_WIDGET_VISIBLE (child))
435 GtkRequisition child_requisition;
436 gtk_widget_get_child_requisition (child, &child_requisition);
438 child_allocation.height = child_requisition.height;
440 gtk_widget_size_allocate (child, &child_allocation);
442 child_allocation.y += child_allocation.height;
449 gtk_list_realize (GtkWidget *widget)
451 GdkWindowAttr attributes;
452 gint attributes_mask;
454 g_return_if_fail (GTK_IS_LIST (widget));
456 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
458 attributes.window_type = GDK_WINDOW_CHILD;
459 attributes.x = widget->allocation.x;
460 attributes.y = widget->allocation.y;
461 attributes.width = widget->allocation.width;
462 attributes.height = widget->allocation.height;
463 attributes.wclass = GDK_INPUT_OUTPUT;
464 attributes.visual = gtk_widget_get_visual (widget);
465 attributes.colormap = gtk_widget_get_colormap (widget);
466 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
468 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
470 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
471 &attributes, attributes_mask);
472 gdk_window_set_user_data (widget->window, widget);
474 widget->style = gtk_style_attach (widget->style, widget->window);
475 gdk_window_set_background (widget->window,
476 &widget->style->base[GTK_STATE_NORMAL]);
480 list_has_grab (GtkList *list)
482 return (GTK_WIDGET_HAS_GRAB (list) &&
483 gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (list))));
488 gtk_list_unmap (GtkWidget *widget)
492 g_return_if_fail (GTK_IS_LIST (widget));
494 if (!GTK_WIDGET_MAPPED (widget))
497 list = GTK_LIST (widget);
499 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
501 if (list_has_grab (list))
503 gtk_list_end_drag_selection (list);
505 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_MULTIPLE)
506 gtk_list_end_selection (list);
509 gdk_window_hide (widget->window);
513 gtk_list_motion_notify (GtkWidget *widget,
514 GdkEventMotion *event)
517 GtkWidget *item = NULL;
519 GtkContainer *container;
527 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
528 g_return_val_if_fail (event != NULL, FALSE);
530 list = GTK_LIST (widget);
532 if (!list->drag_selection || !list->children)
535 container = GTK_CONTAINER (widget);
537 if (event->is_hint || event->window != widget->window)
538 gdk_window_get_pointer (widget->window, &x, &y, NULL);
545 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
547 /* horizontal autoscrolling */
548 if (adj && widget->allocation.width > adj->page_size &&
549 (x < adj->value || x >= adj->value + adj->page_size))
551 if (list->htimer == 0)
553 list->htimer = gtk_timeout_add
554 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
556 if (!((x < adj->value && adj->value <= 0) ||
557 (x > adj->value + adj->page_size &&
558 adj->value >= adj->upper - adj->page_size)))
563 value = adj->value + (x - adj->value) / 2 - 1;
565 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
567 gtk_adjustment_set_value (adj,
569 adj->upper - adj->page_size));
577 /* vertical autoscrolling */
578 for (work = list->children; work; length++, work = work->next)
582 item = GTK_WIDGET (work->data);
583 if (item->allocation.y > y ||
584 (item->allocation.y <= y &&
585 item->allocation.y + item->allocation.height > y))
589 if (work->data == container->focus_child)
596 if (list->vtimer != 0)
599 if (!((y < 0 && focus_row == 0) ||
600 (y > widget->allocation.height && focus_row >= length - 1)))
601 list->vtimer = gtk_timeout_add (SCROLL_TIME,
602 (GtkFunction) gtk_list_vertical_timeout,
605 if (row != focus_row)
606 gtk_widget_grab_focus (item);
608 switch (list->selection_mode)
610 case GTK_SELECTION_BROWSE:
611 gtk_list_select_child (list, item);
613 case GTK_SELECTION_MULTIPLE:
614 gtk_list_update_extended_selection (list, row);
624 gtk_list_button_press (GtkWidget *widget,
625 GdkEventButton *event)
630 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
631 g_return_val_if_fail (event != NULL, FALSE);
633 if (event->button != 1)
636 list = GTK_LIST (widget);
637 item = gtk_get_event_widget ((GdkEvent*) event);
639 while (item && !GTK_IS_LIST_ITEM (item))
642 if (item && (item->parent == widget))
647 if (event->type == GDK_BUTTON_PRESS)
649 gtk_grab_add (widget);
650 list->drag_selection = TRUE;
652 else if (list_has_grab (list))
653 gtk_list_end_drag_selection (list);
655 if (!GTK_WIDGET_HAS_FOCUS(item))
656 gtk_widget_grab_focus (item);
660 list->add_mode = FALSE;
661 gtk_widget_queue_draw (item);
664 switch (list->selection_mode)
666 case GTK_SELECTION_SINGLE:
667 if (event->type != GDK_BUTTON_PRESS)
668 gtk_list_select_child (list, item);
670 list->undo_focus_child = item;
673 case GTK_SELECTION_BROWSE:
676 case GTK_SELECTION_MULTIPLE:
677 focus_row = g_list_index (list->children, item);
679 if (list->last_focus_child)
680 last_focus_row = g_list_index (list->children,
681 list->last_focus_child);
684 last_focus_row = focus_row;
685 list->last_focus_child = item;
688 if (event->type != GDK_BUTTON_PRESS)
690 if (list->anchor >= 0)
692 gtk_list_update_extended_selection (list, focus_row);
693 gtk_list_end_selection (list);
695 gtk_list_select_child (list, item);
699 if (event->state & GDK_CONTROL_MASK)
701 if (event->state & GDK_SHIFT_MASK)
703 if (list->anchor < 0)
705 g_list_free (list->undo_selection);
706 g_list_free (list->undo_unselection);
707 list->undo_selection = NULL;
708 list->undo_unselection = NULL;
710 list->anchor = last_focus_row;
711 list->drag_pos = last_focus_row;
712 list->undo_focus_child = list->last_focus_child;
714 gtk_list_update_extended_selection (list, focus_row);
718 if (list->anchor < 0)
719 gtk_list_set_anchor (list, TRUE,
720 focus_row, list->last_focus_child);
722 gtk_list_update_extended_selection (list, focus_row);
727 if (event->state & GDK_SHIFT_MASK)
729 gtk_list_set_anchor (list, FALSE,
730 last_focus_row, list->last_focus_child);
731 gtk_list_update_extended_selection (list, focus_row);
735 if (list->anchor < 0)
736 gtk_list_set_anchor (list, FALSE, focus_row,
737 list->last_focus_child);
739 gtk_list_update_extended_selection (list, focus_row);
753 gtk_list_button_release (GtkWidget *widget,
754 GdkEventButton *event)
759 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
760 g_return_val_if_fail (event != NULL, FALSE);
762 list = GTK_LIST (widget);
764 /* we don't handle button 2 and 3 */
765 if (event->button != 1)
768 if (list->drag_selection)
770 gtk_list_end_drag_selection (list);
772 switch (list->selection_mode)
774 case GTK_SELECTION_MULTIPLE:
775 if (!(event->state & GDK_SHIFT_MASK))
776 gtk_list_end_selection (list);
779 case GTK_SELECTION_SINGLE:
781 item = gtk_get_event_widget ((GdkEvent*) event);
783 while (item && !GTK_IS_LIST_ITEM (item))
786 if (item && item->parent == widget)
788 if (list->undo_focus_child == item)
789 gtk_list_toggle_row (list, item);
791 list->undo_focus_child = NULL;
805 gtk_list_style_set (GtkWidget *widget,
806 GtkStyle *previous_style)
808 g_return_if_fail (widget != NULL);
810 if (previous_style && GTK_WIDGET_REALIZED (widget))
811 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
814 /* GtkContainer Methods :
818 * gtk_list_child_type
819 * gtk_list_set_focus_child
823 gtk_list_add (GtkContainer *container,
828 g_return_if_fail (GTK_IS_LIST (container));
829 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
831 item_list = g_list_alloc ();
832 item_list->data = widget;
834 gtk_list_append_items (GTK_LIST (container), item_list);
838 gtk_list_remove (GtkContainer *container,
843 g_return_if_fail (GTK_IS_LIST (container));
844 g_return_if_fail (widget != NULL);
845 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
847 item_list = g_list_alloc ();
848 item_list->data = widget;
850 gtk_list_remove_items (GTK_LIST (container), item_list);
852 g_list_free (item_list);
856 gtk_list_forall (GtkContainer *container,
857 gboolean include_internals,
858 GtkCallback callback,
859 gpointer callback_data)
865 g_return_if_fail (GTK_IS_LIST (container));
866 g_return_if_fail (callback != NULL);
868 list = GTK_LIST (container);
869 children = list->children;
873 child = children->data;
874 children = children->next;
876 (* callback) (child, callback_data);
881 gtk_list_child_type (GtkContainer *container)
883 return GTK_TYPE_LIST_ITEM;
887 gtk_list_set_focus_child (GtkContainer *container,
892 g_return_if_fail (GTK_IS_LIST (container));
895 g_return_if_fail (GTK_IS_WIDGET (child));
897 list = GTK_LIST (container);
899 if (child != container->focus_child)
901 if (container->focus_child)
903 list->last_focus_child = container->focus_child;
904 gtk_widget_unref (container->focus_child);
906 container->focus_child = child;
907 if (container->focus_child)
908 gtk_widget_ref (container->focus_child);
911 /* check for v adjustment */
912 if (container->focus_child)
914 GtkAdjustment *adjustment;
916 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
919 gtk_adjustment_clamp_page (adjustment,
920 container->focus_child->allocation.y,
921 (container->focus_child->allocation.y +
922 container->focus_child->allocation.height));
923 switch (list->selection_mode)
925 case GTK_SELECTION_BROWSE:
926 gtk_list_select_child (list, child);
928 case GTK_SELECTION_MULTIPLE:
929 if (!list->last_focus_child && !list->add_mode)
931 list->undo_focus_child = list->last_focus_child;
932 gtk_list_unselect_all (list);
933 gtk_list_select_child (list, child);
943 gtk_list_focus (GtkWidget *widget,
944 GtkDirectionType direction)
946 gint return_val = FALSE;
947 GtkContainer *container;
949 container = GTK_CONTAINER (widget);
951 if (container->focus_child == NULL ||
952 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
954 if (GTK_LIST (container)->last_focus_child)
955 gtk_container_set_focus_child
956 (container, GTK_LIST (container)->last_focus_child);
958 if (GTK_WIDGET_CLASS (parent_class)->focus)
959 return_val = GTK_WIDGET_CLASS (parent_class)->focus (widget,
967 list = GTK_LIST (container);
968 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
969 gtk_list_end_selection (list);
971 if (container->focus_child)
972 list->last_focus_child = container->focus_child;
979 /* Public GtkList Methods :
981 * gtk_list_insert_items
982 * gtk_list_append_items
983 * gtk_list_prepend_items
984 * gtk_list_remove_items
985 * gtk_list_remove_items_no_unref
986 * gtk_list_clear_items
988 * gtk_list_child_position
991 gtk_list_insert_items (GtkList *list,
1000 g_return_if_fail (GTK_IS_LIST (list));
1005 gtk_list_end_drag_selection (list);
1006 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1007 gtk_list_end_selection (list);
1012 widget = tmp_list->data;
1013 tmp_list = tmp_list->next;
1015 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1016 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1017 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1019 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1020 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1022 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1023 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1025 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1026 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1028 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1029 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1031 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1032 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1034 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1035 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1037 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1038 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1040 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1041 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1043 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1044 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1046 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1047 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1049 gtk_signal_connect (GTK_OBJECT (widget), "select",
1050 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1052 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1053 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1055 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1056 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1061 nchildren = g_list_length (list->children);
1062 if ((position < 0) || (position > nchildren))
1063 position = nchildren;
1065 if (position == nchildren)
1069 tmp_list = g_list_last (list->children);
1070 tmp_list->next = items;
1071 items->prev = tmp_list;
1075 list->children = items;
1080 tmp_list = g_list_nth (list->children, position);
1081 last = g_list_last (items);
1084 tmp_list->prev->next = items;
1085 last->next = tmp_list;
1086 items->prev = tmp_list->prev;
1087 tmp_list->prev = last;
1089 if (tmp_list == list->children)
1090 list->children = items;
1093 if (list->children && !list->selection &&
1094 (list->selection_mode == GTK_SELECTION_BROWSE))
1096 widget = list->children->data;
1097 gtk_list_select_child (list, widget);
1102 gtk_list_append_items (GtkList *list,
1105 g_return_if_fail (GTK_IS_LIST (list));
1107 gtk_list_insert_items (list, items, -1);
1111 gtk_list_prepend_items (GtkList *list,
1114 g_return_if_fail (GTK_IS_LIST (list));
1116 gtk_list_insert_items (list, items, 0);
1120 gtk_list_remove_items (GtkList *list,
1123 gtk_list_remove_items_internal (list, items, FALSE);
1127 gtk_list_remove_items_no_unref (GtkList *list,
1130 gtk_list_remove_items_internal (list, items, TRUE);
1134 gtk_list_clear_items (GtkList *list,
1138 GtkContainer *container;
1140 GtkWidget *new_focus_child = NULL;
1145 gboolean grab_focus = FALSE;
1147 g_return_if_fail (GTK_IS_LIST (list));
1149 nchildren = g_list_length (list->children);
1154 if ((end < 0) || (end > nchildren))
1160 container = GTK_CONTAINER (list);
1162 gtk_list_end_drag_selection (list);
1163 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1165 if (list->anchor >= 0)
1166 gtk_list_end_selection (list);
1168 gtk_list_reset_extended_selection (list);
1171 start_list = g_list_nth (list->children, start);
1172 end_list = g_list_nth (list->children, end);
1174 if (start_list->prev)
1175 start_list->prev->next = end_list;
1176 if (end_list && end_list->prev)
1177 end_list->prev->next = NULL;
1179 end_list->prev = start_list->prev;
1180 if (start_list == list->children)
1181 list->children = end_list;
1183 if (container->focus_child)
1185 if (g_list_find (start_list, container->focus_child))
1187 if (start_list->prev)
1188 new_focus_child = start_list->prev->data;
1189 else if (list->children)
1190 new_focus_child = list->children->data;
1192 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1197 tmp_list = start_list;
1200 widget = tmp_list->data;
1201 tmp_list = tmp_list->next;
1203 gtk_widget_ref (widget);
1205 if (widget->state == GTK_STATE_SELECTED)
1206 gtk_list_unselect_child (list, widget);
1208 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1209 gtk_widget_unparent (widget);
1211 if (widget == list->undo_focus_child)
1212 list->undo_focus_child = NULL;
1213 if (widget == list->last_focus_child)
1214 list->last_focus_child = NULL;
1216 gtk_widget_unref (widget);
1219 g_list_free (start_list);
1221 if (new_focus_child)
1224 gtk_widget_grab_focus (new_focus_child);
1225 else if (container->focus_child)
1226 gtk_container_set_focus_child (container, new_focus_child);
1228 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1229 list->selection_mode == GTK_SELECTION_MULTIPLE) && !list->selection)
1231 list->last_focus_child = new_focus_child;
1232 gtk_list_select_child (list, new_focus_child);
1236 if (GTK_WIDGET_VISIBLE (list))
1237 gtk_widget_queue_resize (GTK_WIDGET (list));
1241 gtk_list_child_position (GtkList *list,
1247 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1248 g_return_val_if_fail (child != NULL, -1);
1251 children = list->children;
1255 if (child == GTK_WIDGET (children->data))
1259 children = children->next;
1266 /* Private GtkList Insert/Remove Item Functions:
1268 * gtk_list_remove_items_internal
1271 gtk_list_remove_items_internal (GtkList *list,
1276 GtkWidget *new_focus_child;
1277 GtkWidget *old_focus_child;
1278 GtkContainer *container;
1281 gboolean grab_focus = FALSE;
1283 g_return_if_fail (GTK_IS_LIST (list));
1288 container = GTK_CONTAINER (list);
1290 gtk_list_end_drag_selection (list);
1291 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
1293 if (list->anchor >= 0)
1294 gtk_list_end_selection (list);
1296 gtk_list_reset_extended_selection (list);
1302 widget = tmp_list->data;
1303 tmp_list = tmp_list->next;
1305 if (widget->state == GTK_STATE_SELECTED)
1306 gtk_list_unselect_child (list, widget);
1309 if (container->focus_child)
1311 old_focus_child = new_focus_child = container->focus_child;
1312 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1316 old_focus_child = new_focus_child = list->last_focus_child;
1321 widget = tmp_list->data;
1322 tmp_list = tmp_list->next;
1324 gtk_widget_ref (widget);
1326 gtk_widget_ref (widget);
1328 if (widget == new_focus_child)
1330 work = g_list_find (list->children, widget);
1335 new_focus_child = work->next->data;
1336 else if (list->children != work && work->prev)
1337 new_focus_child = work->prev->data;
1339 new_focus_child = NULL;
1343 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1344 list->children = g_list_remove (list->children, widget);
1345 gtk_widget_unparent (widget);
1347 if (widget == list->undo_focus_child)
1348 list->undo_focus_child = NULL;
1349 if (widget == list->last_focus_child)
1350 list->last_focus_child = NULL;
1352 gtk_widget_unref (widget);
1355 if (new_focus_child && new_focus_child != old_focus_child)
1358 gtk_widget_grab_focus (new_focus_child);
1359 else if (container->focus_child)
1360 gtk_container_set_focus_child (container, new_focus_child);
1362 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1364 list->last_focus_child = new_focus_child;
1365 gtk_list_select_child (list, new_focus_child);
1369 if (GTK_WIDGET_VISIBLE (list))
1370 gtk_widget_queue_resize (GTK_WIDGET (list));
1374 /* Public GtkList Selection Methods :
1376 * gtk_list_set_selection_mode
1377 * gtk_list_select_item
1378 * gtk_list_unselect_item
1379 * gtk_list_select_child
1380 * gtk_list_unselect_child
1381 * gtk_list_select_all
1382 * gtk_list_unselect_all
1383 * gtk_list_extend_selection
1384 * gtk_list_end_drag_selection
1385 * gtk_list_start_selection
1386 * gtk_list_end_selection
1387 * gtk_list_toggle_row
1388 * gtk_list_toggle_focus_row
1389 * gtk_list_toggle_add_mode
1390 * gtk_list_undo_selection
1393 gtk_list_set_selection_mode (GtkList *list,
1394 GtkSelectionMode mode)
1396 g_return_if_fail (GTK_IS_LIST (list));
1398 if (list->selection_mode == mode)
1401 list->selection_mode = mode;
1405 case GTK_SELECTION_SINGLE:
1406 case GTK_SELECTION_BROWSE:
1407 gtk_list_unselect_all (list);
1415 gtk_list_select_item (GtkList *list,
1420 g_return_if_fail (GTK_IS_LIST (list));
1422 tmp_list = g_list_nth (list->children, item);
1424 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1428 gtk_list_unselect_item (GtkList *list,
1433 g_return_if_fail (GTK_IS_LIST (list));
1435 tmp_list = g_list_nth (list->children, item);
1437 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1441 gtk_list_select_child (GtkList *list,
1444 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1448 gtk_list_unselect_child (GtkList *list,
1451 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1455 gtk_list_select_all (GtkList *list)
1457 GtkContainer *container;
1459 g_return_if_fail (GTK_IS_LIST (list));
1461 if (!list->children)
1464 if (list_has_grab (list))
1465 gtk_list_end_drag_selection (list);
1467 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1468 gtk_list_end_selection (list);
1470 container = GTK_CONTAINER (list);
1472 switch (list->selection_mode)
1474 case GTK_SELECTION_BROWSE:
1475 if (container->focus_child)
1477 gtk_list_select_child (list, container->focus_child);
1481 case GTK_SELECTION_MULTIPLE:
1482 g_list_free (list->undo_selection);
1483 g_list_free (list->undo_unselection);
1484 list->undo_selection = NULL;
1485 list->undo_unselection = NULL;
1487 if (list->children &&
1488 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1489 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1491 list->anchor_state = GTK_STATE_SELECTED;
1494 list->undo_focus_child = container->focus_child;
1495 gtk_list_update_extended_selection (list, g_list_length(list->children));
1496 gtk_list_end_selection (list);
1504 gtk_list_unselect_all (GtkList *list)
1506 GtkContainer *container;
1510 g_return_if_fail (GTK_IS_LIST (list));
1512 if (!list->children)
1515 if (list_has_grab (list))
1516 gtk_list_end_drag_selection (list);
1518 if (list->selection_mode == GTK_SELECTION_MULTIPLE && list->anchor >= 0)
1519 gtk_list_end_selection (list);
1521 container = GTK_CONTAINER (list);
1523 switch (list->selection_mode)
1525 case GTK_SELECTION_BROWSE:
1526 if (container->focus_child)
1528 gtk_list_select_child (list, container->focus_child);
1532 case GTK_SELECTION_MULTIPLE:
1533 gtk_list_reset_extended_selection (list);
1539 work = list->selection;
1545 gtk_list_unselect_child (list, item);
1550 gtk_list_extend_selection (GtkList *list,
1551 GtkScrollType scroll_type,
1553 gboolean auto_start_selection)
1555 GtkContainer *container;
1557 g_return_if_fail (GTK_IS_LIST (list));
1559 if (list_has_grab (list) ||
1560 list->selection_mode != GTK_SELECTION_MULTIPLE)
1563 container = GTK_CONTAINER (list);
1565 if (auto_start_selection)
1569 focus_row = g_list_index (list->children, container->focus_child);
1570 gtk_list_set_anchor (list, list->add_mode, focus_row,
1571 container->focus_child);
1573 else if (list->anchor < 0)
1576 gtk_list_move_focus_child (list, scroll_type, position);
1577 gtk_list_update_extended_selection
1578 (list, g_list_index (list->children, container->focus_child));
1582 gtk_list_end_drag_selection (GtkList *list)
1584 g_return_if_fail (GTK_IS_LIST (list));
1586 list->drag_selection = FALSE;
1587 if (GTK_WIDGET_HAS_GRAB (list))
1588 gtk_grab_remove (GTK_WIDGET (list));
1592 gtk_timeout_remove (list->htimer);
1597 gtk_timeout_remove (list->vtimer);
1603 gtk_list_start_selection (GtkList *list)
1605 GtkContainer *container;
1608 g_return_if_fail (GTK_IS_LIST (list));
1610 if (list_has_grab (list))
1613 container = GTK_CONTAINER (list);
1615 if ((focus_row = g_list_index (list->selection, container->focus_child))
1617 gtk_list_set_anchor (list, list->add_mode,
1618 focus_row, container->focus_child);
1622 gtk_list_end_selection (GtkList *list)
1631 g_return_if_fail (GTK_IS_LIST (list));
1633 if (list_has_grab (list) || list->anchor < 0)
1636 i = MIN (list->anchor, list->drag_pos);
1637 e = MAX (list->anchor, list->drag_pos);
1639 top_down = (list->anchor < list->drag_pos);
1642 list->drag_pos = -1;
1644 if (list->undo_selection)
1646 work = list->selection;
1647 list->selection = list->undo_selection;
1648 list->undo_selection = work;
1649 work = list->selection;
1654 item_index = g_list_index (list->children, item);
1655 if (item_index < i || item_index > e)
1657 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1658 gtk_list_unselect_child (list, item);
1659 list->undo_selection = g_list_prepend (list->undo_selection,
1667 for (work = g_list_nth (list->children, i); i <= e;
1668 i++, work = work->next)
1671 if (g_list_find (list->selection, item))
1673 if (item->state == GTK_STATE_NORMAL)
1675 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1676 gtk_list_unselect_child (list, item);
1677 list->undo_selection = g_list_prepend (list->undo_selection,
1681 else if (item->state == GTK_STATE_SELECTED)
1683 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1684 list->undo_unselection = g_list_prepend (list->undo_unselection,
1691 for (work = g_list_nth (list->children, e); i <= e;
1692 e--, work = work->prev)
1695 if (g_list_find (list->selection, item))
1697 if (item->state == GTK_STATE_NORMAL)
1699 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1700 gtk_list_unselect_child (list, item);
1701 list->undo_selection = g_list_prepend (list->undo_selection,
1705 else if (item->state == GTK_STATE_SELECTED)
1707 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1708 list->undo_unselection = g_list_prepend (list->undo_unselection,
1714 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1715 gtk_list_select_child (list, GTK_WIDGET (work->data));
1721 gtk_list_toggle_row (GtkList *list,
1724 g_return_if_fail (GTK_IS_LIST (list));
1725 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1727 switch (list->selection_mode)
1729 case GTK_SELECTION_MULTIPLE:
1730 case GTK_SELECTION_SINGLE:
1731 if (item->state == GTK_STATE_SELECTED)
1733 gtk_list_unselect_child (list, item);
1736 case GTK_SELECTION_BROWSE:
1737 gtk_list_select_child (list, item);
1743 gtk_list_toggle_focus_row (GtkList *list)
1745 GtkContainer *container;
1748 g_return_if_fail (list != 0);
1749 g_return_if_fail (GTK_IS_LIST (list));
1751 container = GTK_CONTAINER (list);
1753 if (list_has_grab (list) || !container->focus_child)
1756 switch (list->selection_mode)
1758 case GTK_SELECTION_SINGLE:
1759 gtk_list_toggle_row (list, container->focus_child);
1761 case GTK_SELECTION_MULTIPLE:
1762 if ((focus_row = g_list_index (list->children, container->focus_child))
1766 g_list_free (list->undo_selection);
1767 g_list_free (list->undo_unselection);
1768 list->undo_selection = NULL;
1769 list->undo_unselection = NULL;
1771 list->anchor = focus_row;
1772 list->drag_pos = focus_row;
1773 list->undo_focus_child = container->focus_child;
1776 gtk_list_fake_toggle_row (list, container->focus_child);
1778 gtk_list_fake_unselect_all (list, container->focus_child);
1780 gtk_list_end_selection (list);
1788 gtk_list_toggle_add_mode (GtkList *list)
1790 GtkContainer *container;
1792 g_return_if_fail (list != 0);
1793 g_return_if_fail (GTK_IS_LIST (list));
1795 if (list_has_grab (list) ||
1796 list->selection_mode != GTK_SELECTION_MULTIPLE)
1799 container = GTK_CONTAINER (list);
1803 list->add_mode = FALSE;
1804 list->anchor_state = GTK_STATE_SELECTED;
1807 list->add_mode = TRUE;
1809 if (container->focus_child)
1810 gtk_widget_queue_draw (container->focus_child);
1814 gtk_list_undo_selection (GtkList *list)
1818 g_return_if_fail (GTK_IS_LIST (list));
1820 if (list->selection_mode != GTK_SELECTION_MULTIPLE ||
1821 list_has_grab (list))
1824 if (list->anchor >= 0)
1825 gtk_list_end_selection (list);
1827 if (!(list->undo_selection || list->undo_unselection))
1829 gtk_list_unselect_all (list);
1833 for (work = list->undo_selection; work; work = work->next)
1834 gtk_list_select_child (list, GTK_WIDGET (work->data));
1836 for (work = list->undo_unselection; work; work = work->next)
1837 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1839 if (list->undo_focus_child)
1841 GtkContainer *container;
1843 container = GTK_CONTAINER (list);
1845 if (container->focus_child &&
1846 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1847 gtk_widget_grab_focus (list->undo_focus_child);
1849 gtk_container_set_focus_child (container, list->undo_focus_child);
1852 list->undo_focus_child = NULL;
1854 g_list_free (list->undo_selection);
1855 g_list_free (list->undo_unselection);
1856 list->undo_selection = NULL;
1857 list->undo_unselection = NULL;
1861 /* Private GtkList Selection Methods :
1863 * gtk_real_list_select_child
1864 * gtk_real_list_unselect_child
1867 gtk_real_list_select_child (GtkList *list,
1870 g_return_if_fail (GTK_IS_LIST (list));
1871 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1873 switch (child->state)
1875 case GTK_STATE_SELECTED:
1876 case GTK_STATE_INSENSITIVE:
1879 gtk_list_item_select (GTK_LIST_ITEM (child));
1885 gtk_real_list_unselect_child (GtkList *list,
1888 g_return_if_fail (GTK_IS_LIST (list));
1889 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1891 if (child->state == GTK_STATE_SELECTED)
1892 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1896 /* Private GtkList Selection Functions :
1898 * gtk_list_set_anchor
1899 * gtk_list_fake_unselect_all
1900 * gtk_list_fake_toggle_row
1901 * gtk_list_update_extended_selection
1902 * gtk_list_reset_extended_selection
1905 gtk_list_set_anchor (GtkList *list,
1908 GtkWidget *undo_focus_child)
1912 g_return_if_fail (GTK_IS_LIST (list));
1914 if (list->selection_mode != GTK_SELECTION_MULTIPLE || list->anchor >= 0)
1917 g_list_free (list->undo_selection);
1918 g_list_free (list->undo_unselection);
1919 list->undo_selection = NULL;
1920 list->undo_unselection = NULL;
1922 if ((work = g_list_nth (list->children, anchor)))
1925 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1928 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1929 list->anchor_state = GTK_STATE_SELECTED;
1933 list->anchor = anchor;
1934 list->drag_pos = anchor;
1935 list->undo_focus_child = undo_focus_child;
1939 gtk_list_fake_unselect_all (GtkList *list,
1944 if (item && item->state == GTK_STATE_NORMAL)
1945 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1947 list->undo_selection = list->selection;
1948 list->selection = NULL;
1950 for (work = list->undo_selection; work; work = work->next)
1951 if (work->data != item)
1952 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1956 gtk_list_fake_toggle_row (GtkList *list,
1962 if (item->state == GTK_STATE_NORMAL)
1964 list->anchor_state = GTK_STATE_SELECTED;
1965 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1969 list->anchor_state = GTK_STATE_NORMAL;
1970 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1975 gtk_list_update_extended_selection (GtkList *list,
1989 length = g_list_length (list->children);
1993 if (list->selection_mode != GTK_SELECTION_MULTIPLE || !list->anchor < 0)
1996 /* extending downwards */
1997 if (row > list->drag_pos && list->anchor <= list->drag_pos)
1999 s2 = list->drag_pos + 1;
2002 /* extending upwards */
2003 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2006 e2 = list->drag_pos - 1;
2008 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2010 e1 = list->drag_pos;
2011 /* row and drag_pos on different sides of anchor :
2012 take back the selection between anchor and drag_pos,
2013 select between anchor and row */
2014 if (row < list->anchor)
2016 s1 = list->anchor + 1;
2018 e2 = list->anchor - 1;
2020 /* take back the selection between anchor and drag_pos */
2024 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2026 s1 = list->drag_pos;
2027 /* row and drag_pos on different sides of anchor :
2028 take back the selection between anchor and drag_pos,
2029 select between anchor and row */
2030 if (row > list->anchor)
2032 e1 = list->anchor - 1;
2033 s2 = list->anchor + 1;
2036 /* take back the selection between anchor and drag_pos */
2041 list->drag_pos = row;
2043 /* restore the elements between s1 and e1 */
2046 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2047 i++, work = work->next)
2049 if (g_list_find (list->selection, work->data))
2050 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2052 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2056 /* extend the selection between s2 and e2 */
2059 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2060 i++, work = work->next)
2061 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2062 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2067 gtk_list_reset_extended_selection (GtkList *list)
2069 g_return_if_fail (list != 0);
2070 g_return_if_fail (GTK_IS_LIST (list));
2072 g_list_free (list->undo_selection);
2073 g_list_free (list->undo_unselection);
2074 list->undo_selection = NULL;
2075 list->undo_unselection = NULL;
2078 list->drag_pos = -1;
2079 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2082 /* Public GtkList Scroll Methods :
2084 * gtk_list_scroll_horizontal
2085 * gtk_list_scroll_vertical
2088 gtk_list_scroll_horizontal (GtkList *list,
2089 GtkScrollType scroll_type,
2094 g_return_if_fail (list != 0);
2095 g_return_if_fail (GTK_IS_LIST (list));
2097 if (list_has_grab (list))
2101 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2104 switch (scroll_type)
2106 case GTK_SCROLL_STEP_UP:
2107 case GTK_SCROLL_STEP_BACKWARD:
2108 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2109 adj->upper - adj->page_size);
2111 case GTK_SCROLL_STEP_DOWN:
2112 case GTK_SCROLL_STEP_FORWARD:
2113 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2114 adj->upper - adj->page_size);
2116 case GTK_SCROLL_PAGE_UP:
2117 case GTK_SCROLL_PAGE_BACKWARD:
2118 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2119 adj->upper - adj->page_size);
2121 case GTK_SCROLL_PAGE_DOWN:
2122 case GTK_SCROLL_PAGE_FORWARD:
2123 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2124 adj->upper - adj->page_size);
2126 case GTK_SCROLL_JUMP:
2127 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2128 adj->lower, adj->upper - adj->page_size);
2133 gtk_adjustment_value_changed (adj);
2137 gtk_list_scroll_vertical (GtkList *list,
2138 GtkScrollType scroll_type,
2141 g_return_if_fail (GTK_IS_LIST (list));
2143 if (list_has_grab (list))
2146 if (list->selection_mode == GTK_SELECTION_MULTIPLE)
2148 GtkContainer *container;
2150 if (list->anchor >= 0)
2153 container = GTK_CONTAINER (list);
2154 list->undo_focus_child = container->focus_child;
2155 gtk_list_move_focus_child (list, scroll_type, position);
2156 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2158 gtk_list_unselect_all (list);
2159 gtk_list_select_child (list, container->focus_child);
2163 gtk_list_move_focus_child (list, scroll_type, position);
2167 /* Private GtkList Scroll/Focus Functions :
2169 * gtk_list_move_focus_child
2170 * gtk_list_horizontal_timeout
2171 * gtk_list_vertical_timeout
2174 gtk_list_move_focus_child (GtkList *list,
2175 GtkScrollType scroll_type,
2178 GtkContainer *container;
2184 g_return_if_fail (list != 0);
2185 g_return_if_fail (GTK_IS_LIST (list));
2187 container = GTK_CONTAINER (list);
2189 if (container->focus_child)
2190 work = g_list_find (list->children, container->focus_child);
2192 work = list->children;
2197 switch (scroll_type)
2199 case GTK_SCROLL_STEP_BACKWARD:
2202 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2204 case GTK_SCROLL_STEP_FORWARD:
2207 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2209 case GTK_SCROLL_PAGE_BACKWARD:
2214 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2218 gboolean correct = FALSE;
2220 new_value = adj->value;
2222 if (item->allocation.y <= adj->value)
2224 new_value = MAX (item->allocation.y + item->allocation.height
2225 - adj->page_size, adj->lower);
2229 if (item->allocation.y > new_value)
2230 for (; work; work = work->prev)
2232 item = GTK_WIDGET (work->data);
2233 if (item->allocation.y <= new_value &&
2234 item->allocation.y + item->allocation.height > new_value)
2238 for (; work; work = work->next)
2240 item = GTK_WIDGET (work->data);
2241 if (item->allocation.y <= new_value &&
2242 item->allocation.y + item->allocation.height > new_value)
2246 if (correct && work && work->next && item->allocation.y < new_value)
2247 item = work->next->data;
2250 item = list->children->data;
2252 gtk_widget_grab_focus (item);
2254 case GTK_SCROLL_PAGE_FORWARD:
2259 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2263 gboolean correct = FALSE;
2265 new_value = adj->value;
2267 if (item->allocation.y + item->allocation.height >=
2268 adj->value + adj->page_size)
2270 new_value = item->allocation.y;
2274 new_value = MIN (new_value + adj->page_size, adj->upper);
2276 if (item->allocation.y > new_value)
2277 for (; work; work = work->prev)
2279 item = GTK_WIDGET (work->data);
2280 if (item->allocation.y <= new_value &&
2281 item->allocation.y + item->allocation.height > new_value)
2285 for (; work; work = work->next)
2287 item = GTK_WIDGET (work->data);
2288 if (item->allocation.y <= new_value &&
2289 item->allocation.y + item->allocation.height > new_value)
2293 if (correct && work && work->prev &&
2294 item->allocation.y + item->allocation.height - 1 > new_value)
2295 item = work->prev->data;
2298 item = g_list_last (work)->data;
2300 gtk_widget_grab_focus (item);
2302 case GTK_SCROLL_JUMP:
2303 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2305 for (item = NULL, work = list->children; work; work =work->next)
2307 item = GTK_WIDGET (work->data);
2308 if (item->allocation.y <= new_value &&
2309 item->allocation.y + item->allocation.height > new_value)
2313 gtk_widget_grab_focus (item);
2321 do_fake_motion (GtkWidget *list)
2323 GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
2325 event->motion.send_event = TRUE;
2327 gtk_list_motion_notify (list, (GdkEventMotion *)event);
2328 gdk_event_free (event);
2332 gtk_list_horizontal_timeout (GtkWidget *list)
2334 GDK_THREADS_ENTER ();
2336 GTK_LIST (list)->htimer = 0;
2337 do_fake_motion (list);
2339 GDK_THREADS_LEAVE ();
2345 gtk_list_vertical_timeout (GtkWidget *list)
2347 GDK_THREADS_ENTER ();
2349 GTK_LIST (list)->vtimer = 0;
2350 do_fake_motion (list);
2352 GDK_THREADS_LEAVE ();
2358 /* Private GtkListItem Signal Functions :
2360 * gtk_list_signal_toggle_focus_row
2361 * gtk_list_signal_select_all
2362 * gtk_list_signal_unselect_all
2363 * gtk_list_signal_undo_selection
2364 * gtk_list_signal_start_selection
2365 * gtk_list_signal_end_selection
2366 * gtk_list_signal_extend_selection
2367 * gtk_list_signal_scroll_horizontal
2368 * gtk_list_signal_scroll_vertical
2369 * gtk_list_signal_toggle_add_mode
2370 * gtk_list_signal_item_select
2371 * gtk_list_signal_item_deselect
2372 * gtk_list_signal_item_toggle
2375 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2378 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2379 g_return_if_fail (GTK_IS_LIST (list));
2381 gtk_list_toggle_focus_row (list);
2385 gtk_list_signal_select_all (GtkListItem *list_item,
2388 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2389 g_return_if_fail (GTK_IS_LIST (list));
2391 gtk_list_select_all (list);
2395 gtk_list_signal_unselect_all (GtkListItem *list_item,
2398 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2399 g_return_if_fail (GTK_IS_LIST (list));
2401 gtk_list_unselect_all (list);
2405 gtk_list_signal_undo_selection (GtkListItem *list_item,
2408 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2409 g_return_if_fail (GTK_IS_LIST (list));
2411 gtk_list_undo_selection (list);
2415 gtk_list_signal_start_selection (GtkListItem *list_item,
2418 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2419 g_return_if_fail (GTK_IS_LIST (list));
2421 gtk_list_start_selection (list);
2425 gtk_list_signal_end_selection (GtkListItem *list_item,
2428 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2429 g_return_if_fail (GTK_IS_LIST (list));
2431 gtk_list_end_selection (list);
2435 gtk_list_signal_extend_selection (GtkListItem *list_item,
2436 GtkScrollType scroll_type,
2438 gboolean auto_start_selection,
2441 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2442 g_return_if_fail (GTK_IS_LIST (list));
2444 gtk_list_extend_selection (list, scroll_type, position,
2445 auto_start_selection);
2449 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2450 GtkScrollType scroll_type,
2454 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2455 g_return_if_fail (GTK_IS_LIST (list));
2457 gtk_list_scroll_horizontal (list, scroll_type, position);
2461 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2462 GtkScrollType scroll_type,
2466 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2467 g_return_if_fail (GTK_IS_LIST (list));
2469 gtk_list_scroll_vertical (list, scroll_type, position);
2473 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2476 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2477 g_return_if_fail (GTK_IS_LIST (list));
2479 gtk_list_toggle_add_mode (list);
2483 gtk_list_signal_item_select (GtkListItem *list_item,
2490 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2491 g_return_if_fail (GTK_IS_LIST (list));
2493 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2496 switch (list->selection_mode)
2498 case GTK_SELECTION_SINGLE:
2499 case GTK_SELECTION_BROWSE:
2501 selection = list->selection;
2505 tmp_list = selection;
2506 selection = selection->next;
2508 if (tmp_list->data == list_item)
2509 sel_list = tmp_list;
2511 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2516 list->selection = g_list_prepend (list->selection, list_item);
2517 gtk_widget_ref (GTK_WIDGET (list_item));
2519 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2521 case GTK_SELECTION_MULTIPLE:
2522 if (list->anchor >= 0)
2528 gtk_list_signal_item_deselect (GtkListItem *list_item,
2533 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2534 g_return_if_fail (GTK_IS_LIST (list));
2536 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2539 node = g_list_find (list->selection, list_item);
2543 list->selection = g_list_remove_link (list->selection, node);
2544 g_list_free_1 (node);
2545 gtk_widget_unref (GTK_WIDGET (list_item));
2546 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2551 gtk_list_signal_item_toggle (GtkListItem *list_item,
2554 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2555 g_return_if_fail (GTK_IS_LIST (list));
2557 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
2558 list->selection_mode == GTK_SELECTION_MULTIPLE) &&
2559 GTK_WIDGET (list_item)->state == GTK_STATE_NORMAL)
2561 gtk_widget_set_state (GTK_WIDGET (list_item), GTK_STATE_SELECTED);
2565 switch (GTK_WIDGET (list_item)->state)
2567 case GTK_STATE_SELECTED:
2568 gtk_list_signal_item_select (list_item, list);
2570 case GTK_STATE_NORMAL:
2571 gtk_list_signal_item_deselect (list_item, list);
2579 gtk_list_signal_drag_begin (GtkWidget *widget,
2580 GdkDragContext *context,
2583 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2584 g_return_if_fail (GTK_IS_LIST (list));
2586 gtk_list_drag_begin (GTK_WIDGET (list), context);
2590 gtk_list_drag_begin (GtkWidget *widget,
2591 GdkDragContext *context)
2595 g_return_if_fail (GTK_IS_LIST (widget));
2596 g_return_if_fail (context != NULL);
2598 list = GTK_LIST (widget);
2600 if (list->drag_selection)
2602 gtk_list_end_drag_selection (list);
2604 switch (list->selection_mode)
2606 case GTK_SELECTION_MULTIPLE:
2607 gtk_list_end_selection (list);
2609 case GTK_SELECTION_SINGLE:
2610 list->undo_focus_child = NULL;