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