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/.
35 #include <gdk/gdkkeysyms.h>
36 #include "gtkcmctree.h"
37 #include "claws-marshal.h"
42 #define TAB_SIZE (PM_SIZE + 6)
43 #define CELL_SPACING 1
44 #define CLIST_OPTIMUM_SIZE 64
45 #define COLUMN_INSET 3
48 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
49 (((row) + 1) * CELL_SPACING) + \
51 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
52 ((clist)->row_height + CELL_SPACING))
53 #define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \
55 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
58 gtk_cmctree_pos_get_type (void)
60 static GType etype = 0;
62 static const GEnumValue values[] = {
63 { GTK_CMCTREE_POS_BEFORE, "GTK_CMCTREE_POS_BEFORE", "before" },
64 { GTK_CMCTREE_POS_AS_CHILD, "GTK_CMCTREE_POS_AS_CHILD", "as-child" },
65 { GTK_CMCTREE_POS_AFTER, "GTK_CMCTREE_POS_AFTER", "after" },
68 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values);
73 gtk_cmctree_line_style_get_type (void)
75 static GType etype = 0;
77 static const GEnumValue values[] = {
78 { GTK_CMCTREE_LINES_NONE, "GTK_CMCTREE_LINES_NONE", "none" },
81 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values);
86 gtk_cmctree_expander_style_get_type (void)
88 static GType etype = 0;
90 static const GEnumValue values[] = {
91 { GTK_CMCTREE_EXPANDER_NONE, "GTK_CMCTREE_EXPANDER_NONE", "none" },
92 { GTK_CMCTREE_EXPANDER_TRIANGLE, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" },
95 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values);
100 gtk_cmctree_expansion_type_get_type (void)
102 static GType etype = 0;
104 static const GEnumValue values[] = {
105 { GTK_CMCTREE_EXPANSION_EXPAND, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" },
106 { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" },
107 { GTK_CMCTREE_EXPANSION_COLLAPSE, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" },
108 { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" },
109 { GTK_CMCTREE_EXPANSION_TOGGLE, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" },
110 { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" },
113 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values);
120 COLUMN_FROM_XPIXEL (GtkCMCList * clist,
125 for (i = 0; i < clist->columns; i++)
126 if (clist->column[i].visible)
128 cx = clist->column[i].area.x + clist->hoffset;
130 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
131 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
139 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
140 #define CLIST_REFRESH(clist) G_STMT_START { \
141 if (CLIST_UNFROZEN (clist)) \
142 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
158 static void gtk_cmctree_class_init (GtkCMCTreeClass *klass);
159 static void gtk_cmctree_init (GtkCMCTree *ctree);
160 static GObject* gtk_cmctree_constructor (GType type,
161 guint n_construct_properties,
162 GObjectConstructParam *construct_params);
163 static void gtk_cmctree_set_arg (GObject *object,
167 static void gtk_cmctree_get_arg (GObject *object,
171 static void gtk_cmctree_realize (GtkWidget *widget);
172 static void gtk_cmctree_unrealize (GtkWidget *widget);
173 static gint gtk_cmctree_button_press (GtkWidget *widget,
174 GdkEventButton *event);
175 static void ctree_attach_styles (GtkCMCTree *ctree,
176 GtkCMCTreeNode *node,
178 static void ctree_detach_styles (GtkCMCTree *ctree,
179 GtkCMCTreeNode *node,
181 static void set_cell_contents (GtkCMCList *clist,
182 GtkCMCListRow *clist_row,
188 static void set_node_info (GtkCMCTree *ctree,
189 GtkCMCTreeNode *node,
192 GdkPixbuf *pixbuf_closed,
193 GdkPixbuf *pixbuf_opened,
196 static GtkCMCTreeRow *row_new (GtkCMCTree *ctree);
197 static void row_delete (GtkCMCTree *ctree,
198 GtkCMCTreeRow *ctree_row);
199 static void tree_delete (GtkCMCTree *ctree,
200 GtkCMCTreeNode *node,
202 static void tree_delete_row (GtkCMCTree *ctree,
203 GtkCMCTreeNode *node,
205 static void real_clear (GtkCMCList *clist);
206 static void tree_update_level (GtkCMCTree *ctree,
207 GtkCMCTreeNode *node,
209 static void tree_select (GtkCMCTree *ctree,
210 GtkCMCTreeNode *node,
212 static void tree_unselect (GtkCMCTree *ctree,
213 GtkCMCTreeNode *node,
215 static void real_select_all (GtkCMCList *clist);
216 static void real_unselect_all (GtkCMCList *clist);
217 static void tree_expand (GtkCMCTree *ctree,
218 GtkCMCTreeNode *node,
220 static void tree_collapse (GtkCMCTree *ctree,
221 GtkCMCTreeNode *node,
223 static void tree_collapse_to_depth (GtkCMCTree *ctree,
224 GtkCMCTreeNode *node,
226 static void tree_toggle_expansion (GtkCMCTree *ctree,
227 GtkCMCTreeNode *node,
229 static void change_focus_row_expansion (GtkCMCTree *ctree,
230 GtkCMCTreeExpansionType expansion);
231 static void real_select_row (GtkCMCList *clist,
235 static void real_unselect_row (GtkCMCList *clist,
239 static void real_tree_select (GtkCMCTree *ctree,
240 GtkCMCTreeNode *node,
242 static void real_tree_unselect (GtkCMCTree *ctree,
243 GtkCMCTreeNode *node,
245 static void real_tree_expand (GtkCMCTree *ctree,
246 GtkCMCTreeNode *node);
247 static void real_tree_collapse (GtkCMCTree *ctree,
248 GtkCMCTreeNode *node);
249 static void real_tree_move (GtkCMCTree *ctree,
250 GtkCMCTreeNode *node,
251 GtkCMCTreeNode *new_parent,
252 GtkCMCTreeNode *new_sibling);
253 static void real_row_move (GtkCMCList *clist,
256 static void gtk_cmctree_link (GtkCMCTree *ctree,
257 GtkCMCTreeNode *node,
258 GtkCMCTreeNode *parent,
259 GtkCMCTreeNode *sibling,
260 gboolean update_focus_row);
261 static void gtk_cmctree_unlink (GtkCMCTree *ctree,
262 GtkCMCTreeNode *node,
263 gboolean update_focus_row);
264 static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree,
265 GtkCMCTreeNode *node);
266 static gboolean ctree_is_hot_spot (GtkCMCTree *ctree,
267 GtkCMCTreeNode *node,
271 static void tree_sort (GtkCMCTree *ctree,
272 GtkCMCTreeNode *node,
274 static void fake_unselect_all (GtkCMCList *clist,
276 static GList * selection_find (GtkCMCList *clist,
278 GList *row_list_element);
279 static void resync_selection (GtkCMCList *clist,
281 static void real_undo_selection (GtkCMCList *clist);
282 static void select_row_recursive (GtkCMCTree *ctree,
283 GtkCMCTreeNode *node,
285 static gint real_insert_row (GtkCMCList *clist,
288 static void real_remove_row (GtkCMCList *clist,
290 static void real_sort_list (GtkCMCList *clist);
291 static void cell_size_request (GtkCMCList *clist,
292 GtkCMCListRow *clist_row,
294 GtkRequisition *requisition);
295 static void column_auto_resize (GtkCMCList *clist,
296 GtkCMCListRow *clist_row,
299 static void auto_resize_columns (GtkCMCList *clist);
302 static gboolean check_drag (GtkCMCTree *ctree,
303 GtkCMCTreeNode *drag_source,
304 GtkCMCTreeNode *drag_target,
305 GtkCMCListDragPos insert_pos);
306 static void gtk_cmctree_drag_begin (GtkWidget *widget,
307 GdkDragContext *context);
308 static gint gtk_cmctree_drag_motion (GtkWidget *widget,
309 GdkDragContext *context,
313 static void gtk_cmctree_drag_data_received (GtkWidget *widget,
314 GdkDragContext *context,
317 GtkSelectionData *selection_data,
320 static void remove_grab (GtkCMCList *clist);
321 static void drag_dest_cell (GtkCMCList *clist,
324 GtkCMCListDestInfo *dest_info);
334 CHANGE_FOCUS_ROW_EXPANSION,
338 static GtkCMCListClass *parent_class = NULL;
339 static GtkContainerClass *container_class = NULL;
340 static guint ctree_signals[LAST_SIGNAL] = {0};
344 gtk_cmctree_get_type (void)
346 static GType ctree_type = 0;
350 static const GTypeInfo ctree_info =
352 sizeof (GtkCMCTreeClass),
354 (GBaseInitFunc) NULL,
355 (GBaseFinalizeFunc) NULL,
357 (GClassInitFunc) gtk_cmctree_class_init,
358 (GClassFinalizeFunc) NULL,
359 NULL, /* class_data */
363 (GInstanceInitFunc) gtk_cmctree_init,
365 (const GTypeValueTable *) NULL /* value table */
368 ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0);
375 draw_cell_pixbuf (GdkWindow *window,
376 GdkRectangle *clip_rectangle,
387 if (!pixbuf || (width == 0 && height == 0))
390 if (x < clip_rectangle->x)
392 xsrc = clip_rectangle->x - x;
394 x = clip_rectangle->x;
396 if (x + width > clip_rectangle->x + clip_rectangle->width)
397 width = clip_rectangle->x + clip_rectangle->width - x;
399 if (y < clip_rectangle->y)
401 ysrc = clip_rectangle->y - y;
403 y = clip_rectangle->y;
406 if (y + height > clip_rectangle->y + clip_rectangle->height)
407 height = clip_rectangle->y + clip_rectangle->height - y;
409 gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
412 return x + MAX (width, 0);
416 draw_expander (GtkCMCTree *ctree,
417 GtkCMCTreeRow *ctree_row,
419 GdkRectangle *clip_rectangle,
424 gint justification_factor;
427 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
430 clist = GTK_CMCLIST (ctree);
431 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
432 justification_factor = -1;
434 justification_factor = 1;
435 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
436 y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
437 (clip_rectangle->height + 1) % 2) + 1;
439 y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 -
440 (clip_rectangle->height/2 + 1) % 2) + 1;
442 if (!ctree_row->children)
444 return x + justification_factor * (PM_SIZE + 3);
447 /* pixel offsets +/- 1 or +/- justification_factor here and there ..
448 * to fill correctly, somewhat ... what do I do wrong?
450 gdk_cairo_set_source_color(cr, >k_widget_get_style(GTK_WIDGET(ctree))->text[GTK_STATE_NORMAL]);
451 if (ctree_row->expanded)
453 gint tmp3 = PM_SIZE / 2;
454 gint tmp6 = PM_SIZE / 6;
455 cairo_move_to(cr, x + justification_factor * (tmp3 + tmp6) + (PM_SIZE / 2), y + 1);
456 cairo_rel_line_to(cr, 0, tmp3 + tmp6 + 1);
457 cairo_rel_line_to(cr, -justification_factor * (tmp3 + tmp6) - justification_factor, -1);
461 gint tmp3 = PM_SIZE / 2;
462 gint tmp6 = PM_SIZE / 6;
463 cairo_move_to(cr, x + tmp6 - justification_factor + (PM_SIZE / 2), y + tmp6 - 1);
464 cairo_rel_line_to(cr, justification_factor * tmp3, tmp3);
465 cairo_rel_line_to(cr, -justification_factor * tmp3, tmp3);
469 x += justification_factor * (PM_SIZE + 3);
475 get_offset(GtkCMCTree *ctree,
476 GtkCMCTreeRow *ctree_row,
478 GdkRectangle *clip_rectangle)
481 justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
484 return (clip_rectangle->x + clip_rectangle->width - 1 -
485 ctree->tree_indent * (ctree_row->level - 1));
487 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
491 get_cell_style (GtkCMCList *clist,
492 GtkCMCListRow *clist_row,
499 gtkstyle = gtk_widget_get_style (GTK_WIDGET (clist));
501 if (clist_row->cell[column].style)
504 *style = clist_row->cell[column].style;
506 else if (clist_row->style)
509 *style = clist_row->style;
518 static gboolean filter_fg (PangoAttribute *attribute, gpointer data)
520 const PangoAttrClass *klass = attribute->klass;
521 if (klass->type == PANGO_ATTR_FOREGROUND)
528 create_cell_layout (GtkCMCList *clist,
529 GtkCMCListRow *clist_row,
537 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style);
540 cell = &clist_row->cell[column];
543 case GTK_CMCELL_TEXT:
544 case GTK_CMCELL_PIXTEXT:
545 text = ((cell->type == GTK_CMCELL_PIXTEXT) ?
546 GTK_CMCELL_PIXTEXT (*cell)->text :
547 GTK_CMCELL_TEXT (*cell)->text);
552 if (!GTK_SCTREE(clist)->use_markup[column]) {
553 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
554 ((cell->type == GTK_CMCELL_PIXTEXT) ?
555 GTK_CMCELL_PIXTEXT (*cell)->text :
556 GTK_CMCELL_TEXT (*cell)->text));
557 pango_layout_set_font_description (layout, style->font_desc);
559 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist));
560 layout = pango_layout_new (context);
561 pango_layout_set_markup (layout, text, -1);
562 pango_layout_set_font_description (layout, style->font_desc);
563 if (clist_row->state == GTK_STATE_SELECTED) {
564 /* for selected row, we should remove any forced foreground color
565 * or it looks like shit */
566 PangoAttrList *list = pango_layout_get_attributes(layout);
567 PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL);
569 pango_attr_list_unref(rem);
582 draw_row (GtkCMCList *clist,
585 GtkCMCListRow *clist_row)
591 GdkRectangle row_rectangle;
592 GdkRectangle cell_rectangle;
593 GdkRectangle clip_rectangle;
594 GdkRectangle intersect_rectangle;
599 static GdkColor greybg={0, 0, 0, 0};
600 static gboolean color_change = TRUE;
602 GdkColor *fgcolor, *bgcolor;
604 cm_return_if_fail (clist != NULL);
605 widget = GTK_WIDGET (clist);
607 /* if the function is passed the pointer to the row instead of null,
608 * it avoids this expensive lookup */
610 clist_row = (g_list_nth (clist->row_list, row))->data;
612 style = clist_row->style ? clist_row->style : gtk_widget_get_style (widget);
614 if (greybg.pixel == 0 &&
618 GdkColor normalbg = {0, 0xffff, 0xffff, 0xffff};
620 normalbg = style->base[GTK_STATE_NORMAL];
622 if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
623 greybg.pixel = normalbg.pixel;
624 greybg.red = normalbg.red - prefs_common.stripes_color_offset;
625 greybg.green = normalbg.green - prefs_common.stripes_color_offset;
626 greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
627 } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
628 greybg.pixel = normalbg.pixel;
629 greybg.red = normalbg.red + prefs_common.stripes_color_offset;
630 greybg.green = normalbg.green + prefs_common.stripes_color_offset;
631 greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
633 color_change = FALSE;
637 /* bail now if we arn't drawable yet */
638 if (!gtk_widget_is_drawable (GTK_WIDGET(clist)) || row < 0 || row >= clist->rows)
641 ctree = GTK_CMCTREE (clist);
643 /* rectangle of the entire row */
645 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
646 row_rectangle.width = clist->clist_window_width;
647 row_rectangle.height = clist->row_height;
649 /* rectangle of the cell spacing above the row */
650 cell_rectangle.x = 0;
651 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
652 cell_rectangle.width = row_rectangle.width;
653 cell_rectangle.height = CELL_SPACING;
655 /* rectangle used to clip drawing operations, its y and height
656 * positions only need to be set once, so we set them once here.
657 * the x and width are set withing the drawing loop below once per
659 clip_rectangle.y = row_rectangle.y;
660 clip_rectangle.height = row_rectangle.height;
662 if (prefs_common.use_stripes_everywhere && GTK_SCTREE(ctree)->show_stripes
663 && color_change && row % 2) {
666 bgcolor = &style->base[GTK_STATE_NORMAL];
668 state = clist_row->state;
670 cr = gdk_cairo_create(clist->clist_window);
672 if (clist_row->fg_set && state != GTK_STATE_SELECTED)
673 fgcolor = &clist_row->foreground;
675 fgcolor = &style->text[clist_row->state];
676 /* draw the cell borders */
679 crect = &intersect_rectangle;
681 if (gdk_rectangle_intersect (area, &cell_rectangle, crect)) {
682 gdk_cairo_rectangle(cr, &cell_rectangle);
683 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
685 cairo_rectangle(cr, cell_rectangle.x, cell_rectangle.y + row_rectangle.height + 1,cell_rectangle.width,cell_rectangle.height);
691 crect = &cell_rectangle;
693 gdk_cairo_rectangle(cr, &cell_rectangle);
694 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
696 cairo_rectangle(cr, cell_rectangle.x, cell_rectangle.y + row_rectangle.height + 1,cell_rectangle.width,cell_rectangle.height);
700 /* the last row has to clear its bottom cell spacing too */
701 if (clist_row == clist->row_list_end->data)
703 cell_rectangle.y += clist->row_height + CELL_SPACING;
705 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
707 gdk_cairo_rectangle(cr, crect);
708 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
713 for (last_column = clist->columns - 1;
714 last_column >= 0 && !clist->column[last_column].visible; last_column--)
717 /* iterate and draw all the columns (row cells) and draw their contents */
718 for (i = 0; i < clist->columns; i++)
721 PangoLayout *layout = NULL;
722 PangoRectangle logical_rect;
730 if (!clist->column[i].visible)
733 get_cell_style (clist, clist_row, state, i, &style);
735 /* calculate clipping region */
736 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
737 clip_rectangle.width = clist->column[i].area.width;
739 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
740 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
741 (1 + (i == last_column)) * CELL_SPACING);
742 cell_rectangle.y = clip_rectangle.y;
743 cell_rectangle.height = clip_rectangle.height;
749 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
750 &intersect_rectangle))
752 if (i != ctree->tree_column)
757 gdk_cairo_rectangle(cr, &cell_rectangle);
758 if (state == GTK_STATE_NORMAL)
759 gdk_cairo_set_source_color(cr, bgcolor);
761 gdk_cairo_set_source_color(cr, &style->base[state]);
763 layout = create_cell_layout (clist, clist_row, i);
766 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
767 width = logical_rect.width;
772 switch (clist_row->cell[i].type)
774 case GTK_CMCELL_PIXBUF:
775 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
776 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
777 width += pixbuf_width;
779 case GTK_CMCELL_PIXTEXT:
780 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
782 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
783 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
784 width += pixbuf_width;
787 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text &&
788 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
789 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
791 if (i == ctree->tree_column)
792 width += (ctree->tree_indent *
793 ((GtkCMCTreeRow *)clist_row)->level);
799 switch (clist->column[i].justification)
801 case GTK_JUSTIFY_LEFT:
802 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
804 case GTK_JUSTIFY_RIGHT:
805 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
806 clip_rectangle.width - width);
808 case GTK_JUSTIFY_CENTER:
809 case GTK_JUSTIFY_FILL:
810 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
811 (clip_rectangle.width / 2) - (width / 2));
815 if (i != ctree->tree_column)
817 int start_y = (clip_rectangle.height - height) / 2;
818 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
819 start_y = (clip_rectangle.height/2 - height) / 2;
821 offset += clist_row->cell[i].horizontal;
822 switch (clist_row->cell[i].type)
824 case GTK_CMCELL_PIXBUF:
826 (clist->clist_window, &clip_rectangle, cr,
827 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf,
829 clip_rectangle.y + clist_row->cell[i].vertical +
831 pixbuf_width, height);
833 case GTK_CMCELL_PIXTEXT:
834 offset = draw_cell_pixbuf
835 (clist->clist_window, &clip_rectangle, cr,
836 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
838 clip_rectangle.y + clist_row->cell[i].vertical +
840 pixbuf_width, height);
841 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
844 case GTK_CMCELL_TEXT:
847 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
848 gdk_cairo_set_source_color(cr, fgcolor);
849 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
850 pango_cairo_show_layout(cr, layout);
851 g_object_unref (G_OBJECT (layout));
861 /* draw ctree->tree_column */
862 cell_rectangle.y -= CELL_SPACING;
863 cell_rectangle.height += CELL_SPACING;
865 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
866 &intersect_rectangle))
869 g_object_unref (G_OBJECT (layout));
875 offset = get_offset (ctree, (GtkCMCTreeRow *)clist_row, i,
879 offset = draw_expander (ctree, (GtkCMCTreeRow *)clist_row,
880 style, &clip_rectangle, cr, offset);
882 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
883 offset -= ctree->tree_spacing;
885 offset += ctree->tree_spacing;
887 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
888 offset -= (pixbuf_width + clist_row->cell[i].horizontal);
890 offset += clist_row->cell[i].horizontal;
893 offset = draw_cell_pixbuf (clist->clist_window, &clip_rectangle, cr,
894 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
896 clip_rectangle.y + clist_row->cell[i].vertical
897 + (clip_rectangle.height - height) / 2,
898 pixbuf_width, height);
902 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
904 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
906 offset = (old_offset - string_width);
907 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
908 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
912 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
913 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
916 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
917 gdk_cairo_set_source_color(cr, fgcolor);
918 pango_cairo_show_layout(cr, layout);
919 g_object_unref (G_OBJECT (layout));
922 /* draw focus rectangle */
923 if (clist->focus_row == row &&
924 gtk_widget_get_can_focus (widget) && gtk_widget_has_focus (widget)
925 && state == GTK_STATE_SELECTED)
927 if (!area || gdk_rectangle_intersect (area, &row_rectangle,
928 &intersect_rectangle))
930 cairo_set_line_width(cr, 1.0);
931 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
932 gdk_cairo_set_source_color(cr, &style->text[GTK_STATE_NORMAL]);
933 cairo_move_to (cr, row_rectangle.x, row_rectangle.y + 0.5);
934 cairo_line_to (cr, row_rectangle.x + row_rectangle.width, row_rectangle.y + 0.5);
935 cairo_move_to (cr, row_rectangle.x, row_rectangle.y + row_rectangle.height - 0.5);
936 cairo_line_to (cr, row_rectangle.x + row_rectangle.width, row_rectangle.y + row_rectangle.height - 0.5);
944 gtk_cmctree_class_init (GtkCMCTreeClass *klass)
946 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
947 GtkObjectClass *object_class;
948 GtkWidgetClass *widget_class;
949 GtkCMCListClass *clist_class;
950 GtkBindingSet *binding_set;
952 gobject_class->constructor = gtk_cmctree_constructor;
954 object_class = (GtkObjectClass *) klass;
955 widget_class = (GtkWidgetClass *) klass;
956 container_class = (GtkContainerClass *) klass;
957 clist_class = (GtkCMCListClass *) klass;
959 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST);
960 container_class = g_type_class_peek (GTK_TYPE_CONTAINER);
962 gobject_class->set_property = gtk_cmctree_set_arg;
963 gobject_class->get_property = gtk_cmctree_get_arg;
965 widget_class->realize = gtk_cmctree_realize;
966 widget_class->unrealize = gtk_cmctree_unrealize;
967 widget_class->button_press_event = gtk_cmctree_button_press;
969 widget_class->drag_begin = gtk_cmctree_drag_begin;
970 widget_class->drag_motion = gtk_cmctree_drag_motion;
971 widget_class->drag_data_received = gtk_cmctree_drag_data_received;
973 clist_class->select_row = real_select_row;
974 clist_class->unselect_row = real_unselect_row;
975 clist_class->row_move = real_row_move;
976 clist_class->undo_selection = real_undo_selection;
977 clist_class->resync_selection = resync_selection;
978 clist_class->selection_find = selection_find;
979 clist_class->click_column = NULL;
980 clist_class->draw_row = draw_row;
981 clist_class->clear = real_clear;
982 clist_class->select_all = real_select_all;
983 clist_class->unselect_all = real_unselect_all;
984 clist_class->fake_unselect_all = fake_unselect_all;
985 clist_class->insert_row = real_insert_row;
986 clist_class->remove_row = real_remove_row;
987 clist_class->sort_list = real_sort_list;
988 clist_class->set_cell_contents = set_cell_contents;
989 clist_class->cell_size_request = cell_size_request;
991 klass->tree_select_row = real_tree_select;
992 klass->tree_unselect_row = real_tree_unselect;
993 klass->tree_expand = real_tree_expand;
994 klass->tree_collapse = real_tree_collapse;
995 klass->tree_move = real_tree_move;
996 klass->change_focus_row_expansion = change_focus_row_expansion;
998 g_object_class_install_property (gobject_class,
1000 g_param_spec_uint ("n-columns",
1006 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1007 g_object_class_install_property (gobject_class,
1009 g_param_spec_uint ("tree-column",
1015 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1016 g_object_class_install_property (gobject_class,
1018 g_param_spec_uint ("indent",
1024 G_PARAM_READWRITE));
1025 g_object_class_install_property (gobject_class,
1027 g_param_spec_uint ("spacing",
1033 G_PARAM_READWRITE));
1034 g_object_class_install_property (gobject_class,
1036 g_param_spec_boolean ("show-stub",
1040 G_PARAM_READWRITE));
1041 g_object_class_install_property (gobject_class,
1043 g_param_spec_enum ("line-style",
1046 GTK_TYPE_CMCTREE_LINE_STYLE, 0,
1047 G_PARAM_READWRITE));
1048 g_object_class_install_property (gobject_class,
1050 g_param_spec_enum ("expander-style",
1053 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0,
1054 G_PARAM_READWRITE));
1056 ctree_signals[TREE_SELECT_ROW] =
1057 g_signal_new ("tree_select_row",
1058 G_TYPE_FROM_CLASS (object_class),
1060 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row),
1062 claws_marshal_VOID__POINTER_INT,
1064 GTK_TYPE_CMCTREE_NODE,
1066 ctree_signals[TREE_UNSELECT_ROW] =
1067 g_signal_new ("tree_unselect_row",
1068 G_TYPE_FROM_CLASS (object_class),
1070 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row),
1072 claws_marshal_VOID__POINTER_INT,
1074 GTK_TYPE_CMCTREE_NODE,
1076 ctree_signals[TREE_EXPAND] =
1077 g_signal_new ("tree_expand",
1078 G_TYPE_FROM_CLASS (object_class),
1080 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand),
1082 claws_marshal_VOID__POINTER,
1084 GTK_TYPE_CMCTREE_NODE);
1085 ctree_signals[TREE_COLLAPSE] =
1086 g_signal_new ("tree_collapse",
1087 G_TYPE_FROM_CLASS (object_class),
1089 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse),
1091 claws_marshal_VOID__POINTER,
1093 GTK_TYPE_CMCTREE_NODE);
1094 ctree_signals[TREE_MOVE] =
1095 g_signal_new ("tree_move",
1096 G_TYPE_FROM_CLASS (object_class),
1098 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move),
1100 claws_marshal_VOID__POINTER_POINTER_POINTER,
1102 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE);
1103 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
1104 g_signal_new ("change_focus_row_expansion",
1105 G_TYPE_FROM_CLASS (object_class),
1106 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1107 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion),
1109 claws_marshal_VOID__ENUM,
1110 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE);
1112 binding_set = gtk_binding_set_by_class (klass);
1113 gtk_binding_entry_add_signal (binding_set,
1115 "change_focus_row_expansion", 1,
1116 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1117 gtk_binding_entry_add_signal (binding_set,
1118 GDK_KEY_plus, GDK_CONTROL_MASK,
1119 "change_focus_row_expansion", 1,
1120 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1122 gtk_binding_entry_add_signal (binding_set,
1124 "change_focus_row_expansion", 1,
1125 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1126 gtk_binding_entry_add_signal (binding_set,
1127 GDK_KEY_KP_Add, GDK_CONTROL_MASK,
1128 "change_focus_row_expansion", 1,
1129 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1131 gtk_binding_entry_add_signal (binding_set,
1133 "change_focus_row_expansion", 1,
1134 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1135 gtk_binding_entry_add_signal (binding_set,
1136 GDK_KEY_minus, GDK_CONTROL_MASK,
1137 "change_focus_row_expansion", 1,
1139 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1140 gtk_binding_entry_add_signal (binding_set,
1141 GDK_KEY_KP_Subtract, 0,
1142 "change_focus_row_expansion", 1,
1143 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1144 gtk_binding_entry_add_signal (binding_set,
1145 GDK_KEY_KP_Subtract, GDK_CONTROL_MASK,
1146 "change_focus_row_expansion", 1,
1148 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1149 gtk_binding_entry_add_signal (binding_set,
1151 "change_focus_row_expansion", 1,
1152 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1153 gtk_binding_entry_add_signal (binding_set,
1154 GDK_KEY_KP_Equal, 0,
1155 "change_focus_row_expansion", 1,
1156 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1157 gtk_binding_entry_add_signal (binding_set,
1158 GDK_KEY_KP_Multiply, 0,
1159 "change_focus_row_expansion", 1,
1160 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1161 gtk_binding_entry_add_signal (binding_set,
1162 GDK_KEY_asterisk, 0,
1163 "change_focus_row_expansion", 1,
1164 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1165 gtk_binding_entry_add_signal (binding_set,
1166 GDK_KEY_KP_Multiply, GDK_CONTROL_MASK,
1167 "change_focus_row_expansion", 1,
1169 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1170 gtk_binding_entry_add_signal (binding_set,
1171 GDK_KEY_asterisk, GDK_CONTROL_MASK,
1172 "change_focus_row_expansion", 1,
1174 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1178 gtk_cmctree_set_arg (GObject *object,
1180 const GValue *value,
1186 ctree = GTK_CMCTREE (object);
1187 clist = GTK_CMCLIST (ctree);
1191 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
1192 clist->columns = MAX (1, g_value_get_uint (value));
1193 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1195 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
1196 ctree->tree_column = g_value_get_uint (value);
1197 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1200 gtk_cmctree_set_indent (ctree, g_value_get_uint (value));
1203 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value));
1206 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value));
1208 case ARG_LINE_STYLE:
1209 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value));
1211 case ARG_EXPANDER_STYLE:
1212 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value));
1220 gtk_cmctree_get_arg (GObject *object,
1227 ctree = GTK_CMCTREE (object);
1232 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns);
1234 case ARG_TREE_COLUMN:
1235 g_value_set_uint(value, ctree->tree_column);
1238 g_value_set_uint(value, ctree->tree_indent);
1241 g_value_set_uint(value, ctree->tree_spacing);
1244 g_value_set_boolean(value, ctree->show_stub);
1246 case ARG_LINE_STYLE:
1247 g_value_set_enum(value, ctree->line_style);
1249 case ARG_EXPANDER_STYLE:
1250 g_value_set_enum(value, ctree->expander_style);
1253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1259 gtk_cmctree_init (GtkCMCTree *ctree)
1263 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT);
1264 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE);
1266 clist = GTK_CMCLIST (ctree);
1268 ctree->tree_indent = 20;
1269 ctree->tree_spacing = 5;
1270 ctree->tree_column = 0;
1271 ctree->line_style = GTK_CMCTREE_LINES_NONE;
1272 ctree->expander_style = GTK_CMCTREE_EXPANDER_TRIANGLE;
1273 ctree->drag_compare = NULL;
1274 ctree->show_stub = TRUE;
1276 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS;
1280 ctree_attach_styles (GtkCMCTree *ctree,
1281 GtkCMCTreeNode *node,
1287 clist = GTK_CMCLIST (ctree);
1289 if (GTK_CMCTREE_ROW (node)->row.style)
1290 GTK_CMCTREE_ROW (node)->row.style =
1291 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window);
1293 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set)
1295 GdkColormap *colormap;
1297 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
1298 if (GTK_CMCTREE_ROW (node)->row.fg_set)
1299 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE);
1300 if (GTK_CMCTREE_ROW (node)->row.bg_set)
1301 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE);
1304 for (i = 0; i < clist->columns; i++)
1305 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1306 GTK_CMCTREE_ROW (node)->row.cell[i].style =
1307 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style,
1308 clist->clist_window);
1312 ctree_detach_styles (GtkCMCTree *ctree,
1313 GtkCMCTreeNode *node,
1319 clist = GTK_CMCLIST (ctree);
1321 if (GTK_CMCTREE_ROW (node)->row.style)
1322 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
1323 for (i = 0; i < clist->columns; i++)
1324 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1325 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style);
1329 gtk_cmctree_realize (GtkWidget *widget)
1333 GtkCMCTreeNode *node;
1334 GtkCMCTreeNode *child;
1337 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1339 GTK_WIDGET_CLASS (parent_class)->realize (widget);
1341 ctree = GTK_CMCTREE (widget);
1342 clist = GTK_CMCLIST (widget);
1344 node = GTK_CMCTREE_NODE (clist->row_list);
1345 for (i = 0; i < clist->rows; i++)
1347 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded)
1348 for (child = GTK_CMCTREE_ROW (node)->children; child;
1349 child = GTK_CMCTREE_ROW (child)->sibling)
1350 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
1351 node = GTK_CMCTREE_NODE_NEXT (node);
1356 gtk_cmctree_unrealize (GtkWidget *widget)
1361 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1363 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1365 ctree = GTK_CMCTREE (widget);
1366 clist = GTK_CMCLIST (widget);
1368 if (gtk_widget_get_realized (widget))
1370 GtkCMCTreeNode *node;
1371 GtkCMCTreeNode *child;
1374 node = GTK_CMCTREE_NODE (clist->row_list);
1375 for (i = 0; i < clist->rows; i++)
1377 if (GTK_CMCTREE_ROW (node)->children &&
1378 !GTK_CMCTREE_ROW (node)->expanded)
1379 for (child = GTK_CMCTREE_ROW (node)->children; child;
1380 child = GTK_CMCTREE_ROW (child)->sibling)
1381 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
1382 node = GTK_CMCTREE_NODE_NEXT (node);
1388 gtk_cmctree_button_press (GtkWidget *widget,
1389 GdkEventButton *event)
1393 gint button_actions;
1395 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
1396 cm_return_val_if_fail (event != NULL, FALSE);
1398 ctree = GTK_CMCTREE (widget);
1399 clist = GTK_CMCLIST (widget);
1401 button_actions = clist->button_actions[event->button - 1];
1403 if (button_actions == GTK_CMBUTTON_IGNORED)
1406 if (event->window == clist->clist_window)
1408 GtkCMCTreeNode *work;
1417 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column))
1420 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
1422 if (button_actions & GTK_CMBUTTON_EXPANDS &&
1423 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf &&
1424 (event->type == GDK_2BUTTON_PRESS ||
1425 ctree_is_hot_spot (ctree, work, row, x, y))))
1427 if (GTK_CMCTREE_ROW (work)->expanded)
1428 gtk_cmctree_collapse (ctree, work);
1430 gtk_cmctree_expand (ctree, work);
1436 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
1439 static GtkCMCTreeNode *
1440 gtk_cmctree_last_visible (GtkCMCTree *ctree,
1441 GtkCMCTreeNode *node)
1443 GtkCMCTreeNode *work;
1448 work = GTK_CMCTREE_ROW (node)->children;
1450 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1453 while (GTK_CMCTREE_ROW (work)->sibling)
1454 work = GTK_CMCTREE_ROW (work)->sibling;
1456 return gtk_cmctree_last_visible (ctree, work);
1460 gtk_cmctree_link (GtkCMCTree *ctree,
1461 GtkCMCTreeNode *node,
1462 GtkCMCTreeNode *parent,
1463 GtkCMCTreeNode *sibling,
1464 gboolean update_focus_row)
1470 gboolean visible = FALSE;
1474 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1475 cm_return_if_fail (node != NULL);
1476 cm_return_if_fail (node != sibling);
1477 cm_return_if_fail (node != parent);
1479 clist = GTK_CMCLIST (ctree);
1481 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1483 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1485 g_list_free (clist->undo_selection);
1486 g_list_free (clist->undo_unselection);
1487 clist->undo_selection = NULL;
1488 clist->undo_unselection = NULL;
1491 for (rows = 1, list_end = (GList *)node; list_end->next;
1492 list_end = list_end->next)
1495 GTK_CMCTREE_ROW (node)->parent = parent;
1496 GTK_CMCTREE_ROW (node)->sibling = sibling;
1498 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1499 GTK_CMCTREE_ROW (parent)->expanded)))
1502 clist->rows += rows;
1506 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1508 work = clist->row_list;
1512 if (work != (GList *)sibling)
1514 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1515 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1516 GTK_CMCTREE_ROW (work)->sibling = node;
1519 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1520 clist->row_list = (GList *) node;
1521 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1522 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling)
1524 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1525 list->next = (GList *)node;
1528 list = (GList *)node;
1529 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1530 list_end->next = (GList *)sibling;
1531 list = (GList *)sibling;
1532 list->prev = list_end;
1533 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1534 GTK_CMCTREE_ROW (parent)->children = node;
1541 while (GTK_CMCTREE_ROW (work)->sibling)
1542 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1543 GTK_CMCTREE_ROW (work)->sibling = node;
1545 /* find last visible child of sibling */
1546 work = (GList *) gtk_cmctree_last_visible (ctree,
1547 GTK_CMCTREE_NODE (work));
1549 list_end->next = work->next;
1551 work->next->prev = list_end;
1552 work->next = (GList *)node;
1553 list = (GList *)node;
1560 GTK_CMCTREE_ROW (parent)->children = node;
1561 list = (GList *)node;
1562 list->prev = (GList *)parent;
1563 if (GTK_CMCTREE_ROW (parent)->expanded)
1565 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1566 if (GTK_CMCTREE_NODE_NEXT(parent))
1568 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1569 list->prev = list_end;
1571 list = (GList *)parent;
1572 list->next = (GList *)node;
1575 list_end->next = NULL;
1579 clist->row_list = (GList *)node;
1580 list = (GList *)node;
1582 list_end->next = NULL;
1587 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL);
1589 if (clist->row_list_end == NULL ||
1590 clist->row_list_end->next == (GList *)node)
1591 clist->row_list_end = list_end;
1593 if (visible && update_focus_row)
1597 pos = g_list_position (clist->row_list, (GList *)node);
1599 if (pos <= clist->focus_row)
1601 clist->focus_row += rows;
1602 clist->undo_anchor = clist->focus_row;
1608 gtk_cmctree_unlink (GtkCMCTree *ctree,
1609 GtkCMCTreeNode *node,
1610 gboolean update_focus_row)
1616 GtkCMCTreeNode *work;
1617 GtkCMCTreeNode *parent;
1620 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1621 cm_return_if_fail (node != NULL);
1623 clist = GTK_CMCLIST (ctree);
1625 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1627 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1629 g_list_free (clist->undo_selection);
1630 g_list_free (clist->undo_unselection);
1631 clist->undo_selection = NULL;
1632 clist->undo_unselection = NULL;
1635 visible = gtk_cmctree_is_viewable (ctree, node);
1637 /* clist->row_list_end unlinked ? */
1639 (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1640 (GTK_CMCTREE_ROW (node)->children &&
1641 gtk_cmctree_is_ancestor (ctree, node,
1642 GTK_CMCTREE_NODE (clist->row_list_end)))))
1643 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1647 level = GTK_CMCTREE_ROW (node)->level;
1648 work = GTK_CMCTREE_NODE_NEXT (node);
1649 while (work && GTK_CMCTREE_ROW (work)->level > level)
1651 work = GTK_CMCTREE_NODE_NEXT (work);
1657 clist->rows -= (rows + 1);
1659 if (update_focus_row)
1663 pos = g_list_position (clist->row_list, (GList *)node);
1664 if (pos + rows < clist->focus_row)
1665 clist->focus_row -= (rows + 1);
1666 else if (pos <= clist->focus_row)
1668 if (!GTK_CMCTREE_ROW (node)->sibling)
1669 clist->focus_row = MAX (pos - 1, 0);
1671 clist->focus_row = pos;
1673 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1675 clist->undo_anchor = clist->focus_row;
1681 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1683 list = (GList *)work;
1684 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1687 if (GTK_CMCTREE_NODE_PREV (node) &&
1688 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node)
1690 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1691 list->next = (GList *)work;
1695 parent = GTK_CMCTREE_ROW (node)->parent;
1698 if (GTK_CMCTREE_ROW (parent)->children == node)
1700 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1701 if (!GTK_CMCTREE_ROW (parent)->children)
1702 gtk_cmctree_collapse (ctree, parent);
1706 GtkCMCTreeNode *sibling;
1708 sibling = GTK_CMCTREE_ROW (parent)->children;
1709 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1710 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1711 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1716 if (clist->row_list == (GList *)node)
1717 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1720 GtkCMCTreeNode *sibling;
1722 sibling = GTK_CMCTREE_NODE (clist->row_list);
1723 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1724 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1725 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1731 real_row_move (GtkCMCList *clist,
1736 GtkCMCTreeNode *node;
1738 cm_return_if_fail (GTK_IS_CMCTREE (clist));
1740 if (GTK_CMCLIST_AUTO_SORT (clist))
1743 if (source_row < 0 || source_row >= clist->rows ||
1744 dest_row < 0 || dest_row >= clist->rows ||
1745 source_row == dest_row)
1748 ctree = GTK_CMCTREE (clist);
1749 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row));
1751 if (source_row < dest_row)
1753 GtkCMCTreeNode *work;
1756 work = GTK_CMCTREE_ROW (node)->children;
1758 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level)
1760 work = GTK_CMCTREE_NODE_NEXT (work);
1764 if (dest_row > clist->rows)
1765 dest_row = clist->rows;
1768 if (dest_row < clist->rows)
1770 GtkCMCTreeNode *sibling;
1772 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row));
1773 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling);
1776 gtk_cmctree_move (ctree, node, NULL, NULL);
1780 real_tree_move (GtkCMCTree *ctree,
1781 GtkCMCTreeNode *node,
1782 GtkCMCTreeNode *new_parent,
1783 GtkCMCTreeNode *new_sibling)
1786 GtkCMCTreeNode *work;
1787 gboolean visible = FALSE;
1789 cm_return_if_fail (ctree != NULL);
1790 cm_return_if_fail (node != NULL);
1791 cm_return_if_fail (!new_sibling ||
1792 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
1794 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1797 /* new_parent != child of child */
1798 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1802 clist = GTK_CMCLIST (ctree);
1804 visible = gtk_cmctree_is_viewable (ctree, node);
1806 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1808 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1810 g_list_free (clist->undo_selection);
1811 g_list_free (clist->undo_unselection);
1812 clist->undo_selection = NULL;
1813 clist->undo_unselection = NULL;
1816 if (GTK_CMCLIST_AUTO_SORT (clist))
1818 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
1822 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
1824 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
1826 while (new_sibling && clist->compare
1827 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
1828 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
1831 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
1832 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
1835 gtk_cmclist_freeze (clist);
1838 if (gtk_cmctree_is_viewable (ctree, node))
1839 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1841 gtk_cmctree_unlink (ctree, node, FALSE);
1842 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE);
1846 while (work && !gtk_cmctree_is_viewable (ctree, work))
1847 work = GTK_CMCTREE_ROW (work)->parent;
1848 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
1849 clist->undo_anchor = clist->focus_row;
1852 if (clist->column[ctree->tree_column].auto_resize &&
1853 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1854 (visible || gtk_cmctree_is_viewable (ctree, node)))
1855 gtk_cmclist_set_column_width
1856 (clist, ctree->tree_column,
1857 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
1859 gtk_cmclist_thaw (clist);
1863 change_focus_row_expansion (GtkCMCTree *ctree,
1864 GtkCMCTreeExpansionType action)
1867 GtkCMCTreeNode *node;
1869 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1871 clist = GTK_CMCLIST (ctree);
1873 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
1874 gtk_widget_has_grab (GTK_WIDGET(ctree)))
1878 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
1879 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
1884 case GTK_CMCTREE_EXPANSION_EXPAND:
1885 gtk_cmctree_expand (ctree, node);
1887 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
1888 gtk_cmctree_expand_recursive (ctree, node);
1890 case GTK_CMCTREE_EXPANSION_COLLAPSE:
1891 gtk_cmctree_collapse (ctree, node);
1893 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
1894 gtk_cmctree_collapse_recursive (ctree, node);
1896 case GTK_CMCTREE_EXPANSION_TOGGLE:
1897 gtk_cmctree_toggle_expansion (ctree, node);
1899 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
1900 gtk_cmctree_toggle_expansion_recursive (ctree, node);
1906 real_tree_expand (GtkCMCTree *ctree,
1907 GtkCMCTreeNode *node)
1910 GtkCMCTreeNode *work;
1911 GtkRequisition requisition;
1914 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1916 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1919 clist = GTK_CMCLIST (ctree);
1921 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1923 GTK_CMCTREE_ROW (node)->expanded = TRUE;
1925 visible = gtk_cmctree_is_viewable (ctree, node);
1926 /* get cell width if tree_column is auto resized */
1927 if (visible && clist->column[ctree->tree_column].auto_resize &&
1928 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1929 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1930 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
1932 /* unref/unset closed pixbuf */
1933 if (GTK_CMCELL_PIXTEXT
1934 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
1938 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
1941 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
1944 /* set/ref opened pixbuf */
1945 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1948 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
1949 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1953 work = GTK_CMCTREE_ROW (node)->children;
1956 GList *list = (GList *)work;
1957 gint *cell_width = NULL;
1962 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1964 cell_width = g_new0 (gint, clist->columns);
1965 if (clist->column[ctree->tree_column].auto_resize)
1966 cell_width[ctree->tree_column] = requisition.width;
1970 /* search maximum cell widths of auto_resize columns */
1971 for (i = 0; i < clist->columns; i++)
1972 if (clist->column[i].auto_resize)
1974 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1975 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
1976 cell_width[i] = MAX (requisition.width, cell_width[i]);
1979 list = (GList *)work;
1980 work = GTK_CMCTREE_NODE_NEXT (work);
1987 list = (GList *)work;
1988 work = GTK_CMCTREE_NODE_NEXT (work);
1992 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1994 if (GTK_CMCTREE_NODE_NEXT (node))
1998 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1999 tmp_list->prev = list;
2002 clist->row_list_end = list;
2004 list = (GList *)node;
2005 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
2007 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2009 /* resize auto_resize columns if needed */
2010 for (i = 0; i < clist->columns; i++)
2011 if (clist->column[i].auto_resize &&
2012 cell_width[i] > clist->column[i].width)
2013 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
2014 g_free (cell_width);
2016 /* update focus_row position */
2017 row = g_list_position (clist->row_list, (GList *)node);
2018 if (row < clist->focus_row)
2019 clist->focus_row += tmp;
2022 CLIST_REFRESH (clist);
2025 else if (visible && clist->column[ctree->tree_column].auto_resize)
2026 /* resize tree_column if needed */
2027 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2032 real_tree_collapse (GtkCMCTree *ctree,
2033 GtkCMCTreeNode *node)
2036 GtkCMCTreeNode *work;
2037 GtkRequisition requisition;
2041 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2043 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
2044 GTK_CMCTREE_ROW (node)->is_leaf)
2047 clist = GTK_CMCLIST (ctree);
2049 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2051 GTK_CMCTREE_ROW (node)->expanded = FALSE;
2052 level = GTK_CMCTREE_ROW (node)->level;
2054 visible = gtk_cmctree_is_viewable (ctree, node);
2055 /* get cell width if tree_column is auto resized */
2056 if (visible && clist->column[ctree->tree_column].auto_resize &&
2057 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2058 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2059 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2061 /* unref/unset opened pixbuf */
2062 if (GTK_CMCELL_PIXTEXT
2063 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2067 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2070 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2073 /* set/ref closed pixbuf */
2074 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2077 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2078 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2081 work = GTK_CMCTREE_ROW (node)->children;
2088 while (work && GTK_CMCTREE_ROW (work)->level > level)
2090 work = GTK_CMCTREE_NODE_NEXT (work);
2096 list = (GList *)node;
2097 list->next = (GList *)work;
2098 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2100 list = (GList *)work;
2101 list->prev = (GList *)node;
2105 list = (GList *)node;
2107 clist->row_list_end = (GList *)node;
2112 /* resize auto_resize columns if needed */
2113 auto_resize_columns (clist);
2115 row = g_list_position (clist->row_list, (GList *)node);
2116 if (row < clist->focus_row)
2117 clist->focus_row -= tmp;
2119 CLIST_REFRESH (clist);
2122 else if (visible && clist->column[ctree->tree_column].auto_resize &&
2123 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2124 /* resize tree_column if needed */
2125 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2131 column_auto_resize (GtkCMCList *clist,
2132 GtkCMCListRow *clist_row,
2136 /* resize column if needed for auto_resize */
2137 GtkRequisition requisition;
2139 if (!clist->column[column].auto_resize ||
2140 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2144 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2145 column, &requisition);
2147 requisition.width = 0;
2149 if (requisition.width > clist->column[column].width)
2150 gtk_cmclist_set_column_width (clist, column, requisition.width);
2151 else if (requisition.width < old_width &&
2152 old_width == clist->column[column].width)
2157 /* run a "gtk_cmclist_optimal_column_width" but break, if
2158 * the column doesn't shrink */
2159 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
2162 gtk_widget_get_requisition (clist->column[column].button, &req);
2163 new_width = (req.width -
2164 (CELL_SPACING + (2 * COLUMN_INSET)));
2169 for (list = clist->row_list; list; list = list->next)
2171 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2172 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
2173 new_width = MAX (new_width, requisition.width);
2174 if (new_width == clist->column[column].width)
2177 if (new_width < clist->column[column].width)
2178 gtk_cmclist_set_column_width (clist, column, new_width);
2183 auto_resize_columns (GtkCMCList *clist)
2187 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2190 for (i = 0; i < clist->columns; i++)
2191 column_auto_resize (clist, NULL, i, clist->column[i].width);
2195 cell_size_request (GtkCMCList *clist,
2196 GtkCMCListRow *clist_row,
2198 GtkRequisition *requisition)
2203 PangoLayout *layout;
2204 PangoRectangle logical_rect;
2206 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2207 cm_return_if_fail (requisition != NULL);
2209 ctree = GTK_CMCTREE (clist);
2211 layout = create_cell_layout (clist, clist_row, column);
2214 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2216 requisition->width = logical_rect.width;
2217 requisition->height = logical_rect.height;
2219 g_object_unref (G_OBJECT (layout));
2223 requisition->width = 0;
2224 requisition->height = 0;
2227 switch (clist_row->cell[column].type)
2229 case GTK_CMCELL_PIXTEXT:
2230 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf)
2232 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2233 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2234 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2239 requisition->width += width;
2240 requisition->height = MAX (requisition->height, height);
2242 if (column == ctree->tree_column)
2244 requisition->width += (ctree->tree_spacing + ctree->tree_indent *
2245 (((GtkCMCTreeRow *) clist_row)->level - 1));
2246 switch (ctree->expander_style)
2248 case GTK_CMCTREE_EXPANDER_NONE:
2250 case GTK_CMCTREE_EXPANDER_TRIANGLE:
2251 requisition->width += PM_SIZE + 3;
2256 case GTK_CMCELL_PIXBUF:
2257 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2258 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2259 requisition->width += width;
2260 requisition->height = MAX (requisition->height, height);
2266 requisition->width += clist_row->cell[column].horizontal;
2267 requisition->height += clist_row->cell[column].vertical;
2271 set_cell_contents (GtkCMCList *clist,
2272 GtkCMCListRow *clist_row,
2279 gboolean visible = FALSE;
2281 GtkRequisition requisition;
2282 gchar *old_text = NULL;
2283 GdkPixbuf *old_pixbuf = NULL;
2285 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2286 cm_return_if_fail (clist_row != NULL);
2288 ctree = GTK_CMCTREE (clist);
2290 if (clist->column[column].auto_resize &&
2291 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2293 GtkCMCTreeNode *parent;
2295 parent = ((GtkCMCTreeRow *)clist_row)->parent;
2296 if ((parent && GTK_CMCTREE_ROW (parent)->expanded &&
2297 gtk_cmctree_is_viewable (ctree, parent)))
2300 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2301 column, &requisition);
2305 switch (clist_row->cell[column].type)
2307 case GTK_CMCELL_EMPTY:
2309 case GTK_CMCELL_TEXT:
2310 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2312 case GTK_CMCELL_PIXBUF:
2313 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2315 case GTK_CMCELL_PIXTEXT:
2316 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2317 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2319 case GTK_CMCELL_WIDGET:
2327 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2328 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY)
2329 type = GTK_CMCELL_PIXTEXT;
2331 /* Note that pixbuf and mask were already ref'ed by the caller
2335 case GTK_CMCELL_TEXT:
2338 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2339 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2342 case GTK_CMCELL_PIXBUF:
2345 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2346 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2349 case GTK_CMCELL_PIXTEXT:
2350 if (column == ctree->tree_column)
2352 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2353 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2355 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2357 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL;
2360 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2364 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = NULL;
2367 else if (text && pixbuf)
2369 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2370 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2371 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2372 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2379 if (visible && clist->column[column].auto_resize &&
2380 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2381 column_auto_resize (clist, clist_row, column, requisition.width);
2385 g_object_unref (old_pixbuf);
2389 set_node_info (GtkCMCTree *ctree,
2390 GtkCMCTreeNode *node,
2393 GdkPixbuf *pixbuf_closed,
2394 GdkPixbuf *pixbuf_opened,
2398 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2400 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2402 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2404 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2407 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
2408 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
2412 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
2416 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
2419 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
2420 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
2422 if (GTK_CMCTREE_ROW (node)->expanded)
2423 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2424 text, spacing, pixbuf_opened);
2426 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2427 text, spacing, pixbuf_closed);
2431 tree_delete (GtkCMCTree *ctree,
2432 GtkCMCTreeNode *node,
2435 tree_unselect (ctree, node, NULL);
2436 row_delete (ctree, GTK_CMCTREE_ROW (node));
2437 g_list_free_1 ((GList *)node);
2441 tree_delete_row (GtkCMCTree *ctree,
2442 GtkCMCTreeNode *node,
2445 row_delete (ctree, GTK_CMCTREE_ROW (node));
2446 g_list_free_1 ((GList *)node);
2450 tree_update_level (GtkCMCTree *ctree,
2451 GtkCMCTreeNode *node,
2457 if (GTK_CMCTREE_ROW (node)->parent)
2458 GTK_CMCTREE_ROW (node)->level =
2459 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
2461 GTK_CMCTREE_ROW (node)->level = 1;
2465 tree_select (GtkCMCTree *ctree,
2466 GtkCMCTreeNode *node,
2469 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
2470 GTK_CMCTREE_ROW (node)->row.selectable)
2471 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
2476 tree_unselect (GtkCMCTree *ctree,
2477 GtkCMCTreeNode *node,
2480 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
2481 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
2486 tree_expand (GtkCMCTree *ctree,
2487 GtkCMCTreeNode *node,
2490 if (node && !GTK_CMCTREE_ROW (node)->expanded)
2491 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2495 tree_collapse (GtkCMCTree *ctree,
2496 GtkCMCTreeNode *node,
2499 if (node && GTK_CMCTREE_ROW (node)->expanded)
2500 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2504 tree_collapse_to_depth (GtkCMCTree *ctree,
2505 GtkCMCTreeNode *node,
2508 if (node && GTK_CMCTREE_ROW (node)->level == depth)
2509 gtk_cmctree_collapse_recursive (ctree, node);
2513 tree_toggle_expansion (GtkCMCTree *ctree,
2514 GtkCMCTreeNode *node,
2520 if (GTK_CMCTREE_ROW (node)->expanded)
2521 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2523 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2526 static GtkCMCTreeRow *
2527 row_new (GtkCMCTree *ctree)
2530 GtkCMCTreeRow *ctree_row;
2533 clist = GTK_CMCLIST (ctree);
2534 ctree_row = g_slice_new (GtkCMCTreeRow);
2535 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
2537 for (i = 0; i < clist->columns; i++)
2539 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
2540 ctree_row->row.cell[i].vertical = 0;
2541 ctree_row->row.cell[i].horizontal = 0;
2542 ctree_row->row.cell[i].style = NULL;
2544 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
2546 ctree_row->row.fg_set = FALSE;
2547 ctree_row->row.bg_set = FALSE;
2548 ctree_row->row.style = NULL;
2549 ctree_row->row.selectable = TRUE;
2550 ctree_row->row.state = GTK_STATE_NORMAL;
2551 ctree_row->row.data = NULL;
2552 ctree_row->row.destroy = NULL;
2554 ctree_row->level = 0;
2555 ctree_row->expanded = FALSE;
2556 ctree_row->parent = NULL;
2557 ctree_row->sibling = NULL;
2558 ctree_row->children = NULL;
2559 ctree_row->pixbuf_closed = NULL;
2560 ctree_row->pixbuf_opened = NULL;
2566 row_delete (GtkCMCTree *ctree,
2567 GtkCMCTreeRow *ctree_row)
2572 clist = GTK_CMCLIST (ctree);
2574 for (i = 0; i < clist->columns; i++)
2576 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2577 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
2578 if (ctree_row->row.cell[i].style)
2580 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2581 gtk_style_detach (ctree_row->row.cell[i].style);
2582 g_object_unref (ctree_row->row.cell[i].style);
2586 if (ctree_row->row.style)
2588 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2589 gtk_style_detach (ctree_row->row.style);
2590 g_object_unref (ctree_row->row.style);
2593 if (ctree_row->pixbuf_closed)
2595 g_object_unref (ctree_row->pixbuf_closed);
2598 if (ctree_row->pixbuf_opened)
2600 g_object_unref (ctree_row->pixbuf_opened);
2603 if (ctree_row->row.destroy)
2605 GDestroyNotify dnotify = ctree_row->row.destroy;
2606 gpointer ddata = ctree_row->row.data;
2608 ctree_row->row.destroy = NULL;
2609 ctree_row->row.data = NULL;
2614 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
2615 g_slice_free (GtkCMCTreeRow, ctree_row);
2619 real_select_row (GtkCMCList *clist,
2626 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2628 if ((node = g_list_nth (clist->row_list, row)) &&
2629 GTK_CMCTREE_ROW (node)->row.selectable)
2630 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0,
2635 real_unselect_row (GtkCMCList *clist,
2642 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2644 if ((node = g_list_nth (clist->row_list, row)))
2645 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0,
2650 tree_draw_node (GtkCMCTree *ctree,
2651 GtkCMCTreeNode *node)
2655 clist = GTK_CMCLIST (ctree);
2657 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node))
2659 GtkCMCTreeNode *work;
2662 work = GTK_CMCTREE_NODE (clist->row_list);
2663 while (work && work != node)
2665 work = GTK_CMCTREE_NODE_NEXT (work);
2668 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2669 GTK_CMCLIST_GET_CLASS(ctree)->draw_row
2670 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node));
2675 real_tree_select (GtkCMCTree *ctree,
2676 GtkCMCTreeNode *node,
2681 GtkCMCTreeNode *sel_row;
2682 gboolean node_selected;
2684 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2686 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2687 !GTK_CMCTREE_ROW (node)->row.selectable)
2690 clist = GTK_CMCLIST (ctree);
2692 switch (clist->selection_mode)
2694 case GTK_SELECTION_SINGLE:
2695 case GTK_SELECTION_BROWSE:
2697 node_selected = FALSE;
2698 list = clist->selection;
2702 sel_row = list->data;
2705 if (node == sel_row)
2706 node_selected = TRUE;
2708 g_signal_emit (G_OBJECT (ctree),
2709 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column);
2719 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
2721 if (!clist->selection)
2723 clist->selection = g_list_append (clist->selection, node);
2724 clist->selection_end = clist->selection;
2727 clist->selection_end = g_list_append (clist->selection_end, node)->next;
2729 tree_draw_node (ctree, node);
2733 real_tree_unselect (GtkCMCTree *ctree,
2734 GtkCMCTreeNode *node,
2739 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2741 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
2744 clist = GTK_CMCLIST (ctree);
2746 if (clist->selection_end && clist->selection_end->data == node)
2747 clist->selection_end = clist->selection_end->prev;
2749 clist->selection = g_list_remove (clist->selection, node);
2751 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
2753 tree_draw_node (ctree, node);
2757 select_row_recursive (GtkCMCTree *ctree,
2758 GtkCMCTreeNode *node,
2761 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2762 !GTK_CMCTREE_ROW (node)->row.selectable)
2765 GTK_CMCLIST (ctree)->undo_unselection =
2766 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node);
2767 gtk_cmctree_select (ctree, node);
2771 real_select_all (GtkCMCList *clist)
2774 GtkCMCTreeNode *node;
2776 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2778 ctree = GTK_CMCTREE (clist);
2780 switch (clist->selection_mode)
2782 case GTK_SELECTION_SINGLE:
2783 case GTK_SELECTION_BROWSE:
2786 case GTK_SELECTION_MULTIPLE:
2788 gtk_cmclist_freeze (clist);
2790 g_list_free (clist->undo_selection);
2791 g_list_free (clist->undo_unselection);
2792 clist->undo_selection = NULL;
2793 clist->undo_unselection = NULL;
2795 clist->anchor_state = GTK_STATE_SELECTED;
2797 clist->drag_pos = -1;
2798 clist->undo_anchor = clist->focus_row;
2800 for (node = GTK_CMCTREE_NODE (clist->row_list); node;
2801 node = GTK_CMCTREE_NODE_NEXT (node))
2802 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL);
2804 gtk_cmclist_thaw (clist);
2814 real_unselect_all (GtkCMCList *clist)
2817 GtkCMCTreeNode *node;
2820 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2822 ctree = GTK_CMCTREE (clist);
2824 switch (clist->selection_mode)
2826 case GTK_SELECTION_BROWSE:
2827 if (clist->focus_row >= 0)
2831 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
2836 case GTK_SELECTION_MULTIPLE:
2837 g_list_free (clist->undo_selection);
2838 g_list_free (clist->undo_unselection);
2839 clist->undo_selection = NULL;
2840 clist->undo_unselection = NULL;
2843 clist->drag_pos = -1;
2844 clist->undo_anchor = clist->focus_row;
2851 list = clist->selection;
2857 gtk_cmctree_unselect (ctree, node);
2862 ctree_is_hot_spot (GtkCMCTree *ctree,
2863 GtkCMCTreeNode *node,
2868 GtkCMCTreeRow *tree_row;
2874 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
2875 cm_return_val_if_fail (node != NULL, FALSE);
2877 clist = GTK_CMCLIST (ctree);
2879 if (!clist->column[ctree->tree_column].visible ||
2880 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
2883 tree_row = GTK_CMCTREE_ROW (node);
2885 hotspot_size = clist->row_height-2;
2886 if (hotspot_size > clist->column[ctree->tree_column].area.width - 2)
2887 hotspot_size = clist->column[ctree->tree_column].area.width - 2;
2889 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - hotspot_size) / 2 -
2890 (clist->row_height - 1) % 2);
2892 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
2893 xl = (clist->column[ctree->tree_column].area.x +
2894 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
2895 (tree_row->level - 1) * ctree->tree_indent - hotspot_size);
2897 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
2898 (tree_row->level - 1) * ctree->tree_indent);
2900 return (x >= xl && x <= xl + hotspot_size && y >= yu && y <= yu + hotspot_size);
2903 /***********************************************************
2904 ***********************************************************
2905 *** Public interface ***
2906 ***********************************************************
2907 ***********************************************************/
2910 /***********************************************************
2911 * Creation, insertion, deletion *
2912 ***********************************************************/
2915 gtk_cmctree_constructor (GType type,
2916 guint n_construct_properties,
2917 GObjectConstructParam *construct_properties)
2919 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
2920 n_construct_properties,
2921 construct_properties);
2927 gtk_cmctree_new_with_titles (gint columns,
2933 cm_return_val_if_fail (columns > 0, NULL);
2934 cm_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
2936 widget = gtk_widget_new (GTK_TYPE_CMCTREE,
2937 "n_columns", columns,
2938 "tree_column", tree_column,
2942 GtkCMCList *clist = GTK_CMCLIST (widget);
2945 for (i = 0; i < columns; i++)
2946 gtk_cmclist_set_column_title (clist, i, titles[i]);
2947 gtk_cmclist_column_titles_show (clist);
2954 gtk_cmctree_new (gint columns,
2957 return gtk_cmctree_new_with_titles (columns, tree_column, NULL);
2961 real_insert_row (GtkCMCList *clist,
2965 GtkCMCTreeNode *parent = NULL;
2966 GtkCMCTreeNode *sibling;
2967 GtkCMCTreeNode *node;
2969 cm_return_val_if_fail (GTK_IS_CMCTREE (clist), -1);
2971 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
2973 parent = GTK_CMCTREE_ROW (sibling)->parent;
2975 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5,
2976 NULL, NULL, TRUE, FALSE);
2978 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling)
2979 return g_list_position (clist->row_list, (GList *) node);
2985 gtk_cmctree_insert_node (GtkCMCTree *ctree,
2986 GtkCMCTreeNode *parent,
2987 GtkCMCTreeNode *sibling,
2990 GdkPixbuf *pixbuf_closed,
2991 GdkPixbuf *pixbuf_opened,
2996 GtkCMCTreeRow *new_row;
2997 GtkCMCTreeNode *node;
3001 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3003 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3005 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
3008 clist = GTK_CMCLIST (ctree);
3010 /* create the row */
3011 new_row = row_new (ctree);
3012 list = g_list_alloc ();
3013 list->data = new_row;
3014 node = GTK_CMCTREE_NODE (list);
3017 for (i = 0; i < clist->columns; i++)
3018 if (text[i] && i != ctree->tree_column)
3019 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3020 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
3022 set_node_info (ctree, node, text ?
3023 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
3024 pixbuf_opened, is_leaf, expanded);
3026 /* sorted insertion */
3027 if (GTK_CMCLIST_AUTO_SORT (clist))
3030 sibling = GTK_CMCTREE_ROW (parent)->children;
3032 sibling = GTK_CMCTREE_NODE (clist->row_list);
3034 while (sibling && clist->compare
3035 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
3036 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3039 gtk_cmctree_link (ctree, node, parent, sibling, TRUE);
3041 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
3042 gtk_cmctree_is_viewable (ctree, node))
3044 for (i = 0; i < clist->columns; i++)
3045 if (clist->column[i].auto_resize)
3046 column_auto_resize (clist, &(new_row->row), i, 0);
3049 if (clist->rows == 1)
3051 clist->focus_row = 0;
3052 if (clist->selection_mode == GTK_SELECTION_BROWSE)
3053 gtk_cmctree_select (ctree, node);
3057 CLIST_REFRESH (clist);
3063 gtk_cmctree_insert_gnode (GtkCMCTree *ctree,
3064 GtkCMCTreeNode *parent,
3065 GtkCMCTreeNode *sibling,
3067 GtkCMCTreeGNodeFunc func,
3071 GtkCMCTreeNode *cnode = NULL;
3072 GtkCMCTreeNode *child = NULL;
3073 GtkCMCTreeNode *new_child;
3078 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3079 cm_return_val_if_fail (gnode != NULL, NULL);
3080 cm_return_val_if_fail (func != NULL, NULL);
3082 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3084 clist = GTK_CMCLIST (ctree);
3087 depth = GTK_CMCTREE_ROW (parent)->level + 1;
3089 list = g_list_alloc ();
3090 list->data = row_new (ctree);
3091 cnode = GTK_CMCTREE_NODE (list);
3093 gtk_cmclist_freeze (clist);
3095 set_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
3097 if (!func (ctree, depth, gnode, cnode, data))
3099 tree_delete_row (ctree, cnode, NULL);
3100 gtk_cmclist_thaw (clist);
3104 if (GTK_CMCLIST_AUTO_SORT (clist))
3107 sibling = GTK_CMCTREE_ROW (parent)->children;
3109 sibling = GTK_CMCTREE_NODE (clist->row_list);
3111 while (sibling && clist->compare
3112 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
3113 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3116 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE);
3118 for (work = g_node_last_child (gnode); work; work = work->prev)
3120 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child,
3126 gtk_cmclist_thaw (clist);
3132 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree,
3135 GtkCMCTreeNode *node,
3136 GtkCMCTreeGNodeFunc func,
3139 GtkCMCTreeNode *work;
3143 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3144 cm_return_val_if_fail (node != NULL, NULL);
3145 cm_return_val_if_fail (func != NULL, NULL);
3148 cm_return_val_if_fail (parent != NULL, NULL);
3149 cm_return_val_if_fail (sibling->parent == parent, NULL);
3152 gnode = g_node_new (NULL);
3153 depth = g_node_depth (parent) + 1;
3155 if (!func (ctree, depth, gnode, node, data))
3157 g_node_destroy (gnode);
3162 g_node_insert_before (parent, sibling, gnode);
3164 if (!GTK_CMCTREE_ROW (node)->is_leaf)
3166 GNode *new_sibling = NULL;
3168 for (work = GTK_CMCTREE_ROW (node)->children; work;
3169 work = GTK_CMCTREE_ROW (work)->sibling)
3170 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling,
3173 g_node_reverse_children (gnode);
3180 real_remove_row (GtkCMCList *clist,
3183 GtkCMCTreeNode *node;
3185 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3187 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3190 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node);
3194 gtk_cmctree_remove_node (GtkCMCTree *ctree,
3195 GtkCMCTreeNode *node)
3199 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3201 clist = GTK_CMCLIST (ctree);
3203 gtk_cmclist_freeze (clist);
3207 gtk_cmctree_unlink (ctree, node, TRUE);
3208 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete),
3210 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3211 clist->focus_row >= 0)
3212 gtk_cmclist_select_row (clist, clist->focus_row, -1);
3214 auto_resize_columns (clist);
3217 gtk_cmclist_clear (clist);
3219 gtk_cmclist_thaw (clist);
3223 real_clear (GtkCMCList *clist)
3226 GtkCMCTreeNode *work;
3227 GtkCMCTreeNode *ptr;
3229 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3231 ctree = GTK_CMCTREE (clist);
3233 /* remove all rows */
3234 work = GTK_CMCTREE_NODE (clist->row_list);
3235 clist->row_list = NULL;
3236 clist->row_list_end = NULL;
3238 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3242 work = GTK_CMCTREE_ROW (work)->sibling;
3243 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row),
3246 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3248 parent_class->clear (clist);
3252 /***********************************************************
3253 * Generic recursive functions, querying / finding tree *
3255 ***********************************************************/
3259 gtk_cmctree_post_recursive (GtkCMCTree *ctree,
3260 GtkCMCTreeNode *node,
3261 GtkCMCTreeFunc func,
3264 GtkCMCTreeNode *work;
3265 GtkCMCTreeNode *tmp;
3267 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3268 cm_return_if_fail (func != NULL);
3271 work = GTK_CMCTREE_ROW (node)->children;
3273 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3277 tmp = GTK_CMCTREE_ROW (work)->sibling;
3278 gtk_cmctree_post_recursive (ctree, work, func, data);
3283 func (ctree, node, data);
3287 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree,
3288 GtkCMCTreeNode *node,
3290 GtkCMCTreeFunc func,
3293 GtkCMCTreeNode *work;
3294 GtkCMCTreeNode *tmp;
3296 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3297 cm_return_if_fail (func != NULL);
3301 gtk_cmctree_post_recursive (ctree, node, func, data);
3306 work = GTK_CMCTREE_ROW (node)->children;
3308 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3310 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3314 tmp = GTK_CMCTREE_ROW (work)->sibling;
3315 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data);
3320 if (node && GTK_CMCTREE_ROW (node)->level <= depth)
3321 func (ctree, node, data);
3325 gtk_cmctree_pre_recursive (GtkCMCTree *ctree,
3326 GtkCMCTreeNode *node,
3327 GtkCMCTreeFunc func,
3330 GtkCMCTreeNode *work;
3331 GtkCMCTreeNode *tmp;
3333 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3334 cm_return_if_fail (func != NULL);
3338 work = GTK_CMCTREE_ROW (node)->children;
3339 func (ctree, node, data);
3342 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3346 tmp = GTK_CMCTREE_ROW (work)->sibling;
3347 gtk_cmctree_pre_recursive (ctree, work, func, data);
3353 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree,
3354 GtkCMCTreeNode *node,
3356 GtkCMCTreeFunc func,
3359 GtkCMCTreeNode *work;
3360 GtkCMCTreeNode *tmp;
3362 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3363 cm_return_if_fail (func != NULL);
3367 gtk_cmctree_pre_recursive (ctree, node, func, data);
3373 work = GTK_CMCTREE_ROW (node)->children;
3374 if (GTK_CMCTREE_ROW (node)->level <= depth)
3375 func (ctree, node, data);
3378 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3380 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3384 tmp = GTK_CMCTREE_ROW (work)->sibling;
3385 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data);
3392 gtk_cmctree_is_viewable (GtkCMCTree *ctree,
3393 GtkCMCTreeNode *node)
3395 GtkCMCTreeRow *work;
3397 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3398 cm_return_val_if_fail (node != NULL, FALSE);
3400 work = GTK_CMCTREE_ROW (node);
3402 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded)
3403 work = GTK_CMCTREE_ROW (work->parent);
3412 gtk_cmctree_last (GtkCMCTree *ctree,
3413 GtkCMCTreeNode *node)
3415 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3420 while (GTK_CMCTREE_ROW (node)->sibling)
3421 node = GTK_CMCTREE_ROW (node)->sibling;
3423 if (GTK_CMCTREE_ROW (node)->children)
3424 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children);
3430 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree,
3431 GtkCMCTreeRow *ctree_row)
3433 GtkCMCTreeNode *node;
3435 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3436 cm_return_val_if_fail (ctree_row != NULL, NULL);
3438 if (ctree_row->parent)
3439 node = GTK_CMCTREE_ROW (ctree_row->parent)->children;
3441 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3443 while (GTK_CMCTREE_ROW (node) != ctree_row)
3444 node = GTK_CMCTREE_ROW (node)->sibling;
3450 gtk_cmctree_node_nth (GtkCMCTree *ctree,
3453 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3455 if ((row >= GTK_CMCLIST(ctree)->rows))
3458 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row));
3462 gtk_cmctree_find (GtkCMCTree *ctree,
3463 GtkCMCTreeNode *node,
3464 GtkCMCTreeNode *child)
3470 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3476 if (GTK_CMCTREE_ROW (node)->children)
3478 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child))
3481 node = GTK_CMCTREE_ROW (node)->sibling;
3487 gtk_cmctree_is_ancestor (GtkCMCTree *ctree,
3488 GtkCMCTreeNode *node,
3489 GtkCMCTreeNode *child)
3491 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3492 cm_return_val_if_fail (node != NULL, FALSE);
3494 if (GTK_CMCTREE_ROW (node)->children)
3495 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child);
3501 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree,
3502 GtkCMCTreeNode *node,
3505 GtkCMCTreeNode *work;
3508 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3512 if (GTK_CMCTREE_ROW (node)->row.data == data)
3514 if (GTK_CMCTREE_ROW (node)->children &&
3515 (work = gtk_cmctree_find_by_row_data
3516 (ctree, GTK_CMCTREE_ROW (node)->children, data)))
3518 node = GTK_CMCTREE_ROW (node)->sibling;
3524 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree,
3525 GtkCMCTreeNode *node,
3530 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3532 /* if node == NULL then look in the whole tree */
3534 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3538 if (GTK_CMCTREE_ROW (node)->row.data == data)
3539 list = g_list_append (list, node);
3541 if (GTK_CMCTREE_ROW (node)->children)
3545 sub_list = gtk_cmctree_find_all_by_row_data (ctree,
3549 list = g_list_concat (list, sub_list);
3551 node = GTK_CMCTREE_ROW (node)->sibling;
3557 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree,
3558 GtkCMCTreeNode *node,
3562 GtkCMCTreeNode *work;
3564 cm_return_val_if_fail (func != NULL, NULL);
3567 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3571 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3573 if (GTK_CMCTREE_ROW (node)->children &&
3574 (work = gtk_cmctree_find_by_row_data_custom
3575 (ctree, GTK_CMCTREE_ROW (node)->children, data, func)))
3577 node = GTK_CMCTREE_ROW (node)->sibling;
3583 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree,
3584 GtkCMCTreeNode *node,
3590 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3591 cm_return_val_if_fail (func != NULL, NULL);
3593 /* if node == NULL then look in the whole tree */
3595 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3599 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3600 list = g_list_append (list, node);
3602 if (GTK_CMCTREE_ROW (node)->children)
3606 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree,
3611 list = g_list_concat (list, sub_list);
3613 node = GTK_CMCTREE_ROW (node)->sibling;
3619 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree,
3623 GtkCMCTreeNode *node;
3627 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3629 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
3630 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
3631 return ctree_is_hot_spot (ctree, node, row, x, y);
3637 /***********************************************************
3638 * Tree signals : move, expand, collapse, (un)select *
3639 ***********************************************************/
3643 gtk_cmctree_move (GtkCMCTree *ctree,
3644 GtkCMCTreeNode *node,
3645 GtkCMCTreeNode *new_parent,
3646 GtkCMCTreeNode *new_sibling)
3648 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3649 cm_return_if_fail (node != NULL);
3651 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node,
3652 new_parent, new_sibling);
3656 gtk_cmctree_expand (GtkCMCTree *ctree,
3657 GtkCMCTreeNode *node)
3659 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3660 cm_return_if_fail (node != NULL);
3662 if (GTK_CMCTREE_ROW (node)->is_leaf)
3665 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node);
3669 gtk_cmctree_expand_recursive (GtkCMCTree *ctree,
3670 GtkCMCTreeNode *node)
3673 gboolean thaw = FALSE;
3675 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3677 clist = GTK_CMCLIST (ctree);
3679 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3682 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3684 gtk_cmclist_freeze (clist);
3688 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL);
3691 gtk_cmclist_thaw (clist);
3695 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree,
3696 GtkCMCTreeNode *node,
3700 gboolean thaw = FALSE;
3702 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3704 clist = GTK_CMCLIST (ctree);
3706 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3709 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3711 gtk_cmclist_freeze (clist);
3715 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3716 GTK_CMCTREE_FUNC (tree_expand), NULL);
3719 gtk_cmclist_thaw (clist);
3723 gtk_cmctree_collapse (GtkCMCTree *ctree,
3724 GtkCMCTreeNode *node)
3726 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3727 cm_return_if_fail (node != NULL);
3729 if (GTK_CMCTREE_ROW (node)->is_leaf)
3732 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node);
3736 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree,
3737 GtkCMCTreeNode *node)
3740 gboolean thaw = FALSE;
3743 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3745 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3748 clist = GTK_CMCLIST (ctree);
3750 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3752 gtk_cmclist_freeze (clist);
3756 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3757 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL);
3758 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3759 for (i = 0; i < clist->columns; i++)
3760 if (clist->column[i].auto_resize)
3761 gtk_cmclist_set_column_width (clist, i,
3762 gtk_cmclist_optimal_column_width (clist, i));
3765 gtk_cmclist_thaw (clist);
3769 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree,
3770 GtkCMCTreeNode *node,
3774 gboolean thaw = FALSE;
3777 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3779 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3782 clist = GTK_CMCLIST (ctree);
3784 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3786 gtk_cmclist_freeze (clist);
3790 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3791 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3792 GTK_CMCTREE_FUNC (tree_collapse_to_depth),
3793 GINT_TO_POINTER (depth));
3794 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3795 for (i = 0; i < clist->columns; i++)
3796 if (clist->column[i].auto_resize)
3797 gtk_cmclist_set_column_width (clist, i,
3798 gtk_cmclist_optimal_column_width (clist, i));
3801 gtk_cmclist_thaw (clist);
3805 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree,
3806 GtkCMCTreeNode *node)
3808 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3809 cm_return_if_fail (node != NULL);
3811 if (GTK_CMCTREE_ROW (node)->is_leaf)
3814 tree_toggle_expansion (ctree, node, NULL);
3818 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree,
3819 GtkCMCTreeNode *node)
3822 gboolean thaw = FALSE;
3824 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3826 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3829 clist = GTK_CMCLIST (ctree);
3831 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3833 gtk_cmclist_freeze (clist);
3837 gtk_cmctree_post_recursive (ctree, node,
3838 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL);
3841 gtk_cmclist_thaw (clist);
3845 gtk_cmctree_select (GtkCMCTree *ctree,
3846 GtkCMCTreeNode *node)
3848 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3849 cm_return_if_fail (node != NULL);
3851 if (GTK_CMCTREE_ROW (node)->row.selectable)
3852 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
3857 gtk_cmctree_unselect (GtkCMCTree *ctree,
3858 GtkCMCTreeNode *node)
3860 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3861 cm_return_if_fail (node != NULL);
3863 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
3868 gtk_cmctree_select_recursive (GtkCMCTree *ctree,
3869 GtkCMCTreeNode *node)
3871 gtk_cmctree_real_select_recursive (ctree, node, TRUE);
3875 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree,
3876 GtkCMCTreeNode *node)
3878 gtk_cmctree_real_select_recursive (ctree, node, FALSE);
3882 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree,
3883 GtkCMCTreeNode *node,
3887 gboolean thaw = FALSE;
3889 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3891 clist = GTK_CMCLIST (ctree);
3894 (clist->selection_mode == GTK_SELECTION_BROWSE ||
3895 clist->selection_mode == GTK_SELECTION_SINGLE)) ||
3896 (!state && clist->selection_mode == GTK_SELECTION_BROWSE))
3899 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3901 gtk_cmclist_freeze (clist);
3905 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
3907 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3909 g_list_free (clist->undo_selection);
3910 g_list_free (clist->undo_unselection);
3911 clist->undo_selection = NULL;
3912 clist->undo_unselection = NULL;
3916 gtk_cmctree_post_recursive (ctree, node,
3917 GTK_CMCTREE_FUNC (tree_select), NULL);
3919 gtk_cmctree_post_recursive (ctree, node,
3920 GTK_CMCTREE_FUNC (tree_unselect), NULL);
3923 gtk_cmclist_thaw (clist);
3927 /***********************************************************
3928 * Analogons of GtkCMCList functions *
3929 ***********************************************************/
3933 gtk_cmctree_node_set_text (GtkCMCTree *ctree,
3934 GtkCMCTreeNode *node,
3940 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3941 cm_return_if_fail (node != NULL);
3943 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
3946 clist = GTK_CMCLIST (ctree);
3948 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3949 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT,
3952 tree_draw_node (ctree, node);
3956 gtk_cmctree_node_set_pixbuf (GtkCMCTree *ctree,
3957 GtkCMCTreeNode *node,
3963 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3964 cm_return_if_fail (node != NULL);
3965 cm_return_if_fail (pixbuf != NULL);
3967 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
3970 g_object_ref (pixbuf);
3972 clist = GTK_CMCLIST (ctree);
3974 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3975 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXBUF,
3978 tree_draw_node (ctree, node);
3982 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree,
3983 GtkCMCTreeNode *node,
3991 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3992 cm_return_if_fail (node != NULL);
3993 if (column != ctree->tree_column)
3994 cm_return_if_fail (pixbuf != NULL);
3995 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
3998 clist = GTK_CMCLIST (ctree);
4002 g_object_ref (pixbuf);
4005 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4006 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT,
4007 text, spacing, pixbuf);
4009 tree_draw_node (ctree, node);
4013 gtk_cmctree_set_node_info (GtkCMCTree *ctree,
4014 GtkCMCTreeNode *node,
4017 GdkPixbuf *pixbuf_closed,
4018 GdkPixbuf *pixbuf_opened,
4023 gboolean old_expanded;
4025 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4026 cm_return_if_fail (node != NULL);
4028 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4029 old_expanded = GTK_CMCTREE_ROW (node)->expanded;
4031 if (is_leaf && GTK_CMCTREE_ROW (node)->children)
4033 GtkCMCTreeNode *work;
4034 GtkCMCTreeNode *ptr;
4036 work = GTK_CMCTREE_ROW (node)->children;
4040 work = GTK_CMCTREE_ROW (work)->sibling;
4041 gtk_cmctree_remove_node (ctree, ptr);
4045 set_node_info (ctree, node, text, spacing, pixbuf_closed,
4046 pixbuf_opened, is_leaf, expanded);
4048 if (!is_leaf && !old_leaf)
4050 GTK_CMCTREE_ROW (node)->expanded = old_expanded;
4051 if (expanded && !old_expanded)
4052 gtk_cmctree_expand (ctree, node);
4053 else if (!expanded && old_expanded)
4054 gtk_cmctree_collapse (ctree, node);
4057 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4059 tree_draw_node (ctree, node);
4063 gtk_cmctree_node_set_shift (GtkCMCTree *ctree,
4064 GtkCMCTreeNode *node,
4070 GtkRequisition requisition;
4071 gboolean visible = FALSE;
4073 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4074 cm_return_if_fail (node != NULL);
4076 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4079 clist = GTK_CMCLIST (ctree);
4081 if (clist->column[column].auto_resize &&
4082 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4084 visible = gtk_cmctree_is_viewable (ctree, node);
4086 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4087 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4090 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical;
4091 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4094 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row,
4095 column, requisition.width);
4097 tree_draw_node (ctree, node);
4101 remove_grab (GtkCMCList *clist)
4103 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4104 gtk_widget_has_grab (GTK_WIDGET(clist)))
4106 gtk_grab_remove (GTK_WIDGET (clist));
4107 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4113 g_source_remove (clist->htimer);
4119 g_source_remove (clist->vtimer);
4125 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree,
4126 GtkCMCTreeNode *node,
4127 gboolean selectable)
4129 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4130 cm_return_if_fail (node != NULL);
4132 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable)
4135 GTK_CMCTREE_ROW (node)->row.selectable = selectable;
4137 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4141 clist = GTK_CMCLIST (ctree);
4143 if (clist->anchor >= 0 &&
4144 clist->selection_mode == GTK_SELECTION_MULTIPLE)
4146 clist->drag_button = 0;
4147 remove_grab (clist);
4149 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4151 gtk_cmctree_unselect (ctree, node);
4156 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree,
4157 GtkCMCTreeNode *node)
4159 cm_return_val_if_fail (node != NULL, FALSE);
4161 return GTK_CMCTREE_ROW (node)->row.selectable;
4165 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree,
4166 GtkCMCTreeNode *node,
4169 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1);
4170 cm_return_val_if_fail (node != NULL, -1);
4172 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4175 return GTK_CMCTREE_ROW (node)->row.cell[column].type;
4179 gtk_cmctree_node_get_text (GtkCMCTree *ctree,
4180 GtkCMCTreeNode *node,
4184 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4185 cm_return_val_if_fail (node != NULL, FALSE);
4187 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4190 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT)
4194 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4200 gtk_cmctree_node_get_pixbuf (GtkCMCTree *ctree,
4201 GtkCMCTreeNode *node,
4205 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4206 cm_return_val_if_fail (node != NULL, FALSE);
4208 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4211 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXBUF)
4215 *pixbuf = GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node)->row.cell[column])->pixbuf;
4221 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree,
4222 GtkCMCTreeNode *node,
4228 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4229 cm_return_val_if_fail (node != NULL, FALSE);
4231 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4234 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT)
4238 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4240 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4241 (node)->row.cell[column])->spacing;
4243 *pixbuf = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4244 (node)->row.cell[column])->pixbuf;
4250 gtk_cmctree_get_node_info (GtkCMCTree *ctree,
4251 GtkCMCTreeNode *node,
4254 GdkPixbuf **pixbuf_closed,
4255 GdkPixbuf **pixbuf_opened,
4259 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4260 cm_return_val_if_fail (node != NULL, FALSE);
4263 *text = GTK_CMCELL_PIXTEXT
4264 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4266 *spacing = GTK_CMCELL_PIXTEXT
4267 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4269 *pixbuf_closed = GTK_CMCTREE_ROW (node)->pixbuf_closed;
4271 *pixbuf_opened = GTK_CMCTREE_ROW (node)->pixbuf_opened;
4273 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4275 *expanded = GTK_CMCTREE_ROW (node)->expanded;
4281 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree,
4282 GtkCMCTreeNode *node,
4287 GtkRequisition requisition;
4288 gboolean visible = FALSE;
4290 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4291 cm_return_if_fail (node != NULL);
4293 clist = GTK_CMCLIST (ctree);
4295 if (column < 0 || column >= clist->columns)
4298 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style)
4301 if (clist->column[column].auto_resize &&
4302 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4304 visible = gtk_cmctree_is_viewable (ctree, node);
4306 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4307 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4310 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4312 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4313 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4314 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4317 GTK_CMCTREE_ROW (node)->row.cell[column].style = style;
4319 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4321 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4323 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4324 GTK_CMCTREE_ROW (node)->row.cell[column].style =
4325 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style,
4326 clist->clist_window);
4330 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column,
4333 tree_draw_node (ctree, node);
4337 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree,
4338 GtkCMCTreeNode *node,
4341 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4342 cm_return_val_if_fail (node != NULL, NULL);
4344 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4347 return GTK_CMCTREE_ROW (node)->row.cell[column].style;
4351 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree,
4352 GtkCMCTreeNode *node,
4356 GtkRequisition requisition;
4358 gint *old_width = NULL;
4361 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4362 cm_return_if_fail (node != NULL);
4364 clist = GTK_CMCLIST (ctree);
4366 if (GTK_CMCTREE_ROW (node)->row.style == style)
4369 visible = gtk_cmctree_is_viewable (ctree, node);
4370 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4372 old_width = g_new (gint, clist->columns);
4373 for (i = 0; i < clist->columns; i++)
4374 if (clist->column[i].auto_resize)
4376 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4377 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition);
4378 old_width[i] = requisition.width;
4382 if (GTK_CMCTREE_ROW (node)->row.style)
4384 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4385 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
4386 g_object_unref (GTK_CMCTREE_ROW (node)->row.style);
4389 GTK_CMCTREE_ROW (node)->row.style = style;
4391 if (GTK_CMCTREE_ROW (node)->row.style)
4393 g_object_ref (GTK_CMCTREE_ROW (node)->row.style);
4395 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4396 GTK_CMCTREE_ROW (node)->row.style =
4397 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style,
4398 clist->clist_window);
4401 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4403 for (i = 0; i < clist->columns; i++)
4404 if (clist->column[i].auto_resize)
4405 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i,
4409 tree_draw_node (ctree, node);
4413 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree,
4414 GtkCMCTreeNode *node)
4416 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4417 cm_return_val_if_fail (node != NULL, NULL);
4419 return GTK_CMCTREE_ROW (node)->row.style;
4423 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree,
4424 GtkCMCTreeNode *node,
4425 const GdkColor *color)
4427 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4428 cm_return_if_fail (node != NULL);
4432 GTK_CMCTREE_ROW (node)->row.foreground = *color;
4433 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE;
4434 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4435 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4436 >K_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE);
4439 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE;
4441 tree_draw_node (ctree, node);
4445 gtk_cmctree_node_set_background (GtkCMCTree *ctree,
4446 GtkCMCTreeNode *node,
4447 const GdkColor *color)
4449 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4450 cm_return_if_fail (node != NULL);
4454 GTK_CMCTREE_ROW (node)->row.background = *color;
4455 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE;
4456 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4457 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4458 >K_CMCTREE_ROW (node)->row.background, TRUE, TRUE);
4461 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE;
4463 tree_draw_node (ctree, node);
4467 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree,
4468 GtkCMCTreeNode *node,
4471 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL);
4475 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree,
4476 GtkCMCTreeNode *node,
4478 GDestroyNotify destroy)
4480 GDestroyNotify dnotify;
4483 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4484 cm_return_if_fail (node != NULL);
4486 dnotify = GTK_CMCTREE_ROW (node)->row.destroy;
4487 ddata = GTK_CMCTREE_ROW (node)->row.data;
4489 GTK_CMCTREE_ROW (node)->row.data = data;
4490 GTK_CMCTREE_ROW (node)->row.destroy = destroy;
4497 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree,
4498 GtkCMCTreeNode *node)
4500 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4502 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL;
4506 gtk_cmctree_node_moveto (GtkCMCTree *ctree,
4507 GtkCMCTreeNode *node,
4515 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4517 clist = GTK_CMCLIST (ctree);
4519 while (node && !gtk_cmctree_is_viewable (ctree, node))
4520 node = GTK_CMCTREE_ROW (node)->parent;
4523 row = g_list_position (clist->row_list, (GList *)node);
4525 gtk_cmclist_moveto (clist, row, column, row_align, col_align);
4529 gtk_cmctree_node_is_visible (GtkCMCTree *ctree,
4530 GtkCMCTreeNode *node)
4534 cm_return_val_if_fail (ctree != NULL, 0);
4535 cm_return_val_if_fail (node != NULL, 0);
4537 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node);
4538 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row);
4542 /***********************************************************
4543 * GtkCMCTree specific functions *
4544 ***********************************************************/
4547 gtk_cmctree_set_indent (GtkCMCTree *ctree,
4552 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4553 cm_return_if_fail (indent >= 0);
4555 if (indent == ctree->tree_indent)
4558 clist = GTK_CMCLIST (ctree);
4559 ctree->tree_indent = indent;
4561 if (clist->column[ctree->tree_column].auto_resize &&
4562 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4563 gtk_cmclist_set_column_width
4564 (clist, ctree->tree_column,
4565 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
4567 CLIST_REFRESH (ctree);
4571 gtk_cmctree_set_spacing (GtkCMCTree *ctree,
4577 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4578 cm_return_if_fail (spacing >= 0);
4580 if (spacing == ctree->tree_spacing)
4583 clist = GTK_CMCLIST (ctree);
4585 old_spacing = ctree->tree_spacing;
4586 ctree->tree_spacing = spacing;
4588 if (clist->column[ctree->tree_column].auto_resize &&
4589 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4590 gtk_cmclist_set_column_width (clist, ctree->tree_column,
4591 clist->column[ctree->tree_column].width +
4592 spacing - old_spacing);
4594 CLIST_REFRESH (ctree);
4598 gtk_cmctree_set_show_stub (GtkCMCTree *ctree,
4601 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4603 show_stub = show_stub != FALSE;
4605 if (show_stub != ctree->show_stub)
4609 clist = GTK_CMCLIST (ctree);
4610 ctree->show_stub = show_stub;
4612 if (CLIST_UNFROZEN (clist) && clist->rows &&
4613 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
4614 GTK_CMCLIST_GET_CLASS (clist)->draw_row
4615 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list));
4620 gtk_cmctree_set_line_style (GtkCMCTree *ctree,
4621 GtkCMCTreeLineStyle line_style)
4626 gtk_cmctree_set_expander_style (GtkCMCTree *ctree,
4627 GtkCMCTreeExpanderStyle expander_style)
4630 GtkCMCTreeExpanderStyle old_style;
4632 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4634 if (expander_style == ctree->expander_style)
4637 clist = GTK_CMCLIST (ctree);
4639 old_style = ctree->expander_style;
4640 ctree->expander_style = expander_style;
4642 if (clist->column[ctree->tree_column].auto_resize &&
4643 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4647 new_width = clist->column[ctree->tree_column].width;
4650 case GTK_CMCTREE_EXPANDER_NONE:
4652 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4653 new_width -= PM_SIZE + 3;
4657 switch (expander_style)
4659 case GTK_CMCTREE_EXPANDER_NONE:
4661 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4662 new_width += PM_SIZE + 3;
4666 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width);
4669 if (gtk_widget_is_drawable (GTK_WIDGET(clist)))
4670 CLIST_REFRESH (clist);
4674 /***********************************************************
4675 * Tree sorting functions *
4676 ***********************************************************/
4680 tree_sort (GtkCMCTree *ctree,
4681 GtkCMCTreeNode *node,
4684 GtkCMCTreeNode *list_start;
4685 GtkCMCTreeNode *cmp;
4686 GtkCMCTreeNode *work;
4689 clist = GTK_CMCLIST (ctree);
4692 list_start = GTK_CMCTREE_ROW (node)->children;
4694 list_start = GTK_CMCTREE_NODE (clist->row_list);
4699 work = GTK_CMCTREE_ROW (cmp)->sibling;
4702 if (clist->sort_type == GTK_SORT_ASCENDING)
4705 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0)
4711 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0)
4714 work = GTK_CMCTREE_ROW (work)->sibling;
4716 if (cmp == list_start)
4717 list_start = GTK_CMCTREE_ROW (cmp)->sibling;
4720 gtk_cmctree_unlink (ctree, cmp, FALSE);
4721 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE);
4727 gtk_cmctree_sort_recursive (GtkCMCTree *ctree,
4728 GtkCMCTreeNode *node)
4731 GtkCMCTreeNode *focus_node = NULL;
4733 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4735 clist = GTK_CMCLIST (ctree);
4737 gtk_cmclist_freeze (clist);
4739 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4741 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4743 g_list_free (clist->undo_selection);
4744 g_list_free (clist->undo_unselection);
4745 clist->undo_selection = NULL;
4746 clist->undo_unselection = NULL;
4749 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4751 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
4753 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL);
4756 tree_sort (ctree, NULL, NULL);
4760 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4761 clist->undo_anchor = clist->focus_row;
4764 gtk_cmclist_thaw (clist);
4768 real_sort_list (GtkCMCList *clist)
4770 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL);
4774 gtk_cmctree_sort_node (GtkCMCTree *ctree,
4775 GtkCMCTreeNode *node)
4778 GtkCMCTreeNode *focus_node = NULL;
4780 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4782 clist = GTK_CMCLIST (ctree);
4784 gtk_cmclist_freeze (clist);
4786 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4788 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4790 g_list_free (clist->undo_selection);
4791 g_list_free (clist->undo_unselection);
4792 clist->undo_selection = NULL;
4793 clist->undo_unselection = NULL;
4796 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4797 focus_node = GTK_CMCTREE_NODE
4798 (g_list_nth (clist->row_list, clist->focus_row));
4800 tree_sort (ctree, node, NULL);
4804 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4805 clist->undo_anchor = clist->focus_row;
4808 gtk_cmclist_thaw (clist);
4811 /************************************************************************/
4814 fake_unselect_all (GtkCMCList *clist,
4818 GList *focus_node = NULL;
4820 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
4822 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
4823 GTK_CMCTREE_ROW (focus_node)->row.selectable)
4825 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
4827 if (CLIST_UNFROZEN (clist) &&
4828 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
4829 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
4830 GTK_CMCLIST_ROW (focus_node));
4834 clist->undo_selection = clist->selection;
4835 clist->selection = NULL;
4836 clist->selection_end = NULL;
4838 for (list = clist->undo_selection; list; list = list->next)
4840 if (list->data == focus_node)
4843 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
4844 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data));
4849 selection_find (GtkCMCList *clist,
4851 GList *row_list_element)
4853 return g_list_find (clist->selection, row_list_element);
4857 resync_selection (GtkCMCList *clist, GdkEvent *event)
4861 GtkCMCTreeNode *node;
4867 cm_return_if_fail (GTK_IS_CMCTREE (clist));
4869 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
4872 if (clist->anchor < 0 || clist->drag_pos < 0)
4875 ctree = GTK_CMCTREE (clist);
4877 clist->freeze_count++;
4879 i = MIN (clist->anchor, clist->drag_pos);
4880 e = MAX (clist->anchor, clist->drag_pos);
4882 if (clist->undo_selection)
4884 list = clist->selection;
4885 clist->selection = clist->undo_selection;
4886 clist->selection_end = g_list_last (clist->selection);
4887 clist->undo_selection = list;
4888 list = clist->selection;
4897 if (gtk_cmctree_is_viewable (ctree, node))
4899 row = g_list_position (clist->row_list, (GList *)node);
4900 if (row >= i && row <= e)
4903 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable)
4905 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4906 gtk_cmctree_unselect (ctree, node);
4907 clist->undo_selection = g_list_prepend (clist->undo_selection,
4913 if (clist->anchor < clist->drag_pos)
4915 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
4916 i++, node = GTK_CMCTREE_NODE_NEXT (node))
4917 if (GTK_CMCTREE_ROW (node)->row.selectable)
4919 if (g_list_find (clist->selection, node))
4921 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
4923 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4924 gtk_cmctree_unselect (ctree, node);
4925 clist->undo_selection =
4926 g_list_prepend (clist->undo_selection, node);
4929 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4931 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
4932 clist->undo_unselection =
4933 g_list_prepend (clist->undo_unselection, node);
4939 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
4940 e--, node = GTK_CMCTREE_NODE_PREV (node))
4941 if (GTK_CMCTREE_ROW (node)->row.selectable)
4943 if (g_list_find (clist->selection, node))
4945 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
4947 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4948 gtk_cmctree_unselect (ctree, node);
4949 clist->undo_selection =
4950 g_list_prepend (clist->undo_selection, node);
4953 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4955 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
4956 clist->undo_unselection =
4957 g_list_prepend (clist->undo_unselection, node);
4962 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
4963 for (list = clist->undo_unselection; list; list = list->next)
4964 gtk_cmctree_select (ctree, list->data);
4967 clist->drag_pos = -1;
4969 if (!CLIST_UNFROZEN (clist))
4970 clist->freeze_count--;
4974 real_undo_selection (GtkCMCList *clist)
4979 cm_return_if_fail (GTK_IS_CMCTREE (clist));
4981 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
4984 if (!(clist->undo_selection || clist->undo_unselection))
4986 gtk_cmclist_unselect_all (clist);
4990 ctree = GTK_CMCTREE (clist);
4992 for (work = clist->undo_selection; work; work = work->next)
4993 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
4994 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data));
4996 for (work = clist->undo_unselection; work; work = work->next)
4997 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
4998 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data));
5000 if (gtk_widget_has_focus (GTK_WIDGET(clist)) &&
5001 clist->focus_row != clist->undo_anchor)
5003 clist->focus_row = clist->undo_anchor;
5004 gtk_widget_queue_draw (GTK_WIDGET (clist));
5007 clist->focus_row = clist->undo_anchor;
5009 clist->undo_anchor = -1;
5011 g_list_free (clist->undo_selection);
5012 g_list_free (clist->undo_unselection);
5013 clist->undo_selection = NULL;
5014 clist->undo_unselection = NULL;
5016 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5017 clist->clist_window_height)
5018 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
5019 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5020 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
5025 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree,
5026 GtkCMCTreeCompareDragFunc cmp_func)
5028 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
5030 ctree->drag_compare = cmp_func;
5034 check_drag (GtkCMCTree *ctree,
5035 GtkCMCTreeNode *drag_source,
5036 GtkCMCTreeNode *drag_target,
5037 GtkCMCListDragPos insert_pos)
5039 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5041 if (drag_source && drag_source != drag_target &&
5042 (!GTK_CMCTREE_ROW (drag_source)->children ||
5043 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target)))
5047 case GTK_CMCLIST_DRAG_NONE:
5049 case GTK_CMCLIST_DRAG_AFTER:
5050 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source)
5051 return (!ctree->drag_compare ||
5052 ctree->drag_compare (ctree,
5054 GTK_CMCTREE_ROW (drag_target)->parent,
5055 GTK_CMCTREE_ROW (drag_target)->sibling));
5057 case GTK_CMCLIST_DRAG_BEFORE:
5058 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target)
5059 return (!ctree->drag_compare ||
5060 ctree->drag_compare (ctree,
5062 GTK_CMCTREE_ROW (drag_target)->parent,
5065 case GTK_CMCLIST_DRAG_INTO:
5066 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf &&
5067 GTK_CMCTREE_ROW (drag_target)->children != drag_source)
5068 return (!ctree->drag_compare ||
5069 ctree->drag_compare (ctree,
5072 GTK_CMCTREE_ROW (drag_target)->children));
5081 /************************************/
5083 drag_dest_info_destroy (gpointer data)
5085 GtkCMCListDestInfo *info = data;
5091 drag_dest_cell (GtkCMCList *clist,
5094 GtkCMCListDestInfo *dest_info)
5100 widget = GTK_WIDGET (clist);
5101 style = gtk_widget_get_style (widget);
5103 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5105 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5106 y -= (border_width +
5107 style->ythickness + clist->column_title_area.height);
5108 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5110 if (dest_info->cell.row >= clist->rows)
5112 dest_info->cell.row = clist->rows - 1;
5113 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5115 if (dest_info->cell.row < -1)
5116 dest_info->cell.row = -1;
5118 x -= border_width + style->xthickness;
5120 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5122 if (dest_info->cell.row >= 0)
5127 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5129 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) &&
5130 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list,
5131 dest_info->cell.row))->is_leaf)
5133 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
5134 h = clist->row_height / 4;
5136 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5138 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5139 h = clist->row_height / 2;
5142 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5145 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5146 else if (clist->row_height - y_delta < h)
5147 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
5153 gtk_cmctree_drag_begin (GtkWidget *widget,
5154 GdkDragContext *context)
5159 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5160 cm_return_if_fail (context != NULL);
5162 clist = GTK_CMCLIST (widget);
5164 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist);
5165 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5166 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
5170 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5171 gtk_drag_set_icon_default (context);
5176 gtk_cmctree_drag_motion (GtkWidget *widget,
5177 GdkDragContext *context,
5184 GtkCMCListDestInfo new_info;
5185 GtkCMCListDestInfo *dest_info;
5187 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
5189 clist = GTK_CMCLIST (widget);
5190 ctree = GTK_CMCTREE (widget);
5192 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
5196 dest_info = g_new (GtkCMCListDestInfo, 1);
5198 dest_info->cell.row = -1;
5199 dest_info->cell.column = -1;
5200 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5202 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
5203 drag_dest_info_destroy);
5206 drag_dest_cell (clist, x, y, &new_info);
5208 if (GTK_CMCLIST_REORDERABLE (clist))
5210 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5211 GdkAtom found = gtk_drag_dest_find_target(widget, context, NULL);
5215 GtkCMCTreeNode *drag_source;
5216 GtkCMCTreeNode *drag_target;
5218 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5219 clist->click_cell.row));
5220 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5221 new_info.cell.row));
5223 if (gtk_drag_get_source_widget (context) != widget ||
5224 !check_drag (ctree, drag_source, drag_target,
5225 new_info.insert_pos))
5227 if (dest_info->cell.row < 0)
5229 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
5235 if (new_info.cell.row != dest_info->cell.row ||
5236 (new_info.cell.row == dest_info->cell.row &&
5237 dest_info->insert_pos != new_info.insert_pos))
5239 dest_info->insert_pos = new_info.insert_pos;
5240 dest_info->cell.row = new_info.cell.row;
5241 dest_info->cell.column = new_info.cell.column;
5243 clist->drag_highlight_row = dest_info->cell.row;
5244 clist->drag_highlight_pos = dest_info->insert_pos;
5246 gdk_drag_status (context,
5247 gdk_drag_context_get_suggested_action(context), time);
5253 dest_info->insert_pos = new_info.insert_pos;
5254 dest_info->cell.row = new_info.cell.row;
5255 dest_info->cell.column = new_info.cell.column;
5260 gtk_cmctree_drag_data_received (GtkWidget *widget,
5261 GdkDragContext *context,
5264 GtkSelectionData *selection_data,
5271 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5272 cm_return_if_fail (context != NULL);
5273 cm_return_if_fail (selection_data != NULL);
5275 ctree = GTK_CMCTREE (widget);
5276 clist = GTK_CMCLIST (widget);
5278 if (GTK_CMCLIST_REORDERABLE (clist) &&
5279 gtk_drag_get_source_widget (context) == widget &&
5280 gtk_selection_data_get_target (selection_data) ==
5281 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
5282 gtk_selection_data_get_format (selection_data) == 8 &&
5283 gtk_selection_data_get_length (selection_data) == sizeof (GtkCMCListCellInfo))
5285 GtkCMCListCellInfo *source_info;
5287 source_info = (GtkCMCListCellInfo *)(gtk_selection_data_get_data (selection_data));
5290 GtkCMCListDestInfo dest_info;
5291 GtkCMCTreeNode *source_node;
5292 GtkCMCTreeNode *dest_node;
5294 drag_dest_cell (clist, x, y, &dest_info);
5296 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5298 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5299 dest_info.cell.row));
5301 if (!source_node || !dest_node)
5304 switch (dest_info.insert_pos)
5306 case GTK_CMCLIST_DRAG_NONE:
5308 case GTK_CMCLIST_DRAG_INTO:
5309 if (check_drag (ctree, source_node, dest_node,
5310 dest_info.insert_pos))
5311 gtk_cmctree_move (ctree, source_node, dest_node,
5312 GTK_CMCTREE_ROW (dest_node)->children);
5313 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5315 case GTK_CMCLIST_DRAG_BEFORE:
5316 if (check_drag (ctree, source_node, dest_node,
5317 dest_info.insert_pos))
5318 gtk_cmctree_move (ctree, source_node,
5319 GTK_CMCTREE_ROW (dest_node)->parent, dest_node);
5320 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5322 case GTK_CMCLIST_DRAG_AFTER:
5323 if (check_drag (ctree, source_node, dest_node,
5324 dest_info.insert_pos))
5325 gtk_cmctree_move (ctree, source_node,
5326 GTK_CMCTREE_ROW (dest_node)->parent,
5327 GTK_CMCTREE_ROW (dest_node)->sibling);
5328 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5336 gtk_cmctree_node_get_type (void)
5338 static GType our_type = 0;
5341 our_type = g_pointer_type_register_static ("GtkCMCTreeNode");