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