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