source: trunk/third/gtk/gtk/gtktreeitem.c @ 14482

Revision 14482, 30.3 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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
40enum {
41  COLLAPSE_TREE,
42  EXPAND_TREE,
43  LAST_SIGNAL
44};
45
46typedef struct _GtkTreePixmaps GtkTreePixmaps;
47
48struct _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
58static GList *pixmaps = NULL;
59
60static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
61static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
62static void gtk_tree_item_realize       (GtkWidget        *widget);
63static void gtk_tree_item_size_request  (GtkWidget        *widget,
64                                         GtkRequisition   *requisition);
65static void gtk_tree_item_size_allocate (GtkWidget        *widget,
66                                         GtkAllocation    *allocation);
67static void gtk_tree_item_draw          (GtkWidget        *widget,
68                                         GdkRectangle     *area);
69static void gtk_tree_item_draw_focus    (GtkWidget        *widget);
70static void gtk_tree_item_paint         (GtkWidget        *widget,
71                                         GdkRectangle     *area);
72static gint gtk_tree_item_button_press  (GtkWidget        *widget,
73                                         GdkEventButton   *event);
74static gint gtk_tree_item_expose        (GtkWidget        *widget,
75                                         GdkEventExpose   *event);
76static gint gtk_tree_item_focus_in      (GtkWidget        *widget,
77                                         GdkEventFocus    *event);
78static gint gtk_tree_item_focus_out     (GtkWidget        *widget,
79                                         GdkEventFocus    *event);
80static void gtk_tree_item_forall        (GtkContainer    *container,
81                                         gboolean         include_internals,
82                                         GtkCallback      callback,
83                                         gpointer         callback_data);
84
85static void gtk_real_tree_item_select   (GtkItem          *item);
86static void gtk_real_tree_item_deselect (GtkItem          *item);
87static void gtk_real_tree_item_toggle   (GtkItem          *item);
88static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
89static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
90static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
91static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
92static void gtk_tree_item_destroy        (GtkObject *object);
93static void gtk_tree_item_subtree_button_click (GtkWidget *widget);
94static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
95
96static void gtk_tree_item_map(GtkWidget*);
97static void gtk_tree_item_unmap(GtkWidget*);
98
99static void gtk_tree_item_add_pixmaps    (GtkTreeItem       *tree_item);
100static void gtk_tree_item_remove_pixmaps (GtkTreeItem       *tree_item);
101
102static GtkItemClass *parent_class = NULL;
103static guint tree_item_signals[LAST_SIGNAL] = { 0 };
104
105GtkType
106gtk_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
130static void
131gtk_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 */
187static void
188gtk_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 */
206static void
207gtk_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
226static void
227gtk_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
275GtkWidget*
276gtk_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
285GtkWidget*
286gtk_tree_item_new_with_label (const 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
302void
303gtk_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
343void
344gtk_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
352void
353gtk_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
361void
362gtk_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
370void
371gtk_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
379static void
380gtk_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
442static void
443gtk_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
471static void
472gtk_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
486static void
487gtk_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
523static void
524gtk_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
573static void
574gtk_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
639static void
640gtk_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
710static void
711gtk_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
734static void
735gtk_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
743static gint
744gtk_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
760static gint
761gtk_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
786static gint
787gtk_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
801static gint
802gtk_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
816static void
817gtk_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
834static void
835gtk_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
852static void
853gtk_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
878static void
879gtk_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
907static void
908gtk_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
936static void
937gtk_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
1002void
1003gtk_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
1042static void
1043gtk_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
1069static void
1070gtk_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
1095static void
1096gtk_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}
Note: See TracBrowser for help on using the repository browser.