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,
97 list_type = gtk_type_unique (gtk_container_get_type (), &list_info);
104 gtk_list_class_init (GtkListClass *class)
106 GtkObjectClass *object_class;
107 GtkWidgetClass *widget_class;
108 GtkContainerClass *container_class;
110 object_class = (GtkObjectClass*) class;
111 widget_class = (GtkWidgetClass*) class;
112 container_class = (GtkContainerClass*) class;
114 parent_class = gtk_type_class (gtk_container_get_type ());
116 list_signals[SELECTION_CHANGED] =
117 gtk_signal_new ("selection_changed",
120 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
121 gtk_signal_default_marshaller,
123 list_signals[SELECT_CHILD] =
124 gtk_signal_new ("select_child",
127 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
128 gtk_list_marshal_signal,
131 list_signals[UNSELECT_CHILD] =
132 gtk_signal_new ("unselect_child",
135 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
136 gtk_list_marshal_signal,
140 gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
142 object_class->destroy = gtk_list_destroy;
144 widget_class->map = gtk_list_map;
145 widget_class->unmap = gtk_list_unmap;
146 widget_class->realize = gtk_list_realize;
147 widget_class->draw = gtk_list_draw;
148 widget_class->expose_event = gtk_list_expose;
149 widget_class->motion_notify_event = gtk_list_motion_notify;
150 widget_class->button_press_event = gtk_list_button_press;
151 widget_class->button_release_event = gtk_list_button_release;
152 widget_class->size_request = gtk_list_size_request;
153 widget_class->size_allocate = gtk_list_size_allocate;
155 container_class->add = gtk_list_add;
156 container_class->remove = gtk_list_remove;
157 container_class->foreach = gtk_list_foreach;
159 class->selection_changed = NULL;
160 class->select_child = gtk_real_list_select_child;
161 class->unselect_child = gtk_real_list_unselect_child;
165 gtk_list_init (GtkList *list)
167 list->children = NULL;
168 list->selection = NULL;
170 list->selection_start_pos = 0;
171 list->selection_end_pos = 0;
172 list->selection_mode = GTK_SELECTION_SINGLE;
173 list->scroll_direction = 0;
174 list->have_grab = FALSE;
180 return GTK_WIDGET (gtk_type_new (gtk_list_get_type ()));
184 gtk_list_insert_items (GtkList *list,
193 g_return_if_fail (list != NULL);
194 g_return_if_fail (GTK_IS_LIST (list));
202 widget = tmp_list->data;
203 tmp_list = tmp_list->next;
205 gtk_widget_set_parent (widget, GTK_WIDGET (list));
207 if (GTK_WIDGET_VISIBLE (widget->parent))
209 if (GTK_WIDGET_REALIZED (widget->parent) &&
210 !GTK_WIDGET_REALIZED (widget))
211 gtk_widget_realize (widget);
213 if (GTK_WIDGET_MAPPED (widget->parent) &&
214 !GTK_WIDGET_MAPPED (widget))
215 gtk_widget_map (widget);
219 nchildren = g_list_length (list->children);
220 if ((position < 0) || (position > nchildren))
221 position = nchildren;
223 if (position == nchildren)
227 tmp_list = g_list_last (list->children);
228 tmp_list->next = items;
229 items->prev = tmp_list;
233 list->children = items;
238 tmp_list = g_list_nth (list->children, position);
239 last = g_list_last (items);
242 tmp_list->prev->next = items;
243 last->next = tmp_list;
244 items->prev = tmp_list->prev;
245 tmp_list->prev = last;
247 if (tmp_list == list->children)
248 list->children = items;
251 if (list->children && !list->selection &&
252 (list->selection_mode == GTK_SELECTION_BROWSE))
254 widget = list->children->data;
255 gtk_list_select_child (list, widget);
258 if (GTK_WIDGET_VISIBLE (list))
259 gtk_widget_queue_resize (GTK_WIDGET (list));
263 gtk_list_append_items (GtkList *list,
266 g_return_if_fail (list != NULL);
267 g_return_if_fail (GTK_IS_LIST (list));
269 gtk_list_insert_items (list, items, -1);
273 gtk_list_prepend_items (GtkList *list,
276 g_return_if_fail (list != NULL);
277 g_return_if_fail (GTK_IS_LIST (list));
279 gtk_list_insert_items (list, items, 0);
283 gtk_list_remove_items (GtkList *list,
287 GList *selected_widgets;
290 g_return_if_fail (list != NULL);
291 g_return_if_fail (GTK_IS_LIST (list));
294 selected_widgets = NULL;
299 widget = tmp_list->data;
300 tmp_list = tmp_list->next;
302 if (widget->state == GTK_STATE_SELECTED)
303 selected_widgets = g_list_prepend (selected_widgets, widget);
305 list->children = g_list_remove (list->children, widget);
307 if (GTK_WIDGET_MAPPED (widget))
308 gtk_widget_unmap (widget);
310 gtk_widget_unparent (widget);
313 if (selected_widgets)
315 tmp_list = selected_widgets;
318 widget = tmp_list->data;
319 tmp_list = tmp_list->next;
321 gtk_list_unselect_child (list, widget);
324 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
327 g_list_free (selected_widgets);
329 if (list->children && !list->selection &&
330 (list->selection_mode == GTK_SELECTION_BROWSE))
332 widget = list->children->data;
333 gtk_list_select_child (list, widget);
336 if (GTK_WIDGET_VISIBLE (list))
337 gtk_widget_queue_resize (GTK_WIDGET (list));
341 gtk_list_clear_items (GtkList *list,
350 gint selection_changed;
352 g_return_if_fail (list != NULL);
353 g_return_if_fail (GTK_IS_LIST (list));
355 nchildren = g_list_length (list->children);
359 if ((end < 0) || (end > nchildren))
362 g_return_if_fail (start < end);
364 start_list = g_list_nth (list->children, start);
365 end_list = g_list_nth (list->children, end);
367 if (start_list->prev)
368 start_list->prev->next = end_list;
369 if (end_list && end_list->prev)
370 end_list->prev->next = NULL;
372 end_list->prev = start_list->prev;
373 if (start_list == list->children)
374 list->children = end_list;
376 selection_changed = FALSE;
378 tmp_list = start_list;
382 widget = tmp_list->data;
383 tmp_list = tmp_list->next;
385 if (widget->state == GTK_STATE_SELECTED)
387 selection_changed = TRUE;
388 list->selection = g_list_remove (list->selection, widget);
391 /* list->children = g_list_remove (list->children, widget); */
392 /* gtk_widget_unparent (widget); */
394 gtk_widget_destroy (widget);
397 if (list->children && !list->selection &&
398 (list->selection_mode == GTK_SELECTION_BROWSE))
400 gtk_list_select_child (list, widget);
401 widget = list->children->data;
404 if (selection_changed)
405 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
407 gtk_widget_queue_resize (GTK_WIDGET (list));
412 gtk_list_select_item (GtkList *list,
417 g_return_if_fail (list != NULL);
418 g_return_if_fail (GTK_IS_LIST (list));
420 tmp_list = g_list_nth (list->children, item);
422 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
426 gtk_list_unselect_item (GtkList *list,
431 g_return_if_fail (list != NULL);
432 g_return_if_fail (GTK_IS_LIST (list));
434 tmp_list = g_list_nth (list->children, item);
436 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
440 gtk_list_select_child (GtkList *list,
443 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
447 gtk_list_unselect_child (GtkList *list,
450 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
454 gtk_list_child_position (GtkList *list,
460 g_return_val_if_fail (list != NULL, -1);
461 g_return_val_if_fail (GTK_IS_LIST (list), -1);
462 g_return_val_if_fail (child != NULL, -1);
465 children = list->children;
469 if (child == GTK_WIDGET (children->data))
473 children = children->next;
480 gtk_list_set_selection_mode (GtkList *list,
481 GtkSelectionMode mode)
483 g_return_if_fail (list != NULL);
484 g_return_if_fail (GTK_IS_LIST (list));
486 list->selection_mode = mode;
491 gtk_list_destroy (GtkObject *object)
497 g_return_if_fail (object != NULL);
498 g_return_if_fail (GTK_IS_LIST (object));
500 list = GTK_LIST (object);
502 children = list->children;
505 child = children->data;
506 children = children->next;
508 child->parent = NULL;
509 gtk_object_unref (GTK_OBJECT (child));
510 gtk_widget_destroy (child);
513 g_list_free (list->children);
514 g_list_free (list->selection);
516 if (GTK_OBJECT_CLASS (parent_class)->destroy)
517 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
521 gtk_list_map (GtkWidget *widget)
527 g_return_if_fail (widget != NULL);
528 g_return_if_fail (GTK_IS_LIST (widget));
530 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
531 list = GTK_LIST (widget);
533 gdk_window_show (widget->window);
535 children = list->children;
538 child = children->data;
539 children = children->next;
541 if (GTK_WIDGET_VISIBLE (child) &&
542 !GTK_WIDGET_MAPPED (child))
543 gtk_widget_map (child);
548 gtk_list_unmap (GtkWidget *widget)
550 g_return_if_fail (widget != NULL);
551 g_return_if_fail (GTK_IS_LIST (widget));
553 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
554 gdk_window_hide (widget->window);
558 gtk_list_realize (GtkWidget *widget)
560 GdkWindowAttr attributes;
561 gint attributes_mask;
563 g_return_if_fail (widget != NULL);
564 g_return_if_fail (GTK_IS_LIST (widget));
566 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
568 attributes.window_type = GDK_WINDOW_CHILD;
569 attributes.x = widget->allocation.x;
570 attributes.y = widget->allocation.y;
571 attributes.width = widget->allocation.width;
572 attributes.height = widget->allocation.height;
573 attributes.wclass = GDK_INPUT_OUTPUT;
574 attributes.visual = gtk_widget_get_visual (widget);
575 attributes.colormap = gtk_widget_get_colormap (widget);
576 attributes.event_mask = GDK_EXPOSURE_MASK;
578 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
580 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
581 gdk_window_set_user_data (widget->window, widget);
583 widget->style = gtk_style_attach (widget->style, widget->window);
584 gdk_window_set_background (widget->window, &widget->style->white);
588 gtk_list_draw (GtkWidget *widget,
593 GdkRectangle child_area;
596 g_return_if_fail (widget != NULL);
597 g_return_if_fail (GTK_IS_LIST (widget));
598 g_return_if_fail (area != NULL);
600 if (GTK_WIDGET_DRAWABLE (widget))
602 list = GTK_LIST (widget);
604 children = list->children;
607 child = children->data;
608 children = children->next;
610 if (gtk_widget_intersect (child, area, &child_area))
611 gtk_widget_draw (child, &child_area);
617 gtk_list_expose (GtkWidget *widget,
618 GdkEventExpose *event)
622 GdkEventExpose child_event;
625 g_return_val_if_fail (widget != NULL, FALSE);
626 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
627 g_return_val_if_fail (event != NULL, FALSE);
629 if (GTK_WIDGET_DRAWABLE (widget))
631 list = GTK_LIST (widget);
633 child_event = *event;
635 children = list->children;
638 child = children->data;
639 children = children->next;
641 if (GTK_WIDGET_NO_WINDOW (child) &&
642 gtk_widget_intersect (child, &event->area, &child_event.area))
643 gtk_widget_event (child, (GdkEvent*) &child_event);
651 gtk_list_motion_notify (GtkWidget *widget,
652 GdkEventMotion *event)
654 g_return_val_if_fail (widget != NULL, FALSE);
655 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
656 g_return_val_if_fail (event != NULL, FALSE);
658 g_print ("gtk_list_motion_notify\n");
664 gtk_list_button_press (GtkWidget *widget,
665 GdkEventButton *event)
670 g_return_val_if_fail (widget != NULL, FALSE);
671 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
672 g_return_val_if_fail (event != NULL, FALSE);
674 list = GTK_LIST (widget);
675 item = gtk_get_event_widget ((GdkEvent*) event);
677 while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_list_item_get_type ()))
680 gtk_list_select_child (list, item);
686 gtk_list_button_release (GtkWidget *widget,
687 GdkEventButton *event)
692 g_return_val_if_fail (widget != NULL, FALSE);
693 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
694 g_return_val_if_fail (event != NULL, FALSE);
696 list = GTK_LIST (widget);
697 item = gtk_get_event_widget ((GdkEvent*) event);
703 gtk_list_size_request (GtkWidget *widget,
704 GtkRequisition *requisition)
710 g_return_if_fail (widget != NULL);
711 g_return_if_fail (GTK_IS_LIST (widget));
712 g_return_if_fail (requisition != NULL);
714 list = GTK_LIST (widget);
715 requisition->width = 0;
716 requisition->height = 0;
718 children = list->children;
721 child = children->data;
722 children = children->next;
724 if (GTK_WIDGET_VISIBLE (child))
726 gtk_widget_size_request (child, &child->requisition);
728 requisition->width = MAX (requisition->width, child->requisition.width);
729 requisition->height += child->requisition.height;
733 requisition->width += GTK_CONTAINER (list)->border_width * 2;
734 requisition->height += GTK_CONTAINER (list)->border_width * 2;
736 requisition->width = MAX (requisition->width, 1);
737 requisition->height = MAX (requisition->height, 1);
741 gtk_list_size_allocate (GtkWidget *widget,
742 GtkAllocation *allocation)
746 GtkAllocation child_allocation;
749 g_return_if_fail (widget != NULL);
750 g_return_if_fail (GTK_IS_LIST (widget));
751 g_return_if_fail (allocation != NULL);
753 list = GTK_LIST (widget);
755 widget->allocation = *allocation;
756 if (GTK_WIDGET_REALIZED (widget))
757 gdk_window_move_resize (widget->window,
758 allocation->x, allocation->y,
759 allocation->width, allocation->height);
763 child_allocation.x = GTK_CONTAINER (list)->border_width;
764 child_allocation.y = GTK_CONTAINER (list)->border_width;
765 child_allocation.width = allocation->width - child_allocation.x * 2;
767 children = list->children;
771 child = children->data;
772 children = children->next;
774 if (GTK_WIDGET_VISIBLE (child))
776 child_allocation.height = child->requisition.height;
778 gtk_widget_size_allocate (child, &child_allocation);
780 child_allocation.y += child_allocation.height;
787 gtk_list_add (GtkContainer *container,
792 g_return_if_fail (container != NULL);
793 g_return_if_fail (GTK_IS_LIST (container));
794 g_return_if_fail (widget != NULL);
796 list = GTK_LIST (container);
798 gtk_widget_set_parent (widget, GTK_WIDGET (container));
799 if (GTK_WIDGET_VISIBLE (widget->parent))
801 if (GTK_WIDGET_REALIZED (widget->parent) &&
802 !GTK_WIDGET_REALIZED (widget))
803 gtk_widget_realize (widget);
805 if (GTK_WIDGET_MAPPED (widget->parent) &&
806 !GTK_WIDGET_MAPPED (widget))
807 gtk_widget_map (widget);
810 list->children = g_list_append (list->children, widget);
812 if (!list->selection && (list->selection_mode == GTK_SELECTION_BROWSE))
814 gtk_list_select_child (list, widget);
817 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
818 gtk_widget_queue_resize (widget);
822 gtk_list_remove (GtkContainer *container,
827 g_return_if_fail (container != NULL);
828 g_return_if_fail (GTK_IS_LIST (container));
829 g_return_if_fail (widget != NULL);
830 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
833 item_list = g_list_alloc ();
834 item_list->data = widget;
836 gtk_list_remove_items (GTK_LIST (container), item_list);
838 g_list_free (item_list);
842 gtk_list_foreach (GtkContainer *container,
843 GtkCallback callback,
844 gpointer callback_data)
850 g_return_if_fail (container != NULL);
851 g_return_if_fail (GTK_IS_LIST (container));
852 g_return_if_fail (callback != NULL);
854 list = GTK_LIST (container);
855 children = list->children;
859 child = children->data;
860 children = children->next;
862 (* callback) (child, callback_data);
868 gtk_real_list_select_child (GtkList *list,
875 g_return_if_fail (list != NULL);
876 g_return_if_fail (GTK_IS_LIST (list));
877 g_return_if_fail (child != NULL);
878 g_return_if_fail (GTK_IS_LIST_ITEM (child));
880 switch (list->selection_mode)
882 case GTK_SELECTION_SINGLE:
883 selection = list->selection;
887 tmp_item = selection->data;
889 if (tmp_item != child)
891 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
893 tmp_list = selection;
894 selection = selection->next;
896 list->selection = g_list_remove_link (list->selection, tmp_list);
898 g_list_free (tmp_list);
901 selection = selection->next;
904 if (child->state == GTK_STATE_NORMAL)
906 gtk_list_item_select (GTK_LIST_ITEM (child));
907 list->selection = g_list_prepend (list->selection, child);
909 else if (child->state == GTK_STATE_SELECTED)
911 gtk_list_item_deselect (GTK_LIST_ITEM (child));
912 list->selection = g_list_remove (list->selection, child);
915 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
918 case GTK_SELECTION_BROWSE:
919 selection = list->selection;
923 tmp_item = selection->data;
925 if (tmp_item != child)
927 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item));
929 tmp_list = selection;
930 selection = selection->next;
932 list->selection = g_list_remove_link (list->selection, tmp_list);
934 g_list_free (tmp_list);
937 selection = selection->next;
940 if (child->state == GTK_STATE_NORMAL)
942 gtk_list_item_select (GTK_LIST_ITEM (child));
943 list->selection = g_list_prepend (list->selection, child);
944 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
948 case GTK_SELECTION_MULTIPLE:
949 if (child->state == GTK_STATE_NORMAL)
951 gtk_list_item_select (GTK_LIST_ITEM (child));
952 list->selection = g_list_prepend (list->selection, child);
953 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
955 else if (child->state == GTK_STATE_SELECTED)
957 gtk_list_item_deselect (GTK_LIST_ITEM (child));
958 list->selection = g_list_remove (list->selection, child);
959 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
963 case GTK_SELECTION_EXTENDED:
969 gtk_real_list_unselect_child (GtkList *list,
972 g_return_if_fail (list != NULL);
973 g_return_if_fail (GTK_IS_LIST (list));
974 g_return_if_fail (child != NULL);
975 g_return_if_fail (GTK_IS_LIST_ITEM (child));
977 switch (list->selection_mode)
979 case GTK_SELECTION_SINGLE:
980 case GTK_SELECTION_MULTIPLE:
981 case GTK_SELECTION_BROWSE:
982 if (child->state == GTK_STATE_SELECTED)
984 gtk_list_item_deselect (GTK_LIST_ITEM (child));
985 list->selection = g_list_remove (list->selection, child);
986 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
990 case GTK_SELECTION_EXTENDED:
997 gtk_list_marshal_signal (GtkObject *object,
1002 GtkListSignal rfunc;
1004 rfunc = (GtkListSignal) func;
1006 (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);