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