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