]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeitem.c
3508516a79e97fbc92418439d36254272a02b6dc
[~andy/gtk] / gtk / gtktreeitem.c
1 /* GTK - The GTK+ Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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.
8  *
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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #undef GTK_DISABLE_DEPRECATED
28
29 #include "config.h"
30
31 #include "gtklabel.h"
32 #include "gtkeventbox.h"
33 #include "gtkpixmap.h"
34 #include "gtkmain.h"
35 #include "gtkmarshalers.h"
36 #include "gtksignal.h"
37 #define GTK_ENABLE_BROKEN
38 #include "gtktree.h"
39 #include "gtktreeitem.h"
40 #include "gtkintl.h"
41
42 #define GTK_DISABLE_DEPRECATED
43 #include "gtkalias.h"
44
45 #include "tree_plus.xpm"
46 #include "tree_minus.xpm"
47
48 #define DEFAULT_DELTA 9
49
50 enum {
51   COLLAPSE_TREE,
52   EXPAND_TREE,
53   LAST_SIGNAL
54 };
55
56 typedef struct _GtkTreePixmaps GtkTreePixmaps;
57
58 struct _GtkTreePixmaps {
59   gint refcount;
60   GdkColormap *colormap;
61   
62   GdkPixmap *pixmap_plus;
63   GdkPixmap *pixmap_minus;
64   GdkBitmap *mask_plus;
65   GdkBitmap *mask_minus;
66 };
67
68 static GList *pixmaps = NULL;
69
70 static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
71 static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
72 static void gtk_tree_item_realize       (GtkWidget        *widget);
73 static void gtk_tree_item_size_request  (GtkWidget        *widget,
74                                          GtkRequisition   *requisition);
75 static void gtk_tree_item_size_allocate (GtkWidget        *widget,
76                                          GtkAllocation    *allocation);
77 static void gtk_tree_item_paint         (GtkWidget        *widget,
78                                          GdkRectangle     *area);
79 static gint gtk_tree_item_button_press  (GtkWidget        *widget,
80                                          GdkEventButton   *event);
81 static gint gtk_tree_item_expose        (GtkWidget        *widget,
82                                          GdkEventExpose   *event);
83 static void gtk_tree_item_forall        (GtkContainer    *container,
84                                          gboolean         include_internals,
85                                          GtkCallback      callback,
86                                          gpointer         callback_data);
87
88 static void gtk_real_tree_item_select   (GtkItem          *item);
89 static void gtk_real_tree_item_deselect (GtkItem          *item);
90 static void gtk_real_tree_item_toggle   (GtkItem          *item);
91 static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
92 static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
93 static void gtk_tree_item_destroy        (GtkObject *object);
94 static gint gtk_tree_item_subtree_button_click (GtkWidget *widget);
95 static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
96
97 static void gtk_tree_item_map(GtkWidget*);
98 static void gtk_tree_item_unmap(GtkWidget*);
99
100 static void gtk_tree_item_add_pixmaps    (GtkTreeItem       *tree_item);
101 static void gtk_tree_item_remove_pixmaps (GtkTreeItem       *tree_item);
102
103 static GtkItemClass *parent_class = NULL;
104 static guint tree_item_signals[LAST_SIGNAL] = { 0 };
105
106 GtkType
107 gtk_tree_item_get_type (void)
108 {
109   static GtkType tree_item_type = 0;
110
111   if (!tree_item_type)
112     {
113       static const GtkTypeInfo tree_item_info =
114       {
115         "GtkTreeItem",
116         sizeof (GtkTreeItem),
117         sizeof (GtkTreeItemClass),
118         (GtkClassInitFunc) gtk_tree_item_class_init,
119         (GtkObjectInitFunc) gtk_tree_item_init,
120         /* reserved_1 */ NULL,
121         /* reserved_2 */ NULL,
122         (GtkClassInitFunc) NULL,
123       };
124
125       I_("GtkTreeItem");
126       tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info);
127     }
128
129   return tree_item_type;
130 }
131
132 static void
133 gtk_tree_item_class_init (GtkTreeItemClass *class)
134 {
135   GtkObjectClass *object_class;
136   GtkWidgetClass *widget_class;
137   GtkContainerClass *container_class;
138   GtkItemClass *item_class;
139
140   parent_class = gtk_type_class (GTK_TYPE_ITEM);
141   
142   object_class = (GtkObjectClass*) class;
143   widget_class = (GtkWidgetClass*) class;
144   item_class = (GtkItemClass*) class;
145   container_class = (GtkContainerClass*) class;
146
147   object_class->destroy = gtk_tree_item_destroy;
148
149   widget_class->realize = gtk_tree_item_realize;
150   widget_class->size_request = gtk_tree_item_size_request;
151   widget_class->size_allocate = gtk_tree_item_size_allocate;
152   widget_class->button_press_event = gtk_tree_item_button_press;
153   widget_class->expose_event = gtk_tree_item_expose;
154   widget_class->map = gtk_tree_item_map;
155   widget_class->unmap = gtk_tree_item_unmap;
156
157   container_class->forall = gtk_tree_item_forall;
158
159   item_class->select = gtk_real_tree_item_select;
160   item_class->deselect = gtk_real_tree_item_deselect;
161   item_class->toggle = gtk_real_tree_item_toggle;
162
163   class->expand = gtk_real_tree_item_expand;
164   class->collapse = gtk_real_tree_item_collapse;
165
166   tree_item_signals[EXPAND_TREE] =
167     gtk_signal_new (I_("expand"),
168                     GTK_RUN_FIRST,
169                     GTK_CLASS_TYPE (object_class),
170                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, expand),
171                     _gtk_marshal_VOID__VOID,
172                     GTK_TYPE_NONE, 0);
173   tree_item_signals[COLLAPSE_TREE] =
174     gtk_signal_new (I_("collapse"),
175                     GTK_RUN_FIRST,
176                     GTK_CLASS_TYPE (object_class),
177                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, collapse),
178                     _gtk_marshal_VOID__VOID,
179                     GTK_TYPE_NONE, 0);
180 }
181
182 /* callback for event box mouse event */
183 static gint
184 gtk_tree_item_subtree_button_click (GtkWidget *widget)
185 {
186   GtkTreeItem* item;
187   
188   g_return_val_if_fail (GTK_IS_EVENT_BOX (widget), FALSE);
189   
190   item = (GtkTreeItem*) gtk_object_get_user_data (GTK_OBJECT (widget));
191   if (!GTK_WIDGET_IS_SENSITIVE (item))
192     return FALSE;
193   
194   if (item->expanded)
195     gtk_tree_item_collapse (item);
196   else
197     gtk_tree_item_expand (item);
198
199   return TRUE;
200 }
201
202 /* callback for event box state changed */
203 static void
204 gtk_tree_item_subtree_button_changed_state (GtkWidget *widget)
205 {
206   g_return_if_fail (GTK_IS_EVENT_BOX (widget));
207   
208   if (GTK_WIDGET_VISIBLE (widget))
209     {
210       
211       if (widget->state == GTK_STATE_NORMAL)
212         gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
213       else
214         gdk_window_set_background (widget->window, &widget->style->bg[widget->state]);
215       
216       if (GTK_WIDGET_DRAWABLE (widget))
217         gdk_window_clear_area (widget->window, 0, 0, 
218                                widget->allocation.width, widget->allocation.height);
219     }
220 }
221
222 static void
223 gtk_tree_item_init (GtkTreeItem *tree_item)
224 {
225   GtkWidget *eventbox, *pixmapwid;
226
227   tree_item->expanded = FALSE;
228   tree_item->subtree = NULL;
229   GTK_WIDGET_SET_FLAGS (tree_item, GTK_CAN_FOCUS);
230   
231   /* create an event box containing one pixmaps */
232   eventbox = gtk_event_box_new();
233   gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK);
234   gtk_signal_connect(GTK_OBJECT(eventbox), "state_changed",
235                      (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
236                      (gpointer)NULL);
237   gtk_signal_connect(GTK_OBJECT(eventbox), "realize",
238                      (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
239                      (gpointer)NULL);
240   gtk_signal_connect(GTK_OBJECT(eventbox), "button_press_event",
241                      (GtkSignalFunc)gtk_tree_item_subtree_button_click,
242                      (gpointer)NULL);
243   gtk_object_set_user_data(GTK_OBJECT(eventbox), tree_item);
244   tree_item->pixmaps_box = eventbox;
245
246   /* create pixmap for button '+' */
247   pixmapwid = gtk_type_new (gtk_pixmap_get_type ());
248   if (!tree_item->expanded) 
249     gtk_container_add (GTK_CONTAINER (eventbox), pixmapwid);
250   gtk_widget_show (pixmapwid);
251   tree_item->plus_pix_widget = pixmapwid;
252   g_object_ref_sink (tree_item->plus_pix_widget);
253   
254   /* create pixmap for button '-' */
255   pixmapwid = gtk_type_new (gtk_pixmap_get_type ());
256   if (tree_item->expanded) 
257     gtk_container_add (GTK_CONTAINER (eventbox), pixmapwid);
258   gtk_widget_show (pixmapwid);
259   tree_item->minus_pix_widget = pixmapwid;
260   g_object_ref_sink (tree_item->minus_pix_widget);
261   
262   gtk_widget_set_parent (eventbox, GTK_WIDGET (tree_item));
263 }
264
265
266 GtkWidget*
267 gtk_tree_item_new (void)
268 {
269   GtkWidget *tree_item;
270
271   tree_item = GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ()));
272
273   return tree_item;
274 }
275
276 GtkWidget*
277 gtk_tree_item_new_with_label (const gchar *label)
278 {
279   GtkWidget *tree_item;
280   GtkWidget *label_widget;
281
282   tree_item = gtk_tree_item_new ();
283   label_widget = gtk_label_new (label);
284   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
285
286   gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
287   gtk_widget_show (label_widget);
288
289
290   return tree_item;
291 }
292
293 void
294 gtk_tree_item_set_subtree (GtkTreeItem *tree_item,
295                            GtkWidget   *subtree)
296 {
297   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
298   g_return_if_fail (GTK_IS_TREE (subtree));
299
300   if (tree_item->subtree)
301     {
302       g_warning("there is already a subtree for this tree item\n");
303       return;
304     }
305
306   tree_item->subtree = subtree; 
307   GTK_TREE (subtree)->tree_owner = GTK_WIDGET (tree_item);
308
309   /* show subtree button */
310   if (tree_item->pixmaps_box)
311     gtk_widget_show (tree_item->pixmaps_box);
312
313   if (tree_item->expanded)
314     gtk_widget_show (subtree);
315   else
316     gtk_widget_hide (subtree);
317
318   gtk_widget_set_parent (subtree, GTK_WIDGET (tree_item)->parent);
319 }
320
321 void
322 gtk_tree_item_select (GtkTreeItem *tree_item)
323 {
324   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
325
326   gtk_item_select (GTK_ITEM (tree_item));
327 }
328
329 void
330 gtk_tree_item_deselect (GtkTreeItem *tree_item)
331 {
332   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
333
334   gtk_item_deselect (GTK_ITEM (tree_item));
335 }
336
337 void
338 gtk_tree_item_expand (GtkTreeItem *tree_item)
339 {
340   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
341
342   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[EXPAND_TREE], NULL);
343 }
344
345 void
346 gtk_tree_item_collapse (GtkTreeItem *tree_item)
347 {
348   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
349
350   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[COLLAPSE_TREE], NULL);
351 }
352
353 static void
354 gtk_tree_item_add_pixmaps (GtkTreeItem *tree_item)
355 {
356   GList *tmp_list;
357   GdkColormap *colormap;
358   GtkTreePixmaps *pixmap_node = NULL;
359
360   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
361
362   if (tree_item->pixmaps)
363     return;
364
365   colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_item));
366
367   tmp_list = pixmaps;
368   while (tmp_list)
369     {
370       pixmap_node = (GtkTreePixmaps *)tmp_list->data;
371
372       if (pixmap_node->colormap == colormap)
373         break;
374       
375       tmp_list = tmp_list->next;
376     }
377
378   if (tmp_list)
379     {
380       pixmap_node->refcount++;
381       tree_item->pixmaps = tmp_list;
382     }
383   else
384     {
385       pixmap_node = g_new (GtkTreePixmaps, 1);
386
387       pixmap_node->colormap = colormap;
388       g_object_ref (colormap);
389
390       pixmap_node->refcount = 1;
391
392       /* create pixmaps for plus icon */
393       pixmap_node->pixmap_plus = 
394         gdk_pixmap_create_from_xpm_d (GTK_WIDGET (tree_item)->window,
395                                       &pixmap_node->mask_plus,
396                                       NULL,
397                                       (gchar **)tree_plus);
398       
399       /* create pixmaps for minus icon */
400       pixmap_node->pixmap_minus = 
401         gdk_pixmap_create_from_xpm_d (GTK_WIDGET (tree_item)->window,
402                                       &pixmap_node->mask_minus,
403                                       NULL,
404                                       (gchar **)tree_minus);
405
406       tree_item->pixmaps = pixmaps = g_list_prepend (pixmaps, pixmap_node);
407     }
408   
409   gtk_pixmap_set (GTK_PIXMAP (tree_item->plus_pix_widget), 
410                   pixmap_node->pixmap_plus, pixmap_node->mask_plus);
411   gtk_pixmap_set (GTK_PIXMAP (tree_item->minus_pix_widget), 
412                   pixmap_node->pixmap_minus, pixmap_node->mask_minus);
413 }
414
415 static void
416 gtk_tree_item_remove_pixmaps (GtkTreeItem *tree_item)
417 {
418   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
419
420   if (tree_item->pixmaps)
421     {
422       GtkTreePixmaps *pixmap_node = (GtkTreePixmaps *)tree_item->pixmaps->data;
423       
424       g_assert (pixmap_node->refcount > 0);
425       
426       if (--pixmap_node->refcount == 0)
427         {
428           g_object_unref (pixmap_node->colormap);
429           g_object_unref (pixmap_node->pixmap_plus);
430           g_object_unref (pixmap_node->mask_plus);
431           g_object_unref (pixmap_node->pixmap_minus);
432           g_object_unref (pixmap_node->mask_minus);
433           
434           pixmaps = g_list_remove_link (pixmaps, tree_item->pixmaps);
435           g_list_free_1 (tree_item->pixmaps);
436           g_free (pixmap_node);
437         }
438
439       tree_item->pixmaps = NULL;
440     }
441 }
442
443 static void
444 gtk_tree_item_realize (GtkWidget *widget)
445 {
446   if (GTK_WIDGET_CLASS (parent_class)->realize)
447     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
448   
449   gdk_window_set_background (widget->window, 
450                              &widget->style->base[GTK_STATE_NORMAL]);
451
452   gtk_tree_item_add_pixmaps (GTK_TREE_ITEM (widget));
453 }
454
455 static void
456 gtk_tree_item_size_request (GtkWidget      *widget,
457                             GtkRequisition *requisition)
458 {
459   GtkBin *bin = GTK_BIN (widget);
460   GtkTreeItem *item = GTK_TREE_ITEM (widget);
461   GtkRequisition child_requisition;
462
463   requisition->width = (GTK_CONTAINER (widget)->border_width +
464                         widget->style->xthickness) * 2;
465   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
466
467   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
468     {
469       GtkRequisition pix_requisition;
470       
471       gtk_widget_size_request (bin->child, &child_requisition);
472
473       requisition->width += child_requisition.width;
474
475       gtk_widget_size_request (item->pixmaps_box, 
476                                &pix_requisition);
477       requisition->width += pix_requisition.width + DEFAULT_DELTA + 
478         GTK_TREE (widget->parent)->current_indent;
479
480       requisition->height += MAX (child_requisition.height,
481                                   pix_requisition.height);
482     }
483 }
484
485 static void
486 gtk_tree_item_size_allocate (GtkWidget     *widget,
487                              GtkAllocation *allocation)
488 {
489   GtkBin *bin = GTK_BIN (widget);
490   GtkTreeItem *item = GTK_TREE_ITEM (widget);
491   GtkAllocation child_allocation;
492   gint border_width;
493   int temp;
494
495   widget->allocation = *allocation;
496   if (GTK_WIDGET_REALIZED (widget))
497     gdk_window_move_resize (widget->window,
498                             allocation->x, allocation->y,
499                             allocation->width, allocation->height);
500
501   if (bin->child)
502     {
503       border_width = (GTK_CONTAINER (widget)->border_width +
504                       widget->style->xthickness);
505
506       child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
507       child_allocation.y = GTK_CONTAINER (widget)->border_width;
508
509       child_allocation.width = item->pixmaps_box->requisition.width;
510       child_allocation.height = item->pixmaps_box->requisition.height;
511       
512       temp = allocation->height - child_allocation.height;
513       child_allocation.y += ( temp / 2 ) + ( temp % 2 );
514
515       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
516
517       child_allocation.y = GTK_CONTAINER (widget)->border_width;
518       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
519       child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
520
521       child_allocation.width = 
522         MAX (1, (gint)allocation->width - ((gint)child_allocation.x + border_width));
523
524       gtk_widget_size_allocate (bin->child, &child_allocation);
525     }
526 }
527
528 static void 
529 gtk_tree_item_draw_lines (GtkWidget *widget) 
530 {
531   GtkTreeItem* item;
532   GtkTree* tree;
533   guint lx1, ly1, lx2, ly2;
534   GdkGC* gc;
535
536   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
537
538   item = GTK_TREE_ITEM(widget);
539   tree = GTK_TREE(widget->parent);
540
541   if (!tree->view_line)
542     return;
543
544   gc = widget->style->text_gc[GTK_STATE_NORMAL];
545
546   /* draw vertical line */
547   lx1 = item->pixmaps_box->allocation.width;
548   lx1 = lx2 = ((lx1 / 2) + (lx1 % 2) + 
549                GTK_CONTAINER (widget)->border_width + 1 + tree->current_indent);
550   ly1 = 0;
551   ly2 = widget->allocation.height;
552
553   if (g_list_last (tree->children)->data == widget)
554     ly2 = (ly2 / 2) + (ly2 % 2);
555
556   if (tree != tree->root_tree)
557     gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
558
559   /* draw vertical line for subtree connecting */
560   if(g_list_last(tree->children)->data != (gpointer)widget)
561     ly2 = (ly2 / 2) + (ly2 % 2);
562   
563   lx2 += DEFAULT_DELTA;
564
565   if (item->subtree && item->expanded)
566     gdk_draw_line (widget->window, gc,
567                    lx2, ly2, lx2, widget->allocation.height);
568
569   /* draw horizontal line */
570   ly1 = ly2;
571   lx2 += 2;
572
573   gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
574
575   lx2 -= DEFAULT_DELTA+2;
576   ly1 = 0;
577   ly2 = widget->allocation.height;
578
579   if (tree != tree->root_tree)
580     {
581       item = GTK_TREE_ITEM (tree->tree_owner);
582       tree = GTK_TREE (GTK_WIDGET (tree)->parent);
583       while (tree != tree->root_tree)
584         {
585           lx1 = lx2 -= tree->indent_value;
586           
587           if (g_list_last (tree->children)->data != item)
588             gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
589           item = GTK_TREE_ITEM (tree->tree_owner);
590           tree = GTK_TREE (GTK_WIDGET (tree)->parent);
591         } 
592     }
593 }
594
595 static void
596 gtk_tree_item_paint (GtkWidget    *widget,
597                      GdkRectangle *area)
598 {
599   GdkRectangle child_area, item_area;
600   GtkTreeItem* tree_item;
601
602   /* FIXME: We should honor tree->view_mode, here - I think
603    * the desired effect is that when the mode is VIEW_ITEM,
604    * only the subitem is drawn as selected, not the entire
605    * line. (Like the way that the tree in Windows Explorer
606    * works).
607    */
608   if (GTK_WIDGET_DRAWABLE (widget))
609     {
610       tree_item = GTK_TREE_ITEM(widget);
611
612       if (widget->state == GTK_STATE_NORMAL)
613         {
614           gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
615           gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
616         }
617       else 
618         {
619           if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
620             gtk_paint_flat_box(widget->style, widget->window,
621                                widget->state, GTK_SHADOW_NONE,
622                                area, widget, "treeitem",
623                                0, 0, -1, -1);
624           else
625             gtk_paint_flat_box(widget->style, widget->window,
626                                widget->state, GTK_SHADOW_ETCHED_OUT,
627                                area, widget, "treeitem",
628                                0, 0, -1, -1);
629         }
630
631       /* draw left size of tree item */
632       item_area.x = 0;
633       item_area.y = 0;
634       item_area.width = (tree_item->pixmaps_box->allocation.width + DEFAULT_DELTA +
635                          GTK_TREE (widget->parent)->current_indent + 2);
636       item_area.height = widget->allocation.height;
637
638
639       if (gdk_rectangle_intersect(&item_area, area, &child_area)) 
640         {
641           
642           gtk_tree_item_draw_lines(widget);
643
644           if (tree_item->pixmaps_box && 
645               GTK_WIDGET_VISIBLE(tree_item->pixmaps_box) &&
646               gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
647             gtk_widget_draw (tree_item->pixmaps_box, &child_area);
648         }
649
650       if (GTK_WIDGET_HAS_FOCUS (widget))
651         gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
652                          NULL, widget, "treeitem",
653                          0, 0,
654                          widget->allocation.width,
655                          widget->allocation.height);
656       
657     }
658 }
659
660 static gint
661 gtk_tree_item_button_press (GtkWidget      *widget,
662                             GdkEventButton *event)
663 {
664   if (event->type == GDK_BUTTON_PRESS
665         && GTK_WIDGET_IS_SENSITIVE(widget)
666         && !GTK_WIDGET_HAS_FOCUS (widget))
667       gtk_widget_grab_focus (widget);
668
669   return (event->type == GDK_BUTTON_PRESS && GTK_WIDGET_IS_SENSITIVE(widget));
670 }
671
672 static void
673 gtk_tree_item_expose_child (GtkWidget *child,
674                             gpointer   client_data)
675 {
676   struct {
677     GtkWidget *container;
678     GdkEventExpose *event;
679   } *data = client_data;
680
681   if (GTK_WIDGET_DRAWABLE (child) &&
682       GTK_WIDGET_NO_WINDOW (child) &&
683       (child->window == data->event->window))
684     {
685       GdkEvent *child_event = gdk_event_new (GDK_EXPOSE);
686       child_event->expose = *data->event;
687       g_object_ref (child_event->expose.window);
688
689       child_event->expose.region = gtk_widget_region_intersect (child,
690                                                                 data->event->region);
691       if (!gdk_region_empty (child_event->expose.region))
692         {
693           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
694           gtk_widget_send_expose (child, child_event);
695         }
696       gdk_event_free (child_event);
697     }
698 }
699
700 static gint
701 gtk_tree_item_expose (GtkWidget      *widget,
702                       GdkEventExpose *event)
703 {
704   struct {
705     GtkWidget *container;
706     GdkEventExpose *event;
707   } data;
708
709   if (GTK_WIDGET_DRAWABLE (widget))
710     {
711       gtk_tree_item_paint (widget, &event->area);
712
713       data.container = widget;
714       data.event = event;
715
716       gtk_container_forall (GTK_CONTAINER (widget),
717                             gtk_tree_item_expose_child,
718                             &data);
719    }
720
721   return FALSE;
722 }
723
724 static void
725 gtk_real_tree_item_select (GtkItem *item)
726 {
727   GtkWidget *widget;
728
729   g_return_if_fail (GTK_IS_TREE_ITEM (item));
730
731   widget = GTK_WIDGET (item);
732
733   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
734
735   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
736     gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
737 }
738
739 static void
740 gtk_real_tree_item_deselect (GtkItem *item)
741 {
742   GtkTreeItem *tree_item;
743   GtkWidget *widget;
744
745   g_return_if_fail (GTK_IS_TREE_ITEM (item));
746
747   tree_item = GTK_TREE_ITEM (item);
748   widget = GTK_WIDGET (item);
749
750   gtk_widget_set_state (widget, GTK_STATE_NORMAL);
751
752   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
753     gtk_widget_set_state (tree_item->pixmaps_box, GTK_STATE_NORMAL);
754 }
755
756 static void
757 gtk_real_tree_item_toggle (GtkItem *item)
758 {
759   g_return_if_fail (GTK_IS_TREE_ITEM (item));
760
761   if(!GTK_WIDGET_IS_SENSITIVE(item))
762     return;
763
764   if (GTK_IS_TREE (GTK_WIDGET (item)->parent))
765     gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
766                            GTK_WIDGET (item));
767   else
768     {
769       /* Should we really bother with this bit? A listitem not in a list?
770        * -Johannes Keukelaar
771        * yes, always be on the safe side!
772        * -timj
773        */
774       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
775         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
776       else
777         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
778     }
779 }
780
781 static void
782 gtk_real_tree_item_expand (GtkTreeItem *tree_item)
783 {
784   GtkTree* tree;
785   
786   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
787   
788   if (tree_item->subtree && !tree_item->expanded)
789     {
790       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent); 
791       
792       /* hide subtree widget */
793       gtk_widget_show (tree_item->subtree);
794       
795       /* hide button '+' and show button '-' */
796       if (tree_item->pixmaps_box)
797         {
798           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
799                                 tree_item->plus_pix_widget);
800           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
801                              tree_item->minus_pix_widget);
802         }
803       if (tree->root_tree)
804         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
805       tree_item->expanded = TRUE;
806     }
807 }
808
809 static void
810 gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
811 {
812   GtkTree* tree;
813   
814   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
815   
816   if (tree_item->subtree && tree_item->expanded) 
817     {
818       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent);
819       
820       /* hide subtree widget */
821       gtk_widget_hide (tree_item->subtree);
822       
823       /* hide button '-' and show button '+' */
824       if (tree_item->pixmaps_box)
825         {
826           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
827                                 tree_item->minus_pix_widget);
828           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
829                              tree_item->plus_pix_widget);
830         }
831       if (tree->root_tree)
832         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
833       tree_item->expanded = FALSE;
834     }
835 }
836
837 static void
838 gtk_tree_item_destroy (GtkObject *object)
839 {
840   GtkTreeItem* item = GTK_TREE_ITEM(object);
841   GtkWidget* child;
842
843 #ifdef TREE_DEBUG
844   g_message("+ gtk_tree_item_destroy [object %#x]\n", (int)object);
845 #endif /* TREE_DEBUG */
846
847   /* free sub tree if it exist */
848   child = item->subtree;
849   if (child)
850     {
851       gtk_widget_ref (child);
852       gtk_widget_unparent (child);
853       gtk_widget_destroy (child);
854       gtk_widget_unref (child);
855       item->subtree = NULL;
856     }
857   
858   /* free pixmaps box */
859   child = item->pixmaps_box;
860   if (child)
861     {
862       gtk_widget_ref (child);
863       gtk_widget_unparent (child);
864       gtk_widget_destroy (child);
865       gtk_widget_unref (child);
866       item->pixmaps_box = NULL;
867     }
868   
869   
870   /* destroy plus pixmap */
871   if (item->plus_pix_widget)
872     {
873       gtk_widget_destroy (item->plus_pix_widget);
874       gtk_widget_unref (item->plus_pix_widget);
875       item->plus_pix_widget = NULL;
876     }
877   
878   /* destroy minus pixmap */
879   if (item->minus_pix_widget)
880     {
881       gtk_widget_destroy (item->minus_pix_widget);
882       gtk_widget_unref (item->minus_pix_widget);
883       item->minus_pix_widget = NULL;
884     }
885   
886   /* By removing the pixmaps here, and not in unrealize, we depend on
887    * the fact that a widget can never change colormap or visual.
888    */
889   gtk_tree_item_remove_pixmaps (item);
890   
891   GTK_OBJECT_CLASS (parent_class)->destroy (object);
892   
893 #ifdef TREE_DEBUG
894   g_message("- gtk_tree_item_destroy\n");
895 #endif /* TREE_DEBUG */
896 }
897
898 void
899 gtk_tree_item_remove_subtree (GtkTreeItem* item) 
900 {
901   g_return_if_fail (GTK_IS_TREE_ITEM(item));
902   g_return_if_fail (item->subtree != NULL);
903   
904   if (GTK_TREE (item->subtree)->children)
905     {
906       /* The following call will remove the children and call
907        * gtk_tree_item_remove_subtree() again. So we are done.
908        */
909       gtk_tree_remove_items (GTK_TREE (item->subtree), 
910                              GTK_TREE (item->subtree)->children);
911       return;
912     }
913
914   if (GTK_WIDGET_MAPPED (item->subtree))
915     gtk_widget_unmap (item->subtree);
916       
917   gtk_widget_unparent (item->subtree);
918   
919   if (item->pixmaps_box)
920     gtk_widget_hide (item->pixmaps_box);
921   
922   item->subtree = NULL;
923
924   if (item->expanded)
925     {
926       item->expanded = FALSE;
927       if (item->pixmaps_box)
928         {
929           gtk_container_remove (GTK_CONTAINER (item->pixmaps_box), 
930                                 item->minus_pix_widget);
931           gtk_container_add (GTK_CONTAINER (item->pixmaps_box), 
932                              item->plus_pix_widget);
933         }
934     }
935 }
936
937 static void
938 gtk_tree_item_map (GtkWidget *widget)
939 {
940   GtkBin *bin = GTK_BIN (widget);
941   GtkTreeItem* item = GTK_TREE_ITEM(widget);
942
943   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
944
945   if(item->pixmaps_box &&
946      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
947      !GTK_WIDGET_MAPPED (item->pixmaps_box))
948     gtk_widget_map (item->pixmaps_box);
949
950   if (bin->child &&
951       GTK_WIDGET_VISIBLE (bin->child) &&
952       !GTK_WIDGET_MAPPED (bin->child))
953     gtk_widget_map (bin->child);
954
955   gdk_window_show (widget->window);
956 }
957
958 static void
959 gtk_tree_item_unmap (GtkWidget *widget)
960 {
961   GtkBin *bin = GTK_BIN (widget);
962   GtkTreeItem* item = GTK_TREE_ITEM(widget);
963
964   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
965
966   gdk_window_hide (widget->window);
967
968   if(item->pixmaps_box &&
969      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
970      GTK_WIDGET_MAPPED (item->pixmaps_box))
971     gtk_widget_unmap (bin->child);
972
973   if (bin->child &&
974       GTK_WIDGET_VISIBLE (bin->child) &&
975       GTK_WIDGET_MAPPED (bin->child))
976     gtk_widget_unmap (bin->child);
977 }
978
979 static void
980 gtk_tree_item_forall (GtkContainer *container,
981                       gboolean      include_internals,
982                       GtkCallback   callback,
983                       gpointer      callback_data)
984 {
985   GtkBin *bin = GTK_BIN (container);
986   GtkTreeItem *tree_item = GTK_TREE_ITEM (container);
987
988   if (bin->child)
989     (* callback) (bin->child, callback_data);
990   if (include_internals && tree_item->subtree)
991     (* callback) (tree_item->subtree, callback_data);
992   if (include_internals && tree_item->pixmaps_box)
993     (* callback) (tree_item->pixmaps_box, callback_data);
994 }
995
996 #define __GTK_TREE_ITEM_C__
997 #include "gtkaliasdef.c"