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