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