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