1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * GtkCMCTree widget for GTK+
6 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #include <gdk/gdkkeysyms.h>
35 #include "gtkcmctree.h"
36 #include "claws-marshal.h"
38 #if !GTK_CHECK_VERSION(2,10,0)
39 #define gdk_atom_intern_static_string(str) gdk_atom_intern(str, FALSE)
43 #define TAB_SIZE (PM_SIZE + 6)
44 #define CELL_SPACING 1
45 #define CLIST_OPTIMUM_SIZE 64
46 #define COLUMN_INSET 3
49 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
50 (((row) + 1) * CELL_SPACING) + \
52 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
53 ((clist)->row_height + CELL_SPACING))
54 #define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \
56 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
59 gtk_cmctree_pos_get_type (void)
61 static GType etype = 0;
63 static const GEnumValue values[] = {
64 { GTK_CMCTREE_POS_BEFORE, "GTK_CMCTREE_POS_BEFORE", "before" },
65 { GTK_CMCTREE_POS_AS_CHILD, "GTK_CMCTREE_POS_AS_CHILD", "as-child" },
66 { GTK_CMCTREE_POS_AFTER, "GTK_CMCTREE_POS_AFTER", "after" },
69 #if GLIB_CHECK_VERSION(2,10,0)
70 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values);
72 etype = g_enum_register_static ("GtkCMCTreePos", values);
78 gtk_cmctree_line_style_get_type (void)
80 static GType etype = 0;
82 static const GEnumValue values[] = {
83 { GTK_CMCTREE_LINES_NONE, "GTK_CMCTREE_LINES_NONE", "none" },
84 { GTK_CMCTREE_LINES_SOLID, "GTK_CMCTREE_LINES_SOLID", "solid" },
85 { GTK_CMCTREE_LINES_DOTTED, "GTK_CMCTREE_LINES_DOTTED", "dotted" },
86 { GTK_CMCTREE_LINES_TABBED, "GTK_CMCTREE_LINES_TABBED", "tabbed" },
89 #if GLIB_CHECK_VERSION(2,10,0)
90 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values);
92 etype = g_enum_register_static ("GtkCMCTreeLineStyle", values);
98 gtk_cmctree_expander_style_get_type (void)
100 static GType etype = 0;
102 static const GEnumValue values[] = {
103 { GTK_CMCTREE_EXPANDER_NONE, "GTK_CMCTREE_EXPANDER_NONE", "none" },
104 { GTK_CMCTREE_EXPANDER_SQUARE, "GTK_CMCTREE_EXPANDER_SQUARE", "square" },
105 { GTK_CMCTREE_EXPANDER_TRIANGLE, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" },
106 { GTK_CMCTREE_EXPANDER_CIRCULAR, "GTK_CMCTREE_EXPANDER_CIRCULAR", "circular" },
109 #if GLIB_CHECK_VERSION(2,10,0)
110 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values);
112 etype = g_enum_register_static ("GtkCMCTreeExpanderStyle", values);
118 gtk_cmctree_expansion_type_get_type (void)
120 static GType etype = 0;
122 static const GEnumValue values[] = {
123 { GTK_CMCTREE_EXPANSION_EXPAND, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" },
124 { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" },
125 { GTK_CMCTREE_EXPANSION_COLLAPSE, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" },
126 { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" },
127 { GTK_CMCTREE_EXPANSION_TOGGLE, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" },
128 { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" },
131 #if GLIB_CHECK_VERSION(2,10,0)
132 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values);
134 etype = g_enum_register_static ("GtkCMCTreeExpansionType", values);
142 COLUMN_FROM_XPIXEL (GtkCMCList * clist,
147 for (i = 0; i < clist->columns; i++)
148 if (clist->column[i].visible)
150 cx = clist->column[i].area.x + clist->hoffset;
152 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
153 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
161 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
162 #define CLIST_REFRESH(clist) G_STMT_START { \
163 if (CLIST_UNFROZEN (clist)) \
164 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
180 static void gtk_cmctree_class_init (GtkCMCTreeClass *klass);
181 static void gtk_cmctree_init (GtkCMCTree *ctree);
182 static GObject* gtk_cmctree_constructor (GType type,
183 guint n_construct_properties,
184 GObjectConstructParam *construct_params);
185 static void gtk_cmctree_set_arg (GObject *object,
189 static void gtk_cmctree_get_arg (GObject *object,
193 static void gtk_cmctree_realize (GtkWidget *widget);
194 static void gtk_cmctree_unrealize (GtkWidget *widget);
195 static gint gtk_cmctree_button_press (GtkWidget *widget,
196 GdkEventButton *event);
197 static void ctree_attach_styles (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
200 static void ctree_detach_styles (GtkCMCTree *ctree,
201 GtkCMCTreeNode *node,
203 static gint draw_cell_pixmap (GdkWindow *window,
204 GdkRectangle *clip_rectangle,
212 static void get_cell_style (GtkCMCList *clist,
213 GtkCMCListRow *clist_row,
219 static gint gtk_cmctree_draw_expander (GtkCMCTree *ctree,
220 GtkCMCTreeRow *ctree_row,
222 GdkRectangle *clip_rectangle,
224 static gint gtk_cmctree_draw_lines (GtkCMCTree *ctree,
225 GtkCMCTreeRow *ctree_row,
229 GdkRectangle *clip_rectangle,
230 GdkRectangle *cell_rectangle,
234 static void draw_row (GtkCMCList *clist,
237 GtkCMCListRow *clist_row);
238 static void draw_drag_highlight (GtkCMCList *clist,
239 GtkCMCListRow *dest_row,
240 gint dest_row_number,
241 GtkCMCListDragPos drag_pos);
242 static void tree_draw_node (GtkCMCTree *ctree,
243 GtkCMCTreeNode *node);
244 static void set_cell_contents (GtkCMCList *clist,
245 GtkCMCListRow *clist_row,
252 static void set_node_info (GtkCMCTree *ctree,
253 GtkCMCTreeNode *node,
256 GdkPixmap *pixmap_closed,
257 GdkBitmap *mask_closed,
258 GdkPixmap *pixmap_opened,
259 GdkBitmap *mask_opened,
262 static GtkCMCTreeRow *row_new (GtkCMCTree *ctree);
263 static void row_delete (GtkCMCTree *ctree,
264 GtkCMCTreeRow *ctree_row);
265 static void tree_delete (GtkCMCTree *ctree,
266 GtkCMCTreeNode *node,
268 static void tree_delete_row (GtkCMCTree *ctree,
269 GtkCMCTreeNode *node,
271 static void real_clear (GtkCMCList *clist);
272 static void tree_update_level (GtkCMCTree *ctree,
273 GtkCMCTreeNode *node,
275 static void tree_select (GtkCMCTree *ctree,
276 GtkCMCTreeNode *node,
278 static void tree_unselect (GtkCMCTree *ctree,
279 GtkCMCTreeNode *node,
281 static void real_select_all (GtkCMCList *clist);
282 static void real_unselect_all (GtkCMCList *clist);
283 static void tree_expand (GtkCMCTree *ctree,
284 GtkCMCTreeNode *node,
286 static void tree_collapse (GtkCMCTree *ctree,
287 GtkCMCTreeNode *node,
289 static void tree_collapse_to_depth (GtkCMCTree *ctree,
290 GtkCMCTreeNode *node,
292 static void tree_toggle_expansion (GtkCMCTree *ctree,
293 GtkCMCTreeNode *node,
295 static void change_focus_row_expansion (GtkCMCTree *ctree,
296 GtkCMCTreeExpansionType expansion);
297 static void real_select_row (GtkCMCList *clist,
301 static void real_unselect_row (GtkCMCList *clist,
305 static void real_tree_select (GtkCMCTree *ctree,
306 GtkCMCTreeNode *node,
308 static void real_tree_unselect (GtkCMCTree *ctree,
309 GtkCMCTreeNode *node,
311 static void real_tree_expand (GtkCMCTree *ctree,
312 GtkCMCTreeNode *node);
313 static void real_tree_collapse (GtkCMCTree *ctree,
314 GtkCMCTreeNode *node);
315 static void real_tree_move (GtkCMCTree *ctree,
316 GtkCMCTreeNode *node,
317 GtkCMCTreeNode *new_parent,
318 GtkCMCTreeNode *new_sibling);
319 static void real_row_move (GtkCMCList *clist,
322 static void gtk_cmctree_link (GtkCMCTree *ctree,
323 GtkCMCTreeNode *node,
324 GtkCMCTreeNode *parent,
325 GtkCMCTreeNode *sibling,
326 gboolean update_focus_row);
327 static void gtk_cmctree_unlink (GtkCMCTree *ctree,
328 GtkCMCTreeNode *node,
329 gboolean update_focus_row);
330 static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree,
331 GtkCMCTreeNode *node);
332 static gboolean ctree_is_hot_spot (GtkCMCTree *ctree,
333 GtkCMCTreeNode *node,
337 static void tree_sort (GtkCMCTree *ctree,
338 GtkCMCTreeNode *node,
340 static void fake_unselect_all (GtkCMCList *clist,
342 static GList * selection_find (GtkCMCList *clist,
344 GList *row_list_element);
345 static void resync_selection (GtkCMCList *clist,
347 static void real_undo_selection (GtkCMCList *clist);
348 static void select_row_recursive (GtkCMCTree *ctree,
349 GtkCMCTreeNode *node,
351 static gint real_insert_row (GtkCMCList *clist,
354 static void real_remove_row (GtkCMCList *clist,
356 static void real_sort_list (GtkCMCList *clist);
357 static void cell_size_request (GtkCMCList *clist,
358 GtkCMCListRow *clist_row,
360 GtkRequisition *requisition);
361 static void column_auto_resize (GtkCMCList *clist,
362 GtkCMCListRow *clist_row,
365 static void auto_resize_columns (GtkCMCList *clist);
368 static gboolean check_drag (GtkCMCTree *ctree,
369 GtkCMCTreeNode *drag_source,
370 GtkCMCTreeNode *drag_target,
371 GtkCMCListDragPos insert_pos);
372 static void gtk_cmctree_drag_begin (GtkWidget *widget,
373 GdkDragContext *context);
374 static gint gtk_cmctree_drag_motion (GtkWidget *widget,
375 GdkDragContext *context,
379 static void gtk_cmctree_drag_data_received (GtkWidget *widget,
380 GdkDragContext *context,
383 GtkSelectionData *selection_data,
386 static void remove_grab (GtkCMCList *clist);
387 static void drag_dest_cell (GtkCMCList *clist,
390 GtkCMCListDestInfo *dest_info);
400 CHANGE_FOCUS_ROW_EXPANSION,
404 static GtkCMCListClass *parent_class = NULL;
405 static GtkContainerClass *container_class = NULL;
406 static guint ctree_signals[LAST_SIGNAL] = {0};
410 gtk_cmctree_get_type (void)
412 static GType ctree_type = 0;
416 static const GTypeInfo ctree_info =
418 sizeof (GtkCMCTreeClass),
420 (GBaseInitFunc) NULL,
421 (GBaseFinalizeFunc) NULL,
423 (GClassInitFunc) gtk_cmctree_class_init,
424 (GClassFinalizeFunc) NULL,
425 NULL, /* class_data */
429 (GInstanceInitFunc) gtk_cmctree_init,
432 ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0);
439 gtk_cmctree_class_init (GtkCMCTreeClass *klass)
441 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
442 GtkObjectClass *object_class;
443 GtkWidgetClass *widget_class;
444 GtkCMCListClass *clist_class;
445 GtkBindingSet *binding_set;
447 gobject_class->constructor = gtk_cmctree_constructor;
449 object_class = (GtkObjectClass *) klass;
450 widget_class = (GtkWidgetClass *) klass;
451 container_class = (GtkContainerClass *) klass;
452 clist_class = (GtkCMCListClass *) klass;
454 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST);
455 container_class = g_type_class_peek (GTK_TYPE_CONTAINER);
457 gobject_class->set_property = gtk_cmctree_set_arg;
458 gobject_class->get_property = gtk_cmctree_get_arg;
460 widget_class->realize = gtk_cmctree_realize;
461 widget_class->unrealize = gtk_cmctree_unrealize;
462 widget_class->button_press_event = gtk_cmctree_button_press;
464 widget_class->drag_begin = gtk_cmctree_drag_begin;
465 widget_class->drag_motion = gtk_cmctree_drag_motion;
466 widget_class->drag_data_received = gtk_cmctree_drag_data_received;
468 clist_class->select_row = real_select_row;
469 clist_class->unselect_row = real_unselect_row;
470 clist_class->row_move = real_row_move;
471 clist_class->undo_selection = real_undo_selection;
472 clist_class->resync_selection = resync_selection;
473 clist_class->selection_find = selection_find;
474 clist_class->click_column = NULL;
475 clist_class->draw_row = draw_row;
476 clist_class->draw_drag_highlight = draw_drag_highlight;
477 clist_class->clear = real_clear;
478 clist_class->select_all = real_select_all;
479 clist_class->unselect_all = real_unselect_all;
480 clist_class->fake_unselect_all = fake_unselect_all;
481 clist_class->insert_row = real_insert_row;
482 clist_class->remove_row = real_remove_row;
483 clist_class->sort_list = real_sort_list;
484 clist_class->set_cell_contents = set_cell_contents;
485 clist_class->cell_size_request = cell_size_request;
487 klass->tree_select_row = real_tree_select;
488 klass->tree_unselect_row = real_tree_unselect;
489 klass->tree_expand = real_tree_expand;
490 klass->tree_collapse = real_tree_collapse;
491 klass->tree_move = real_tree_move;
492 klass->change_focus_row_expansion = change_focus_row_expansion;
494 g_object_class_install_property (gobject_class,
496 g_param_spec_uint ("n-columns",
502 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
503 g_object_class_install_property (gobject_class,
505 g_param_spec_uint ("tree-column",
511 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
512 g_object_class_install_property (gobject_class,
514 g_param_spec_uint ("indent",
521 g_object_class_install_property (gobject_class,
523 g_param_spec_uint ("spacing",
530 g_object_class_install_property (gobject_class,
532 g_param_spec_boolean ("show-stub",
537 g_object_class_install_property (gobject_class,
539 g_param_spec_enum ("line-style",
542 GTK_TYPE_CMCTREE_LINE_STYLE, 0,
544 g_object_class_install_property (gobject_class,
546 g_param_spec_enum ("expander-style",
549 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0,
552 ctree_signals[TREE_SELECT_ROW] =
553 g_signal_new ("tree_select_row",
554 G_TYPE_FROM_CLASS (object_class),
556 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row),
558 claws_marshal_VOID__POINTER_INT,
560 GTK_TYPE_CMCTREE_NODE,
562 ctree_signals[TREE_UNSELECT_ROW] =
563 g_signal_new ("tree_unselect_row",
564 G_TYPE_FROM_CLASS (object_class),
566 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row),
568 claws_marshal_VOID__POINTER_INT,
570 GTK_TYPE_CMCTREE_NODE,
572 ctree_signals[TREE_EXPAND] =
573 g_signal_new ("tree_expand",
574 G_TYPE_FROM_CLASS (object_class),
576 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand),
578 claws_marshal_VOID__POINTER,
580 GTK_TYPE_CMCTREE_NODE);
581 ctree_signals[TREE_COLLAPSE] =
582 g_signal_new ("tree_collapse",
583 G_TYPE_FROM_CLASS (object_class),
585 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse),
587 claws_marshal_VOID__POINTER,
589 GTK_TYPE_CMCTREE_NODE);
590 ctree_signals[TREE_MOVE] =
591 g_signal_new ("tree_move",
592 G_TYPE_FROM_CLASS (object_class),
594 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move),
596 claws_marshal_VOID__POINTER_POINTER_POINTER,
598 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE);
599 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
600 g_signal_new ("change_focus_row_expansion",
601 G_TYPE_FROM_CLASS (object_class),
602 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
603 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion),
605 claws_marshal_VOID__ENUM,
606 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE);
608 binding_set = gtk_binding_set_by_class (klass);
609 gtk_binding_entry_add_signal (binding_set,
611 "change_focus_row_expansion", 1,
612 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
613 gtk_binding_entry_add_signal (binding_set,
614 GDK_plus, GDK_CONTROL_MASK,
615 "change_focus_row_expansion", 1,
616 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
618 gtk_binding_entry_add_signal (binding_set,
620 "change_focus_row_expansion", 1,
621 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
622 gtk_binding_entry_add_signal (binding_set,
623 GDK_KP_Add, GDK_CONTROL_MASK,
624 "change_focus_row_expansion", 1,
625 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
627 gtk_binding_entry_add_signal (binding_set,
629 "change_focus_row_expansion", 1,
630 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
631 gtk_binding_entry_add_signal (binding_set,
632 GDK_minus, GDK_CONTROL_MASK,
633 "change_focus_row_expansion", 1,
635 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
636 gtk_binding_entry_add_signal (binding_set,
638 "change_focus_row_expansion", 1,
639 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
640 gtk_binding_entry_add_signal (binding_set,
641 GDK_KP_Subtract, GDK_CONTROL_MASK,
642 "change_focus_row_expansion", 1,
644 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
645 gtk_binding_entry_add_signal (binding_set,
647 "change_focus_row_expansion", 1,
648 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
649 gtk_binding_entry_add_signal (binding_set,
651 "change_focus_row_expansion", 1,
652 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
653 gtk_binding_entry_add_signal (binding_set,
655 "change_focus_row_expansion", 1,
656 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
657 gtk_binding_entry_add_signal (binding_set,
659 "change_focus_row_expansion", 1,
660 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
661 gtk_binding_entry_add_signal (binding_set,
662 GDK_KP_Multiply, GDK_CONTROL_MASK,
663 "change_focus_row_expansion", 1,
665 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
666 gtk_binding_entry_add_signal (binding_set,
667 GDK_asterisk, GDK_CONTROL_MASK,
668 "change_focus_row_expansion", 1,
670 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
674 gtk_cmctree_set_arg (GObject *object,
682 ctree = GTK_CMCTREE (object);
683 clist = GTK_CMCLIST (ctree);
687 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
688 #if !GLIB_CHECK_VERSION(2,10,0)
689 g_return_if_fail (clist->row_mem_chunk == NULL);
691 clist->columns = MAX (1, g_value_get_uint (value));
692 #if !GLIB_CHECK_VERSION(2,10,0)
693 clist->row_mem_chunk = g_mem_chunk_new ("ctree row mem chunk",
694 sizeof (GtkCMCTreeRow),
695 sizeof (GtkCMCTreeRow)
696 * CLIST_OPTIMUM_SIZE,
698 clist->cell_mem_chunk = g_mem_chunk_new ("ctree cell mem chunk",
699 sizeof (GtkCMCell) * clist->columns,
700 sizeof (GtkCMCell) * clist->columns
701 * CLIST_OPTIMUM_SIZE,
704 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
706 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
707 ctree->tree_column = g_value_get_uint (value);
708 #if !GLIB_CHECK_VERSION(2,10,0)
709 if (clist->row_mem_chunk)
711 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
714 gtk_cmctree_set_indent (ctree, g_value_get_uint (value));
717 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value));
720 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value));
723 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value));
725 case ARG_EXPANDER_STYLE:
726 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value));
734 gtk_cmctree_get_arg (GObject *object,
741 ctree = GTK_CMCTREE (object);
746 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns);
748 case ARG_TREE_COLUMN:
749 g_value_set_uint(value, ctree->tree_column);
752 g_value_set_uint(value, ctree->tree_indent);
755 g_value_set_uint(value, ctree->tree_spacing);
758 g_value_set_boolean(value, ctree->show_stub);
761 g_value_set_enum(value, ctree->line_style);
763 case ARG_EXPANDER_STYLE:
764 g_value_set_enum(value, ctree->expander_style);
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
773 gtk_cmctree_init (GtkCMCTree *ctree)
777 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT);
778 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE);
780 clist = GTK_CMCLIST (ctree);
782 ctree->tree_indent = 20;
783 ctree->tree_spacing = 5;
784 ctree->tree_column = 0;
785 ctree->line_style = GTK_CMCTREE_LINES_SOLID;
786 ctree->expander_style = GTK_CMCTREE_EXPANDER_SQUARE;
787 ctree->drag_compare = NULL;
788 ctree->show_stub = TRUE;
790 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS;
794 ctree_attach_styles (GtkCMCTree *ctree,
795 GtkCMCTreeNode *node,
801 clist = GTK_CMCLIST (ctree);
803 if (GTK_CMCTREE_ROW (node)->row.style)
804 GTK_CMCTREE_ROW (node)->row.style =
805 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window);
807 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set)
809 GdkColormap *colormap;
811 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
812 if (GTK_CMCTREE_ROW (node)->row.fg_set)
813 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE);
814 if (GTK_CMCTREE_ROW (node)->row.bg_set)
815 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE);
818 for (i = 0; i < clist->columns; i++)
819 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
820 GTK_CMCTREE_ROW (node)->row.cell[i].style =
821 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style,
822 clist->clist_window);
826 ctree_detach_styles (GtkCMCTree *ctree,
827 GtkCMCTreeNode *node,
833 clist = GTK_CMCLIST (ctree);
835 if (GTK_CMCTREE_ROW (node)->row.style)
836 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
837 for (i = 0; i < clist->columns; i++)
838 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
839 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style);
843 gtk_cmctree_realize (GtkWidget *widget)
848 GtkCMCTreeNode *node;
849 GtkCMCTreeNode *child;
852 g_return_if_fail (GTK_IS_CMCTREE (widget));
854 GTK_WIDGET_CLASS (parent_class)->realize (widget);
856 ctree = GTK_CMCTREE (widget);
857 clist = GTK_CMCLIST (widget);
859 node = GTK_CMCTREE_NODE (clist->row_list);
860 for (i = 0; i < clist->rows; i++)
862 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded)
863 for (child = GTK_CMCTREE_ROW (node)->children; child;
864 child = GTK_CMCTREE_ROW (child)->sibling)
865 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
866 node = GTK_CMCTREE_NODE_NEXT (node);
869 values.foreground = widget->style->fg[GTK_STATE_NORMAL];
870 values.background = widget->style->base[GTK_STATE_NORMAL];
871 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
872 values.line_style = GDK_LINE_SOLID;
873 ctree->lines_gc = gdk_gc_new_with_values (GTK_CMCLIST(widget)->clist_window,
880 if (ctree->line_style == GTK_CMCTREE_LINES_DOTTED)
882 gdk_gc_set_line_attributes (ctree->lines_gc, 1,
883 GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER);
884 gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2);
889 gtk_cmctree_unrealize (GtkWidget *widget)
894 g_return_if_fail (GTK_IS_CMCTREE (widget));
896 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
898 ctree = GTK_CMCTREE (widget);
899 clist = GTK_CMCLIST (widget);
901 if (GTK_WIDGET_REALIZED (widget))
903 GtkCMCTreeNode *node;
904 GtkCMCTreeNode *child;
907 node = GTK_CMCTREE_NODE (clist->row_list);
908 for (i = 0; i < clist->rows; i++)
910 if (GTK_CMCTREE_ROW (node)->children &&
911 !GTK_CMCTREE_ROW (node)->expanded)
912 for (child = GTK_CMCTREE_ROW (node)->children; child;
913 child = GTK_CMCTREE_ROW (child)->sibling)
914 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
915 node = GTK_CMCTREE_NODE_NEXT (node);
919 g_object_unref (ctree->lines_gc);
923 gtk_cmctree_button_press (GtkWidget *widget,
924 GdkEventButton *event)
930 g_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
931 g_return_val_if_fail (event != NULL, FALSE);
933 ctree = GTK_CMCTREE (widget);
934 clist = GTK_CMCLIST (widget);
936 button_actions = clist->button_actions[event->button - 1];
938 if (button_actions == GTK_CMBUTTON_IGNORED)
941 if (event->window == clist->clist_window)
943 GtkCMCTreeNode *work;
952 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column))
955 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
957 if (button_actions & GTK_CMBUTTON_EXPANDS &&
958 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf &&
959 (event->type == GDK_2BUTTON_PRESS ||
960 ctree_is_hot_spot (ctree, work, row, x, y))))
962 if (GTK_CMCTREE_ROW (work)->expanded)
963 gtk_cmctree_collapse (ctree, work);
965 gtk_cmctree_expand (ctree, work);
971 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
975 draw_drag_highlight (GtkCMCList *clist,
976 GtkCMCListRow *dest_row,
977 gint dest_row_number,
978 GtkCMCListDragPos drag_pos)
986 g_return_if_fail (GTK_IS_CMCTREE (clist));
988 ctree = GTK_CMCTREE (clist);
990 level = ((GtkCMCTreeRow *)(dest_row))->level;
992 y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
996 case GTK_CMCLIST_DRAG_NONE:
998 case GTK_CMCLIST_DRAG_AFTER:
999 y += clist->row_height + 1;
1000 case GTK_CMCLIST_DRAG_BEFORE:
1002 if (clist->column[ctree->tree_column].visible)
1003 switch (clist->column[ctree->tree_column].justification)
1005 case GTK_JUSTIFY_CENTER:
1006 case GTK_JUSTIFY_FILL:
1007 case GTK_JUSTIFY_LEFT:
1008 if (ctree->tree_column > 0)
1009 gdk_draw_line (clist->clist_window, clist->xor_gc,
1010 COLUMN_LEFT_XPIXEL(clist, 0), y,
1011 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1)+
1012 clist->column[ctree->tree_column - 1].area.width,
1015 gdk_draw_line (clist->clist_window, clist->xor_gc,
1016 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
1017 ctree->tree_indent * level -
1018 (ctree->tree_indent - PM_SIZE) / 2, y,
1019 GTK_WIDGET (ctree)->allocation.width, y);
1021 case GTK_JUSTIFY_RIGHT:
1022 if (ctree->tree_column < clist->columns - 1)
1023 gdk_draw_line (clist->clist_window, clist->xor_gc,
1024 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1),
1026 COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) +
1027 clist->column[clist->columns - 1].area.width, y);
1029 gdk_draw_line (clist->clist_window, clist->xor_gc,
1030 0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column)
1031 + clist->column[ctree->tree_column].area.width -
1032 ctree->tree_indent * level +
1033 (ctree->tree_indent - PM_SIZE) / 2, y);
1037 gdk_draw_line (clist->clist_window, clist->xor_gc,
1038 0, y, clist->clist_window_width, y);
1040 case GTK_CMCLIST_DRAG_INTO:
1041 y = ROW_TOP_YPIXEL (clist, dest_row_number) + clist->row_height;
1043 if (clist->column[ctree->tree_column].visible)
1044 switch (clist->column[ctree->tree_column].justification)
1046 case GTK_JUSTIFY_CENTER:
1047 case GTK_JUSTIFY_FILL:
1048 case GTK_JUSTIFY_LEFT:
1049 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
1050 ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2;
1052 points[3].x = points[0].x;
1053 points[3].y = y - clist->row_height - 1;
1054 points[1].x = clist->clist_window_width - 1;
1055 points[1].y = points[0].y;
1056 points[2].x = points[1].x;
1057 points[2].y = points[3].y;
1059 for (i = 0; i < 3; i++)
1060 gdk_draw_line (clist->clist_window, clist->xor_gc,
1061 points[i].x, points[i].y,
1062 points[i+1].x, points[i+1].y);
1064 if (ctree->tree_column > 0)
1066 points[0].x = COLUMN_LEFT_XPIXEL(clist,
1067 ctree->tree_column - 1) +
1068 clist->column[ctree->tree_column - 1].area.width ;
1070 points[3].x = points[0].x;
1071 points[3].y = y - clist->row_height - 1;
1073 points[1].y = points[0].y;
1075 points[2].y = points[3].y;
1077 for (i = 0; i < 3; i++)
1078 gdk_draw_line (clist->clist_window, clist->xor_gc,
1079 points[i].x, points[i].y, points[i+1].x,
1083 case GTK_JUSTIFY_RIGHT:
1084 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) -
1085 ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2 +
1086 clist->column[ctree->tree_column].area.width;
1088 points[3].x = points[0].x;
1089 points[3].y = y - clist->row_height - 1;
1091 points[1].y = points[0].y;
1093 points[2].y = points[3].y;
1095 for (i = 0; i < 3; i++)
1096 gdk_draw_line (clist->clist_window, clist->xor_gc,
1097 points[i].x, points[i].y,
1098 points[i+1].x, points[i+1].y);
1100 if (ctree->tree_column < clist->columns - 1)
1102 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column +1);
1104 points[3].x = points[0].x;
1105 points[3].y = y - clist->row_height - 1;
1106 points[1].x = clist->clist_window_width - 1;
1107 points[1].y = points[0].y;
1108 points[2].x = points[1].x;
1109 points[2].y = points[3].y;
1111 for (i = 0; i < 3; i++)
1112 gdk_draw_line (clist->clist_window, clist->xor_gc,
1113 points[i].x, points[i].y,
1114 points[i+1].x, points[i+1].y);
1119 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
1120 0, y - clist->row_height,
1121 clist->clist_window_width - 1, clist->row_height);
1127 draw_cell_pixmap (GdkWindow *window,
1128 GdkRectangle *clip_rectangle,
1142 gdk_gc_set_clip_mask (fg_gc, mask);
1143 gdk_gc_set_clip_origin (fg_gc, x, y);
1145 if (x < clip_rectangle->x)
1147 xsrc = clip_rectangle->x - x;
1149 x = clip_rectangle->x;
1151 if (x + width > clip_rectangle->x + clip_rectangle->width)
1152 width = clip_rectangle->x + clip_rectangle->width - x;
1154 if (y < clip_rectangle->y)
1156 ysrc = clip_rectangle->y - y;
1158 y = clip_rectangle->y;
1160 if (y + height > clip_rectangle->y + clip_rectangle->height)
1161 height = clip_rectangle->y + clip_rectangle->height - y;
1163 if (width > 0 && height > 0)
1164 gdk_draw_drawable (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
1168 gdk_gc_set_clip_rectangle (fg_gc, NULL);
1169 gdk_gc_set_clip_origin (fg_gc, 0, 0);
1172 return x + MAX (width, 0);
1176 get_cell_style (GtkCMCList *clist,
1177 GtkCMCListRow *clist_row,
1186 if ((state == GTK_STATE_NORMAL) &&
1187 (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE))
1188 fg_state = GTK_STATE_INSENSITIVE;
1192 if (clist_row->cell[column].style)
1195 *style = clist_row->cell[column].style;
1197 *fg_gc = clist_row->cell[column].style->fg_gc[fg_state];
1199 if (state == GTK_STATE_SELECTED)
1200 *bg_gc = clist_row->cell[column].style->bg_gc[state];
1202 *bg_gc = clist_row->cell[column].style->base_gc[state];
1205 else if (clist_row->style)
1208 *style = clist_row->style;
1210 *fg_gc = clist_row->style->fg_gc[fg_state];
1212 if (state == GTK_STATE_SELECTED)
1213 *bg_gc = clist_row->style->bg_gc[state];
1215 *bg_gc = clist_row->style->base_gc[state];
1221 *style = GTK_WIDGET (clist)->style;
1223 *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state];
1225 if (state == GTK_STATE_SELECTED)
1226 *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
1228 *bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
1231 if (state != GTK_STATE_SELECTED)
1233 if (fg_gc && clist_row->fg_set)
1234 *fg_gc = clist->fg_gc;
1235 if (bg_gc && clist_row->bg_set)
1236 *bg_gc = clist->bg_gc;
1242 gtk_cmctree_draw_expander (GtkCMCTree *ctree,
1243 GtkCMCTreeRow *ctree_row,
1245 GdkRectangle *clip_rectangle,
1250 gint justification_factor;
1253 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
1256 clist = GTK_CMCLIST (ctree);
1257 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
1258 justification_factor = -1;
1260 justification_factor = 1;
1261 y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
1262 (clip_rectangle->height + 1) % 2);
1264 if (!ctree_row->children)
1266 switch (ctree->expander_style)
1268 case GTK_CMCTREE_EXPANDER_NONE:
1270 case GTK_CMCTREE_EXPANDER_TRIANGLE:
1271 return x + justification_factor * (PM_SIZE + 3);
1272 case GTK_CMCTREE_EXPANDER_SQUARE:
1273 case GTK_CMCTREE_EXPANDER_CIRCULAR:
1274 return x + justification_factor * (PM_SIZE + 1);
1278 gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], clip_rectangle);
1279 gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], clip_rectangle);
1281 switch (ctree->expander_style)
1283 case GTK_CMCTREE_EXPANDER_NONE:
1285 case GTK_CMCTREE_EXPANDER_TRIANGLE:
1286 if (ctree_row->expanded)
1289 points[0].y = y + (PM_SIZE + 2) / 6;
1290 points[1].x = points[0].x + justification_factor * (PM_SIZE + 2);
1291 points[1].y = points[0].y;
1292 points[2].x = (points[0].x +
1293 justification_factor * (PM_SIZE + 2) / 2);
1294 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
1298 points[0].x = x + justification_factor * ((PM_SIZE + 2) / 6 + 2);
1299 points[0].y = y - 1;
1300 points[1].x = points[0].x;
1301 points[1].y = points[0].y + (PM_SIZE + 2);
1302 points[2].x = (points[0].x +
1303 justification_factor * (2 * (PM_SIZE + 2) / 3 - 1));
1304 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
1307 gdk_draw_polygon (clist->clist_window, style->base_gc[GTK_STATE_NORMAL],
1309 gdk_draw_polygon (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1312 x += justification_factor * (PM_SIZE + 3);
1314 case GTK_CMCTREE_EXPANDER_SQUARE:
1315 case GTK_CMCTREE_EXPANDER_CIRCULAR:
1316 if (justification_factor == -1)
1317 x += justification_factor * (PM_SIZE + 1);
1319 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_CIRCULAR)
1321 gdk_draw_arc (clist->clist_window, style->base_gc[GTK_STATE_NORMAL],
1322 TRUE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64);
1323 gdk_draw_arc (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1324 FALSE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64);
1328 gdk_draw_rectangle (clist->clist_window,
1329 style->base_gc[GTK_STATE_NORMAL], TRUE,
1330 x, y, PM_SIZE, PM_SIZE);
1331 gdk_draw_rectangle (clist->clist_window,
1332 style->fg_gc[GTK_STATE_NORMAL], FALSE,
1333 x, y, PM_SIZE, PM_SIZE);
1336 gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1337 x + 2, y + PM_SIZE / 2, x + PM_SIZE - 2, y + PM_SIZE / 2);
1339 if (!ctree_row->expanded)
1340 gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1341 x + PM_SIZE / 2, y + 2,
1342 x + PM_SIZE / 2, y + PM_SIZE - 2);
1344 if (justification_factor == 1)
1345 x += justification_factor * (PM_SIZE + 1);
1349 gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], NULL);
1350 gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], NULL);
1357 gtk_cmctree_draw_lines (GtkCMCTree *ctree,
1358 GtkCMCTreeRow *ctree_row,
1362 GdkRectangle *clip_rectangle,
1363 GdkRectangle *cell_rectangle,
1364 GdkRectangle *crect,
1369 GtkCMCTreeNode *node;
1370 GtkCMCTreeNode *parent;
1371 GdkRectangle tree_rectangle;
1372 GdkRectangle tc_rectangle;
1383 gint justification_factor;
1385 clist = GTK_CMCLIST (ctree);
1386 ycenter = clip_rectangle->y + (clip_rectangle->height / 2);
1387 justify_right = (clist->column[column].justification == GTK_JUSTIFY_RIGHT);
1391 offset = (clip_rectangle->x + clip_rectangle->width - 1 -
1392 ctree->tree_indent * (ctree_row->level - 1));
1393 justification_factor = -1;
1397 offset = clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
1398 justification_factor = 1;
1401 switch (ctree->line_style)
1403 case GTK_CMCTREE_LINES_NONE:
1405 case GTK_CMCTREE_LINES_TABBED:
1406 xcenter = offset + justification_factor * TAB_SIZE;
1408 column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) +
1409 clist->column[ctree->tree_column].area.width +
1411 column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) -
1412 COLUMN_INSET - CELL_SPACING);
1416 tree_rectangle.y = crect->y;
1417 tree_rectangle.height = crect->height;
1421 tree_rectangle.x = xcenter;
1422 tree_rectangle.width = column_right - xcenter;
1426 tree_rectangle.x = column_left;
1427 tree_rectangle.width = xcenter - column_left;
1430 if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle))
1432 offset += justification_factor * 3;
1437 gdk_gc_set_clip_rectangle (ctree->lines_gc, crect);
1439 next_level = ctree_row->level;
1441 if (!ctree_row->sibling || (ctree_row->children && ctree_row->expanded))
1443 node = gtk_cmctree_find_node_ptr (ctree, ctree_row);
1444 if (GTK_CMCTREE_NODE_NEXT (node))
1445 next_level = GTK_CMCTREE_ROW (GTK_CMCTREE_NODE_NEXT (node))->level;
1450 if (ctree->tree_indent > 0)
1452 node = ctree_row->parent;
1455 xcenter -= (justification_factor * ctree->tree_indent);
1457 if ((justify_right && xcenter < column_left) ||
1458 (!justify_right && xcenter > column_right))
1460 node = GTK_CMCTREE_ROW (node)->parent;
1464 tree_rectangle.y = cell_rectangle->y;
1465 tree_rectangle.height = cell_rectangle->height;
1468 tree_rectangle.x = MAX (xcenter - ctree->tree_indent + 1,
1470 tree_rectangle.width = MIN (xcenter - column_left,
1471 ctree->tree_indent);
1475 tree_rectangle.x = xcenter;
1476 tree_rectangle.width = MIN (column_right - xcenter,
1477 ctree->tree_indent);
1480 if (!area || gdk_rectangle_intersect (area, &tree_rectangle,
1483 get_cell_style (clist, >K_CMCTREE_ROW (node)->row,
1484 state, column, NULL, NULL, &bg_gc);
1486 if (bg_gc == clist->bg_gc)
1487 gdk_gc_set_foreground
1488 (clist->bg_gc, >K_CMCTREE_ROW (node)->row.background);
1491 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1494 tree_rectangle.width,
1495 tree_rectangle.height);
1497 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1501 tc_rectangle.height);
1503 if (next_level > GTK_CMCTREE_ROW (node)->level)
1504 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1506 xcenter, crect->y + crect->height);
1511 offset_x = MIN (ctree->tree_indent, 2 * TAB_SIZE);
1512 width = offset_x / 2 + offset_x % 2;
1514 parent = GTK_CMCTREE_ROW (node)->parent;
1516 tree_rectangle.y = ycenter;
1517 tree_rectangle.height = (cell_rectangle->y - ycenter +
1518 cell_rectangle->height);
1522 tree_rectangle.x = MAX(xcenter + 1 - width, column_left);
1523 tree_rectangle.width = MIN (xcenter + 1 - column_left,
1528 tree_rectangle.x = xcenter;
1529 tree_rectangle.width = MIN (column_right - xcenter,
1534 gdk_rectangle_intersect (area, &tree_rectangle,
1539 get_cell_style (clist, >K_CMCTREE_ROW (parent)->row,
1540 state, column, NULL, NULL, &bg_gc);
1541 if (bg_gc == clist->bg_gc)
1542 gdk_gc_set_foreground
1544 >K_CMCTREE_ROW (parent)->row.background);
1546 else if (state == GTK_STATE_SELECTED)
1547 bg_gc = style->base_gc[state];
1549 bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
1552 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1555 tree_rectangle.width,
1556 tree_rectangle.height);
1558 gdk_draw_rectangle (clist->clist_window,
1563 tc_rectangle.height);
1566 get_cell_style (clist, >K_CMCTREE_ROW (node)->row,
1567 state, column, NULL, NULL, &bg_gc);
1568 if (bg_gc == clist->bg_gc)
1569 gdk_gc_set_foreground
1570 (clist->bg_gc, >K_CMCTREE_ROW (node)->row.background);
1572 gdk_gc_set_clip_rectangle (bg_gc, crect);
1573 gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
1574 xcenter - (justify_right * offset_x),
1576 offset_x, clist->row_height,
1577 (180 + (justify_right * 90)) * 64, 90 * 64);
1578 gdk_gc_set_clip_rectangle (bg_gc, NULL);
1580 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1581 xcenter, cell_rectangle->y, xcenter, ycenter);
1584 gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1585 xcenter - offset_x, cell_rectangle->y,
1586 offset_x, clist->row_height,
1589 gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1590 xcenter, cell_rectangle->y,
1591 offset_x, clist->row_height,
1594 node = GTK_CMCTREE_ROW (node)->parent;
1598 if (state != GTK_STATE_SELECTED)
1600 tree_rectangle.y = clip_rectangle->y;
1601 tree_rectangle.height = clip_rectangle->height;
1602 tree_rectangle.width = COLUMN_INSET + CELL_SPACING +
1603 MIN (clist->column[ctree->tree_column].area.width + COLUMN_INSET,
1607 tree_rectangle.x = MAX (xcenter + 1, column_left);
1609 tree_rectangle.x = column_left;
1612 gdk_draw_rectangle (clist->clist_window,
1614 (ctree)->style->base_gc[GTK_STATE_NORMAL],
1618 tree_rectangle.width,
1619 tree_rectangle.height);
1620 else if (gdk_rectangle_intersect (area, &tree_rectangle,
1622 gdk_draw_rectangle (clist->clist_window,
1624 (ctree)->style->base_gc[GTK_STATE_NORMAL],
1629 tc_rectangle.height);
1632 xcenter = offset + (justification_factor * ctree->tree_indent / 2);
1634 get_cell_style (clist, &ctree_row->row, state, column, NULL, NULL,
1636 if (bg_gc == clist->bg_gc)
1637 gdk_gc_set_foreground (clist->bg_gc, &ctree_row->row.background);
1639 gdk_gc_set_clip_rectangle (bg_gc, crect);
1640 if (ctree_row->is_leaf)
1644 points[0].x = offset + justification_factor * TAB_SIZE;
1645 points[0].y = cell_rectangle->y;
1647 points[1].x = points[0].x - justification_factor * 4;
1648 points[1].y = points[0].y;
1650 points[2].x = points[1].x - justification_factor * 2;
1651 points[2].y = points[1].y + 3;
1653 points[3].x = points[2].x;
1654 points[3].y = points[2].y + clist->row_height - 5;
1656 points[4].x = points[3].x + justification_factor * 2;
1657 points[4].y = points[3].y + 3;
1659 points[5].x = points[4].x + justification_factor * 4;
1660 points[5].y = points[4].y;
1662 gdk_draw_polygon (clist->clist_window, bg_gc, TRUE, points, 6);
1663 gdk_draw_lines (clist->clist_window, ctree->lines_gc, points, 6);
1667 gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
1668 offset - (justify_right * 2 * TAB_SIZE),
1670 2 * TAB_SIZE, clist->row_height,
1671 (90 + (180 * justify_right)) * 64, 180 * 64);
1672 gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1673 offset - (justify_right * 2 * TAB_SIZE),
1675 2 * TAB_SIZE, clist->row_height,
1676 (90 + (180 * justify_right)) * 64, 180 * 64);
1678 gdk_gc_set_clip_rectangle (bg_gc, NULL);
1679 gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1681 offset += justification_factor * 3;
1684 xcenter = offset + justification_factor * PM_SIZE / 2;
1688 tree_rectangle.y = crect->y;
1689 tree_rectangle.height = crect->height;
1693 tree_rectangle.x = xcenter - PM_SIZE / 2 - 2;
1694 tree_rectangle.width = (clip_rectangle->x +
1695 clip_rectangle->width -tree_rectangle.x);
1699 tree_rectangle.x = clip_rectangle->x + PM_SIZE / 2;
1700 tree_rectangle.width = (xcenter + PM_SIZE / 2 + 2 -
1704 if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle))
1710 if (ctree->line_style == GTK_CMCTREE_LINES_DOTTED)
1712 offset_x += abs((clip_rectangle->x + clist->hoffset) % 2);
1713 offset_y = abs((cell_rectangle->y + clist->voffset) % 2);
1716 clip_rectangle->y--;
1717 clip_rectangle->height++;
1718 gdk_gc_set_clip_rectangle (ctree->lines_gc, clip_rectangle);
1719 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1721 (ctree->show_stub || clist->row_list->data != ctree_row) ?
1722 cell_rectangle->y + offset_y : ycenter,
1724 (ctree_row->sibling) ? crect->y +crect->height : ycenter);
1726 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1727 xcenter + (justification_factor * offset_x), ycenter,
1728 xcenter + (justification_factor * (PM_SIZE / 2 + 2)),
1731 node = ctree_row->parent;
1734 xcenter -= (justification_factor * ctree->tree_indent);
1736 if (GTK_CMCTREE_ROW (node)->sibling)
1737 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1738 xcenter, cell_rectangle->y + offset_y,
1739 xcenter, crect->y + crect->height);
1740 node = GTK_CMCTREE_ROW (node)->parent;
1742 gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1743 clip_rectangle->y++;
1744 clip_rectangle->height--;
1751 draw_row (GtkCMCList *clist,
1754 GtkCMCListRow *clist_row)
1758 GdkRectangle *crect;
1759 GdkRectangle row_rectangle;
1760 GdkRectangle cell_rectangle;
1761 GdkRectangle clip_rectangle;
1762 GdkRectangle intersect_rectangle;
1764 gint column_left = 0;
1765 gint column_right = 0;
1770 g_return_if_fail (clist != NULL);
1772 /* bail now if we arn't drawable yet */
1773 if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows)
1776 widget = GTK_WIDGET (clist);
1777 ctree = GTK_CMCTREE (clist);
1779 /* if the function is passed the pointer to the row instead of null,
1780 * it avoids this expensive lookup */
1782 clist_row = (g_list_nth (clist->row_list, row))->data;
1784 /* rectangle of the entire row */
1785 row_rectangle.x = 0;
1786 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
1787 row_rectangle.width = clist->clist_window_width;
1788 row_rectangle.height = clist->row_height;
1790 /* rectangle of the cell spacing above the row */
1791 cell_rectangle.x = 0;
1792 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
1793 cell_rectangle.width = row_rectangle.width;
1794 cell_rectangle.height = CELL_SPACING;
1796 /* rectangle used to clip drawing operations, its y and height
1797 * positions only need to be set once, so we set them once here.
1798 * the x and width are set withing the drawing loop below once per
1800 clip_rectangle.y = row_rectangle.y;
1801 clip_rectangle.height = row_rectangle.height;
1803 if (clist_row->state == GTK_STATE_NORMAL)
1805 if (clist_row->fg_set)
1806 gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
1807 if (clist_row->bg_set)
1808 gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
1811 state = clist_row->state;
1813 gdk_gc_set_foreground (ctree->lines_gc,
1814 &widget->style->fg[clist_row->state]);
1816 /* draw the cell borders */
1819 crect = &intersect_rectangle;
1821 if (gdk_rectangle_intersect (area, &cell_rectangle, crect))
1822 gdk_draw_rectangle (clist->clist_window,
1823 widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1824 crect->x, crect->y, crect->width, crect->height);
1828 crect = &cell_rectangle;
1830 gdk_draw_rectangle (clist->clist_window,
1831 widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1832 crect->x, crect->y, crect->width, crect->height);
1835 /* horizontal black lines */
1836 if (ctree->line_style == GTK_CMCTREE_LINES_TABBED)
1839 column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) +
1840 clist->column[ctree->tree_column].area.width +
1842 column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) -
1843 COLUMN_INSET - (ctree->tree_column != 0) * CELL_SPACING);
1845 switch (clist->column[ctree->tree_column].justification)
1847 case GTK_JUSTIFY_CENTER:
1848 case GTK_JUSTIFY_FILL:
1849 case GTK_JUSTIFY_LEFT:
1850 offset = (column_left + ctree->tree_indent *
1851 (((GtkCMCTreeRow *)clist_row)->level - 1));
1853 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1854 MIN (offset + TAB_SIZE, column_right),
1856 clist->clist_window_width, cell_rectangle.y);
1858 case GTK_JUSTIFY_RIGHT:
1859 offset = (column_right - 1 - ctree->tree_indent *
1860 (((GtkCMCTreeRow *)clist_row)->level - 1));
1862 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1863 -1, cell_rectangle.y,
1864 MAX (offset - TAB_SIZE, column_left),
1870 /* the last row has to clear its bottom cell spacing too */
1871 if (clist_row == clist->row_list_end->data)
1873 cell_rectangle.y += clist->row_height + CELL_SPACING;
1875 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
1877 gdk_draw_rectangle (clist->clist_window,
1878 widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1879 crect->x, crect->y, crect->width, crect->height);
1881 /* horizontal black lines */
1882 if (ctree->line_style == GTK_CMCTREE_LINES_TABBED)
1884 switch (clist->column[ctree->tree_column].justification)
1886 case GTK_JUSTIFY_CENTER:
1887 case GTK_JUSTIFY_FILL:
1888 case GTK_JUSTIFY_LEFT:
1889 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1890 MIN (column_left + TAB_SIZE + COLUMN_INSET +
1891 (((GtkCMCTreeRow *)clist_row)->level > 1) *
1892 MIN (ctree->tree_indent / 2, TAB_SIZE),
1895 clist->clist_window_width, cell_rectangle.y);
1897 case GTK_JUSTIFY_RIGHT:
1898 gdk_draw_line (clist->clist_window, ctree->lines_gc,
1899 -1, cell_rectangle.y,
1900 MAX (column_right - TAB_SIZE - 1 -
1902 (((GtkCMCTreeRow *)clist_row)->level > 1) *
1903 MIN (ctree->tree_indent / 2, TAB_SIZE),
1904 column_left - 1), cell_rectangle.y);
1911 for (last_column = clist->columns - 1;
1912 last_column >= 0 && !clist->column[last_column].visible; last_column--)
1915 /* iterate and draw all the columns (row cells) and draw their contents */
1916 for (i = 0; i < clist->columns; i++)
1921 PangoLayout *layout = NULL;
1922 PangoRectangle logical_rect;
1930 if (!clist->column[i].visible)
1933 get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
1935 /* calculate clipping region */
1936 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
1937 clip_rectangle.width = clist->column[i].area.width;
1939 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
1940 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
1941 (1 + (i == last_column)) * CELL_SPACING);
1942 cell_rectangle.y = clip_rectangle.y;
1943 cell_rectangle.height = clip_rectangle.height;
1948 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
1949 &intersect_rectangle))
1951 if (i != ctree->tree_column)
1956 gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1957 crect->x, crect->y, crect->width, crect->height);
1960 layout = _gtk_cmclist_create_cell_layout (clist, clist_row, i);
1963 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1964 width = logical_rect.width;
1969 switch (clist_row->cell[i].type)
1971 case GTK_CMCELL_PIXMAP:
1972 gdk_drawable_get_size
1973 (GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, &pixmap_width,
1975 width += pixmap_width;
1977 case GTK_CMCELL_PIXTEXT:
1978 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap)
1980 gdk_drawable_get_size
1981 (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap,
1982 &pixmap_width, &height);
1983 width += pixmap_width;
1986 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text &&
1987 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap)
1988 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
1990 if (i == ctree->tree_column)
1991 width += (ctree->tree_indent *
1992 ((GtkCMCTreeRow *)clist_row)->level);
1998 switch (clist->column[i].justification)
2000 case GTK_JUSTIFY_LEFT:
2001 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
2003 case GTK_JUSTIFY_RIGHT:
2004 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
2005 clip_rectangle.width - width);
2007 case GTK_JUSTIFY_CENTER:
2008 case GTK_JUSTIFY_FILL:
2009 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
2010 (clip_rectangle.width / 2) - (width / 2));
2014 if (i != ctree->tree_column)
2016 offset += clist_row->cell[i].horizontal;
2017 switch (clist_row->cell[i].type)
2019 case GTK_CMCELL_PIXMAP:
2021 (clist->clist_window, &clip_rectangle, fg_gc,
2022 GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap,
2023 GTK_CMCELL_PIXMAP (clist_row->cell[i])->mask,
2025 clip_rectangle.y + clist_row->cell[i].vertical +
2026 (clip_rectangle.height - height) / 2,
2027 pixmap_width, height);
2029 case GTK_CMCELL_PIXTEXT:
2030 offset = draw_cell_pixmap
2031 (clist->clist_window, &clip_rectangle, fg_gc,
2032 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap,
2033 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask,
2035 clip_rectangle.y + clist_row->cell[i].vertical +
2036 (clip_rectangle.height - height) / 2,
2037 pixmap_width, height);
2038 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
2041 case GTK_CMCELL_TEXT:
2044 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
2046 gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
2047 gdk_draw_layout (clist->clist_window, fg_gc,
2049 row_rectangle.y + row_center_offset + clist_row->cell[i].vertical,
2051 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2052 g_object_unref (G_OBJECT (layout));
2062 if (bg_gc == clist->bg_gc)
2063 gdk_gc_set_background (ctree->lines_gc, &clist_row->background);
2065 /* draw ctree->tree_column */
2066 cell_rectangle.y -= CELL_SPACING;
2067 cell_rectangle.height += CELL_SPACING;
2069 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
2070 &intersect_rectangle))
2073 g_object_unref (G_OBJECT (layout));
2078 offset = gtk_cmctree_draw_lines (ctree, (GtkCMCTreeRow *)clist_row, row, i,
2079 state, &clip_rectangle, &cell_rectangle,
2080 crect, area, style);
2083 offset = gtk_cmctree_draw_expander (ctree, (GtkCMCTreeRow *)clist_row,
2084 style, &clip_rectangle, offset);
2086 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
2087 offset -= ctree->tree_spacing;
2089 offset += ctree->tree_spacing;
2091 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
2092 offset -= (pixmap_width + clist_row->cell[i].horizontal);
2094 offset += clist_row->cell[i].horizontal;
2096 old_offset = offset;
2097 offset = draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
2098 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap,
2099 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask,
2101 clip_rectangle.y + clist_row->cell[i].vertical
2102 + (clip_rectangle.height - height) / 2,
2103 pixmap_width, height);
2107 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
2109 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
2111 offset = (old_offset - string_width);
2112 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap)
2113 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
2117 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap)
2118 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
2121 gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
2122 gdk_draw_layout (clist->clist_window, fg_gc,
2124 row_rectangle.y + row_center_offset + clist_row->cell[i].vertical,
2127 g_object_unref (G_OBJECT (layout));
2129 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2132 /* draw focus rectangle */
2133 if (clist->focus_row == row &&
2134 GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS (widget))
2137 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2138 row_rectangle.x, row_rectangle.y,
2139 row_rectangle.width - 1, row_rectangle.height - 1);
2140 else if (gdk_rectangle_intersect (area, &row_rectangle,
2141 &intersect_rectangle))
2143 gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
2144 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2145 row_rectangle.x, row_rectangle.y,
2146 row_rectangle.width - 1,
2147 row_rectangle.height - 1);
2148 gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
2154 tree_draw_node (GtkCMCTree *ctree,
2155 GtkCMCTreeNode *node)
2159 clist = GTK_CMCLIST (ctree);
2161 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node))
2163 GtkCMCTreeNode *work;
2166 work = GTK_CMCTREE_NODE (clist->row_list);
2167 while (work && work != node)
2169 work = GTK_CMCTREE_NODE_NEXT (work);
2172 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2173 GTK_CMCLIST_GET_CLASS (clist)->draw_row
2174 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node));
2178 static GtkCMCTreeNode *
2179 gtk_cmctree_last_visible (GtkCMCTree *ctree,
2180 GtkCMCTreeNode *node)
2182 GtkCMCTreeNode *work;
2187 work = GTK_CMCTREE_ROW (node)->children;
2189 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
2192 while (GTK_CMCTREE_ROW (work)->sibling)
2193 work = GTK_CMCTREE_ROW (work)->sibling;
2195 return gtk_cmctree_last_visible (ctree, work);
2199 gtk_cmctree_link (GtkCMCTree *ctree,
2200 GtkCMCTreeNode *node,
2201 GtkCMCTreeNode *parent,
2202 GtkCMCTreeNode *sibling,
2203 gboolean update_focus_row)
2209 gboolean visible = FALSE;
2213 g_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
2214 g_return_if_fail (node != NULL);
2215 g_return_if_fail (node != sibling);
2216 g_return_if_fail (node != parent);
2218 clist = GTK_CMCLIST (ctree);
2220 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
2222 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2224 g_list_free (clist->undo_selection);
2225 g_list_free (clist->undo_unselection);
2226 clist->undo_selection = NULL;
2227 clist->undo_unselection = NULL;
2230 for (rows = 1, list_end = (GList *)node; list_end->next;
2231 list_end = list_end->next)
2234 GTK_CMCTREE_ROW (node)->parent = parent;
2235 GTK_CMCTREE_ROW (node)->sibling = sibling;
2237 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
2238 GTK_CMCTREE_ROW (parent)->expanded)))
2241 clist->rows += rows;
2245 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
2247 work = clist->row_list;
2251 if (work != (GList *)sibling)
2253 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
2254 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
2255 GTK_CMCTREE_ROW (work)->sibling = node;
2258 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
2259 clist->row_list = (GList *) node;
2260 if (GTK_CMCTREE_NODE_PREV (sibling) &&
2261 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling)
2263 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
2264 list->next = (GList *)node;
2267 list = (GList *)node;
2268 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
2269 list_end->next = (GList *)sibling;
2270 list = (GList *)sibling;
2271 list->prev = list_end;
2272 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
2273 GTK_CMCTREE_ROW (parent)->children = node;
2280 while (GTK_CMCTREE_ROW (work)->sibling)
2281 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
2282 GTK_CMCTREE_ROW (work)->sibling = node;
2284 /* find last visible child of sibling */
2285 work = (GList *) gtk_cmctree_last_visible (ctree,
2286 GTK_CMCTREE_NODE (work));
2288 list_end->next = work->next;
2290 list = work->next->prev = list_end;
2291 work->next = (GList *)node;
2292 list = (GList *)node;
2299 GTK_CMCTREE_ROW (parent)->children = node;
2300 list = (GList *)node;
2301 list->prev = (GList *)parent;
2302 if (GTK_CMCTREE_ROW (parent)->expanded)
2304 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
2305 if (GTK_CMCTREE_NODE_NEXT(parent))
2307 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
2308 list->prev = list_end;
2310 list = (GList *)parent;
2311 list->next = (GList *)node;
2314 list_end->next = NULL;
2318 clist->row_list = (GList *)node;
2319 list = (GList *)node;
2321 list_end->next = NULL;
2326 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL);
2328 if (clist->row_list_end == NULL ||
2329 clist->row_list_end->next == (GList *)node)
2330 clist->row_list_end = list_end;
2332 if (visible && update_focus_row)
2336 pos = g_list_position (clist->row_list, (GList *)node);
2338 if (pos <= clist->focus_row)
2340 clist->focus_row += rows;
2341 clist->undo_anchor = clist->focus_row;
2347 gtk_cmctree_unlink (GtkCMCTree *ctree,
2348 GtkCMCTreeNode *node,
2349 gboolean update_focus_row)
2355 GtkCMCTreeNode *work;
2356 GtkCMCTreeNode *parent;
2359 g_return_if_fail (GTK_IS_CMCTREE (ctree));
2360 g_return_if_fail (node != NULL);
2362 clist = GTK_CMCLIST (ctree);
2364 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
2366 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2368 g_list_free (clist->undo_selection);
2369 g_list_free (clist->undo_unselection);
2370 clist->undo_selection = NULL;
2371 clist->undo_unselection = NULL;
2374 visible = gtk_cmctree_is_viewable (ctree, node);
2376 /* clist->row_list_end unlinked ? */
2378 (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
2379 (GTK_CMCTREE_ROW (node)->children &&
2380 gtk_cmctree_is_ancestor (ctree, node,
2381 GTK_CMCTREE_NODE (clist->row_list_end)))))
2382 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
2386 level = GTK_CMCTREE_ROW (node)->level;
2387 work = GTK_CMCTREE_NODE_NEXT (node);
2388 while (work && GTK_CMCTREE_ROW (work)->level > level)
2390 work = GTK_CMCTREE_NODE_NEXT (work);
2396 clist->rows -= (rows + 1);
2398 if (update_focus_row)
2402 pos = g_list_position (clist->row_list, (GList *)node);
2403 if (pos + rows < clist->focus_row)
2404 clist->focus_row -= (rows + 1);
2405 else if (pos <= clist->focus_row)
2407 if (!GTK_CMCTREE_ROW (node)->sibling)
2408 clist->focus_row = MAX (pos - 1, 0);
2410 clist->focus_row = pos;
2412 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
2414 clist->undo_anchor = clist->focus_row;
2420 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2422 list = (GList *)work;
2423 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
2426 if (GTK_CMCTREE_NODE_PREV (node) &&
2427 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node)
2429 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
2430 list->next = (GList *)work;
2434 parent = GTK_CMCTREE_ROW (node)->parent;
2437 if (GTK_CMCTREE_ROW (parent)->children == node)
2439 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
2440 if (!GTK_CMCTREE_ROW (parent)->children)
2441 gtk_cmctree_collapse (ctree, parent);
2445 GtkCMCTreeNode *sibling;
2447 sibling = GTK_CMCTREE_ROW (parent)->children;
2448 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
2449 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
2450 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
2455 if (clist->row_list == (GList *)node)
2456 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
2459 GtkCMCTreeNode *sibling;
2461 sibling = GTK_CMCTREE_NODE (clist->row_list);
2462 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
2463 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
2464 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
2470 real_row_move (GtkCMCList *clist,
2475 GtkCMCTreeNode *node;
2477 g_return_if_fail (GTK_IS_CMCTREE (clist));
2479 if (GTK_CMCLIST_AUTO_SORT (clist))
2482 if (source_row < 0 || source_row >= clist->rows ||
2483 dest_row < 0 || dest_row >= clist->rows ||
2484 source_row == dest_row)
2487 ctree = GTK_CMCTREE (clist);
2488 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row));
2490 if (source_row < dest_row)
2492 GtkCMCTreeNode *work;
2495 work = GTK_CMCTREE_ROW (node)->children;
2497 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level)
2499 work = GTK_CMCTREE_NODE_NEXT (work);
2503 if (dest_row > clist->rows)
2504 dest_row = clist->rows;
2507 if (dest_row < clist->rows)
2509 GtkCMCTreeNode *sibling;
2511 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row));
2512 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling);
2515 gtk_cmctree_move (ctree, node, NULL, NULL);
2519 real_tree_move (GtkCMCTree *ctree,
2520 GtkCMCTreeNode *node,
2521 GtkCMCTreeNode *new_parent,
2522 GtkCMCTreeNode *new_sibling)
2525 GtkCMCTreeNode *work;
2526 gboolean visible = FALSE;
2528 g_return_if_fail (ctree != NULL);
2529 g_return_if_fail (node != NULL);
2530 g_return_if_fail (!new_sibling ||
2531 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
2533 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
2536 /* new_parent != child of child */
2537 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
2541 clist = GTK_CMCLIST (ctree);
2543 visible = gtk_cmctree_is_viewable (ctree, node);
2545 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
2547 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2549 g_list_free (clist->undo_selection);
2550 g_list_free (clist->undo_unselection);
2551 clist->undo_selection = NULL;
2552 clist->undo_unselection = NULL;
2555 if (GTK_CMCLIST_AUTO_SORT (clist))
2557 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
2561 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
2563 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
2565 while (new_sibling && clist->compare
2566 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
2567 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
2570 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
2571 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
2574 gtk_cmclist_freeze (clist);
2577 if (gtk_cmctree_is_viewable (ctree, node))
2578 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2580 gtk_cmctree_unlink (ctree, node, FALSE);
2581 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE);
2585 while (work && !gtk_cmctree_is_viewable (ctree, work))
2586 work = GTK_CMCTREE_ROW (work)->parent;
2587 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2588 clist->undo_anchor = clist->focus_row;
2591 if (clist->column[ctree->tree_column].auto_resize &&
2592 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
2593 (visible || gtk_cmctree_is_viewable (ctree, node)))
2594 gtk_cmclist_set_column_width
2595 (clist, ctree->tree_column,
2596 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
2598 gtk_cmclist_thaw (clist);
2602 change_focus_row_expansion (GtkCMCTree *ctree,
2603 GtkCMCTreeExpansionType action)
2606 GtkCMCTreeNode *node;
2608 g_return_if_fail (GTK_IS_CMCTREE (ctree));
2610 clist = GTK_CMCLIST (ctree);
2612 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
2613 GTK_WIDGET_HAS_GRAB (ctree))
2617 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
2618 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
2623 case GTK_CMCTREE_EXPANSION_EXPAND:
2624 gtk_cmctree_expand (ctree, node);
2626 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
2627 gtk_cmctree_expand_recursive (ctree, node);
2629 case GTK_CMCTREE_EXPANSION_COLLAPSE:
2630 gtk_cmctree_collapse (ctree, node);
2632 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
2633 gtk_cmctree_collapse_recursive (ctree, node);
2635 case GTK_CMCTREE_EXPANSION_TOGGLE:
2636 gtk_cmctree_toggle_expansion (ctree, node);
2638 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
2639 gtk_cmctree_toggle_expansion_recursive (ctree, node);
2645 real_tree_expand (GtkCMCTree *ctree,
2646 GtkCMCTreeNode *node)
2649 GtkCMCTreeNode *work;
2650 GtkRequisition requisition;
2653 g_return_if_fail (GTK_IS_CMCTREE (ctree));
2655 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
2658 clist = GTK_CMCLIST (ctree);
2660 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2662 GTK_CMCTREE_ROW (node)->expanded = TRUE;
2664 visible = gtk_cmctree_is_viewable (ctree, node);
2665 /* get cell width if tree_column is auto resized */
2666 if (visible && clist->column[ctree->tree_column].auto_resize &&
2667 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2668 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2669 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2671 /* unref/unset closed pixmap */
2672 if (GTK_CMCELL_PIXTEXT
2673 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
2677 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
2680 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
2682 if (GTK_CMCELL_PIXTEXT
2683 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
2687 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
2689 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
2693 /* set/ref opened pixmap */
2694 if (GTK_CMCTREE_ROW (node)->pixmap_opened)
2697 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap =
2698 g_object_ref (GTK_CMCTREE_ROW (node)->pixmap_opened);
2700 if (GTK_CMCTREE_ROW (node)->mask_opened)
2702 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask =
2703 g_object_ref (GTK_CMCTREE_ROW (node)->mask_opened);
2707 work = GTK_CMCTREE_ROW (node)->children;
2710 GList *list = (GList *)work;
2711 gint *cell_width = NULL;
2716 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2718 cell_width = g_new0 (gint, clist->columns);
2719 if (clist->column[ctree->tree_column].auto_resize)
2720 cell_width[ctree->tree_column] = requisition.width;
2724 /* search maximum cell widths of auto_resize columns */
2725 for (i = 0; i < clist->columns; i++)
2726 if (clist->column[i].auto_resize)
2728 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2729 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
2730 cell_width[i] = MAX (requisition.width, cell_width[i]);
2733 list = (GList *)work;
2734 work = GTK_CMCTREE_NODE_NEXT (work);
2741 list = (GList *)work;
2742 work = GTK_CMCTREE_NODE_NEXT (work);
2746 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2748 if (GTK_CMCTREE_NODE_NEXT (node))
2752 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2753 tmp_list->prev = list;
2756 clist->row_list_end = list;
2758 list = (GList *)node;
2759 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
2763 /* resize auto_resize columns if needed */
2764 for (i = 0; i < clist->columns; i++)
2765 if (clist->column[i].auto_resize &&
2766 cell_width[i] > clist->column[i].width)
2767 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
2768 g_free (cell_width);
2770 /* update focus_row position */
2771 row = g_list_position (clist->row_list, (GList *)node);
2772 if (row < clist->focus_row)
2773 clist->focus_row += tmp;
2776 CLIST_REFRESH (clist);
2779 else if (visible && clist->column[ctree->tree_column].auto_resize)
2780 /* resize tree_column if needed */
2781 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2786 real_tree_collapse (GtkCMCTree *ctree,
2787 GtkCMCTreeNode *node)
2790 GtkCMCTreeNode *work;
2791 GtkRequisition requisition;
2795 g_return_if_fail (GTK_IS_CMCTREE (ctree));
2797 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
2798 GTK_CMCTREE_ROW (node)->is_leaf)
2801 clist = GTK_CMCLIST (ctree);
2803 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2805 GTK_CMCTREE_ROW (node)->expanded = FALSE;
2806 level = GTK_CMCTREE_ROW (node)->level;
2808 visible = gtk_cmctree_is_viewable (ctree, node);
2809 /* get cell width if tree_column is auto resized */
2810 if (visible && clist->column[ctree->tree_column].auto_resize &&
2811 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2812 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2813 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2815 /* unref/unset opened pixmap */
2816 if (GTK_CMCELL_PIXTEXT
2817 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
2821 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
2824 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
2826 if (GTK_CMCELL_PIXTEXT
2827 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
2831 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
2833 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
2837 /* set/ref closed pixmap */
2838 if (GTK_CMCTREE_ROW (node)->pixmap_closed)
2841 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap =
2842 g_object_ref (GTK_CMCTREE_ROW (node)->pixmap_closed);
2844 if (GTK_CMCTREE_ROW (node)->mask_closed)
2846 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask =
2847 g_object_ref (GTK_CMCTREE_ROW (node)->mask_closed);
2850 work = GTK_CMCTREE_ROW (node)->children;
2857 while (work && GTK_CMCTREE_ROW (work)->level > level)
2859 work = GTK_CMCTREE_NODE_NEXT (work);
2865 list = (GList *)node;
2866 list->next = (GList *)work;
2867 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2869 list = (GList *)work;
2870 list->prev = (GList *)node;
2874 list = (GList *)node;
2876 clist->row_list_end = (GList *)node;
2881 /* resize auto_resize columns if needed */
2882 auto_resize_columns (clist);
2884 row = g_list_position (clist->row_list, (GList *)node);
2885 if (row < clist->focus_row)
2886 clist->focus_row -= tmp;
2888 CLIST_REFRESH (clist);
2891 else if (visible && clist->column[ctree->tree_column].auto_resize &&
2892 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2893 /* resize tree_column if needed */
2894 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2900 column_auto_resize (GtkCMCList *clist,
2901 GtkCMCListRow *clist_row,
2905 /* resize column if needed for auto_resize */
2906 GtkRequisition requisition;
2908 if (!clist->column[column].auto_resize ||
2909 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2913 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2914 column, &requisition);
2916 requisition.width = 0;
2918 if (requisition.width > clist->column[column].width)
2919 gtk_cmclist_set_column_width (clist, column, requisition.width);
2920 else if (requisition.width < old_width &&
2921 old_width == clist->column[column].width)
2926 /* run a "gtk_cmclist_optimal_column_width" but break, if
2927 * the column doesn't shrink */
2928 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
2929 new_width = (clist->column[column].button->requisition.width -
2930 (CELL_SPACING + (2 * COLUMN_INSET)));
2934 for (list = clist->row_list; list; list = list->next)
2936 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2937 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
2938 new_width = MAX (new_width, requisition.width);
2939 if (new_width == clist->column[column].width)
2942 if (new_width < clist->column[column].width)
2943 gtk_cmclist_set_column_width (clist, column, new_width);
2948 auto_resize_columns (GtkCMCList *clist)
2952 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2955 for (i = 0; i < clist->columns; i++)
2956 column_auto_resize (clist, NULL, i, clist->column[i].width);
2960 cell_size_request (GtkCMCList *clist,
2961 GtkCMCListRow *clist_row,
2963 GtkRequisition *requisition)
2968 PangoLayout *layout;
2969 PangoRectangle logical_rect;
2971 g_return_if_fail (GTK_IS_CMCTREE (clist));
2972 g_return_if_fail (requisition != NULL);
2974 ctree = GTK_CMCTREE (clist);
2976 layout = _gtk_cmclist_create_cell_layout (clist, clist_row, column);
2979 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2981 requisition->width = logical_rect.width;
2982 requisition->height = logical_rect.height;
2984 g_object_unref (G_OBJECT (layout));
2988 requisition->width = 0;
2989 requisition->height = 0;
2992 switch (clist_row->cell[column].type)
2994 case GTK_CMCELL_PIXTEXT:
2995 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap)
2997 gdk_drawable_get_size (GTK_CMCELL_PIXTEXT
2998 (clist_row->cell[column])->pixmap,
3000 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
3005 requisition->width += width;
3006 requisition->height = MAX (requisition->height, height);
3008 if (column == ctree->tree_column)
3010 requisition->width += (ctree->tree_spacing + ctree->tree_indent *
3011 (((GtkCMCTreeRow *) clist_row)->level - 1));
3012 switch (ctree->expander_style)
3014 case GTK_CMCTREE_EXPANDER_NONE:
3016 case GTK_CMCTREE_EXPANDER_TRIANGLE:
3017 requisition->width += PM_SIZE + 3;
3019 case GTK_CMCTREE_EXPANDER_SQUARE:
3020 case GTK_CMCTREE_EXPANDER_CIRCULAR:
3021 requisition->width += PM_SIZE + 1;
3024 if (ctree->line_style == GTK_CMCTREE_LINES_TABBED)
3025 requisition->width += 3;
3028 case GTK_CMCELL_PIXMAP:
3029 gdk_drawable_get_size (GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap,
3031 requisition->width += width;
3032 requisition->height = MAX (requisition->height, height);
3038 requisition->width += clist_row->cell[column].horizontal;
3039 requisition->height += clist_row->cell[column].vertical;
3043 set_cell_contents (GtkCMCList *clist,
3044 GtkCMCListRow *clist_row,
3052 gboolean visible = FALSE;
3054 GtkRequisition requisition;
3055 gchar *old_text = NULL;
3056 GdkPixmap *old_pixmap = NULL;
3057 GdkBitmap *old_mask = NULL;
3059 g_return_if_fail (GTK_IS_CMCTREE (clist));
3060 g_return_if_fail (clist_row != NULL);
3062 ctree = GTK_CMCTREE (clist);
3064 if (clist->column[column].auto_resize &&
3065 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3067 GtkCMCTreeNode *parent;
3069 parent = ((GtkCMCTreeRow *)clist_row)->parent;
3070 if (!parent || (parent && GTK_CMCTREE_ROW (parent)->expanded &&
3071 gtk_cmctree_is_viewable (ctree, parent)))
3074 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
3075 column, &requisition);
3079 switch (clist_row->cell[column].type)
3081 case GTK_CMCELL_EMPTY:
3083 case GTK_CMCELL_TEXT:
3084 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
3086 case GTK_CMCELL_PIXMAP:
3087 old_pixmap = GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap;
3088 old_mask = GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask;
3090 case GTK_CMCELL_PIXTEXT:
3091 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
3092 old_pixmap = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap;
3093 old_mask = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask;
3095 case GTK_CMCELL_WIDGET:
3103 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
3104 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY)
3105 type = GTK_CMCELL_PIXTEXT;
3107 /* Note that pixmap and mask were already ref'ed by the caller
3111 case GTK_CMCELL_TEXT:
3114 clist_row->cell[column].type = GTK_CMCELL_TEXT;
3115 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
3118 case GTK_CMCELL_PIXMAP:
3121 clist_row->cell[column].type = GTK_CMCELL_PIXMAP;
3122 GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
3123 /* We set the mask even if it is NULL */
3124 GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask = mask;
3127 case GTK_CMCELL_PIXTEXT:
3128 if (column == ctree->tree_column)
3130 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
3131 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3133 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3135 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL;
3138 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3139 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3143 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = NULL;
3144 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = NULL;
3147 else if (text && pixmap)
3149 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
3150 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3151 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3152 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3153 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3160 if (visible && clist->column[column].auto_resize &&
3161 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
3162 column_auto_resize (clist, clist_row, column, requisition.width);
3166 g_object_unref (old_pixmap);
3168 g_object_unref (old_mask);
3172 set_node_info (GtkCMCTree *ctree,
3173 GtkCMCTreeNode *node,
3176 GdkPixmap *pixmap_closed,
3177 GdkBitmap *mask_closed,
3178 GdkPixmap *pixmap_opened,
3179 GdkBitmap *mask_opened,
3183 if (GTK_CMCTREE_ROW (node)->pixmap_opened)
3185 g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_opened);
3186 if (GTK_CMCTREE_ROW (node)->mask_opened)
3187 g_object_unref (GTK_CMCTREE_ROW (node)->mask_opened);
3189 if (GTK_CMCTREE_ROW (node)->pixmap_closed)
3191 g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_closed);
3192 if (GTK_CMCTREE_ROW (node)->mask_closed)
3193 g_object_unref (GTK_CMCTREE_ROW (node)->mask_closed);
3196 GTK_CMCTREE_ROW (node)->pixmap_opened = NULL;
3197 GTK_CMCTREE_ROW (node)->mask_opened = NULL;
3198 GTK_CMCTREE_ROW (node)->pixmap_closed = NULL;
3199 GTK_CMCTREE_ROW (node)->mask_closed = NULL;
3203 GTK_CMCTREE_ROW (node)->pixmap_closed = g_object_ref (pixmap_closed);
3205 GTK_CMCTREE_ROW (node)->mask_closed = g_object_ref (mask_closed);
3209 GTK_CMCTREE_ROW (node)->pixmap_opened = g_object_ref (pixmap_opened);
3211 GTK_CMCTREE_ROW (node)->mask_opened = g_object_ref (mask_opened);
3214 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
3215 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
3217 if (GTK_CMCTREE_ROW (node)->expanded)
3218 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
3219 text, spacing, pixmap_opened, mask_opened);
3221 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
3222 text, spacing, pixmap_closed, mask_closed);
3226 tree_delete (GtkCMCTree *ctree,
3227 GtkCMCTreeNode *node,
3230 tree_unselect (ctree, node, NULL);
3231 row_delete (ctree, GTK_CMCTREE_ROW (node));
3232 g_list_free_1 ((GList *)node);
3236 tree_delete_row (GtkCMCTree *ctree,
3237 GtkCMCTreeNode *node,
3240 row_delete (ctree, GTK_CMCTREE_ROW (node));
3241 g_list_free_1 ((GList *)node);
3245 tree_update_level (GtkCMCTree *ctree,
3246 GtkCMCTreeNode *node,
3252 if (GTK_CMCTREE_ROW (node)->parent)
3253 GTK_CMCTREE_ROW (node)->level =
3254 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
3256 GTK_CMCTREE_ROW (node)->level = 1;
3260 tree_select (GtkCMCTree *ctree,
3261 GtkCMCTreeNode *node,
3264 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
3265 GTK_CMCTREE_ROW (node)->row.selectable)
3266 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
3271 tree_unselect (GtkCMCTree *ctree,
3272 GtkCMCTreeNode *node,
3275 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3276 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
3281 tree_expand (GtkCMCTree *ctree,
3282 GtkCMCTreeNode *node,
3285 if (node && !GTK_CMCTREE_ROW (node)->expanded)
3286 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
3290 tree_collapse (GtkCMCTree *ctree,
3291 GtkCMCTreeNode *node,
3294 if (node && GTK_CMCTREE_ROW (node)->expanded)
3295 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
3299 tree_collapse_to_depth (GtkCMCTree *ctree,
3300 GtkCMCTreeNode *node,
3303 if (node && GTK_CMCTREE_ROW (node)->level == depth)
3304 gtk_cmctree_collapse_recursive (ctree, node);
3308 tree_toggle_expansion (GtkCMCTree *ctree,
3309 GtkCMCTreeNode *node,
3315 if (GTK_CMCTREE_ROW (node)->expanded)
3316 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
3318 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
3321 static GtkCMCTreeRow *
3322 row_new (GtkCMCTree *ctree)
3325 GtkCMCTreeRow *ctree_row;
3328 clist = GTK_CMCLIST (ctree);
3329 #if GLIB_CHECK_VERSION(2,10,0)
3330 ctree_row = g_slice_new (GtkCMCTreeRow);
3331 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
3333 ctree_row = g_chunk_new (GtkCMCTreeRow, (GMemChunk *)clist->row_mem_chunk);
3334 ctree_row->row.cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk);
3337 for (i = 0; i < clist->columns; i++)
3339 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
3340 ctree_row->row.cell[i].vertical = 0;
3341 ctree_row->row.cell[i].horizontal = 0;
3342 ctree_row->row.cell[i].style = NULL;
3345 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
3347 ctree_row->row.fg_set = FALSE;
3348 ctree_row->row.bg_set = FALSE;
3349 ctree_row->row.style = NULL;
3350 ctree_row->row.selectable = TRUE;
3351 ctree_row->row.state = GTK_STATE_NORMAL;
3352 ctree_row->row.data = NULL;
3353 ctree_row->row.destroy = NULL;
3355 ctree_row->level = 0;
3356 ctree_row->expanded = FALSE;
3357 ctree_row->parent = NULL;
3358 ctree_row->sibling = NULL;
3359 ctree_row->children = NULL;
3360 ctree_row->pixmap_closed = NULL;
3361 ctree_row->mask_closed = NULL;
3362 ctree_row->pixmap_opened = NULL;
3363 ctree_row->mask_opened = NULL;
3369 row_delete (GtkCMCTree *ctree,
3370 GtkCMCTreeRow *ctree_row)
3375 clist = GTK_CMCLIST (ctree);
3377 for (i = 0; i < clist->columns; i++)
3379 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3380 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL, NULL);
3381 if (ctree_row->row.cell[i].style)
3383 if (GTK_WIDGET_REALIZED (ctree))
3384 gtk_style_detach (ctree_row->row.cell[i].style);
3385 g_object_unref (ctree_row->row.cell[i].style);
3389 if (ctree_row->row.style)
3391 if (GTK_WIDGET_REALIZED (ctree))
3392 gtk_style_detach (ctree_row->row.style);
3393 g_object_unref (ctree_row->row.style);
3396 if (ctree_row->pixmap_closed)
3398 g_object_unref (ctree_row->pixmap_closed);
3399 if (ctree_row->mask_closed)
3400 g_object_unref (ctree_row->mask_closed);
3403 if (ctree_row->pixmap_opened)
3405 g_object_unref (ctree_row->pixmap_opened);
3406 if (ctree_row->mask_opened)
3407 g_object_unref (ctree_row->mask_opened);
3410 if (ctree_row->row.destroy)
3412 GDestroyNotify dnotify = ctree_row->row.destroy;
3413 gpointer ddata = ctree_row->row.data;
3415 ctree_row->row.destroy = NULL;
3416 ctree_row->row.data = NULL;
3421 #if GLIB_CHECK_VERSION(2,10,0)
3422 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
3423 g_slice_free (GtkCMCTreeRow, ctree_row);
3425 g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
3426 g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
3431 real_select_row (GtkCMCList *clist,
3438 g_return_if_fail (GTK_IS_CMCTREE (clist));
3440 if ((node = g_list_nth (clist->row_list, row)) &&
3441 GTK_CMCTREE_ROW (node)->row.selectable)
3442 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0,
3447 real_unselect_row (GtkCMCList *clist,
3454 g_return_if_fail (GTK_IS_CMCTREE (clist));
3456 if ((node = g_list_nth (clist->row_list, row)))
3457 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0,
3462 real_tree_select (GtkCMCTree *ctree,
3463 GtkCMCTreeNode *node,
3468 GtkCMCTreeNode *sel_row;
3469 gboolean node_selected;
3471 g_return_if_fail (GTK_IS_CMCTREE (ctree));
3473 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
3474 !GTK_CMCTREE_ROW (node)->row.selectable)
3477 clist = GTK_CMCLIST (ctree);
3479 switch (clist->selection_mode)
3481 case GTK_SELECTION_SINGLE:
3482 case GTK_SELECTION_BROWSE:
3484 node_selected = FALSE;
3485 list = clist->selection;
3489 sel_row = list->data;
3492 if (node == sel_row)
3493 node_selected = TRUE;
3495 g_signal_emit (G_OBJECT (ctree),
3496 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column);
3506 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
3508 if (!clist->selection)
3510 clist->selection = g_list_append (clist->selection, node);
3511 clist->selection_end = clist->selection;
3514 clist->selection_end = g_list_append (clist->selection_end, node)->next;
3516 tree_draw_node (ctree, node);
3520 real_tree_unselect (GtkCMCTree *ctree,
3521 GtkCMCTreeNode *node,
3526 g_return_if_fail (GTK_IS_CMCTREE (ctree));
3528 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
3531 clist = GTK_CMCLIST (ctree);
3533 if (clist->selection_end && clist->selection_end->data == node)
3534 clist->selection_end = clist->selection_end->prev;
3536 clist->selection = g_list_remove (clist->selection, node);
3538 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
3540 tree_draw_node (ctree, node);
3544 select_row_recursive (GtkCMCTree *ctree,
3545 GtkCMCTreeNode *node,
3548 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
3549 !GTK_CMCTREE_ROW (node)->row.selectable)
3552 GTK_CMCLIST (ctree)->undo_unselection =
3553 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node);
3554 gtk_cmctree_select (ctree, node);
3558 real_select_all (GtkCMCList *clist)
3561 GtkCMCTreeNode *node;
3563 g_return_if_fail (GTK_IS_CMCTREE (clist));
3565 ctree = GTK_CMCTREE (clist);
3567 switch (clist->selection_mode)
3569 case GTK_SELECTION_SINGLE:
3570 case GTK_SELECTION_BROWSE:
3573 case GTK_SELECTION_MULTIPLE:
3575 gtk_cmclist_freeze (clist);
3577 g_list_free (clist->undo_selection);
3578 g_list_free (clist->undo_unselection);
3579 clist->undo_selection = NULL;
3580 clist->undo_unselection = NULL;
3582 clist->anchor_state = GTK_STATE_SELECTED;
3584 clist->drag_pos = -1;
3585 clist->undo_anchor = clist->focus_row;
3587 for (node = GTK_CMCTREE_NODE (clist->row_list); node;
3588 node = GTK_CMCTREE_NODE_NEXT (node))
3589 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL);
3591 gtk_cmclist_thaw (clist);
3601 real_unselect_all (GtkCMCList *clist)
3604 GtkCMCTreeNode *node;
3607 g_return_if_fail (GTK_IS_CMCTREE (clist));
3609 ctree = GTK_CMCTREE (clist);
3611 switch (clist->selection_mode)
3613 case GTK_SELECTION_BROWSE:
3614 if (clist->focus_row >= 0)
3618 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
3623 case GTK_SELECTION_MULTIPLE:
3624 g_list_free (clist->undo_selection);
3625 g_list_free (clist->undo_unselection);
3626 clist->undo_selection = NULL;
3627 clist->undo_unselection = NULL;
3630 clist->drag_pos = -1;
3631 clist->undo_anchor = clist->focus_row;
3638 list = clist->selection;
3644 gtk_cmctree_unselect (ctree, node);
3649 ctree_is_hot_spot (GtkCMCTree *ctree,
3650 GtkCMCTreeNode *node,
3655 GtkCMCTreeRow *tree_row;
3660 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3661 g_return_val_if_fail (node != NULL, FALSE);
3663 clist = GTK_CMCLIST (ctree);
3665 if (!clist->column[ctree->tree_column].visible ||
3666 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
3669 tree_row = GTK_CMCTREE_ROW (node);
3671 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
3672 (clist->row_height - 1) % 2);
3674 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
3675 xl = (clist->column[ctree->tree_column].area.x +
3676 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
3677 (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
3678 (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3);
3680 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
3681 (tree_row->level - 1) * ctree->tree_indent +
3682 (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3);
3684 return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
3687 /***********************************************************
3688 ***********************************************************
3689 *** Public interface ***
3690 ***********************************************************
3691 ***********************************************************/
3694 /***********************************************************
3695 * Creation, insertion, deletion *
3696 ***********************************************************/
3699 gtk_cmctree_constructor (GType type,
3700 guint n_construct_properties,
3701 GObjectConstructParam *construct_properties)
3703 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
3704 n_construct_properties,
3705 construct_properties);
3711 gtk_cmctree_new_with_titles (gint columns,
3717 g_return_val_if_fail (columns > 0, NULL);
3718 g_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3720 widget = gtk_widget_new (GTK_TYPE_CMCTREE,
3721 "n_columns", columns,
3722 "tree_column", tree_column,
3726 GtkCMCList *clist = GTK_CMCLIST (widget);
3729 for (i = 0; i < columns; i++)
3730 gtk_cmclist_set_column_title (clist, i, titles[i]);
3731 gtk_cmclist_column_titles_show (clist);
3738 gtk_cmctree_new (gint columns,
3741 return gtk_cmctree_new_with_titles (columns, tree_column, NULL);
3745 real_insert_row (GtkCMCList *clist,
3749 GtkCMCTreeNode *parent = NULL;
3750 GtkCMCTreeNode *sibling;
3751 GtkCMCTreeNode *node;
3753 g_return_val_if_fail (GTK_IS_CMCTREE (clist), -1);
3755 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3757 parent = GTK_CMCTREE_ROW (sibling)->parent;
3759 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5,
3760 NULL, NULL, NULL, NULL, TRUE, FALSE);
3762 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling)
3763 return g_list_position (clist->row_list, (GList *) node);
3769 gtk_cmctree_insert_node (GtkCMCTree *ctree,
3770 GtkCMCTreeNode *parent,
3771 GtkCMCTreeNode *sibling,
3774 GdkPixmap *pixmap_closed,
3775 GdkBitmap *mask_closed,
3776 GdkPixmap *pixmap_opened,
3777 GdkBitmap *mask_opened,
3782 GtkCMCTreeRow *new_row;
3783 GtkCMCTreeNode *node;
3787 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3789 g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3791 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
3794 clist = GTK_CMCLIST (ctree);
3796 /* create the row */
3797 new_row = row_new (ctree);
3798 list = g_list_alloc ();
3799 list->data = new_row;
3800 node = GTK_CMCTREE_NODE (list);
3803 for (i = 0; i < clist->columns; i++)
3804 if (text[i] && i != ctree->tree_column)
3805 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3806 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL, NULL);
3808 set_node_info (ctree, node, text ?
3809 text[ctree->tree_column] : NULL, spacing, pixmap_closed,
3810 mask_closed, pixmap_opened, mask_opened, is_leaf, expanded);
3812 /* sorted insertion */
3813 if (GTK_CMCLIST_AUTO_SORT (clist))
3816 sibling = GTK_CMCTREE_ROW (parent)->children;
3818 sibling = GTK_CMCTREE_NODE (clist->row_list);
3820 while (sibling && clist->compare
3821 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
3822 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3825 gtk_cmctree_link (ctree, node, parent, sibling, TRUE);
3827 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
3828 gtk_cmctree_is_viewable (ctree, node))
3830 for (i = 0; i < clist->columns; i++)
3831 if (clist->column[i].auto_resize)
3832 column_auto_resize (clist, &(new_row->row), i, 0);
3835 if (clist->rows == 1)
3837 clist->focus_row = 0;
3838 if (clist->selection_mode == GTK_SELECTION_BROWSE)
3839 gtk_cmctree_select (ctree, node);
3843 CLIST_REFRESH (clist);
3849 gtk_cmctree_insert_gnode (GtkCMCTree *ctree,
3850 GtkCMCTreeNode *parent,
3851 GtkCMCTreeNode *sibling,
3853 GtkCMCTreeGNodeFunc func,
3857 GtkCMCTreeNode *cnode = NULL;
3858 GtkCMCTreeNode *child = NULL;
3859 GtkCMCTreeNode *new_child;
3864 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3865 g_return_val_if_fail (gnode != NULL, NULL);
3866 g_return_val_if_fail (func != NULL, NULL);
3868 g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3870 clist = GTK_CMCLIST (ctree);
3873 depth = GTK_CMCTREE_ROW (parent)->level + 1;
3875 list = g_list_alloc ();
3876 list->data = row_new (ctree);
3877 cnode = GTK_CMCTREE_NODE (list);
3879 gtk_cmclist_freeze (clist);
3881 set_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE);
3883 if (!func (ctree, depth, gnode, cnode, data))
3885 tree_delete_row (ctree, cnode, NULL);
3886 gtk_cmclist_thaw (clist);
3890 if (GTK_CMCLIST_AUTO_SORT (clist))
3893 sibling = GTK_CMCTREE_ROW (parent)->children;
3895 sibling = GTK_CMCTREE_NODE (clist->row_list);
3897 while (sibling && clist->compare
3898 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
3899 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3902 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE);
3904 for (work = g_node_last_child (gnode); work; work = work->prev)
3906 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child,
3912 gtk_cmclist_thaw (clist);
3918 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree,
3921 GtkCMCTreeNode *node,
3922 GtkCMCTreeGNodeFunc func,
3925 GtkCMCTreeNode *work;
3929 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3930 g_return_val_if_fail (node != NULL, NULL);
3931 g_return_val_if_fail (func != NULL, NULL);
3934 g_return_val_if_fail (parent != NULL, NULL);
3935 g_return_val_if_fail (sibling->parent == parent, NULL);
3938 gnode = g_node_new (NULL);
3939 depth = g_node_depth (parent) + 1;
3941 if (!func (ctree, depth, gnode, node, data))
3943 g_node_destroy (gnode);
3948 g_node_insert_before (parent, sibling, gnode);
3950 if (!GTK_CMCTREE_ROW (node)->is_leaf)
3952 GNode *new_sibling = NULL;
3954 for (work = GTK_CMCTREE_ROW (node)->children; work;
3955 work = GTK_CMCTREE_ROW (work)->sibling)
3956 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling,
3959 g_node_reverse_children (gnode);
3966 real_remove_row (GtkCMCList *clist,
3969 GtkCMCTreeNode *node;
3971 g_return_if_fail (GTK_IS_CMCTREE (clist));
3973 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3976 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node);
3980 gtk_cmctree_remove_node (GtkCMCTree *ctree,
3981 GtkCMCTreeNode *node)
3985 g_return_if_fail (GTK_IS_CMCTREE (ctree));
3987 clist = GTK_CMCLIST (ctree);
3989 gtk_cmclist_freeze (clist);
3993 gtk_cmctree_unlink (ctree, node, TRUE);
3994 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete),
3996 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3997 clist->focus_row >= 0)
3998 gtk_cmclist_select_row (clist, clist->focus_row, -1);
4000 auto_resize_columns (clist);
4003 gtk_cmclist_clear (clist);
4005 gtk_cmclist_thaw (clist);
4009 real_clear (GtkCMCList *clist)
4012 GtkCMCTreeNode *work;
4013 GtkCMCTreeNode *ptr;
4015 g_return_if_fail (GTK_IS_CMCTREE (clist));
4017 ctree = GTK_CMCTREE (clist);
4019 /* remove all rows */
4020 work = GTK_CMCTREE_NODE (clist->row_list);
4021 clist->row_list = NULL;
4022 clist->row_list_end = NULL;
4024 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4028 work = GTK_CMCTREE_ROW (work)->sibling;
4029 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row),
4032 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4034 parent_class->clear (clist);
4038 /***********************************************************
4039 * Generic recursive functions, querying / finding tree *
4041 ***********************************************************/
4045 gtk_cmctree_post_recursive (GtkCMCTree *ctree,
4046 GtkCMCTreeNode *node,
4047 GtkCMCTreeFunc func,
4050 GtkCMCTreeNode *work;
4051 GtkCMCTreeNode *tmp;
4053 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4054 g_return_if_fail (func != NULL);
4057 work = GTK_CMCTREE_ROW (node)->children;
4059 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4063 tmp = GTK_CMCTREE_ROW (work)->sibling;
4064 gtk_cmctree_post_recursive (ctree, work, func, data);
4069 func (ctree, node, data);
4073 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree,
4074 GtkCMCTreeNode *node,
4076 GtkCMCTreeFunc func,
4079 GtkCMCTreeNode *work;
4080 GtkCMCTreeNode *tmp;
4082 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4083 g_return_if_fail (func != NULL);
4087 gtk_cmctree_post_recursive (ctree, node, func, data);
4092 work = GTK_CMCTREE_ROW (node)->children;
4094 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4096 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
4100 tmp = GTK_CMCTREE_ROW (work)->sibling;
4101 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data);
4106 if (node && GTK_CMCTREE_ROW (node)->level <= depth)
4107 func (ctree, node, data);
4111 gtk_cmctree_pre_recursive (GtkCMCTree *ctree,
4112 GtkCMCTreeNode *node,
4113 GtkCMCTreeFunc func,
4116 GtkCMCTreeNode *work;
4117 GtkCMCTreeNode *tmp;
4119 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4120 g_return_if_fail (func != NULL);
4124 work = GTK_CMCTREE_ROW (node)->children;
4125 func (ctree, node, data);
4128 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4132 tmp = GTK_CMCTREE_ROW (work)->sibling;
4133 gtk_cmctree_pre_recursive (ctree, work, func, data);
4139 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree,
4140 GtkCMCTreeNode *node,
4142 GtkCMCTreeFunc func,
4145 GtkCMCTreeNode *work;
4146 GtkCMCTreeNode *tmp;
4148 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4149 g_return_if_fail (func != NULL);
4153 gtk_cmctree_pre_recursive (ctree, node, func, data);
4159 work = GTK_CMCTREE_ROW (node)->children;
4160 if (GTK_CMCTREE_ROW (node)->level <= depth)
4161 func (ctree, node, data);
4164 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4166 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
4170 tmp = GTK_CMCTREE_ROW (work)->sibling;
4171 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data);
4178 gtk_cmctree_is_viewable (GtkCMCTree *ctree,
4179 GtkCMCTreeNode *node)
4181 GtkCMCTreeRow *work;
4183 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4184 g_return_val_if_fail (node != NULL, FALSE);
4186 work = GTK_CMCTREE_ROW (node);
4188 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded)
4189 work = GTK_CMCTREE_ROW (work->parent);
4198 gtk_cmctree_last (GtkCMCTree *ctree,
4199 GtkCMCTreeNode *node)
4201 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4206 while (GTK_CMCTREE_ROW (node)->sibling)
4207 node = GTK_CMCTREE_ROW (node)->sibling;
4209 if (GTK_CMCTREE_ROW (node)->children)
4210 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children);
4216 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree,
4217 GtkCMCTreeRow *ctree_row)
4219 GtkCMCTreeNode *node;
4221 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4222 g_return_val_if_fail (ctree_row != NULL, NULL);
4224 if (ctree_row->parent)
4225 node = GTK_CMCTREE_ROW (ctree_row->parent)->children;
4227 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4229 while (GTK_CMCTREE_ROW (node) != ctree_row)
4230 node = GTK_CMCTREE_ROW (node)->sibling;
4236 gtk_cmctree_node_nth (GtkCMCTree *ctree,
4239 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4241 if ((row >= GTK_CMCLIST(ctree)->rows))
4244 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row));
4248 gtk_cmctree_find (GtkCMCTree *ctree,
4249 GtkCMCTreeNode *node,
4250 GtkCMCTreeNode *child)
4256 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4262 if (GTK_CMCTREE_ROW (node)->children)
4264 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child))
4267 node = GTK_CMCTREE_ROW (node)->sibling;
4273 gtk_cmctree_is_ancestor (GtkCMCTree *ctree,
4274 GtkCMCTreeNode *node,
4275 GtkCMCTreeNode *child)
4277 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4278 g_return_val_if_fail (node != NULL, FALSE);
4280 if (GTK_CMCTREE_ROW (node)->children)
4281 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child);
4287 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree,
4288 GtkCMCTreeNode *node,
4291 GtkCMCTreeNode *work;
4294 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4298 if (GTK_CMCTREE_ROW (node)->row.data == data)
4300 if (GTK_CMCTREE_ROW (node)->children &&
4301 (work = gtk_cmctree_find_by_row_data
4302 (ctree, GTK_CMCTREE_ROW (node)->children, data)))
4304 node = GTK_CMCTREE_ROW (node)->sibling;
4310 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree,
4311 GtkCMCTreeNode *node,
4316 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4318 /* if node == NULL then look in the whole tree */
4320 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4324 if (GTK_CMCTREE_ROW (node)->row.data == data)
4325 list = g_list_append (list, node);
4327 if (GTK_CMCTREE_ROW (node)->children)
4331 sub_list = gtk_cmctree_find_all_by_row_data (ctree,
4335 list = g_list_concat (list, sub_list);
4337 node = GTK_CMCTREE_ROW (node)->sibling;
4343 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree,
4344 GtkCMCTreeNode *node,
4348 GtkCMCTreeNode *work;
4350 g_return_val_if_fail (func != NULL, NULL);
4353 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4357 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
4359 if (GTK_CMCTREE_ROW (node)->children &&
4360 (work = gtk_cmctree_find_by_row_data_custom
4361 (ctree, GTK_CMCTREE_ROW (node)->children, data, func)))
4363 node = GTK_CMCTREE_ROW (node)->sibling;
4369 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree,
4370 GtkCMCTreeNode *node,
4376 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4377 g_return_val_if_fail (func != NULL, NULL);
4379 /* if node == NULL then look in the whole tree */
4381 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
4385 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
4386 list = g_list_append (list, node);
4388 if (GTK_CMCTREE_ROW (node)->children)
4392 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree,
4397 list = g_list_concat (list, sub_list);
4399 node = GTK_CMCTREE_ROW (node)->sibling;
4405 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree,
4409 GtkCMCTreeNode *node;
4413 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4415 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
4416 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
4417 return ctree_is_hot_spot (ctree, node, row, x, y);
4423 /***********************************************************
4424 * Tree signals : move, expand, collapse, (un)select *
4425 ***********************************************************/
4429 gtk_cmctree_move (GtkCMCTree *ctree,
4430 GtkCMCTreeNode *node,
4431 GtkCMCTreeNode *new_parent,
4432 GtkCMCTreeNode *new_sibling)
4434 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4435 g_return_if_fail (node != NULL);
4437 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node,
4438 new_parent, new_sibling);
4442 gtk_cmctree_expand (GtkCMCTree *ctree,
4443 GtkCMCTreeNode *node)
4445 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4446 g_return_if_fail (node != NULL);
4448 if (GTK_CMCTREE_ROW (node)->is_leaf)
4451 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node);
4455 gtk_cmctree_expand_recursive (GtkCMCTree *ctree,
4456 GtkCMCTreeNode *node)
4459 gboolean thaw = FALSE;
4461 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4463 clist = GTK_CMCLIST (ctree);
4465 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4468 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4470 gtk_cmclist_freeze (clist);
4474 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL);
4477 gtk_cmclist_thaw (clist);
4481 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree,
4482 GtkCMCTreeNode *node,
4486 gboolean thaw = FALSE;
4488 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4490 clist = GTK_CMCLIST (ctree);
4492 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4495 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4497 gtk_cmclist_freeze (clist);
4501 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
4502 GTK_CMCTREE_FUNC (tree_expand), NULL);
4505 gtk_cmclist_thaw (clist);
4509 gtk_cmctree_collapse (GtkCMCTree *ctree,
4510 GtkCMCTreeNode *node)
4512 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4513 g_return_if_fail (node != NULL);
4515 if (GTK_CMCTREE_ROW (node)->is_leaf)
4518 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node);
4522 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree,
4523 GtkCMCTreeNode *node)
4526 gboolean thaw = FALSE;
4529 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4531 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4534 clist = GTK_CMCLIST (ctree);
4536 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4538 gtk_cmclist_freeze (clist);
4542 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4543 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL);
4544 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4545 for (i = 0; i < clist->columns; i++)
4546 if (clist->column[i].auto_resize)
4547 gtk_cmclist_set_column_width (clist, i,
4548 gtk_cmclist_optimal_column_width (clist, i));
4551 gtk_cmclist_thaw (clist);
4555 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree,
4556 GtkCMCTreeNode *node,
4560 gboolean thaw = FALSE;
4563 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4565 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4568 clist = GTK_CMCLIST (ctree);
4570 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4572 gtk_cmclist_freeze (clist);
4576 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4577 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
4578 GTK_CMCTREE_FUNC (tree_collapse_to_depth),
4579 GINT_TO_POINTER (depth));
4580 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4581 for (i = 0; i < clist->columns; i++)
4582 if (clist->column[i].auto_resize)
4583 gtk_cmclist_set_column_width (clist, i,
4584 gtk_cmclist_optimal_column_width (clist, i));
4587 gtk_cmclist_thaw (clist);
4591 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree,
4592 GtkCMCTreeNode *node)
4594 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4595 g_return_if_fail (node != NULL);
4597 if (GTK_CMCTREE_ROW (node)->is_leaf)
4600 tree_toggle_expansion (ctree, node, NULL);
4604 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree,
4605 GtkCMCTreeNode *node)
4608 gboolean thaw = FALSE;
4610 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4612 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4615 clist = GTK_CMCLIST (ctree);
4617 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4619 gtk_cmclist_freeze (clist);
4623 gtk_cmctree_post_recursive (ctree, node,
4624 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL);
4627 gtk_cmclist_thaw (clist);
4631 gtk_cmctree_select (GtkCMCTree *ctree,
4632 GtkCMCTreeNode *node)
4634 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4635 g_return_if_fail (node != NULL);
4637 if (GTK_CMCTREE_ROW (node)->row.selectable)
4638 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
4643 gtk_cmctree_unselect (GtkCMCTree *ctree,
4644 GtkCMCTreeNode *node)
4646 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4647 g_return_if_fail (node != NULL);
4649 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
4654 gtk_cmctree_select_recursive (GtkCMCTree *ctree,
4655 GtkCMCTreeNode *node)
4657 gtk_cmctree_real_select_recursive (ctree, node, TRUE);
4661 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree,
4662 GtkCMCTreeNode *node)
4664 gtk_cmctree_real_select_recursive (ctree, node, FALSE);
4668 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree,
4669 GtkCMCTreeNode *node,
4673 gboolean thaw = FALSE;
4675 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4677 clist = GTK_CMCLIST (ctree);
4680 (clist->selection_mode == GTK_SELECTION_BROWSE ||
4681 clist->selection_mode == GTK_SELECTION_SINGLE)) ||
4682 (!state && clist->selection_mode == GTK_SELECTION_BROWSE))
4685 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4687 gtk_cmclist_freeze (clist);
4691 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4693 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4695 g_list_free (clist->undo_selection);
4696 g_list_free (clist->undo_unselection);
4697 clist->undo_selection = NULL;
4698 clist->undo_unselection = NULL;
4702 gtk_cmctree_post_recursive (ctree, node,
4703 GTK_CMCTREE_FUNC (tree_select), NULL);
4705 gtk_cmctree_post_recursive (ctree, node,
4706 GTK_CMCTREE_FUNC (tree_unselect), NULL);
4709 gtk_cmclist_thaw (clist);
4713 /***********************************************************
4714 * Analogons of GtkCMCList functions *
4715 ***********************************************************/
4719 gtk_cmctree_node_set_text (GtkCMCTree *ctree,
4720 GtkCMCTreeNode *node,
4726 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4727 g_return_if_fail (node != NULL);
4729 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4732 clist = GTK_CMCLIST (ctree);
4734 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4735 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT,
4736 text, 0, NULL, NULL);
4738 tree_draw_node (ctree, node);
4742 gtk_cmctree_node_set_pixmap (GtkCMCTree *ctree,
4743 GtkCMCTreeNode *node,
4750 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4751 g_return_if_fail (node != NULL);
4752 g_return_if_fail (pixmap != NULL);
4754 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4757 g_object_ref (pixmap);
4759 g_object_ref (mask);
4761 clist = GTK_CMCLIST (ctree);
4763 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4764 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXMAP,
4765 NULL, 0, pixmap, mask);
4767 tree_draw_node (ctree, node);
4771 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree,
4772 GtkCMCTreeNode *node,
4781 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4782 g_return_if_fail (node != NULL);
4783 if (column != ctree->tree_column)
4784 g_return_if_fail (pixmap != NULL);
4785 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4788 clist = GTK_CMCLIST (ctree);
4792 g_object_ref (pixmap);
4794 g_object_ref (mask);
4797 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4798 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT,
4799 text, spacing, pixmap, mask);
4801 tree_draw_node (ctree, node);
4805 gtk_cmctree_set_node_info (GtkCMCTree *ctree,
4806 GtkCMCTreeNode *node,
4809 GdkPixmap *pixmap_closed,
4810 GdkBitmap *mask_closed,
4811 GdkPixmap *pixmap_opened,
4812 GdkBitmap *mask_opened,
4817 gboolean old_expanded;
4819 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4820 g_return_if_fail (node != NULL);
4822 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4823 old_expanded = GTK_CMCTREE_ROW (node)->expanded;
4825 if (is_leaf && GTK_CMCTREE_ROW (node)->children)
4827 GtkCMCTreeNode *work;
4828 GtkCMCTreeNode *ptr;
4830 work = GTK_CMCTREE_ROW (node)->children;
4834 work = GTK_CMCTREE_ROW (work)->sibling;
4835 gtk_cmctree_remove_node (ctree, ptr);
4839 set_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed,
4840 pixmap_opened, mask_opened, is_leaf, expanded);
4842 if (!is_leaf && !old_leaf)
4844 GTK_CMCTREE_ROW (node)->expanded = old_expanded;
4845 if (expanded && !old_expanded)
4846 gtk_cmctree_expand (ctree, node);
4847 else if (!expanded && old_expanded)
4848 gtk_cmctree_collapse (ctree, node);
4851 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4853 tree_draw_node (ctree, node);
4857 gtk_cmctree_node_set_shift (GtkCMCTree *ctree,
4858 GtkCMCTreeNode *node,
4864 GtkRequisition requisition;
4865 gboolean visible = FALSE;
4867 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4868 g_return_if_fail (node != NULL);
4870 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4873 clist = GTK_CMCLIST (ctree);
4875 if (clist->column[column].auto_resize &&
4876 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4878 visible = gtk_cmctree_is_viewable (ctree, node);
4880 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4881 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4884 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical;
4885 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4888 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row,
4889 column, requisition.width);
4891 tree_draw_node (ctree, node);
4895 remove_grab (GtkCMCList *clist)
4897 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4898 GTK_WIDGET_HAS_GRAB (clist))
4900 gtk_grab_remove (GTK_WIDGET (clist));
4901 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4907 g_source_remove (clist->htimer);
4913 g_source_remove (clist->vtimer);
4919 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree,
4920 GtkCMCTreeNode *node,
4921 gboolean selectable)
4923 g_return_if_fail (GTK_IS_CMCTREE (ctree));
4924 g_return_if_fail (node != NULL);
4926 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable)
4929 GTK_CMCTREE_ROW (node)->row.selectable = selectable;
4931 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4935 clist = GTK_CMCLIST (ctree);
4937 if (clist->anchor >= 0 &&
4938 clist->selection_mode == GTK_SELECTION_MULTIPLE)
4940 clist->drag_button = 0;
4941 remove_grab (clist);
4943 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4945 gtk_cmctree_unselect (ctree, node);
4950 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree,
4951 GtkCMCTreeNode *node)
4953 g_return_val_if_fail (node != NULL, FALSE);
4955 return GTK_CMCTREE_ROW (node)->row.selectable;
4959 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree,
4960 GtkCMCTreeNode *node,
4963 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1);
4964 g_return_val_if_fail (node != NULL, -1);
4966 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4969 return GTK_CMCTREE_ROW (node)->row.cell[column].type;
4973 gtk_cmctree_node_get_text (GtkCMCTree *ctree,
4974 GtkCMCTreeNode *node,
4978 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4979 g_return_val_if_fail (node != NULL, FALSE);
4981 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4984 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT)
4988 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4994 gtk_cmctree_node_get_pixmap (GtkCMCTree *ctree,
4995 GtkCMCTreeNode *node,
5000 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5001 g_return_val_if_fail (node != NULL, FALSE);
5003 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
5006 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXMAP)
5010 *pixmap = GTK_CMCELL_PIXMAP (GTK_CMCTREE_ROW (node)->row.cell[column])->pixmap;
5012 *mask = GTK_CMCELL_PIXMAP (GTK_CMCTREE_ROW (node)->row.cell[column])->mask;
5018 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree,
5019 GtkCMCTreeNode *node,
5026 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5027 g_return_val_if_fail (node != NULL, FALSE);
5029 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
5032 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT)
5036 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
5038 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
5039 (node)->row.cell[column])->spacing;
5041 *pixmap = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
5042 (node)->row.cell[column])->pixmap;
5044 *mask = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->mask;
5050 gtk_cmctree_get_node_info (GtkCMCTree *ctree,
5051 GtkCMCTreeNode *node,
5054 GdkPixmap **pixmap_closed,
5055 GdkBitmap **mask_closed,
5056 GdkPixmap **pixmap_opened,
5057 GdkBitmap **mask_opened,
5061 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5062 g_return_val_if_fail (node != NULL, FALSE);
5065 *text = GTK_CMCELL_PIXTEXT
5066 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text;
5068 *spacing = GTK_CMCELL_PIXTEXT
5069 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
5071 *pixmap_closed = GTK_CMCTREE_ROW (node)->pixmap_closed;
5073 *mask_closed = GTK_CMCTREE_ROW (node)->mask_closed;
5075 *pixmap_opened = GTK_CMCTREE_ROW (node)->pixmap_opened;
5077 *mask_opened = GTK_CMCTREE_ROW (node)->mask_opened;
5079 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
5081 *expanded = GTK_CMCTREE_ROW (node)->expanded;
5087 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree,
5088 GtkCMCTreeNode *node,
5093 GtkRequisition requisition;
5094 gboolean visible = FALSE;
5096 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5097 g_return_if_fail (node != NULL);
5099 clist = GTK_CMCLIST (ctree);
5101 if (column < 0 || column >= clist->columns)
5104 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style)
5107 if (clist->column[column].auto_resize &&
5108 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5110 visible = gtk_cmctree_is_viewable (ctree, node);
5112 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
5113 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
5116 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
5118 if (GTK_WIDGET_REALIZED (ctree))
5119 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style);
5120 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
5123 GTK_CMCTREE_ROW (node)->row.cell[column].style = style;
5125 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
5127 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
5129 if (GTK_WIDGET_REALIZED (ctree))
5130 GTK_CMCTREE_ROW (node)->row.cell[column].style =
5131 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style,
5132 clist->clist_window);
5136 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column,
5139 tree_draw_node (ctree, node);
5143 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree,
5144 GtkCMCTreeNode *node,
5147 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
5148 g_return_val_if_fail (node != NULL, NULL);
5150 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
5153 return GTK_CMCTREE_ROW (node)->row.cell[column].style;
5157 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree,
5158 GtkCMCTreeNode *node,
5162 GtkRequisition requisition;
5164 gint *old_width = NULL;
5167 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5168 g_return_if_fail (node != NULL);
5170 clist = GTK_CMCLIST (ctree);
5172 if (GTK_CMCTREE_ROW (node)->row.style == style)
5175 visible = gtk_cmctree_is_viewable (ctree, node);
5176 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5178 old_width = g_new (gint, clist->columns);
5179 for (i = 0; i < clist->columns; i++)
5180 if (clist->column[i].auto_resize)
5182 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
5183 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition);
5184 old_width[i] = requisition.width;
5188 if (GTK_CMCTREE_ROW (node)->row.style)
5190 if (GTK_WIDGET_REALIZED (ctree))
5191 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
5192 g_object_unref (GTK_CMCTREE_ROW (node)->row.style);
5195 GTK_CMCTREE_ROW (node)->row.style = style;
5197 if (GTK_CMCTREE_ROW (node)->row.style)
5199 g_object_ref (GTK_CMCTREE_ROW (node)->row.style);
5201 if (GTK_WIDGET_REALIZED (ctree))
5202 GTK_CMCTREE_ROW (node)->row.style =
5203 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style,
5204 clist->clist_window);
5207 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5209 for (i = 0; i < clist->columns; i++)
5210 if (clist->column[i].auto_resize)
5211 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i,
5215 tree_draw_node (ctree, node);
5219 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree,
5220 GtkCMCTreeNode *node)
5222 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
5223 g_return_val_if_fail (node != NULL, NULL);
5225 return GTK_CMCTREE_ROW (node)->row.style;
5229 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree,
5230 GtkCMCTreeNode *node,
5231 const GdkColor *color)
5233 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5234 g_return_if_fail (node != NULL);
5238 GTK_CMCTREE_ROW (node)->row.foreground = *color;
5239 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE;
5240 if (GTK_WIDGET_REALIZED (ctree))
5241 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
5242 >K_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE);
5245 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE;
5247 tree_draw_node (ctree, node);
5251 gtk_cmctree_node_set_background (GtkCMCTree *ctree,
5252 GtkCMCTreeNode *node,
5253 const GdkColor *color)
5255 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5256 g_return_if_fail (node != NULL);
5260 GTK_CMCTREE_ROW (node)->row.background = *color;
5261 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE;
5262 if (GTK_WIDGET_REALIZED (ctree))
5263 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
5264 >K_CMCTREE_ROW (node)->row.background, TRUE, TRUE);
5267 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE;
5269 tree_draw_node (ctree, node);
5273 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree,
5274 GtkCMCTreeNode *node,
5277 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL);
5281 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree,
5282 GtkCMCTreeNode *node,
5284 GDestroyNotify destroy)
5286 GDestroyNotify dnotify;
5289 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5290 g_return_if_fail (node != NULL);
5292 dnotify = GTK_CMCTREE_ROW (node)->row.destroy;
5293 ddata = GTK_CMCTREE_ROW (node)->row.data;
5295 GTK_CMCTREE_ROW (node)->row.data = data;
5296 GTK_CMCTREE_ROW (node)->row.destroy = destroy;
5303 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree,
5304 GtkCMCTreeNode *node)
5306 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
5308 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL;
5312 gtk_cmctree_node_moveto (GtkCMCTree *ctree,
5313 GtkCMCTreeNode *node,
5321 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5323 clist = GTK_CMCLIST (ctree);
5325 while (node && !gtk_cmctree_is_viewable (ctree, node))
5326 node = GTK_CMCTREE_ROW (node)->parent;
5329 row = g_list_position (clist->row_list, (GList *)node);
5331 gtk_cmclist_moveto (clist, row, column, row_align, col_align);
5335 gtk_cmctree_node_is_visible (GtkCMCTree *ctree,
5336 GtkCMCTreeNode *node)
5340 g_return_val_if_fail (ctree != NULL, 0);
5341 g_return_val_if_fail (node != NULL, 0);
5343 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node);
5344 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row);
5348 /***********************************************************
5349 * GtkCMCTree specific functions *
5350 ***********************************************************/
5353 gtk_cmctree_set_indent (GtkCMCTree *ctree,
5358 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5359 g_return_if_fail (indent >= 0);
5361 if (indent == ctree->tree_indent)
5364 clist = GTK_CMCLIST (ctree);
5365 ctree->tree_indent = indent;
5367 if (clist->column[ctree->tree_column].auto_resize &&
5368 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5369 gtk_cmclist_set_column_width
5370 (clist, ctree->tree_column,
5371 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
5373 CLIST_REFRESH (ctree);
5377 gtk_cmctree_set_spacing (GtkCMCTree *ctree,
5383 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5384 g_return_if_fail (spacing >= 0);
5386 if (spacing == ctree->tree_spacing)
5389 clist = GTK_CMCLIST (ctree);
5391 old_spacing = ctree->tree_spacing;
5392 ctree->tree_spacing = spacing;
5394 if (clist->column[ctree->tree_column].auto_resize &&
5395 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5396 gtk_cmclist_set_column_width (clist, ctree->tree_column,
5397 clist->column[ctree->tree_column].width +
5398 spacing - old_spacing);
5400 CLIST_REFRESH (ctree);
5404 gtk_cmctree_set_show_stub (GtkCMCTree *ctree,
5407 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5409 show_stub = show_stub != FALSE;
5411 if (show_stub != ctree->show_stub)
5415 clist = GTK_CMCLIST (ctree);
5416 ctree->show_stub = show_stub;
5418 if (CLIST_UNFROZEN (clist) && clist->rows &&
5419 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
5420 GTK_CMCLIST_GET_CLASS (clist)->draw_row
5421 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list));
5426 gtk_cmctree_set_line_style (GtkCMCTree *ctree,
5427 GtkCMCTreeLineStyle line_style)
5430 GtkCMCTreeLineStyle old_style;
5432 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5434 if (line_style == ctree->line_style)
5437 clist = GTK_CMCLIST (ctree);
5439 old_style = ctree->line_style;
5440 ctree->line_style = line_style;
5442 if (clist->column[ctree->tree_column].auto_resize &&
5443 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5445 if (old_style == GTK_CMCTREE_LINES_TABBED)
5446 gtk_cmclist_set_column_width
5447 (clist, ctree->tree_column,
5448 clist->column[ctree->tree_column].width - 3);
5449 else if (line_style == GTK_CMCTREE_LINES_TABBED)
5450 gtk_cmclist_set_column_width
5451 (clist, ctree->tree_column,
5452 clist->column[ctree->tree_column].width + 3);
5455 if (GTK_WIDGET_REALIZED (ctree))
5459 case GTK_CMCTREE_LINES_SOLID:
5460 if (GTK_WIDGET_REALIZED (ctree))
5461 gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID,
5462 GDK_CAP_BUTT, GDK_JOIN_MITER);
5464 case GTK_CMCTREE_LINES_DOTTED:
5465 if (GTK_WIDGET_REALIZED (ctree))
5466 gdk_gc_set_line_attributes (ctree->lines_gc, 1,
5467 GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER);
5468 gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2);
5470 case GTK_CMCTREE_LINES_TABBED:
5471 if (GTK_WIDGET_REALIZED (ctree))
5472 gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID,
5473 GDK_CAP_BUTT, GDK_JOIN_MITER);
5475 case GTK_CMCTREE_LINES_NONE:
5480 CLIST_REFRESH (ctree);
5485 gtk_cmctree_set_expander_style (GtkCMCTree *ctree,
5486 GtkCMCTreeExpanderStyle expander_style)
5489 GtkCMCTreeExpanderStyle old_style;
5491 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5493 if (expander_style == ctree->expander_style)
5496 clist = GTK_CMCLIST (ctree);
5498 old_style = ctree->expander_style;
5499 ctree->expander_style = expander_style;
5501 if (clist->column[ctree->tree_column].auto_resize &&
5502 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
5506 new_width = clist->column[ctree->tree_column].width;
5509 case GTK_CMCTREE_EXPANDER_NONE:
5511 case GTK_CMCTREE_EXPANDER_TRIANGLE:
5512 new_width -= PM_SIZE + 3;
5514 case GTK_CMCTREE_EXPANDER_SQUARE:
5515 case GTK_CMCTREE_EXPANDER_CIRCULAR:
5516 new_width -= PM_SIZE + 1;
5520 switch (expander_style)
5522 case GTK_CMCTREE_EXPANDER_NONE:
5524 case GTK_CMCTREE_EXPANDER_TRIANGLE:
5525 new_width += PM_SIZE + 3;
5527 case GTK_CMCTREE_EXPANDER_SQUARE:
5528 case GTK_CMCTREE_EXPANDER_CIRCULAR:
5529 new_width += PM_SIZE + 1;
5533 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width);
5536 if (GTK_WIDGET_DRAWABLE (clist))
5537 CLIST_REFRESH (clist);
5541 /***********************************************************
5542 * Tree sorting functions *
5543 ***********************************************************/
5547 tree_sort (GtkCMCTree *ctree,
5548 GtkCMCTreeNode *node,
5551 GtkCMCTreeNode *list_start;
5552 GtkCMCTreeNode *cmp;
5553 GtkCMCTreeNode *work;
5556 clist = GTK_CMCLIST (ctree);
5559 list_start = GTK_CMCTREE_ROW (node)->children;
5561 list_start = GTK_CMCTREE_NODE (clist->row_list);
5566 work = GTK_CMCTREE_ROW (cmp)->sibling;
5569 if (clist->sort_type == GTK_SORT_ASCENDING)
5572 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0)
5578 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0)
5581 work = GTK_CMCTREE_ROW (work)->sibling;
5583 if (cmp == list_start)
5584 list_start = GTK_CMCTREE_ROW (cmp)->sibling;
5587 gtk_cmctree_unlink (ctree, cmp, FALSE);
5588 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE);
5594 gtk_cmctree_sort_recursive (GtkCMCTree *ctree,
5595 GtkCMCTreeNode *node)
5598 GtkCMCTreeNode *focus_node = NULL;
5600 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5602 clist = GTK_CMCLIST (ctree);
5604 gtk_cmclist_freeze (clist);
5606 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
5608 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
5610 g_list_free (clist->undo_selection);
5611 g_list_free (clist->undo_unselection);
5612 clist->undo_selection = NULL;
5613 clist->undo_unselection = NULL;
5616 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
5618 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
5620 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL);
5623 tree_sort (ctree, NULL, NULL);
5627 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5628 clist->undo_anchor = clist->focus_row;
5631 gtk_cmclist_thaw (clist);
5635 real_sort_list (GtkCMCList *clist)
5637 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL);
5641 gtk_cmctree_sort_node (GtkCMCTree *ctree,
5642 GtkCMCTreeNode *node)
5645 GtkCMCTreeNode *focus_node = NULL;
5647 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5649 clist = GTK_CMCLIST (ctree);
5651 gtk_cmclist_freeze (clist);
5653 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
5655 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
5657 g_list_free (clist->undo_selection);
5658 g_list_free (clist->undo_unselection);
5659 clist->undo_selection = NULL;
5660 clist->undo_unselection = NULL;
5663 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
5664 focus_node = GTK_CMCTREE_NODE
5665 (g_list_nth (clist->row_list, clist->focus_row));
5667 tree_sort (ctree, node, NULL);
5671 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5672 clist->undo_anchor = clist->focus_row;
5675 gtk_cmclist_thaw (clist);
5678 /************************************************************************/
5681 fake_unselect_all (GtkCMCList *clist,
5685 GList *focus_node = NULL;
5687 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
5689 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
5690 GTK_CMCTREE_ROW (focus_node)->row.selectable)
5692 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
5694 if (CLIST_UNFROZEN (clist) &&
5695 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5696 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
5697 GTK_CMCLIST_ROW (focus_node));
5701 clist->undo_selection = clist->selection;
5702 clist->selection = NULL;
5703 clist->selection_end = NULL;
5705 for (list = clist->undo_selection; list; list = list->next)
5707 if (list->data == focus_node)
5710 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
5711 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data));
5716 selection_find (GtkCMCList *clist,
5718 GList *row_list_element)
5720 return g_list_find (clist->selection, row_list_element);
5724 resync_selection (GtkCMCList *clist, GdkEvent *event)
5728 GtkCMCTreeNode *node;
5734 g_return_if_fail (GTK_IS_CMCTREE (clist));
5736 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5739 if (clist->anchor < 0 || clist->drag_pos < 0)
5742 ctree = GTK_CMCTREE (clist);
5744 clist->freeze_count++;
5746 i = MIN (clist->anchor, clist->drag_pos);
5747 e = MAX (clist->anchor, clist->drag_pos);
5749 if (clist->undo_selection)
5751 list = clist->selection;
5752 clist->selection = clist->undo_selection;
5753 clist->selection_end = g_list_last (clist->selection);
5754 clist->undo_selection = list;
5755 list = clist->selection;
5764 if (gtk_cmctree_is_viewable (ctree, node))
5766 row = g_list_position (clist->row_list, (GList *)node);
5767 if (row >= i && row <= e)
5770 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable)
5772 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5773 gtk_cmctree_unselect (ctree, node);
5774 clist->undo_selection = g_list_prepend (clist->undo_selection,
5780 if (clist->anchor < clist->drag_pos)
5782 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
5783 i++, node = GTK_CMCTREE_NODE_NEXT (node))
5784 if (GTK_CMCTREE_ROW (node)->row.selectable)
5786 if (g_list_find (clist->selection, node))
5788 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5790 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5791 gtk_cmctree_unselect (ctree, node);
5792 clist->undo_selection =
5793 g_list_prepend (clist->undo_selection, node);
5796 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5798 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5799 clist->undo_unselection =
5800 g_list_prepend (clist->undo_unselection, node);
5806 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
5807 e--, node = GTK_CMCTREE_NODE_PREV (node))
5808 if (GTK_CMCTREE_ROW (node)->row.selectable)
5810 if (g_list_find (clist->selection, node))
5812 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5814 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5815 gtk_cmctree_unselect (ctree, node);
5816 clist->undo_selection =
5817 g_list_prepend (clist->undo_selection, node);
5820 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5822 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5823 clist->undo_unselection =
5824 g_list_prepend (clist->undo_unselection, node);
5829 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
5830 for (list = clist->undo_unselection; list; list = list->next)
5831 gtk_cmctree_select (ctree, list->data);
5834 clist->drag_pos = -1;
5836 if (!CLIST_UNFROZEN (clist))
5837 clist->freeze_count--;
5841 real_undo_selection (GtkCMCList *clist)
5846 g_return_if_fail (GTK_IS_CMCTREE (clist));
5848 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5851 if (!(clist->undo_selection || clist->undo_unselection))
5853 gtk_cmclist_unselect_all (clist);
5857 ctree = GTK_CMCTREE (clist);
5859 for (work = clist->undo_selection; work; work = work->next)
5860 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5861 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data));
5863 for (work = clist->undo_unselection; work; work = work->next)
5864 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5865 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data));
5867 if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
5869 clist->focus_row = clist->undo_anchor;
5870 gtk_widget_queue_draw (GTK_WIDGET (clist));
5873 clist->focus_row = clist->undo_anchor;
5875 clist->undo_anchor = -1;
5877 g_list_free (clist->undo_selection);
5878 g_list_free (clist->undo_unselection);
5879 clist->undo_selection = NULL;
5880 clist->undo_unselection = NULL;
5882 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5883 clist->clist_window_height)
5884 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
5885 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5886 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
5891 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree,
5892 GtkCMCTreeCompareDragFunc cmp_func)
5894 g_return_if_fail (GTK_IS_CMCTREE (ctree));
5896 ctree->drag_compare = cmp_func;
5900 check_drag (GtkCMCTree *ctree,
5901 GtkCMCTreeNode *drag_source,
5902 GtkCMCTreeNode *drag_target,
5903 GtkCMCListDragPos insert_pos)
5905 g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5907 if (drag_source && drag_source != drag_target &&
5908 (!GTK_CMCTREE_ROW (drag_source)->children ||
5909 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target)))
5913 case GTK_CMCLIST_DRAG_NONE:
5915 case GTK_CMCLIST_DRAG_AFTER:
5916 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source)
5917 return (!ctree->drag_compare ||
5918 ctree->drag_compare (ctree,
5920 GTK_CMCTREE_ROW (drag_target)->parent,
5921 GTK_CMCTREE_ROW (drag_target)->sibling));
5923 case GTK_CMCLIST_DRAG_BEFORE:
5924 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target)
5925 return (!ctree->drag_compare ||
5926 ctree->drag_compare (ctree,
5928 GTK_CMCTREE_ROW (drag_target)->parent,
5931 case GTK_CMCLIST_DRAG_INTO:
5932 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf &&
5933 GTK_CMCTREE_ROW (drag_target)->children != drag_source)
5934 return (!ctree->drag_compare ||
5935 ctree->drag_compare (ctree,
5938 GTK_CMCTREE_ROW (drag_target)->children));
5947 /************************************/
5949 drag_dest_info_destroy (gpointer data)
5951 GtkCMCListDestInfo *info = data;
5957 drag_dest_cell (GtkCMCList *clist,
5960 GtkCMCListDestInfo *dest_info)
5964 widget = GTK_WIDGET (clist);
5966 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5968 y -= (GTK_CONTAINER (widget)->border_width +
5969 widget->style->ythickness + clist->column_title_area.height);
5970 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5972 if (dest_info->cell.row >= clist->rows)
5974 dest_info->cell.row = clist->rows - 1;
5975 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5977 if (dest_info->cell.row < -1)
5978 dest_info->cell.row = -1;
5980 x -= GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
5982 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5984 if (dest_info->cell.row >= 0)
5989 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5991 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) &&
5992 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list,
5993 dest_info->cell.row))->is_leaf)
5995 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
5996 h = clist->row_height / 4;
5998 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
6000 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
6001 h = clist->row_height / 2;
6004 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
6007 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
6008 else if (clist->row_height - y_delta < h)
6009 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
6015 gtk_cmctree_drag_begin (GtkWidget *widget,
6016 GdkDragContext *context)
6022 g_return_if_fail (GTK_IS_CMCTREE (widget));
6023 g_return_if_fail (context != NULL);
6025 clist = GTK_CMCLIST (widget);
6026 ctree = GTK_CMCTREE (widget);
6028 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist);
6029 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
6030 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
6034 GtkCMCTreeNode *node;
6036 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
6037 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
6038 clist->click_cell.row));
6041 if (GTK_CMCELL_PIXTEXT
6042 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
6044 gtk_drag_set_icon_pixmap
6046 gtk_widget_get_colormap (widget),
6048 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap,
6050 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask,
6055 gtk_drag_set_icon_default (context);
6060 gtk_cmctree_drag_motion (GtkWidget *widget,
6061 GdkDragContext *context,
6068 GtkCMCListDestInfo new_info;
6069 GtkCMCListDestInfo *dest_info;
6071 g_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
6073 clist = GTK_CMCLIST (widget);
6074 ctree = GTK_CMCTREE (widget);
6076 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
6080 dest_info = g_new (GtkCMCListDestInfo, 1);
6082 dest_info->cell.row = -1;
6083 dest_info->cell.column = -1;
6084 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
6086 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
6087 drag_dest_info_destroy);
6090 drag_dest_cell (clist, x, y, &new_info);
6092 if (GTK_CMCLIST_REORDERABLE (clist))
6095 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
6097 list = context->targets;
6100 if (atom == GDK_POINTER_TO_ATOM (list->data))
6107 GtkCMCTreeNode *drag_source;
6108 GtkCMCTreeNode *drag_target;
6110 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
6111 clist->click_cell.row));
6112 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
6113 new_info.cell.row));
6115 if (gtk_drag_get_source_widget (context) != widget ||
6116 !check_drag (ctree, drag_source, drag_target,
6117 new_info.insert_pos))
6119 if (dest_info->cell.row < 0)
6121 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
6127 if (new_info.cell.row != dest_info->cell.row ||
6128 (new_info.cell.row == dest_info->cell.row &&
6129 dest_info->insert_pos != new_info.insert_pos))
6131 if (dest_info->cell.row >= 0)
6132 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
6134 g_list_nth (clist->row_list, dest_info->cell.row)->data,
6135 dest_info->cell.row, dest_info->insert_pos);
6137 dest_info->insert_pos = new_info.insert_pos;
6138 dest_info->cell.row = new_info.cell.row;
6139 dest_info->cell.column = new_info.cell.column;
6141 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
6143 g_list_nth (clist->row_list, dest_info->cell.row)->data,
6144 dest_info->cell.row, dest_info->insert_pos);
6146 clist->drag_highlight_row = dest_info->cell.row;
6147 clist->drag_highlight_pos = dest_info->insert_pos;
6149 gdk_drag_status (context, context->suggested_action, time);
6155 dest_info->insert_pos = new_info.insert_pos;
6156 dest_info->cell.row = new_info.cell.row;
6157 dest_info->cell.column = new_info.cell.column;
6162 gtk_cmctree_drag_data_received (GtkWidget *widget,
6163 GdkDragContext *context,
6166 GtkSelectionData *selection_data,
6173 g_return_if_fail (GTK_IS_CMCTREE (widget));
6174 g_return_if_fail (context != NULL);
6175 g_return_if_fail (selection_data != NULL);
6177 ctree = GTK_CMCTREE (widget);
6178 clist = GTK_CMCLIST (widget);
6180 if (GTK_CMCLIST_REORDERABLE (clist) &&
6181 gtk_drag_get_source_widget (context) == widget &&
6182 selection_data->target ==
6183 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
6184 selection_data->format == 8 &&
6185 selection_data->length == sizeof (GtkCMCListCellInfo))
6187 GtkCMCListCellInfo *source_info;
6189 source_info = (GtkCMCListCellInfo *)(selection_data->data);
6192 GtkCMCListDestInfo dest_info;
6193 GtkCMCTreeNode *source_node;
6194 GtkCMCTreeNode *dest_node;
6196 drag_dest_cell (clist, x, y, &dest_info);
6198 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
6200 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
6201 dest_info.cell.row));
6203 if (!source_node || !dest_node)
6206 switch (dest_info.insert_pos)
6208 case GTK_CMCLIST_DRAG_NONE:
6210 case GTK_CMCLIST_DRAG_INTO:
6211 if (check_drag (ctree, source_node, dest_node,
6212 dest_info.insert_pos))
6213 gtk_cmctree_move (ctree, source_node, dest_node,
6214 GTK_CMCTREE_ROW (dest_node)->children);
6215 g_dataset_remove_data (context, "gtk-clist-drag-dest");
6217 case GTK_CMCLIST_DRAG_BEFORE:
6218 if (check_drag (ctree, source_node, dest_node,
6219 dest_info.insert_pos))
6220 gtk_cmctree_move (ctree, source_node,
6221 GTK_CMCTREE_ROW (dest_node)->parent, dest_node);
6222 g_dataset_remove_data (context, "gtk-clist-drag-dest");
6224 case GTK_CMCLIST_DRAG_AFTER:
6225 if (check_drag (ctree, source_node, dest_node,
6226 dest_info.insert_pos))
6227 gtk_cmctree_move (ctree, source_node,
6228 GTK_CMCTREE_ROW (dest_node)->parent,
6229 GTK_CMCTREE_ROW (dest_node)->sibling);
6230 g_dataset_remove_data (context, "gtk-clist-drag-dest");
6238 gtk_cmctree_node_get_type (void)
6240 static GType our_type = 0;
6243 our_type = g_pointer_type_register_static ("GtkCMCTreeNode");