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