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