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