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