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_insert_items (GtkList *list,
194 g_return_if_fail (list != NULL);
195 g_return_if_fail (GTK_IS_LIST (list));
203 widget = tmp_list->data;
204 tmp_list = tmp_list->next;
206 gtk_widget_set_parent (widget, GTK_WIDGET (list));
208 if (GTK_WIDGET_VISIBLE (widget->parent))
210 if (GTK_WIDGET_REALIZED (widget->parent) &&
211 !GTK_WIDGET_REALIZED (widget))
212 gtk_widget_realize (widget);
214 if (GTK_WIDGET_MAPPED (widget->parent) &&
215 !GTK_WIDGET_MAPPED (widget))
216 gtk_widget_map (widget);
220 nchildren = g_list_length (list->children);
221 if ((position < 0) || (position > nchildren))
222 position = nchildren;
224 if (position == nchildren)
228 tmp_list = g_list_last (list->children);
229 tmp_list->next = items;
230 items->prev = tmp_list;
234 list->children = items;
239 tmp_list = g_list_nth (list->children, position);
240 last = g_list_last (items);
243 tmp_list->prev->next = items;
244 last->next = tmp_list;
245 items->prev = tmp_list->prev;
246 tmp_list->prev = last;
248 if (tmp_list == list->children)
249 list->children = items;
252 if (list->children && !list->selection &&
253 (list->selection_mode == GTK_SELECTION_BROWSE))
255 widget = list->children->data;
256 gtk_list_select_child (list, widget);
259 if (GTK_WIDGET_VISIBLE (list))
260 gtk_widget_queue_resize (GTK_WIDGET (list));
264 gtk_list_append_items (GtkList *list,
267 g_return_if_fail (list != NULL);
268 g_return_if_fail (GTK_IS_LIST (list));
270 gtk_list_insert_items (list, items, -1);
274 gtk_list_prepend_items (GtkList *list,
277 g_return_if_fail (list != NULL);
278 g_return_if_fail (GTK_IS_LIST (list));
280 gtk_list_insert_items (list, items, 0);
284 gtk_list_remove_items (GtkList *list,
288 GList *selected_widgets;
291 g_return_if_fail (list != NULL);
292 g_return_if_fail (GTK_IS_LIST (list));
295 selected_widgets = NULL;
300 widget = tmp_list->data;
301 tmp_list = tmp_list->next;
303 if (widget->state == GTK_STATE_SELECTED)
304 selected_widgets = g_list_prepend (selected_widgets, widget);
306 list->children = g_list_remove (list->children, widget);
308 if (GTK_WIDGET_MAPPED (widget))
309 gtk_widget_unmap (widget);
311 gtk_widget_unparent (widget);
314 if (selected_widgets)
316 tmp_list = selected_widgets;
319 widget = tmp_list->data;
320 tmp_list = tmp_list->next;
322 gtk_list_unselect_child (list, widget);
325 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
328 g_list_free (selected_widgets);
330 if (list->children && !list->selection &&
331 (list->selection_mode == GTK_SELECTION_BROWSE))
333 widget = list->children->data;
334 gtk_list_select_child (list, widget);
337 if (GTK_WIDGET_VISIBLE (list))
338 gtk_widget_queue_resize (GTK_WIDGET (list));
342 gtk_list_clear_items (GtkList *list,
351 gint selection_changed;
353 g_return_if_fail (list != NULL);
354 g_return_if_fail (GTK_IS_LIST (list));
356 nchildren = g_list_length (list->children);
360 if ((end < 0) || (end > nchildren))
363 g_return_if_fail (start < end);
365 start_list = g_list_nth (list->children, start);
366 end_list = g_list_nth (list->children, end);
368 if (start_list->prev)
369 start_list->prev->next = end_list;
370 if (end_list && end_list->prev)
371 end_list->prev->next = NULL;
373 end_list->prev = start_list->prev;
374 if (start_list == list->children)
375 list->children = end_list;
377 selection_changed = FALSE;
379 tmp_list = start_list;
383 widget = tmp_list->data;
384 tmp_list = tmp_list->next;
386 if (widget->state == GTK_STATE_SELECTED)
388 selection_changed = TRUE;
389 list->selection = g_list_remove (list->selection, widget);
392 /* list->children = g_list_remove (list->children, widget); */
393 /* gtk_widget_unparent (widget); */
395 gtk_widget_destroy (widget);
398 if (list->children && !list->selection &&
399 (list->selection_mode == GTK_SELECTION_BROWSE))
401 gtk_list_select_child (list, widget);
402 widget = list->children->data;
405 if (selection_changed)
406 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
408 gtk_widget_queue_resize (GTK_WIDGET (list));
413 gtk_list_select_item (GtkList *list,
418 g_return_if_fail (list != NULL);
419 g_return_if_fail (GTK_IS_LIST (list));
421 tmp_list = g_list_nth (list->children, item);
423 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
427 gtk_list_unselect_item (GtkList *list,
432 g_return_if_fail (list != NULL);
433 g_return_if_fail (GTK_IS_LIST (list));
435 tmp_list = g_list_nth (list->children, item);
437 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
441 gtk_list_select_child (GtkList *list,
444 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
448 gtk_list_unselect_child (GtkList *list,
451 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
455 gtk_list_child_position (GtkList *list,
461 g_return_val_if_fail (list != NULL, -1);
462 g_return_val_if_fail (GTK_IS_LIST (list), -1);
463 g_return_val_if_fail (child != NULL, -1);
466 children = list->children;
470 if (child == GTK_WIDGET (children->data))
474 children = children->next;
481 gtk_list_set_selection_mode (GtkList *list,
482 GtkSelectionMode mode)
484 g_return_if_fail (list != NULL);
485 g_return_if_fail (GTK_IS_LIST (list));
487 list->selection_mode = mode;
492 gtk_list_destroy (GtkObject *object)
498 g_return_if_fail (object != NULL);
499 g_return_if_fail (GTK_IS_LIST (object));
501 list = GTK_LIST (object);
503 children = list->children;
506 child = children->data;
507 children = children->next;
509 child->parent = NULL;
510 gtk_object_unref (GTK_OBJECT (child));
511 gtk_widget_destroy (child);
514 g_list_free (list->children);
515 g_list_free (list->selection);
517 if (GTK_OBJECT_CLASS (parent_class)->destroy)
518 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
522 gtk_list_map (GtkWidget *widget)
528 g_return_if_fail (widget != NULL);
529 g_return_if_fail (GTK_IS_LIST (widget));
531 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
532 list = GTK_LIST (widget);
534 gdk_window_show (widget->window);
536 children = list->children;
539 child = children->data;
540 children = children->next;
542 if (GTK_WIDGET_VISIBLE (child) &&
543 !GTK_WIDGET_MAPPED (child))
544 gtk_widget_map (child);
549 gtk_list_unmap (GtkWidget *widget)
551 g_return_if_fail (widget != NULL);
552 g_return_if_fail (GTK_IS_LIST (widget));
554 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
555 gdk_window_hide (widget->window);
559 gtk_list_realize (GtkWidget *widget)
561 GdkWindowAttr attributes;
562 gint attributes_mask;
564 g_return_if_fail (widget != NULL);
565 g_return_if_fail (GTK_IS_LIST (widget));
567 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
569 attributes.window_type = GDK_WINDOW_CHILD;
570 attributes.x = widget->allocation.x;
571 attributes.y = widget->allocation.y;
572 attributes.width = widget->allocation.width;
573 attributes.height = widget->allocation.height;
574 attributes.wclass = GDK_INPUT_OUTPUT;
575 attributes.visual = gtk_widget_get_visual (widget);
576 attributes.colormap = gtk_widget_get_colormap (widget);
577 attributes.event_mask = GDK_EXPOSURE_MASK;
579 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
581 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
582 gdk_window_set_user_data (widget->window, widget);
584 widget->style = gtk_style_attach (widget->style, widget->window);
585 gdk_window_set_background (widget->window, &widget->style->white);
589 gtk_list_draw (GtkWidget *widget,
594 GdkRectangle child_area;
597 g_return_if_fail (widget != NULL);
598 g_return_if_fail (GTK_IS_LIST (widget));
599 g_return_if_fail (area != NULL);
601 if (GTK_WIDGET_DRAWABLE (widget))
603 list = GTK_LIST (widget);
605 children = list->children;
608 child = children->data;
609 children = children->next;
611 if (gtk_widget_intersect (child, area, &child_area))
612 gtk_widget_draw (child, &child_area);
618 gtk_list_expose (GtkWidget *widget,
619 GdkEventExpose *event)
623 GdkEventExpose child_event;
626 g_return_val_if_fail (widget != NULL, FALSE);
627 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
628 g_return_val_if_fail (event != NULL, FALSE);
630 if (GTK_WIDGET_DRAWABLE (widget))
632 list = GTK_LIST (widget);
634 child_event = *event;
636 children = list->children;
639 child = children->data;
640 children = children->next;
642 if (GTK_WIDGET_NO_WINDOW (child) &&
643 gtk_widget_intersect (child, &event->area, &child_event.area))
644 gtk_widget_event (child, (GdkEvent*) &child_event);
652 gtk_list_motion_notify (GtkWidget *widget,
653 GdkEventMotion *event)
655 g_return_val_if_fail (widget != NULL, FALSE);
656 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
657 g_return_val_if_fail (event != NULL, FALSE);
659 g_print ("gtk_list_motion_notify\n");
665 gtk_list_button_press (GtkWidget *widget,
666 GdkEventButton *event)
671 g_return_val_if_fail (widget != NULL, FALSE);
672 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
673 g_return_val_if_fail (event != NULL, FALSE);
675 list = GTK_LIST (widget);
676 item = gtk_get_event_widget ((GdkEvent*) event);
678 while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_list_item_get_type ()))
681 gtk_list_select_child (list, item);
687 gtk_list_button_release (GtkWidget *widget,
688 GdkEventButton *event)
693 g_return_val_if_fail (widget != NULL, FALSE);
694 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
695 g_return_val_if_fail (event != NULL, FALSE);
697 list = GTK_LIST (widget);
698 item = gtk_get_event_widget ((GdkEvent*) event);
704 gtk_list_size_request (GtkWidget *widget,
705 GtkRequisition *requisition)
711 g_return_if_fail (widget != NULL);
712 g_return_if_fail (GTK_IS_LIST (widget));
713 g_return_if_fail (requisition != NULL);
715 list = GTK_LIST (widget);
716 requisition->width = 0;
717 requisition->height = 0;
719 children = list->children;
722 child = children->data;
723 children = children->next;
725 if (GTK_WIDGET_VISIBLE (child))
727 gtk_widget_size_request (child, &child->requisition);
729 requisition->width = MAX (requisition->width, child->requisition.width);
730 requisition->height += child->requisition.height;
734 requisition->width += GTK_CONTAINER (list)->border_width * 2;
735 requisition->height += GTK_CONTAINER (list)->border_width * 2;
737 requisition->width = MAX (requisition->width, 1);
738 requisition->height = MAX (requisition->height, 1);
742 gtk_list_size_allocate (GtkWidget *widget,
743 GtkAllocation *allocation)
747 GtkAllocation child_allocation;
750 g_return_if_fail (widget != NULL);
751 g_return_if_fail (GTK_IS_LIST (widget));
752 g_return_if_fail (allocation != NULL);
754 list = GTK_LIST (widget);
756 widget->allocation = *allocation;
757 if (GTK_WIDGET_REALIZED (widget))
758 gdk_window_move_resize (widget->window,
759 allocation->x, allocation->y,
760 allocation->width, allocation->height);
764 child_allocation.x = GTK_CONTAINER (list)->border_width;
765 child_allocation.y = GTK_CONTAINER (list)->border_width;
766 child_allocation.width = allocation->width - child_allocation.x * 2;
768 children = list->children;
772 child = children->data;
773 children = children->next;
775 if (GTK_WIDGET_VISIBLE (child))
777 child_allocation.height = child->requisition.height;
779 gtk_widget_size_allocate (child, &child_allocation);
781 child_allocation.y += child_allocation.height;
788 gtk_list_add (GtkContainer *container,
793 g_return_if_fail (container != NULL);
794 g_return_if_fail (GTK_IS_LIST (container));
795 g_return_if_fail (widget != NULL);
797 list = GTK_LIST (container);
799 gtk_widget_set_parent (widget, GTK_WIDGET (container));
800 if (GTK_WIDGET_VISIBLE (widget->parent))
802 if (GTK_WIDGET_REALIZED (widget->parent) &&
803 !GTK_WIDGET_REALIZED (widget))
804 gtk_widget_realize (widget);
806 if (GTK_WIDGET_MAPPED (widget->parent) &&
807 !GTK_WIDGET_MAPPED (widget))
808 gtk_widget_map (widget);
811 list->children = g_list_append (list->children, widget);
813 if (!list->selection && (list->selection_mode == GTK_SELECTION_BROWSE))
815 gtk_list_select_child (list, widget);
818 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
819 gtk_widget_queue_resize (widget);
823 gtk_list_remove (GtkContainer *container,
828 g_return_if_fail (container != NULL);
829 g_return_if_fail (GTK_IS_LIST (container));
830 g_return_if_fail (widget != NULL);
831 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
834 item_list = g_list_alloc ();
835 item_list->data = widget;
837 gtk_list_remove_items (GTK_LIST (container), item_list);
839 g_list_free (item_list);
843 gtk_list_foreach (GtkContainer *container,
844 GtkCallback callback,
845 gpointer callback_data)
851 g_return_if_fail (container != NULL);
852 g_return_if_fail (GTK_IS_LIST (container));
853 g_return_if_fail (callback != NULL);
855 list = GTK_LIST (container);
856 children = list->children;
860 child = children->data;
861 children = children->next;
863 (* callback) (child, callback_data);
869 gtk_real_list_select_child (GtkList *list,
876 g_return_if_fail (list != NULL);
877 g_return_if_fail (GTK_IS_LIST (list));
878 g_return_if_fail (child != NULL);
879 g_return_if_fail (GTK_IS_LIST_ITEM (child));
881 switch (list->selection_mode)
883 case GTK_SELECTION_SINGLE:
884 selection = list->selection;
888 tmp_item = selection->data;
890 if (tmp_item != child)
892 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
894 tmp_list = selection;
895 selection = selection->next;
897 list->selection = g_list_remove_link (list->selection, tmp_list);
899 g_list_free (tmp_list);
902 selection = selection->next;
905 if (child->state == GTK_STATE_NORMAL)
907 gtk_list_item_select (GTK_LIST_ITEM (child));
908 list->selection = g_list_prepend (list->selection, child);
910 else if (child->state == GTK_STATE_SELECTED)
912 gtk_list_item_deselect (GTK_LIST_ITEM (child));
913 list->selection = g_list_remove (list->selection, child);
916 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
919 case GTK_SELECTION_BROWSE:
920 selection = list->selection;
924 tmp_item = selection->data;
926 if (tmp_item != child)
928 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
930 tmp_list = selection;
931 selection = selection->next;
933 list->selection = g_list_remove_link (list->selection, tmp_list);
935 g_list_free (tmp_list);
938 selection = selection->next;
941 if (child->state == GTK_STATE_NORMAL)
943 gtk_list_item_select (GTK_LIST_ITEM (child));
944 list->selection = g_list_prepend (list->selection, child);
945 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
949 case GTK_SELECTION_MULTIPLE:
950 if (child->state == GTK_STATE_NORMAL)
952 gtk_list_item_select (GTK_LIST_ITEM (child));
953 list->selection = g_list_prepend (list->selection, child);
954 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
956 else if (child->state == GTK_STATE_SELECTED)
958 gtk_list_item_deselect (GTK_LIST_ITEM (child));
959 list->selection = g_list_remove (list->selection, child);
960 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
964 case GTK_SELECTION_EXTENDED:
970 gtk_real_list_unselect_child (GtkList *list,
973 g_return_if_fail (list != NULL);
974 g_return_if_fail (GTK_IS_LIST (list));
975 g_return_if_fail (child != NULL);
976 g_return_if_fail (GTK_IS_LIST_ITEM (child));
978 switch (list->selection_mode)
980 case GTK_SELECTION_SINGLE:
981 case GTK_SELECTION_MULTIPLE:
982 case GTK_SELECTION_BROWSE:
983 if (child->state == GTK_STATE_SELECTED)
985 gtk_list_item_deselect (GTK_LIST_ITEM (child));
986 list->selection = g_list_remove (list->selection, child);
987 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
991 case GTK_SELECTION_EXTENDED:
998 gtk_list_marshal_signal (GtkObject *object,
1003 GtkListSignal rfunc;
1005 rfunc = (GtkListSignal) func;
1007 (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);