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 Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "gtklistitem.h"
21 #include "gtksignal.h"
32 typedef void (*GtkListSignal) (GtkObject *object,
37 static void gtk_list_class_init (GtkListClass *klass);
38 static void gtk_list_init (GtkList *list);
39 static void gtk_list_destroy (GtkObject *object);
40 static void gtk_list_map (GtkWidget *widget);
41 static void gtk_list_unmap (GtkWidget *widget);
42 static void gtk_list_realize (GtkWidget *widget);
43 static void gtk_list_draw (GtkWidget *widget,
45 static gint gtk_list_expose (GtkWidget *widget,
46 GdkEventExpose *event);
47 static gint gtk_list_motion_notify (GtkWidget *widget,
48 GdkEventMotion *event);
49 static gint gtk_list_button_press (GtkWidget *widget,
50 GdkEventButton *event);
51 static gint gtk_list_button_release (GtkWidget *widget,
52 GdkEventButton *event);
53 static void gtk_list_size_request (GtkWidget *widget,
54 GtkRequisition *requisition);
55 static void gtk_list_size_allocate (GtkWidget *widget,
56 GtkAllocation *allocation);
57 static void gtk_list_add (GtkContainer *container,
59 static void gtk_list_remove (GtkContainer *container,
61 static void gtk_list_foreach (GtkContainer *container,
63 gpointer callback_data);
65 static void gtk_real_list_select_child (GtkList *list,
67 static void gtk_real_list_unselect_child (GtkList *list,
70 static void gtk_list_marshal_signal (GtkObject *object,
76 static GtkContainerClass *parent_class = NULL;
77 static gint list_signals[LAST_SIGNAL] = { 0 };
83 static guint list_type = 0;
87 GtkTypeInfo list_info =
91 sizeof (GtkListClass),
92 (GtkClassInitFunc) gtk_list_class_init,
93 (GtkObjectInitFunc) gtk_list_init,
98 list_type = gtk_type_unique (gtk_container_get_type (), &list_info);
105 gtk_list_class_init (GtkListClass *class)
107 GtkObjectClass *object_class;
108 GtkWidgetClass *widget_class;
109 GtkContainerClass *container_class;
111 object_class = (GtkObjectClass*) class;
112 widget_class = (GtkWidgetClass*) class;
113 container_class = (GtkContainerClass*) class;
115 parent_class = gtk_type_class (gtk_container_get_type ());
117 list_signals[SELECTION_CHANGED] =
118 gtk_signal_new ("selection_changed",
121 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
122 gtk_signal_default_marshaller,
124 list_signals[SELECT_CHILD] =
125 gtk_signal_new ("select_child",
128 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
129 gtk_list_marshal_signal,
132 list_signals[UNSELECT_CHILD] =
133 gtk_signal_new ("unselect_child",
136 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
137 gtk_list_marshal_signal,
141 gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
143 object_class->destroy = gtk_list_destroy;
145 widget_class->map = gtk_list_map;
146 widget_class->unmap = gtk_list_unmap;
147 widget_class->realize = gtk_list_realize;
148 widget_class->draw = gtk_list_draw;
149 widget_class->expose_event = gtk_list_expose;
150 widget_class->motion_notify_event = gtk_list_motion_notify;
151 widget_class->button_press_event = gtk_list_button_press;
152 widget_class->button_release_event = gtk_list_button_release;
153 widget_class->size_request = gtk_list_size_request;
154 widget_class->size_allocate = gtk_list_size_allocate;
156 container_class->add = gtk_list_add;
157 container_class->remove = gtk_list_remove;
158 container_class->foreach = gtk_list_foreach;
160 class->selection_changed = NULL;
161 class->select_child = gtk_real_list_select_child;
162 class->unselect_child = gtk_real_list_unselect_child;
166 gtk_list_init (GtkList *list)
168 list->children = NULL;
169 list->selection = NULL;
171 list->selection_start_pos = 0;
172 list->selection_end_pos = 0;
173 list->selection_mode = GTK_SELECTION_SINGLE;
174 list->scroll_direction = 0;
175 list->have_grab = FALSE;
181 return GTK_WIDGET (gtk_type_new (gtk_list_get_type ()));
185 gtk_list_destroy (GtkObject *object)
189 GtkList *list = GTK_LIST (object);
191 for (node = list->children; node; node = node->next)
195 child = (GtkWidget *)node->data;
196 gtk_widget_ref (child);
197 gtk_widget_unparent (child);
198 gtk_widget_destroy (child);
199 gtk_widget_unref (child);
201 g_list_free (list->children);
202 list->children = NULL;
204 for (node = list->selection; node; node = node->next)
208 child = (GtkWidget *)node->data;
209 gtk_widget_unref (child);
211 g_list_free (list->selection);
212 list->selection = NULL;
214 if (GTK_OBJECT_CLASS (parent_class)->destroy)
215 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
219 gtk_list_insert_items (GtkList *list,
228 g_return_if_fail (list != NULL);
229 g_return_if_fail (GTK_IS_LIST (list));
237 widget = tmp_list->data;
238 tmp_list = tmp_list->next;
240 gtk_widget_set_parent (widget, GTK_WIDGET (list));
242 if (GTK_WIDGET_VISIBLE (widget->parent))
244 if (GTK_WIDGET_REALIZED (widget->parent) &&
245 !GTK_WIDGET_REALIZED (widget))
246 gtk_widget_realize (widget);
248 if (GTK_WIDGET_MAPPED (widget->parent) &&
249 !GTK_WIDGET_MAPPED (widget))
250 gtk_widget_map (widget);
254 nchildren = g_list_length (list->children);
255 if ((position < 0) || (position > nchildren))
256 position = nchildren;
258 if (position == nchildren)
262 tmp_list = g_list_last (list->children);
263 tmp_list->next = items;
264 items->prev = tmp_list;
268 list->children = items;
273 tmp_list = g_list_nth (list->children, position);
274 last = g_list_last (items);
277 tmp_list->prev->next = items;
278 last->next = tmp_list;
279 items->prev = tmp_list->prev;
280 tmp_list->prev = last;
282 if (tmp_list == list->children)
283 list->children = items;
286 if (list->children && !list->selection &&
287 (list->selection_mode == GTK_SELECTION_BROWSE))
289 widget = list->children->data;
290 gtk_list_select_child (list, widget);
293 if (GTK_WIDGET_VISIBLE (list))
294 gtk_widget_queue_resize (GTK_WIDGET (list));
298 gtk_list_append_items (GtkList *list,
301 g_return_if_fail (list != NULL);
302 g_return_if_fail (GTK_IS_LIST (list));
304 gtk_list_insert_items (list, items, -1);
308 gtk_list_prepend_items (GtkList *list,
311 g_return_if_fail (list != NULL);
312 g_return_if_fail (GTK_IS_LIST (list));
314 gtk_list_insert_items (list, items, 0);
318 gtk_list_remove_items_internal (GtkList *list,
323 GList *selected_widgets;
326 g_return_if_fail (list != NULL);
327 g_return_if_fail (GTK_IS_LIST (list));
330 selected_widgets = NULL;
335 widget = tmp_list->data;
336 tmp_list = tmp_list->next;
338 if (widget->state == GTK_STATE_SELECTED)
339 selected_widgets = g_list_prepend (selected_widgets, widget);
341 list->children = g_list_remove (list->children, widget);
343 if (GTK_WIDGET_MAPPED (widget))
344 gtk_widget_unmap (widget);
347 gtk_widget_ref (widget);
348 gtk_widget_unparent (widget);
351 if (selected_widgets)
353 tmp_list = selected_widgets;
356 widget = tmp_list->data;
357 tmp_list = tmp_list->next;
359 gtk_list_unselect_child (list, widget);
362 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
365 g_list_free (selected_widgets);
367 if (list->children && !list->selection &&
368 (list->selection_mode == GTK_SELECTION_BROWSE))
370 widget = list->children->data;
371 gtk_list_select_child (list, widget);
374 if (GTK_WIDGET_VISIBLE (list))
375 gtk_widget_queue_resize (GTK_WIDGET (list));
379 gtk_list_remove_items (GtkList *list,
382 gtk_list_remove_items_internal (list, items, FALSE);
386 gtk_list_remove_items_no_unref (GtkList *list,
389 gtk_list_remove_items_internal (list, items, TRUE);
393 gtk_list_clear_items (GtkList *list,
402 gint selection_changed;
404 g_return_if_fail (list != NULL);
405 g_return_if_fail (GTK_IS_LIST (list));
407 nchildren = g_list_length (list->children);
411 if ((end < 0) || (end > nchildren))
417 start_list = g_list_nth (list->children, start);
418 end_list = g_list_nth (list->children, end);
420 if (start_list->prev)
421 start_list->prev->next = end_list;
422 if (end_list && end_list->prev)
423 end_list->prev->next = NULL;
425 end_list->prev = start_list->prev;
426 if (start_list == list->children)
427 list->children = end_list;
429 selection_changed = FALSE;
431 tmp_list = start_list;
435 widget = tmp_list->data;
436 tmp_list = tmp_list->next;
438 if (widget->state == GTK_STATE_SELECTED)
440 selection_changed = TRUE;
441 list->selection = g_list_remove (list->selection, widget);
442 gtk_widget_unref (widget);
445 gtk_widget_unparent (widget);
448 g_list_free (start_list);
450 if (list->children && !list->selection &&
451 (list->selection_mode == GTK_SELECTION_BROWSE))
453 widget = list->children->data;
454 gtk_list_select_child (list, widget);
457 if (selection_changed)
458 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
460 gtk_widget_queue_resize (GTK_WIDGET (list));
465 gtk_list_select_item (GtkList *list,
470 g_return_if_fail (list != NULL);
471 g_return_if_fail (GTK_IS_LIST (list));
473 tmp_list = g_list_nth (list->children, item);
475 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
479 gtk_list_unselect_item (GtkList *list,
484 g_return_if_fail (list != NULL);
485 g_return_if_fail (GTK_IS_LIST (list));
487 tmp_list = g_list_nth (list->children, item);
489 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
493 gtk_list_select_child (GtkList *list,
496 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
500 gtk_list_unselect_child (GtkList *list,
503 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
507 gtk_list_child_position (GtkList *list,
513 g_return_val_if_fail (list != NULL, -1);
514 g_return_val_if_fail (GTK_IS_LIST (list), -1);
515 g_return_val_if_fail (child != NULL, -1);
518 children = list->children;
522 if (child == GTK_WIDGET (children->data))
526 children = children->next;
533 gtk_list_set_selection_mode (GtkList *list,
534 GtkSelectionMode mode)
536 g_return_if_fail (list != NULL);
537 g_return_if_fail (GTK_IS_LIST (list));
539 list->selection_mode = mode;
544 gtk_list_map (GtkWidget *widget)
550 g_return_if_fail (widget != NULL);
551 g_return_if_fail (GTK_IS_LIST (widget));
553 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
554 list = GTK_LIST (widget);
556 gdk_window_show (widget->window);
558 children = list->children;
561 child = children->data;
562 children = children->next;
564 if (GTK_WIDGET_VISIBLE (child) &&
565 !GTK_WIDGET_MAPPED (child))
566 gtk_widget_map (child);
571 gtk_list_unmap (GtkWidget *widget)
573 g_return_if_fail (widget != NULL);
574 g_return_if_fail (GTK_IS_LIST (widget));
576 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
577 gdk_window_hide (widget->window);
581 gtk_list_realize (GtkWidget *widget)
583 GdkWindowAttr attributes;
584 gint attributes_mask;
586 g_return_if_fail (widget != NULL);
587 g_return_if_fail (GTK_IS_LIST (widget));
589 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
591 attributes.window_type = GDK_WINDOW_CHILD;
592 attributes.x = widget->allocation.x;
593 attributes.y = widget->allocation.y;
594 attributes.width = widget->allocation.width;
595 attributes.height = widget->allocation.height;
596 attributes.wclass = GDK_INPUT_OUTPUT;
597 attributes.visual = gtk_widget_get_visual (widget);
598 attributes.colormap = gtk_widget_get_colormap (widget);
599 attributes.event_mask = GDK_EXPOSURE_MASK;
601 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
603 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
604 gdk_window_set_user_data (widget->window, widget);
606 widget->style = gtk_style_attach (widget->style, widget->window);
607 gdk_window_set_background (widget->window,
608 &widget->style->base[GTK_STATE_NORMAL]);
612 gtk_list_draw (GtkWidget *widget,
617 GdkRectangle child_area;
620 g_return_if_fail (widget != NULL);
621 g_return_if_fail (GTK_IS_LIST (widget));
622 g_return_if_fail (area != NULL);
624 if (GTK_WIDGET_DRAWABLE (widget))
626 list = GTK_LIST (widget);
628 children = list->children;
631 child = children->data;
632 children = children->next;
634 if (gtk_widget_intersect (child, area, &child_area))
635 gtk_widget_draw (child, &child_area);
641 gtk_list_expose (GtkWidget *widget,
642 GdkEventExpose *event)
646 GdkEventExpose child_event;
649 g_return_val_if_fail (widget != NULL, FALSE);
650 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
651 g_return_val_if_fail (event != NULL, FALSE);
653 if (GTK_WIDGET_DRAWABLE (widget))
655 list = GTK_LIST (widget);
657 child_event = *event;
659 children = list->children;
662 child = children->data;
663 children = children->next;
665 if (GTK_WIDGET_NO_WINDOW (child) &&
666 gtk_widget_intersect (child, &event->area, &child_event.area))
667 gtk_widget_event (child, (GdkEvent*) &child_event);
675 gtk_list_motion_notify (GtkWidget *widget,
676 GdkEventMotion *event)
678 g_return_val_if_fail (widget != NULL, FALSE);
679 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
680 g_return_val_if_fail (event != NULL, FALSE);
682 g_print ("gtk_list_motion_notify\n");
688 gtk_list_button_press (GtkWidget *widget,
689 GdkEventButton *event)
694 g_return_val_if_fail (widget != NULL, FALSE);
695 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
696 g_return_val_if_fail (event != NULL, FALSE);
698 list = GTK_LIST (widget);
699 item = gtk_get_event_widget ((GdkEvent*) event);
704 while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_list_item_get_type ()))
707 gtk_list_select_child (list, item);
713 gtk_list_button_release (GtkWidget *widget,
714 GdkEventButton *event)
719 g_return_val_if_fail (widget != NULL, FALSE);
720 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
721 g_return_val_if_fail (event != NULL, FALSE);
723 list = GTK_LIST (widget);
724 item = gtk_get_event_widget ((GdkEvent*) event);
730 gtk_list_size_request (GtkWidget *widget,
731 GtkRequisition *requisition)
737 g_return_if_fail (widget != NULL);
738 g_return_if_fail (GTK_IS_LIST (widget));
739 g_return_if_fail (requisition != NULL);
741 list = GTK_LIST (widget);
742 requisition->width = 0;
743 requisition->height = 0;
745 children = list->children;
748 child = children->data;
749 children = children->next;
751 if (GTK_WIDGET_VISIBLE (child))
753 gtk_widget_size_request (child, &child->requisition);
755 requisition->width = MAX (requisition->width, child->requisition.width);
756 requisition->height += child->requisition.height;
760 requisition->width += GTK_CONTAINER (list)->border_width * 2;
761 requisition->height += GTK_CONTAINER (list)->border_width * 2;
763 requisition->width = MAX (requisition->width, 1);
764 requisition->height = MAX (requisition->height, 1);
768 gtk_list_size_allocate (GtkWidget *widget,
769 GtkAllocation *allocation)
773 GtkAllocation child_allocation;
776 g_return_if_fail (widget != NULL);
777 g_return_if_fail (GTK_IS_LIST (widget));
778 g_return_if_fail (allocation != NULL);
780 list = GTK_LIST (widget);
782 widget->allocation = *allocation;
783 if (GTK_WIDGET_REALIZED (widget))
784 gdk_window_move_resize (widget->window,
785 allocation->x, allocation->y,
786 allocation->width, allocation->height);
790 child_allocation.x = GTK_CONTAINER (list)->border_width;
791 child_allocation.y = GTK_CONTAINER (list)->border_width;
792 child_allocation.width = allocation->width - child_allocation.x * 2;
794 children = list->children;
798 child = children->data;
799 children = children->next;
801 if (GTK_WIDGET_VISIBLE (child))
803 child_allocation.height = child->requisition.height;
805 gtk_widget_size_allocate (child, &child_allocation);
807 child_allocation.y += child_allocation.height;
814 gtk_list_add (GtkContainer *container,
819 g_return_if_fail (container != NULL);
820 g_return_if_fail (GTK_IS_LIST (container));
821 g_return_if_fail (widget != NULL);
823 list = GTK_LIST (container);
825 gtk_widget_set_parent (widget, GTK_WIDGET (container));
826 if (GTK_WIDGET_VISIBLE (widget->parent))
828 if (GTK_WIDGET_REALIZED (widget->parent) &&
829 !GTK_WIDGET_REALIZED (widget))
830 gtk_widget_realize (widget);
832 if (GTK_WIDGET_MAPPED (widget->parent) &&
833 !GTK_WIDGET_MAPPED (widget))
834 gtk_widget_map (widget);
837 list->children = g_list_append (list->children, widget);
839 if (!list->selection && (list->selection_mode == GTK_SELECTION_BROWSE))
840 gtk_list_select_child (list, widget);
842 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
843 gtk_widget_queue_resize (widget);
847 gtk_list_remove (GtkContainer *container,
852 g_return_if_fail (container != NULL);
853 g_return_if_fail (GTK_IS_LIST (container));
854 g_return_if_fail (widget != NULL);
855 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_foreach (GtkContainer *container,
868 GtkCallback callback,
869 gpointer callback_data)
875 g_return_if_fail (container != NULL);
876 g_return_if_fail (GTK_IS_LIST (container));
877 g_return_if_fail (callback != NULL);
879 list = GTK_LIST (container);
880 children = list->children;
884 child = children->data;
885 children = children->next;
887 (* callback) (child, callback_data);
893 gtk_real_list_select_child (GtkList *list,
900 g_return_if_fail (list != NULL);
901 g_return_if_fail (GTK_IS_LIST (list));
902 g_return_if_fail (child != NULL);
903 g_return_if_fail (GTK_IS_LIST_ITEM (child));
905 switch (list->selection_mode)
907 case GTK_SELECTION_SINGLE:
908 selection = list->selection;
912 tmp_item = selection->data;
914 if (tmp_item != child)
916 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
918 tmp_list = selection;
919 selection = selection->next;
921 list->selection = g_list_remove_link (list->selection, tmp_list);
922 gtk_widget_unref (GTK_WIDGET (tmp_item));
924 g_list_free (tmp_list);
927 selection = selection->next;
930 if (child->state == GTK_STATE_NORMAL)
932 gtk_list_item_select (GTK_LIST_ITEM (child));
933 list->selection = g_list_prepend (list->selection, child);
934 gtk_widget_ref (child);
936 else if (child->state == GTK_STATE_SELECTED)
938 gtk_list_item_deselect (GTK_LIST_ITEM (child));
939 list->selection = g_list_remove (list->selection, child);
940 gtk_widget_unref (child);
943 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
946 case GTK_SELECTION_BROWSE:
947 selection = list->selection;
951 tmp_item = selection->data;
953 if (tmp_item != child)
955 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
957 tmp_list = selection;
958 selection = selection->next;
960 list->selection = g_list_remove_link (list->selection, tmp_list);
961 gtk_widget_unref (GTK_WIDGET (tmp_item));
963 g_list_free (tmp_list);
966 selection = selection->next;
969 if (child->state == GTK_STATE_NORMAL)
971 gtk_list_item_select (GTK_LIST_ITEM (child));
972 list->selection = g_list_prepend (list->selection, child);
973 gtk_widget_ref (child);
974 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
978 case GTK_SELECTION_MULTIPLE:
979 if (child->state == GTK_STATE_NORMAL)
981 gtk_list_item_select (GTK_LIST_ITEM (child));
982 list->selection = g_list_prepend (list->selection, child);
983 gtk_widget_ref (child);
984 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
986 else if (child->state == GTK_STATE_SELECTED)
988 gtk_list_item_deselect (GTK_LIST_ITEM (child));
989 list->selection = g_list_remove (list->selection, child);
990 gtk_widget_unref (child);
991 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
995 case GTK_SELECTION_EXTENDED:
1001 gtk_real_list_unselect_child (GtkList *list,
1004 g_return_if_fail (list != NULL);
1005 g_return_if_fail (GTK_IS_LIST (list));
1006 g_return_if_fail (child != NULL);
1007 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1009 switch (list->selection_mode)
1011 case GTK_SELECTION_SINGLE:
1012 case GTK_SELECTION_MULTIPLE:
1013 case GTK_SELECTION_BROWSE:
1014 if (child->state == GTK_STATE_SELECTED)
1016 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1017 list->selection = g_list_remove (list->selection, child);
1018 gtk_widget_unref (child);
1019 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
1023 case GTK_SELECTION_EXTENDED:
1030 gtk_list_marshal_signal (GtkObject *object,
1035 GtkListSignal rfunc;
1037 rfunc = (GtkListSignal) func;
1039 (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);