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