]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeitem.c
gtk_object_query_args takes an additional pointer now which if supplied
[~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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "gtklabel.h"
19 #include "gtktree.h"
20 #include "gtktreeitem.h"
21 #include "gtkeventbox.h"
22 #include "gtkpixmap.h"
23 #include "gtkmain.h"
24 #include "gtksignal.h"
25
26 #include "tree_plus.xpm"
27 #include "tree_minus.xpm"
28
29 #define DEFAULT_DELTA 9
30
31 enum {
32   COLLAPSE_TREE,
33   EXPAND_TREE,
34   LAST_SIGNAL
35 };
36
37 typedef void (*GtkTreeItemSignal) (GtkObject *object,
38                                    gpointer   arg1,
39                                    gpointer   data);
40
41 static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
42 static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
43 static void gtk_tree_item_realize       (GtkWidget        *widget);
44 static void gtk_tree_item_size_request  (GtkWidget        *widget,
45                                          GtkRequisition   *requisition);
46 static void gtk_tree_item_size_allocate (GtkWidget        *widget,
47                                          GtkAllocation    *allocation);
48 static void gtk_tree_item_draw          (GtkWidget        *widget,
49                                          GdkRectangle     *area);
50 static void gtk_tree_item_draw_focus    (GtkWidget        *widget);
51 static gint gtk_tree_item_button_press  (GtkWidget        *widget,
52                                          GdkEventButton   *event);
53 static gint gtk_tree_item_expose        (GtkWidget        *widget,
54                                          GdkEventExpose   *event);
55 static gint gtk_tree_item_focus_in      (GtkWidget        *widget,
56                                          GdkEventFocus    *event);
57 static gint gtk_tree_item_focus_out     (GtkWidget        *widget,
58                                          GdkEventFocus    *event);
59 static void gtk_real_tree_item_select   (GtkItem          *item);
60 static void gtk_real_tree_item_deselect (GtkItem          *item);
61 static void gtk_real_tree_item_toggle   (GtkItem          *item);
62 static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
63 static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
64 static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
65 static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
66 static void gtk_tree_item_destroy        (GtkObject *object);
67 static void gtk_tree_item_subtree_button_click (GtkWidget *widget);
68 static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
69
70 static void gtk_tree_item_map(GtkWidget*);
71 static void gtk_tree_item_unmap(GtkWidget*);
72
73 static GtkItemClass *parent_class = NULL;
74 static GtkContainerClass *container_class = NULL;
75 static gint tree_item_signals[LAST_SIGNAL] = { 0 };
76
77 guint
78 gtk_tree_item_get_type ()
79 {
80   static guint tree_item_type = 0;
81
82   if (!tree_item_type)
83     {
84       GtkTypeInfo tree_item_info =
85       {
86         "GtkTreeItem",
87         sizeof (GtkTreeItem),
88         sizeof (GtkTreeItemClass),
89         (GtkClassInitFunc) gtk_tree_item_class_init,
90         (GtkObjectInitFunc) gtk_tree_item_init,
91         (GtkArgSetFunc) NULL,
92         (GtkArgGetFunc) NULL,
93       };
94
95       tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info);
96     }
97
98   return tree_item_type;
99 }
100
101 static void
102 gtk_tree_item_class_init (GtkTreeItemClass *class)
103 {
104   GtkObjectClass *object_class;
105   GtkWidgetClass *widget_class;
106   GtkItemClass *item_class;
107
108   object_class = (GtkObjectClass*) class;
109   widget_class = (GtkWidgetClass*) class;
110   item_class = (GtkItemClass*) class;
111   container_class = (GtkContainerClass*) class;
112
113   parent_class = gtk_type_class (gtk_item_get_type ());
114   
115   tree_item_signals[EXPAND_TREE] =
116     gtk_signal_new ("expand",
117                     GTK_RUN_FIRST,
118                     object_class->type,
119                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, expand),
120                     gtk_signal_default_marshaller,
121                     GTK_TYPE_NONE, 0);
122   tree_item_signals[COLLAPSE_TREE] =
123     gtk_signal_new ("collapse",
124                     GTK_RUN_FIRST,
125                     object_class->type,
126                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, collapse),
127                     gtk_signal_default_marshaller,
128                     GTK_TYPE_NONE, 0);
129
130   gtk_object_class_add_signals (object_class, tree_item_signals, LAST_SIGNAL);
131
132   object_class->destroy = gtk_tree_item_destroy;
133
134   widget_class->realize = gtk_tree_item_realize;
135   widget_class->size_request = gtk_tree_item_size_request;
136   widget_class->size_allocate = gtk_tree_item_size_allocate;
137   widget_class->draw = gtk_tree_item_draw;
138   widget_class->draw_focus = gtk_tree_item_draw_focus;
139   widget_class->button_press_event = gtk_tree_item_button_press;
140   widget_class->expose_event = gtk_tree_item_expose;
141   widget_class->focus_in_event = gtk_tree_item_focus_in;
142   widget_class->focus_out_event = gtk_tree_item_focus_out;
143   widget_class->map = gtk_tree_item_map;
144   widget_class->unmap = gtk_tree_item_unmap;
145
146   item_class->select = gtk_real_tree_item_select;
147   item_class->deselect = gtk_real_tree_item_deselect;
148   item_class->toggle = gtk_real_tree_item_toggle;
149
150   class->expand = gtk_real_tree_item_expand;
151   class->collapse = gtk_real_tree_item_collapse;
152
153   container_class = (GtkContainerClass*) parent_class;
154 }
155
156 /* callback for event box mouse event */
157 static void 
158 gtk_tree_item_subtree_button_click (GtkWidget *widget)
159 {
160   GtkTreeItem* item;
161
162   item = (GtkTreeItem*) gtk_object_get_user_data(GTK_OBJECT(widget));
163   if(!GTK_WIDGET_IS_SENSITIVE(item))
164     return;
165
166   if(item->expanded)
167     gtk_tree_item_collapse(item);
168   else
169     gtk_tree_item_expand(item);
170 }
171
172 /* callback for event box state changed */
173 static void
174 gtk_tree_item_subtree_button_changed_state(GtkWidget *w)
175 {
176   if(GTK_WIDGET_VISIBLE (w)) {
177
178     if (w->state == GTK_STATE_NORMAL)
179       gdk_window_set_background (w->window, &w->style->base[w->state]);
180     else
181       gdk_window_set_background (w->window, &w->style->bg[w->state]);
182
183     if (GTK_WIDGET_DRAWABLE(w))
184       gdk_window_clear_area (w->window, 0, 0, 
185                              w->allocation.width, w->allocation.height);
186   }
187 }
188
189 static void
190 gtk_tree_item_init (GtkTreeItem *tree_item)
191 {
192   GtkWidget *eventbox, *pixmapwid;
193   static GdkPixmap *pixmap_plus = NULL;
194   static GdkPixmap *pixmap_minus = NULL;
195   static GdkBitmap *mask_plus = NULL; 
196   static GdkBitmap *mask_minus = NULL;
197   GdkColor xpmcolor;
198
199   tree_item->expanded = FALSE;
200   tree_item->subtree = NULL;
201   GTK_WIDGET_SET_FLAGS (tree_item, GTK_CAN_FOCUS);
202
203   /* check if icons are already created */
204   if(pixmap_plus == NULL && pixmap_minus == NULL) 
205     {
206       /* create pixmaps for plus icon */
207       pixmap_plus = gdk_pixmap_create_from_xpm_d(GTK_WIDGET(tree_item)->window,
208                                                &mask_plus,
209                                                &xpmcolor,
210                                                tree_plus);
211       /* create pixmaps for minus icon */
212       pixmap_minus = gdk_pixmap_create_from_xpm_d(GTK_WIDGET(tree_item)->window,
213                                                 &mask_minus,
214                                                 &xpmcolor,
215                                                 tree_minus);
216     }
217   
218   if(pixmap_plus && pixmap_minus) 
219     {
220       /* create an event box containing one pixmaps */
221       eventbox = gtk_event_box_new();
222       gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK);
223       gtk_signal_connect(GTK_OBJECT(eventbox), "state_changed",
224                          (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
225                          (gpointer)NULL);
226       gtk_signal_connect(GTK_OBJECT(eventbox), "realize",
227                          (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
228                          (gpointer)NULL);
229       gtk_signal_connect(GTK_OBJECT(eventbox), "button_press_event",
230                          (GtkSignalFunc)gtk_tree_item_subtree_button_click,
231                          (gpointer)NULL);
232       gtk_object_set_user_data(GTK_OBJECT(eventbox), tree_item);
233       tree_item->pixmaps_box = eventbox;
234
235       /* create pixmap for button '+' */
236       pixmapwid = gtk_pixmap_new (pixmap_plus, mask_plus);
237       if(!tree_item->expanded) 
238         gtk_container_add(GTK_CONTAINER(eventbox), pixmapwid);
239       gtk_widget_show(pixmapwid);
240       tree_item->plus_pix_widget = pixmapwid;
241       gtk_widget_ref (tree_item->plus_pix_widget);
242       gtk_object_sink (GTK_OBJECT (tree_item->plus_pix_widget));
243       
244       /* create pixmap for button '-' */
245       pixmapwid = gtk_pixmap_new (pixmap_minus, mask_minus);
246       if(tree_item->expanded) 
247         gtk_container_add(GTK_CONTAINER(eventbox), pixmapwid);
248       gtk_widget_show(pixmapwid);
249       tree_item->minus_pix_widget = pixmapwid;
250       gtk_widget_ref (tree_item->minus_pix_widget);
251       gtk_object_sink (GTK_OBJECT (tree_item->minus_pix_widget));
252       
253       gtk_widget_set_parent(eventbox, GTK_WIDGET(tree_item));
254     } else
255       tree_item->pixmaps_box = NULL;
256 }
257
258
259 GtkWidget*
260 gtk_tree_item_new ()
261 {
262   GtkWidget *tree_item;
263
264   tree_item = GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ()));
265
266   return tree_item;
267 }
268
269 GtkWidget*
270 gtk_tree_item_new_with_label (gchar *label)
271 {
272   GtkWidget *tree_item;
273   GtkWidget *label_widget;
274
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
294   if(tree_item->subtree) {
295     g_warning("there is already a subtree for this tree item\n");
296     return;
297   }
298
299   tree_item->subtree = subtree; 
300   GTK_TREE(subtree)->tree_owner = GTK_WIDGET(tree_item);
301
302   /* set root tree for selection list */
303   GTK_TREE(subtree)->root_tree = GTK_TREE(GTK_WIDGET(tree_item)->parent)->root_tree;
304
305   /* show subtree button */
306   if(tree_item->pixmaps_box)
307     gtk_widget_show(tree_item->pixmaps_box);
308
309   /* set parent widget */
310   gtk_widget_set_parent(subtree, GTK_WIDGET(tree_item)->parent);
311
312   if(GTK_WIDGET_VISIBLE(GTK_WIDGET(tree_item))) 
313     {
314       if(GTK_WIDGET_REALIZED (GTK_WIDGET(tree_item)) &&
315          !GTK_WIDGET_REALIZED (GTK_WIDGET(subtree)))
316         gtk_widget_realize (GTK_WIDGET(subtree));
317
318       if(GTK_WIDGET_MAPPED (GTK_WIDGET(tree_item)) &&
319          !GTK_WIDGET_MAPPED (GTK_WIDGET(subtree)))
320         gtk_widget_map (GTK_WIDGET(subtree));
321     }
322
323   if(tree_item->expanded)
324     gtk_widget_show(subtree);
325   else
326     gtk_widget_hide(subtree);
327   
328   if (GTK_WIDGET_VISIBLE (tree_item) && GTK_WIDGET_VISIBLE (tree_item))
329     gtk_widget_queue_resize (GTK_WIDGET(tree_item));
330
331 }
332
333 void
334 gtk_tree_item_select (GtkTreeItem *tree_item)
335 {
336
337   gtk_item_select (GTK_ITEM (tree_item));
338
339 }
340
341 void
342 gtk_tree_item_deselect (GtkTreeItem *tree_item)
343 {
344
345   gtk_item_deselect (GTK_ITEM (tree_item));
346
347 }
348
349 void
350 gtk_tree_item_expand (GtkTreeItem *tree_item)
351 {
352
353   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[EXPAND_TREE], NULL);
354
355 }
356
357 void
358 gtk_tree_item_collapse (GtkTreeItem *tree_item)
359 {
360
361   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[COLLAPSE_TREE], NULL);
362
363 }
364
365 static void
366 gtk_tree_item_realize (GtkWidget *widget)
367 {    
368   g_return_if_fail (widget != NULL);
369   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
370
371   if (GTK_WIDGET_CLASS (parent_class)->realize)
372     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
373   
374   gdk_window_set_background (widget->window, 
375                              &widget->style->base[GTK_STATE_NORMAL]);
376 }
377
378 static void
379 gtk_tree_item_size_request (GtkWidget      *widget,
380                             GtkRequisition *requisition)
381 {
382   GtkBin *bin;
383   GtkTreeItem* item;
384
385   g_return_if_fail (widget != NULL);
386   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
387   g_return_if_fail (requisition != NULL);
388
389   bin = GTK_BIN (widget);
390   item = GTK_TREE_ITEM(widget);
391
392   requisition->width = (GTK_CONTAINER (widget)->border_width +
393                         widget->style->klass->xthickness) * 2;
394   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
395
396   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
397     {
398       gtk_widget_size_request (bin->child, &bin->child->requisition);
399
400       requisition->width += bin->child->requisition.width;
401
402       gtk_widget_size_request (item->pixmaps_box, 
403                                &item->pixmaps_box->requisition);
404       requisition->width += item->pixmaps_box->requisition.width + DEFAULT_DELTA + 
405         GTK_TREE(widget->parent)->current_indent;
406
407       requisition->height += MAX(bin->child->requisition.height,
408                                  item->pixmaps_box->requisition.height);
409     }
410 }
411
412 static void
413 gtk_tree_item_size_allocate (GtkWidget     *widget,
414                              GtkAllocation *allocation)
415 {
416   GtkBin *bin;
417   GtkTreeItem* item;
418   GtkAllocation child_allocation;
419   guint border_width;
420   int temp;
421
422   g_return_if_fail (widget != NULL);
423   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
424   g_return_if_fail (allocation != NULL);
425
426   widget->allocation = *allocation;
427   if (GTK_WIDGET_REALIZED (widget))
428     gdk_window_move_resize (widget->window,
429                             allocation->x, allocation->y,
430                             allocation->width, allocation->height);
431
432   bin = GTK_BIN (widget);
433   item = GTK_TREE_ITEM(widget);
434
435   if (bin->child)
436     {
437       border_width = (GTK_CONTAINER (widget)->border_width +
438                       widget->style->klass->xthickness);
439
440       child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
441       child_allocation.y = GTK_CONTAINER (widget)->border_width;
442
443 #if 0
444       child_allocation.height = allocation->height - child_allocation.y * 2;
445       child_allocation.width = item->pixmaps_box->requisition.width;
446
447       child_allocation.y += 1;
448       child_allocation.height -= 2;
449       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
450
451       child_allocation.height += 2;
452 #else
453       child_allocation.width = item->pixmaps_box->requisition.width;
454       child_allocation.height = item->pixmaps_box->requisition.height;
455       
456       temp = allocation->height - child_allocation.height;
457       child_allocation.y += ( temp / 2 ) + ( temp % 2 );
458
459       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
460
461       child_allocation.y = GTK_CONTAINER (widget)->border_width;
462       child_allocation.height = allocation->height - child_allocation.y * 2;
463 #endif
464       child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
465
466       child_allocation.width = 
467         allocation->width - (child_allocation.x + border_width);
468
469       gtk_widget_size_allocate (bin->child, &child_allocation);
470     }
471
472 }
473
474 static void 
475 gtk_tree_item_draw_lines(GtkWidget *widget) 
476 {
477   GtkTreeItem* item;
478   GtkTree* tree;
479   guint lx1, ly1, lx2, ly2;
480
481   item = GTK_TREE_ITEM(widget);
482   tree = GTK_TREE(widget->parent);
483
484   /* draw vertical line */
485   lx1 = item->pixmaps_box->allocation.width;
486   lx1 = lx2 = ( lx1 / 2 ) + ( lx1 % 2 ) + 
487     GTK_CONTAINER(widget)->border_width + 1 + tree->current_indent;
488   ly1 = 0;
489   ly2 = widget->allocation.height;
490
491   if(g_list_last(tree->children)->data == (gpointer)widget)
492     ly2 = (ly2 / 2) + (ly2 % 2);
493
494   if(tree != tree->root_tree)
495     gdk_draw_line(widget->window, widget->style->black_gc,
496                   lx1, ly1, lx2, ly2);
497
498   /* draw vertical line for subtree connecting */
499   if(g_list_last(tree->children)->data != (gpointer)widget)
500     ly2 = (ly2 / 2) + (ly2 % 2);
501   
502   lx2 += DEFAULT_DELTA;
503
504   if(item->subtree && item->expanded)
505     gdk_draw_line(widget->window, widget->style->black_gc,
506                   lx2, ly2, lx2, widget->allocation.height);
507
508   /* draw horizontal line */
509   ly1 = ly2;
510   lx2 += 2;
511
512   gdk_draw_line(widget->window, widget->style->black_gc,
513                 lx1, ly1, lx2, ly2);
514
515   lx2 -= DEFAULT_DELTA+2;
516   ly1 = 0;
517   ly2 = widget->allocation.height;
518
519   if(tree != tree->root_tree)
520     {
521       item = GTK_TREE_ITEM(tree->tree_owner);
522       tree = GTK_TREE(GTK_WIDGET(tree)->parent);
523       while(tree != tree->root_tree) {
524         lx1 = lx2 -= tree->indent_value;
525       
526         if(g_list_last(tree->children)->data != (gpointer)item)
527           gdk_draw_line(widget->window, widget->style->black_gc,
528                         lx1, ly1, lx2, ly2);
529         item = GTK_TREE_ITEM(tree->tree_owner);
530         tree = GTK_TREE(GTK_WIDGET(tree)->parent);
531       } 
532     }
533 }
534
535 static void
536 gtk_tree_item_draw (GtkWidget    *widget,
537                     GdkRectangle *area)
538 {
539   GtkBin *bin;
540   GdkRectangle child_area, item_area;
541   GtkTreeItem* tree_item;
542
543   g_return_if_fail (widget != NULL);
544   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
545   g_return_if_fail (area != NULL);
546
547   if (GTK_WIDGET_DRAWABLE (widget))
548     {
549       bin = GTK_BIN (widget);
550       tree_item = GTK_TREE_ITEM(widget);
551
552       /* draw left size of tree item */
553       item_area.x = 0; item_area.y = 0;
554       item_area.width = tree_item->pixmaps_box->allocation.width+DEFAULT_DELTA +
555         (GTK_TREE(widget->parent)->current_indent + 2);
556       item_area.height = widget->allocation.height;
557
558       if(gdk_rectangle_intersect(&item_area, area, &child_area)) {
559         
560         if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
561           gtk_style_set_background (widget->style, widget->window, 
562                                     GTK_STATE_INSENSITIVE);
563         else if(GTK_TREE(widget->parent)->view_mode == GTK_TREE_VIEW_LINE &&
564                 widget->state == GTK_STATE_SELECTED)
565           gtk_style_set_background (widget->style, widget->window, widget->state);
566         else
567           gdk_window_set_background (widget->window, 
568                                      &widget->style->base[GTK_STATE_NORMAL]);
569
570         gdk_window_clear_area (widget->window, 
571                                child_area.x, child_area.y,
572                                child_area.width, child_area.height);
573
574 /*      gtk_tree_item_draw_lines(widget); */
575
576         if (tree_item->pixmaps_box && 
577             GTK_WIDGET_VISIBLE(tree_item->pixmaps_box) &&
578             gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
579           gtk_widget_draw (tree_item->pixmaps_box, &child_area);
580       }
581
582       /* draw right side */
583       if(gtk_widget_intersect (bin->child, area, &child_area)) {
584
585         if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
586           gtk_style_set_background (widget->style, widget->window, 
587                                     GTK_STATE_INSENSITIVE);
588         else if (widget->state == GTK_STATE_NORMAL)
589           gdk_window_set_background(widget->window, &widget->style->base[GTK_STATE_NORMAL]);
590         else
591           gtk_style_set_background (widget->style, widget->window, widget->state);
592
593         gdk_window_clear_area (widget->window, child_area.x, child_area.y,
594                                child_area.width+1, child_area.height);
595
596         if (bin->child && 
597             GTK_WIDGET_VISIBLE(bin->child) &&
598             gtk_widget_intersect (bin->child, area, &child_area))
599           gtk_widget_draw (bin->child, &child_area);
600       }
601
602       gtk_widget_draw_focus (widget);
603     }
604 }
605
606 static void
607 gtk_tree_item_draw_focus (GtkWidget *widget)
608 {
609   GdkGC *gc;
610   int dx;
611
612   g_return_if_fail (widget != NULL);
613   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
614
615   if (GTK_WIDGET_DRAWABLE (widget))
616     {
617       if (GTK_WIDGET_HAS_FOCUS (widget))
618         gc = widget->style->black_gc;
619       else if (!GTK_WIDGET_IS_SENSITIVE (widget))
620         gc = widget->style->bg_gc[GTK_STATE_INSENSITIVE];
621       else if (widget->state == GTK_STATE_NORMAL)
622         gc = widget->style->base_gc[GTK_STATE_NORMAL];
623       else
624         gc = widget->style->bg_gc[widget->state];
625
626       dx = 0;
627
628       if(GTK_TREE(widget->parent)->view_mode == GTK_TREE_VIEW_ITEM) 
629         dx = GTK_TREE_ITEM(widget)->pixmaps_box->allocation.width + DEFAULT_DELTA +
630           GTK_TREE(widget->parent)->current_indent+1;
631
632       gdk_draw_rectangle (widget->window, gc, FALSE, dx, 0,
633                           widget->allocation.width - 1 - dx,
634                           widget->allocation.height - 1);
635
636       if(GTK_TREE(widget->parent)->view_line) 
637         gtk_tree_item_draw_lines(widget);
638     }
639 }
640
641 static gint
642 gtk_tree_item_button_press (GtkWidget      *widget,
643                             GdkEventButton *event)
644 {
645
646   g_return_val_if_fail (widget != NULL, FALSE);
647   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
648   g_return_val_if_fail (event != NULL, FALSE);
649
650   if (event->type == GDK_BUTTON_PRESS
651         && GTK_WIDGET_IS_SENSITIVE(widget)
652         && !GTK_WIDGET_HAS_FOCUS (widget))
653       gtk_widget_grab_focus (widget);
654
655   return FALSE;
656 }
657
658 static gint
659 gtk_tree_item_expose (GtkWidget      *widget,
660                       GdkEventExpose *event)
661 {
662   g_return_val_if_fail (widget != NULL, FALSE);
663   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
664   g_return_val_if_fail (event != NULL, FALSE);
665
666   if (GTK_WIDGET_DRAWABLE (widget))
667     gtk_tree_item_draw(widget, &event->area);
668
669   return FALSE;
670 }
671
672 static gint
673 gtk_tree_item_focus_in (GtkWidget     *widget,
674                         GdkEventFocus *event)
675 {
676
677   g_return_val_if_fail (widget != NULL, FALSE);
678   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
679   g_return_val_if_fail (event != NULL, FALSE);
680
681   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
682   gtk_widget_draw_focus (widget);
683
684
685   return FALSE;
686 }
687
688 static gint
689 gtk_tree_item_focus_out (GtkWidget     *widget,
690                          GdkEventFocus *event)
691 {
692
693   g_return_val_if_fail (widget != NULL, FALSE);
694   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
695   g_return_val_if_fail (event != NULL, FALSE);
696
697   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
698   gtk_widget_draw_focus (widget);
699
700
701   return FALSE;
702 }
703
704 static void
705 gtk_real_tree_item_select (GtkItem *item)
706 {
707     
708   g_return_if_fail (item != NULL);
709   g_return_if_fail (GTK_IS_TREE_ITEM (item));
710
711   if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED
712         || !GTK_WIDGET_IS_SENSITIVE(item))
713     return;
714
715   if(GTK_TREE(GTK_WIDGET(item)->parent)->view_mode == GTK_TREE_VIEW_LINE)
716     gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
717
718   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
719
720   gtk_widget_queue_draw (GTK_WIDGET (item));
721 }
722
723 static void
724 gtk_real_tree_item_deselect (GtkItem *item)
725 {
726
727   g_return_if_fail (item != NULL);
728   g_return_if_fail (GTK_IS_TREE_ITEM (item));
729
730   if (GTK_WIDGET (item)->state == GTK_STATE_NORMAL)
731     return;
732
733   if(GTK_WIDGET_MAPPED(GTK_WIDGET (item))) 
734     {
735       gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
736       
737       if(GTK_TREE(GTK_WIDGET(item)->parent)->view_mode == GTK_TREE_VIEW_LINE)
738         gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_NORMAL);
739
740       gtk_widget_queue_draw (GTK_WIDGET (item));
741     }
742 }
743
744 static void
745 gtk_real_tree_item_toggle (GtkItem *item)
746 {
747
748   g_return_if_fail (item != NULL);
749   g_return_if_fail (GTK_IS_TREE_ITEM (item));
750
751   if(!GTK_WIDGET_IS_SENSITIVE(item))
752     return;
753
754   if (GTK_WIDGET (item)->parent && GTK_IS_TREE (GTK_WIDGET (item)->parent))
755     gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
756                            GTK_WIDGET (item));
757   else
758     {
759       /* Should we really bother with this bit? A listitem not in a list?
760        * -Johannes Keukelaar
761        * yes, always be on the save side!
762        * -timj
763        */
764       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
765         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
766       else
767         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
768       gtk_widget_queue_draw (GTK_WIDGET (item));
769     }
770 }
771
772 static void
773 gtk_real_tree_item_expand (GtkTreeItem *tree_item)
774 {
775   GtkTree* tree;
776   
777   g_return_if_fail (tree_item != NULL);
778   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
779   g_return_if_fail (tree_item->subtree != NULL);
780
781
782   if(!tree_item->expanded) 
783     {
784       tree = GTK_TREE(GTK_WIDGET(tree_item)->parent); 
785
786       /* hide subtree widget */
787       gtk_widget_show(tree_item->subtree);
788
789       /* hide button '+' and show button '-' */
790       if(tree_item->pixmaps_box) {
791         gtk_container_remove(GTK_CONTAINER(tree_item->pixmaps_box), 
792                              tree_item->plus_pix_widget);
793         gtk_container_add(GTK_CONTAINER(tree_item->pixmaps_box), 
794                           tree_item->minus_pix_widget);
795       }
796       if(tree->root_tree) gtk_widget_queue_resize(GTK_WIDGET(tree->root_tree));
797       tree_item->expanded = TRUE;
798     }
799 }
800
801 static void
802 gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
803 {
804   GtkTree* tree;
805
806   g_return_if_fail (tree_item != NULL);
807   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
808   g_return_if_fail (tree_item->subtree != NULL);
809
810   if(tree_item->expanded) 
811     {
812       tree = GTK_TREE(GTK_WIDGET(tree_item)->parent);
813
814       /* hide subtree widget */
815       gtk_widget_hide(tree_item->subtree);
816
817       /* hide button '-' and show button '+' */
818       if(tree_item->pixmaps_box) {
819         gtk_container_remove(GTK_CONTAINER(tree_item->pixmaps_box), 
820                              tree_item->minus_pix_widget);
821         gtk_container_add(GTK_CONTAINER(tree_item->pixmaps_box), 
822                           tree_item->plus_pix_widget);
823       }
824       if(tree->root_tree) gtk_widget_queue_resize(GTK_WIDGET(tree->root_tree));
825       tree_item->expanded = FALSE;
826     }
827
828 }
829
830 static void
831 gtk_tree_item_destroy (GtkObject *object)
832 {
833   GtkTreeItem* item;
834   GtkWidget* child;
835
836   g_return_if_fail (object != NULL);
837   g_return_if_fail (GTK_IS_TREE_ITEM (object));
838
839   item = GTK_TREE_ITEM(object);
840
841   /* free sub tree if it exist */
842   if((child = item->subtree)) 
843     {
844       gtk_widget_ref (child);
845       gtk_widget_unparent (child);
846       gtk_widget_destroy (child);
847       gtk_widget_unref (child);
848       item->subtree = NULL;
849     }
850
851   /* free pixmaps box */
852   if((child = item->pixmaps_box))
853     {
854       gtk_widget_ref (child);
855       gtk_widget_unparent (child);
856       gtk_widget_destroy (child);
857       gtk_widget_unref (child);
858       item->pixmaps_box = NULL;
859     }
860
861   /* destroy plus pixmap */
862   if (item->plus_pix_widget)
863     {
864       gtk_widget_destroy (item->plus_pix_widget);
865       gtk_widget_unref (item->plus_pix_widget);
866       item->plus_pix_widget = NULL;
867     }
868
869   /* destroy minus pixmap */
870   if (item->minus_pix_widget)
871     {
872       gtk_widget_destroy (item->minus_pix_widget);
873       gtk_widget_unref (item->minus_pix_widget);
874       item->minus_pix_widget = NULL;
875     }
876   
877   if (GTK_OBJECT_CLASS (parent_class)->destroy)
878     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
879
880 }
881
882 void
883 gtk_tree_item_remove_subtree (GtkTreeItem* item) 
884 {
885   g_return_if_fail(item != NULL);
886   g_return_if_fail(GTK_IS_TREE_ITEM(item));
887   g_return_if_fail(item->subtree);
888
889   if(GTK_TREE(item->subtree)->children)
890     gtk_tree_remove_items(GTK_TREE(item->subtree), 
891                           GTK_TREE(item->subtree)->children);
892
893   if (GTK_WIDGET_MAPPED (item->subtree))
894     gtk_widget_unmap (item->subtree);
895
896   gtk_widget_unparent (item->subtree);
897
898   if(item->pixmaps_box)
899     gtk_widget_hide(item->pixmaps_box);
900
901   item->subtree = NULL;
902   item->expanded = FALSE;
903   if(item->pixmaps_box) {
904     gtk_container_remove(GTK_CONTAINER(item->pixmaps_box), 
905                          item->minus_pix_widget);
906     gtk_container_add(GTK_CONTAINER(item->pixmaps_box), 
907                       item->plus_pix_widget);
908   }
909 }
910
911 static void
912 gtk_tree_item_map (GtkWidget *widget)
913 {
914   GtkBin *bin;
915   GtkTreeItem* item;
916
917   g_return_if_fail (widget != NULL);
918   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
919
920   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
921   bin = GTK_BIN (widget);
922   item = GTK_TREE_ITEM(widget);
923
924   if (!GTK_WIDGET_NO_WINDOW (widget))
925     gdk_window_show (widget->window);
926   else
927     gtk_widget_queue_draw (widget);
928
929   if(item->pixmaps_box &&
930      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
931      !GTK_WIDGET_MAPPED (item->pixmaps_box))
932     gtk_widget_map (item->pixmaps_box);
933
934   if (bin->child &&
935       GTK_WIDGET_VISIBLE (bin->child) &&
936       !GTK_WIDGET_MAPPED (bin->child))
937     gtk_widget_map (bin->child);
938 }
939
940 static void
941 gtk_tree_item_unmap (GtkWidget *widget)
942 {
943   GtkBin *bin;
944   GtkTreeItem* item;
945
946   g_return_if_fail (widget != NULL);
947   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
948
949   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
950   bin = GTK_BIN (widget);
951   item = GTK_TREE_ITEM(widget);
952
953   if (GTK_WIDGET_NO_WINDOW (widget))
954     gdk_window_clear_area (widget->window,
955                            widget->allocation.x,
956                            widget->allocation.y,
957                            widget->allocation.width,
958                            widget->allocation.height);
959   else
960     gdk_window_hide (widget->window);
961
962   if(item->pixmaps_box &&
963      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
964      GTK_WIDGET_MAPPED (item->pixmaps_box))
965     gtk_widget_unmap (bin->child);
966
967   if (bin->child &&
968       GTK_WIDGET_VISIBLE (bin->child) &&
969       GTK_WIDGET_MAPPED (bin->child))
970     gtk_widget_unmap (bin->child);
971 }