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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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-1999. 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/.
28 #include "gtklistitem.h"
30 #include "gtksignal.h"
45 #define SCROLL_TIME 100
47 /** GtkList Methods **/
48 static void gtk_list_class_init (GtkListClass *klass);
49 static void gtk_list_init (GtkList *list);
50 static void gtk_list_set_arg (GtkObject *object,
53 static void gtk_list_get_arg (GtkObject *object,
56 /** GtkObject Methods **/
57 static void gtk_list_shutdown (GObject *object);
59 /** GtkWidget Methods **/
60 static void gtk_list_size_request (GtkWidget *widget,
61 GtkRequisition *requisition);
62 static void gtk_list_size_allocate (GtkWidget *widget,
63 GtkAllocation *allocation);
64 static void gtk_list_realize (GtkWidget *widget);
65 static void gtk_list_map (GtkWidget *widget);
66 static void gtk_list_unmap (GtkWidget *widget);
67 static void gtk_list_style_set (GtkWidget *widget,
68 GtkStyle *previous_style);
69 static void gtk_list_draw (GtkWidget *widget,
71 static gint gtk_list_expose (GtkWidget *widget,
72 GdkEventExpose *event);
73 static gint gtk_list_motion_notify (GtkWidget *widget,
74 GdkEventMotion *event);
75 static gint gtk_list_button_press (GtkWidget *widget,
76 GdkEventButton *event);
77 static gint gtk_list_button_release (GtkWidget *widget,
78 GdkEventButton *event);
80 /** GtkContainer Methods **/
81 static void gtk_list_add (GtkContainer *container,
83 static void gtk_list_remove (GtkContainer *container,
85 static void gtk_list_forall (GtkContainer *container,
86 gboolean include_internals,
88 gpointer callback_data);
89 static GtkType gtk_list_child_type (GtkContainer *container);
90 static void gtk_list_set_focus_child (GtkContainer *container,
92 static gint gtk_list_focus (GtkContainer *container,
93 GtkDirectionType direction);
95 /** GtkList Private Functions **/
96 static void gtk_list_move_focus_child (GtkList *list,
97 GtkScrollType scroll_type,
99 static gint gtk_list_horizontal_timeout (GtkWidget *list);
100 static gint gtk_list_vertical_timeout (GtkWidget *list);
101 static void gtk_list_remove_items_internal (GtkList *list,
105 /** GtkList Selection Methods **/
106 static void gtk_real_list_select_child (GtkList *list,
108 static void gtk_real_list_unselect_child (GtkList *list,
111 /** GtkList Selection Functions **/
112 static void gtk_list_set_anchor (GtkList *list,
115 GtkWidget *undo_focus_child);
116 static void gtk_list_fake_unselect_all (GtkList *list,
118 static void gtk_list_fake_toggle_row (GtkList *list,
120 static void gtk_list_update_extended_selection (GtkList *list,
122 static void gtk_list_reset_extended_selection (GtkList *list);
124 /** GtkListItem Signal Functions **/
125 static void gtk_list_signal_drag_begin (GtkWidget *widget,
126 GdkDragContext *context,
128 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
130 static void gtk_list_signal_select_all (GtkListItem *list_item,
132 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
134 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
136 static void gtk_list_signal_start_selection (GtkListItem *list_item,
138 static void gtk_list_signal_end_selection (GtkListItem *list_item,
140 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
141 GtkScrollType scroll_type,
143 gboolean auto_start_selection,
145 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
146 GtkScrollType scroll_type,
149 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
150 GtkScrollType scroll_type,
153 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
155 static void gtk_list_signal_item_select (GtkListItem *list_item,
157 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
159 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
163 static void gtk_list_drag_begin (GtkWidget *widget,
164 GdkDragContext *context);
167 static GtkContainerClass *parent_class = NULL;
168 static guint list_signals[LAST_SIGNAL] = { 0 };
170 static const gchar *vadjustment_key = "gtk-vadjustment";
171 static guint vadjustment_key_id = 0;
172 static const gchar *hadjustment_key = "gtk-hadjustment";
173 static guint hadjustment_key_id = 0;
176 gtk_list_get_type (void)
178 static GtkType list_type = 0;
182 static const GtkTypeInfo list_info =
186 sizeof (GtkListClass),
187 (GtkClassInitFunc) gtk_list_class_init,
188 (GtkObjectInitFunc) gtk_list_init,
189 /* reserved_1 */ NULL,
190 /* reserved_2 */ NULL,
191 (GtkClassInitFunc) NULL,
194 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
201 gtk_list_class_init (GtkListClass *class)
203 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
204 GtkObjectClass *object_class;
205 GtkWidgetClass *widget_class;
206 GtkContainerClass *container_class;
208 object_class = (GtkObjectClass*) class;
209 widget_class = (GtkWidgetClass*) class;
210 container_class = (GtkContainerClass*) class;
212 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
214 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
215 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
217 gobject_class->shutdown = gtk_list_shutdown;
219 list_signals[SELECTION_CHANGED] =
220 gtk_signal_new ("selection_changed",
222 GTK_CLASS_TYPE (object_class),
223 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
224 gtk_marshal_NONE__NONE,
226 list_signals[SELECT_CHILD] =
227 gtk_signal_new ("select_child",
229 GTK_CLASS_TYPE (object_class),
230 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
231 gtk_marshal_NONE__POINTER,
234 list_signals[UNSELECT_CHILD] =
235 gtk_signal_new ("unselect_child",
237 GTK_CLASS_TYPE (object_class),
238 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
239 gtk_marshal_NONE__POINTER,
243 gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
245 object_class->set_arg = gtk_list_set_arg;
246 object_class->get_arg = gtk_list_get_arg;
248 widget_class->map = gtk_list_map;
249 widget_class->unmap = gtk_list_unmap;
250 widget_class->style_set = gtk_list_style_set;
251 widget_class->realize = gtk_list_realize;
252 widget_class->draw = gtk_list_draw;
253 widget_class->expose_event = gtk_list_expose;
254 widget_class->button_press_event = gtk_list_button_press;
255 widget_class->button_release_event = gtk_list_button_release;
256 widget_class->motion_notify_event = gtk_list_motion_notify;
257 widget_class->size_request = gtk_list_size_request;
258 widget_class->size_allocate = gtk_list_size_allocate;
259 widget_class->drag_begin = gtk_list_drag_begin;
261 container_class->add = gtk_list_add;
262 container_class->remove = gtk_list_remove;
263 container_class->forall = gtk_list_forall;
264 container_class->child_type = gtk_list_child_type;
265 container_class->set_focus_child = gtk_list_set_focus_child;
266 container_class->focus = gtk_list_focus;
268 class->selection_changed = NULL;
269 class->select_child = gtk_real_list_select_child;
270 class->unselect_child = gtk_real_list_unselect_child;
272 gtk_object_add_arg_type ("GtkList::selection_mode",
273 GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
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_shutdown (GObject *object)
348 gtk_list_clear_items (GTK_LIST (object), 0, -1);
350 G_OBJECT_CLASS (parent_class)->shutdown (object);
354 /* Private GtkWidget Methods :
356 * gtk_list_size_request
357 * gtk_list_size_allocate
361 * gtk_list_motion_notify
362 * gtk_list_button_press
363 * gtk_list_button_release
366 gtk_list_size_request (GtkWidget *widget,
367 GtkRequisition *requisition)
373 g_return_if_fail (widget != NULL);
374 g_return_if_fail (GTK_IS_LIST (widget));
375 g_return_if_fail (requisition != NULL);
377 list = GTK_LIST (widget);
378 requisition->width = 0;
379 requisition->height = 0;
381 children = list->children;
384 child = children->data;
385 children = children->next;
387 if (GTK_WIDGET_VISIBLE (child))
389 GtkRequisition child_requisition;
391 gtk_widget_size_request (child, &child_requisition);
393 requisition->width = MAX (requisition->width,
394 child_requisition.width);
395 requisition->height += child_requisition.height;
399 requisition->width += GTK_CONTAINER (list)->border_width * 2;
400 requisition->height += GTK_CONTAINER (list)->border_width * 2;
402 requisition->width = MAX (requisition->width, 1);
403 requisition->height = MAX (requisition->height, 1);
407 gtk_list_size_allocate (GtkWidget *widget,
408 GtkAllocation *allocation)
412 GtkAllocation child_allocation;
415 g_return_if_fail (widget != NULL);
416 g_return_if_fail (GTK_IS_LIST (widget));
417 g_return_if_fail (allocation != NULL);
419 list = GTK_LIST (widget);
421 widget->allocation = *allocation;
422 if (GTK_WIDGET_REALIZED (widget))
423 gdk_window_move_resize (widget->window,
424 allocation->x, allocation->y,
425 allocation->width, allocation->height);
429 child_allocation.x = GTK_CONTAINER (list)->border_width;
430 child_allocation.y = GTK_CONTAINER (list)->border_width;
431 child_allocation.width = MAX (1, (gint)allocation->width -
432 child_allocation.x * 2);
434 children = list->children;
438 child = children->data;
439 children = children->next;
441 if (GTK_WIDGET_VISIBLE (child))
443 GtkRequisition child_requisition;
444 gtk_widget_get_child_requisition (child, &child_requisition);
446 child_allocation.height = child_requisition.height;
448 gtk_widget_size_allocate (child, &child_allocation);
450 child_allocation.y += child_allocation.height;
457 gtk_list_realize (GtkWidget *widget)
459 GdkWindowAttr attributes;
460 gint attributes_mask;
462 g_return_if_fail (widget != NULL);
463 g_return_if_fail (GTK_IS_LIST (widget));
465 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
467 attributes.window_type = GDK_WINDOW_CHILD;
468 attributes.x = widget->allocation.x;
469 attributes.y = widget->allocation.y;
470 attributes.width = widget->allocation.width;
471 attributes.height = widget->allocation.height;
472 attributes.wclass = GDK_INPUT_OUTPUT;
473 attributes.visual = gtk_widget_get_visual (widget);
474 attributes.colormap = gtk_widget_get_colormap (widget);
475 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
477 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
479 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
480 &attributes, attributes_mask);
481 gdk_window_set_user_data (widget->window, widget);
483 widget->style = gtk_style_attach (widget->style, widget->window);
484 gdk_window_set_background (widget->window,
485 &widget->style->base[GTK_STATE_NORMAL]);
489 gtk_list_map (GtkWidget *widget)
495 g_return_if_fail (widget != NULL);
496 g_return_if_fail (GTK_IS_LIST (widget));
498 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
499 list = GTK_LIST (widget);
501 children = list->children;
504 child = children->data;
505 children = children->next;
507 if (GTK_WIDGET_VISIBLE (child) &&
508 !GTK_WIDGET_MAPPED (child))
509 gtk_widget_map (child);
512 gdk_window_show (widget->window);
516 gtk_list_unmap (GtkWidget *widget)
520 g_return_if_fail (widget != NULL);
521 g_return_if_fail (GTK_IS_LIST (widget));
523 if (!GTK_WIDGET_MAPPED (widget))
526 list = GTK_LIST (widget);
528 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
530 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
532 gtk_list_end_drag_selection (list);
534 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_EXTENDED)
535 gtk_list_end_selection (list);
538 gdk_window_hide (widget->window);
542 gtk_list_motion_notify (GtkWidget *widget,
543 GdkEventMotion *event)
546 GtkWidget *item = NULL;
548 GtkContainer *container;
556 g_return_val_if_fail (widget != NULL, FALSE);
557 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
558 g_return_val_if_fail (event != NULL, FALSE);
560 list = GTK_LIST (widget);
562 if (!list->drag_selection || !list->children)
565 container = GTK_CONTAINER (widget);
567 if (event->is_hint || event->window != widget->window)
568 gdk_window_get_pointer (widget->window, &x, &y, NULL);
575 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
577 /* horizontal autoscrolling */
578 if (adj && widget->allocation.width > adj->page_size &&
579 (x < adj->value || x >= adj->value + adj->page_size))
581 if (list->htimer == 0)
583 list->htimer = gtk_timeout_add
584 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
586 if (!((x < adj->value && adj->value <= 0) ||
587 (x > adj->value + adj->page_size &&
588 adj->value >= adj->upper - adj->page_size)))
593 value = adj->value + (x - adj->value) / 2 - 1;
595 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
597 gtk_adjustment_set_value (adj,
599 adj->upper - adj->page_size));
607 /* vertical autoscrolling */
608 for (work = list->children; work; length++, work = work->next)
612 item = GTK_WIDGET (work->data);
613 if (item->allocation.y > y ||
614 (item->allocation.y <= y &&
615 item->allocation.y + item->allocation.height > y))
619 if (work->data == container->focus_child)
626 if (list->vtimer != 0)
629 if (!((y < 0 && focus_row == 0) ||
630 (y > widget->allocation.height && focus_row >= length - 1)))
631 list->vtimer = gtk_timeout_add (SCROLL_TIME,
632 (GtkFunction) gtk_list_vertical_timeout,
635 if (row != focus_row)
636 gtk_widget_grab_focus (item);
638 switch (list->selection_mode)
640 case GTK_SELECTION_BROWSE:
641 gtk_list_select_child (list, item);
643 case GTK_SELECTION_EXTENDED:
644 gtk_list_update_extended_selection (list, row);
654 gtk_list_button_press (GtkWidget *widget,
655 GdkEventButton *event)
660 g_return_val_if_fail (widget != NULL, FALSE);
661 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
662 g_return_val_if_fail (event != NULL, FALSE);
664 if (event->button != 1)
667 list = GTK_LIST (widget);
668 item = gtk_get_event_widget ((GdkEvent*) event);
670 while (item && !GTK_IS_LIST_ITEM (item))
673 if (item && (item->parent == widget))
678 if (event->type == GDK_BUTTON_PRESS)
680 if (gdk_pointer_grab (widget->window, TRUE,
681 GDK_POINTER_MOTION_HINT_MASK |
682 GDK_BUTTON1_MOTION_MASK |
683 GDK_BUTTON_RELEASE_MASK,
684 NULL, NULL, event->time))
687 gtk_grab_add (widget);
688 list->drag_selection = TRUE;
690 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
691 gtk_list_end_drag_selection (list);
693 if (!GTK_WIDGET_HAS_FOCUS(item))
694 gtk_widget_grab_focus (item);
698 list->add_mode = FALSE;
699 gtk_widget_queue_draw (item);
702 switch (list->selection_mode)
704 case GTK_SELECTION_SINGLE:
705 case GTK_SELECTION_MULTIPLE:
706 if (event->type != GDK_BUTTON_PRESS)
707 gtk_list_select_child (list, item);
709 list->undo_focus_child = item;
712 case GTK_SELECTION_BROWSE:
715 case GTK_SELECTION_EXTENDED:
716 focus_row = g_list_index (list->children, item);
718 if (list->last_focus_child)
719 last_focus_row = g_list_index (list->children,
720 list->last_focus_child);
723 last_focus_row = focus_row;
724 list->last_focus_child = item;
727 if (event->type != GDK_BUTTON_PRESS)
729 if (list->anchor >= 0)
731 gtk_list_update_extended_selection (list, focus_row);
732 gtk_list_end_selection (list);
734 gtk_list_select_child (list, item);
738 if (event->state & GDK_CONTROL_MASK)
740 if (event->state & GDK_SHIFT_MASK)
742 if (list->anchor < 0)
744 g_list_free (list->undo_selection);
745 g_list_free (list->undo_unselection);
746 list->undo_selection = NULL;
747 list->undo_unselection = NULL;
749 list->anchor = last_focus_row;
750 list->drag_pos = last_focus_row;
751 list->undo_focus_child = list->last_focus_child;
753 gtk_list_update_extended_selection (list, focus_row);
757 if (list->anchor < 0)
758 gtk_list_set_anchor (list, TRUE,
759 focus_row, list->last_focus_child);
761 gtk_list_update_extended_selection (list, focus_row);
766 if (event->state & GDK_SHIFT_MASK)
768 gtk_list_set_anchor (list, FALSE,
769 last_focus_row, list->last_focus_child);
770 gtk_list_update_extended_selection (list, focus_row);
774 if (list->anchor < 0)
775 gtk_list_set_anchor (list, FALSE, focus_row,
776 list->last_focus_child);
778 gtk_list_update_extended_selection (list, focus_row);
790 gtk_list_button_release (GtkWidget *widget,
791 GdkEventButton *event)
796 g_return_val_if_fail (widget != NULL, FALSE);
797 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
798 g_return_val_if_fail (event != NULL, FALSE);
800 list = GTK_LIST (widget);
802 /* we don't handle button 2 and 3 */
803 if (event->button != 1)
806 if (list->drag_selection)
808 gtk_list_end_drag_selection (list);
810 switch (list->selection_mode)
812 case GTK_SELECTION_EXTENDED:
813 if (!(event->state & GDK_SHIFT_MASK))
814 gtk_list_end_selection (list);
817 case GTK_SELECTION_SINGLE:
818 case GTK_SELECTION_MULTIPLE:
820 item = gtk_get_event_widget ((GdkEvent*) event);
822 while (item && !GTK_IS_LIST_ITEM (item))
825 if (item && item->parent == widget)
827 if (list->undo_focus_child == item)
828 gtk_list_toggle_row (list, item);
830 list->undo_focus_child = NULL;
842 gtk_list_draw (GtkWidget *widget,
847 GdkRectangle child_area;
850 g_return_if_fail (widget != NULL);
851 g_return_if_fail (GTK_IS_LIST (widget));
852 g_return_if_fail (area != NULL);
854 if (GTK_WIDGET_DRAWABLE (widget))
856 list = GTK_LIST (widget);
858 children = list->children;
861 child = children->data;
862 children = children->next;
864 if (gtk_widget_intersect (child, area, &child_area))
865 gtk_widget_draw (child, &child_area);
871 gtk_list_expose (GtkWidget *widget,
872 GdkEventExpose *event)
876 GdkEventExpose child_event;
879 g_return_val_if_fail (widget != NULL, FALSE);
880 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
881 g_return_val_if_fail (event != NULL, FALSE);
883 if (GTK_WIDGET_DRAWABLE (widget))
885 list = GTK_LIST (widget);
887 child_event = *event;
889 children = list->children;
892 child = children->data;
893 children = children->next;
895 if (GTK_WIDGET_NO_WINDOW (child) &&
896 gtk_widget_intersect (child, &event->area, &child_event.area))
897 gtk_widget_event (child, (GdkEvent*) &child_event);
905 gtk_list_style_set (GtkWidget *widget,
906 GtkStyle *previous_style)
908 g_return_if_fail (widget != NULL);
910 if (previous_style && GTK_WIDGET_REALIZED (widget))
911 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
914 /* GtkContainer Methods :
918 * gtk_list_child_type
919 * gtk_list_set_focus_child
923 gtk_list_add (GtkContainer *container,
928 g_return_if_fail (container != NULL);
929 g_return_if_fail (GTK_IS_LIST (container));
930 g_return_if_fail (widget != NULL);
931 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
933 item_list = g_list_alloc ();
934 item_list->data = widget;
936 gtk_list_append_items (GTK_LIST (container), item_list);
940 gtk_list_remove (GtkContainer *container,
945 g_return_if_fail (container != NULL);
946 g_return_if_fail (GTK_IS_LIST (container));
947 g_return_if_fail (widget != NULL);
948 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
950 item_list = g_list_alloc ();
951 item_list->data = widget;
953 gtk_list_remove_items (GTK_LIST (container), item_list);
955 g_list_free (item_list);
959 gtk_list_forall (GtkContainer *container,
960 gboolean include_internals,
961 GtkCallback callback,
962 gpointer callback_data)
968 g_return_if_fail (container != NULL);
969 g_return_if_fail (GTK_IS_LIST (container));
970 g_return_if_fail (callback != NULL);
972 list = GTK_LIST (container);
973 children = list->children;
977 child = children->data;
978 children = children->next;
980 (* callback) (child, callback_data);
985 gtk_list_child_type (GtkContainer *container)
987 return GTK_TYPE_LIST_ITEM;
991 gtk_list_set_focus_child (GtkContainer *container,
996 g_return_if_fail (container != NULL);
997 g_return_if_fail (GTK_IS_LIST (container));
1000 g_return_if_fail (GTK_IS_WIDGET (child));
1002 list = GTK_LIST (container);
1004 if (child != container->focus_child)
1006 if (container->focus_child)
1008 list->last_focus_child = container->focus_child;
1009 gtk_widget_unref (container->focus_child);
1011 container->focus_child = child;
1012 if (container->focus_child)
1013 gtk_widget_ref (container->focus_child);
1016 /* check for v adjustment */
1017 if (container->focus_child)
1019 GtkAdjustment *adjustment;
1021 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
1022 vadjustment_key_id);
1024 gtk_adjustment_clamp_page (adjustment,
1025 container->focus_child->allocation.y,
1026 (container->focus_child->allocation.y +
1027 container->focus_child->allocation.height));
1028 switch (list->selection_mode)
1030 case GTK_SELECTION_BROWSE:
1031 gtk_list_select_child (list, child);
1033 case GTK_SELECTION_EXTENDED:
1034 if (!list->last_focus_child && !list->add_mode)
1036 list->undo_focus_child = list->last_focus_child;
1037 gtk_list_unselect_all (list);
1038 gtk_list_select_child (list, child);
1048 gtk_list_focus (GtkContainer *container,
1049 GtkDirectionType direction)
1051 gint return_val = FALSE;
1053 g_return_val_if_fail (container != NULL, FALSE);
1054 g_return_val_if_fail (GTK_IS_LIST (container), FALSE);
1056 if (container->focus_child == NULL ||
1057 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
1059 if (GTK_LIST (container)->last_focus_child)
1060 gtk_container_set_focus_child
1061 (container, GTK_LIST (container)->last_focus_child);
1063 if (GTK_CONTAINER_CLASS (parent_class)->focus)
1064 return_val = GTK_CONTAINER_CLASS (parent_class)->focus (container,
1072 list = GTK_LIST (container);
1073 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1074 gtk_list_end_selection (list);
1076 if (container->focus_child)
1077 list->last_focus_child = container->focus_child;
1084 /* Public GtkList Methods :
1086 * gtk_list_insert_items
1087 * gtk_list_append_items
1088 * gtk_list_prepend_items
1089 * gtk_list_remove_items
1090 * gtk_list_remove_items_no_unref
1091 * gtk_list_clear_items
1093 * gtk_list_child_position
1096 gtk_list_insert_items (GtkList *list,
1105 g_return_if_fail (list != NULL);
1106 g_return_if_fail (GTK_IS_LIST (list));
1111 gtk_list_end_drag_selection (list);
1112 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1113 gtk_list_end_selection (list);
1118 widget = tmp_list->data;
1119 tmp_list = tmp_list->next;
1121 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1122 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1123 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1125 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1126 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1128 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1129 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1131 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1132 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1134 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1135 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1137 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1138 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1140 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1141 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1143 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1144 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1146 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1147 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1149 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1150 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1152 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1153 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1155 gtk_signal_connect (GTK_OBJECT (widget), "select",
1156 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1158 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1159 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1161 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1162 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1165 if (GTK_WIDGET_REALIZED (widget->parent))
1166 gtk_widget_realize (widget);
1168 if (GTK_WIDGET_VISIBLE (widget->parent) && GTK_WIDGET_VISIBLE (widget))
1170 if (GTK_WIDGET_MAPPED (widget->parent))
1171 gtk_widget_map (widget);
1173 gtk_widget_queue_resize (widget);
1178 nchildren = g_list_length (list->children);
1179 if ((position < 0) || (position > nchildren))
1180 position = nchildren;
1182 if (position == nchildren)
1186 tmp_list = g_list_last (list->children);
1187 tmp_list->next = items;
1188 items->prev = tmp_list;
1192 list->children = items;
1197 tmp_list = g_list_nth (list->children, position);
1198 last = g_list_last (items);
1201 tmp_list->prev->next = items;
1202 last->next = tmp_list;
1203 items->prev = tmp_list->prev;
1204 tmp_list->prev = last;
1206 if (tmp_list == list->children)
1207 list->children = items;
1210 if (list->children && !list->selection &&
1211 (list->selection_mode == GTK_SELECTION_BROWSE))
1213 widget = list->children->data;
1214 gtk_list_select_child (list, widget);
1219 gtk_list_append_items (GtkList *list,
1222 g_return_if_fail (list != NULL);
1223 g_return_if_fail (GTK_IS_LIST (list));
1225 gtk_list_insert_items (list, items, -1);
1229 gtk_list_prepend_items (GtkList *list,
1232 g_return_if_fail (list != NULL);
1233 g_return_if_fail (GTK_IS_LIST (list));
1235 gtk_list_insert_items (list, items, 0);
1239 gtk_list_remove_items (GtkList *list,
1242 gtk_list_remove_items_internal (list, items, FALSE);
1246 gtk_list_remove_items_no_unref (GtkList *list,
1249 gtk_list_remove_items_internal (list, items, TRUE);
1253 gtk_list_clear_items (GtkList *list,
1257 GtkContainer *container;
1259 GtkWidget *new_focus_child = NULL;
1264 gboolean grab_focus = FALSE;
1266 g_return_if_fail (list != NULL);
1267 g_return_if_fail (GTK_IS_LIST (list));
1269 nchildren = g_list_length (list->children);
1274 if ((end < 0) || (end > nchildren))
1280 container = GTK_CONTAINER (list);
1282 gtk_list_end_drag_selection (list);
1283 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1285 if (list->anchor >= 0)
1286 gtk_list_end_selection (list);
1288 gtk_list_reset_extended_selection (list);
1291 start_list = g_list_nth (list->children, start);
1292 end_list = g_list_nth (list->children, end);
1294 if (start_list->prev)
1295 start_list->prev->next = end_list;
1296 if (end_list && end_list->prev)
1297 end_list->prev->next = NULL;
1299 end_list->prev = start_list->prev;
1300 if (start_list == list->children)
1301 list->children = end_list;
1303 if (container->focus_child)
1305 if (g_list_find (start_list, container->focus_child))
1307 if (start_list->prev)
1308 new_focus_child = start_list->prev->data;
1309 else if (list->children)
1310 new_focus_child = list->children->prev->data;
1312 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1317 tmp_list = start_list;
1320 widget = tmp_list->data;
1321 tmp_list = tmp_list->next;
1323 if (widget->state == GTK_STATE_SELECTED)
1324 gtk_list_unselect_child (list, widget);
1326 if (widget == list->undo_focus_child)
1327 list->undo_focus_child = NULL;
1328 if (widget == list->last_focus_child)
1329 list->last_focus_child = NULL;
1331 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1332 gtk_widget_unparent (widget);
1335 g_list_free (start_list);
1337 if (new_focus_child)
1340 gtk_widget_grab_focus (new_focus_child);
1341 else if (container->focus_child)
1342 gtk_container_set_focus_child (container, new_focus_child);
1344 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1345 list->selection_mode == GTK_SELECTION_EXTENDED) && !list->selection)
1347 list->last_focus_child = new_focus_child;
1348 gtk_list_select_child (list, new_focus_child);
1352 if (GTK_WIDGET_VISIBLE (list))
1353 gtk_widget_queue_resize (GTK_WIDGET (list));
1357 gtk_list_child_position (GtkList *list,
1363 g_return_val_if_fail (list != NULL, -1);
1364 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1365 g_return_val_if_fail (child != NULL, -1);
1368 children = list->children;
1372 if (child == GTK_WIDGET (children->data))
1376 children = children->next;
1383 /* Private GtkList Insert/Remove Item Functions:
1385 * gtk_list_remove_items_internal
1388 gtk_list_remove_items_internal (GtkList *list,
1393 GtkWidget *new_focus_child;
1394 GtkWidget *old_focus_child;
1395 GtkContainer *container;
1398 gboolean grab_focus = FALSE;
1400 g_return_if_fail (list != NULL);
1401 g_return_if_fail (GTK_IS_LIST (list));
1406 container = GTK_CONTAINER (list);
1408 gtk_list_end_drag_selection (list);
1409 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1411 if (list->anchor >= 0)
1412 gtk_list_end_selection (list);
1414 gtk_list_reset_extended_selection (list);
1420 widget = tmp_list->data;
1421 tmp_list = tmp_list->next;
1423 if (widget->state == GTK_STATE_SELECTED)
1424 gtk_list_unselect_child (list, widget);
1427 if (container->focus_child)
1429 old_focus_child = new_focus_child = container->focus_child;
1430 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1434 old_focus_child = new_focus_child = list->last_focus_child;
1439 widget = tmp_list->data;
1440 tmp_list = tmp_list->next;
1443 gtk_widget_ref (widget);
1445 if (widget == new_focus_child)
1447 work = g_list_find (list->children, widget);
1452 new_focus_child = work->next->data;
1453 else if (list->children != work && work->prev)
1454 new_focus_child = work->prev->data;
1456 new_focus_child = NULL;
1460 if (widget == list->undo_focus_child)
1461 list->undo_focus_child = NULL;
1462 if (widget == list->last_focus_child)
1463 list->last_focus_child = NULL;
1465 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1466 list->children = g_list_remove (list->children, widget);
1467 gtk_widget_unparent (widget);
1470 if (new_focus_child && new_focus_child != old_focus_child)
1473 gtk_widget_grab_focus (new_focus_child);
1474 else if (container->focus_child)
1475 gtk_container_set_focus_child (container, new_focus_child);
1477 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1479 list->last_focus_child = new_focus_child;
1480 gtk_list_select_child (list, new_focus_child);
1484 if (GTK_WIDGET_VISIBLE (list))
1485 gtk_widget_queue_resize (GTK_WIDGET (list));
1489 /* Public GtkList Selection Methods :
1491 * gtk_list_set_selection_mode
1492 * gtk_list_select_item
1493 * gtk_list_unselect_item
1494 * gtk_list_select_child
1495 * gtk_list_unselect_child
1496 * gtk_list_select_all
1497 * gtk_list_unselect_all
1498 * gtk_list_extend_selection
1499 * gtk_list_end_drag_selection
1500 * gtk_list_start_selection
1501 * gtk_list_end_selection
1502 * gtk_list_toggle_row
1503 * gtk_list_toggle_focus_row
1504 * gtk_list_toggle_add_mode
1505 * gtk_list_undo_selection
1508 gtk_list_set_selection_mode (GtkList *list,
1509 GtkSelectionMode mode)
1511 g_return_if_fail (list != NULL);
1512 g_return_if_fail (GTK_IS_LIST (list));
1514 if (list->selection_mode == mode)
1517 list->selection_mode = mode;
1521 case GTK_SELECTION_SINGLE:
1522 case GTK_SELECTION_BROWSE:
1523 gtk_list_unselect_all (list);
1531 gtk_list_select_item (GtkList *list,
1536 g_return_if_fail (list != NULL);
1537 g_return_if_fail (GTK_IS_LIST (list));
1539 tmp_list = g_list_nth (list->children, item);
1541 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1545 gtk_list_unselect_item (GtkList *list,
1550 g_return_if_fail (list != NULL);
1551 g_return_if_fail (GTK_IS_LIST (list));
1553 tmp_list = g_list_nth (list->children, item);
1555 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1559 gtk_list_select_child (GtkList *list,
1562 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1566 gtk_list_unselect_child (GtkList *list,
1569 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1573 gtk_list_select_all (GtkList *list)
1575 GtkContainer *container;
1578 g_return_if_fail (list != NULL);
1579 g_return_if_fail (GTK_IS_LIST (list));
1581 if (!list->children)
1584 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1585 gtk_list_end_drag_selection (list);
1587 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1588 gtk_list_end_selection (list);
1590 container = GTK_CONTAINER (list);
1592 switch (list->selection_mode)
1594 case GTK_SELECTION_BROWSE:
1595 if (container->focus_child)
1597 gtk_list_select_child (list, container->focus_child);
1601 case GTK_SELECTION_EXTENDED:
1602 g_list_free (list->undo_selection);
1603 g_list_free (list->undo_unselection);
1604 list->undo_selection = NULL;
1605 list->undo_unselection = NULL;
1607 if (list->children &&
1608 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1609 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1611 list->anchor_state = GTK_STATE_SELECTED;
1614 list->undo_focus_child = container->focus_child;
1615 gtk_list_update_extended_selection (list, g_list_length(list->children));
1616 gtk_list_end_selection (list);
1618 case GTK_SELECTION_MULTIPLE:
1619 for (work = list->children; work; work = work->next)
1621 if (GTK_WIDGET_STATE (work->data) == GTK_STATE_NORMAL)
1622 gtk_list_select_child (list, GTK_WIDGET (work->data));
1631 gtk_list_unselect_all (GtkList *list)
1633 GtkContainer *container;
1637 g_return_if_fail (list != NULL);
1638 g_return_if_fail (GTK_IS_LIST (list));
1640 if (!list->children)
1643 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1644 gtk_list_end_drag_selection (list);
1646 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1647 gtk_list_end_selection (list);
1649 container = GTK_CONTAINER (list);
1651 switch (list->selection_mode)
1653 case GTK_SELECTION_BROWSE:
1654 if (container->focus_child)
1656 gtk_list_select_child (list, container->focus_child);
1660 case GTK_SELECTION_EXTENDED:
1661 gtk_list_reset_extended_selection (list);
1667 work = list->selection;
1673 gtk_list_unselect_child (list, item);
1678 gtk_list_extend_selection (GtkList *list,
1679 GtkScrollType scroll_type,
1681 gboolean auto_start_selection)
1683 GtkContainer *container;
1685 g_return_if_fail (list != NULL);
1686 g_return_if_fail (GTK_IS_LIST (list));
1688 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1689 list->selection_mode != GTK_SELECTION_EXTENDED)
1692 container = GTK_CONTAINER (list);
1694 if (auto_start_selection)
1698 focus_row = g_list_index (list->children, container->focus_child);
1699 gtk_list_set_anchor (list, list->add_mode, focus_row,
1700 container->focus_child);
1702 else if (list->anchor < 0)
1705 gtk_list_move_focus_child (list, scroll_type, position);
1706 gtk_list_update_extended_selection
1707 (list, g_list_index (list->children, container->focus_child));
1711 gtk_list_end_drag_selection (GtkList *list)
1713 g_return_if_fail (list != NULL);
1714 g_return_if_fail (GTK_IS_LIST (list));
1716 list->drag_selection = FALSE;
1717 if (GTK_WIDGET_HAS_GRAB (list))
1719 gtk_grab_remove (GTK_WIDGET (list));
1720 if (gdk_pointer_is_grabbed())
1721 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1725 gtk_timeout_remove (list->htimer);
1730 gtk_timeout_remove (list->vtimer);
1736 gtk_list_start_selection (GtkList *list)
1738 GtkContainer *container;
1741 g_return_if_fail (list != NULL);
1742 g_return_if_fail (GTK_IS_LIST (list));
1744 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1747 container = GTK_CONTAINER (list);
1749 if ((focus_row = g_list_index (list->selection, container->focus_child))
1751 gtk_list_set_anchor (list, list->add_mode,
1752 focus_row, container->focus_child);
1756 gtk_list_end_selection (GtkList *list)
1765 g_return_if_fail (list != NULL);
1766 g_return_if_fail (GTK_IS_LIST (list));
1768 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1772 i = MIN (list->anchor, list->drag_pos);
1773 e = MAX (list->anchor, list->drag_pos);
1775 top_down = (list->anchor < list->drag_pos);
1778 list->drag_pos = -1;
1780 if (list->undo_selection)
1782 work = list->selection;
1783 list->selection = list->undo_selection;
1784 list->undo_selection = work;
1785 work = list->selection;
1790 item_index = g_list_index (list->children, item);
1791 if (item_index < i || item_index > e)
1793 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1794 gtk_list_unselect_child (list, item);
1795 list->undo_selection = g_list_prepend (list->undo_selection,
1803 for (work = g_list_nth (list->children, i); i <= e;
1804 i++, work = work->next)
1807 if (g_list_find (list->selection, item))
1809 if (item->state == GTK_STATE_NORMAL)
1811 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1812 gtk_list_unselect_child (list, item);
1813 list->undo_selection = g_list_prepend (list->undo_selection,
1817 else if (item->state == GTK_STATE_SELECTED)
1819 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1820 list->undo_unselection = g_list_prepend (list->undo_unselection,
1827 for (work = g_list_nth (list->children, e); i <= e;
1828 e--, work = work->prev)
1831 if (g_list_find (list->selection, item))
1833 if (item->state == GTK_STATE_NORMAL)
1835 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1836 gtk_list_unselect_child (list, item);
1837 list->undo_selection = g_list_prepend (list->undo_selection,
1841 else if (item->state == GTK_STATE_SELECTED)
1843 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1844 list->undo_unselection = g_list_prepend (list->undo_unselection,
1850 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1851 gtk_list_select_child (list, GTK_WIDGET (work->data));
1857 gtk_list_toggle_row (GtkList *list,
1860 g_return_if_fail (list != NULL);
1861 g_return_if_fail (GTK_IS_LIST (list));
1862 g_return_if_fail (item != NULL);
1863 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1865 switch (list->selection_mode)
1867 case GTK_SELECTION_EXTENDED:
1868 case GTK_SELECTION_MULTIPLE:
1869 case GTK_SELECTION_SINGLE:
1870 if (item->state == GTK_STATE_SELECTED)
1872 gtk_list_unselect_child (list, item);
1875 case GTK_SELECTION_BROWSE:
1876 gtk_list_select_child (list, item);
1882 gtk_list_toggle_focus_row (GtkList *list)
1884 GtkContainer *container;
1887 g_return_if_fail (list != 0);
1888 g_return_if_fail (GTK_IS_LIST (list));
1890 container = GTK_CONTAINER (list);
1892 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1893 !container->focus_child)
1896 switch (list->selection_mode)
1898 case GTK_SELECTION_SINGLE:
1899 case GTK_SELECTION_MULTIPLE:
1900 gtk_list_toggle_row (list, container->focus_child);
1902 case GTK_SELECTION_EXTENDED:
1903 if ((focus_row = g_list_index (list->children, container->focus_child))
1907 g_list_free (list->undo_selection);
1908 g_list_free (list->undo_unselection);
1909 list->undo_selection = NULL;
1910 list->undo_unselection = NULL;
1912 list->anchor = focus_row;
1913 list->drag_pos = focus_row;
1914 list->undo_focus_child = container->focus_child;
1917 gtk_list_fake_toggle_row (list, container->focus_child);
1919 gtk_list_fake_unselect_all (list, container->focus_child);
1921 gtk_list_end_selection (list);
1929 gtk_list_toggle_add_mode (GtkList *list)
1931 GtkContainer *container;
1933 g_return_if_fail (list != 0);
1934 g_return_if_fail (GTK_IS_LIST (list));
1936 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1937 list->selection_mode != GTK_SELECTION_EXTENDED)
1940 container = GTK_CONTAINER (list);
1944 list->add_mode = FALSE;
1945 list->anchor_state = GTK_STATE_SELECTED;
1948 list->add_mode = TRUE;
1950 if (container->focus_child)
1951 gtk_widget_queue_draw (container->focus_child);
1955 gtk_list_undo_selection (GtkList *list)
1959 g_return_if_fail (list != NULL);
1960 g_return_if_fail (GTK_IS_LIST (list));
1962 if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1963 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1966 if (list->anchor >= 0)
1967 gtk_list_end_selection (list);
1969 if (!(list->undo_selection || list->undo_unselection))
1971 gtk_list_unselect_all (list);
1975 for (work = list->undo_selection; work; work = work->next)
1976 gtk_list_select_child (list, GTK_WIDGET (work->data));
1978 for (work = list->undo_unselection; work; work = work->next)
1979 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1981 if (list->undo_focus_child)
1983 GtkContainer *container;
1985 container = GTK_CONTAINER (list);
1987 if (container->focus_child &&
1988 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1989 gtk_widget_grab_focus (list->undo_focus_child);
1991 gtk_container_set_focus_child (container, list->undo_focus_child);
1994 list->undo_focus_child = NULL;
1996 g_list_free (list->undo_selection);
1997 g_list_free (list->undo_unselection);
1998 list->undo_selection = NULL;
1999 list->undo_unselection = NULL;
2003 /* Private GtkList Selection Methods :
2005 * gtk_real_list_select_child
2006 * gtk_real_list_unselect_child
2009 gtk_real_list_select_child (GtkList *list,
2012 g_return_if_fail (list != NULL);
2013 g_return_if_fail (GTK_IS_LIST (list));
2014 g_return_if_fail (child != NULL);
2015 g_return_if_fail (GTK_IS_LIST_ITEM (child));
2017 switch (child->state)
2019 case GTK_STATE_SELECTED:
2020 case GTK_STATE_INSENSITIVE:
2023 gtk_list_item_select (GTK_LIST_ITEM (child));
2029 gtk_real_list_unselect_child (GtkList *list,
2032 g_return_if_fail (list != NULL);
2033 g_return_if_fail (GTK_IS_LIST (list));
2034 g_return_if_fail (child != NULL);
2035 g_return_if_fail (GTK_IS_LIST_ITEM (child));
2037 if (child->state == GTK_STATE_SELECTED)
2038 gtk_list_item_deselect (GTK_LIST_ITEM (child));
2042 /* Private GtkList Selection Functions :
2044 * gtk_list_set_anchor
2045 * gtk_list_fake_unselect_all
2046 * gtk_list_fake_toggle_row
2047 * gtk_list_update_extended_selection
2048 * gtk_list_reset_extended_selection
2051 gtk_list_set_anchor (GtkList *list,
2054 GtkWidget *undo_focus_child)
2058 g_return_if_fail (list != NULL);
2059 g_return_if_fail (GTK_IS_LIST (list));
2061 if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
2064 g_list_free (list->undo_selection);
2065 g_list_free (list->undo_unselection);
2066 list->undo_selection = NULL;
2067 list->undo_unselection = NULL;
2069 if ((work = g_list_nth (list->children, anchor)))
2072 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
2075 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
2076 list->anchor_state = GTK_STATE_SELECTED;
2080 list->anchor = anchor;
2081 list->drag_pos = anchor;
2082 list->undo_focus_child = undo_focus_child;
2086 gtk_list_fake_unselect_all (GtkList *list,
2091 if (item && item->state == GTK_STATE_NORMAL)
2092 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2094 list->undo_selection = list->selection;
2095 list->selection = NULL;
2097 for (work = list->undo_selection; work; work = work->next)
2098 if (work->data != item)
2099 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2103 gtk_list_fake_toggle_row (GtkList *list,
2109 if (item->state == GTK_STATE_NORMAL)
2111 list->anchor_state = GTK_STATE_SELECTED;
2112 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2116 list->anchor_state = GTK_STATE_NORMAL;
2117 gtk_widget_set_state (item, GTK_STATE_NORMAL);
2122 gtk_list_update_extended_selection (GtkList *list,
2136 length = g_list_length (list->children);
2140 if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
2143 /* extending downwards */
2144 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2146 s2 = list->drag_pos + 1;
2149 /* extending upwards */
2150 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2153 e2 = list->drag_pos - 1;
2155 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2157 e1 = list->drag_pos;
2158 /* row and drag_pos on different sides of anchor :
2159 take back the selection between anchor and drag_pos,
2160 select between anchor and row */
2161 if (row < list->anchor)
2163 s1 = list->anchor + 1;
2165 e2 = list->anchor - 1;
2167 /* take back the selection between anchor and drag_pos */
2171 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2173 s1 = list->drag_pos;
2174 /* row and drag_pos on different sides of anchor :
2175 take back the selection between anchor and drag_pos,
2176 select between anchor and row */
2177 if (row > list->anchor)
2179 e1 = list->anchor - 1;
2180 s2 = list->anchor + 1;
2183 /* take back the selection between anchor and drag_pos */
2188 list->drag_pos = row;
2190 /* restore the elements between s1 and e1 */
2193 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2194 i++, work = work->next)
2196 if (g_list_find (list->selection, work->data))
2197 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2199 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2203 /* extend the selection between s2 and e2 */
2206 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2207 i++, work = work->next)
2208 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2209 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2214 gtk_list_reset_extended_selection (GtkList *list)
2216 g_return_if_fail (list != 0);
2217 g_return_if_fail (GTK_IS_LIST (list));
2219 g_list_free (list->undo_selection);
2220 g_list_free (list->undo_unselection);
2221 list->undo_selection = NULL;
2222 list->undo_unselection = NULL;
2225 list->drag_pos = -1;
2226 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2229 /* Public GtkList Scroll Methods :
2231 * gtk_list_scroll_horizontal
2232 * gtk_list_scroll_vertical
2235 gtk_list_scroll_horizontal (GtkList *list,
2236 GtkScrollType scroll_type,
2241 g_return_if_fail (list != 0);
2242 g_return_if_fail (GTK_IS_LIST (list));
2244 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2248 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2251 switch (scroll_type)
2253 case GTK_SCROLL_STEP_BACKWARD:
2254 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2255 adj->upper - adj->page_size);
2257 case GTK_SCROLL_STEP_FORWARD:
2258 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2259 adj->upper - adj->page_size);
2261 case GTK_SCROLL_PAGE_BACKWARD:
2262 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2263 adj->upper - adj->page_size);
2265 case GTK_SCROLL_PAGE_FORWARD:
2266 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2267 adj->upper - adj->page_size);
2269 case GTK_SCROLL_JUMP:
2270 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2271 adj->lower, adj->upper - adj->page_size);
2276 gtk_adjustment_value_changed (adj);
2280 gtk_list_scroll_vertical (GtkList *list,
2281 GtkScrollType scroll_type,
2284 g_return_if_fail (list != NULL);
2285 g_return_if_fail (GTK_IS_LIST (list));
2287 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2290 if (list->selection_mode == GTK_SELECTION_EXTENDED)
2292 GtkContainer *container;
2294 if (list->anchor >= 0)
2297 container = GTK_CONTAINER (list);
2298 list->undo_focus_child = container->focus_child;
2299 gtk_list_move_focus_child (list, scroll_type, position);
2300 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2302 gtk_list_unselect_all (list);
2303 gtk_list_select_child (list, container->focus_child);
2307 gtk_list_move_focus_child (list, scroll_type, position);
2311 /* Private GtkList Scroll/Focus Functions :
2313 * gtk_list_move_focus_child
2314 * gtk_list_horizontal_timeout
2315 * gtk_list_vertical_timeout
2318 gtk_list_move_focus_child (GtkList *list,
2319 GtkScrollType scroll_type,
2322 GtkContainer *container;
2328 g_return_if_fail (list != 0);
2329 g_return_if_fail (GTK_IS_LIST (list));
2331 container = GTK_CONTAINER (list);
2333 if (container->focus_child)
2334 work = g_list_find (list->children, container->focus_child);
2336 work = list->children;
2341 switch (scroll_type)
2343 case GTK_SCROLL_STEP_BACKWARD:
2346 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2348 case GTK_SCROLL_STEP_FORWARD:
2351 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2353 case GTK_SCROLL_PAGE_BACKWARD:
2358 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2362 gboolean correct = FALSE;
2364 new_value = adj->value;
2366 if (item->allocation.y <= adj->value)
2368 new_value = MAX (item->allocation.y + item->allocation.height
2369 - adj->page_size, adj->lower);
2373 if (item->allocation.y > new_value)
2374 for (; work; work = work->prev)
2376 item = GTK_WIDGET (work->data);
2377 if (item->allocation.y <= new_value &&
2378 item->allocation.y + item->allocation.height > new_value)
2382 for (; work; work = work->next)
2384 item = GTK_WIDGET (work->data);
2385 if (item->allocation.y <= new_value &&
2386 item->allocation.y + item->allocation.height > new_value)
2390 if (correct && work && work->next && item->allocation.y < new_value)
2391 item = work->next->data;
2394 item = list->children->data;
2396 gtk_widget_grab_focus (item);
2398 case GTK_SCROLL_PAGE_FORWARD:
2403 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2407 gboolean correct = FALSE;
2409 new_value = adj->value;
2411 if (item->allocation.y + item->allocation.height >=
2412 adj->value + adj->page_size)
2414 new_value = item->allocation.y;
2418 new_value = MIN (new_value + adj->page_size, adj->upper);
2420 if (item->allocation.y > new_value)
2421 for (; work; work = work->prev)
2423 item = GTK_WIDGET (work->data);
2424 if (item->allocation.y <= new_value &&
2425 item->allocation.y + item->allocation.height > new_value)
2429 for (; work; work = work->next)
2431 item = GTK_WIDGET (work->data);
2432 if (item->allocation.y <= new_value &&
2433 item->allocation.y + item->allocation.height > new_value)
2437 if (correct && work && work->prev &&
2438 item->allocation.y + item->allocation.height - 1 > new_value)
2439 item = work->prev->data;
2442 item = g_list_last (work)->data;
2444 gtk_widget_grab_focus (item);
2446 case GTK_SCROLL_JUMP:
2447 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2449 for (item = NULL, work = list->children; work; work =work->next)
2451 item = GTK_WIDGET (work->data);
2452 if (item->allocation.y <= new_value &&
2453 item->allocation.y + item->allocation.height > new_value)
2457 gtk_widget_grab_focus (item);
2465 gtk_list_horizontal_timeout (GtkWidget *list)
2467 GdkEventMotion event = { 0 };
2469 GDK_THREADS_ENTER ();
2471 GTK_LIST (list)->htimer = 0;
2473 event.type = GDK_MOTION_NOTIFY;
2474 event.send_event = TRUE;
2476 gtk_list_motion_notify (list, &event);
2478 GDK_THREADS_LEAVE ();
2484 gtk_list_vertical_timeout (GtkWidget *list)
2486 GdkEventMotion event = { 0 };
2488 GDK_THREADS_ENTER ();
2490 GTK_LIST (list)->vtimer = 0;
2492 event.type = GDK_MOTION_NOTIFY;
2493 event.send_event = TRUE;
2495 gtk_list_motion_notify (list, &event);
2497 GDK_THREADS_LEAVE ();
2503 /* Private GtkListItem Signal Functions :
2505 * gtk_list_signal_toggle_focus_row
2506 * gtk_list_signal_select_all
2507 * gtk_list_signal_unselect_all
2508 * gtk_list_signal_undo_selection
2509 * gtk_list_signal_start_selection
2510 * gtk_list_signal_end_selection
2511 * gtk_list_signal_extend_selection
2512 * gtk_list_signal_scroll_horizontal
2513 * gtk_list_signal_scroll_vertical
2514 * gtk_list_signal_toggle_add_mode
2515 * gtk_list_signal_item_select
2516 * gtk_list_signal_item_deselect
2517 * gtk_list_signal_item_toggle
2520 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2523 g_return_if_fail (list_item != 0);
2524 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2525 g_return_if_fail (list != NULL);
2526 g_return_if_fail (GTK_IS_LIST (list));
2528 gtk_list_toggle_focus_row (list);
2532 gtk_list_signal_select_all (GtkListItem *list_item,
2535 g_return_if_fail (list_item != 0);
2536 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2537 g_return_if_fail (list != NULL);
2538 g_return_if_fail (GTK_IS_LIST (list));
2540 gtk_list_select_all (list);
2544 gtk_list_signal_unselect_all (GtkListItem *list_item,
2547 g_return_if_fail (list_item != 0);
2548 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2549 g_return_if_fail (list != NULL);
2550 g_return_if_fail (GTK_IS_LIST (list));
2552 gtk_list_unselect_all (list);
2556 gtk_list_signal_undo_selection (GtkListItem *list_item,
2559 g_return_if_fail (list_item != 0);
2560 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2561 g_return_if_fail (list != NULL);
2562 g_return_if_fail (GTK_IS_LIST (list));
2564 gtk_list_undo_selection (list);
2568 gtk_list_signal_start_selection (GtkListItem *list_item,
2571 g_return_if_fail (list_item != 0);
2572 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2573 g_return_if_fail (list != NULL);
2574 g_return_if_fail (GTK_IS_LIST (list));
2576 gtk_list_start_selection (list);
2580 gtk_list_signal_end_selection (GtkListItem *list_item,
2583 g_return_if_fail (list_item != 0);
2584 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2585 g_return_if_fail (list != NULL);
2586 g_return_if_fail (GTK_IS_LIST (list));
2588 gtk_list_end_selection (list);
2592 gtk_list_signal_extend_selection (GtkListItem *list_item,
2593 GtkScrollType scroll_type,
2595 gboolean auto_start_selection,
2598 g_return_if_fail (list_item != 0);
2599 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2600 g_return_if_fail (list != NULL);
2601 g_return_if_fail (GTK_IS_LIST (list));
2603 gtk_list_extend_selection (list, scroll_type, position,
2604 auto_start_selection);
2608 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2609 GtkScrollType scroll_type,
2613 g_return_if_fail (list_item != 0);
2614 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2615 g_return_if_fail (list != NULL);
2616 g_return_if_fail (GTK_IS_LIST (list));
2618 gtk_list_scroll_horizontal (list, scroll_type, position);
2622 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2623 GtkScrollType scroll_type,
2627 g_return_if_fail (list_item != 0);
2628 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2629 g_return_if_fail (list != NULL);
2630 g_return_if_fail (GTK_IS_LIST (list));
2632 gtk_list_scroll_vertical (list, scroll_type, position);
2636 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2639 g_return_if_fail (list_item != 0);
2640 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2641 g_return_if_fail (list != NULL);
2642 g_return_if_fail (GTK_IS_LIST (list));
2644 gtk_list_toggle_add_mode (list);
2648 gtk_list_signal_item_select (GtkListItem *list_item,
2655 g_return_if_fail (list_item != 0);
2656 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2657 g_return_if_fail (list != NULL);
2658 g_return_if_fail (GTK_IS_LIST (list));
2660 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2663 switch (list->selection_mode)
2665 case GTK_SELECTION_SINGLE:
2666 case GTK_SELECTION_BROWSE:
2668 selection = list->selection;
2672 tmp_list = selection;
2673 selection = selection->next;
2675 if (tmp_list->data == list_item)
2676 sel_list = tmp_list;
2678 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2683 list->selection = g_list_prepend (list->selection, list_item);
2684 gtk_widget_ref (GTK_WIDGET (list_item));
2686 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2688 case GTK_SELECTION_EXTENDED:
2689 if (list->anchor >= 0)
2691 case GTK_SELECTION_MULTIPLE:
2692 if (!g_list_find (list->selection, list_item))
2694 list->selection = g_list_prepend (list->selection, list_item);
2695 gtk_widget_ref (GTK_WIDGET (list_item));
2696 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2703 gtk_list_signal_item_deselect (GtkListItem *list_item,
2708 g_return_if_fail (list_item != 0);
2709 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2710 g_return_if_fail (list != NULL);
2711 g_return_if_fail (GTK_IS_LIST (list));
2713 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2716 node = g_list_find (list->selection, list_item);
2720 list->selection = g_list_remove_link (list->selection, node);
2721 g_list_free_1 (node);
2722 gtk_widget_unref (GTK_WIDGET (list_item));
2723 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2728 gtk_list_signal_item_toggle (GtkListItem *list_item,
2731 g_return_if_fail (list_item != 0);
2732 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2733 g_return_if_fail (list != NULL);
2734 g_return_if_fail (GTK_IS_LIST (list));
2736 switch (GTK_WIDGET (list_item)->state)
2738 case GTK_STATE_SELECTED:
2739 gtk_list_signal_item_select (list_item, list);
2741 case GTK_STATE_NORMAL:
2742 gtk_list_signal_item_deselect (list_item, list);
2750 gtk_list_signal_drag_begin (GtkWidget *widget,
2751 GdkDragContext *context,
2754 g_return_if_fail (widget != NULL);
2755 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2756 g_return_if_fail (list != NULL);
2757 g_return_if_fail (GTK_IS_LIST (list));
2759 gtk_list_drag_begin (GTK_WIDGET (list), context);
2763 gtk_list_drag_begin (GtkWidget *widget,
2764 GdkDragContext *context)
2768 g_return_if_fail (widget != NULL);
2769 g_return_if_fail (GTK_IS_LIST (widget));
2770 g_return_if_fail (context != NULL);
2772 list = GTK_LIST (widget);
2774 if (list->drag_selection)
2776 gtk_list_end_drag_selection (list);
2778 switch (list->selection_mode)
2780 case GTK_SELECTION_EXTENDED:
2781 gtk_list_end_selection (list);
2783 case GTK_SELECTION_SINGLE:
2784 case GTK_SELECTION_MULTIPLE:
2785 list->undo_focus_child = NULL;