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 #if GLIB_CHECK_VERSION(2,10,0)
69 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values);
71 etype = g_enum_register_static ("GtkCMCTreePos", values);
77 gtk_cmctree_line_style_get_type (void)
79 static GType etype = 0;
81 static const GEnumValue values[] = {
82 { GTK_CMCTREE_LINES_NONE, "GTK_CMCTREE_LINES_NONE", "none" },
85 #if GLIB_CHECK_VERSION(2,10,0)
86 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values);
88 etype = g_enum_register_static ("GtkCMCTreeLineStyle", values);
94 gtk_cmctree_expander_style_get_type (void)
96 static GType etype = 0;
98 static const GEnumValue values[] = {
99 { GTK_CMCTREE_EXPANDER_NONE, "GTK_CMCTREE_EXPANDER_NONE", "none" },
100 { GTK_CMCTREE_EXPANDER_TRIANGLE, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" },
103 #if GLIB_CHECK_VERSION(2,10,0)
104 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values);
106 etype = g_enum_register_static ("GtkCMCTreeExpanderStyle", values);
112 gtk_cmctree_expansion_type_get_type (void)
114 static GType etype = 0;
116 static const GEnumValue values[] = {
117 { GTK_CMCTREE_EXPANSION_EXPAND, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" },
118 { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" },
119 { GTK_CMCTREE_EXPANSION_COLLAPSE, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" },
120 { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" },
121 { GTK_CMCTREE_EXPANSION_TOGGLE, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" },
122 { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" },
125 #if GLIB_CHECK_VERSION(2,10,0)
126 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values);
128 etype = g_enum_register_static ("GtkCMCTreeExpansionType", values);
136 COLUMN_FROM_XPIXEL (GtkCMCList * clist,
141 for (i = 0; i < clist->columns; i++)
142 if (clist->column[i].visible)
144 cx = clist->column[i].area.x + clist->hoffset;
146 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
147 x <= (cx + clist->column[i].area.width + COLUMN_INSET))
155 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
156 #define CLIST_REFRESH(clist) G_STMT_START { \
157 if (CLIST_UNFROZEN (clist)) \
158 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
174 static void gtk_cmctree_class_init (GtkCMCTreeClass *klass);
175 static void gtk_cmctree_init (GtkCMCTree *ctree);
176 static GObject* gtk_cmctree_constructor (GType type,
177 guint n_construct_properties,
178 GObjectConstructParam *construct_params);
179 static void gtk_cmctree_set_arg (GObject *object,
183 static void gtk_cmctree_get_arg (GObject *object,
187 static void gtk_cmctree_realize (GtkWidget *widget);
188 static void gtk_cmctree_unrealize (GtkWidget *widget);
189 static gint gtk_cmctree_button_press (GtkWidget *widget,
190 GdkEventButton *event);
191 static void ctree_attach_styles (GtkCMCTree *ctree,
192 GtkCMCTreeNode *node,
194 static void ctree_detach_styles (GtkCMCTree *ctree,
195 GtkCMCTreeNode *node,
197 static void set_cell_contents (GtkCMCList *clist,
198 GtkCMCListRow *clist_row,
204 static void set_node_info (GtkCMCTree *ctree,
205 GtkCMCTreeNode *node,
208 GdkPixbuf *pixbuf_closed,
209 GdkPixbuf *pixbuf_opened,
212 static GtkCMCTreeRow *row_new (GtkCMCTree *ctree);
213 static void row_delete (GtkCMCTree *ctree,
214 GtkCMCTreeRow *ctree_row);
215 static void tree_delete (GtkCMCTree *ctree,
216 GtkCMCTreeNode *node,
218 static void tree_delete_row (GtkCMCTree *ctree,
219 GtkCMCTreeNode *node,
221 static void real_clear (GtkCMCList *clist);
222 static void tree_update_level (GtkCMCTree *ctree,
223 GtkCMCTreeNode *node,
225 static void tree_select (GtkCMCTree *ctree,
226 GtkCMCTreeNode *node,
228 static void tree_unselect (GtkCMCTree *ctree,
229 GtkCMCTreeNode *node,
231 static void real_select_all (GtkCMCList *clist);
232 static void real_unselect_all (GtkCMCList *clist);
233 static void tree_expand (GtkCMCTree *ctree,
234 GtkCMCTreeNode *node,
236 static void tree_collapse (GtkCMCTree *ctree,
237 GtkCMCTreeNode *node,
239 static void tree_collapse_to_depth (GtkCMCTree *ctree,
240 GtkCMCTreeNode *node,
242 static void tree_toggle_expansion (GtkCMCTree *ctree,
243 GtkCMCTreeNode *node,
245 static void change_focus_row_expansion (GtkCMCTree *ctree,
246 GtkCMCTreeExpansionType expansion);
247 static void real_select_row (GtkCMCList *clist,
251 static void real_unselect_row (GtkCMCList *clist,
255 static void real_tree_select (GtkCMCTree *ctree,
256 GtkCMCTreeNode *node,
258 static void real_tree_unselect (GtkCMCTree *ctree,
259 GtkCMCTreeNode *node,
261 static void real_tree_expand (GtkCMCTree *ctree,
262 GtkCMCTreeNode *node);
263 static void real_tree_collapse (GtkCMCTree *ctree,
264 GtkCMCTreeNode *node);
265 static void real_tree_move (GtkCMCTree *ctree,
266 GtkCMCTreeNode *node,
267 GtkCMCTreeNode *new_parent,
268 GtkCMCTreeNode *new_sibling);
269 static void real_row_move (GtkCMCList *clist,
272 static void gtk_cmctree_link (GtkCMCTree *ctree,
273 GtkCMCTreeNode *node,
274 GtkCMCTreeNode *parent,
275 GtkCMCTreeNode *sibling,
276 gboolean update_focus_row);
277 static void gtk_cmctree_unlink (GtkCMCTree *ctree,
278 GtkCMCTreeNode *node,
279 gboolean update_focus_row);
280 static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree,
281 GtkCMCTreeNode *node);
282 static gboolean ctree_is_hot_spot (GtkCMCTree *ctree,
283 GtkCMCTreeNode *node,
287 static void tree_sort (GtkCMCTree *ctree,
288 GtkCMCTreeNode *node,
290 static void fake_unselect_all (GtkCMCList *clist,
292 static GList * selection_find (GtkCMCList *clist,
294 GList *row_list_element);
295 static void resync_selection (GtkCMCList *clist,
297 static void real_undo_selection (GtkCMCList *clist);
298 static void select_row_recursive (GtkCMCTree *ctree,
299 GtkCMCTreeNode *node,
301 static gint real_insert_row (GtkCMCList *clist,
304 static void real_remove_row (GtkCMCList *clist,
306 static void real_sort_list (GtkCMCList *clist);
307 static void cell_size_request (GtkCMCList *clist,
308 GtkCMCListRow *clist_row,
310 GtkRequisition *requisition);
311 static void column_auto_resize (GtkCMCList *clist,
312 GtkCMCListRow *clist_row,
315 static void auto_resize_columns (GtkCMCList *clist);
318 static gboolean check_drag (GtkCMCTree *ctree,
319 GtkCMCTreeNode *drag_source,
320 GtkCMCTreeNode *drag_target,
321 GtkCMCListDragPos insert_pos);
322 static void gtk_cmctree_drag_begin (GtkWidget *widget,
323 GdkDragContext *context);
324 static gint gtk_cmctree_drag_motion (GtkWidget *widget,
325 GdkDragContext *context,
329 static void gtk_cmctree_drag_data_received (GtkWidget *widget,
330 GdkDragContext *context,
333 GtkSelectionData *selection_data,
336 static void remove_grab (GtkCMCList *clist);
337 static void drag_dest_cell (GtkCMCList *clist,
340 GtkCMCListDestInfo *dest_info);
350 CHANGE_FOCUS_ROW_EXPANSION,
354 static GtkCMCListClass *parent_class = NULL;
355 static GtkContainerClass *container_class = NULL;
356 static guint ctree_signals[LAST_SIGNAL] = {0};
360 gtk_cmctree_get_type (void)
362 static GType ctree_type = 0;
366 static const GTypeInfo ctree_info =
368 sizeof (GtkCMCTreeClass),
370 (GBaseInitFunc) NULL,
371 (GBaseFinalizeFunc) NULL,
373 (GClassInitFunc) gtk_cmctree_class_init,
374 (GClassFinalizeFunc) NULL,
375 NULL, /* class_data */
379 (GInstanceInitFunc) gtk_cmctree_init,
382 ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0);
389 draw_cell_pixbuf (GdkWindow *window,
390 GdkRectangle *clip_rectangle,
401 if (!pixbuf || (width == 0 && height == 0))
404 if (x < clip_rectangle->x)
406 xsrc = clip_rectangle->x - x;
408 x = clip_rectangle->x;
410 if (x + width > clip_rectangle->x + clip_rectangle->width)
411 width = clip_rectangle->x + clip_rectangle->width - x;
413 if (y < clip_rectangle->y)
415 ysrc = clip_rectangle->y - y;
417 y = clip_rectangle->y;
420 if (y + height > clip_rectangle->y + clip_rectangle->height)
421 height = clip_rectangle->y + clip_rectangle->height - y;
423 gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
426 return x + MAX (width, 0);
430 draw_expander (GtkCMCTree *ctree,
431 GtkCMCTreeRow *ctree_row,
433 GdkRectangle *clip_rectangle,
439 gint justification_factor;
442 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
445 clist = GTK_CMCLIST (ctree);
446 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
447 justification_factor = -1;
449 justification_factor = 1;
450 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
451 y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
452 (clip_rectangle->height + 1) % 2) + 1;
454 y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 -
455 (clip_rectangle->height/2 + 1) % 2) + 1;
457 if (!ctree_row->children)
459 return x + justification_factor * (PM_SIZE + 3);
462 if (ctree_row->expanded)
465 points[0].y = y + (PM_SIZE + 2) / 6;
466 points[1].x = points[0].x + justification_factor * (PM_SIZE + 2);
467 points[1].y = points[0].y;
468 points[2].x = (points[0].x +
469 justification_factor * (PM_SIZE + 2) / 2);
470 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
474 points[0].x = x + justification_factor * ((PM_SIZE + 2) / 6 + 2);
476 points[1].x = points[0].x;
477 points[1].y = points[0].y + (PM_SIZE + 2);
478 points[2].x = (points[0].x +
479 justification_factor * (2 * (PM_SIZE + 2) / 3 - 1));
480 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
485 cairo_set_source_rgb(cr, 255, 255, 255);
486 cairo_set_line_width(cr, 1);
487 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
488 cairo_move_to(cr, points[0].x, points[0].y);
489 cairo_line_to(cr, points[1].x, points[1].y);
490 cairo_line_to(cr, points[2].x, points[2].y);
491 cairo_close_path(cr);
495 gdk_cairo_set_source_color(cr, >k_widget_get_style(GTK_WIDGET(ctree))->fg[GTK_STATE_NORMAL]);
496 cairo_set_line_width(cr, 1);
497 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
498 cairo_move_to(cr, points[0].x, points[0].y);
499 cairo_line_to(cr, points[1].x, points[1].y);
500 cairo_line_to(cr, points[2].x, points[2].y);
501 cairo_close_path(cr);
503 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
505 x += justification_factor * (PM_SIZE + 3);
511 get_offset(GtkCMCTree *ctree,
512 GtkCMCTreeRow *ctree_row,
514 GdkRectangle *clip_rectangle)
517 justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
520 return (clip_rectangle->x + clip_rectangle->width - 1 -
521 ctree->tree_indent * (ctree_row->level - 1));
523 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
527 get_cell_style (GtkCMCList *clist,
528 GtkCMCListRow *clist_row,
535 gtkstyle = gtk_widget_get_style (GTK_WIDGET (clist));
537 if (clist_row->cell[column].style)
540 *style = clist_row->cell[column].style;
542 else if (clist_row->style)
545 *style = clist_row->style;
554 static gboolean filter_fg (PangoAttribute *attribute, gpointer data)
556 const PangoAttrClass *klass = attribute->klass;
557 if (klass->type == PANGO_ATTR_FOREGROUND)
564 create_cell_layout (GtkCMCList *clist,
565 GtkCMCListRow *clist_row,
573 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style);
576 cell = &clist_row->cell[column];
579 case GTK_CMCELL_TEXT:
580 case GTK_CMCELL_PIXTEXT:
581 text = ((cell->type == GTK_CMCELL_PIXTEXT) ?
582 GTK_CMCELL_PIXTEXT (*cell)->text :
583 GTK_CMCELL_TEXT (*cell)->text);
588 if (!GTK_SCTREE(clist)->use_markup[column]) {
589 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
590 ((cell->type == GTK_CMCELL_PIXTEXT) ?
591 GTK_CMCELL_PIXTEXT (*cell)->text :
592 GTK_CMCELL_TEXT (*cell)->text));
593 pango_layout_set_font_description (layout, style->font_desc);
595 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist));
596 layout = pango_layout_new (context);
597 pango_layout_set_markup (layout, text, -1);
598 pango_layout_set_font_description (layout, style->font_desc);
599 if (clist_row->state == GTK_STATE_SELECTED) {
600 /* for selected row, we should remove any forced foreground color
601 * or it looks like shit */
602 PangoAttrList *list = pango_layout_get_attributes(layout);
603 PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL);
605 pango_attr_list_unref(rem);
618 draw_row (GtkCMCList *clist,
621 GtkCMCListRow *clist_row)
627 GdkRectangle row_rectangle;
628 GdkRectangle cell_rectangle;
629 GdkRectangle clip_rectangle;
630 GdkRectangle intersect_rectangle;
635 static GdkColor greybg={0, 0, 0, 0};
636 static gboolean color_change = TRUE;
638 GdkColor *fgcolor, *bgcolor;
640 cm_return_if_fail (clist != NULL);
641 widget = GTK_WIDGET (clist);
642 style = clist_row->style ? clist_row->style : gtk_widget_get_style (widget);
644 if (greybg.pixel == 0 &&
648 GdkColor normalbg = {0, 0xffff, 0xffff, 0xffff};
650 normalbg = style->base[GTK_STATE_NORMAL];
652 if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
653 greybg.pixel = normalbg.pixel;
654 greybg.red = normalbg.red - prefs_common.stripes_color_offset;
655 greybg.green = normalbg.green - prefs_common.stripes_color_offset;
656 greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
657 } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
658 greybg.pixel = normalbg.pixel;
659 greybg.red = normalbg.red + prefs_common.stripes_color_offset;
660 greybg.green = normalbg.green + prefs_common.stripes_color_offset;
661 greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
663 color_change = FALSE;
667 /* bail now if we arn't drawable yet */
668 if (!gtk_widget_is_drawable (GTK_WIDGET(clist)) || row < 0 || row >= clist->rows)
671 ctree = GTK_CMCTREE (clist);
673 /* if the function is passed the pointer to the row instead of null,
674 * it avoids this expensive lookup */
676 clist_row = (g_list_nth (clist->row_list, row))->data;
678 /* rectangle of the entire row */
680 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
681 row_rectangle.width = clist->clist_window_width;
682 row_rectangle.height = clist->row_height;
684 /* rectangle of the cell spacing above the row */
685 cell_rectangle.x = 0;
686 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
687 cell_rectangle.width = row_rectangle.width;
688 cell_rectangle.height = CELL_SPACING;
690 /* rectangle used to clip drawing operations, its y and height
691 * positions only need to be set once, so we set them once here.
692 * the x and width are set withing the drawing loop below once per
694 clip_rectangle.y = row_rectangle.y;
695 clip_rectangle.height = row_rectangle.height;
697 if (prefs_common.use_stripes_everywhere && GTK_SCTREE(ctree)->show_stripes
698 && color_change && row % 2) {
701 bgcolor = &style->base[GTK_STATE_NORMAL];
703 state = clist_row->state;
705 cr = gdk_cairo_create(clist->clist_window);
707 if (clist_row->fg_set && state != GTK_STATE_SELECTED)
708 fgcolor = &clist_row->foreground;
710 fgcolor = &style->fg[clist_row->state];
711 /* draw the cell borders */
714 crect = &intersect_rectangle;
716 if (gdk_rectangle_intersect (area, &cell_rectangle, crect)) {
717 gdk_cairo_rectangle(cr, &cell_rectangle);
718 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
724 crect = &cell_rectangle;
726 gdk_cairo_rectangle(cr, &cell_rectangle);
727 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
731 /* the last row has to clear its bottom cell spacing too */
732 if (clist_row == clist->row_list_end->data)
734 cell_rectangle.y += clist->row_height + CELL_SPACING;
736 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
738 gdk_cairo_rectangle(cr, crect);
739 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
744 for (last_column = clist->columns - 1;
745 last_column >= 0 && !clist->column[last_column].visible; last_column--)
748 /* iterate and draw all the columns (row cells) and draw their contents */
749 for (i = 0; i < clist->columns; i++)
752 PangoLayout *layout = NULL;
753 PangoRectangle logical_rect;
761 if (!clist->column[i].visible)
764 get_cell_style (clist, clist_row, state, i, &style);
766 /* calculate clipping region */
767 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
768 clip_rectangle.width = clist->column[i].area.width;
770 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
771 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
772 (1 + (i == last_column)) * CELL_SPACING);
773 cell_rectangle.y = clip_rectangle.y;
774 cell_rectangle.height = clip_rectangle.height;
780 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
781 &intersect_rectangle))
783 if (i != ctree->tree_column)
788 gdk_cairo_rectangle(cr, &cell_rectangle);
789 if (state == GTK_STATE_NORMAL)
790 gdk_cairo_set_source_color(cr, bgcolor);
792 gdk_cairo_set_source_color(cr, &style->base[state]);
795 layout = create_cell_layout (clist, clist_row, i);
798 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
799 width = logical_rect.width;
804 switch (clist_row->cell[i].type)
806 case GTK_CMCELL_PIXBUF:
807 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
808 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
809 width += pixbuf_width;
811 case GTK_CMCELL_PIXTEXT:
812 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
814 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
815 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
816 width += pixbuf_width;
819 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text &&
820 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
821 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
823 if (i == ctree->tree_column)
824 width += (ctree->tree_indent *
825 ((GtkCMCTreeRow *)clist_row)->level);
831 switch (clist->column[i].justification)
833 case GTK_JUSTIFY_LEFT:
834 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
836 case GTK_JUSTIFY_RIGHT:
837 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
838 clip_rectangle.width - width);
840 case GTK_JUSTIFY_CENTER:
841 case GTK_JUSTIFY_FILL:
842 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
843 (clip_rectangle.width / 2) - (width / 2));
847 if (i != ctree->tree_column)
849 int start_y = (clip_rectangle.height - height) / 2;
850 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
851 start_y = (clip_rectangle.height/2 - height) / 2;
853 offset += clist_row->cell[i].horizontal;
854 switch (clist_row->cell[i].type)
856 case GTK_CMCELL_PIXBUF:
858 (clist->clist_window, &clip_rectangle, cr,
859 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf,
861 clip_rectangle.y + clist_row->cell[i].vertical +
863 pixbuf_width, height);
865 case GTK_CMCELL_PIXTEXT:
866 offset = draw_cell_pixbuf
867 (clist->clist_window, &clip_rectangle, cr,
868 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
870 clip_rectangle.y + clist_row->cell[i].vertical +
872 pixbuf_width, height);
873 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
876 case GTK_CMCELL_TEXT:
879 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
880 gdk_cairo_set_source_color(cr, fgcolor);
881 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
882 pango_cairo_show_layout(cr, layout);
883 g_object_unref (G_OBJECT (layout));
893 /* draw ctree->tree_column */
894 cell_rectangle.y -= CELL_SPACING;
895 cell_rectangle.height += CELL_SPACING;
897 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
898 &intersect_rectangle))
901 g_object_unref (G_OBJECT (layout));
907 offset = get_offset (ctree, (GtkCMCTreeRow *)clist_row, i,
911 offset = draw_expander (ctree, (GtkCMCTreeRow *)clist_row,
912 style, &clip_rectangle, cr, offset);
914 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
915 offset -= ctree->tree_spacing;
917 offset += ctree->tree_spacing;
919 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
920 offset -= (pixbuf_width + clist_row->cell[i].horizontal);
922 offset += clist_row->cell[i].horizontal;
925 offset = draw_cell_pixbuf (clist->clist_window, &clip_rectangle, cr,
926 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
928 clip_rectangle.y + clist_row->cell[i].vertical
929 + (clip_rectangle.height - height) / 2,
930 pixbuf_width, height);
934 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
936 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
938 offset = (old_offset - string_width);
939 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
940 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
944 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
945 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
948 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
949 gdk_cairo_set_source_color(cr, fgcolor);
950 pango_cairo_show_layout(cr, layout);
952 g_object_unref (G_OBJECT (layout));
955 /* draw focus rectangle */
956 if (clist->focus_row == row &&
957 gtk_widget_get_can_focus (widget) && gtk_widget_has_focus (widget))
959 if (!area || gdk_rectangle_intersect (area, &row_rectangle,
960 &intersect_rectangle))
962 cairo_set_line_width(cr, 1.0);
963 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
964 gdk_cairo_set_source_color(cr, &style->fg[GTK_STATE_NORMAL]);
965 cairo_rectangle(cr, row_rectangle.x, row_rectangle.y,
966 row_rectangle.width + 1,
967 row_rectangle.height);
975 gtk_cmctree_class_init (GtkCMCTreeClass *klass)
977 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
978 GtkObjectClass *object_class;
979 GtkWidgetClass *widget_class;
980 GtkCMCListClass *clist_class;
981 GtkBindingSet *binding_set;
983 gobject_class->constructor = gtk_cmctree_constructor;
985 object_class = (GtkObjectClass *) klass;
986 widget_class = (GtkWidgetClass *) klass;
987 container_class = (GtkContainerClass *) klass;
988 clist_class = (GtkCMCListClass *) klass;
990 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST);
991 container_class = g_type_class_peek (GTK_TYPE_CONTAINER);
993 gobject_class->set_property = gtk_cmctree_set_arg;
994 gobject_class->get_property = gtk_cmctree_get_arg;
996 widget_class->realize = gtk_cmctree_realize;
997 widget_class->unrealize = gtk_cmctree_unrealize;
998 widget_class->button_press_event = gtk_cmctree_button_press;
1000 widget_class->drag_begin = gtk_cmctree_drag_begin;
1001 widget_class->drag_motion = gtk_cmctree_drag_motion;
1002 widget_class->drag_data_received = gtk_cmctree_drag_data_received;
1004 clist_class->select_row = real_select_row;
1005 clist_class->unselect_row = real_unselect_row;
1006 clist_class->row_move = real_row_move;
1007 clist_class->undo_selection = real_undo_selection;
1008 clist_class->resync_selection = resync_selection;
1009 clist_class->selection_find = selection_find;
1010 clist_class->click_column = NULL;
1011 clist_class->draw_row = draw_row;
1012 clist_class->clear = real_clear;
1013 clist_class->select_all = real_select_all;
1014 clist_class->unselect_all = real_unselect_all;
1015 clist_class->fake_unselect_all = fake_unselect_all;
1016 clist_class->insert_row = real_insert_row;
1017 clist_class->remove_row = real_remove_row;
1018 clist_class->sort_list = real_sort_list;
1019 clist_class->set_cell_contents = set_cell_contents;
1020 clist_class->cell_size_request = cell_size_request;
1022 klass->tree_select_row = real_tree_select;
1023 klass->tree_unselect_row = real_tree_unselect;
1024 klass->tree_expand = real_tree_expand;
1025 klass->tree_collapse = real_tree_collapse;
1026 klass->tree_move = real_tree_move;
1027 klass->change_focus_row_expansion = change_focus_row_expansion;
1029 g_object_class_install_property (gobject_class,
1031 g_param_spec_uint ("n-columns",
1037 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1038 g_object_class_install_property (gobject_class,
1040 g_param_spec_uint ("tree-column",
1046 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1047 g_object_class_install_property (gobject_class,
1049 g_param_spec_uint ("indent",
1055 G_PARAM_READWRITE));
1056 g_object_class_install_property (gobject_class,
1058 g_param_spec_uint ("spacing",
1064 G_PARAM_READWRITE));
1065 g_object_class_install_property (gobject_class,
1067 g_param_spec_boolean ("show-stub",
1071 G_PARAM_READWRITE));
1072 g_object_class_install_property (gobject_class,
1074 g_param_spec_enum ("line-style",
1077 GTK_TYPE_CMCTREE_LINE_STYLE, 0,
1078 G_PARAM_READWRITE));
1079 g_object_class_install_property (gobject_class,
1081 g_param_spec_enum ("expander-style",
1084 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0,
1085 G_PARAM_READWRITE));
1087 ctree_signals[TREE_SELECT_ROW] =
1088 g_signal_new ("tree_select_row",
1089 G_TYPE_FROM_CLASS (object_class),
1091 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row),
1093 claws_marshal_VOID__POINTER_INT,
1095 GTK_TYPE_CMCTREE_NODE,
1097 ctree_signals[TREE_UNSELECT_ROW] =
1098 g_signal_new ("tree_unselect_row",
1099 G_TYPE_FROM_CLASS (object_class),
1101 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row),
1103 claws_marshal_VOID__POINTER_INT,
1105 GTK_TYPE_CMCTREE_NODE,
1107 ctree_signals[TREE_EXPAND] =
1108 g_signal_new ("tree_expand",
1109 G_TYPE_FROM_CLASS (object_class),
1111 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand),
1113 claws_marshal_VOID__POINTER,
1115 GTK_TYPE_CMCTREE_NODE);
1116 ctree_signals[TREE_COLLAPSE] =
1117 g_signal_new ("tree_collapse",
1118 G_TYPE_FROM_CLASS (object_class),
1120 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse),
1122 claws_marshal_VOID__POINTER,
1124 GTK_TYPE_CMCTREE_NODE);
1125 ctree_signals[TREE_MOVE] =
1126 g_signal_new ("tree_move",
1127 G_TYPE_FROM_CLASS (object_class),
1129 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move),
1131 claws_marshal_VOID__POINTER_POINTER_POINTER,
1133 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE);
1134 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
1135 g_signal_new ("change_focus_row_expansion",
1136 G_TYPE_FROM_CLASS (object_class),
1137 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1138 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion),
1140 claws_marshal_VOID__ENUM,
1141 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE);
1143 binding_set = gtk_binding_set_by_class (klass);
1144 gtk_binding_entry_add_signal (binding_set,
1146 "change_focus_row_expansion", 1,
1147 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1148 gtk_binding_entry_add_signal (binding_set,
1149 GDK_KEY_plus, GDK_CONTROL_MASK,
1150 "change_focus_row_expansion", 1,
1151 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1153 gtk_binding_entry_add_signal (binding_set,
1155 "change_focus_row_expansion", 1,
1156 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1157 gtk_binding_entry_add_signal (binding_set,
1158 GDK_KEY_KP_Add, GDK_CONTROL_MASK,
1159 "change_focus_row_expansion", 1,
1160 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1162 gtk_binding_entry_add_signal (binding_set,
1164 "change_focus_row_expansion", 1,
1165 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1166 gtk_binding_entry_add_signal (binding_set,
1167 GDK_KEY_minus, GDK_CONTROL_MASK,
1168 "change_focus_row_expansion", 1,
1170 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1171 gtk_binding_entry_add_signal (binding_set,
1172 GDK_KEY_KP_Subtract, 0,
1173 "change_focus_row_expansion", 1,
1174 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1175 gtk_binding_entry_add_signal (binding_set,
1176 GDK_KEY_KP_Subtract, GDK_CONTROL_MASK,
1177 "change_focus_row_expansion", 1,
1179 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1180 gtk_binding_entry_add_signal (binding_set,
1182 "change_focus_row_expansion", 1,
1183 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1184 gtk_binding_entry_add_signal (binding_set,
1185 GDK_KEY_KP_Equal, 0,
1186 "change_focus_row_expansion", 1,
1187 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1188 gtk_binding_entry_add_signal (binding_set,
1189 GDK_KEY_KP_Multiply, 0,
1190 "change_focus_row_expansion", 1,
1191 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1192 gtk_binding_entry_add_signal (binding_set,
1193 GDK_KEY_asterisk, 0,
1194 "change_focus_row_expansion", 1,
1195 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1196 gtk_binding_entry_add_signal (binding_set,
1197 GDK_KEY_KP_Multiply, GDK_CONTROL_MASK,
1198 "change_focus_row_expansion", 1,
1200 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1201 gtk_binding_entry_add_signal (binding_set,
1202 GDK_KEY_asterisk, GDK_CONTROL_MASK,
1203 "change_focus_row_expansion", 1,
1205 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1209 gtk_cmctree_set_arg (GObject *object,
1211 const GValue *value,
1217 ctree = GTK_CMCTREE (object);
1218 clist = GTK_CMCLIST (ctree);
1222 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
1223 #if !GLIB_CHECK_VERSION(2,10,0)
1224 cm_return_if_fail (clist->row_mem_chunk == NULL);
1226 clist->columns = MAX (1, g_value_get_uint (value));
1227 #if !GLIB_CHECK_VERSION(2,10,0)
1228 clist->row_mem_chunk = g_mem_chunk_new ("ctree row mem chunk",
1229 sizeof (GtkCMCTreeRow),
1230 sizeof (GtkCMCTreeRow)
1231 * CLIST_OPTIMUM_SIZE,
1233 clist->cell_mem_chunk = g_mem_chunk_new ("ctree cell mem chunk",
1234 sizeof (GtkCMCell) * clist->columns,
1235 sizeof (GtkCMCell) * clist->columns
1236 * CLIST_OPTIMUM_SIZE,
1239 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1241 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
1242 ctree->tree_column = g_value_get_uint (value);
1243 #if !GLIB_CHECK_VERSION(2,10,0)
1244 if (clist->row_mem_chunk)
1246 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1249 gtk_cmctree_set_indent (ctree, g_value_get_uint (value));
1252 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value));
1255 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value));
1257 case ARG_LINE_STYLE:
1258 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value));
1260 case ARG_EXPANDER_STYLE:
1261 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value));
1269 gtk_cmctree_get_arg (GObject *object,
1276 ctree = GTK_CMCTREE (object);
1281 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns);
1283 case ARG_TREE_COLUMN:
1284 g_value_set_uint(value, ctree->tree_column);
1287 g_value_set_uint(value, ctree->tree_indent);
1290 g_value_set_uint(value, ctree->tree_spacing);
1293 g_value_set_boolean(value, ctree->show_stub);
1295 case ARG_LINE_STYLE:
1296 g_value_set_enum(value, ctree->line_style);
1298 case ARG_EXPANDER_STYLE:
1299 g_value_set_enum(value, ctree->expander_style);
1302 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1308 gtk_cmctree_init (GtkCMCTree *ctree)
1312 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT);
1313 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE);
1315 clist = GTK_CMCLIST (ctree);
1317 ctree->tree_indent = 20;
1318 ctree->tree_spacing = 5;
1319 ctree->tree_column = 0;
1320 ctree->line_style = GTK_CMCTREE_LINES_NONE;
1321 ctree->expander_style = GTK_CMCTREE_EXPANDER_TRIANGLE;
1322 ctree->drag_compare = NULL;
1323 ctree->show_stub = TRUE;
1325 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS;
1329 ctree_attach_styles (GtkCMCTree *ctree,
1330 GtkCMCTreeNode *node,
1336 clist = GTK_CMCLIST (ctree);
1338 if (GTK_CMCTREE_ROW (node)->row.style)
1339 GTK_CMCTREE_ROW (node)->row.style =
1340 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window);
1342 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set)
1344 GdkColormap *colormap;
1346 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
1347 if (GTK_CMCTREE_ROW (node)->row.fg_set)
1348 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE);
1349 if (GTK_CMCTREE_ROW (node)->row.bg_set)
1350 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE);
1353 for (i = 0; i < clist->columns; i++)
1354 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1355 GTK_CMCTREE_ROW (node)->row.cell[i].style =
1356 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style,
1357 clist->clist_window);
1361 ctree_detach_styles (GtkCMCTree *ctree,
1362 GtkCMCTreeNode *node,
1368 clist = GTK_CMCLIST (ctree);
1370 if (GTK_CMCTREE_ROW (node)->row.style)
1371 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
1372 for (i = 0; i < clist->columns; i++)
1373 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1374 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style);
1378 gtk_cmctree_realize (GtkWidget *widget)
1382 GtkCMCTreeNode *node;
1383 GtkCMCTreeNode *child;
1386 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1388 GTK_WIDGET_CLASS (parent_class)->realize (widget);
1390 ctree = GTK_CMCTREE (widget);
1391 clist = GTK_CMCLIST (widget);
1393 node = GTK_CMCTREE_NODE (clist->row_list);
1394 for (i = 0; i < clist->rows; i++)
1396 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded)
1397 for (child = GTK_CMCTREE_ROW (node)->children; child;
1398 child = GTK_CMCTREE_ROW (child)->sibling)
1399 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
1400 node = GTK_CMCTREE_NODE_NEXT (node);
1405 gtk_cmctree_unrealize (GtkWidget *widget)
1410 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1412 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1414 ctree = GTK_CMCTREE (widget);
1415 clist = GTK_CMCLIST (widget);
1417 if (gtk_widget_get_realized (widget))
1419 GtkCMCTreeNode *node;
1420 GtkCMCTreeNode *child;
1423 node = GTK_CMCTREE_NODE (clist->row_list);
1424 for (i = 0; i < clist->rows; i++)
1426 if (GTK_CMCTREE_ROW (node)->children &&
1427 !GTK_CMCTREE_ROW (node)->expanded)
1428 for (child = GTK_CMCTREE_ROW (node)->children; child;
1429 child = GTK_CMCTREE_ROW (child)->sibling)
1430 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
1431 node = GTK_CMCTREE_NODE_NEXT (node);
1437 gtk_cmctree_button_press (GtkWidget *widget,
1438 GdkEventButton *event)
1442 gint button_actions;
1444 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
1445 cm_return_val_if_fail (event != NULL, FALSE);
1447 ctree = GTK_CMCTREE (widget);
1448 clist = GTK_CMCLIST (widget);
1450 button_actions = clist->button_actions[event->button - 1];
1452 if (button_actions == GTK_CMBUTTON_IGNORED)
1455 if (event->window == clist->clist_window)
1457 GtkCMCTreeNode *work;
1466 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column))
1469 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
1471 if (button_actions & GTK_CMBUTTON_EXPANDS &&
1472 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf &&
1473 (event->type == GDK_2BUTTON_PRESS ||
1474 ctree_is_hot_spot (ctree, work, row, x, y))))
1476 if (GTK_CMCTREE_ROW (work)->expanded)
1477 gtk_cmctree_collapse (ctree, work);
1479 gtk_cmctree_expand (ctree, work);
1485 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
1489 gtk_cmctree_get_offset(GtkCMCTree *ctree,
1490 GtkCMCTreeRow *ctree_row,
1492 GdkRectangle *clip_rectangle)
1494 gint justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
1497 return (clip_rectangle->x + clip_rectangle->width - 1 -
1498 ctree->tree_indent * (ctree_row->level - 1));
1500 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
1503 static GtkCMCTreeNode *
1504 gtk_cmctree_last_visible (GtkCMCTree *ctree,
1505 GtkCMCTreeNode *node)
1507 GtkCMCTreeNode *work;
1512 work = GTK_CMCTREE_ROW (node)->children;
1514 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1517 while (GTK_CMCTREE_ROW (work)->sibling)
1518 work = GTK_CMCTREE_ROW (work)->sibling;
1520 return gtk_cmctree_last_visible (ctree, work);
1524 gtk_cmctree_link (GtkCMCTree *ctree,
1525 GtkCMCTreeNode *node,
1526 GtkCMCTreeNode *parent,
1527 GtkCMCTreeNode *sibling,
1528 gboolean update_focus_row)
1534 gboolean visible = FALSE;
1538 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1539 cm_return_if_fail (node != NULL);
1540 cm_return_if_fail (node != sibling);
1541 cm_return_if_fail (node != parent);
1543 clist = GTK_CMCLIST (ctree);
1545 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1547 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1549 g_list_free (clist->undo_selection);
1550 g_list_free (clist->undo_unselection);
1551 clist->undo_selection = NULL;
1552 clist->undo_unselection = NULL;
1555 for (rows = 1, list_end = (GList *)node; list_end->next;
1556 list_end = list_end->next)
1559 GTK_CMCTREE_ROW (node)->parent = parent;
1560 GTK_CMCTREE_ROW (node)->sibling = sibling;
1562 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1563 GTK_CMCTREE_ROW (parent)->expanded)))
1566 clist->rows += rows;
1570 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1572 work = clist->row_list;
1576 if (work != (GList *)sibling)
1578 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1579 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1580 GTK_CMCTREE_ROW (work)->sibling = node;
1583 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1584 clist->row_list = (GList *) node;
1585 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1586 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling)
1588 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1589 list->next = (GList *)node;
1592 list = (GList *)node;
1593 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1594 list_end->next = (GList *)sibling;
1595 list = (GList *)sibling;
1596 list->prev = list_end;
1597 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1598 GTK_CMCTREE_ROW (parent)->children = node;
1605 while (GTK_CMCTREE_ROW (work)->sibling)
1606 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1607 GTK_CMCTREE_ROW (work)->sibling = node;
1609 /* find last visible child of sibling */
1610 work = (GList *) gtk_cmctree_last_visible (ctree,
1611 GTK_CMCTREE_NODE (work));
1613 list_end->next = work->next;
1615 list = work->next->prev = list_end;
1616 work->next = (GList *)node;
1617 list = (GList *)node;
1624 GTK_CMCTREE_ROW (parent)->children = node;
1625 list = (GList *)node;
1626 list->prev = (GList *)parent;
1627 if (GTK_CMCTREE_ROW (parent)->expanded)
1629 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1630 if (GTK_CMCTREE_NODE_NEXT(parent))
1632 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1633 list->prev = list_end;
1635 list = (GList *)parent;
1636 list->next = (GList *)node;
1639 list_end->next = NULL;
1643 clist->row_list = (GList *)node;
1644 list = (GList *)node;
1646 list_end->next = NULL;
1651 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL);
1653 if (clist->row_list_end == NULL ||
1654 clist->row_list_end->next == (GList *)node)
1655 clist->row_list_end = list_end;
1657 if (visible && update_focus_row)
1661 pos = g_list_position (clist->row_list, (GList *)node);
1663 if (pos <= clist->focus_row)
1665 clist->focus_row += rows;
1666 clist->undo_anchor = clist->focus_row;
1672 gtk_cmctree_unlink (GtkCMCTree *ctree,
1673 GtkCMCTreeNode *node,
1674 gboolean update_focus_row)
1680 GtkCMCTreeNode *work;
1681 GtkCMCTreeNode *parent;
1684 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1685 cm_return_if_fail (node != NULL);
1687 clist = GTK_CMCLIST (ctree);
1689 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1691 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1693 g_list_free (clist->undo_selection);
1694 g_list_free (clist->undo_unselection);
1695 clist->undo_selection = NULL;
1696 clist->undo_unselection = NULL;
1699 visible = gtk_cmctree_is_viewable (ctree, node);
1701 /* clist->row_list_end unlinked ? */
1703 (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1704 (GTK_CMCTREE_ROW (node)->children &&
1705 gtk_cmctree_is_ancestor (ctree, node,
1706 GTK_CMCTREE_NODE (clist->row_list_end)))))
1707 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1711 level = GTK_CMCTREE_ROW (node)->level;
1712 work = GTK_CMCTREE_NODE_NEXT (node);
1713 while (work && GTK_CMCTREE_ROW (work)->level > level)
1715 work = GTK_CMCTREE_NODE_NEXT (work);
1721 clist->rows -= (rows + 1);
1723 if (update_focus_row)
1727 pos = g_list_position (clist->row_list, (GList *)node);
1728 if (pos + rows < clist->focus_row)
1729 clist->focus_row -= (rows + 1);
1730 else if (pos <= clist->focus_row)
1732 if (!GTK_CMCTREE_ROW (node)->sibling)
1733 clist->focus_row = MAX (pos - 1, 0);
1735 clist->focus_row = pos;
1737 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1739 clist->undo_anchor = clist->focus_row;
1745 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1747 list = (GList *)work;
1748 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1751 if (GTK_CMCTREE_NODE_PREV (node) &&
1752 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node)
1754 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1755 list->next = (GList *)work;
1759 parent = GTK_CMCTREE_ROW (node)->parent;
1762 if (GTK_CMCTREE_ROW (parent)->children == node)
1764 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1765 if (!GTK_CMCTREE_ROW (parent)->children)
1766 gtk_cmctree_collapse (ctree, parent);
1770 GtkCMCTreeNode *sibling;
1772 sibling = GTK_CMCTREE_ROW (parent)->children;
1773 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1774 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1775 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1780 if (clist->row_list == (GList *)node)
1781 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1784 GtkCMCTreeNode *sibling;
1786 sibling = GTK_CMCTREE_NODE (clist->row_list);
1787 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1788 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1789 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1795 real_row_move (GtkCMCList *clist,
1800 GtkCMCTreeNode *node;
1802 cm_return_if_fail (GTK_IS_CMCTREE (clist));
1804 if (GTK_CMCLIST_AUTO_SORT (clist))
1807 if (source_row < 0 || source_row >= clist->rows ||
1808 dest_row < 0 || dest_row >= clist->rows ||
1809 source_row == dest_row)
1812 ctree = GTK_CMCTREE (clist);
1813 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row));
1815 if (source_row < dest_row)
1817 GtkCMCTreeNode *work;
1820 work = GTK_CMCTREE_ROW (node)->children;
1822 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level)
1824 work = GTK_CMCTREE_NODE_NEXT (work);
1828 if (dest_row > clist->rows)
1829 dest_row = clist->rows;
1832 if (dest_row < clist->rows)
1834 GtkCMCTreeNode *sibling;
1836 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row));
1837 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling);
1840 gtk_cmctree_move (ctree, node, NULL, NULL);
1844 real_tree_move (GtkCMCTree *ctree,
1845 GtkCMCTreeNode *node,
1846 GtkCMCTreeNode *new_parent,
1847 GtkCMCTreeNode *new_sibling)
1850 GtkCMCTreeNode *work;
1851 gboolean visible = FALSE;
1853 cm_return_if_fail (ctree != NULL);
1854 cm_return_if_fail (node != NULL);
1855 cm_return_if_fail (!new_sibling ||
1856 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
1858 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1861 /* new_parent != child of child */
1862 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1866 clist = GTK_CMCLIST (ctree);
1868 visible = gtk_cmctree_is_viewable (ctree, node);
1870 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1872 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1874 g_list_free (clist->undo_selection);
1875 g_list_free (clist->undo_unselection);
1876 clist->undo_selection = NULL;
1877 clist->undo_unselection = NULL;
1880 if (GTK_CMCLIST_AUTO_SORT (clist))
1882 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
1886 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
1888 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
1890 while (new_sibling && clist->compare
1891 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
1892 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
1895 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
1896 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
1899 gtk_cmclist_freeze (clist);
1902 if (gtk_cmctree_is_viewable (ctree, node))
1903 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1905 gtk_cmctree_unlink (ctree, node, FALSE);
1906 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE);
1910 while (work && !gtk_cmctree_is_viewable (ctree, work))
1911 work = GTK_CMCTREE_ROW (work)->parent;
1912 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
1913 clist->undo_anchor = clist->focus_row;
1916 if (clist->column[ctree->tree_column].auto_resize &&
1917 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1918 (visible || gtk_cmctree_is_viewable (ctree, node)))
1919 gtk_cmclist_set_column_width
1920 (clist, ctree->tree_column,
1921 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
1923 gtk_cmclist_thaw (clist);
1927 change_focus_row_expansion (GtkCMCTree *ctree,
1928 GtkCMCTreeExpansionType action)
1931 GtkCMCTreeNode *node;
1933 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1935 clist = GTK_CMCLIST (ctree);
1937 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
1938 gtk_widget_has_grab (GTK_WIDGET(ctree)))
1942 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
1943 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
1948 case GTK_CMCTREE_EXPANSION_EXPAND:
1949 gtk_cmctree_expand (ctree, node);
1951 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
1952 gtk_cmctree_expand_recursive (ctree, node);
1954 case GTK_CMCTREE_EXPANSION_COLLAPSE:
1955 gtk_cmctree_collapse (ctree, node);
1957 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
1958 gtk_cmctree_collapse_recursive (ctree, node);
1960 case GTK_CMCTREE_EXPANSION_TOGGLE:
1961 gtk_cmctree_toggle_expansion (ctree, node);
1963 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
1964 gtk_cmctree_toggle_expansion_recursive (ctree, node);
1970 real_tree_expand (GtkCMCTree *ctree,
1971 GtkCMCTreeNode *node)
1974 GtkCMCTreeNode *work;
1975 GtkRequisition requisition;
1978 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1980 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1983 clist = GTK_CMCLIST (ctree);
1985 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1987 GTK_CMCTREE_ROW (node)->expanded = TRUE;
1989 visible = gtk_cmctree_is_viewable (ctree, node);
1990 /* get cell width if tree_column is auto resized */
1991 if (visible && clist->column[ctree->tree_column].auto_resize &&
1992 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1993 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1994 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
1996 /* unref/unset closed pixbuf */
1997 if (GTK_CMCELL_PIXTEXT
1998 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2002 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2005 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2008 /* set/ref opened pixbuf */
2009 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2012 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2013 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2017 work = GTK_CMCTREE_ROW (node)->children;
2020 GList *list = (GList *)work;
2021 gint *cell_width = NULL;
2026 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2028 cell_width = g_new0 (gint, clist->columns);
2029 if (clist->column[ctree->tree_column].auto_resize)
2030 cell_width[ctree->tree_column] = requisition.width;
2034 /* search maximum cell widths of auto_resize columns */
2035 for (i = 0; i < clist->columns; i++)
2036 if (clist->column[i].auto_resize)
2038 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2039 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
2040 cell_width[i] = MAX (requisition.width, cell_width[i]);
2043 list = (GList *)work;
2044 work = GTK_CMCTREE_NODE_NEXT (work);
2051 list = (GList *)work;
2052 work = GTK_CMCTREE_NODE_NEXT (work);
2056 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2058 if (GTK_CMCTREE_NODE_NEXT (node))
2062 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2063 tmp_list->prev = list;
2066 clist->row_list_end = list;
2068 list = (GList *)node;
2069 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
2071 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2073 /* resize auto_resize columns if needed */
2074 for (i = 0; i < clist->columns; i++)
2075 if (clist->column[i].auto_resize &&
2076 cell_width[i] > clist->column[i].width)
2077 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
2078 g_free (cell_width);
2080 /* update focus_row position */
2081 row = g_list_position (clist->row_list, (GList *)node);
2082 if (row < clist->focus_row)
2083 clist->focus_row += tmp;
2086 CLIST_REFRESH (clist);
2089 else if (visible && clist->column[ctree->tree_column].auto_resize)
2090 /* resize tree_column if needed */
2091 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2096 real_tree_collapse (GtkCMCTree *ctree,
2097 GtkCMCTreeNode *node)
2100 GtkCMCTreeNode *work;
2101 GtkRequisition requisition;
2105 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2107 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
2108 GTK_CMCTREE_ROW (node)->is_leaf)
2111 clist = GTK_CMCLIST (ctree);
2113 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2115 GTK_CMCTREE_ROW (node)->expanded = FALSE;
2116 level = GTK_CMCTREE_ROW (node)->level;
2118 visible = gtk_cmctree_is_viewable (ctree, node);
2119 /* get cell width if tree_column is auto resized */
2120 if (visible && clist->column[ctree->tree_column].auto_resize &&
2121 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2122 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2123 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2125 /* unref/unset opened pixbuf */
2126 if (GTK_CMCELL_PIXTEXT
2127 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2131 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2134 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2137 /* set/ref closed pixbuf */
2138 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2141 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2142 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2145 work = GTK_CMCTREE_ROW (node)->children;
2152 while (work && GTK_CMCTREE_ROW (work)->level > level)
2154 work = GTK_CMCTREE_NODE_NEXT (work);
2160 list = (GList *)node;
2161 list->next = (GList *)work;
2162 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2164 list = (GList *)work;
2165 list->prev = (GList *)node;
2169 list = (GList *)node;
2171 clist->row_list_end = (GList *)node;
2176 /* resize auto_resize columns if needed */
2177 auto_resize_columns (clist);
2179 row = g_list_position (clist->row_list, (GList *)node);
2180 if (row < clist->focus_row)
2181 clist->focus_row -= tmp;
2183 CLIST_REFRESH (clist);
2186 else if (visible && clist->column[ctree->tree_column].auto_resize &&
2187 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2188 /* resize tree_column if needed */
2189 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2195 column_auto_resize (GtkCMCList *clist,
2196 GtkCMCListRow *clist_row,
2200 /* resize column if needed for auto_resize */
2201 GtkRequisition requisition;
2203 if (!clist->column[column].auto_resize ||
2204 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2208 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2209 column, &requisition);
2211 requisition.width = 0;
2213 if (requisition.width > clist->column[column].width)
2214 gtk_cmclist_set_column_width (clist, column, requisition.width);
2215 else if (requisition.width < old_width &&
2216 old_width == clist->column[column].width)
2221 /* run a "gtk_cmclist_optimal_column_width" but break, if
2222 * the column doesn't shrink */
2223 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
2226 gtk_widget_get_requisition (clist->column[column].button, &req);
2227 new_width = (req.width -
2228 (CELL_SPACING + (2 * COLUMN_INSET)));
2233 for (list = clist->row_list; list; list = list->next)
2235 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2236 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
2237 new_width = MAX (new_width, requisition.width);
2238 if (new_width == clist->column[column].width)
2241 if (new_width < clist->column[column].width)
2242 gtk_cmclist_set_column_width (clist, column, new_width);
2247 auto_resize_columns (GtkCMCList *clist)
2251 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2254 for (i = 0; i < clist->columns; i++)
2255 column_auto_resize (clist, NULL, i, clist->column[i].width);
2259 cell_size_request (GtkCMCList *clist,
2260 GtkCMCListRow *clist_row,
2262 GtkRequisition *requisition)
2267 PangoLayout *layout;
2268 PangoRectangle logical_rect;
2270 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2271 cm_return_if_fail (requisition != NULL);
2273 ctree = GTK_CMCTREE (clist);
2275 layout = create_cell_layout (clist, clist_row, column);
2278 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2280 requisition->width = logical_rect.width;
2281 requisition->height = logical_rect.height;
2283 g_object_unref (G_OBJECT (layout));
2287 requisition->width = 0;
2288 requisition->height = 0;
2291 switch (clist_row->cell[column].type)
2293 case GTK_CMCELL_PIXTEXT:
2294 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf)
2296 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2297 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2298 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2303 requisition->width += width;
2304 requisition->height = MAX (requisition->height, height);
2306 if (column == ctree->tree_column)
2308 requisition->width += (ctree->tree_spacing + ctree->tree_indent *
2309 (((GtkCMCTreeRow *) clist_row)->level - 1));
2310 switch (ctree->expander_style)
2312 case GTK_CMCTREE_EXPANDER_NONE:
2314 case GTK_CMCTREE_EXPANDER_TRIANGLE:
2315 requisition->width += PM_SIZE + 3;
2320 case GTK_CMCELL_PIXBUF:
2321 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2322 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2323 requisition->width += width;
2324 requisition->height = MAX (requisition->height, height);
2330 requisition->width += clist_row->cell[column].horizontal;
2331 requisition->height += clist_row->cell[column].vertical;
2335 set_cell_contents (GtkCMCList *clist,
2336 GtkCMCListRow *clist_row,
2343 gboolean visible = FALSE;
2345 GtkRequisition requisition;
2346 gchar *old_text = NULL;
2347 GdkPixbuf *old_pixbuf = NULL;
2349 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2350 cm_return_if_fail (clist_row != NULL);
2352 ctree = GTK_CMCTREE (clist);
2354 if (clist->column[column].auto_resize &&
2355 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2357 GtkCMCTreeNode *parent;
2359 parent = ((GtkCMCTreeRow *)clist_row)->parent;
2360 if ((parent && GTK_CMCTREE_ROW (parent)->expanded &&
2361 gtk_cmctree_is_viewable (ctree, parent)))
2364 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2365 column, &requisition);
2369 switch (clist_row->cell[column].type)
2371 case GTK_CMCELL_EMPTY:
2373 case GTK_CMCELL_TEXT:
2374 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2376 case GTK_CMCELL_PIXBUF:
2377 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2379 case GTK_CMCELL_PIXTEXT:
2380 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2381 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2383 case GTK_CMCELL_WIDGET:
2391 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2392 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY)
2393 type = GTK_CMCELL_PIXTEXT;
2395 /* Note that pixbuf and mask were already ref'ed by the caller
2399 case GTK_CMCELL_TEXT:
2402 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2403 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2406 case GTK_CMCELL_PIXBUF:
2409 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2410 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2413 case GTK_CMCELL_PIXTEXT:
2414 if (column == ctree->tree_column)
2416 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2417 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2419 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2421 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL;
2424 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2428 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = NULL;
2431 else if (text && pixbuf)
2433 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2434 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2435 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2436 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2443 if (visible && clist->column[column].auto_resize &&
2444 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2445 column_auto_resize (clist, clist_row, column, requisition.width);
2449 g_object_unref (old_pixbuf);
2453 set_node_info (GtkCMCTree *ctree,
2454 GtkCMCTreeNode *node,
2457 GdkPixbuf *pixbuf_closed,
2458 GdkPixbuf *pixbuf_opened,
2462 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2464 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2466 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2468 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2471 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
2472 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
2476 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
2480 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
2483 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
2484 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
2486 if (GTK_CMCTREE_ROW (node)->expanded)
2487 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2488 text, spacing, pixbuf_opened);
2490 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2491 text, spacing, pixbuf_closed);
2495 tree_delete (GtkCMCTree *ctree,
2496 GtkCMCTreeNode *node,
2499 tree_unselect (ctree, node, NULL);
2500 row_delete (ctree, GTK_CMCTREE_ROW (node));
2501 g_list_free_1 ((GList *)node);
2505 tree_delete_row (GtkCMCTree *ctree,
2506 GtkCMCTreeNode *node,
2509 row_delete (ctree, GTK_CMCTREE_ROW (node));
2510 g_list_free_1 ((GList *)node);
2514 tree_update_level (GtkCMCTree *ctree,
2515 GtkCMCTreeNode *node,
2521 if (GTK_CMCTREE_ROW (node)->parent)
2522 GTK_CMCTREE_ROW (node)->level =
2523 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
2525 GTK_CMCTREE_ROW (node)->level = 1;
2529 tree_select (GtkCMCTree *ctree,
2530 GtkCMCTreeNode *node,
2533 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
2534 GTK_CMCTREE_ROW (node)->row.selectable)
2535 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
2540 tree_unselect (GtkCMCTree *ctree,
2541 GtkCMCTreeNode *node,
2544 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
2545 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
2550 tree_expand (GtkCMCTree *ctree,
2551 GtkCMCTreeNode *node,
2554 if (node && !GTK_CMCTREE_ROW (node)->expanded)
2555 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2559 tree_collapse (GtkCMCTree *ctree,
2560 GtkCMCTreeNode *node,
2563 if (node && GTK_CMCTREE_ROW (node)->expanded)
2564 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2568 tree_collapse_to_depth (GtkCMCTree *ctree,
2569 GtkCMCTreeNode *node,
2572 if (node && GTK_CMCTREE_ROW (node)->level == depth)
2573 gtk_cmctree_collapse_recursive (ctree, node);
2577 tree_toggle_expansion (GtkCMCTree *ctree,
2578 GtkCMCTreeNode *node,
2584 if (GTK_CMCTREE_ROW (node)->expanded)
2585 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2587 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2590 static GtkCMCTreeRow *
2591 row_new (GtkCMCTree *ctree)
2594 GtkCMCTreeRow *ctree_row;
2597 clist = GTK_CMCLIST (ctree);
2598 #if GLIB_CHECK_VERSION(2,10,0)
2599 ctree_row = g_slice_new (GtkCMCTreeRow);
2600 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
2602 ctree_row = g_chunk_new (GtkCMCTreeRow, (GMemChunk *)clist->row_mem_chunk);
2603 ctree_row->row.cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk);
2606 for (i = 0; i < clist->columns; i++)
2608 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
2609 ctree_row->row.cell[i].vertical = 0;
2610 ctree_row->row.cell[i].horizontal = 0;
2611 ctree_row->row.cell[i].style = NULL;
2613 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
2615 ctree_row->row.fg_set = FALSE;
2616 ctree_row->row.bg_set = FALSE;
2617 ctree_row->row.style = NULL;
2618 ctree_row->row.selectable = TRUE;
2619 ctree_row->row.state = GTK_STATE_NORMAL;
2620 ctree_row->row.data = NULL;
2621 ctree_row->row.destroy = NULL;
2623 ctree_row->level = 0;
2624 ctree_row->expanded = FALSE;
2625 ctree_row->parent = NULL;
2626 ctree_row->sibling = NULL;
2627 ctree_row->children = NULL;
2628 ctree_row->pixbuf_closed = NULL;
2629 ctree_row->pixbuf_opened = NULL;
2635 row_delete (GtkCMCTree *ctree,
2636 GtkCMCTreeRow *ctree_row)
2641 clist = GTK_CMCLIST (ctree);
2643 for (i = 0; i < clist->columns; i++)
2645 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2646 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
2647 if (ctree_row->row.cell[i].style)
2649 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2650 gtk_style_detach (ctree_row->row.cell[i].style);
2651 g_object_unref (ctree_row->row.cell[i].style);
2655 if (ctree_row->row.style)
2657 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2658 gtk_style_detach (ctree_row->row.style);
2659 g_object_unref (ctree_row->row.style);
2662 if (ctree_row->pixbuf_closed)
2664 g_object_unref (ctree_row->pixbuf_closed);
2667 if (ctree_row->pixbuf_opened)
2669 g_object_unref (ctree_row->pixbuf_opened);
2672 if (ctree_row->row.destroy)
2674 GDestroyNotify dnotify = ctree_row->row.destroy;
2675 gpointer ddata = ctree_row->row.data;
2677 ctree_row->row.destroy = NULL;
2678 ctree_row->row.data = NULL;
2683 #if GLIB_CHECK_VERSION(2,10,0)
2684 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
2685 g_slice_free (GtkCMCTreeRow, ctree_row);
2687 g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
2688 g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
2693 real_select_row (GtkCMCList *clist,
2700 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2702 if ((node = g_list_nth (clist->row_list, row)) &&
2703 GTK_CMCTREE_ROW (node)->row.selectable)
2704 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0,
2709 real_unselect_row (GtkCMCList *clist,
2716 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2718 if ((node = g_list_nth (clist->row_list, row)))
2719 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0,
2724 tree_draw_node (GtkCMCTree *ctree,
2725 GtkCMCTreeNode *node)
2729 clist = GTK_CMCLIST (ctree);
2731 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node))
2733 GtkCMCTreeNode *work;
2736 work = GTK_CMCTREE_NODE (clist->row_list);
2737 while (work && work != node)
2739 work = GTK_CMCTREE_NODE_NEXT (work);
2742 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2743 GTK_CMCLIST_GET_CLASS(ctree)->draw_row
2744 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node));
2749 real_tree_select (GtkCMCTree *ctree,
2750 GtkCMCTreeNode *node,
2755 GtkCMCTreeNode *sel_row;
2756 gboolean node_selected;
2758 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2760 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2761 !GTK_CMCTREE_ROW (node)->row.selectable)
2764 clist = GTK_CMCLIST (ctree);
2766 switch (clist->selection_mode)
2768 case GTK_SELECTION_SINGLE:
2769 case GTK_SELECTION_BROWSE:
2771 node_selected = FALSE;
2772 list = clist->selection;
2776 sel_row = list->data;
2779 if (node == sel_row)
2780 node_selected = TRUE;
2782 g_signal_emit (G_OBJECT (ctree),
2783 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column);
2793 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
2795 if (!clist->selection)
2797 clist->selection = g_list_append (clist->selection, node);
2798 clist->selection_end = clist->selection;
2801 clist->selection_end = g_list_append (clist->selection_end, node)->next;
2803 tree_draw_node (ctree, node);
2807 real_tree_unselect (GtkCMCTree *ctree,
2808 GtkCMCTreeNode *node,
2813 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2815 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
2818 clist = GTK_CMCLIST (ctree);
2820 if (clist->selection_end && clist->selection_end->data == node)
2821 clist->selection_end = clist->selection_end->prev;
2823 clist->selection = g_list_remove (clist->selection, node);
2825 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
2827 tree_draw_node (ctree, node);
2831 select_row_recursive (GtkCMCTree *ctree,
2832 GtkCMCTreeNode *node,
2835 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2836 !GTK_CMCTREE_ROW (node)->row.selectable)
2839 GTK_CMCLIST (ctree)->undo_unselection =
2840 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node);
2841 gtk_cmctree_select (ctree, node);
2845 real_select_all (GtkCMCList *clist)
2848 GtkCMCTreeNode *node;
2850 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2852 ctree = GTK_CMCTREE (clist);
2854 switch (clist->selection_mode)
2856 case GTK_SELECTION_SINGLE:
2857 case GTK_SELECTION_BROWSE:
2860 case GTK_SELECTION_MULTIPLE:
2862 gtk_cmclist_freeze (clist);
2864 g_list_free (clist->undo_selection);
2865 g_list_free (clist->undo_unselection);
2866 clist->undo_selection = NULL;
2867 clist->undo_unselection = NULL;
2869 clist->anchor_state = GTK_STATE_SELECTED;
2871 clist->drag_pos = -1;
2872 clist->undo_anchor = clist->focus_row;
2874 for (node = GTK_CMCTREE_NODE (clist->row_list); node;
2875 node = GTK_CMCTREE_NODE_NEXT (node))
2876 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL);
2878 gtk_cmclist_thaw (clist);
2888 real_unselect_all (GtkCMCList *clist)
2891 GtkCMCTreeNode *node;
2894 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2896 ctree = GTK_CMCTREE (clist);
2898 switch (clist->selection_mode)
2900 case GTK_SELECTION_BROWSE:
2901 if (clist->focus_row >= 0)
2905 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
2910 case GTK_SELECTION_MULTIPLE:
2911 g_list_free (clist->undo_selection);
2912 g_list_free (clist->undo_unselection);
2913 clist->undo_selection = NULL;
2914 clist->undo_unselection = NULL;
2917 clist->drag_pos = -1;
2918 clist->undo_anchor = clist->focus_row;
2925 list = clist->selection;
2931 gtk_cmctree_unselect (ctree, node);
2936 ctree_is_hot_spot (GtkCMCTree *ctree,
2937 GtkCMCTreeNode *node,
2942 GtkCMCTreeRow *tree_row;
2947 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
2948 cm_return_val_if_fail (node != NULL, FALSE);
2950 clist = GTK_CMCLIST (ctree);
2952 if (!clist->column[ctree->tree_column].visible ||
2953 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
2956 tree_row = GTK_CMCTREE_ROW (node);
2958 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
2959 (clist->row_height - 1) % 2);
2961 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
2962 xl = (clist->column[ctree->tree_column].area.x +
2963 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
2964 (tree_row->level - 1) * ctree->tree_indent - PM_SIZE);
2966 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
2967 (tree_row->level - 1) * ctree->tree_indent);
2969 return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
2972 /***********************************************************
2973 ***********************************************************
2974 *** Public interface ***
2975 ***********************************************************
2976 ***********************************************************/
2979 /***********************************************************
2980 * Creation, insertion, deletion *
2981 ***********************************************************/
2984 gtk_cmctree_constructor (GType type,
2985 guint n_construct_properties,
2986 GObjectConstructParam *construct_properties)
2988 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
2989 n_construct_properties,
2990 construct_properties);
2996 gtk_cmctree_new_with_titles (gint columns,
3002 cm_return_val_if_fail (columns > 0, NULL);
3003 cm_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3005 widget = gtk_widget_new (GTK_TYPE_CMCTREE,
3006 "n_columns", columns,
3007 "tree_column", tree_column,
3011 GtkCMCList *clist = GTK_CMCLIST (widget);
3014 for (i = 0; i < columns; i++)
3015 gtk_cmclist_set_column_title (clist, i, titles[i]);
3016 gtk_cmclist_column_titles_show (clist);
3023 gtk_cmctree_new (gint columns,
3026 return gtk_cmctree_new_with_titles (columns, tree_column, NULL);
3030 real_insert_row (GtkCMCList *clist,
3034 GtkCMCTreeNode *parent = NULL;
3035 GtkCMCTreeNode *sibling;
3036 GtkCMCTreeNode *node;
3038 cm_return_val_if_fail (GTK_IS_CMCTREE (clist), -1);
3040 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3042 parent = GTK_CMCTREE_ROW (sibling)->parent;
3044 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5,
3045 NULL, NULL, TRUE, FALSE);
3047 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling)
3048 return g_list_position (clist->row_list, (GList *) node);
3054 gtk_cmctree_insert_node (GtkCMCTree *ctree,
3055 GtkCMCTreeNode *parent,
3056 GtkCMCTreeNode *sibling,
3059 GdkPixbuf *pixbuf_closed,
3060 GdkPixbuf *pixbuf_opened,
3065 GtkCMCTreeRow *new_row;
3066 GtkCMCTreeNode *node;
3070 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3072 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3074 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
3077 clist = GTK_CMCLIST (ctree);
3079 /* create the row */
3080 new_row = row_new (ctree);
3081 list = g_list_alloc ();
3082 list->data = new_row;
3083 node = GTK_CMCTREE_NODE (list);
3086 for (i = 0; i < clist->columns; i++)
3087 if (text[i] && i != ctree->tree_column)
3088 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3089 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
3091 set_node_info (ctree, node, text ?
3092 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
3093 pixbuf_opened, is_leaf, expanded);
3095 /* sorted insertion */
3096 if (GTK_CMCLIST_AUTO_SORT (clist))
3099 sibling = GTK_CMCTREE_ROW (parent)->children;
3101 sibling = GTK_CMCTREE_NODE (clist->row_list);
3103 while (sibling && clist->compare
3104 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
3105 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3108 gtk_cmctree_link (ctree, node, parent, sibling, TRUE);
3110 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
3111 gtk_cmctree_is_viewable (ctree, node))
3113 for (i = 0; i < clist->columns; i++)
3114 if (clist->column[i].auto_resize)
3115 column_auto_resize (clist, &(new_row->row), i, 0);
3118 if (clist->rows == 1)
3120 clist->focus_row = 0;
3121 if (clist->selection_mode == GTK_SELECTION_BROWSE)
3122 gtk_cmctree_select (ctree, node);
3126 CLIST_REFRESH (clist);
3132 gtk_cmctree_insert_gnode (GtkCMCTree *ctree,
3133 GtkCMCTreeNode *parent,
3134 GtkCMCTreeNode *sibling,
3136 GtkCMCTreeGNodeFunc func,
3140 GtkCMCTreeNode *cnode = NULL;
3141 GtkCMCTreeNode *child = NULL;
3142 GtkCMCTreeNode *new_child;
3147 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3148 cm_return_val_if_fail (gnode != NULL, NULL);
3149 cm_return_val_if_fail (func != NULL, NULL);
3151 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3153 clist = GTK_CMCLIST (ctree);
3156 depth = GTK_CMCTREE_ROW (parent)->level + 1;
3158 list = g_list_alloc ();
3159 list->data = row_new (ctree);
3160 cnode = GTK_CMCTREE_NODE (list);
3162 gtk_cmclist_freeze (clist);
3164 set_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
3166 if (!func (ctree, depth, gnode, cnode, data))
3168 tree_delete_row (ctree, cnode, NULL);
3169 gtk_cmclist_thaw (clist);
3173 if (GTK_CMCLIST_AUTO_SORT (clist))
3176 sibling = GTK_CMCTREE_ROW (parent)->children;
3178 sibling = GTK_CMCTREE_NODE (clist->row_list);
3180 while (sibling && clist->compare
3181 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
3182 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3185 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE);
3187 for (work = g_node_last_child (gnode); work; work = work->prev)
3189 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child,
3195 gtk_cmclist_thaw (clist);
3201 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree,
3204 GtkCMCTreeNode *node,
3205 GtkCMCTreeGNodeFunc func,
3208 GtkCMCTreeNode *work;
3212 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3213 cm_return_val_if_fail (node != NULL, NULL);
3214 cm_return_val_if_fail (func != NULL, NULL);
3217 cm_return_val_if_fail (parent != NULL, NULL);
3218 cm_return_val_if_fail (sibling->parent == parent, NULL);
3221 gnode = g_node_new (NULL);
3222 depth = g_node_depth (parent) + 1;
3224 if (!func (ctree, depth, gnode, node, data))
3226 g_node_destroy (gnode);
3231 g_node_insert_before (parent, sibling, gnode);
3233 if (!GTK_CMCTREE_ROW (node)->is_leaf)
3235 GNode *new_sibling = NULL;
3237 for (work = GTK_CMCTREE_ROW (node)->children; work;
3238 work = GTK_CMCTREE_ROW (work)->sibling)
3239 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling,
3242 g_node_reverse_children (gnode);
3249 real_remove_row (GtkCMCList *clist,
3252 GtkCMCTreeNode *node;
3254 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3256 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3259 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node);
3263 gtk_cmctree_remove_node (GtkCMCTree *ctree,
3264 GtkCMCTreeNode *node)
3268 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3270 clist = GTK_CMCLIST (ctree);
3272 gtk_cmclist_freeze (clist);
3276 gtk_cmctree_unlink (ctree, node, TRUE);
3277 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete),
3279 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3280 clist->focus_row >= 0)
3281 gtk_cmclist_select_row (clist, clist->focus_row, -1);
3283 auto_resize_columns (clist);
3286 gtk_cmclist_clear (clist);
3288 gtk_cmclist_thaw (clist);
3292 real_clear (GtkCMCList *clist)
3295 GtkCMCTreeNode *work;
3296 GtkCMCTreeNode *ptr;
3298 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3300 ctree = GTK_CMCTREE (clist);
3302 /* remove all rows */
3303 work = GTK_CMCTREE_NODE (clist->row_list);
3304 clist->row_list = NULL;
3305 clist->row_list_end = NULL;
3307 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3311 work = GTK_CMCTREE_ROW (work)->sibling;
3312 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row),
3315 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3317 parent_class->clear (clist);
3321 /***********************************************************
3322 * Generic recursive functions, querying / finding tree *
3324 ***********************************************************/
3328 gtk_cmctree_post_recursive (GtkCMCTree *ctree,
3329 GtkCMCTreeNode *node,
3330 GtkCMCTreeFunc func,
3333 GtkCMCTreeNode *work;
3334 GtkCMCTreeNode *tmp;
3336 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3337 cm_return_if_fail (func != NULL);
3340 work = GTK_CMCTREE_ROW (node)->children;
3342 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3346 tmp = GTK_CMCTREE_ROW (work)->sibling;
3347 gtk_cmctree_post_recursive (ctree, work, func, data);
3352 func (ctree, node, data);
3356 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree,
3357 GtkCMCTreeNode *node,
3359 GtkCMCTreeFunc func,
3362 GtkCMCTreeNode *work;
3363 GtkCMCTreeNode *tmp;
3365 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3366 cm_return_if_fail (func != NULL);
3370 gtk_cmctree_post_recursive (ctree, node, func, data);
3375 work = GTK_CMCTREE_ROW (node)->children;
3377 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3379 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3383 tmp = GTK_CMCTREE_ROW (work)->sibling;
3384 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data);
3389 if (node && GTK_CMCTREE_ROW (node)->level <= depth)
3390 func (ctree, node, data);
3394 gtk_cmctree_pre_recursive (GtkCMCTree *ctree,
3395 GtkCMCTreeNode *node,
3396 GtkCMCTreeFunc func,
3399 GtkCMCTreeNode *work;
3400 GtkCMCTreeNode *tmp;
3402 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3403 cm_return_if_fail (func != NULL);
3407 work = GTK_CMCTREE_ROW (node)->children;
3408 func (ctree, node, data);
3411 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3415 tmp = GTK_CMCTREE_ROW (work)->sibling;
3416 gtk_cmctree_pre_recursive (ctree, work, func, data);
3422 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree,
3423 GtkCMCTreeNode *node,
3425 GtkCMCTreeFunc func,
3428 GtkCMCTreeNode *work;
3429 GtkCMCTreeNode *tmp;
3431 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3432 cm_return_if_fail (func != NULL);
3436 gtk_cmctree_pre_recursive (ctree, node, func, data);
3442 work = GTK_CMCTREE_ROW (node)->children;
3443 if (GTK_CMCTREE_ROW (node)->level <= depth)
3444 func (ctree, node, data);
3447 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3449 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3453 tmp = GTK_CMCTREE_ROW (work)->sibling;
3454 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data);
3461 gtk_cmctree_is_viewable (GtkCMCTree *ctree,
3462 GtkCMCTreeNode *node)
3464 GtkCMCTreeRow *work;
3466 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3467 cm_return_val_if_fail (node != NULL, FALSE);
3469 work = GTK_CMCTREE_ROW (node);
3471 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded)
3472 work = GTK_CMCTREE_ROW (work->parent);
3481 gtk_cmctree_last (GtkCMCTree *ctree,
3482 GtkCMCTreeNode *node)
3484 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3489 while (GTK_CMCTREE_ROW (node)->sibling)
3490 node = GTK_CMCTREE_ROW (node)->sibling;
3492 if (GTK_CMCTREE_ROW (node)->children)
3493 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children);
3499 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree,
3500 GtkCMCTreeRow *ctree_row)
3502 GtkCMCTreeNode *node;
3504 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3505 cm_return_val_if_fail (ctree_row != NULL, NULL);
3507 if (ctree_row->parent)
3508 node = GTK_CMCTREE_ROW (ctree_row->parent)->children;
3510 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3512 while (GTK_CMCTREE_ROW (node) != ctree_row)
3513 node = GTK_CMCTREE_ROW (node)->sibling;
3519 gtk_cmctree_node_nth (GtkCMCTree *ctree,
3522 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3524 if ((row >= GTK_CMCLIST(ctree)->rows))
3527 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row));
3531 gtk_cmctree_find (GtkCMCTree *ctree,
3532 GtkCMCTreeNode *node,
3533 GtkCMCTreeNode *child)
3539 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3545 if (GTK_CMCTREE_ROW (node)->children)
3547 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child))
3550 node = GTK_CMCTREE_ROW (node)->sibling;
3556 gtk_cmctree_is_ancestor (GtkCMCTree *ctree,
3557 GtkCMCTreeNode *node,
3558 GtkCMCTreeNode *child)
3560 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3561 cm_return_val_if_fail (node != NULL, FALSE);
3563 if (GTK_CMCTREE_ROW (node)->children)
3564 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child);
3570 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree,
3571 GtkCMCTreeNode *node,
3574 GtkCMCTreeNode *work;
3577 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3581 if (GTK_CMCTREE_ROW (node)->row.data == data)
3583 if (GTK_CMCTREE_ROW (node)->children &&
3584 (work = gtk_cmctree_find_by_row_data
3585 (ctree, GTK_CMCTREE_ROW (node)->children, data)))
3587 node = GTK_CMCTREE_ROW (node)->sibling;
3593 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree,
3594 GtkCMCTreeNode *node,
3599 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3601 /* if node == NULL then look in the whole tree */
3603 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3607 if (GTK_CMCTREE_ROW (node)->row.data == data)
3608 list = g_list_append (list, node);
3610 if (GTK_CMCTREE_ROW (node)->children)
3614 sub_list = gtk_cmctree_find_all_by_row_data (ctree,
3618 list = g_list_concat (list, sub_list);
3620 node = GTK_CMCTREE_ROW (node)->sibling;
3626 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree,
3627 GtkCMCTreeNode *node,
3631 GtkCMCTreeNode *work;
3633 cm_return_val_if_fail (func != NULL, NULL);
3636 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3640 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3642 if (GTK_CMCTREE_ROW (node)->children &&
3643 (work = gtk_cmctree_find_by_row_data_custom
3644 (ctree, GTK_CMCTREE_ROW (node)->children, data, func)))
3646 node = GTK_CMCTREE_ROW (node)->sibling;
3652 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree,
3653 GtkCMCTreeNode *node,
3659 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3660 cm_return_val_if_fail (func != NULL, NULL);
3662 /* if node == NULL then look in the whole tree */
3664 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3668 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3669 list = g_list_append (list, node);
3671 if (GTK_CMCTREE_ROW (node)->children)
3675 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree,
3680 list = g_list_concat (list, sub_list);
3682 node = GTK_CMCTREE_ROW (node)->sibling;
3688 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree,
3692 GtkCMCTreeNode *node;
3696 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3698 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
3699 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
3700 return ctree_is_hot_spot (ctree, node, row, x, y);
3706 /***********************************************************
3707 * Tree signals : move, expand, collapse, (un)select *
3708 ***********************************************************/
3712 gtk_cmctree_move (GtkCMCTree *ctree,
3713 GtkCMCTreeNode *node,
3714 GtkCMCTreeNode *new_parent,
3715 GtkCMCTreeNode *new_sibling)
3717 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3718 cm_return_if_fail (node != NULL);
3720 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node,
3721 new_parent, new_sibling);
3725 gtk_cmctree_expand (GtkCMCTree *ctree,
3726 GtkCMCTreeNode *node)
3728 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3729 cm_return_if_fail (node != NULL);
3731 if (GTK_CMCTREE_ROW (node)->is_leaf)
3734 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node);
3738 gtk_cmctree_expand_recursive (GtkCMCTree *ctree,
3739 GtkCMCTreeNode *node)
3742 gboolean thaw = FALSE;
3744 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3746 clist = GTK_CMCLIST (ctree);
3748 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3751 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3753 gtk_cmclist_freeze (clist);
3757 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL);
3760 gtk_cmclist_thaw (clist);
3764 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree,
3765 GtkCMCTreeNode *node,
3769 gboolean thaw = FALSE;
3771 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3773 clist = GTK_CMCLIST (ctree);
3775 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3778 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3780 gtk_cmclist_freeze (clist);
3784 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3785 GTK_CMCTREE_FUNC (tree_expand), NULL);
3788 gtk_cmclist_thaw (clist);
3792 gtk_cmctree_collapse (GtkCMCTree *ctree,
3793 GtkCMCTreeNode *node)
3795 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3796 cm_return_if_fail (node != NULL);
3798 if (GTK_CMCTREE_ROW (node)->is_leaf)
3801 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node);
3805 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree,
3806 GtkCMCTreeNode *node)
3809 gboolean thaw = FALSE;
3812 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3814 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3817 clist = GTK_CMCLIST (ctree);
3819 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3821 gtk_cmclist_freeze (clist);
3825 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3826 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL);
3827 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3828 for (i = 0; i < clist->columns; i++)
3829 if (clist->column[i].auto_resize)
3830 gtk_cmclist_set_column_width (clist, i,
3831 gtk_cmclist_optimal_column_width (clist, i));
3834 gtk_cmclist_thaw (clist);
3838 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree,
3839 GtkCMCTreeNode *node,
3843 gboolean thaw = FALSE;
3846 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3848 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3851 clist = GTK_CMCLIST (ctree);
3853 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3855 gtk_cmclist_freeze (clist);
3859 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3860 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3861 GTK_CMCTREE_FUNC (tree_collapse_to_depth),
3862 GINT_TO_POINTER (depth));
3863 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3864 for (i = 0; i < clist->columns; i++)
3865 if (clist->column[i].auto_resize)
3866 gtk_cmclist_set_column_width (clist, i,
3867 gtk_cmclist_optimal_column_width (clist, i));
3870 gtk_cmclist_thaw (clist);
3874 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree,
3875 GtkCMCTreeNode *node)
3877 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3878 cm_return_if_fail (node != NULL);
3880 if (GTK_CMCTREE_ROW (node)->is_leaf)
3883 tree_toggle_expansion (ctree, node, NULL);
3887 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree,
3888 GtkCMCTreeNode *node)
3891 gboolean thaw = FALSE;
3893 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3895 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3898 clist = GTK_CMCLIST (ctree);
3900 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3902 gtk_cmclist_freeze (clist);
3906 gtk_cmctree_post_recursive (ctree, node,
3907 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL);
3910 gtk_cmclist_thaw (clist);
3914 gtk_cmctree_select (GtkCMCTree *ctree,
3915 GtkCMCTreeNode *node)
3917 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3918 cm_return_if_fail (node != NULL);
3920 if (GTK_CMCTREE_ROW (node)->row.selectable)
3921 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
3926 gtk_cmctree_unselect (GtkCMCTree *ctree,
3927 GtkCMCTreeNode *node)
3929 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3930 cm_return_if_fail (node != NULL);
3932 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
3937 gtk_cmctree_select_recursive (GtkCMCTree *ctree,
3938 GtkCMCTreeNode *node)
3940 gtk_cmctree_real_select_recursive (ctree, node, TRUE);
3944 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree,
3945 GtkCMCTreeNode *node)
3947 gtk_cmctree_real_select_recursive (ctree, node, FALSE);
3951 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree,
3952 GtkCMCTreeNode *node,
3956 gboolean thaw = FALSE;
3958 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3960 clist = GTK_CMCLIST (ctree);
3963 (clist->selection_mode == GTK_SELECTION_BROWSE ||
3964 clist->selection_mode == GTK_SELECTION_SINGLE)) ||
3965 (!state && clist->selection_mode == GTK_SELECTION_BROWSE))
3968 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3970 gtk_cmclist_freeze (clist);
3974 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
3976 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3978 g_list_free (clist->undo_selection);
3979 g_list_free (clist->undo_unselection);
3980 clist->undo_selection = NULL;
3981 clist->undo_unselection = NULL;
3985 gtk_cmctree_post_recursive (ctree, node,
3986 GTK_CMCTREE_FUNC (tree_select), NULL);
3988 gtk_cmctree_post_recursive (ctree, node,
3989 GTK_CMCTREE_FUNC (tree_unselect), NULL);
3992 gtk_cmclist_thaw (clist);
3996 /***********************************************************
3997 * Analogons of GtkCMCList functions *
3998 ***********************************************************/
4002 gtk_cmctree_node_set_text (GtkCMCTree *ctree,
4003 GtkCMCTreeNode *node,
4009 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4010 cm_return_if_fail (node != NULL);
4012 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4015 clist = GTK_CMCLIST (ctree);
4017 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4018 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT,
4021 tree_draw_node (ctree, node);
4025 gtk_cmctree_node_set_pixbuf (GtkCMCTree *ctree,
4026 GtkCMCTreeNode *node,
4032 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4033 cm_return_if_fail (node != NULL);
4034 cm_return_if_fail (pixbuf != NULL);
4036 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4039 g_object_ref (pixbuf);
4041 clist = GTK_CMCLIST (ctree);
4043 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4044 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXBUF,
4047 tree_draw_node (ctree, node);
4051 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree,
4052 GtkCMCTreeNode *node,
4060 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4061 cm_return_if_fail (node != NULL);
4062 if (column != ctree->tree_column)
4063 cm_return_if_fail (pixbuf != NULL);
4064 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4067 clist = GTK_CMCLIST (ctree);
4071 g_object_ref (pixbuf);
4074 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4075 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT,
4076 text, spacing, pixbuf);
4078 tree_draw_node (ctree, node);
4082 gtk_cmctree_set_node_info (GtkCMCTree *ctree,
4083 GtkCMCTreeNode *node,
4086 GdkPixbuf *pixbuf_closed,
4087 GdkPixbuf *pixbuf_opened,
4092 gboolean old_expanded;
4094 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4095 cm_return_if_fail (node != NULL);
4097 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4098 old_expanded = GTK_CMCTREE_ROW (node)->expanded;
4100 if (is_leaf && GTK_CMCTREE_ROW (node)->children)
4102 GtkCMCTreeNode *work;
4103 GtkCMCTreeNode *ptr;
4105 work = GTK_CMCTREE_ROW (node)->children;
4109 work = GTK_CMCTREE_ROW (work)->sibling;
4110 gtk_cmctree_remove_node (ctree, ptr);
4114 set_node_info (ctree, node, text, spacing, pixbuf_closed,
4115 pixbuf_opened, is_leaf, expanded);
4117 if (!is_leaf && !old_leaf)
4119 GTK_CMCTREE_ROW (node)->expanded = old_expanded;
4120 if (expanded && !old_expanded)
4121 gtk_cmctree_expand (ctree, node);
4122 else if (!expanded && old_expanded)
4123 gtk_cmctree_collapse (ctree, node);
4126 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4128 tree_draw_node (ctree, node);
4132 gtk_cmctree_node_set_shift (GtkCMCTree *ctree,
4133 GtkCMCTreeNode *node,
4139 GtkRequisition requisition;
4140 gboolean visible = FALSE;
4142 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4143 cm_return_if_fail (node != NULL);
4145 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4148 clist = GTK_CMCLIST (ctree);
4150 if (clist->column[column].auto_resize &&
4151 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4153 visible = gtk_cmctree_is_viewable (ctree, node);
4155 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4156 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4159 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical;
4160 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4163 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row,
4164 column, requisition.width);
4166 tree_draw_node (ctree, node);
4170 remove_grab (GtkCMCList *clist)
4172 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4173 gtk_widget_has_grab (GTK_WIDGET(clist)))
4175 gtk_grab_remove (GTK_WIDGET (clist));
4176 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4182 g_source_remove (clist->htimer);
4188 g_source_remove (clist->vtimer);
4194 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree,
4195 GtkCMCTreeNode *node,
4196 gboolean selectable)
4198 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4199 cm_return_if_fail (node != NULL);
4201 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable)
4204 GTK_CMCTREE_ROW (node)->row.selectable = selectable;
4206 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4210 clist = GTK_CMCLIST (ctree);
4212 if (clist->anchor >= 0 &&
4213 clist->selection_mode == GTK_SELECTION_MULTIPLE)
4215 clist->drag_button = 0;
4216 remove_grab (clist);
4218 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4220 gtk_cmctree_unselect (ctree, node);
4225 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree,
4226 GtkCMCTreeNode *node)
4228 cm_return_val_if_fail (node != NULL, FALSE);
4230 return GTK_CMCTREE_ROW (node)->row.selectable;
4234 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree,
4235 GtkCMCTreeNode *node,
4238 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1);
4239 cm_return_val_if_fail (node != NULL, -1);
4241 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4244 return GTK_CMCTREE_ROW (node)->row.cell[column].type;
4248 gtk_cmctree_node_get_text (GtkCMCTree *ctree,
4249 GtkCMCTreeNode *node,
4253 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4254 cm_return_val_if_fail (node != NULL, FALSE);
4256 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4259 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT)
4263 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4269 gtk_cmctree_node_get_pixbuf (GtkCMCTree *ctree,
4270 GtkCMCTreeNode *node,
4274 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4275 cm_return_val_if_fail (node != NULL, FALSE);
4277 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4280 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXBUF)
4284 *pixbuf = GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node)->row.cell[column])->pixbuf;
4290 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree,
4291 GtkCMCTreeNode *node,
4297 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4298 cm_return_val_if_fail (node != NULL, FALSE);
4300 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4303 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT)
4307 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4309 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4310 (node)->row.cell[column])->spacing;
4312 *pixbuf = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4313 (node)->row.cell[column])->pixbuf;
4319 gtk_cmctree_get_node_info (GtkCMCTree *ctree,
4320 GtkCMCTreeNode *node,
4323 GdkPixbuf **pixbuf_closed,
4324 GdkPixbuf **pixbuf_opened,
4328 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4329 cm_return_val_if_fail (node != NULL, FALSE);
4332 *text = GTK_CMCELL_PIXTEXT
4333 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4335 *spacing = GTK_CMCELL_PIXTEXT
4336 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4338 *pixbuf_closed = GTK_CMCTREE_ROW (node)->pixbuf_closed;
4340 *pixbuf_opened = GTK_CMCTREE_ROW (node)->pixbuf_opened;
4342 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4344 *expanded = GTK_CMCTREE_ROW (node)->expanded;
4350 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree,
4351 GtkCMCTreeNode *node,
4356 GtkRequisition requisition;
4357 gboolean visible = FALSE;
4359 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4360 cm_return_if_fail (node != NULL);
4362 clist = GTK_CMCLIST (ctree);
4364 if (column < 0 || column >= clist->columns)
4367 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style)
4370 if (clist->column[column].auto_resize &&
4371 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4373 visible = gtk_cmctree_is_viewable (ctree, node);
4375 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4376 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4379 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4381 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4382 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4383 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4386 GTK_CMCTREE_ROW (node)->row.cell[column].style = style;
4388 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4390 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4392 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4393 GTK_CMCTREE_ROW (node)->row.cell[column].style =
4394 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style,
4395 clist->clist_window);
4399 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column,
4402 tree_draw_node (ctree, node);
4406 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree,
4407 GtkCMCTreeNode *node,
4410 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4411 cm_return_val_if_fail (node != NULL, NULL);
4413 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4416 return GTK_CMCTREE_ROW (node)->row.cell[column].style;
4420 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree,
4421 GtkCMCTreeNode *node,
4425 GtkRequisition requisition;
4427 gint *old_width = NULL;
4430 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4431 cm_return_if_fail (node != NULL);
4433 clist = GTK_CMCLIST (ctree);
4435 if (GTK_CMCTREE_ROW (node)->row.style == style)
4438 visible = gtk_cmctree_is_viewable (ctree, node);
4439 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4441 old_width = g_new (gint, clist->columns);
4442 for (i = 0; i < clist->columns; i++)
4443 if (clist->column[i].auto_resize)
4445 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4446 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition);
4447 old_width[i] = requisition.width;
4451 if (GTK_CMCTREE_ROW (node)->row.style)
4453 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4454 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
4455 g_object_unref (GTK_CMCTREE_ROW (node)->row.style);
4458 GTK_CMCTREE_ROW (node)->row.style = style;
4460 if (GTK_CMCTREE_ROW (node)->row.style)
4462 g_object_ref (GTK_CMCTREE_ROW (node)->row.style);
4464 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4465 GTK_CMCTREE_ROW (node)->row.style =
4466 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style,
4467 clist->clist_window);
4470 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4472 for (i = 0; i < clist->columns; i++)
4473 if (clist->column[i].auto_resize)
4474 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i,
4478 tree_draw_node (ctree, node);
4482 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree,
4483 GtkCMCTreeNode *node)
4485 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4486 cm_return_val_if_fail (node != NULL, NULL);
4488 return GTK_CMCTREE_ROW (node)->row.style;
4492 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree,
4493 GtkCMCTreeNode *node,
4494 const GdkColor *color)
4496 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4497 cm_return_if_fail (node != NULL);
4501 GTK_CMCTREE_ROW (node)->row.foreground = *color;
4502 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE;
4503 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4504 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4505 >K_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE);
4508 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE;
4510 tree_draw_node (ctree, node);
4514 gtk_cmctree_node_set_background (GtkCMCTree *ctree,
4515 GtkCMCTreeNode *node,
4516 const GdkColor *color)
4518 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4519 cm_return_if_fail (node != NULL);
4523 GTK_CMCTREE_ROW (node)->row.background = *color;
4524 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE;
4525 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4526 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4527 >K_CMCTREE_ROW (node)->row.background, TRUE, TRUE);
4530 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE;
4532 tree_draw_node (ctree, node);
4536 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree,
4537 GtkCMCTreeNode *node,
4540 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL);
4544 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree,
4545 GtkCMCTreeNode *node,
4547 GDestroyNotify destroy)
4549 GDestroyNotify dnotify;
4552 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4553 cm_return_if_fail (node != NULL);
4555 dnotify = GTK_CMCTREE_ROW (node)->row.destroy;
4556 ddata = GTK_CMCTREE_ROW (node)->row.data;
4558 GTK_CMCTREE_ROW (node)->row.data = data;
4559 GTK_CMCTREE_ROW (node)->row.destroy = destroy;
4566 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree,
4567 GtkCMCTreeNode *node)
4569 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4571 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL;
4575 gtk_cmctree_node_moveto (GtkCMCTree *ctree,
4576 GtkCMCTreeNode *node,
4584 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4586 clist = GTK_CMCLIST (ctree);
4588 while (node && !gtk_cmctree_is_viewable (ctree, node))
4589 node = GTK_CMCTREE_ROW (node)->parent;
4592 row = g_list_position (clist->row_list, (GList *)node);
4594 gtk_cmclist_moveto (clist, row, column, row_align, col_align);
4598 gtk_cmctree_node_is_visible (GtkCMCTree *ctree,
4599 GtkCMCTreeNode *node)
4603 cm_return_val_if_fail (ctree != NULL, 0);
4604 cm_return_val_if_fail (node != NULL, 0);
4606 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node);
4607 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row);
4611 /***********************************************************
4612 * GtkCMCTree specific functions *
4613 ***********************************************************/
4616 gtk_cmctree_set_indent (GtkCMCTree *ctree,
4621 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4622 cm_return_if_fail (indent >= 0);
4624 if (indent == ctree->tree_indent)
4627 clist = GTK_CMCLIST (ctree);
4628 ctree->tree_indent = indent;
4630 if (clist->column[ctree->tree_column].auto_resize &&
4631 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4632 gtk_cmclist_set_column_width
4633 (clist, ctree->tree_column,
4634 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
4636 CLIST_REFRESH (ctree);
4640 gtk_cmctree_set_spacing (GtkCMCTree *ctree,
4646 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4647 cm_return_if_fail (spacing >= 0);
4649 if (spacing == ctree->tree_spacing)
4652 clist = GTK_CMCLIST (ctree);
4654 old_spacing = ctree->tree_spacing;
4655 ctree->tree_spacing = spacing;
4657 if (clist->column[ctree->tree_column].auto_resize &&
4658 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4659 gtk_cmclist_set_column_width (clist, ctree->tree_column,
4660 clist->column[ctree->tree_column].width +
4661 spacing - old_spacing);
4663 CLIST_REFRESH (ctree);
4667 gtk_cmctree_set_show_stub (GtkCMCTree *ctree,
4670 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4672 show_stub = show_stub != FALSE;
4674 if (show_stub != ctree->show_stub)
4678 clist = GTK_CMCLIST (ctree);
4679 ctree->show_stub = show_stub;
4681 if (CLIST_UNFROZEN (clist) && clist->rows &&
4682 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
4683 GTK_CMCLIST_GET_CLASS (clist)->draw_row
4684 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list));
4689 gtk_cmctree_set_line_style (GtkCMCTree *ctree,
4690 GtkCMCTreeLineStyle line_style)
4695 gtk_cmctree_set_expander_style (GtkCMCTree *ctree,
4696 GtkCMCTreeExpanderStyle expander_style)
4699 GtkCMCTreeExpanderStyle old_style;
4701 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4703 if (expander_style == ctree->expander_style)
4706 clist = GTK_CMCLIST (ctree);
4708 old_style = ctree->expander_style;
4709 ctree->expander_style = expander_style;
4711 if (clist->column[ctree->tree_column].auto_resize &&
4712 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4716 new_width = clist->column[ctree->tree_column].width;
4719 case GTK_CMCTREE_EXPANDER_NONE:
4721 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4722 new_width -= PM_SIZE + 3;
4726 switch (expander_style)
4728 case GTK_CMCTREE_EXPANDER_NONE:
4730 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4731 new_width += PM_SIZE + 3;
4735 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width);
4738 if (gtk_widget_is_drawable (GTK_WIDGET(clist)))
4739 CLIST_REFRESH (clist);
4743 /***********************************************************
4744 * Tree sorting functions *
4745 ***********************************************************/
4749 tree_sort (GtkCMCTree *ctree,
4750 GtkCMCTreeNode *node,
4753 GtkCMCTreeNode *list_start;
4754 GtkCMCTreeNode *cmp;
4755 GtkCMCTreeNode *work;
4758 clist = GTK_CMCLIST (ctree);
4761 list_start = GTK_CMCTREE_ROW (node)->children;
4763 list_start = GTK_CMCTREE_NODE (clist->row_list);
4768 work = GTK_CMCTREE_ROW (cmp)->sibling;
4771 if (clist->sort_type == GTK_SORT_ASCENDING)
4774 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0)
4780 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0)
4783 work = GTK_CMCTREE_ROW (work)->sibling;
4785 if (cmp == list_start)
4786 list_start = GTK_CMCTREE_ROW (cmp)->sibling;
4789 gtk_cmctree_unlink (ctree, cmp, FALSE);
4790 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE);
4796 gtk_cmctree_sort_recursive (GtkCMCTree *ctree,
4797 GtkCMCTreeNode *node)
4800 GtkCMCTreeNode *focus_node = NULL;
4802 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4804 clist = GTK_CMCLIST (ctree);
4806 gtk_cmclist_freeze (clist);
4808 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4810 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4812 g_list_free (clist->undo_selection);
4813 g_list_free (clist->undo_unselection);
4814 clist->undo_selection = NULL;
4815 clist->undo_unselection = NULL;
4818 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4820 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
4822 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL);
4825 tree_sort (ctree, NULL, NULL);
4829 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4830 clist->undo_anchor = clist->focus_row;
4833 gtk_cmclist_thaw (clist);
4837 real_sort_list (GtkCMCList *clist)
4839 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL);
4843 gtk_cmctree_sort_node (GtkCMCTree *ctree,
4844 GtkCMCTreeNode *node)
4847 GtkCMCTreeNode *focus_node = NULL;
4849 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4851 clist = GTK_CMCLIST (ctree);
4853 gtk_cmclist_freeze (clist);
4855 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4857 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4859 g_list_free (clist->undo_selection);
4860 g_list_free (clist->undo_unselection);
4861 clist->undo_selection = NULL;
4862 clist->undo_unselection = NULL;
4865 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4866 focus_node = GTK_CMCTREE_NODE
4867 (g_list_nth (clist->row_list, clist->focus_row));
4869 tree_sort (ctree, node, NULL);
4873 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4874 clist->undo_anchor = clist->focus_row;
4877 gtk_cmclist_thaw (clist);
4880 /************************************************************************/
4883 fake_unselect_all (GtkCMCList *clist,
4887 GList *focus_node = NULL;
4889 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
4891 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
4892 GTK_CMCTREE_ROW (focus_node)->row.selectable)
4894 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
4896 if (CLIST_UNFROZEN (clist) &&
4897 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
4898 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
4899 GTK_CMCLIST_ROW (focus_node));
4903 clist->undo_selection = clist->selection;
4904 clist->selection = NULL;
4905 clist->selection_end = NULL;
4907 for (list = clist->undo_selection; list; list = list->next)
4909 if (list->data == focus_node)
4912 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
4913 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data));
4918 selection_find (GtkCMCList *clist,
4920 GList *row_list_element)
4922 return g_list_find (clist->selection, row_list_element);
4926 resync_selection (GtkCMCList *clist, GdkEvent *event)
4930 GtkCMCTreeNode *node;
4936 cm_return_if_fail (GTK_IS_CMCTREE (clist));
4938 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
4941 if (clist->anchor < 0 || clist->drag_pos < 0)
4944 ctree = GTK_CMCTREE (clist);
4946 clist->freeze_count++;
4948 i = MIN (clist->anchor, clist->drag_pos);
4949 e = MAX (clist->anchor, clist->drag_pos);
4951 if (clist->undo_selection)
4953 list = clist->selection;
4954 clist->selection = clist->undo_selection;
4955 clist->selection_end = g_list_last (clist->selection);
4956 clist->undo_selection = list;
4957 list = clist->selection;
4966 if (gtk_cmctree_is_viewable (ctree, node))
4968 row = g_list_position (clist->row_list, (GList *)node);
4969 if (row >= i && row <= e)
4972 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable)
4974 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4975 gtk_cmctree_unselect (ctree, node);
4976 clist->undo_selection = g_list_prepend (clist->undo_selection,
4982 if (clist->anchor < clist->drag_pos)
4984 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
4985 i++, node = GTK_CMCTREE_NODE_NEXT (node))
4986 if (GTK_CMCTREE_ROW (node)->row.selectable)
4988 if (g_list_find (clist->selection, node))
4990 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
4992 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4993 gtk_cmctree_unselect (ctree, node);
4994 clist->undo_selection =
4995 g_list_prepend (clist->undo_selection, node);
4998 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5000 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5001 clist->undo_unselection =
5002 g_list_prepend (clist->undo_unselection, node);
5008 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
5009 e--, node = GTK_CMCTREE_NODE_PREV (node))
5010 if (GTK_CMCTREE_ROW (node)->row.selectable)
5012 if (g_list_find (clist->selection, node))
5014 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5016 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5017 gtk_cmctree_unselect (ctree, node);
5018 clist->undo_selection =
5019 g_list_prepend (clist->undo_selection, node);
5022 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5024 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5025 clist->undo_unselection =
5026 g_list_prepend (clist->undo_unselection, node);
5031 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
5032 for (list = clist->undo_unselection; list; list = list->next)
5033 gtk_cmctree_select (ctree, list->data);
5036 clist->drag_pos = -1;
5038 if (!CLIST_UNFROZEN (clist))
5039 clist->freeze_count--;
5043 real_undo_selection (GtkCMCList *clist)
5048 cm_return_if_fail (GTK_IS_CMCTREE (clist));
5050 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5053 if (!(clist->undo_selection || clist->undo_unselection))
5055 gtk_cmclist_unselect_all (clist);
5059 ctree = GTK_CMCTREE (clist);
5061 for (work = clist->undo_selection; work; work = work->next)
5062 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5063 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data));
5065 for (work = clist->undo_unselection; work; work = work->next)
5066 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5067 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data));
5069 if (gtk_widget_has_focus (GTK_WIDGET(clist)) &&
5070 clist->focus_row != clist->undo_anchor)
5072 clist->focus_row = clist->undo_anchor;
5073 gtk_widget_queue_draw (GTK_WIDGET (clist));
5076 clist->focus_row = clist->undo_anchor;
5078 clist->undo_anchor = -1;
5080 g_list_free (clist->undo_selection);
5081 g_list_free (clist->undo_unselection);
5082 clist->undo_selection = NULL;
5083 clist->undo_unselection = NULL;
5085 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5086 clist->clist_window_height)
5087 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
5088 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5089 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
5094 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree,
5095 GtkCMCTreeCompareDragFunc cmp_func)
5097 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
5099 ctree->drag_compare = cmp_func;
5103 check_drag (GtkCMCTree *ctree,
5104 GtkCMCTreeNode *drag_source,
5105 GtkCMCTreeNode *drag_target,
5106 GtkCMCListDragPos insert_pos)
5108 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5110 if (drag_source && drag_source != drag_target &&
5111 (!GTK_CMCTREE_ROW (drag_source)->children ||
5112 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target)))
5116 case GTK_CMCLIST_DRAG_NONE:
5118 case GTK_CMCLIST_DRAG_AFTER:
5119 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source)
5120 return (!ctree->drag_compare ||
5121 ctree->drag_compare (ctree,
5123 GTK_CMCTREE_ROW (drag_target)->parent,
5124 GTK_CMCTREE_ROW (drag_target)->sibling));
5126 case GTK_CMCLIST_DRAG_BEFORE:
5127 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target)
5128 return (!ctree->drag_compare ||
5129 ctree->drag_compare (ctree,
5131 GTK_CMCTREE_ROW (drag_target)->parent,
5134 case GTK_CMCLIST_DRAG_INTO:
5135 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf &&
5136 GTK_CMCTREE_ROW (drag_target)->children != drag_source)
5137 return (!ctree->drag_compare ||
5138 ctree->drag_compare (ctree,
5141 GTK_CMCTREE_ROW (drag_target)->children));
5150 /************************************/
5152 drag_dest_info_destroy (gpointer data)
5154 GtkCMCListDestInfo *info = data;
5160 drag_dest_cell (GtkCMCList *clist,
5163 GtkCMCListDestInfo *dest_info)
5169 widget = GTK_WIDGET (clist);
5170 style = gtk_widget_get_style (widget);
5172 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5174 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5175 y -= (border_width +
5176 style->ythickness + clist->column_title_area.height);
5177 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5179 if (dest_info->cell.row >= clist->rows)
5181 dest_info->cell.row = clist->rows - 1;
5182 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5184 if (dest_info->cell.row < -1)
5185 dest_info->cell.row = -1;
5187 x -= border_width + style->xthickness;
5189 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5191 if (dest_info->cell.row >= 0)
5196 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5198 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) &&
5199 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list,
5200 dest_info->cell.row))->is_leaf)
5202 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
5203 h = clist->row_height / 4;
5205 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5207 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5208 h = clist->row_height / 2;
5211 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5214 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5215 else if (clist->row_height - y_delta < h)
5216 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
5222 gtk_cmctree_drag_begin (GtkWidget *widget,
5223 GdkDragContext *context)
5228 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5229 cm_return_if_fail (context != NULL);
5231 clist = GTK_CMCLIST (widget);
5233 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist);
5234 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5235 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
5239 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5240 gtk_drag_set_icon_default (context);
5245 gtk_cmctree_drag_motion (GtkWidget *widget,
5246 GdkDragContext *context,
5253 GtkCMCListDestInfo new_info;
5254 GtkCMCListDestInfo *dest_info;
5256 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
5258 clist = GTK_CMCLIST (widget);
5259 ctree = GTK_CMCTREE (widget);
5261 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
5265 dest_info = g_new (GtkCMCListDestInfo, 1);
5267 dest_info->cell.row = -1;
5268 dest_info->cell.column = -1;
5269 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5271 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
5272 drag_dest_info_destroy);
5275 drag_dest_cell (clist, x, y, &new_info);
5277 if (GTK_CMCLIST_REORDERABLE (clist))
5279 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5280 GdkAtom found = gtk_drag_dest_find_target(widget, context, NULL);
5284 GtkCMCTreeNode *drag_source;
5285 GtkCMCTreeNode *drag_target;
5287 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5288 clist->click_cell.row));
5289 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5290 new_info.cell.row));
5292 if (gtk_drag_get_source_widget (context) != widget ||
5293 !check_drag (ctree, drag_source, drag_target,
5294 new_info.insert_pos))
5296 if (dest_info->cell.row < 0)
5298 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
5304 if (new_info.cell.row != dest_info->cell.row ||
5305 (new_info.cell.row == dest_info->cell.row &&
5306 dest_info->insert_pos != new_info.insert_pos))
5308 dest_info->insert_pos = new_info.insert_pos;
5309 dest_info->cell.row = new_info.cell.row;
5310 dest_info->cell.column = new_info.cell.column;
5312 clist->drag_highlight_row = dest_info->cell.row;
5313 clist->drag_highlight_pos = dest_info->insert_pos;
5315 gdk_drag_status (context,
5316 gdk_drag_context_get_suggested_action(context), time);
5322 dest_info->insert_pos = new_info.insert_pos;
5323 dest_info->cell.row = new_info.cell.row;
5324 dest_info->cell.column = new_info.cell.column;
5329 gtk_cmctree_drag_data_received (GtkWidget *widget,
5330 GdkDragContext *context,
5333 GtkSelectionData *selection_data,
5340 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5341 cm_return_if_fail (context != NULL);
5342 cm_return_if_fail (selection_data != NULL);
5344 ctree = GTK_CMCTREE (widget);
5345 clist = GTK_CMCLIST (widget);
5347 if (GTK_CMCLIST_REORDERABLE (clist) &&
5348 gtk_drag_get_source_widget (context) == widget &&
5349 gtk_selection_data_get_target (selection_data) ==
5350 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
5351 gtk_selection_data_get_format (selection_data) == 8 &&
5352 gtk_selection_data_get_length (selection_data) == sizeof (GtkCMCListCellInfo))
5354 GtkCMCListCellInfo *source_info;
5356 source_info = (GtkCMCListCellInfo *)(gtk_selection_data_get_data (selection_data));
5359 GtkCMCListDestInfo dest_info;
5360 GtkCMCTreeNode *source_node;
5361 GtkCMCTreeNode *dest_node;
5363 drag_dest_cell (clist, x, y, &dest_info);
5365 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5367 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5368 dest_info.cell.row));
5370 if (!source_node || !dest_node)
5373 switch (dest_info.insert_pos)
5375 case GTK_CMCLIST_DRAG_NONE:
5377 case GTK_CMCLIST_DRAG_INTO:
5378 if (check_drag (ctree, source_node, dest_node,
5379 dest_info.insert_pos))
5380 gtk_cmctree_move (ctree, source_node, dest_node,
5381 GTK_CMCTREE_ROW (dest_node)->children);
5382 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5384 case GTK_CMCLIST_DRAG_BEFORE:
5385 if (check_drag (ctree, source_node, dest_node,
5386 dest_info.insert_pos))
5387 gtk_cmctree_move (ctree, source_node,
5388 GTK_CMCTREE_ROW (dest_node)->parent, dest_node);
5389 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5391 case GTK_CMCLIST_DRAG_AFTER:
5392 if (check_drag (ctree, source_node, dest_node,
5393 dest_info.insert_pos))
5394 gtk_cmctree_move (ctree, source_node,
5395 GTK_CMCTREE_ROW (dest_node)->parent,
5396 GTK_CMCTREE_ROW (dest_node)->sibling);
5397 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5405 gtk_cmctree_node_get_type (void)
5407 static GType our_type = 0;
5410 our_type = g_pointer_type_register_static ("GtkCMCTreeNode");