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.
20 #include "gtklistitem.h"
22 #include "gtksignal.h"
32 #define SCROLL_TIME 100
34 /** GtkList Methods **/
35 static void gtk_list_class_init (GtkListClass *klass);
36 static void gtk_list_init (GtkList *list);
38 /** GtkObject Methods **/
39 static void gtk_list_shutdown (GtkObject *object);
41 /** GtkWidget Methods **/
42 static void gtk_list_size_request (GtkWidget *widget,
43 GtkRequisition *requisition);
44 static void gtk_list_size_allocate (GtkWidget *widget,
45 GtkAllocation *allocation);
46 static void gtk_list_realize (GtkWidget *widget);
47 static void gtk_list_map (GtkWidget *widget);
48 static void gtk_list_unmap (GtkWidget *widget);
49 static void gtk_list_style_set (GtkWidget *widget,
50 GtkStyle *previous_style);
51 static void gtk_list_draw (GtkWidget *widget,
53 static gint gtk_list_expose (GtkWidget *widget,
54 GdkEventExpose *event);
55 static gint gtk_list_motion_notify (GtkWidget *widget,
56 GdkEventMotion *event);
57 static gint gtk_list_button_press (GtkWidget *widget,
58 GdkEventButton *event);
59 static gint gtk_list_button_release (GtkWidget *widget,
60 GdkEventButton *event);
62 /** GtkContainer Methods **/
63 static void gtk_list_add (GtkContainer *container,
65 static void gtk_list_remove (GtkContainer *container,
67 static void gtk_list_forall (GtkContainer *container,
68 gboolean include_internals,
70 gpointer callback_data);
71 static GtkType gtk_list_child_type (GtkContainer *container);
72 static void gtk_list_set_focus_child (GtkContainer *container,
74 static gint gtk_list_focus (GtkContainer *container,
75 GtkDirectionType direction);
77 /** GtkList Private Functions **/
78 static void gtk_list_move_focus_child (GtkList *list,
79 GtkScrollType scroll_type,
81 static gint gtk_list_horizontal_timeout (GtkWidget *list);
82 static gint gtk_list_vertical_timeout (GtkWidget *list);
83 static void gtk_list_remove_items_internal (GtkList *list,
87 /** GtkList Selection Methods **/
88 static void gtk_real_list_select_child (GtkList *list,
90 static void gtk_real_list_unselect_child (GtkList *list,
93 /** GtkList Selection Functions **/
94 static void gtk_list_set_anchor (GtkList *list,
97 GtkWidget *undo_focus_child);
98 static void gtk_list_fake_unselect_all (GtkList *list,
100 static void gtk_list_fake_toggle_row (GtkList *list,
102 static void gtk_list_update_extended_selection (GtkList *list,
105 /** GtkListItem Signal Functions **/
106 static void gtk_list_signal_focus_lost (GtkWidget *item,
109 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
111 static void gtk_list_signal_select_all (GtkListItem *list_item,
113 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
115 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
117 static void gtk_list_signal_start_selection (GtkListItem *list_item,
119 static void gtk_list_signal_end_selection (GtkListItem *list_item,
121 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
122 GtkScrollType scroll_type,
124 gboolean auto_start_selection,
126 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
127 GtkScrollType scroll_type,
130 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
131 GtkScrollType scroll_type,
134 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
136 static void gtk_list_signal_item_select (GtkListItem *list_item,
138 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
140 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
144 static GtkContainerClass *parent_class = NULL;
145 static guint list_signals[LAST_SIGNAL] = { 0 };
147 static const gchar *vadjustment_key = "gtk-vadjustment";
148 static guint vadjustment_key_id = 0;
149 static const gchar *hadjustment_key = "gtk-hadjustment";
150 static guint hadjustment_key_id = 0;
153 gtk_list_get_type (void)
155 static GtkType list_type = 0;
159 static const GtkTypeInfo list_info =
163 sizeof (GtkListClass),
164 (GtkClassInitFunc) gtk_list_class_init,
165 (GtkObjectInitFunc) gtk_list_init,
166 /* reserved_1 */ NULL,
167 /* reserved_2 */ NULL,
168 (GtkClassInitFunc) NULL,
171 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
178 gtk_list_class_init (GtkListClass *class)
180 GtkObjectClass *object_class;
181 GtkWidgetClass *widget_class;
182 GtkContainerClass *container_class;
184 object_class = (GtkObjectClass*) class;
185 widget_class = (GtkWidgetClass*) class;
186 container_class = (GtkContainerClass*) class;
188 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
190 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
191 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
193 list_signals[SELECTION_CHANGED] =
194 gtk_signal_new ("selection_changed",
197 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
198 gtk_marshal_NONE__NONE,
200 list_signals[SELECT_CHILD] =
201 gtk_signal_new ("select_child",
204 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
205 gtk_marshal_NONE__POINTER,
208 list_signals[UNSELECT_CHILD] =
209 gtk_signal_new ("unselect_child",
212 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
213 gtk_marshal_NONE__POINTER,
217 gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
219 object_class->shutdown = gtk_list_shutdown;
221 widget_class->map = gtk_list_map;
222 widget_class->unmap = gtk_list_unmap;
223 widget_class->style_set = gtk_list_style_set;
224 widget_class->realize = gtk_list_realize;
225 widget_class->draw = gtk_list_draw;
226 widget_class->expose_event = gtk_list_expose;
227 widget_class->button_press_event = gtk_list_button_press;
228 widget_class->button_release_event = gtk_list_button_release;
229 widget_class->motion_notify_event = gtk_list_motion_notify;
230 widget_class->size_request = gtk_list_size_request;
231 widget_class->size_allocate = gtk_list_size_allocate;
233 container_class->add = gtk_list_add;
234 container_class->remove = gtk_list_remove;
235 container_class->forall = gtk_list_forall;
236 container_class->child_type = gtk_list_child_type;
237 container_class->set_focus_child = gtk_list_set_focus_child;
238 container_class->focus = gtk_list_focus;
240 class->selection_changed = NULL;
241 class->select_child = gtk_real_list_select_child;
242 class->unselect_child = gtk_real_list_unselect_child;
246 gtk_list_init (GtkList *list)
248 list->children = NULL;
249 list->selection = NULL;
251 list->undo_selection = NULL;
252 list->undo_unselection = NULL;
254 list->last_focus_child = NULL;
255 list->undo_focus_child = NULL;
262 list->anchor_state = GTK_STATE_SELECTED;
264 list->selection_mode = GTK_SELECTION_SINGLE;
265 list->drag_selection = FALSE;
266 list->add_mode = FALSE;
272 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
276 /* Private GtkObject Methods :
281 gtk_list_shutdown (GtkObject *object)
283 gtk_list_clear_items (GTK_LIST (object), 0, -1);
284 GTK_OBJECT_CLASS (parent_class)->shutdown (object);
288 /* Private GtkWidget Methods :
290 * gtk_list_size_request
291 * gtk_list_size_allocate
295 * gtk_list_motion_notify
296 * gtk_list_button_press
297 * gtk_list_button_release
300 gtk_list_size_request (GtkWidget *widget,
301 GtkRequisition *requisition)
307 g_return_if_fail (widget != NULL);
308 g_return_if_fail (GTK_IS_LIST (widget));
309 g_return_if_fail (requisition != NULL);
311 list = GTK_LIST (widget);
312 requisition->width = 0;
313 requisition->height = 0;
315 children = list->children;
318 child = children->data;
319 children = children->next;
321 if (GTK_WIDGET_VISIBLE (child))
323 gtk_widget_size_request (child, &child->requisition);
325 requisition->width = MAX (requisition->width,
326 child->requisition.width);
327 requisition->height += child->requisition.height;
331 requisition->width += GTK_CONTAINER (list)->border_width * 2;
332 requisition->height += GTK_CONTAINER (list)->border_width * 2;
334 requisition->width = MAX (requisition->width, 1);
335 requisition->height = MAX (requisition->height, 1);
339 gtk_list_size_allocate (GtkWidget *widget,
340 GtkAllocation *allocation)
344 GtkAllocation child_allocation;
347 g_return_if_fail (widget != NULL);
348 g_return_if_fail (GTK_IS_LIST (widget));
349 g_return_if_fail (allocation != NULL);
351 list = GTK_LIST (widget);
353 widget->allocation = *allocation;
354 if (GTK_WIDGET_REALIZED (widget))
355 gdk_window_move_resize (widget->window,
356 allocation->x, allocation->y,
357 allocation->width, allocation->height);
361 child_allocation.x = GTK_CONTAINER (list)->border_width;
362 child_allocation.y = GTK_CONTAINER (list)->border_width;
363 child_allocation.width = MAX (1, allocation->width -
364 child_allocation.x * 2);
366 children = list->children;
370 child = children->data;
371 children = children->next;
373 if (GTK_WIDGET_VISIBLE (child))
375 child_allocation.height = child->requisition.height;
377 gtk_widget_size_allocate (child, &child_allocation);
379 child_allocation.y += child_allocation.height;
386 gtk_list_realize (GtkWidget *widget)
388 GdkWindowAttr attributes;
389 gint attributes_mask;
391 g_return_if_fail (widget != NULL);
392 g_return_if_fail (GTK_IS_LIST (widget));
394 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
396 attributes.window_type = GDK_WINDOW_CHILD;
397 attributes.x = widget->allocation.x;
398 attributes.y = widget->allocation.y;
399 attributes.width = widget->allocation.width;
400 attributes.height = widget->allocation.height;
401 attributes.wclass = GDK_INPUT_OUTPUT;
402 attributes.visual = gtk_widget_get_visual (widget);
403 attributes.colormap = gtk_widget_get_colormap (widget);
404 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
406 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
408 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
409 &attributes, attributes_mask);
410 gdk_window_set_user_data (widget->window, widget);
412 widget->style = gtk_style_attach (widget->style, widget->window);
413 gdk_window_set_background (widget->window,
414 &widget->style->base[GTK_STATE_NORMAL]);
418 gtk_list_map (GtkWidget *widget)
424 g_return_if_fail (widget != NULL);
425 g_return_if_fail (GTK_IS_LIST (widget));
427 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
428 list = GTK_LIST (widget);
430 gdk_window_show (widget->window);
432 children = list->children;
435 child = children->data;
436 children = children->next;
438 if (GTK_WIDGET_VISIBLE (child) &&
439 !GTK_WIDGET_MAPPED (child))
440 gtk_widget_map (child);
445 gtk_list_unmap (GtkWidget *widget)
447 g_return_if_fail (widget != NULL);
448 g_return_if_fail (GTK_IS_LIST (widget));
450 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
451 gdk_window_hide (widget->window);
455 gtk_list_motion_notify (GtkWidget *widget,
456 GdkEventMotion *event)
459 GtkWidget *item = NULL;
461 GtkContainer *container;
469 g_return_val_if_fail (widget != NULL, FALSE);
470 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
471 g_return_val_if_fail (event != NULL, FALSE);
473 list = GTK_LIST (widget);
475 if (!list->drag_selection || !list->children)
478 container = GTK_CONTAINER (widget);
480 if (event->is_hint || event->window != widget->window)
481 gdk_window_get_pointer (widget->window, &x, &y, NULL);
483 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
485 /* horizontal autoscrolling */
486 if (adj && widget->allocation.width > adj->page_size &&
487 (x < adj->value || x >= adj->value + adj->page_size))
489 if (list->htimer == 0)
491 list->htimer = gtk_timeout_add
492 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
494 if (!((x < adj->value && adj->value <= 0) ||
495 (x > adj->value + adj->page_size &&
496 adj->value >= adj->upper - adj->page_size)))
501 value = adj->value + (x - adj->value) / 2 - 1;
503 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
505 gtk_adjustment_set_value (adj,
507 adj->upper - adj->page_size));
515 /* vertical autoscrolling */
516 for (work = list->children; work; length++, work = work->next)
520 item = GTK_WIDGET (work->data);
521 if (item->allocation.y > y ||
522 (item->allocation.y <= y &&
523 item->allocation.y + item->allocation.height > y))
527 if (work->data == container->focus_child)
534 if (list->vtimer != 0)
537 if (!((y < 0 && focus_row == 0) ||
538 (y > widget->allocation.height && focus_row >= length - 1)))
539 list->vtimer = gtk_timeout_add (SCROLL_TIME,
540 (GtkFunction) gtk_list_vertical_timeout,
543 if (row != focus_row)
544 gtk_widget_grab_focus (item);
546 switch (list->selection_mode)
548 case GTK_SELECTION_BROWSE:
549 gtk_list_select_child (list, item);
552 case GTK_SELECTION_EXTENDED:
553 gtk_list_update_extended_selection (list, row);
564 gtk_list_button_press (GtkWidget *widget,
565 GdkEventButton *event)
570 g_return_val_if_fail (widget != NULL, FALSE);
571 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
572 g_return_val_if_fail (event != NULL, FALSE);
574 if (event->button != 1)
577 list = GTK_LIST (widget);
578 item = gtk_get_event_widget ((GdkEvent*) event);
580 while (item && !GTK_IS_LIST_ITEM (item))
583 if (item && (item->parent == widget))
588 if (event->type == GDK_BUTTON_PRESS)
590 list->drag_selection = TRUE;
591 gdk_pointer_grab (widget->window, TRUE,
592 GDK_POINTER_MOTION_HINT_MASK |
593 GDK_BUTTON1_MOTION_MASK |
594 GDK_BUTTON_RELEASE_MASK,
595 NULL, NULL, event->time);
596 gtk_grab_add (widget);
598 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
599 gtk_list_end_drag_selection (list);
601 if (!GTK_WIDGET_HAS_FOCUS(item))
602 gtk_widget_grab_focus (item);
606 list->add_mode = FALSE;
607 gtk_widget_queue_draw (item);
610 switch (list->selection_mode)
612 case GTK_SELECTION_SINGLE:
613 case GTK_SELECTION_MULTIPLE:
614 if (event->type != GDK_BUTTON_PRESS)
615 gtk_list_select_child (list, item);
617 list->undo_focus_child = item;
620 case GTK_SELECTION_BROWSE:
623 case GTK_SELECTION_EXTENDED:
624 focus_row = g_list_index (list->children, item);
626 if (list->last_focus_child)
627 last_focus_row = g_list_index (list->children,
628 list->last_focus_child);
631 last_focus_row = focus_row;
632 list->last_focus_child = item;
635 if (event->type != GDK_BUTTON_PRESS)
637 if (list->anchor >= 0)
639 gtk_list_update_extended_selection (list, focus_row);
640 gtk_list_end_selection (list);
642 gtk_list_select_child (list, item);
646 if (event->state & GDK_CONTROL_MASK)
648 if (event->state & GDK_SHIFT_MASK)
650 if (list->anchor < 0)
652 g_list_free (list->undo_selection);
653 g_list_free (list->undo_unselection);
654 list->undo_selection = NULL;
655 list->undo_unselection = NULL;
657 list->anchor = last_focus_row;
658 list->drag_pos = last_focus_row;
659 list->undo_focus_child = list->last_focus_child;
661 gtk_list_update_extended_selection (list, focus_row);
665 if (list->anchor < 0)
666 gtk_list_set_anchor (list, TRUE,
667 focus_row, list->last_focus_child);
669 gtk_list_update_extended_selection (list, focus_row);
674 if (event->state & GDK_SHIFT_MASK)
676 gtk_list_set_anchor (list, FALSE,
677 last_focus_row, list->last_focus_child);
678 gtk_list_update_extended_selection (list, focus_row);
682 if (list->anchor < 0)
683 gtk_list_set_anchor (list, FALSE, focus_row,
684 list->last_focus_child);
686 gtk_list_update_extended_selection (list, focus_row);
698 gtk_list_button_release (GtkWidget *widget,
699 GdkEventButton *event)
704 g_return_val_if_fail (widget != NULL, FALSE);
705 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
706 g_return_val_if_fail (event != NULL, FALSE);
708 list = GTK_LIST (widget);
710 /* we don't handle button 2 and 3 */
711 if (event->button != 1)
714 if (list->drag_selection)
716 gtk_list_end_drag_selection (list);
718 switch (list->selection_mode)
720 case GTK_SELECTION_EXTENDED:
721 if (!(event->state & GDK_SHIFT_MASK))
722 gtk_list_end_selection (list);
725 case GTK_SELECTION_SINGLE:
726 case GTK_SELECTION_MULTIPLE:
728 item = gtk_get_event_widget ((GdkEvent*) event);
730 while (item && !GTK_IS_LIST_ITEM (item))
733 if (item && item->parent == widget)
735 if (list->undo_focus_child == item)
736 gtk_list_toggle_row (list, item);
738 list->undo_focus_child = NULL;
750 gtk_list_draw (GtkWidget *widget,
755 GdkRectangle child_area;
758 g_return_if_fail (widget != NULL);
759 g_return_if_fail (GTK_IS_LIST (widget));
760 g_return_if_fail (area != NULL);
762 if (GTK_WIDGET_DRAWABLE (widget))
764 list = GTK_LIST (widget);
766 children = list->children;
769 child = children->data;
770 children = children->next;
772 if (gtk_widget_intersect (child, area, &child_area))
773 gtk_widget_draw (child, &child_area);
779 gtk_list_expose (GtkWidget *widget,
780 GdkEventExpose *event)
784 GdkEventExpose child_event;
787 g_return_val_if_fail (widget != NULL, FALSE);
788 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
789 g_return_val_if_fail (event != NULL, FALSE);
791 if (GTK_WIDGET_DRAWABLE (widget))
793 list = GTK_LIST (widget);
795 child_event = *event;
797 children = list->children;
800 child = children->data;
801 children = children->next;
803 if (GTK_WIDGET_NO_WINDOW (child) &&
804 gtk_widget_intersect (child, &event->area, &child_event.area))
805 gtk_widget_event (child, (GdkEvent*) &child_event);
813 gtk_list_style_set (GtkWidget *widget,
814 GtkStyle *previous_style)
816 g_return_if_fail (widget != NULL);
818 if (previous_style && GTK_WIDGET_REALIZED (widget))
819 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
822 /* GtkContainer Methods :
826 * gtk_list_child_type
827 * gtk_list_set_focus_child
831 gtk_list_add (GtkContainer *container,
836 g_return_if_fail (container != NULL);
837 g_return_if_fail (GTK_IS_LIST (container));
838 g_return_if_fail (widget != NULL);
839 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
841 item_list = g_list_alloc ();
842 item_list->data = widget;
844 gtk_list_append_items (GTK_LIST (container), item_list);
848 gtk_list_remove (GtkContainer *container,
853 g_return_if_fail (container != NULL);
854 g_return_if_fail (GTK_IS_LIST (container));
855 g_return_if_fail (widget != NULL);
856 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
858 item_list = g_list_alloc ();
859 item_list->data = widget;
861 gtk_list_remove_items (GTK_LIST (container), item_list);
863 g_list_free (item_list);
867 gtk_list_forall (GtkContainer *container,
868 gboolean include_internals,
869 GtkCallback callback,
870 gpointer callback_data)
876 g_return_if_fail (container != NULL);
877 g_return_if_fail (GTK_IS_LIST (container));
878 g_return_if_fail (callback != NULL);
880 list = GTK_LIST (container);
881 children = list->children;
885 child = children->data;
886 children = children->next;
888 (* callback) (child, callback_data);
893 gtk_list_child_type (GtkContainer *container)
895 return GTK_TYPE_LIST_ITEM;
899 gtk_list_set_focus_child (GtkContainer *container,
904 g_return_if_fail (container != NULL);
905 g_return_if_fail (GTK_IS_LIST (container));
908 g_return_if_fail (GTK_IS_WIDGET (child));
910 list = GTK_LIST (container);
911 list->last_focus_child = container->focus_child;
913 if (child != container->focus_child)
915 if (container->focus_child)
916 gtk_widget_unref (container->focus_child);
917 container->focus_child = child;
918 if (container->focus_child)
919 gtk_widget_ref (container->focus_child);
922 /* check for v adjustment */
923 if (container->focus_child)
925 GtkAdjustment *adjustment;
927 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
930 gtk_adjustment_clamp_page (adjustment,
931 container->focus_child->allocation.y,
932 (container->focus_child->allocation.y +
933 container->focus_child->allocation.height));
936 switch (list->selection_mode)
938 case GTK_SELECTION_BROWSE:
940 gtk_list_select_child (list, child);
948 gtk_list_focus (GtkContainer *container,
949 GtkDirectionType direction)
951 gint return_val = FALSE;
953 g_return_val_if_fail (container != NULL, FALSE);
954 g_return_val_if_fail (GTK_IS_LIST (container), FALSE);
956 if (!GTK_WIDGET_SENSITIVE (container))
958 else if (container->focus_child == NULL ||
959 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
961 if (GTK_CONTAINER_CLASS (parent_class)->focus)
962 return_val = GTK_CONTAINER_CLASS (parent_class)->focus
963 (container, direction);
970 list = GTK_LIST (container);
971 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
972 gtk_list_end_selection (list);
979 /* Public GtkList Methods :
981 * gtk_list_insert_items
982 * gtk_list_append_items
983 * gtk_list_prepend_items
984 * gtk_list_remove_items
985 * gtk_list_remove_items_no_unref
986 * gtk_list_clear_items
988 * gtk_list_child_position
991 gtk_list_insert_items (GtkList *list,
1000 g_return_if_fail (list != NULL);
1001 g_return_if_fail (GTK_IS_LIST (list));
1006 gtk_list_end_drag_selection (list);
1007 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1008 gtk_list_end_selection (list);
1013 widget = tmp_list->data;
1014 tmp_list = tmp_list->next;
1016 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1017 gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event",
1018 GTK_SIGNAL_FUNC (gtk_list_signal_focus_lost),
1020 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1021 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1023 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1024 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1026 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1027 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1029 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1030 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1032 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1033 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1035 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1036 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1038 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1039 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1041 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1042 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1044 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1045 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1047 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1048 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1050 gtk_signal_connect (GTK_OBJECT (widget), "select",
1051 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1053 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1054 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1056 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1057 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1060 if (GTK_WIDGET_VISIBLE (widget->parent))
1062 if (GTK_WIDGET_REALIZED (widget->parent) &&
1063 !GTK_WIDGET_REALIZED (widget))
1064 gtk_widget_realize (widget);
1066 if (GTK_WIDGET_MAPPED (widget->parent) &&
1067 !GTK_WIDGET_MAPPED (widget))
1068 gtk_widget_map (widget);
1072 nchildren = g_list_length (list->children);
1073 if ((position < 0) || (position > nchildren))
1074 position = nchildren;
1076 if (position == nchildren)
1080 tmp_list = g_list_last (list->children);
1081 tmp_list->next = items;
1082 items->prev = tmp_list;
1086 list->children = items;
1091 tmp_list = g_list_nth (list->children, position);
1092 last = g_list_last (items);
1095 tmp_list->prev->next = items;
1096 last->next = tmp_list;
1097 items->prev = tmp_list->prev;
1098 tmp_list->prev = last;
1100 if (tmp_list == list->children)
1101 list->children = items;
1104 if (list->children && !list->selection &&
1105 (list->selection_mode == GTK_SELECTION_BROWSE))
1107 widget = list->children->data;
1108 gtk_list_select_child (list, widget);
1111 if (GTK_WIDGET_VISIBLE (list))
1112 gtk_widget_queue_resize (GTK_WIDGET (list));
1116 gtk_list_append_items (GtkList *list,
1119 g_return_if_fail (list != NULL);
1120 g_return_if_fail (GTK_IS_LIST (list));
1122 gtk_list_insert_items (list, items, -1);
1126 gtk_list_prepend_items (GtkList *list,
1129 g_return_if_fail (list != NULL);
1130 g_return_if_fail (GTK_IS_LIST (list));
1132 gtk_list_insert_items (list, items, 0);
1136 gtk_list_remove_items (GtkList *list,
1139 gtk_list_remove_items_internal (list, items, FALSE);
1143 gtk_list_remove_items_no_unref (GtkList *list,
1146 gtk_list_remove_items_internal (list, items, TRUE);
1150 gtk_list_clear_items (GtkList *list,
1160 g_return_if_fail (list != NULL);
1161 g_return_if_fail (GTK_IS_LIST (list));
1163 nchildren = g_list_length (list->children);
1167 gboolean selection_changed;
1169 if ((end < 0) || (end > nchildren))
1175 start_list = g_list_nth (list->children, start);
1176 end_list = g_list_nth (list->children, end);
1178 gtk_list_end_drag_selection (list);
1179 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1180 gtk_list_end_selection (list);
1182 if (start_list->prev)
1183 start_list->prev->next = end_list;
1184 if (end_list && end_list->prev)
1185 end_list->prev->next = NULL;
1187 end_list->prev = start_list->prev;
1188 if (start_list == list->children)
1189 list->children = end_list;
1191 selection_changed = FALSE;
1193 tmp_list = start_list;
1197 widget = tmp_list->data;
1198 tmp_list = tmp_list->next;
1200 if (widget->state == GTK_STATE_SELECTED)
1202 gtk_list_unselect_child (list, widget);
1203 selection_changed = TRUE;
1206 gtk_widget_unparent (widget);
1209 g_list_free (start_list);
1211 if (list->children && !list->selection &&
1212 (list->selection_mode == GTK_SELECTION_BROWSE))
1214 widget = list->children->data;
1215 gtk_list_select_child (list, widget);
1217 else if (selection_changed)
1218 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1220 gtk_widget_queue_resize (GTK_WIDGET (list));
1225 gtk_list_child_position (GtkList *list,
1231 g_return_val_if_fail (list != NULL, -1);
1232 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1233 g_return_val_if_fail (child != NULL, -1);
1236 children = list->children;
1240 if (child == GTK_WIDGET (children->data))
1244 children = children->next;
1251 /* Private GtkList Insert/Remove Item Functions:
1253 * gtk_list_remove_items_internal
1256 gtk_list_remove_items_internal (GtkList *list,
1261 GtkWidget *new_focus_child;
1262 GtkWidget *old_focus_child;
1263 GtkContainer *container;
1266 gboolean grab_focus = FALSE;
1268 g_return_if_fail (list != NULL);
1269 g_return_if_fail (GTK_IS_LIST (list));
1274 container = GTK_CONTAINER (list);
1276 gtk_list_end_drag_selection (list);
1277 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1279 if (list->anchor >= 0)
1280 gtk_list_end_selection (list);
1282 if (list->undo_selection || list->undo_unselection)
1284 g_list_free (list->undo_selection);
1285 g_list_free (list->undo_unselection);
1286 list->undo_selection = NULL;
1287 list->undo_unselection = NULL;
1290 list->drag_pos = -1;
1291 list->undo_focus_child = container->focus_child;
1298 widget = tmp_list->data;
1299 tmp_list = tmp_list->next;
1301 if (widget->state == GTK_STATE_SELECTED)
1302 gtk_list_unselect_child (list, widget);
1307 old_focus_child = new_focus_child = container->focus_child;
1311 widget = tmp_list->data;
1312 tmp_list = tmp_list->next;
1315 gtk_widget_ref (widget);
1318 if (widget == new_focus_child)
1320 work = g_list_find (list->children, widget);
1325 new_focus_child = work->next->data;
1326 else if (list->children != work && work->prev)
1327 new_focus_child = work->prev->data;
1329 new_focus_child = NULL;
1331 if (GTK_WIDGET_HAS_FOCUS (widget))
1336 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1337 list->children = g_list_remove (list->children, widget);
1338 gtk_widget_unparent (widget);
1341 if (new_focus_child && new_focus_child != old_focus_child)
1344 gtk_widget_grab_focus (new_focus_child);
1346 gtk_container_set_focus_child (container, new_focus_child);
1349 if (GTK_WIDGET_VISIBLE (list))
1350 gtk_widget_queue_resize (GTK_WIDGET (list));
1354 /* Public GtkList Selection Methods :
1356 * gtk_list_set_selection_mode
1357 * gtk_list_select_item
1358 * gtk_list_unselect_item
1359 * gtk_list_select_child
1360 * gtk_list_unselect_child
1361 * gtk_list_select_all
1362 * gtk_list_unselect_all
1363 * gtk_list_extend_selection
1364 * gtk_list_end_drag_selection
1365 * gtk_list_start_selection
1366 * gtk_list_end_selection
1367 * gtk_list_toggle_row
1368 * gtk_list_toggle_focus_row
1369 * gtk_list_toggle_add_mode
1370 * gtk_list_undo_selection
1373 gtk_list_set_selection_mode (GtkList *list,
1374 GtkSelectionMode mode)
1376 g_return_if_fail (list != NULL);
1377 g_return_if_fail (GTK_IS_LIST (list));
1379 if (list->selection_mode == mode)
1382 list->selection_mode = mode;
1386 case GTK_SELECTION_SINGLE:
1387 case GTK_SELECTION_BROWSE:
1388 gtk_list_unselect_all (list);
1397 gtk_list_select_item (GtkList *list,
1402 g_return_if_fail (list != NULL);
1403 g_return_if_fail (GTK_IS_LIST (list));
1405 tmp_list = g_list_nth (list->children, item);
1407 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1411 gtk_list_unselect_item (GtkList *list,
1416 g_return_if_fail (list != NULL);
1417 g_return_if_fail (GTK_IS_LIST (list));
1419 tmp_list = g_list_nth (list->children, item);
1421 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1425 gtk_list_select_child (GtkList *list,
1428 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1432 gtk_list_unselect_child (GtkList *list,
1435 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1439 gtk_list_select_all (GtkList *list)
1441 GtkContainer *container;
1444 g_return_if_fail (list != NULL);
1445 g_return_if_fail (GTK_IS_LIST (list));
1447 if (!list->children)
1450 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1451 gtk_list_end_drag_selection (list);
1453 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1454 gtk_list_end_selection (list);
1456 container = GTK_CONTAINER (list);
1458 switch (list->selection_mode)
1460 case GTK_SELECTION_BROWSE:
1461 if (container->focus_child)
1463 gtk_list_select_child (list, container->focus_child);
1468 case GTK_SELECTION_EXTENDED:
1469 g_list_free (list->undo_selection);
1470 g_list_free (list->undo_unselection);
1471 list->undo_selection = NULL;
1472 list->undo_unselection = NULL;
1474 if (list->children &&
1475 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1476 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1478 list->anchor_state = GTK_STATE_SELECTED;
1481 list->undo_focus_child = container->focus_child;
1482 gtk_list_update_extended_selection (list, g_list_length(list->children));
1483 gtk_list_end_selection (list);
1486 case GTK_SELECTION_MULTIPLE:
1487 for (work = list->children; work; work = work->next)
1489 if (GTK_WIDGET_STATE (work->data) == GTK_STATE_NORMAL)
1490 gtk_list_select_child (list, GTK_WIDGET (work->data));
1500 gtk_list_unselect_all (GtkList *list)
1502 GtkContainer *container;
1506 g_return_if_fail (list != NULL);
1507 g_return_if_fail (GTK_IS_LIST (list));
1509 if (!list->children)
1512 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1513 gtk_list_end_drag_selection (list);
1515 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1516 gtk_list_end_selection (list);
1518 container = GTK_CONTAINER (list);
1520 switch (list->selection_mode)
1522 case GTK_SELECTION_BROWSE:
1523 if (container->focus_child)
1525 gtk_list_select_child (list, container->focus_child);
1530 case GTK_SELECTION_EXTENDED:
1531 g_list_free (list->undo_selection);
1532 g_list_free (list->undo_unselection);
1533 list->undo_selection = NULL;
1534 list->undo_unselection = NULL;
1537 list->drag_pos = -1;
1538 list->undo_focus_child = container->focus_child;
1545 work = list->selection;
1551 gtk_list_unselect_child (list, item);
1556 gtk_list_extend_selection (GtkList *list,
1557 GtkScrollType scroll_type,
1559 gboolean auto_start_selection)
1561 GtkContainer *container;
1563 g_return_if_fail (list != NULL);
1564 g_return_if_fail (GTK_IS_LIST (list));
1566 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1567 list->selection_mode != GTK_SELECTION_EXTENDED)
1570 container = GTK_CONTAINER (list);
1572 if (auto_start_selection)
1576 focus_row = g_list_index (list->children, container->focus_child);
1577 gtk_list_set_anchor (list, list->add_mode, focus_row,
1578 container->focus_child);
1580 else if (list->anchor < 0)
1583 gtk_list_move_focus_child (list, scroll_type, position);
1584 gtk_list_update_extended_selection
1585 (list, g_list_index (list->children, container->focus_child));
1589 gtk_list_end_drag_selection (GtkList *list)
1591 g_return_if_fail (list != NULL);
1592 g_return_if_fail (GTK_IS_LIST (list));
1594 list->drag_selection = FALSE;
1595 if (GTK_WIDGET_HAS_GRAB (list))
1597 gtk_grab_remove (GTK_WIDGET (list));
1598 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1602 gtk_timeout_remove (list->htimer);
1607 gtk_timeout_remove (list->vtimer);
1613 gtk_list_start_selection (GtkList *list)
1615 GtkContainer *container;
1618 g_return_if_fail (list != NULL);
1619 g_return_if_fail (GTK_IS_LIST (list));
1621 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1624 container = GTK_CONTAINER (list);
1626 if ((focus_row = g_list_index (list->selection, container->focus_child))
1628 gtk_list_set_anchor (list, list->add_mode,
1629 focus_row, container->focus_child);
1633 gtk_list_end_selection (GtkList *list)
1641 g_return_if_fail (list != NULL);
1642 g_return_if_fail (GTK_IS_LIST (list));
1644 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1648 i = MIN (list->anchor, list->drag_pos);
1649 e = MAX (list->anchor, list->drag_pos);
1652 list->drag_pos = -1;
1654 if (list->undo_selection)
1656 work = list->selection;
1657 list->selection = list->undo_selection;
1658 list->undo_selection = work;
1659 work = list->selection;
1664 item_index = g_list_index (list->children, item);
1665 if (item_index < i || item_index > e)
1667 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1668 gtk_list_unselect_child (list, item);
1669 list->undo_selection = g_list_prepend (list->undo_selection,
1675 for (work = g_list_nth (list->children, i); i <= e; i++, work = work->next)
1678 if (g_list_find (list->selection, item))
1680 if (item->state == GTK_STATE_NORMAL)
1682 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1683 gtk_list_unselect_child (list, item);
1684 list->undo_selection = g_list_prepend (list->undo_selection,
1688 else if (item->state == GTK_STATE_SELECTED)
1690 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1691 list->undo_unselection = g_list_prepend (list->undo_unselection,
1696 for (work = list->undo_unselection; work; work = work->next)
1697 gtk_list_select_child (list, GTK_WIDGET (work->data));
1702 gtk_list_toggle_row (GtkList *list,
1705 g_return_if_fail (list != NULL);
1706 g_return_if_fail (GTK_IS_LIST (list));
1707 g_return_if_fail (item != NULL);
1708 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1710 switch (list->selection_mode)
1712 case GTK_SELECTION_EXTENDED:
1713 case GTK_SELECTION_MULTIPLE:
1714 case GTK_SELECTION_SINGLE:
1716 if (item->state == GTK_STATE_SELECTED)
1718 gtk_list_unselect_child (list, item);
1722 case GTK_SELECTION_BROWSE:
1723 gtk_list_select_child (list, item);
1729 gtk_list_toggle_focus_row (GtkList *list)
1731 GtkContainer *container;
1734 g_return_if_fail (list != 0);
1735 g_return_if_fail (GTK_IS_LIST (list));
1737 container = GTK_CONTAINER (list);
1739 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1740 !container->focus_child)
1743 switch (list->selection_mode)
1745 case GTK_SELECTION_SINGLE:
1746 case GTK_SELECTION_MULTIPLE:
1748 gtk_list_toggle_row (list, container->focus_child);
1751 case GTK_SELECTION_EXTENDED:
1753 if ((focus_row = g_list_index (list->children, container->focus_child))
1757 g_list_free (list->undo_selection);
1758 g_list_free (list->undo_unselection);
1759 list->undo_selection = NULL;
1760 list->undo_unselection = NULL;
1762 list->anchor = focus_row;
1763 list->drag_pos = focus_row;
1764 list->undo_focus_child = container->focus_child;
1767 gtk_list_fake_toggle_row (list, container->focus_child);
1769 gtk_list_fake_unselect_all (list, container->focus_child);
1771 gtk_list_end_selection (list);
1780 gtk_list_toggle_add_mode (GtkList *list)
1782 GtkContainer *container;
1784 g_return_if_fail (list != 0);
1785 g_return_if_fail (GTK_IS_LIST (list));
1787 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1788 list->selection_mode != GTK_SELECTION_EXTENDED)
1791 container = GTK_CONTAINER (list);
1795 list->add_mode = FALSE;
1796 list->anchor_state = GTK_STATE_SELECTED;
1799 list->add_mode = TRUE;
1801 if (container->focus_child)
1802 gtk_widget_queue_draw (container->focus_child);
1806 gtk_list_undo_selection (GtkList *list)
1810 g_return_if_fail (list != NULL);
1811 g_return_if_fail (GTK_IS_LIST (list));
1813 if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1814 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1817 if (list->anchor >= 0)
1818 gtk_list_end_selection (list);
1820 if (!(list->undo_selection || list->undo_unselection))
1822 gtk_list_unselect_all (list);
1826 for (work = list->undo_selection; work; work = work->next)
1827 gtk_list_select_child (list, GTK_WIDGET (work->data));
1829 for (work = list->undo_unselection; work; work = work->next)
1830 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1832 if (list->undo_focus_child)
1834 GtkContainer *container;
1836 container = GTK_CONTAINER (list);
1838 if (container->focus_child &&
1839 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1840 gtk_widget_grab_focus (list->undo_focus_child);
1842 gtk_container_set_focus_child (container, list->undo_focus_child);
1845 list->undo_focus_child = NULL;
1847 g_list_free (list->undo_selection);
1848 g_list_free (list->undo_unselection);
1849 list->undo_selection = NULL;
1850 list->undo_unselection = NULL;
1854 /* Private GtkList Selection Methods :
1856 * gtk_real_list_select_child
1857 * gtk_real_list_unselect_child
1860 gtk_real_list_select_child (GtkList *list,
1863 g_return_if_fail (list != NULL);
1864 g_return_if_fail (GTK_IS_LIST (list));
1865 g_return_if_fail (child != NULL);
1866 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1868 switch (child->state)
1870 case GTK_STATE_SELECTED:
1871 case GTK_STATE_INSENSITIVE:
1874 gtk_list_item_select (GTK_LIST_ITEM (child));
1880 gtk_real_list_unselect_child (GtkList *list,
1883 g_return_if_fail (list != NULL);
1884 g_return_if_fail (GTK_IS_LIST (list));
1885 g_return_if_fail (child != NULL);
1886 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1888 if (child->state == GTK_STATE_SELECTED)
1889 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1893 /* Private GtkList Selection Functions :
1895 * gtk_list_set_anchor
1896 * gtk_list_fake_unselect_all
1897 * gtk_list_fake_toggle_row
1898 * gtk_list_update_extended_selection
1901 gtk_list_set_anchor (GtkList *list,
1904 GtkWidget *undo_focus_child)
1908 g_return_if_fail (list != NULL);
1909 g_return_if_fail (GTK_IS_LIST (list));
1911 if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
1914 g_list_free (list->undo_selection);
1915 g_list_free (list->undo_unselection);
1916 list->undo_selection = NULL;
1917 list->undo_unselection = NULL;
1919 if ((work = g_list_nth (list->children, anchor)))
1922 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
1925 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
1926 list->anchor_state = GTK_STATE_SELECTED;
1930 list->anchor = anchor;
1931 list->drag_pos = anchor;
1932 list->undo_focus_child = undo_focus_child;
1936 gtk_list_fake_unselect_all (GtkList *list,
1941 if (item && item->state == GTK_STATE_NORMAL)
1942 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1944 list->undo_selection = list->selection;
1945 list->selection = NULL;
1947 for (work = list->undo_selection; work; work = work->next)
1948 if (work->data != item)
1949 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
1953 gtk_list_fake_toggle_row (GtkList *list,
1959 if (item->state == GTK_STATE_NORMAL)
1961 list->anchor_state = GTK_STATE_SELECTED;
1962 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1966 list->anchor_state = GTK_STATE_NORMAL;
1967 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1972 gtk_list_update_extended_selection (GtkList *list,
1986 length = g_list_length (list->children);
1990 if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
1993 /* extending downwards */
1994 if (row > list->drag_pos && list->anchor <= list->drag_pos)
1996 s2 = list->drag_pos + 1;
1999 /* extending upwards */
2000 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2003 e2 = list->drag_pos - 1;
2005 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2007 e1 = list->drag_pos;
2008 /* row and drag_pos on different sides of anchor :
2009 take back the selection between anchor and drag_pos,
2010 select between anchor and row */
2011 if (row < list->anchor)
2013 s1 = list->anchor + 1;
2015 e2 = list->anchor - 1;
2017 /* take back the selection between anchor and drag_pos */
2021 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2023 s1 = list->drag_pos;
2024 /* row and drag_pos on different sides of anchor :
2025 take back the selection between anchor and drag_pos,
2026 select between anchor and row */
2027 if (row > list->anchor)
2029 e1 = list->anchor - 1;
2030 s2 = list->anchor + 1;
2033 /* take back the selection between anchor and drag_pos */
2038 list->drag_pos = row;
2040 /* restore the elements between s1 and e1 */
2043 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2044 i++, work = work->next)
2046 if (g_list_find (list->selection, work->data))
2047 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2049 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2053 /* extend the selection between s2 and e2 */
2056 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2057 i++, work = work->next)
2058 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2059 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2064 /* Public GtkList Scroll Methods :
2066 * gtk_list_scroll_horizontal
2067 * gtk_list_scroll_vertical
2070 gtk_list_scroll_horizontal (GtkList *list,
2071 GtkScrollType scroll_type,
2076 g_return_if_fail (list != 0);
2077 g_return_if_fail (GTK_IS_LIST (list));
2079 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2083 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2086 switch (scroll_type)
2088 case GTK_SCROLL_STEP_BACKWARD:
2089 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2090 adj->upper - adj->page_size);
2092 case GTK_SCROLL_STEP_FORWARD:
2093 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2094 adj->upper - adj->page_size);
2096 case GTK_SCROLL_PAGE_BACKWARD:
2097 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2098 adj->upper - adj->page_size);
2100 case GTK_SCROLL_PAGE_FORWARD:
2101 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2102 adj->upper - adj->page_size);
2104 case GTK_SCROLL_JUMP:
2105 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2106 adj->lower, adj->upper - adj->page_size);
2111 gtk_adjustment_value_changed (adj);
2115 gtk_list_scroll_vertical (GtkList *list,
2116 GtkScrollType scroll_type,
2119 g_return_if_fail (list != NULL);
2120 g_return_if_fail (GTK_IS_LIST (list));
2122 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2125 if (list->selection_mode == GTK_SELECTION_EXTENDED)
2127 GtkContainer *container;
2129 if (list->anchor >= 0)
2132 container = GTK_CONTAINER (list);
2133 list->undo_focus_child = container->focus_child;
2134 gtk_list_move_focus_child (list, scroll_type, position);
2135 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2137 gtk_list_unselect_all (list);
2138 gtk_list_select_child (list, container->focus_child);
2142 gtk_list_move_focus_child (list, scroll_type, position);
2146 /* Private GtkList Scroll/Focus Functions :
2148 * gtk_list_move_focus_child
2149 * gtk_list_horizontal_timeout
2150 * gtk_list_vertical_timeout
2153 gtk_list_move_focus_child (GtkList *list,
2154 GtkScrollType scroll_type,
2157 GtkContainer *container;
2163 g_return_if_fail (list != 0);
2164 g_return_if_fail (GTK_IS_LIST (list));
2166 container = GTK_CONTAINER (list);
2168 if (container->focus_child)
2169 work = g_list_find (list->children, container->focus_child);
2171 work = list->children;
2176 switch (scroll_type)
2178 case GTK_SCROLL_STEP_BACKWARD:
2181 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2184 case GTK_SCROLL_STEP_FORWARD:
2187 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2190 case GTK_SCROLL_PAGE_BACKWARD:
2195 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2199 gboolean correct = FALSE;
2201 new_value = adj->value;
2203 if (item->allocation.y <= adj->value)
2205 new_value = MAX (item->allocation.y + item->allocation.height
2206 - adj->page_size, adj->lower);
2210 if (item->allocation.y > new_value)
2211 for (; work; work = work->prev)
2213 item = GTK_WIDGET (work->data);
2214 if (item->allocation.y <= new_value &&
2215 item->allocation.y + item->allocation.height > new_value)
2219 for (; work; work = work->next)
2221 item = GTK_WIDGET (work->data);
2222 if (item->allocation.y <= new_value &&
2223 item->allocation.y + item->allocation.height > new_value)
2227 if (correct && work && work->next && item->allocation.y < new_value)
2228 item = work->next->data;
2231 item = list->children->data;
2233 gtk_widget_grab_focus (item);
2236 case GTK_SCROLL_PAGE_FORWARD:
2241 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2245 gboolean correct = FALSE;
2247 new_value = adj->value;
2249 if (item->allocation.y + item->allocation.height >=
2250 adj->value + adj->page_size)
2252 new_value = item->allocation.y;
2256 new_value = MIN (new_value + adj->page_size, adj->upper);
2258 if (item->allocation.y > new_value)
2259 for (; work; work = work->prev)
2261 item = GTK_WIDGET (work->data);
2262 if (item->allocation.y <= new_value &&
2263 item->allocation.y + item->allocation.height > new_value)
2267 for (; work; work = work->next)
2269 item = GTK_WIDGET (work->data);
2270 if (item->allocation.y <= new_value &&
2271 item->allocation.y + item->allocation.height > new_value)
2275 if (correct && work && work->prev &&
2276 item->allocation.y + item->allocation.height - 1 > new_value)
2277 item = work->prev->data;
2280 item = g_list_last (work)->data;
2282 gtk_widget_grab_focus (item);
2285 case GTK_SCROLL_JUMP:
2286 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2288 for (item = NULL, work = list->children; work; work =work->next)
2290 item = GTK_WIDGET (work->data);
2291 if (item->allocation.y <= new_value &&
2292 item->allocation.y + item->allocation.height > new_value)
2296 gtk_widget_grab_focus (item);
2305 gtk_list_horizontal_timeout (GtkWidget *list)
2308 GdkEventMotion event;
2309 GdkModifierType mask;
2311 GDK_THREADS_ENTER ();
2313 GTK_LIST (list)->htimer = 0;
2314 gdk_window_get_pointer (list->window, &x, &y, &mask);
2321 gtk_list_motion_notify (list, &event);
2323 GDK_THREADS_LEAVE ();
2329 gtk_list_vertical_timeout (GtkWidget *list)
2333 GdkEventMotion event;
2334 GdkModifierType mask;
2336 GDK_THREADS_ENTER ();
2338 GTK_LIST (list)->vtimer = 0;
2339 gdk_window_get_pointer (list->window, &x, &y, &mask);
2346 gtk_list_motion_notify (list, &event);
2348 GDK_THREADS_LEAVE ();
2354 /* Private GtkListItem Signal Functions :
2356 * gtk_list_signal_focus_lost
2357 * gtk_list_signal_toggle_focus_row
2358 * gtk_list_signal_select_all
2359 * gtk_list_signal_unselect_all
2360 * gtk_list_signal_undo_selection
2361 * gtk_list_signal_start_selection
2362 * gtk_list_signal_end_selection
2363 * gtk_list_signal_extend_selection
2364 * gtk_list_signal_scroll_horizontal
2365 * gtk_list_signal_scroll_vertical
2366 * gtk_list_signal_toggle_add_mode
2367 * gtk_list_signal_item_select
2368 * gtk_list_signal_item_deselect
2369 * gtk_list_signal_item_toggle
2372 gtk_list_signal_focus_lost (GtkWidget *item,
2376 g_return_if_fail (list != NULL);
2377 g_return_if_fail (GTK_IS_LIST (list));
2378 g_return_if_fail (item != NULL);
2379 g_return_if_fail (GTK_IS_LIST_ITEM (item));
2381 if (list->selection_mode == GTK_SELECTION_EXTENDED &&
2382 list->anchor >= 0 &&
2383 item == GTK_CONTAINER (list)->focus_child)
2384 gtk_list_end_selection (list);
2388 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2391 g_return_if_fail (list_item != 0);
2392 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2393 g_return_if_fail (list != NULL);
2394 g_return_if_fail (GTK_IS_LIST (list));
2396 gtk_list_toggle_focus_row (list);
2400 gtk_list_signal_select_all (GtkListItem *list_item,
2403 g_return_if_fail (list_item != 0);
2404 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2405 g_return_if_fail (list != NULL);
2406 g_return_if_fail (GTK_IS_LIST (list));
2408 gtk_list_select_all (list);
2412 gtk_list_signal_unselect_all (GtkListItem *list_item,
2415 g_return_if_fail (list_item != 0);
2416 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2417 g_return_if_fail (list != NULL);
2418 g_return_if_fail (GTK_IS_LIST (list));
2420 gtk_list_unselect_all (list);
2424 gtk_list_signal_undo_selection (GtkListItem *list_item,
2427 g_return_if_fail (list_item != 0);
2428 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2429 g_return_if_fail (list != NULL);
2430 g_return_if_fail (GTK_IS_LIST (list));
2432 gtk_list_undo_selection (list);
2436 gtk_list_signal_start_selection (GtkListItem *list_item,
2439 g_return_if_fail (list_item != 0);
2440 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2441 g_return_if_fail (list != NULL);
2442 g_return_if_fail (GTK_IS_LIST (list));
2444 gtk_list_start_selection (list);
2448 gtk_list_signal_end_selection (GtkListItem *list_item,
2451 g_return_if_fail (list_item != 0);
2452 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2453 g_return_if_fail (list != NULL);
2454 g_return_if_fail (GTK_IS_LIST (list));
2456 gtk_list_end_selection (list);
2460 gtk_list_signal_extend_selection (GtkListItem *list_item,
2461 GtkScrollType scroll_type,
2463 gboolean auto_start_selection,
2466 g_return_if_fail (list_item != 0);
2467 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2468 g_return_if_fail (list != NULL);
2469 g_return_if_fail (GTK_IS_LIST (list));
2471 gtk_list_extend_selection (list, scroll_type, position,
2472 auto_start_selection);
2476 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2477 GtkScrollType scroll_type,
2481 g_return_if_fail (list_item != 0);
2482 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2483 g_return_if_fail (list != NULL);
2484 g_return_if_fail (GTK_IS_LIST (list));
2486 gtk_list_scroll_horizontal (list, scroll_type, position);
2490 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2491 GtkScrollType scroll_type,
2495 g_return_if_fail (list_item != 0);
2496 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2497 g_return_if_fail (list != NULL);
2498 g_return_if_fail (GTK_IS_LIST (list));
2500 gtk_list_scroll_vertical (list, scroll_type, position);
2504 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2507 g_return_if_fail (list_item != 0);
2508 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2509 g_return_if_fail (list != NULL);
2510 g_return_if_fail (GTK_IS_LIST (list));
2512 gtk_list_toggle_add_mode (list);
2516 gtk_list_signal_item_select (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 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2531 switch (list->selection_mode)
2533 case GTK_SELECTION_SINGLE:
2534 case GTK_SELECTION_BROWSE:
2536 selection = list->selection;
2540 tmp_list = selection;
2541 selection = selection->next;
2543 if (tmp_list->data == list_item)
2544 sel_list = tmp_list;
2546 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2551 list->selection = g_list_prepend (list->selection, list_item);
2552 gtk_widget_ref (GTK_WIDGET (list_item));
2554 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2556 case GTK_SELECTION_EXTENDED:
2557 if (list->anchor >= 0)
2559 case GTK_SELECTION_MULTIPLE:
2560 if (!g_list_find (list->selection, list_item))
2562 list->selection = g_list_prepend (list->selection, list_item);
2563 gtk_widget_ref (GTK_WIDGET (list_item));
2564 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2571 gtk_list_signal_item_deselect (GtkListItem *list_item,
2576 g_return_if_fail (list_item != 0);
2577 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2578 g_return_if_fail (list != NULL);
2579 g_return_if_fail (GTK_IS_LIST (list));
2581 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2584 node = g_list_find (list->selection, list_item);
2588 list->selection = g_list_remove_link (list->selection, node);
2589 g_list_free_1 (node);
2590 gtk_widget_unref (GTK_WIDGET (list_item));
2591 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2596 gtk_list_signal_item_toggle (GtkListItem *list_item,
2599 g_return_if_fail (list_item != 0);
2600 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2601 g_return_if_fail (list != NULL);
2602 g_return_if_fail (GTK_IS_LIST (list));
2604 switch (GTK_WIDGET (list_item)->state)
2606 case GTK_STATE_SELECTED:
2607 gtk_list_signal_item_select (list_item, list);
2609 case GTK_STATE_NORMAL:
2610 gtk_list_signal_item_deselect (list_item, list);