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