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"
40 #define SCROLL_TIME 100
42 /** GtkList Methods **/
43 static void gtk_list_class_init (GtkListClass *klass);
44 static void gtk_list_init (GtkList *list);
46 /** GtkObject Methods **/
47 static void gtk_list_shutdown (GtkObject *object);
49 /** GtkWidget Methods **/
50 static void gtk_list_size_request (GtkWidget *widget,
51 GtkRequisition *requisition);
52 static void gtk_list_size_allocate (GtkWidget *widget,
53 GtkAllocation *allocation);
54 static void gtk_list_realize (GtkWidget *widget);
55 static void gtk_list_map (GtkWidget *widget);
56 static void gtk_list_unmap (GtkWidget *widget);
57 static void gtk_list_style_set (GtkWidget *widget,
58 GtkStyle *previous_style);
59 static void gtk_list_draw (GtkWidget *widget,
61 static gint gtk_list_expose (GtkWidget *widget,
62 GdkEventExpose *event);
63 static gint gtk_list_motion_notify (GtkWidget *widget,
64 GdkEventMotion *event);
65 static gint gtk_list_button_press (GtkWidget *widget,
66 GdkEventButton *event);
67 static gint gtk_list_button_release (GtkWidget *widget,
68 GdkEventButton *event);
70 /** GtkContainer Methods **/
71 static void gtk_list_add (GtkContainer *container,
73 static void gtk_list_remove (GtkContainer *container,
75 static void gtk_list_forall (GtkContainer *container,
76 gboolean include_internals,
78 gpointer callback_data);
79 static GtkType gtk_list_child_type (GtkContainer *container);
80 static void gtk_list_set_focus_child (GtkContainer *container,
82 static gint gtk_list_focus (GtkContainer *container,
83 GtkDirectionType direction);
85 /** GtkList Private Functions **/
86 static void gtk_list_move_focus_child (GtkList *list,
87 GtkScrollType scroll_type,
89 static gint gtk_list_horizontal_timeout (GtkWidget *list);
90 static gint gtk_list_vertical_timeout (GtkWidget *list);
91 static void gtk_list_remove_items_internal (GtkList *list,
95 /** GtkList Selection Methods **/
96 static void gtk_real_list_select_child (GtkList *list,
98 static void gtk_real_list_unselect_child (GtkList *list,
101 /** GtkList Selection Functions **/
102 static void gtk_list_set_anchor (GtkList *list,
105 GtkWidget *undo_focus_child);
106 static void gtk_list_fake_unselect_all (GtkList *list,
108 static void gtk_list_fake_toggle_row (GtkList *list,
110 static void gtk_list_update_extended_selection (GtkList *list,
112 static void gtk_list_reset_extended_selection (GtkList *list);
114 /** GtkListItem Signal Functions **/
115 static void gtk_list_signal_drag_begin (GtkWidget *widget,
116 GdkDragContext *context,
118 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
120 static void gtk_list_signal_select_all (GtkListItem *list_item,
122 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
124 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
126 static void gtk_list_signal_start_selection (GtkListItem *list_item,
128 static void gtk_list_signal_end_selection (GtkListItem *list_item,
130 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
131 GtkScrollType scroll_type,
133 gboolean auto_start_selection,
135 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
136 GtkScrollType scroll_type,
139 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
140 GtkScrollType scroll_type,
143 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
145 static void gtk_list_signal_item_select (GtkListItem *list_item,
147 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
149 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
153 static void gtk_list_drag_begin (GtkWidget *widget,
154 GdkDragContext *context);
157 static GtkContainerClass *parent_class = NULL;
158 static guint list_signals[LAST_SIGNAL] = { 0 };
160 static const gchar *vadjustment_key = "gtk-vadjustment";
161 static guint vadjustment_key_id = 0;
162 static const gchar *hadjustment_key = "gtk-hadjustment";
163 static guint hadjustment_key_id = 0;
166 gtk_list_get_type (void)
168 static GtkType list_type = 0;
172 static const GtkTypeInfo list_info =
176 sizeof (GtkListClass),
177 (GtkClassInitFunc) gtk_list_class_init,
178 (GtkObjectInitFunc) gtk_list_init,
179 /* reserved_1 */ NULL,
180 /* reserved_2 */ NULL,
181 (GtkClassInitFunc) NULL,
184 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
191 gtk_list_class_init (GtkListClass *class)
193 GtkObjectClass *object_class;
194 GtkWidgetClass *widget_class;
195 GtkContainerClass *container_class;
197 object_class = (GtkObjectClass*) class;
198 widget_class = (GtkWidgetClass*) class;
199 container_class = (GtkContainerClass*) class;
201 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
203 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
204 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
206 list_signals[SELECTION_CHANGED] =
207 gtk_signal_new ("selection_changed",
210 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
211 gtk_marshal_NONE__NONE,
213 list_signals[SELECT_CHILD] =
214 gtk_signal_new ("select_child",
217 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
218 gtk_marshal_NONE__POINTER,
221 list_signals[UNSELECT_CHILD] =
222 gtk_signal_new ("unselect_child",
225 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
226 gtk_marshal_NONE__POINTER,
230 gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
232 object_class->shutdown = gtk_list_shutdown;
234 widget_class->map = gtk_list_map;
235 widget_class->unmap = gtk_list_unmap;
236 widget_class->style_set = gtk_list_style_set;
237 widget_class->realize = gtk_list_realize;
238 widget_class->draw = gtk_list_draw;
239 widget_class->expose_event = gtk_list_expose;
240 widget_class->button_press_event = gtk_list_button_press;
241 widget_class->button_release_event = gtk_list_button_release;
242 widget_class->motion_notify_event = gtk_list_motion_notify;
243 widget_class->size_request = gtk_list_size_request;
244 widget_class->size_allocate = gtk_list_size_allocate;
245 widget_class->drag_begin = gtk_list_drag_begin;
247 container_class->add = gtk_list_add;
248 container_class->remove = gtk_list_remove;
249 container_class->forall = gtk_list_forall;
250 container_class->child_type = gtk_list_child_type;
251 container_class->set_focus_child = gtk_list_set_focus_child;
252 container_class->focus = gtk_list_focus;
254 class->selection_changed = NULL;
255 class->select_child = gtk_real_list_select_child;
256 class->unselect_child = gtk_real_list_unselect_child;
260 gtk_list_init (GtkList *list)
262 list->children = NULL;
263 list->selection = NULL;
265 list->undo_selection = NULL;
266 list->undo_unselection = NULL;
268 list->last_focus_child = NULL;
269 list->undo_focus_child = NULL;
276 list->anchor_state = GTK_STATE_SELECTED;
278 list->selection_mode = GTK_SELECTION_SINGLE;
279 list->drag_selection = FALSE;
280 list->add_mode = FALSE;
286 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
290 /* Private GtkObject Methods :
295 gtk_list_shutdown (GtkObject *object)
297 gtk_list_clear_items (GTK_LIST (object), 0, -1);
298 GTK_OBJECT_CLASS (parent_class)->shutdown (object);
302 /* Private GtkWidget Methods :
304 * gtk_list_size_request
305 * gtk_list_size_allocate
309 * gtk_list_motion_notify
310 * gtk_list_button_press
311 * gtk_list_button_release
314 gtk_list_size_request (GtkWidget *widget,
315 GtkRequisition *requisition)
321 g_return_if_fail (widget != NULL);
322 g_return_if_fail (GTK_IS_LIST (widget));
323 g_return_if_fail (requisition != NULL);
325 list = GTK_LIST (widget);
326 requisition->width = 0;
327 requisition->height = 0;
329 children = list->children;
332 child = children->data;
333 children = children->next;
335 if (GTK_WIDGET_VISIBLE (child))
337 GtkRequisition child_requisition;
339 gtk_widget_size_request (child, &child_requisition);
341 requisition->width = MAX (requisition->width,
342 child_requisition.width);
343 requisition->height += child_requisition.height;
347 requisition->width += GTK_CONTAINER (list)->border_width * 2;
348 requisition->height += GTK_CONTAINER (list)->border_width * 2;
350 requisition->width = MAX (requisition->width, 1);
351 requisition->height = MAX (requisition->height, 1);
355 gtk_list_size_allocate (GtkWidget *widget,
356 GtkAllocation *allocation)
360 GtkAllocation child_allocation;
363 g_return_if_fail (widget != NULL);
364 g_return_if_fail (GTK_IS_LIST (widget));
365 g_return_if_fail (allocation != NULL);
367 list = GTK_LIST (widget);
369 widget->allocation = *allocation;
370 if (GTK_WIDGET_REALIZED (widget))
371 gdk_window_move_resize (widget->window,
372 allocation->x, allocation->y,
373 allocation->width, allocation->height);
377 child_allocation.x = GTK_CONTAINER (list)->border_width;
378 child_allocation.y = GTK_CONTAINER (list)->border_width;
379 child_allocation.width = MAX (1, (gint)allocation->width -
380 child_allocation.x * 2);
382 children = list->children;
386 child = children->data;
387 children = children->next;
389 if (GTK_WIDGET_VISIBLE (child))
391 GtkRequisition child_requisition;
392 gtk_widget_get_child_requisition (child, &child_requisition);
394 child_allocation.height = child_requisition.height;
396 gtk_widget_size_allocate (child, &child_allocation);
398 child_allocation.y += child_allocation.height;
405 gtk_list_realize (GtkWidget *widget)
407 GdkWindowAttr attributes;
408 gint attributes_mask;
410 g_return_if_fail (widget != NULL);
411 g_return_if_fail (GTK_IS_LIST (widget));
413 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
415 attributes.window_type = GDK_WINDOW_CHILD;
416 attributes.x = widget->allocation.x;
417 attributes.y = widget->allocation.y;
418 attributes.width = widget->allocation.width;
419 attributes.height = widget->allocation.height;
420 attributes.wclass = GDK_INPUT_OUTPUT;
421 attributes.visual = gtk_widget_get_visual (widget);
422 attributes.colormap = gtk_widget_get_colormap (widget);
423 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
425 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
427 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
428 &attributes, attributes_mask);
429 gdk_window_set_user_data (widget->window, widget);
431 widget->style = gtk_style_attach (widget->style, widget->window);
432 gdk_window_set_background (widget->window,
433 &widget->style->base[GTK_STATE_NORMAL]);
437 gtk_list_map (GtkWidget *widget)
443 g_return_if_fail (widget != NULL);
444 g_return_if_fail (GTK_IS_LIST (widget));
446 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
447 list = GTK_LIST (widget);
449 children = list->children;
452 child = children->data;
453 children = children->next;
455 if (GTK_WIDGET_VISIBLE (child) &&
456 !GTK_WIDGET_MAPPED (child))
457 gtk_widget_map (child);
460 gdk_window_show (widget->window);
464 gtk_list_unmap (GtkWidget *widget)
468 g_return_if_fail (widget != NULL);
469 g_return_if_fail (GTK_IS_LIST (widget));
471 if (!GTK_WIDGET_MAPPED (widget))
474 list = GTK_LIST (widget);
476 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
478 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
480 gtk_list_end_drag_selection (list);
482 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_EXTENDED)
483 gtk_list_end_selection (list);
486 gdk_window_hide (widget->window);
490 gtk_list_motion_notify (GtkWidget *widget,
491 GdkEventMotion *event)
494 GtkWidget *item = NULL;
496 GtkContainer *container;
504 g_return_val_if_fail (widget != NULL, FALSE);
505 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
506 g_return_val_if_fail (event != NULL, FALSE);
508 list = GTK_LIST (widget);
510 if (!list->drag_selection || !list->children)
513 container = GTK_CONTAINER (widget);
515 if (event->is_hint || event->window != widget->window)
516 gdk_window_get_pointer (widget->window, &x, &y, NULL);
518 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
520 /* horizontal autoscrolling */
521 if (adj && widget->allocation.width > adj->page_size &&
522 (x < adj->value || x >= adj->value + adj->page_size))
524 if (list->htimer == 0)
526 list->htimer = gtk_timeout_add
527 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
529 if (!((x < adj->value && adj->value <= 0) ||
530 (x > adj->value + adj->page_size &&
531 adj->value >= adj->upper - adj->page_size)))
536 value = adj->value + (x - adj->value) / 2 - 1;
538 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
540 gtk_adjustment_set_value (adj,
542 adj->upper - adj->page_size));
550 /* vertical autoscrolling */
551 for (work = list->children; work; length++, work = work->next)
555 item = GTK_WIDGET (work->data);
556 if (item->allocation.y > y ||
557 (item->allocation.y <= y &&
558 item->allocation.y + item->allocation.height > y))
562 if (work->data == container->focus_child)
569 if (list->vtimer != 0)
572 if (!((y < 0 && focus_row == 0) ||
573 (y > widget->allocation.height && focus_row >= length - 1)))
574 list->vtimer = gtk_timeout_add (SCROLL_TIME,
575 (GtkFunction) gtk_list_vertical_timeout,
578 if (row != focus_row)
579 gtk_widget_grab_focus (item);
581 switch (list->selection_mode)
583 case GTK_SELECTION_BROWSE:
584 gtk_list_select_child (list, item);
586 case GTK_SELECTION_EXTENDED:
587 gtk_list_update_extended_selection (list, row);
597 gtk_list_button_press (GtkWidget *widget,
598 GdkEventButton *event)
603 g_return_val_if_fail (widget != NULL, FALSE);
604 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
605 g_return_val_if_fail (event != NULL, FALSE);
607 if (event->button != 1)
610 list = GTK_LIST (widget);
611 item = gtk_get_event_widget ((GdkEvent*) event);
613 while (item && !GTK_IS_LIST_ITEM (item))
616 if (item && (item->parent == widget))
621 if (event->type == GDK_BUTTON_PRESS)
623 if (gdk_pointer_grab (widget->window, TRUE,
624 GDK_POINTER_MOTION_HINT_MASK |
625 GDK_BUTTON1_MOTION_MASK |
626 GDK_BUTTON_RELEASE_MASK,
627 NULL, NULL, event->time))
630 gtk_grab_add (widget);
631 list->drag_selection = TRUE;
633 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
634 gtk_list_end_drag_selection (list);
636 if (!GTK_WIDGET_HAS_FOCUS(item))
637 gtk_widget_grab_focus (item);
641 list->add_mode = FALSE;
642 gtk_widget_queue_draw (item);
645 switch (list->selection_mode)
647 case GTK_SELECTION_SINGLE:
648 case GTK_SELECTION_MULTIPLE:
649 if (event->type != GDK_BUTTON_PRESS)
650 gtk_list_select_child (list, item);
652 list->undo_focus_child = item;
655 case GTK_SELECTION_BROWSE:
658 case GTK_SELECTION_EXTENDED:
659 focus_row = g_list_index (list->children, item);
661 if (list->last_focus_child)
662 last_focus_row = g_list_index (list->children,
663 list->last_focus_child);
666 last_focus_row = focus_row;
667 list->last_focus_child = item;
670 if (event->type != GDK_BUTTON_PRESS)
672 if (list->anchor >= 0)
674 gtk_list_update_extended_selection (list, focus_row);
675 gtk_list_end_selection (list);
677 gtk_list_select_child (list, item);
681 if (event->state & GDK_CONTROL_MASK)
683 if (event->state & GDK_SHIFT_MASK)
685 if (list->anchor < 0)
687 g_list_free (list->undo_selection);
688 g_list_free (list->undo_unselection);
689 list->undo_selection = NULL;
690 list->undo_unselection = NULL;
692 list->anchor = last_focus_row;
693 list->drag_pos = last_focus_row;
694 list->undo_focus_child = list->last_focus_child;
696 gtk_list_update_extended_selection (list, focus_row);
700 if (list->anchor < 0)
701 gtk_list_set_anchor (list, TRUE,
702 focus_row, list->last_focus_child);
704 gtk_list_update_extended_selection (list, focus_row);
709 if (event->state & GDK_SHIFT_MASK)
711 gtk_list_set_anchor (list, FALSE,
712 last_focus_row, list->last_focus_child);
713 gtk_list_update_extended_selection (list, focus_row);
717 if (list->anchor < 0)
718 gtk_list_set_anchor (list, FALSE, focus_row,
719 list->last_focus_child);
721 gtk_list_update_extended_selection (list, focus_row);
733 gtk_list_button_release (GtkWidget *widget,
734 GdkEventButton *event)
739 g_return_val_if_fail (widget != NULL, FALSE);
740 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
741 g_return_val_if_fail (event != NULL, FALSE);
743 list = GTK_LIST (widget);
745 /* we don't handle button 2 and 3 */
746 if (event->button != 1)
749 if (list->drag_selection)
751 gtk_list_end_drag_selection (list);
753 switch (list->selection_mode)
755 case GTK_SELECTION_EXTENDED:
756 if (!(event->state & GDK_SHIFT_MASK))
757 gtk_list_end_selection (list);
760 case GTK_SELECTION_SINGLE:
761 case GTK_SELECTION_MULTIPLE:
763 item = gtk_get_event_widget ((GdkEvent*) event);
765 while (item && !GTK_IS_LIST_ITEM (item))
768 if (item && item->parent == widget)
770 if (list->undo_focus_child == item)
771 gtk_list_toggle_row (list, item);
773 list->undo_focus_child = NULL;
785 gtk_list_draw (GtkWidget *widget,
790 GdkRectangle child_area;
793 g_return_if_fail (widget != NULL);
794 g_return_if_fail (GTK_IS_LIST (widget));
795 g_return_if_fail (area != NULL);
797 if (GTK_WIDGET_DRAWABLE (widget))
799 list = GTK_LIST (widget);
801 children = list->children;
804 child = children->data;
805 children = children->next;
807 if (gtk_widget_intersect (child, area, &child_area))
808 gtk_widget_draw (child, &child_area);
814 gtk_list_expose (GtkWidget *widget,
815 GdkEventExpose *event)
819 GdkEventExpose child_event;
822 g_return_val_if_fail (widget != NULL, FALSE);
823 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
824 g_return_val_if_fail (event != NULL, FALSE);
826 if (GTK_WIDGET_DRAWABLE (widget))
828 list = GTK_LIST (widget);
830 child_event = *event;
832 children = list->children;
835 child = children->data;
836 children = children->next;
838 if (GTK_WIDGET_NO_WINDOW (child) &&
839 gtk_widget_intersect (child, &event->area, &child_event.area))
840 gtk_widget_event (child, (GdkEvent*) &child_event);
848 gtk_list_style_set (GtkWidget *widget,
849 GtkStyle *previous_style)
851 g_return_if_fail (widget != NULL);
853 if (previous_style && GTK_WIDGET_REALIZED (widget))
854 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
857 /* GtkContainer Methods :
861 * gtk_list_child_type
862 * gtk_list_set_focus_child
866 gtk_list_add (GtkContainer *container,
871 g_return_if_fail (container != NULL);
872 g_return_if_fail (GTK_IS_LIST (container));
873 g_return_if_fail (widget != NULL);
874 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
876 item_list = g_list_alloc ();
877 item_list->data = widget;
879 gtk_list_append_items (GTK_LIST (container), item_list);
883 gtk_list_remove (GtkContainer *container,
888 g_return_if_fail (container != NULL);
889 g_return_if_fail (GTK_IS_LIST (container));
890 g_return_if_fail (widget != NULL);
891 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
893 item_list = g_list_alloc ();
894 item_list->data = widget;
896 gtk_list_remove_items (GTK_LIST (container), item_list);
898 g_list_free (item_list);
902 gtk_list_forall (GtkContainer *container,
903 gboolean include_internals,
904 GtkCallback callback,
905 gpointer callback_data)
911 g_return_if_fail (container != NULL);
912 g_return_if_fail (GTK_IS_LIST (container));
913 g_return_if_fail (callback != NULL);
915 list = GTK_LIST (container);
916 children = list->children;
920 child = children->data;
921 children = children->next;
923 (* callback) (child, callback_data);
928 gtk_list_child_type (GtkContainer *container)
930 return GTK_TYPE_LIST_ITEM;
934 gtk_list_set_focus_child (GtkContainer *container,
939 g_return_if_fail (container != NULL);
940 g_return_if_fail (GTK_IS_LIST (container));
943 g_return_if_fail (GTK_IS_WIDGET (child));
945 list = GTK_LIST (container);
947 if (child != container->focus_child)
949 if (container->focus_child)
951 list->last_focus_child = container->focus_child;
952 gtk_widget_unref (container->focus_child);
954 container->focus_child = child;
955 if (container->focus_child)
956 gtk_widget_ref (container->focus_child);
959 /* check for v adjustment */
960 if (container->focus_child)
962 GtkAdjustment *adjustment;
964 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
967 gtk_adjustment_clamp_page (adjustment,
968 container->focus_child->allocation.y,
969 (container->focus_child->allocation.y +
970 container->focus_child->allocation.height));
971 switch (list->selection_mode)
973 case GTK_SELECTION_BROWSE:
974 gtk_list_select_child (list, child);
976 case GTK_SELECTION_EXTENDED:
977 if (!list->last_focus_child && !list->add_mode)
979 list->undo_focus_child = list->last_focus_child;
980 gtk_list_unselect_all (list);
981 gtk_list_select_child (list, child);
991 gtk_list_focus (GtkContainer *container,
992 GtkDirectionType direction)
994 gint return_val = FALSE;
996 g_return_val_if_fail (container != NULL, FALSE);
997 g_return_val_if_fail (GTK_IS_LIST (container), FALSE);
999 if (container->focus_child == NULL ||
1000 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
1002 if (GTK_LIST (container)->last_focus_child)
1003 gtk_container_set_focus_child
1004 (container, GTK_LIST (container)->last_focus_child);
1006 if (GTK_CONTAINER_CLASS (parent_class)->focus)
1007 return_val = GTK_CONTAINER_CLASS (parent_class)->focus (container,
1015 list = GTK_LIST (container);
1016 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1017 gtk_list_end_selection (list);
1019 if (container->focus_child)
1020 list->last_focus_child = container->focus_child;
1027 /* Public GtkList Methods :
1029 * gtk_list_insert_items
1030 * gtk_list_append_items
1031 * gtk_list_prepend_items
1032 * gtk_list_remove_items
1033 * gtk_list_remove_items_no_unref
1034 * gtk_list_clear_items
1036 * gtk_list_child_position
1039 gtk_list_insert_items (GtkList *list,
1048 g_return_if_fail (list != NULL);
1049 g_return_if_fail (GTK_IS_LIST (list));
1054 gtk_list_end_drag_selection (list);
1055 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1056 gtk_list_end_selection (list);
1061 widget = tmp_list->data;
1062 tmp_list = tmp_list->next;
1064 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1065 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1066 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1068 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1069 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1071 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1072 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1074 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1075 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1077 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1078 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1080 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1081 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1083 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1084 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1086 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1087 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1089 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1090 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1092 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1093 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1095 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1096 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1098 gtk_signal_connect (GTK_OBJECT (widget), "select",
1099 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1101 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1102 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1104 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1105 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1107 if (GTK_WIDGET_VISIBLE (widget->parent))
1109 if (GTK_WIDGET_REALIZED (widget->parent) &&
1110 !GTK_WIDGET_REALIZED (widget))
1111 gtk_widget_realize (widget);
1113 if (GTK_WIDGET_MAPPED (widget->parent) &&
1114 !GTK_WIDGET_MAPPED (widget))
1115 gtk_widget_map (widget);
1120 nchildren = g_list_length (list->children);
1121 if ((position < 0) || (position > nchildren))
1122 position = nchildren;
1124 if (position == nchildren)
1128 tmp_list = g_list_last (list->children);
1129 tmp_list->next = items;
1130 items->prev = tmp_list;
1134 list->children = items;
1139 tmp_list = g_list_nth (list->children, position);
1140 last = g_list_last (items);
1143 tmp_list->prev->next = items;
1144 last->next = tmp_list;
1145 items->prev = tmp_list->prev;
1146 tmp_list->prev = last;
1148 if (tmp_list == list->children)
1149 list->children = items;
1152 if (list->children && !list->selection &&
1153 (list->selection_mode == GTK_SELECTION_BROWSE))
1155 widget = list->children->data;
1156 gtk_list_select_child (list, widget);
1159 if (GTK_WIDGET_VISIBLE (list))
1160 gtk_widget_queue_resize (GTK_WIDGET (list));
1164 gtk_list_append_items (GtkList *list,
1167 g_return_if_fail (list != NULL);
1168 g_return_if_fail (GTK_IS_LIST (list));
1170 gtk_list_insert_items (list, items, -1);
1174 gtk_list_prepend_items (GtkList *list,
1177 g_return_if_fail (list != NULL);
1178 g_return_if_fail (GTK_IS_LIST (list));
1180 gtk_list_insert_items (list, items, 0);
1184 gtk_list_remove_items (GtkList *list,
1187 gtk_list_remove_items_internal (list, items, FALSE);
1191 gtk_list_remove_items_no_unref (GtkList *list,
1194 gtk_list_remove_items_internal (list, items, TRUE);
1198 gtk_list_clear_items (GtkList *list,
1202 GtkContainer *container;
1204 GtkWidget *new_focus_child = NULL;
1209 gboolean grab_focus = FALSE;
1211 g_return_if_fail (list != NULL);
1212 g_return_if_fail (GTK_IS_LIST (list));
1214 nchildren = g_list_length (list->children);
1219 if ((end < 0) || (end > nchildren))
1225 container = GTK_CONTAINER (list);
1227 gtk_list_end_drag_selection (list);
1228 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1230 if (list->anchor >= 0)
1231 gtk_list_end_selection (list);
1233 gtk_list_reset_extended_selection (list);
1236 start_list = g_list_nth (list->children, start);
1237 end_list = g_list_nth (list->children, end);
1239 if (start_list->prev)
1240 start_list->prev->next = end_list;
1241 if (end_list && end_list->prev)
1242 end_list->prev->next = NULL;
1244 end_list->prev = start_list->prev;
1245 if (start_list == list->children)
1246 list->children = end_list;
1248 if (container->focus_child)
1250 if (g_list_find (start_list, container->focus_child))
1252 if (start_list->prev)
1253 new_focus_child = start_list->prev->data;
1254 else if (list->children)
1255 new_focus_child = list->children->prev->data;
1257 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1262 tmp_list = start_list;
1265 widget = tmp_list->data;
1266 tmp_list = tmp_list->next;
1268 if (widget->state == GTK_STATE_SELECTED)
1269 gtk_list_unselect_child (list, widget);
1271 if (widget == list->undo_focus_child)
1272 list->undo_focus_child = NULL;
1273 if (widget == list->last_focus_child)
1274 list->last_focus_child = NULL;
1276 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1277 gtk_widget_unparent (widget);
1280 g_list_free (start_list);
1282 if (new_focus_child)
1285 gtk_widget_grab_focus (new_focus_child);
1286 else if (container->focus_child)
1287 gtk_container_set_focus_child (container, new_focus_child);
1289 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1290 list->selection_mode == GTK_SELECTION_EXTENDED) && !list->selection)
1292 list->last_focus_child = new_focus_child;
1293 gtk_list_select_child (list, new_focus_child);
1297 if (GTK_WIDGET_VISIBLE (list))
1298 gtk_widget_queue_resize (GTK_WIDGET (list));
1302 gtk_list_child_position (GtkList *list,
1308 g_return_val_if_fail (list != NULL, -1);
1309 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1310 g_return_val_if_fail (child != NULL, -1);
1313 children = list->children;
1317 if (child == GTK_WIDGET (children->data))
1321 children = children->next;
1328 /* Private GtkList Insert/Remove Item Functions:
1330 * gtk_list_remove_items_internal
1333 gtk_list_remove_items_internal (GtkList *list,
1338 GtkWidget *new_focus_child;
1339 GtkWidget *old_focus_child;
1340 GtkContainer *container;
1343 gboolean grab_focus = FALSE;
1345 g_return_if_fail (list != NULL);
1346 g_return_if_fail (GTK_IS_LIST (list));
1351 container = GTK_CONTAINER (list);
1353 gtk_list_end_drag_selection (list);
1354 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1356 if (list->anchor >= 0)
1357 gtk_list_end_selection (list);
1359 gtk_list_reset_extended_selection (list);
1365 widget = tmp_list->data;
1366 tmp_list = tmp_list->next;
1368 if (widget->state == GTK_STATE_SELECTED)
1369 gtk_list_unselect_child (list, widget);
1372 if (container->focus_child)
1374 old_focus_child = new_focus_child = container->focus_child;
1375 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1379 old_focus_child = new_focus_child = list->last_focus_child;
1384 widget = tmp_list->data;
1385 tmp_list = tmp_list->next;
1388 gtk_widget_ref (widget);
1390 if (widget == new_focus_child)
1392 work = g_list_find (list->children, widget);
1397 new_focus_child = work->next->data;
1398 else if (list->children != work && work->prev)
1399 new_focus_child = work->prev->data;
1401 new_focus_child = NULL;
1405 if (widget == list->undo_focus_child)
1406 list->undo_focus_child = NULL;
1407 if (widget == list->last_focus_child)
1408 list->last_focus_child = NULL;
1410 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1411 list->children = g_list_remove (list->children, widget);
1412 gtk_widget_unparent (widget);
1415 if (new_focus_child && new_focus_child != old_focus_child)
1418 gtk_widget_grab_focus (new_focus_child);
1419 else if (container->focus_child)
1420 gtk_container_set_focus_child (container, new_focus_child);
1422 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1424 list->last_focus_child = new_focus_child;
1425 gtk_list_select_child (list, new_focus_child);
1429 if (GTK_WIDGET_VISIBLE (list))
1430 gtk_widget_queue_resize (GTK_WIDGET (list));
1434 /* Public GtkList Selection Methods :
1436 * gtk_list_set_selection_mode
1437 * gtk_list_select_item
1438 * gtk_list_unselect_item
1439 * gtk_list_select_child
1440 * gtk_list_unselect_child
1441 * gtk_list_select_all
1442 * gtk_list_unselect_all
1443 * gtk_list_extend_selection
1444 * gtk_list_end_drag_selection
1445 * gtk_list_start_selection
1446 * gtk_list_end_selection
1447 * gtk_list_toggle_row
1448 * gtk_list_toggle_focus_row
1449 * gtk_list_toggle_add_mode
1450 * gtk_list_undo_selection
1453 gtk_list_set_selection_mode (GtkList *list,
1454 GtkSelectionMode mode)
1456 g_return_if_fail (list != NULL);
1457 g_return_if_fail (GTK_IS_LIST (list));
1459 if (list->selection_mode == mode)
1462 list->selection_mode = mode;
1466 case GTK_SELECTION_SINGLE:
1467 case GTK_SELECTION_BROWSE:
1468 gtk_list_unselect_all (list);
1476 gtk_list_select_item (GtkList *list,
1481 g_return_if_fail (list != NULL);
1482 g_return_if_fail (GTK_IS_LIST (list));
1484 tmp_list = g_list_nth (list->children, item);
1486 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1490 gtk_list_unselect_item (GtkList *list,
1495 g_return_if_fail (list != NULL);
1496 g_return_if_fail (GTK_IS_LIST (list));
1498 tmp_list = g_list_nth (list->children, item);
1500 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1504 gtk_list_select_child (GtkList *list,
1507 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1511 gtk_list_unselect_child (GtkList *list,
1514 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1518 gtk_list_select_all (GtkList *list)
1520 GtkContainer *container;
1523 g_return_if_fail (list != NULL);
1524 g_return_if_fail (GTK_IS_LIST (list));
1526 if (!list->children)
1529 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1530 gtk_list_end_drag_selection (list);
1532 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1533 gtk_list_end_selection (list);
1535 container = GTK_CONTAINER (list);
1537 switch (list->selection_mode)
1539 case GTK_SELECTION_BROWSE:
1540 if (container->focus_child)
1542 gtk_list_select_child (list, container->focus_child);
1546 case GTK_SELECTION_EXTENDED:
1547 g_list_free (list->undo_selection);
1548 g_list_free (list->undo_unselection);
1549 list->undo_selection = NULL;
1550 list->undo_unselection = NULL;
1552 if (list->children &&
1553 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1554 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1556 list->anchor_state = GTK_STATE_SELECTED;
1559 list->undo_focus_child = container->focus_child;
1560 gtk_list_update_extended_selection (list, g_list_length(list->children));
1561 gtk_list_end_selection (list);
1563 case GTK_SELECTION_MULTIPLE:
1564 for (work = list->children; work; work = work->next)
1566 if (GTK_WIDGET_STATE (work->data) == GTK_STATE_NORMAL)
1567 gtk_list_select_child (list, GTK_WIDGET (work->data));
1576 gtk_list_unselect_all (GtkList *list)
1578 GtkContainer *container;
1582 g_return_if_fail (list != NULL);
1583 g_return_if_fail (GTK_IS_LIST (list));
1585 if (!list->children)
1588 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1589 gtk_list_end_drag_selection (list);
1591 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1592 gtk_list_end_selection (list);
1594 container = GTK_CONTAINER (list);
1596 switch (list->selection_mode)
1598 case GTK_SELECTION_BROWSE:
1599 if (container->focus_child)
1601 gtk_list_select_child (list, container->focus_child);
1605 case GTK_SELECTION_EXTENDED:
1606 gtk_list_reset_extended_selection (list);
1612 work = list->selection;
1618 gtk_list_unselect_child (list, item);
1623 gtk_list_extend_selection (GtkList *list,
1624 GtkScrollType scroll_type,
1626 gboolean auto_start_selection)
1628 GtkContainer *container;
1630 g_return_if_fail (list != NULL);
1631 g_return_if_fail (GTK_IS_LIST (list));
1633 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1634 list->selection_mode != GTK_SELECTION_EXTENDED)
1637 container = GTK_CONTAINER (list);
1639 if (auto_start_selection)
1643 focus_row = g_list_index (list->children, container->focus_child);
1644 gtk_list_set_anchor (list, list->add_mode, focus_row,
1645 container->focus_child);
1647 else if (list->anchor < 0)
1650 gtk_list_move_focus_child (list, scroll_type, position);
1651 gtk_list_update_extended_selection
1652 (list, g_list_index (list->children, container->focus_child));
1656 gtk_list_end_drag_selection (GtkList *list)
1658 g_return_if_fail (list != NULL);
1659 g_return_if_fail (GTK_IS_LIST (list));
1661 list->drag_selection = FALSE;
1662 if (GTK_WIDGET_HAS_GRAB (list))
1664 gtk_grab_remove (GTK_WIDGET (list));
1665 if (gdk_pointer_is_grabbed())
1666 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1670 gtk_timeout_remove (list->htimer);
1675 gtk_timeout_remove (list->vtimer);
1681 gtk_list_start_selection (GtkList *list)
1683 GtkContainer *container;
1686 g_return_if_fail (list != NULL);
1687 g_return_if_fail (GTK_IS_LIST (list));
1689 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1692 container = GTK_CONTAINER (list);
1694 if ((focus_row = g_list_index (list->selection, container->focus_child))
1696 gtk_list_set_anchor (list, list->add_mode,
1697 focus_row, container->focus_child);
1701 gtk_list_end_selection (GtkList *list)
1710 g_return_if_fail (list != NULL);
1711 g_return_if_fail (GTK_IS_LIST (list));
1713 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1717 i = MIN (list->anchor, list->drag_pos);
1718 e = MAX (list->anchor, list->drag_pos);
1720 top_down = (list->anchor < list->drag_pos);
1723 list->drag_pos = -1;
1725 if (list->undo_selection)
1727 work = list->selection;
1728 list->selection = list->undo_selection;
1729 list->undo_selection = work;
1730 work = list->selection;
1735 item_index = g_list_index (list->children, item);
1736 if (item_index < i || item_index > e)
1738 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1739 gtk_list_unselect_child (list, item);
1740 list->undo_selection = g_list_prepend (list->undo_selection,
1748 for (work = g_list_nth (list->children, i); i <= e;
1749 i++, work = work->next)
1752 if (g_list_find (list->selection, item))
1754 if (item->state == GTK_STATE_NORMAL)
1756 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1757 gtk_list_unselect_child (list, item);
1758 list->undo_selection = g_list_prepend (list->undo_selection,
1762 else if (item->state == GTK_STATE_SELECTED)
1764 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1765 list->undo_unselection = g_list_prepend (list->undo_unselection,
1772 for (work = g_list_nth (list->children, e); i <= e;
1773 e--, work = work->prev)
1776 if (g_list_find (list->selection, item))
1778 if (item->state == GTK_STATE_NORMAL)
1780 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1781 gtk_list_unselect_child (list, item);
1782 list->undo_selection = g_list_prepend (list->undo_selection,
1786 else if (item->state == GTK_STATE_SELECTED)
1788 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1789 list->undo_unselection = g_list_prepend (list->undo_unselection,
1795 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1796 gtk_list_select_child (list, GTK_WIDGET (work->data));
1802 gtk_list_toggle_row (GtkList *list,
1805 g_return_if_fail (list != NULL);
1806 g_return_if_fail (GTK_IS_LIST (list));
1807 g_return_if_fail (item != NULL);
1808 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1810 switch (list->selection_mode)
1812 case GTK_SELECTION_EXTENDED:
1813 case GTK_SELECTION_MULTIPLE:
1814 case GTK_SELECTION_SINGLE:
1815 if (item->state == GTK_STATE_SELECTED)
1817 gtk_list_unselect_child (list, item);
1820 case GTK_SELECTION_BROWSE:
1821 gtk_list_select_child (list, item);
1827 gtk_list_toggle_focus_row (GtkList *list)
1829 GtkContainer *container;
1832 g_return_if_fail (list != 0);
1833 g_return_if_fail (GTK_IS_LIST (list));
1835 container = GTK_CONTAINER (list);
1837 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1838 !container->focus_child)
1841 switch (list->selection_mode)
1843 case GTK_SELECTION_SINGLE:
1844 case GTK_SELECTION_MULTIPLE:
1845 gtk_list_toggle_row (list, container->focus_child);
1847 case GTK_SELECTION_EXTENDED:
1848 if ((focus_row = g_list_index (list->children, container->focus_child))
1852 g_list_free (list->undo_selection);
1853 g_list_free (list->undo_unselection);
1854 list->undo_selection = NULL;
1855 list->undo_unselection = NULL;
1857 list->anchor = focus_row;
1858 list->drag_pos = focus_row;
1859 list->undo_focus_child = container->focus_child;
1862 gtk_list_fake_toggle_row (list, container->focus_child);
1864 gtk_list_fake_unselect_all (list, container->focus_child);
1866 gtk_list_end_selection (list);
1874 gtk_list_toggle_add_mode (GtkList *list)
1876 GtkContainer *container;
1878 g_return_if_fail (list != 0);
1879 g_return_if_fail (GTK_IS_LIST (list));
1881 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1882 list->selection_mode != GTK_SELECTION_EXTENDED)
1885 container = GTK_CONTAINER (list);
1889 list->add_mode = FALSE;
1890 list->anchor_state = GTK_STATE_SELECTED;
1893 list->add_mode = TRUE;
1895 if (container->focus_child)
1896 gtk_widget_queue_draw (container->focus_child);
1900 gtk_list_undo_selection (GtkList *list)
1904 g_return_if_fail (list != NULL);
1905 g_return_if_fail (GTK_IS_LIST (list));
1907 if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1908 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1911 if (list->anchor >= 0)
1912 gtk_list_end_selection (list);
1914 if (!(list->undo_selection || list->undo_unselection))
1916 gtk_list_unselect_all (list);
1920 for (work = list->undo_selection; work; work = work->next)
1921 gtk_list_select_child (list, GTK_WIDGET (work->data));
1923 for (work = list->undo_unselection; work; work = work->next)
1924 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1926 if (list->undo_focus_child)
1928 GtkContainer *container;
1930 container = GTK_CONTAINER (list);
1932 if (container->focus_child &&
1933 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1934 gtk_widget_grab_focus (list->undo_focus_child);
1936 gtk_container_set_focus_child (container, list->undo_focus_child);
1939 list->undo_focus_child = NULL;
1941 g_list_free (list->undo_selection);
1942 g_list_free (list->undo_unselection);
1943 list->undo_selection = NULL;
1944 list->undo_unselection = NULL;
1948 /* Private GtkList Selection Methods :
1950 * gtk_real_list_select_child
1951 * gtk_real_list_unselect_child
1954 gtk_real_list_select_child (GtkList *list,
1957 g_return_if_fail (list != NULL);
1958 g_return_if_fail (GTK_IS_LIST (list));
1959 g_return_if_fail (child != NULL);
1960 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1962 switch (child->state)
1964 case GTK_STATE_SELECTED:
1965 case GTK_STATE_INSENSITIVE:
1968 gtk_list_item_select (GTK_LIST_ITEM (child));
1974 gtk_real_list_unselect_child (GtkList *list,
1977 g_return_if_fail (list != NULL);
1978 g_return_if_fail (GTK_IS_LIST (list));
1979 g_return_if_fail (child != NULL);
1980 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1982 if (child->state == GTK_STATE_SELECTED)
1983 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1987 /* Private GtkList Selection Functions :
1989 * gtk_list_set_anchor
1990 * gtk_list_fake_unselect_all
1991 * gtk_list_fake_toggle_row
1992 * gtk_list_update_extended_selection
1993 * gtk_list_reset_extended_selection
1996 gtk_list_set_anchor (GtkList *list,
1999 GtkWidget *undo_focus_child)
2003 g_return_if_fail (list != NULL);
2004 g_return_if_fail (GTK_IS_LIST (list));
2006 if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
2009 g_list_free (list->undo_selection);
2010 g_list_free (list->undo_unselection);
2011 list->undo_selection = NULL;
2012 list->undo_unselection = NULL;
2014 if ((work = g_list_nth (list->children, anchor)))
2017 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
2020 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
2021 list->anchor_state = GTK_STATE_SELECTED;
2025 list->anchor = anchor;
2026 list->drag_pos = anchor;
2027 list->undo_focus_child = undo_focus_child;
2031 gtk_list_fake_unselect_all (GtkList *list,
2036 if (item && item->state == GTK_STATE_NORMAL)
2037 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2039 list->undo_selection = list->selection;
2040 list->selection = NULL;
2042 for (work = list->undo_selection; work; work = work->next)
2043 if (work->data != item)
2044 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2048 gtk_list_fake_toggle_row (GtkList *list,
2054 if (item->state == GTK_STATE_NORMAL)
2056 list->anchor_state = GTK_STATE_SELECTED;
2057 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2061 list->anchor_state = GTK_STATE_NORMAL;
2062 gtk_widget_set_state (item, GTK_STATE_NORMAL);
2067 gtk_list_update_extended_selection (GtkList *list,
2081 length = g_list_length (list->children);
2085 if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
2088 /* extending downwards */
2089 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2091 s2 = list->drag_pos + 1;
2094 /* extending upwards */
2095 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2098 e2 = list->drag_pos - 1;
2100 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2102 e1 = list->drag_pos;
2103 /* row and drag_pos on different sides of anchor :
2104 take back the selection between anchor and drag_pos,
2105 select between anchor and row */
2106 if (row < list->anchor)
2108 s1 = list->anchor + 1;
2110 e2 = list->anchor - 1;
2112 /* take back the selection between anchor and drag_pos */
2116 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2118 s1 = list->drag_pos;
2119 /* row and drag_pos on different sides of anchor :
2120 take back the selection between anchor and drag_pos,
2121 select between anchor and row */
2122 if (row > list->anchor)
2124 e1 = list->anchor - 1;
2125 s2 = list->anchor + 1;
2128 /* take back the selection between anchor and drag_pos */
2133 list->drag_pos = row;
2135 /* restore the elements between s1 and e1 */
2138 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2139 i++, work = work->next)
2141 if (g_list_find (list->selection, work->data))
2142 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2144 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2148 /* extend the selection between s2 and e2 */
2151 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2152 i++, work = work->next)
2153 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2154 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2159 gtk_list_reset_extended_selection (GtkList *list)
2161 g_return_if_fail (list != 0);
2162 g_return_if_fail (GTK_IS_LIST (list));
2164 g_list_free (list->undo_selection);
2165 g_list_free (list->undo_unselection);
2166 list->undo_selection = NULL;
2167 list->undo_unselection = NULL;
2170 list->drag_pos = -1;
2171 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2174 /* Public GtkList Scroll Methods :
2176 * gtk_list_scroll_horizontal
2177 * gtk_list_scroll_vertical
2180 gtk_list_scroll_horizontal (GtkList *list,
2181 GtkScrollType scroll_type,
2186 g_return_if_fail (list != 0);
2187 g_return_if_fail (GTK_IS_LIST (list));
2189 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2193 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2196 switch (scroll_type)
2198 case GTK_SCROLL_STEP_BACKWARD:
2199 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2200 adj->upper - adj->page_size);
2202 case GTK_SCROLL_STEP_FORWARD:
2203 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2204 adj->upper - adj->page_size);
2206 case GTK_SCROLL_PAGE_BACKWARD:
2207 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2208 adj->upper - adj->page_size);
2210 case GTK_SCROLL_PAGE_FORWARD:
2211 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2212 adj->upper - adj->page_size);
2214 case GTK_SCROLL_JUMP:
2215 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2216 adj->lower, adj->upper - adj->page_size);
2221 gtk_adjustment_value_changed (adj);
2225 gtk_list_scroll_vertical (GtkList *list,
2226 GtkScrollType scroll_type,
2229 g_return_if_fail (list != NULL);
2230 g_return_if_fail (GTK_IS_LIST (list));
2232 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2235 if (list->selection_mode == GTK_SELECTION_EXTENDED)
2237 GtkContainer *container;
2239 if (list->anchor >= 0)
2242 container = GTK_CONTAINER (list);
2243 list->undo_focus_child = container->focus_child;
2244 gtk_list_move_focus_child (list, scroll_type, position);
2245 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2247 gtk_list_unselect_all (list);
2248 gtk_list_select_child (list, container->focus_child);
2252 gtk_list_move_focus_child (list, scroll_type, position);
2256 /* Private GtkList Scroll/Focus Functions :
2258 * gtk_list_move_focus_child
2259 * gtk_list_horizontal_timeout
2260 * gtk_list_vertical_timeout
2263 gtk_list_move_focus_child (GtkList *list,
2264 GtkScrollType scroll_type,
2267 GtkContainer *container;
2273 g_return_if_fail (list != 0);
2274 g_return_if_fail (GTK_IS_LIST (list));
2276 container = GTK_CONTAINER (list);
2278 if (container->focus_child)
2279 work = g_list_find (list->children, container->focus_child);
2281 work = list->children;
2286 switch (scroll_type)
2288 case GTK_SCROLL_STEP_BACKWARD:
2291 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2293 case GTK_SCROLL_STEP_FORWARD:
2296 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2298 case GTK_SCROLL_PAGE_BACKWARD:
2303 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2307 gboolean correct = FALSE;
2309 new_value = adj->value;
2311 if (item->allocation.y <= adj->value)
2313 new_value = MAX (item->allocation.y + item->allocation.height
2314 - adj->page_size, adj->lower);
2318 if (item->allocation.y > new_value)
2319 for (; work; work = work->prev)
2321 item = GTK_WIDGET (work->data);
2322 if (item->allocation.y <= new_value &&
2323 item->allocation.y + item->allocation.height > new_value)
2327 for (; work; work = work->next)
2329 item = GTK_WIDGET (work->data);
2330 if (item->allocation.y <= new_value &&
2331 item->allocation.y + item->allocation.height > new_value)
2335 if (correct && work && work->next && item->allocation.y < new_value)
2336 item = work->next->data;
2339 item = list->children->data;
2341 gtk_widget_grab_focus (item);
2343 case GTK_SCROLL_PAGE_FORWARD:
2348 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2352 gboolean correct = FALSE;
2354 new_value = adj->value;
2356 if (item->allocation.y + item->allocation.height >=
2357 adj->value + adj->page_size)
2359 new_value = item->allocation.y;
2363 new_value = MIN (new_value + adj->page_size, adj->upper);
2365 if (item->allocation.y > new_value)
2366 for (; work; work = work->prev)
2368 item = GTK_WIDGET (work->data);
2369 if (item->allocation.y <= new_value &&
2370 item->allocation.y + item->allocation.height > new_value)
2374 for (; work; work = work->next)
2376 item = GTK_WIDGET (work->data);
2377 if (item->allocation.y <= new_value &&
2378 item->allocation.y + item->allocation.height > new_value)
2382 if (correct && work && work->prev &&
2383 item->allocation.y + item->allocation.height - 1 > new_value)
2384 item = work->prev->data;
2387 item = g_list_last (work)->data;
2389 gtk_widget_grab_focus (item);
2391 case GTK_SCROLL_JUMP:
2392 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2394 for (item = NULL, work = list->children; work; work =work->next)
2396 item = GTK_WIDGET (work->data);
2397 if (item->allocation.y <= new_value &&
2398 item->allocation.y + item->allocation.height > new_value)
2402 gtk_widget_grab_focus (item);
2410 gtk_list_horizontal_timeout (GtkWidget *list)
2413 GdkEventMotion event;
2414 GdkModifierType mask;
2416 GDK_THREADS_ENTER ();
2418 GTK_LIST (list)->htimer = 0;
2419 gdk_window_get_pointer (list->window, &x, &y, &mask);
2426 gtk_list_motion_notify (list, &event);
2428 GDK_THREADS_LEAVE ();
2434 gtk_list_vertical_timeout (GtkWidget *list)
2438 GdkEventMotion event;
2439 GdkModifierType mask;
2441 GDK_THREADS_ENTER ();
2443 GTK_LIST (list)->vtimer = 0;
2444 gdk_window_get_pointer (list->window, &x, &y, &mask);
2451 gtk_list_motion_notify (list, &event);
2453 GDK_THREADS_LEAVE ();
2459 /* Private GtkListItem Signal Functions :
2461 * gtk_list_signal_toggle_focus_row
2462 * gtk_list_signal_select_all
2463 * gtk_list_signal_unselect_all
2464 * gtk_list_signal_undo_selection
2465 * gtk_list_signal_start_selection
2466 * gtk_list_signal_end_selection
2467 * gtk_list_signal_extend_selection
2468 * gtk_list_signal_scroll_horizontal
2469 * gtk_list_signal_scroll_vertical
2470 * gtk_list_signal_toggle_add_mode
2471 * gtk_list_signal_item_select
2472 * gtk_list_signal_item_deselect
2473 * gtk_list_signal_item_toggle
2476 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2479 g_return_if_fail (list_item != 0);
2480 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2481 g_return_if_fail (list != NULL);
2482 g_return_if_fail (GTK_IS_LIST (list));
2484 gtk_list_toggle_focus_row (list);
2488 gtk_list_signal_select_all (GtkListItem *list_item,
2491 g_return_if_fail (list_item != 0);
2492 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2493 g_return_if_fail (list != NULL);
2494 g_return_if_fail (GTK_IS_LIST (list));
2496 gtk_list_select_all (list);
2500 gtk_list_signal_unselect_all (GtkListItem *list_item,
2503 g_return_if_fail (list_item != 0);
2504 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2505 g_return_if_fail (list != NULL);
2506 g_return_if_fail (GTK_IS_LIST (list));
2508 gtk_list_unselect_all (list);
2512 gtk_list_signal_undo_selection (GtkListItem *list_item,
2515 g_return_if_fail (list_item != 0);
2516 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2517 g_return_if_fail (list != NULL);
2518 g_return_if_fail (GTK_IS_LIST (list));
2520 gtk_list_undo_selection (list);
2524 gtk_list_signal_start_selection (GtkListItem *list_item,
2527 g_return_if_fail (list_item != 0);
2528 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2529 g_return_if_fail (list != NULL);
2530 g_return_if_fail (GTK_IS_LIST (list));
2532 gtk_list_start_selection (list);
2536 gtk_list_signal_end_selection (GtkListItem *list_item,
2539 g_return_if_fail (list_item != 0);
2540 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2541 g_return_if_fail (list != NULL);
2542 g_return_if_fail (GTK_IS_LIST (list));
2544 gtk_list_end_selection (list);
2548 gtk_list_signal_extend_selection (GtkListItem *list_item,
2549 GtkScrollType scroll_type,
2551 gboolean auto_start_selection,
2554 g_return_if_fail (list_item != 0);
2555 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2556 g_return_if_fail (list != NULL);
2557 g_return_if_fail (GTK_IS_LIST (list));
2559 gtk_list_extend_selection (list, scroll_type, position,
2560 auto_start_selection);
2564 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2565 GtkScrollType scroll_type,
2569 g_return_if_fail (list_item != 0);
2570 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2571 g_return_if_fail (list != NULL);
2572 g_return_if_fail (GTK_IS_LIST (list));
2574 gtk_list_scroll_horizontal (list, scroll_type, position);
2578 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2579 GtkScrollType scroll_type,
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_scroll_vertical (list, scroll_type, position);
2592 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2595 g_return_if_fail (list_item != 0);
2596 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2597 g_return_if_fail (list != NULL);
2598 g_return_if_fail (GTK_IS_LIST (list));
2600 gtk_list_toggle_add_mode (list);
2604 gtk_list_signal_item_select (GtkListItem *list_item,
2611 g_return_if_fail (list_item != 0);
2612 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2613 g_return_if_fail (list != NULL);
2614 g_return_if_fail (GTK_IS_LIST (list));
2616 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2619 switch (list->selection_mode)
2621 case GTK_SELECTION_SINGLE:
2622 case GTK_SELECTION_BROWSE:
2624 selection = list->selection;
2628 tmp_list = selection;
2629 selection = selection->next;
2631 if (tmp_list->data == list_item)
2632 sel_list = tmp_list;
2634 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2639 list->selection = g_list_prepend (list->selection, list_item);
2640 gtk_widget_ref (GTK_WIDGET (list_item));
2642 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2644 case GTK_SELECTION_EXTENDED:
2645 if (list->anchor >= 0)
2647 case GTK_SELECTION_MULTIPLE:
2648 if (!g_list_find (list->selection, list_item))
2650 list->selection = g_list_prepend (list->selection, list_item);
2651 gtk_widget_ref (GTK_WIDGET (list_item));
2652 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2659 gtk_list_signal_item_deselect (GtkListItem *list_item,
2664 g_return_if_fail (list_item != 0);
2665 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2666 g_return_if_fail (list != NULL);
2667 g_return_if_fail (GTK_IS_LIST (list));
2669 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2672 node = g_list_find (list->selection, list_item);
2676 list->selection = g_list_remove_link (list->selection, node);
2677 g_list_free_1 (node);
2678 gtk_widget_unref (GTK_WIDGET (list_item));
2679 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2684 gtk_list_signal_item_toggle (GtkListItem *list_item,
2687 g_return_if_fail (list_item != 0);
2688 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2689 g_return_if_fail (list != NULL);
2690 g_return_if_fail (GTK_IS_LIST (list));
2692 switch (GTK_WIDGET (list_item)->state)
2694 case GTK_STATE_SELECTED:
2695 gtk_list_signal_item_select (list_item, list);
2697 case GTK_STATE_NORMAL:
2698 gtk_list_signal_item_deselect (list_item, list);
2706 gtk_list_signal_drag_begin (GtkWidget *widget,
2707 GdkDragContext *context,
2710 g_return_if_fail (widget != NULL);
2711 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2712 g_return_if_fail (list != NULL);
2713 g_return_if_fail (GTK_IS_LIST (list));
2715 gtk_list_drag_begin (GTK_WIDGET (list), context);
2719 gtk_list_drag_begin (GtkWidget *widget,
2720 GdkDragContext *context)
2724 g_return_if_fail (widget != NULL);
2725 g_return_if_fail (GTK_IS_LIST (widget));
2726 g_return_if_fail (context != NULL);
2728 list = GTK_LIST (widget);
2730 if (list->drag_selection)
2732 gtk_list_end_drag_selection (list);
2734 switch (list->selection_mode)
2736 case GTK_SELECTION_EXTENDED:
2737 gtk_list_end_selection (list);
2739 case GTK_SELECTION_SINGLE:
2740 case GTK_SELECTION_MULTIPLE:
2741 list->undo_focus_child = NULL;