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