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(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)
628 GdkRectangle row_rectangle;
629 GdkRectangle cell_rectangle;
630 GdkRectangle clip_rectangle;
631 GdkRectangle intersect_rectangle;
633 gint column_left = 0;
634 gint column_right = 0;
638 static GdkColor greybg={0, 0, 0, 0};
639 static gboolean color_change = TRUE;
641 GdkColor *fgcolor, *bgcolor;
643 cm_return_if_fail (clist != NULL);
644 widget = GTK_WIDGET (clist);
645 style = gtk_widget_get_style (widget);
647 if (greybg.pixel == 0 &&
651 GdkColor normalbg = {0, 0xffff, 0xffff, 0xffff};
653 normalbg = style->base[GTK_STATE_NORMAL];
655 if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
656 greybg.pixel = normalbg.pixel;
657 greybg.red = normalbg.red - prefs_common.stripes_color_offset;
658 greybg.green = normalbg.green - prefs_common.stripes_color_offset;
659 greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
660 } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
661 greybg.pixel = normalbg.pixel;
662 greybg.red = normalbg.red + prefs_common.stripes_color_offset;
663 greybg.green = normalbg.green + prefs_common.stripes_color_offset;
664 greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
666 color_change = FALSE;
670 /* bail now if we arn't drawable yet */
671 if (!gtk_widget_is_drawable (GTK_WIDGET(clist)) || row < 0 || row >= clist->rows)
674 ctree = GTK_CMCTREE (clist);
676 /* if the function is passed the pointer to the row instead of null,
677 * it avoids this expensive lookup */
679 clist_row = (g_list_nth (clist->row_list, row))->data;
681 /* rectangle of the entire row */
683 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
684 row_rectangle.width = clist->clist_window_width;
685 row_rectangle.height = clist->row_height;
687 /* rectangle of the cell spacing above the row */
688 cell_rectangle.x = 0;
689 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
690 cell_rectangle.width = row_rectangle.width;
691 cell_rectangle.height = CELL_SPACING;
693 /* rectangle used to clip drawing operations, its y and height
694 * positions only need to be set once, so we set them once here.
695 * the x and width are set withing the drawing loop below once per
697 clip_rectangle.y = row_rectangle.y;
698 clip_rectangle.height = row_rectangle.height;
700 if (prefs_common.use_stripes_everywhere && GTK_SCTREE(ctree)->show_stripes
701 && color_change && row % 2) {
704 bgcolor = &style->base[GTK_STATE_NORMAL];
706 state = clist_row->state;
708 cr = gdk_cairo_create(clist->clist_window);
709 fgcolor = &style->fg[clist_row->state];
710 /* draw the cell borders */
713 rect = &intersect_rectangle;
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 rect = &clip_rectangle;
725 crect = &cell_rectangle;
727 gdk_cairo_rectangle(cr, &cell_rectangle);
728 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
732 /* the last row has to clear its bottom cell spacing too */
733 if (clist_row == clist->row_list_end->data)
735 cell_rectangle.y += clist->row_height + CELL_SPACING;
737 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
739 gdk_cairo_rectangle(cr, crect);
740 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
745 for (last_column = clist->columns - 1;
746 last_column >= 0 && !clist->column[last_column].visible; last_column--)
749 /* iterate and draw all the columns (row cells) and draw their contents */
750 for (i = 0; i < clist->columns; i++)
753 PangoLayout *layout = NULL;
754 PangoRectangle logical_rect;
762 if (!clist->column[i].visible)
765 get_cell_style (clist, clist_row, state, i, &style);
767 /* calculate clipping region */
768 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
769 clip_rectangle.width = clist->column[i].area.width;
771 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
772 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
773 (1 + (i == last_column)) * CELL_SPACING);
774 cell_rectangle.y = clip_rectangle.y;
775 cell_rectangle.height = clip_rectangle.height;
781 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
782 &intersect_rectangle))
784 if (i != ctree->tree_column)
789 gdk_cairo_rectangle(cr, &cell_rectangle);
790 if (state == GTK_STATE_NORMAL)
791 gdk_cairo_set_source_color(cr, bgcolor);
793 gdk_cairo_set_source_color(cr, &style->base[state]);
796 layout = create_cell_layout (clist, clist_row, i);
799 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
800 width = logical_rect.width;
805 switch (clist_row->cell[i].type)
807 case GTK_CMCELL_PIXBUF:
808 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
809 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
810 width += pixbuf_width;
812 case GTK_CMCELL_PIXTEXT:
813 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
815 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
816 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
817 width += pixbuf_width;
820 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text &&
821 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
822 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
824 if (i == ctree->tree_column)
825 width += (ctree->tree_indent *
826 ((GtkCMCTreeRow *)clist_row)->level);
832 switch (clist->column[i].justification)
834 case GTK_JUSTIFY_LEFT:
835 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
837 case GTK_JUSTIFY_RIGHT:
838 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
839 clip_rectangle.width - width);
841 case GTK_JUSTIFY_CENTER:
842 case GTK_JUSTIFY_FILL:
843 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
844 (clip_rectangle.width / 2) - (width / 2));
848 if (i != ctree->tree_column)
850 int start_y = (clip_rectangle.height - height) / 2;
851 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
852 start_y = (clip_rectangle.height/2 - height) / 2;
854 offset += clist_row->cell[i].horizontal;
855 switch (clist_row->cell[i].type)
857 case GTK_CMCELL_PIXBUF:
859 (clist->clist_window, &clip_rectangle, cr,
860 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf,
862 clip_rectangle.y + clist_row->cell[i].vertical +
864 pixbuf_width, height);
866 case GTK_CMCELL_PIXTEXT:
867 offset = draw_cell_pixbuf
868 (clist->clist_window, &clip_rectangle, cr,
869 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
871 clip_rectangle.y + clist_row->cell[i].vertical +
873 pixbuf_width, height);
874 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
877 case GTK_CMCELL_TEXT:
880 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
881 gdk_cairo_set_source_color(cr, fgcolor);
882 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
883 pango_cairo_show_layout(cr, layout);
884 g_object_unref (G_OBJECT (layout));
894 /* draw ctree->tree_column */
895 cell_rectangle.y -= CELL_SPACING;
896 cell_rectangle.height += CELL_SPACING;
898 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
899 &intersect_rectangle))
902 g_object_unref (G_OBJECT (layout));
908 offset = get_offset (ctree, (GtkCMCTreeRow *)clist_row, i,
912 offset = draw_expander (ctree, (GtkCMCTreeRow *)clist_row,
913 style, &clip_rectangle, cr, offset);
915 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
916 offset -= ctree->tree_spacing;
918 offset += ctree->tree_spacing;
920 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
921 offset -= (pixbuf_width + clist_row->cell[i].horizontal);
923 offset += clist_row->cell[i].horizontal;
926 offset = draw_cell_pixbuf (clist->clist_window, &clip_rectangle, cr,
927 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
929 clip_rectangle.y + clist_row->cell[i].vertical
930 + (clip_rectangle.height - height) / 2,
931 pixbuf_width, height);
935 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
937 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
939 offset = (old_offset - string_width);
940 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
941 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
945 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
946 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
949 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
950 gdk_cairo_set_source_color(cr, fgcolor);
951 pango_cairo_show_layout(cr, layout);
953 g_object_unref (G_OBJECT (layout));
956 /* draw focus rectangle */
957 if (clist->focus_row == row &&
958 gtk_widget_get_can_focus (widget) && gtk_widget_has_focus (widget))
960 if (!area || gdk_rectangle_intersect (area, &row_rectangle,
961 &intersect_rectangle))
963 cairo_set_line_width(cr, 1.0);
964 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
965 gdk_cairo_set_source_color(cr, &style->fg[GTK_STATE_NORMAL]);
966 cairo_rectangle(cr, row_rectangle.x, row_rectangle.y,
967 row_rectangle.width + 1,
968 row_rectangle.height);
976 gtk_cmctree_class_init (GtkCMCTreeClass *klass)
978 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
979 GtkObjectClass *object_class;
980 GtkWidgetClass *widget_class;
981 GtkCMCListClass *clist_class;
982 GtkBindingSet *binding_set;
984 gobject_class->constructor = gtk_cmctree_constructor;
986 object_class = (GtkObjectClass *) klass;
987 widget_class = (GtkWidgetClass *) klass;
988 container_class = (GtkContainerClass *) klass;
989 clist_class = (GtkCMCListClass *) klass;
991 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST);
992 container_class = g_type_class_peek (GTK_TYPE_CONTAINER);
994 gobject_class->set_property = gtk_cmctree_set_arg;
995 gobject_class->get_property = gtk_cmctree_get_arg;
997 widget_class->realize = gtk_cmctree_realize;
998 widget_class->unrealize = gtk_cmctree_unrealize;
999 widget_class->button_press_event = gtk_cmctree_button_press;
1001 widget_class->drag_begin = gtk_cmctree_drag_begin;
1002 widget_class->drag_motion = gtk_cmctree_drag_motion;
1003 widget_class->drag_data_received = gtk_cmctree_drag_data_received;
1005 clist_class->select_row = real_select_row;
1006 clist_class->unselect_row = real_unselect_row;
1007 clist_class->row_move = real_row_move;
1008 clist_class->undo_selection = real_undo_selection;
1009 clist_class->resync_selection = resync_selection;
1010 clist_class->selection_find = selection_find;
1011 clist_class->click_column = NULL;
1012 clist_class->draw_row = draw_row;
1013 clist_class->clear = real_clear;
1014 clist_class->select_all = real_select_all;
1015 clist_class->unselect_all = real_unselect_all;
1016 clist_class->fake_unselect_all = fake_unselect_all;
1017 clist_class->insert_row = real_insert_row;
1018 clist_class->remove_row = real_remove_row;
1019 clist_class->sort_list = real_sort_list;
1020 clist_class->set_cell_contents = set_cell_contents;
1021 clist_class->cell_size_request = cell_size_request;
1023 klass->tree_select_row = real_tree_select;
1024 klass->tree_unselect_row = real_tree_unselect;
1025 klass->tree_expand = real_tree_expand;
1026 klass->tree_collapse = real_tree_collapse;
1027 klass->tree_move = real_tree_move;
1028 klass->change_focus_row_expansion = change_focus_row_expansion;
1030 g_object_class_install_property (gobject_class,
1032 g_param_spec_uint ("n-columns",
1038 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1039 g_object_class_install_property (gobject_class,
1041 g_param_spec_uint ("tree-column",
1047 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1048 g_object_class_install_property (gobject_class,
1050 g_param_spec_uint ("indent",
1056 G_PARAM_READWRITE));
1057 g_object_class_install_property (gobject_class,
1059 g_param_spec_uint ("spacing",
1065 G_PARAM_READWRITE));
1066 g_object_class_install_property (gobject_class,
1068 g_param_spec_boolean ("show-stub",
1072 G_PARAM_READWRITE));
1073 g_object_class_install_property (gobject_class,
1075 g_param_spec_enum ("line-style",
1078 GTK_TYPE_CMCTREE_LINE_STYLE, 0,
1079 G_PARAM_READWRITE));
1080 g_object_class_install_property (gobject_class,
1082 g_param_spec_enum ("expander-style",
1085 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0,
1086 G_PARAM_READWRITE));
1088 ctree_signals[TREE_SELECT_ROW] =
1089 g_signal_new ("tree_select_row",
1090 G_TYPE_FROM_CLASS (object_class),
1092 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row),
1094 claws_marshal_VOID__POINTER_INT,
1096 GTK_TYPE_CMCTREE_NODE,
1098 ctree_signals[TREE_UNSELECT_ROW] =
1099 g_signal_new ("tree_unselect_row",
1100 G_TYPE_FROM_CLASS (object_class),
1102 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row),
1104 claws_marshal_VOID__POINTER_INT,
1106 GTK_TYPE_CMCTREE_NODE,
1108 ctree_signals[TREE_EXPAND] =
1109 g_signal_new ("tree_expand",
1110 G_TYPE_FROM_CLASS (object_class),
1112 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand),
1114 claws_marshal_VOID__POINTER,
1116 GTK_TYPE_CMCTREE_NODE);
1117 ctree_signals[TREE_COLLAPSE] =
1118 g_signal_new ("tree_collapse",
1119 G_TYPE_FROM_CLASS (object_class),
1121 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse),
1123 claws_marshal_VOID__POINTER,
1125 GTK_TYPE_CMCTREE_NODE);
1126 ctree_signals[TREE_MOVE] =
1127 g_signal_new ("tree_move",
1128 G_TYPE_FROM_CLASS (object_class),
1130 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move),
1132 claws_marshal_VOID__POINTER_POINTER_POINTER,
1134 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE);
1135 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
1136 g_signal_new ("change_focus_row_expansion",
1137 G_TYPE_FROM_CLASS (object_class),
1138 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1139 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion),
1141 claws_marshal_VOID__ENUM,
1142 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE);
1144 binding_set = gtk_binding_set_by_class (klass);
1145 gtk_binding_entry_add_signal (binding_set,
1147 "change_focus_row_expansion", 1,
1148 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1149 gtk_binding_entry_add_signal (binding_set,
1150 GDK_KEY_plus, GDK_CONTROL_MASK,
1151 "change_focus_row_expansion", 1,
1152 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1154 gtk_binding_entry_add_signal (binding_set,
1156 "change_focus_row_expansion", 1,
1157 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1158 gtk_binding_entry_add_signal (binding_set,
1159 GDK_KEY_KP_Add, GDK_CONTROL_MASK,
1160 "change_focus_row_expansion", 1,
1161 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1163 gtk_binding_entry_add_signal (binding_set,
1165 "change_focus_row_expansion", 1,
1166 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1167 gtk_binding_entry_add_signal (binding_set,
1168 GDK_KEY_minus, GDK_CONTROL_MASK,
1169 "change_focus_row_expansion", 1,
1171 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1172 gtk_binding_entry_add_signal (binding_set,
1173 GDK_KEY_KP_Subtract, 0,
1174 "change_focus_row_expansion", 1,
1175 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1176 gtk_binding_entry_add_signal (binding_set,
1177 GDK_KEY_KP_Subtract, GDK_CONTROL_MASK,
1178 "change_focus_row_expansion", 1,
1180 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1181 gtk_binding_entry_add_signal (binding_set,
1183 "change_focus_row_expansion", 1,
1184 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1185 gtk_binding_entry_add_signal (binding_set,
1186 GDK_KEY_KP_Equal, 0,
1187 "change_focus_row_expansion", 1,
1188 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1189 gtk_binding_entry_add_signal (binding_set,
1190 GDK_KEY_KP_Multiply, 0,
1191 "change_focus_row_expansion", 1,
1192 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1193 gtk_binding_entry_add_signal (binding_set,
1194 GDK_KEY_asterisk, 0,
1195 "change_focus_row_expansion", 1,
1196 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1197 gtk_binding_entry_add_signal (binding_set,
1198 GDK_KEY_KP_Multiply, GDK_CONTROL_MASK,
1199 "change_focus_row_expansion", 1,
1201 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1202 gtk_binding_entry_add_signal (binding_set,
1203 GDK_KEY_asterisk, GDK_CONTROL_MASK,
1204 "change_focus_row_expansion", 1,
1206 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1210 gtk_cmctree_set_arg (GObject *object,
1212 const GValue *value,
1218 ctree = GTK_CMCTREE (object);
1219 clist = GTK_CMCLIST (ctree);
1223 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
1224 #if !GLIB_CHECK_VERSION(2,10,0)
1225 cm_return_if_fail (clist->row_mem_chunk == NULL);
1227 clist->columns = MAX (1, g_value_get_uint (value));
1228 #if !GLIB_CHECK_VERSION(2,10,0)
1229 clist->row_mem_chunk = g_mem_chunk_new ("ctree row mem chunk",
1230 sizeof (GtkCMCTreeRow),
1231 sizeof (GtkCMCTreeRow)
1232 * CLIST_OPTIMUM_SIZE,
1234 clist->cell_mem_chunk = g_mem_chunk_new ("ctree cell mem chunk",
1235 sizeof (GtkCMCell) * clist->columns,
1236 sizeof (GtkCMCell) * clist->columns
1237 * CLIST_OPTIMUM_SIZE,
1240 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1242 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
1243 ctree->tree_column = g_value_get_uint (value);
1244 #if !GLIB_CHECK_VERSION(2,10,0)
1245 if (clist->row_mem_chunk)
1247 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1250 gtk_cmctree_set_indent (ctree, g_value_get_uint (value));
1253 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value));
1256 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value));
1258 case ARG_LINE_STYLE:
1259 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value));
1261 case ARG_EXPANDER_STYLE:
1262 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value));
1270 gtk_cmctree_get_arg (GObject *object,
1277 ctree = GTK_CMCTREE (object);
1282 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns);
1284 case ARG_TREE_COLUMN:
1285 g_value_set_uint(value, ctree->tree_column);
1288 g_value_set_uint(value, ctree->tree_indent);
1291 g_value_set_uint(value, ctree->tree_spacing);
1294 g_value_set_boolean(value, ctree->show_stub);
1296 case ARG_LINE_STYLE:
1297 g_value_set_enum(value, ctree->line_style);
1299 case ARG_EXPANDER_STYLE:
1300 g_value_set_enum(value, ctree->expander_style);
1303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1309 gtk_cmctree_init (GtkCMCTree *ctree)
1313 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT);
1314 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE);
1316 clist = GTK_CMCLIST (ctree);
1318 ctree->tree_indent = 20;
1319 ctree->tree_spacing = 5;
1320 ctree->tree_column = 0;
1321 ctree->line_style = GTK_CMCTREE_LINES_NONE;
1322 ctree->expander_style = GTK_CMCTREE_EXPANDER_TRIANGLE;
1323 ctree->drag_compare = NULL;
1324 ctree->show_stub = TRUE;
1326 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS;
1330 ctree_attach_styles (GtkCMCTree *ctree,
1331 GtkCMCTreeNode *node,
1337 clist = GTK_CMCLIST (ctree);
1339 if (GTK_CMCTREE_ROW (node)->row.style)
1340 GTK_CMCTREE_ROW (node)->row.style =
1341 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window);
1343 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set)
1345 GdkColormap *colormap;
1347 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
1348 if (GTK_CMCTREE_ROW (node)->row.fg_set)
1349 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE);
1350 if (GTK_CMCTREE_ROW (node)->row.bg_set)
1351 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE);
1354 for (i = 0; i < clist->columns; i++)
1355 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1356 GTK_CMCTREE_ROW (node)->row.cell[i].style =
1357 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style,
1358 clist->clist_window);
1362 ctree_detach_styles (GtkCMCTree *ctree,
1363 GtkCMCTreeNode *node,
1369 clist = GTK_CMCLIST (ctree);
1371 if (GTK_CMCTREE_ROW (node)->row.style)
1372 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
1373 for (i = 0; i < clist->columns; i++)
1374 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1375 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style);
1379 gtk_cmctree_realize (GtkWidget *widget)
1383 GtkCMCTreeNode *node;
1384 GtkCMCTreeNode *child;
1388 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1390 GTK_WIDGET_CLASS (parent_class)->realize (widget);
1392 ctree = GTK_CMCTREE (widget);
1393 clist = GTK_CMCLIST (widget);
1395 node = GTK_CMCTREE_NODE (clist->row_list);
1396 for (i = 0; i < clist->rows; i++)
1398 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded)
1399 for (child = GTK_CMCTREE_ROW (node)->children; child;
1400 child = GTK_CMCTREE_ROW (child)->sibling)
1401 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
1402 node = GTK_CMCTREE_NODE_NEXT (node);
1405 style = gtk_widget_get_style(widget);
1409 gtk_cmctree_unrealize (GtkWidget *widget)
1414 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1416 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1418 ctree = GTK_CMCTREE (widget);
1419 clist = GTK_CMCLIST (widget);
1421 if (gtk_widget_get_realized (widget))
1423 GtkCMCTreeNode *node;
1424 GtkCMCTreeNode *child;
1427 node = GTK_CMCTREE_NODE (clist->row_list);
1428 for (i = 0; i < clist->rows; i++)
1430 if (GTK_CMCTREE_ROW (node)->children &&
1431 !GTK_CMCTREE_ROW (node)->expanded)
1432 for (child = GTK_CMCTREE_ROW (node)->children; child;
1433 child = GTK_CMCTREE_ROW (child)->sibling)
1434 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
1435 node = GTK_CMCTREE_NODE_NEXT (node);
1441 gtk_cmctree_button_press (GtkWidget *widget,
1442 GdkEventButton *event)
1446 gint button_actions;
1448 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
1449 cm_return_val_if_fail (event != NULL, FALSE);
1451 ctree = GTK_CMCTREE (widget);
1452 clist = GTK_CMCLIST (widget);
1454 button_actions = clist->button_actions[event->button - 1];
1456 if (button_actions == GTK_CMBUTTON_IGNORED)
1459 if (event->window == clist->clist_window)
1461 GtkCMCTreeNode *work;
1470 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column))
1473 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
1475 if (button_actions & GTK_CMBUTTON_EXPANDS &&
1476 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf &&
1477 (event->type == GDK_2BUTTON_PRESS ||
1478 ctree_is_hot_spot (ctree, work, row, x, y))))
1480 if (GTK_CMCTREE_ROW (work)->expanded)
1481 gtk_cmctree_collapse (ctree, work);
1483 gtk_cmctree_expand (ctree, work);
1489 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
1493 gtk_cmctree_get_offset(GtkCMCTree *ctree,
1494 GtkCMCTreeRow *ctree_row,
1496 GdkRectangle *clip_rectangle)
1498 gint justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
1501 return (clip_rectangle->x + clip_rectangle->width - 1 -
1502 ctree->tree_indent * (ctree_row->level - 1));
1504 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
1507 static GtkCMCTreeNode *
1508 gtk_cmctree_last_visible (GtkCMCTree *ctree,
1509 GtkCMCTreeNode *node)
1511 GtkCMCTreeNode *work;
1516 work = GTK_CMCTREE_ROW (node)->children;
1518 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1521 while (GTK_CMCTREE_ROW (work)->sibling)
1522 work = GTK_CMCTREE_ROW (work)->sibling;
1524 return gtk_cmctree_last_visible (ctree, work);
1528 gtk_cmctree_link (GtkCMCTree *ctree,
1529 GtkCMCTreeNode *node,
1530 GtkCMCTreeNode *parent,
1531 GtkCMCTreeNode *sibling,
1532 gboolean update_focus_row)
1538 gboolean visible = FALSE;
1542 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1543 cm_return_if_fail (node != NULL);
1544 cm_return_if_fail (node != sibling);
1545 cm_return_if_fail (node != parent);
1547 clist = GTK_CMCLIST (ctree);
1549 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1551 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1553 g_list_free (clist->undo_selection);
1554 g_list_free (clist->undo_unselection);
1555 clist->undo_selection = NULL;
1556 clist->undo_unselection = NULL;
1559 for (rows = 1, list_end = (GList *)node; list_end->next;
1560 list_end = list_end->next)
1563 GTK_CMCTREE_ROW (node)->parent = parent;
1564 GTK_CMCTREE_ROW (node)->sibling = sibling;
1566 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1567 GTK_CMCTREE_ROW (parent)->expanded)))
1570 clist->rows += rows;
1574 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1576 work = clist->row_list;
1580 if (work != (GList *)sibling)
1582 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1583 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1584 GTK_CMCTREE_ROW (work)->sibling = node;
1587 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1588 clist->row_list = (GList *) node;
1589 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1590 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling)
1592 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1593 list->next = (GList *)node;
1596 list = (GList *)node;
1597 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1598 list_end->next = (GList *)sibling;
1599 list = (GList *)sibling;
1600 list->prev = list_end;
1601 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1602 GTK_CMCTREE_ROW (parent)->children = node;
1609 while (GTK_CMCTREE_ROW (work)->sibling)
1610 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1611 GTK_CMCTREE_ROW (work)->sibling = node;
1613 /* find last visible child of sibling */
1614 work = (GList *) gtk_cmctree_last_visible (ctree,
1615 GTK_CMCTREE_NODE (work));
1617 list_end->next = work->next;
1619 list = work->next->prev = list_end;
1620 work->next = (GList *)node;
1621 list = (GList *)node;
1628 GTK_CMCTREE_ROW (parent)->children = node;
1629 list = (GList *)node;
1630 list->prev = (GList *)parent;
1631 if (GTK_CMCTREE_ROW (parent)->expanded)
1633 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1634 if (GTK_CMCTREE_NODE_NEXT(parent))
1636 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1637 list->prev = list_end;
1639 list = (GList *)parent;
1640 list->next = (GList *)node;
1643 list_end->next = NULL;
1647 clist->row_list = (GList *)node;
1648 list = (GList *)node;
1650 list_end->next = NULL;
1655 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL);
1657 if (clist->row_list_end == NULL ||
1658 clist->row_list_end->next == (GList *)node)
1659 clist->row_list_end = list_end;
1661 if (visible && update_focus_row)
1665 pos = g_list_position (clist->row_list, (GList *)node);
1667 if (pos <= clist->focus_row)
1669 clist->focus_row += rows;
1670 clist->undo_anchor = clist->focus_row;
1676 gtk_cmctree_unlink (GtkCMCTree *ctree,
1677 GtkCMCTreeNode *node,
1678 gboolean update_focus_row)
1684 GtkCMCTreeNode *work;
1685 GtkCMCTreeNode *parent;
1688 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1689 cm_return_if_fail (node != NULL);
1691 clist = GTK_CMCLIST (ctree);
1693 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1695 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1697 g_list_free (clist->undo_selection);
1698 g_list_free (clist->undo_unselection);
1699 clist->undo_selection = NULL;
1700 clist->undo_unselection = NULL;
1703 visible = gtk_cmctree_is_viewable (ctree, node);
1705 /* clist->row_list_end unlinked ? */
1707 (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1708 (GTK_CMCTREE_ROW (node)->children &&
1709 gtk_cmctree_is_ancestor (ctree, node,
1710 GTK_CMCTREE_NODE (clist->row_list_end)))))
1711 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1715 level = GTK_CMCTREE_ROW (node)->level;
1716 work = GTK_CMCTREE_NODE_NEXT (node);
1717 while (work && GTK_CMCTREE_ROW (work)->level > level)
1719 work = GTK_CMCTREE_NODE_NEXT (work);
1725 clist->rows -= (rows + 1);
1727 if (update_focus_row)
1731 pos = g_list_position (clist->row_list, (GList *)node);
1732 if (pos + rows < clist->focus_row)
1733 clist->focus_row -= (rows + 1);
1734 else if (pos <= clist->focus_row)
1736 if (!GTK_CMCTREE_ROW (node)->sibling)
1737 clist->focus_row = MAX (pos - 1, 0);
1739 clist->focus_row = pos;
1741 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1743 clist->undo_anchor = clist->focus_row;
1749 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1751 list = (GList *)work;
1752 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1755 if (GTK_CMCTREE_NODE_PREV (node) &&
1756 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node)
1758 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1759 list->next = (GList *)work;
1763 parent = GTK_CMCTREE_ROW (node)->parent;
1766 if (GTK_CMCTREE_ROW (parent)->children == node)
1768 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1769 if (!GTK_CMCTREE_ROW (parent)->children)
1770 gtk_cmctree_collapse (ctree, parent);
1774 GtkCMCTreeNode *sibling;
1776 sibling = GTK_CMCTREE_ROW (parent)->children;
1777 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1778 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1779 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1784 if (clist->row_list == (GList *)node)
1785 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1788 GtkCMCTreeNode *sibling;
1790 sibling = GTK_CMCTREE_NODE (clist->row_list);
1791 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1792 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1793 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1799 real_row_move (GtkCMCList *clist,
1804 GtkCMCTreeNode *node;
1806 cm_return_if_fail (GTK_IS_CMCTREE (clist));
1808 if (GTK_CMCLIST_AUTO_SORT (clist))
1811 if (source_row < 0 || source_row >= clist->rows ||
1812 dest_row < 0 || dest_row >= clist->rows ||
1813 source_row == dest_row)
1816 ctree = GTK_CMCTREE (clist);
1817 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row));
1819 if (source_row < dest_row)
1821 GtkCMCTreeNode *work;
1824 work = GTK_CMCTREE_ROW (node)->children;
1826 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level)
1828 work = GTK_CMCTREE_NODE_NEXT (work);
1832 if (dest_row > clist->rows)
1833 dest_row = clist->rows;
1836 if (dest_row < clist->rows)
1838 GtkCMCTreeNode *sibling;
1840 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row));
1841 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling);
1844 gtk_cmctree_move (ctree, node, NULL, NULL);
1848 real_tree_move (GtkCMCTree *ctree,
1849 GtkCMCTreeNode *node,
1850 GtkCMCTreeNode *new_parent,
1851 GtkCMCTreeNode *new_sibling)
1854 GtkCMCTreeNode *work;
1855 gboolean visible = FALSE;
1857 cm_return_if_fail (ctree != NULL);
1858 cm_return_if_fail (node != NULL);
1859 cm_return_if_fail (!new_sibling ||
1860 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
1862 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1865 /* new_parent != child of child */
1866 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1870 clist = GTK_CMCLIST (ctree);
1872 visible = gtk_cmctree_is_viewable (ctree, node);
1874 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1876 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1878 g_list_free (clist->undo_selection);
1879 g_list_free (clist->undo_unselection);
1880 clist->undo_selection = NULL;
1881 clist->undo_unselection = NULL;
1884 if (GTK_CMCLIST_AUTO_SORT (clist))
1886 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
1890 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
1892 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
1894 while (new_sibling && clist->compare
1895 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
1896 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
1899 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
1900 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
1903 gtk_cmclist_freeze (clist);
1906 if (gtk_cmctree_is_viewable (ctree, node))
1907 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1909 gtk_cmctree_unlink (ctree, node, FALSE);
1910 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE);
1914 while (work && !gtk_cmctree_is_viewable (ctree, work))
1915 work = GTK_CMCTREE_ROW (work)->parent;
1916 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
1917 clist->undo_anchor = clist->focus_row;
1920 if (clist->column[ctree->tree_column].auto_resize &&
1921 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1922 (visible || gtk_cmctree_is_viewable (ctree, node)))
1923 gtk_cmclist_set_column_width
1924 (clist, ctree->tree_column,
1925 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
1927 gtk_cmclist_thaw (clist);
1931 change_focus_row_expansion (GtkCMCTree *ctree,
1932 GtkCMCTreeExpansionType action)
1935 GtkCMCTreeNode *node;
1937 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1939 clist = GTK_CMCLIST (ctree);
1941 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
1942 gtk_widget_has_grab (GTK_WIDGET(ctree)))
1946 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
1947 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
1952 case GTK_CMCTREE_EXPANSION_EXPAND:
1953 gtk_cmctree_expand (ctree, node);
1955 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
1956 gtk_cmctree_expand_recursive (ctree, node);
1958 case GTK_CMCTREE_EXPANSION_COLLAPSE:
1959 gtk_cmctree_collapse (ctree, node);
1961 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
1962 gtk_cmctree_collapse_recursive (ctree, node);
1964 case GTK_CMCTREE_EXPANSION_TOGGLE:
1965 gtk_cmctree_toggle_expansion (ctree, node);
1967 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
1968 gtk_cmctree_toggle_expansion_recursive (ctree, node);
1974 real_tree_expand (GtkCMCTree *ctree,
1975 GtkCMCTreeNode *node)
1978 GtkCMCTreeNode *work;
1979 GtkRequisition requisition;
1982 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1984 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1987 clist = GTK_CMCLIST (ctree);
1989 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1991 GTK_CMCTREE_ROW (node)->expanded = TRUE;
1993 visible = gtk_cmctree_is_viewable (ctree, node);
1994 /* get cell width if tree_column is auto resized */
1995 if (visible && clist->column[ctree->tree_column].auto_resize &&
1996 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1997 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1998 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2000 /* unref/unset closed pixbuf */
2001 if (GTK_CMCELL_PIXTEXT
2002 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2006 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2009 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2012 /* set/ref opened pixbuf */
2013 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2016 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2017 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2021 work = GTK_CMCTREE_ROW (node)->children;
2024 GList *list = (GList *)work;
2025 gint *cell_width = NULL;
2030 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2032 cell_width = g_new0 (gint, clist->columns);
2033 if (clist->column[ctree->tree_column].auto_resize)
2034 cell_width[ctree->tree_column] = requisition.width;
2038 /* search maximum cell widths of auto_resize columns */
2039 for (i = 0; i < clist->columns; i++)
2040 if (clist->column[i].auto_resize)
2042 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2043 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
2044 cell_width[i] = MAX (requisition.width, cell_width[i]);
2047 list = (GList *)work;
2048 work = GTK_CMCTREE_NODE_NEXT (work);
2055 list = (GList *)work;
2056 work = GTK_CMCTREE_NODE_NEXT (work);
2060 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2062 if (GTK_CMCTREE_NODE_NEXT (node))
2066 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2067 tmp_list->prev = list;
2070 clist->row_list_end = list;
2072 list = (GList *)node;
2073 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
2075 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2077 /* resize auto_resize columns if needed */
2078 for (i = 0; i < clist->columns; i++)
2079 if (clist->column[i].auto_resize &&
2080 cell_width[i] > clist->column[i].width)
2081 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
2082 g_free (cell_width);
2084 /* update focus_row position */
2085 row = g_list_position (clist->row_list, (GList *)node);
2086 if (row < clist->focus_row)
2087 clist->focus_row += tmp;
2090 CLIST_REFRESH (clist);
2093 else if (visible && clist->column[ctree->tree_column].auto_resize)
2094 /* resize tree_column if needed */
2095 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2100 real_tree_collapse (GtkCMCTree *ctree,
2101 GtkCMCTreeNode *node)
2104 GtkCMCTreeNode *work;
2105 GtkRequisition requisition;
2109 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2111 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
2112 GTK_CMCTREE_ROW (node)->is_leaf)
2115 clist = GTK_CMCLIST (ctree);
2117 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2119 GTK_CMCTREE_ROW (node)->expanded = FALSE;
2120 level = GTK_CMCTREE_ROW (node)->level;
2122 visible = gtk_cmctree_is_viewable (ctree, node);
2123 /* get cell width if tree_column is auto resized */
2124 if (visible && clist->column[ctree->tree_column].auto_resize &&
2125 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2126 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2127 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2129 /* unref/unset opened pixbuf */
2130 if (GTK_CMCELL_PIXTEXT
2131 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2135 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2138 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2141 /* set/ref closed pixbuf */
2142 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2145 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2146 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2149 work = GTK_CMCTREE_ROW (node)->children;
2156 while (work && GTK_CMCTREE_ROW (work)->level > level)
2158 work = GTK_CMCTREE_NODE_NEXT (work);
2164 list = (GList *)node;
2165 list->next = (GList *)work;
2166 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2168 list = (GList *)work;
2169 list->prev = (GList *)node;
2173 list = (GList *)node;
2175 clist->row_list_end = (GList *)node;
2180 /* resize auto_resize columns if needed */
2181 auto_resize_columns (clist);
2183 row = g_list_position (clist->row_list, (GList *)node);
2184 if (row < clist->focus_row)
2185 clist->focus_row -= tmp;
2187 CLIST_REFRESH (clist);
2190 else if (visible && clist->column[ctree->tree_column].auto_resize &&
2191 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2192 /* resize tree_column if needed */
2193 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2199 column_auto_resize (GtkCMCList *clist,
2200 GtkCMCListRow *clist_row,
2204 /* resize column if needed for auto_resize */
2205 GtkRequisition requisition;
2207 if (!clist->column[column].auto_resize ||
2208 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2212 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2213 column, &requisition);
2215 requisition.width = 0;
2217 if (requisition.width > clist->column[column].width)
2218 gtk_cmclist_set_column_width (clist, column, requisition.width);
2219 else if (requisition.width < old_width &&
2220 old_width == clist->column[column].width)
2225 /* run a "gtk_cmclist_optimal_column_width" but break, if
2226 * the column doesn't shrink */
2227 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
2230 gtk_widget_get_requisition (clist->column[column].button, &req);
2231 new_width = (req.width -
2232 (CELL_SPACING + (2 * COLUMN_INSET)));
2237 for (list = clist->row_list; list; list = list->next)
2239 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2240 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
2241 new_width = MAX (new_width, requisition.width);
2242 if (new_width == clist->column[column].width)
2245 if (new_width < clist->column[column].width)
2246 gtk_cmclist_set_column_width (clist, column, new_width);
2251 auto_resize_columns (GtkCMCList *clist)
2255 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2258 for (i = 0; i < clist->columns; i++)
2259 column_auto_resize (clist, NULL, i, clist->column[i].width);
2263 cell_size_request (GtkCMCList *clist,
2264 GtkCMCListRow *clist_row,
2266 GtkRequisition *requisition)
2271 PangoLayout *layout;
2272 PangoRectangle logical_rect;
2274 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2275 cm_return_if_fail (requisition != NULL);
2277 ctree = GTK_CMCTREE (clist);
2279 layout = create_cell_layout (clist, clist_row, column);
2282 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2284 requisition->width = logical_rect.width;
2285 requisition->height = logical_rect.height;
2287 g_object_unref (G_OBJECT (layout));
2291 requisition->width = 0;
2292 requisition->height = 0;
2295 switch (clist_row->cell[column].type)
2297 case GTK_CMCELL_PIXTEXT:
2298 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf)
2300 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2301 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2302 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2307 requisition->width += width;
2308 requisition->height = MAX (requisition->height, height);
2310 if (column == ctree->tree_column)
2312 requisition->width += (ctree->tree_spacing + ctree->tree_indent *
2313 (((GtkCMCTreeRow *) clist_row)->level - 1));
2314 switch (ctree->expander_style)
2316 case GTK_CMCTREE_EXPANDER_NONE:
2318 case GTK_CMCTREE_EXPANDER_TRIANGLE:
2319 requisition->width += PM_SIZE + 3;
2324 case GTK_CMCELL_PIXBUF:
2325 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2326 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2327 requisition->width += width;
2328 requisition->height = MAX (requisition->height, height);
2334 requisition->width += clist_row->cell[column].horizontal;
2335 requisition->height += clist_row->cell[column].vertical;
2339 set_cell_contents (GtkCMCList *clist,
2340 GtkCMCListRow *clist_row,
2347 gboolean visible = FALSE;
2349 GtkRequisition requisition;
2350 gchar *old_text = NULL;
2351 GdkPixbuf *old_pixbuf = NULL;
2353 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2354 cm_return_if_fail (clist_row != NULL);
2356 ctree = GTK_CMCTREE (clist);
2358 if (clist->column[column].auto_resize &&
2359 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2361 GtkCMCTreeNode *parent;
2363 parent = ((GtkCMCTreeRow *)clist_row)->parent;
2364 if ((parent && GTK_CMCTREE_ROW (parent)->expanded &&
2365 gtk_cmctree_is_viewable (ctree, parent)))
2368 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2369 column, &requisition);
2373 switch (clist_row->cell[column].type)
2375 case GTK_CMCELL_EMPTY:
2377 case GTK_CMCELL_TEXT:
2378 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2380 case GTK_CMCELL_PIXBUF:
2381 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2383 case GTK_CMCELL_PIXTEXT:
2384 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2385 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2387 case GTK_CMCELL_WIDGET:
2395 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2396 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY)
2397 type = GTK_CMCELL_PIXTEXT;
2399 /* Note that pixbuf and mask were already ref'ed by the caller
2403 case GTK_CMCELL_TEXT:
2406 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2407 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2410 case GTK_CMCELL_PIXBUF:
2413 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2414 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2417 case GTK_CMCELL_PIXTEXT:
2418 if (column == ctree->tree_column)
2420 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2421 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2423 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2425 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL;
2428 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2432 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = NULL;
2435 else if (text && pixbuf)
2437 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2438 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2439 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2440 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2447 if (visible && clist->column[column].auto_resize &&
2448 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2449 column_auto_resize (clist, clist_row, column, requisition.width);
2453 g_object_unref (old_pixbuf);
2457 set_node_info (GtkCMCTree *ctree,
2458 GtkCMCTreeNode *node,
2461 GdkPixbuf *pixbuf_closed,
2462 GdkPixbuf *pixbuf_opened,
2466 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2468 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2470 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2472 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2475 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
2476 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
2480 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
2484 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
2487 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
2488 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
2490 if (GTK_CMCTREE_ROW (node)->expanded)
2491 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2492 text, spacing, pixbuf_opened);
2494 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2495 text, spacing, pixbuf_closed);
2499 tree_delete (GtkCMCTree *ctree,
2500 GtkCMCTreeNode *node,
2503 tree_unselect (ctree, node, NULL);
2504 row_delete (ctree, GTK_CMCTREE_ROW (node));
2505 g_list_free_1 ((GList *)node);
2509 tree_delete_row (GtkCMCTree *ctree,
2510 GtkCMCTreeNode *node,
2513 row_delete (ctree, GTK_CMCTREE_ROW (node));
2514 g_list_free_1 ((GList *)node);
2518 tree_update_level (GtkCMCTree *ctree,
2519 GtkCMCTreeNode *node,
2525 if (GTK_CMCTREE_ROW (node)->parent)
2526 GTK_CMCTREE_ROW (node)->level =
2527 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
2529 GTK_CMCTREE_ROW (node)->level = 1;
2533 tree_select (GtkCMCTree *ctree,
2534 GtkCMCTreeNode *node,
2537 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
2538 GTK_CMCTREE_ROW (node)->row.selectable)
2539 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
2544 tree_unselect (GtkCMCTree *ctree,
2545 GtkCMCTreeNode *node,
2548 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
2549 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
2554 tree_expand (GtkCMCTree *ctree,
2555 GtkCMCTreeNode *node,
2558 if (node && !GTK_CMCTREE_ROW (node)->expanded)
2559 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2563 tree_collapse (GtkCMCTree *ctree,
2564 GtkCMCTreeNode *node,
2567 if (node && GTK_CMCTREE_ROW (node)->expanded)
2568 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2572 tree_collapse_to_depth (GtkCMCTree *ctree,
2573 GtkCMCTreeNode *node,
2576 if (node && GTK_CMCTREE_ROW (node)->level == depth)
2577 gtk_cmctree_collapse_recursive (ctree, node);
2581 tree_toggle_expansion (GtkCMCTree *ctree,
2582 GtkCMCTreeNode *node,
2588 if (GTK_CMCTREE_ROW (node)->expanded)
2589 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2591 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2594 static GtkCMCTreeRow *
2595 row_new (GtkCMCTree *ctree)
2598 GtkCMCTreeRow *ctree_row;
2601 clist = GTK_CMCLIST (ctree);
2602 #if GLIB_CHECK_VERSION(2,10,0)
2603 ctree_row = g_slice_new (GtkCMCTreeRow);
2604 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
2606 ctree_row = g_chunk_new (GtkCMCTreeRow, (GMemChunk *)clist->row_mem_chunk);
2607 ctree_row->row.cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk);
2610 for (i = 0; i < clist->columns; i++)
2612 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
2613 ctree_row->row.cell[i].vertical = 0;
2614 ctree_row->row.cell[i].horizontal = 0;
2615 ctree_row->row.cell[i].style = NULL;
2617 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
2619 ctree_row->row.fg_set = FALSE;
2620 ctree_row->row.bg_set = FALSE;
2621 ctree_row->row.style = NULL;
2622 ctree_row->row.selectable = TRUE;
2623 ctree_row->row.state = GTK_STATE_NORMAL;
2624 ctree_row->row.data = NULL;
2625 ctree_row->row.destroy = NULL;
2627 ctree_row->level = 0;
2628 ctree_row->expanded = FALSE;
2629 ctree_row->parent = NULL;
2630 ctree_row->sibling = NULL;
2631 ctree_row->children = NULL;
2632 ctree_row->pixbuf_closed = NULL;
2633 ctree_row->pixbuf_opened = NULL;
2639 row_delete (GtkCMCTree *ctree,
2640 GtkCMCTreeRow *ctree_row)
2645 clist = GTK_CMCLIST (ctree);
2647 for (i = 0; i < clist->columns; i++)
2649 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2650 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
2651 if (ctree_row->row.cell[i].style)
2653 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2654 gtk_style_detach (ctree_row->row.cell[i].style);
2655 g_object_unref (ctree_row->row.cell[i].style);
2659 if (ctree_row->row.style)
2661 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2662 gtk_style_detach (ctree_row->row.style);
2663 g_object_unref (ctree_row->row.style);
2666 if (ctree_row->pixbuf_closed)
2668 g_object_unref (ctree_row->pixbuf_closed);
2671 if (ctree_row->pixbuf_opened)
2673 g_object_unref (ctree_row->pixbuf_opened);
2676 if (ctree_row->row.destroy)
2678 GDestroyNotify dnotify = ctree_row->row.destroy;
2679 gpointer ddata = ctree_row->row.data;
2681 ctree_row->row.destroy = NULL;
2682 ctree_row->row.data = NULL;
2687 #if GLIB_CHECK_VERSION(2,10,0)
2688 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
2689 g_slice_free (GtkCMCTreeRow, ctree_row);
2691 g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
2692 g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
2697 real_select_row (GtkCMCList *clist,
2704 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2706 if ((node = g_list_nth (clist->row_list, row)) &&
2707 GTK_CMCTREE_ROW (node)->row.selectable)
2708 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0,
2713 real_unselect_row (GtkCMCList *clist,
2720 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2722 if ((node = g_list_nth (clist->row_list, row)))
2723 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0,
2728 tree_draw_node (GtkCMCTree *ctree,
2729 GtkCMCTreeNode *node)
2733 clist = GTK_CMCLIST (ctree);
2735 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node))
2737 GtkCMCTreeNode *work;
2740 work = GTK_CMCTREE_NODE (clist->row_list);
2741 while (work && work != node)
2743 work = GTK_CMCTREE_NODE_NEXT (work);
2746 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2747 GTK_CMCLIST_GET_CLASS(ctree)->draw_row
2748 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node));
2753 real_tree_select (GtkCMCTree *ctree,
2754 GtkCMCTreeNode *node,
2759 GtkCMCTreeNode *sel_row;
2760 gboolean node_selected;
2762 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2764 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2765 !GTK_CMCTREE_ROW (node)->row.selectable)
2768 clist = GTK_CMCLIST (ctree);
2770 switch (clist->selection_mode)
2772 case GTK_SELECTION_SINGLE:
2773 case GTK_SELECTION_BROWSE:
2775 node_selected = FALSE;
2776 list = clist->selection;
2780 sel_row = list->data;
2783 if (node == sel_row)
2784 node_selected = TRUE;
2786 g_signal_emit (G_OBJECT (ctree),
2787 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column);
2797 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
2799 if (!clist->selection)
2801 clist->selection = g_list_append (clist->selection, node);
2802 clist->selection_end = clist->selection;
2805 clist->selection_end = g_list_append (clist->selection_end, node)->next;
2807 tree_draw_node (ctree, node);
2811 real_tree_unselect (GtkCMCTree *ctree,
2812 GtkCMCTreeNode *node,
2817 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2819 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
2822 clist = GTK_CMCLIST (ctree);
2824 if (clist->selection_end && clist->selection_end->data == node)
2825 clist->selection_end = clist->selection_end->prev;
2827 clist->selection = g_list_remove (clist->selection, node);
2829 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
2831 tree_draw_node (ctree, node);
2835 select_row_recursive (GtkCMCTree *ctree,
2836 GtkCMCTreeNode *node,
2839 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2840 !GTK_CMCTREE_ROW (node)->row.selectable)
2843 GTK_CMCLIST (ctree)->undo_unselection =
2844 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node);
2845 gtk_cmctree_select (ctree, node);
2849 real_select_all (GtkCMCList *clist)
2852 GtkCMCTreeNode *node;
2854 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2856 ctree = GTK_CMCTREE (clist);
2858 switch (clist->selection_mode)
2860 case GTK_SELECTION_SINGLE:
2861 case GTK_SELECTION_BROWSE:
2864 case GTK_SELECTION_MULTIPLE:
2866 gtk_cmclist_freeze (clist);
2868 g_list_free (clist->undo_selection);
2869 g_list_free (clist->undo_unselection);
2870 clist->undo_selection = NULL;
2871 clist->undo_unselection = NULL;
2873 clist->anchor_state = GTK_STATE_SELECTED;
2875 clist->drag_pos = -1;
2876 clist->undo_anchor = clist->focus_row;
2878 for (node = GTK_CMCTREE_NODE (clist->row_list); node;
2879 node = GTK_CMCTREE_NODE_NEXT (node))
2880 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL);
2882 gtk_cmclist_thaw (clist);
2892 real_unselect_all (GtkCMCList *clist)
2895 GtkCMCTreeNode *node;
2898 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2900 ctree = GTK_CMCTREE (clist);
2902 switch (clist->selection_mode)
2904 case GTK_SELECTION_BROWSE:
2905 if (clist->focus_row >= 0)
2909 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
2914 case GTK_SELECTION_MULTIPLE:
2915 g_list_free (clist->undo_selection);
2916 g_list_free (clist->undo_unselection);
2917 clist->undo_selection = NULL;
2918 clist->undo_unselection = NULL;
2921 clist->drag_pos = -1;
2922 clist->undo_anchor = clist->focus_row;
2929 list = clist->selection;
2935 gtk_cmctree_unselect (ctree, node);
2940 ctree_is_hot_spot (GtkCMCTree *ctree,
2941 GtkCMCTreeNode *node,
2946 GtkCMCTreeRow *tree_row;
2951 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
2952 cm_return_val_if_fail (node != NULL, FALSE);
2954 clist = GTK_CMCLIST (ctree);
2956 if (!clist->column[ctree->tree_column].visible ||
2957 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
2960 tree_row = GTK_CMCTREE_ROW (node);
2962 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
2963 (clist->row_height - 1) % 2);
2965 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
2966 xl = (clist->column[ctree->tree_column].area.x +
2967 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
2968 (tree_row->level - 1) * ctree->tree_indent - PM_SIZE);
2970 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
2971 (tree_row->level - 1) * ctree->tree_indent);
2973 return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
2976 /***********************************************************
2977 ***********************************************************
2978 *** Public interface ***
2979 ***********************************************************
2980 ***********************************************************/
2983 /***********************************************************
2984 * Creation, insertion, deletion *
2985 ***********************************************************/
2988 gtk_cmctree_constructor (GType type,
2989 guint n_construct_properties,
2990 GObjectConstructParam *construct_properties)
2992 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
2993 n_construct_properties,
2994 construct_properties);
3000 gtk_cmctree_new_with_titles (gint columns,
3006 cm_return_val_if_fail (columns > 0, NULL);
3007 cm_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3009 widget = gtk_widget_new (GTK_TYPE_CMCTREE,
3010 "n_columns", columns,
3011 "tree_column", tree_column,
3015 GtkCMCList *clist = GTK_CMCLIST (widget);
3018 for (i = 0; i < columns; i++)
3019 gtk_cmclist_set_column_title (clist, i, titles[i]);
3020 gtk_cmclist_column_titles_show (clist);
3027 gtk_cmctree_new (gint columns,
3030 return gtk_cmctree_new_with_titles (columns, tree_column, NULL);
3034 real_insert_row (GtkCMCList *clist,
3038 GtkCMCTreeNode *parent = NULL;
3039 GtkCMCTreeNode *sibling;
3040 GtkCMCTreeNode *node;
3042 cm_return_val_if_fail (GTK_IS_CMCTREE (clist), -1);
3044 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3046 parent = GTK_CMCTREE_ROW (sibling)->parent;
3048 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5,
3049 NULL, NULL, TRUE, FALSE);
3051 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling)
3052 return g_list_position (clist->row_list, (GList *) node);
3058 gtk_cmctree_insert_node (GtkCMCTree *ctree,
3059 GtkCMCTreeNode *parent,
3060 GtkCMCTreeNode *sibling,
3063 GdkPixbuf *pixbuf_closed,
3064 GdkPixbuf *pixbuf_opened,
3069 GtkCMCTreeRow *new_row;
3070 GtkCMCTreeNode *node;
3074 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3076 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3078 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
3081 clist = GTK_CMCLIST (ctree);
3083 /* create the row */
3084 new_row = row_new (ctree);
3085 list = g_list_alloc ();
3086 list->data = new_row;
3087 node = GTK_CMCTREE_NODE (list);
3090 for (i = 0; i < clist->columns; i++)
3091 if (text[i] && i != ctree->tree_column)
3092 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3093 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
3095 set_node_info (ctree, node, text ?
3096 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
3097 pixbuf_opened, is_leaf, expanded);
3099 /* sorted insertion */
3100 if (GTK_CMCLIST_AUTO_SORT (clist))
3103 sibling = GTK_CMCTREE_ROW (parent)->children;
3105 sibling = GTK_CMCTREE_NODE (clist->row_list);
3107 while (sibling && clist->compare
3108 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
3109 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3112 gtk_cmctree_link (ctree, node, parent, sibling, TRUE);
3114 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
3115 gtk_cmctree_is_viewable (ctree, node))
3117 for (i = 0; i < clist->columns; i++)
3118 if (clist->column[i].auto_resize)
3119 column_auto_resize (clist, &(new_row->row), i, 0);
3122 if (clist->rows == 1)
3124 clist->focus_row = 0;
3125 if (clist->selection_mode == GTK_SELECTION_BROWSE)
3126 gtk_cmctree_select (ctree, node);
3130 CLIST_REFRESH (clist);
3136 gtk_cmctree_insert_gnode (GtkCMCTree *ctree,
3137 GtkCMCTreeNode *parent,
3138 GtkCMCTreeNode *sibling,
3140 GtkCMCTreeGNodeFunc func,
3144 GtkCMCTreeNode *cnode = NULL;
3145 GtkCMCTreeNode *child = NULL;
3146 GtkCMCTreeNode *new_child;
3151 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3152 cm_return_val_if_fail (gnode != NULL, NULL);
3153 cm_return_val_if_fail (func != NULL, NULL);
3155 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3157 clist = GTK_CMCLIST (ctree);
3160 depth = GTK_CMCTREE_ROW (parent)->level + 1;
3162 list = g_list_alloc ();
3163 list->data = row_new (ctree);
3164 cnode = GTK_CMCTREE_NODE (list);
3166 gtk_cmclist_freeze (clist);
3168 set_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
3170 if (!func (ctree, depth, gnode, cnode, data))
3172 tree_delete_row (ctree, cnode, NULL);
3173 gtk_cmclist_thaw (clist);
3177 if (GTK_CMCLIST_AUTO_SORT (clist))
3180 sibling = GTK_CMCTREE_ROW (parent)->children;
3182 sibling = GTK_CMCTREE_NODE (clist->row_list);
3184 while (sibling && clist->compare
3185 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
3186 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3189 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE);
3191 for (work = g_node_last_child (gnode); work; work = work->prev)
3193 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child,
3199 gtk_cmclist_thaw (clist);
3205 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree,
3208 GtkCMCTreeNode *node,
3209 GtkCMCTreeGNodeFunc func,
3212 GtkCMCTreeNode *work;
3216 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3217 cm_return_val_if_fail (node != NULL, NULL);
3218 cm_return_val_if_fail (func != NULL, NULL);
3221 cm_return_val_if_fail (parent != NULL, NULL);
3222 cm_return_val_if_fail (sibling->parent == parent, NULL);
3225 gnode = g_node_new (NULL);
3226 depth = g_node_depth (parent) + 1;
3228 if (!func (ctree, depth, gnode, node, data))
3230 g_node_destroy (gnode);
3235 g_node_insert_before (parent, sibling, gnode);
3237 if (!GTK_CMCTREE_ROW (node)->is_leaf)
3239 GNode *new_sibling = NULL;
3241 for (work = GTK_CMCTREE_ROW (node)->children; work;
3242 work = GTK_CMCTREE_ROW (work)->sibling)
3243 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling,
3246 g_node_reverse_children (gnode);
3253 real_remove_row (GtkCMCList *clist,
3256 GtkCMCTreeNode *node;
3258 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3260 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3263 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node);
3267 gtk_cmctree_remove_node (GtkCMCTree *ctree,
3268 GtkCMCTreeNode *node)
3272 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3274 clist = GTK_CMCLIST (ctree);
3276 gtk_cmclist_freeze (clist);
3280 gtk_cmctree_unlink (ctree, node, TRUE);
3281 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete),
3283 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3284 clist->focus_row >= 0)
3285 gtk_cmclist_select_row (clist, clist->focus_row, -1);
3287 auto_resize_columns (clist);
3290 gtk_cmclist_clear (clist);
3292 gtk_cmclist_thaw (clist);
3296 real_clear (GtkCMCList *clist)
3299 GtkCMCTreeNode *work;
3300 GtkCMCTreeNode *ptr;
3302 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3304 ctree = GTK_CMCTREE (clist);
3306 /* remove all rows */
3307 work = GTK_CMCTREE_NODE (clist->row_list);
3308 clist->row_list = NULL;
3309 clist->row_list_end = NULL;
3311 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3315 work = GTK_CMCTREE_ROW (work)->sibling;
3316 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row),
3319 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3321 parent_class->clear (clist);
3325 /***********************************************************
3326 * Generic recursive functions, querying / finding tree *
3328 ***********************************************************/
3332 gtk_cmctree_post_recursive (GtkCMCTree *ctree,
3333 GtkCMCTreeNode *node,
3334 GtkCMCTreeFunc func,
3337 GtkCMCTreeNode *work;
3338 GtkCMCTreeNode *tmp;
3340 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3341 cm_return_if_fail (func != NULL);
3344 work = GTK_CMCTREE_ROW (node)->children;
3346 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3350 tmp = GTK_CMCTREE_ROW (work)->sibling;
3351 gtk_cmctree_post_recursive (ctree, work, func, data);
3356 func (ctree, node, data);
3360 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree,
3361 GtkCMCTreeNode *node,
3363 GtkCMCTreeFunc func,
3366 GtkCMCTreeNode *work;
3367 GtkCMCTreeNode *tmp;
3369 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3370 cm_return_if_fail (func != NULL);
3374 gtk_cmctree_post_recursive (ctree, node, func, data);
3379 work = GTK_CMCTREE_ROW (node)->children;
3381 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3383 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3387 tmp = GTK_CMCTREE_ROW (work)->sibling;
3388 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data);
3393 if (node && GTK_CMCTREE_ROW (node)->level <= depth)
3394 func (ctree, node, data);
3398 gtk_cmctree_pre_recursive (GtkCMCTree *ctree,
3399 GtkCMCTreeNode *node,
3400 GtkCMCTreeFunc func,
3403 GtkCMCTreeNode *work;
3404 GtkCMCTreeNode *tmp;
3406 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3407 cm_return_if_fail (func != NULL);
3411 work = GTK_CMCTREE_ROW (node)->children;
3412 func (ctree, node, data);
3415 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3419 tmp = GTK_CMCTREE_ROW (work)->sibling;
3420 gtk_cmctree_pre_recursive (ctree, work, func, data);
3426 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree,
3427 GtkCMCTreeNode *node,
3429 GtkCMCTreeFunc func,
3432 GtkCMCTreeNode *work;
3433 GtkCMCTreeNode *tmp;
3435 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3436 cm_return_if_fail (func != NULL);
3440 gtk_cmctree_pre_recursive (ctree, node, func, data);
3446 work = GTK_CMCTREE_ROW (node)->children;
3447 if (GTK_CMCTREE_ROW (node)->level <= depth)
3448 func (ctree, node, data);
3451 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3453 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3457 tmp = GTK_CMCTREE_ROW (work)->sibling;
3458 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data);
3465 gtk_cmctree_is_viewable (GtkCMCTree *ctree,
3466 GtkCMCTreeNode *node)
3468 GtkCMCTreeRow *work;
3470 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3471 cm_return_val_if_fail (node != NULL, FALSE);
3473 work = GTK_CMCTREE_ROW (node);
3475 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded)
3476 work = GTK_CMCTREE_ROW (work->parent);
3485 gtk_cmctree_last (GtkCMCTree *ctree,
3486 GtkCMCTreeNode *node)
3488 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3493 while (GTK_CMCTREE_ROW (node)->sibling)
3494 node = GTK_CMCTREE_ROW (node)->sibling;
3496 if (GTK_CMCTREE_ROW (node)->children)
3497 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children);
3503 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree,
3504 GtkCMCTreeRow *ctree_row)
3506 GtkCMCTreeNode *node;
3508 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3509 cm_return_val_if_fail (ctree_row != NULL, NULL);
3511 if (ctree_row->parent)
3512 node = GTK_CMCTREE_ROW (ctree_row->parent)->children;
3514 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3516 while (GTK_CMCTREE_ROW (node) != ctree_row)
3517 node = GTK_CMCTREE_ROW (node)->sibling;
3523 gtk_cmctree_node_nth (GtkCMCTree *ctree,
3526 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3528 if ((row >= GTK_CMCLIST(ctree)->rows))
3531 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row));
3535 gtk_cmctree_find (GtkCMCTree *ctree,
3536 GtkCMCTreeNode *node,
3537 GtkCMCTreeNode *child)
3543 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3549 if (GTK_CMCTREE_ROW (node)->children)
3551 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child))
3554 node = GTK_CMCTREE_ROW (node)->sibling;
3560 gtk_cmctree_is_ancestor (GtkCMCTree *ctree,
3561 GtkCMCTreeNode *node,
3562 GtkCMCTreeNode *child)
3564 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3565 cm_return_val_if_fail (node != NULL, FALSE);
3567 if (GTK_CMCTREE_ROW (node)->children)
3568 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child);
3574 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree,
3575 GtkCMCTreeNode *node,
3578 GtkCMCTreeNode *work;
3581 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3585 if (GTK_CMCTREE_ROW (node)->row.data == data)
3587 if (GTK_CMCTREE_ROW (node)->children &&
3588 (work = gtk_cmctree_find_by_row_data
3589 (ctree, GTK_CMCTREE_ROW (node)->children, data)))
3591 node = GTK_CMCTREE_ROW (node)->sibling;
3597 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree,
3598 GtkCMCTreeNode *node,
3603 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3605 /* if node == NULL then look in the whole tree */
3607 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3611 if (GTK_CMCTREE_ROW (node)->row.data == data)
3612 list = g_list_append (list, node);
3614 if (GTK_CMCTREE_ROW (node)->children)
3618 sub_list = gtk_cmctree_find_all_by_row_data (ctree,
3622 list = g_list_concat (list, sub_list);
3624 node = GTK_CMCTREE_ROW (node)->sibling;
3630 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree,
3631 GtkCMCTreeNode *node,
3635 GtkCMCTreeNode *work;
3637 cm_return_val_if_fail (func != NULL, NULL);
3640 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3644 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3646 if (GTK_CMCTREE_ROW (node)->children &&
3647 (work = gtk_cmctree_find_by_row_data_custom
3648 (ctree, GTK_CMCTREE_ROW (node)->children, data, func)))
3650 node = GTK_CMCTREE_ROW (node)->sibling;
3656 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree,
3657 GtkCMCTreeNode *node,
3663 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3664 cm_return_val_if_fail (func != NULL, NULL);
3666 /* if node == NULL then look in the whole tree */
3668 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3672 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3673 list = g_list_append (list, node);
3675 if (GTK_CMCTREE_ROW (node)->children)
3679 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree,
3684 list = g_list_concat (list, sub_list);
3686 node = GTK_CMCTREE_ROW (node)->sibling;
3692 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree,
3696 GtkCMCTreeNode *node;
3700 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3702 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
3703 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
3704 return ctree_is_hot_spot (ctree, node, row, x, y);
3710 /***********************************************************
3711 * Tree signals : move, expand, collapse, (un)select *
3712 ***********************************************************/
3716 gtk_cmctree_move (GtkCMCTree *ctree,
3717 GtkCMCTreeNode *node,
3718 GtkCMCTreeNode *new_parent,
3719 GtkCMCTreeNode *new_sibling)
3721 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3722 cm_return_if_fail (node != NULL);
3724 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node,
3725 new_parent, new_sibling);
3729 gtk_cmctree_expand (GtkCMCTree *ctree,
3730 GtkCMCTreeNode *node)
3732 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3733 cm_return_if_fail (node != NULL);
3735 if (GTK_CMCTREE_ROW (node)->is_leaf)
3738 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node);
3742 gtk_cmctree_expand_recursive (GtkCMCTree *ctree,
3743 GtkCMCTreeNode *node)
3746 gboolean thaw = FALSE;
3748 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3750 clist = GTK_CMCLIST (ctree);
3752 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3755 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3757 gtk_cmclist_freeze (clist);
3761 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL);
3764 gtk_cmclist_thaw (clist);
3768 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree,
3769 GtkCMCTreeNode *node,
3773 gboolean thaw = FALSE;
3775 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3777 clist = GTK_CMCLIST (ctree);
3779 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3782 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3784 gtk_cmclist_freeze (clist);
3788 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3789 GTK_CMCTREE_FUNC (tree_expand), NULL);
3792 gtk_cmclist_thaw (clist);
3796 gtk_cmctree_collapse (GtkCMCTree *ctree,
3797 GtkCMCTreeNode *node)
3799 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3800 cm_return_if_fail (node != NULL);
3802 if (GTK_CMCTREE_ROW (node)->is_leaf)
3805 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node);
3809 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree,
3810 GtkCMCTreeNode *node)
3813 gboolean thaw = FALSE;
3816 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3818 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3821 clist = GTK_CMCLIST (ctree);
3823 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3825 gtk_cmclist_freeze (clist);
3829 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3830 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL);
3831 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3832 for (i = 0; i < clist->columns; i++)
3833 if (clist->column[i].auto_resize)
3834 gtk_cmclist_set_column_width (clist, i,
3835 gtk_cmclist_optimal_column_width (clist, i));
3838 gtk_cmclist_thaw (clist);
3842 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree,
3843 GtkCMCTreeNode *node,
3847 gboolean thaw = FALSE;
3850 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3852 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3855 clist = GTK_CMCLIST (ctree);
3857 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3859 gtk_cmclist_freeze (clist);
3863 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3864 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3865 GTK_CMCTREE_FUNC (tree_collapse_to_depth),
3866 GINT_TO_POINTER (depth));
3867 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3868 for (i = 0; i < clist->columns; i++)
3869 if (clist->column[i].auto_resize)
3870 gtk_cmclist_set_column_width (clist, i,
3871 gtk_cmclist_optimal_column_width (clist, i));
3874 gtk_cmclist_thaw (clist);
3878 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree,
3879 GtkCMCTreeNode *node)
3881 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3882 cm_return_if_fail (node != NULL);
3884 if (GTK_CMCTREE_ROW (node)->is_leaf)
3887 tree_toggle_expansion (ctree, node, NULL);
3891 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree,
3892 GtkCMCTreeNode *node)
3895 gboolean thaw = FALSE;
3897 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3899 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3902 clist = GTK_CMCLIST (ctree);
3904 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3906 gtk_cmclist_freeze (clist);
3910 gtk_cmctree_post_recursive (ctree, node,
3911 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL);
3914 gtk_cmclist_thaw (clist);
3918 gtk_cmctree_select (GtkCMCTree *ctree,
3919 GtkCMCTreeNode *node)
3921 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3922 cm_return_if_fail (node != NULL);
3924 if (GTK_CMCTREE_ROW (node)->row.selectable)
3925 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
3930 gtk_cmctree_unselect (GtkCMCTree *ctree,
3931 GtkCMCTreeNode *node)
3933 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3934 cm_return_if_fail (node != NULL);
3936 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
3941 gtk_cmctree_select_recursive (GtkCMCTree *ctree,
3942 GtkCMCTreeNode *node)
3944 gtk_cmctree_real_select_recursive (ctree, node, TRUE);
3948 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree,
3949 GtkCMCTreeNode *node)
3951 gtk_cmctree_real_select_recursive (ctree, node, FALSE);
3955 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree,
3956 GtkCMCTreeNode *node,
3960 gboolean thaw = FALSE;
3962 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3964 clist = GTK_CMCLIST (ctree);
3967 (clist->selection_mode == GTK_SELECTION_BROWSE ||
3968 clist->selection_mode == GTK_SELECTION_SINGLE)) ||
3969 (!state && clist->selection_mode == GTK_SELECTION_BROWSE))
3972 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3974 gtk_cmclist_freeze (clist);
3978 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
3980 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
3982 g_list_free (clist->undo_selection);
3983 g_list_free (clist->undo_unselection);
3984 clist->undo_selection = NULL;
3985 clist->undo_unselection = NULL;
3989 gtk_cmctree_post_recursive (ctree, node,
3990 GTK_CMCTREE_FUNC (tree_select), NULL);
3992 gtk_cmctree_post_recursive (ctree, node,
3993 GTK_CMCTREE_FUNC (tree_unselect), NULL);
3996 gtk_cmclist_thaw (clist);
4000 /***********************************************************
4001 * Analogons of GtkCMCList functions *
4002 ***********************************************************/
4006 gtk_cmctree_node_set_text (GtkCMCTree *ctree,
4007 GtkCMCTreeNode *node,
4013 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4014 cm_return_if_fail (node != NULL);
4016 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4019 clist = GTK_CMCLIST (ctree);
4021 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4022 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT,
4025 tree_draw_node (ctree, node);
4029 gtk_cmctree_node_set_pixbuf (GtkCMCTree *ctree,
4030 GtkCMCTreeNode *node,
4036 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4037 cm_return_if_fail (node != NULL);
4038 cm_return_if_fail (pixbuf != NULL);
4040 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4043 g_object_ref (pixbuf);
4045 clist = GTK_CMCLIST (ctree);
4047 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4048 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXBUF,
4051 tree_draw_node (ctree, node);
4055 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree,
4056 GtkCMCTreeNode *node,
4064 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4065 cm_return_if_fail (node != NULL);
4066 if (column != ctree->tree_column)
4067 cm_return_if_fail (pixbuf != NULL);
4068 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4071 clist = GTK_CMCLIST (ctree);
4075 g_object_ref (pixbuf);
4078 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4079 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT,
4080 text, spacing, pixbuf);
4082 tree_draw_node (ctree, node);
4086 gtk_cmctree_set_node_info (GtkCMCTree *ctree,
4087 GtkCMCTreeNode *node,
4090 GdkPixbuf *pixbuf_closed,
4091 GdkPixbuf *pixbuf_opened,
4096 gboolean old_expanded;
4098 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4099 cm_return_if_fail (node != NULL);
4101 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4102 old_expanded = GTK_CMCTREE_ROW (node)->expanded;
4104 if (is_leaf && GTK_CMCTREE_ROW (node)->children)
4106 GtkCMCTreeNode *work;
4107 GtkCMCTreeNode *ptr;
4109 work = GTK_CMCTREE_ROW (node)->children;
4113 work = GTK_CMCTREE_ROW (work)->sibling;
4114 gtk_cmctree_remove_node (ctree, ptr);
4118 set_node_info (ctree, node, text, spacing, pixbuf_closed,
4119 pixbuf_opened, is_leaf, expanded);
4121 if (!is_leaf && !old_leaf)
4123 GTK_CMCTREE_ROW (node)->expanded = old_expanded;
4124 if (expanded && !old_expanded)
4125 gtk_cmctree_expand (ctree, node);
4126 else if (!expanded && old_expanded)
4127 gtk_cmctree_collapse (ctree, node);
4130 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4132 tree_draw_node (ctree, node);
4136 gtk_cmctree_node_set_shift (GtkCMCTree *ctree,
4137 GtkCMCTreeNode *node,
4143 GtkRequisition requisition;
4144 gboolean visible = FALSE;
4146 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4147 cm_return_if_fail (node != NULL);
4149 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4152 clist = GTK_CMCLIST (ctree);
4154 if (clist->column[column].auto_resize &&
4155 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4157 visible = gtk_cmctree_is_viewable (ctree, node);
4159 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4160 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4163 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical;
4164 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4167 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row,
4168 column, requisition.width);
4170 tree_draw_node (ctree, node);
4174 remove_grab (GtkCMCList *clist)
4176 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4177 gtk_widget_has_grab (GTK_WIDGET(clist)))
4179 gtk_grab_remove (GTK_WIDGET (clist));
4180 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4186 g_source_remove (clist->htimer);
4192 g_source_remove (clist->vtimer);
4198 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree,
4199 GtkCMCTreeNode *node,
4200 gboolean selectable)
4202 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4203 cm_return_if_fail (node != NULL);
4205 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable)
4208 GTK_CMCTREE_ROW (node)->row.selectable = selectable;
4210 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4214 clist = GTK_CMCLIST (ctree);
4216 if (clist->anchor >= 0 &&
4217 clist->selection_mode == GTK_SELECTION_MULTIPLE)
4219 clist->drag_button = 0;
4220 remove_grab (clist);
4222 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4224 gtk_cmctree_unselect (ctree, node);
4229 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree,
4230 GtkCMCTreeNode *node)
4232 cm_return_val_if_fail (node != NULL, FALSE);
4234 return GTK_CMCTREE_ROW (node)->row.selectable;
4238 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree,
4239 GtkCMCTreeNode *node,
4242 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1);
4243 cm_return_val_if_fail (node != NULL, -1);
4245 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4248 return GTK_CMCTREE_ROW (node)->row.cell[column].type;
4252 gtk_cmctree_node_get_text (GtkCMCTree *ctree,
4253 GtkCMCTreeNode *node,
4257 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4258 cm_return_val_if_fail (node != NULL, FALSE);
4260 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4263 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT)
4267 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4273 gtk_cmctree_node_get_pixbuf (GtkCMCTree *ctree,
4274 GtkCMCTreeNode *node,
4278 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4279 cm_return_val_if_fail (node != NULL, FALSE);
4281 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4284 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXBUF)
4288 *pixbuf = GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node)->row.cell[column])->pixbuf;
4294 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree,
4295 GtkCMCTreeNode *node,
4301 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4302 cm_return_val_if_fail (node != NULL, FALSE);
4304 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4307 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT)
4311 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4313 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4314 (node)->row.cell[column])->spacing;
4316 *pixbuf = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4317 (node)->row.cell[column])->pixbuf;
4323 gtk_cmctree_get_node_info (GtkCMCTree *ctree,
4324 GtkCMCTreeNode *node,
4327 GdkPixbuf **pixbuf_closed,
4328 GdkPixbuf **pixbuf_opened,
4332 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4333 cm_return_val_if_fail (node != NULL, FALSE);
4336 *text = GTK_CMCELL_PIXTEXT
4337 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4339 *spacing = GTK_CMCELL_PIXTEXT
4340 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4342 *pixbuf_closed = GTK_CMCTREE_ROW (node)->pixbuf_closed;
4344 *pixbuf_opened = GTK_CMCTREE_ROW (node)->pixbuf_opened;
4346 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4348 *expanded = GTK_CMCTREE_ROW (node)->expanded;
4354 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree,
4355 GtkCMCTreeNode *node,
4360 GtkRequisition requisition;
4361 gboolean visible = FALSE;
4363 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4364 cm_return_if_fail (node != NULL);
4366 clist = GTK_CMCLIST (ctree);
4368 if (column < 0 || column >= clist->columns)
4371 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style)
4374 if (clist->column[column].auto_resize &&
4375 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4377 visible = gtk_cmctree_is_viewable (ctree, node);
4379 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4380 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4383 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4385 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4386 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4387 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4390 GTK_CMCTREE_ROW (node)->row.cell[column].style = style;
4392 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4394 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4396 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4397 GTK_CMCTREE_ROW (node)->row.cell[column].style =
4398 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style,
4399 clist->clist_window);
4403 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column,
4406 tree_draw_node (ctree, node);
4410 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree,
4411 GtkCMCTreeNode *node,
4414 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4415 cm_return_val_if_fail (node != NULL, NULL);
4417 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4420 return GTK_CMCTREE_ROW (node)->row.cell[column].style;
4424 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree,
4425 GtkCMCTreeNode *node,
4429 GtkRequisition requisition;
4431 gint *old_width = NULL;
4434 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4435 cm_return_if_fail (node != NULL);
4437 clist = GTK_CMCLIST (ctree);
4439 if (GTK_CMCTREE_ROW (node)->row.style == style)
4442 visible = gtk_cmctree_is_viewable (ctree, node);
4443 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4445 old_width = g_new (gint, clist->columns);
4446 for (i = 0; i < clist->columns; i++)
4447 if (clist->column[i].auto_resize)
4449 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4450 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition);
4451 old_width[i] = requisition.width;
4455 if (GTK_CMCTREE_ROW (node)->row.style)
4457 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4458 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
4459 g_object_unref (GTK_CMCTREE_ROW (node)->row.style);
4462 GTK_CMCTREE_ROW (node)->row.style = style;
4464 if (GTK_CMCTREE_ROW (node)->row.style)
4466 g_object_ref (GTK_CMCTREE_ROW (node)->row.style);
4468 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4469 GTK_CMCTREE_ROW (node)->row.style =
4470 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style,
4471 clist->clist_window);
4474 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4476 for (i = 0; i < clist->columns; i++)
4477 if (clist->column[i].auto_resize)
4478 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i,
4482 tree_draw_node (ctree, node);
4486 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree,
4487 GtkCMCTreeNode *node)
4489 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4490 cm_return_val_if_fail (node != NULL, NULL);
4492 return GTK_CMCTREE_ROW (node)->row.style;
4496 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree,
4497 GtkCMCTreeNode *node,
4498 const GdkColor *color)
4500 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4501 cm_return_if_fail (node != NULL);
4505 GTK_CMCTREE_ROW (node)->row.foreground = *color;
4506 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE;
4507 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4508 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4509 >K_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE);
4512 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE;
4514 tree_draw_node (ctree, node);
4518 gtk_cmctree_node_set_background (GtkCMCTree *ctree,
4519 GtkCMCTreeNode *node,
4520 const GdkColor *color)
4522 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4523 cm_return_if_fail (node != NULL);
4527 GTK_CMCTREE_ROW (node)->row.background = *color;
4528 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE;
4529 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4530 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4531 >K_CMCTREE_ROW (node)->row.background, TRUE, TRUE);
4534 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE;
4536 tree_draw_node (ctree, node);
4540 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree,
4541 GtkCMCTreeNode *node,
4544 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL);
4548 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree,
4549 GtkCMCTreeNode *node,
4551 GDestroyNotify destroy)
4553 GDestroyNotify dnotify;
4556 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4557 cm_return_if_fail (node != NULL);
4559 dnotify = GTK_CMCTREE_ROW (node)->row.destroy;
4560 ddata = GTK_CMCTREE_ROW (node)->row.data;
4562 GTK_CMCTREE_ROW (node)->row.data = data;
4563 GTK_CMCTREE_ROW (node)->row.destroy = destroy;
4570 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree,
4571 GtkCMCTreeNode *node)
4573 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4575 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL;
4579 gtk_cmctree_node_moveto (GtkCMCTree *ctree,
4580 GtkCMCTreeNode *node,
4588 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4590 clist = GTK_CMCLIST (ctree);
4592 while (node && !gtk_cmctree_is_viewable (ctree, node))
4593 node = GTK_CMCTREE_ROW (node)->parent;
4596 row = g_list_position (clist->row_list, (GList *)node);
4598 gtk_cmclist_moveto (clist, row, column, row_align, col_align);
4602 gtk_cmctree_node_is_visible (GtkCMCTree *ctree,
4603 GtkCMCTreeNode *node)
4607 cm_return_val_if_fail (ctree != NULL, 0);
4608 cm_return_val_if_fail (node != NULL, 0);
4610 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node);
4611 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row);
4615 /***********************************************************
4616 * GtkCMCTree specific functions *
4617 ***********************************************************/
4620 gtk_cmctree_set_indent (GtkCMCTree *ctree,
4625 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4626 cm_return_if_fail (indent >= 0);
4628 if (indent == ctree->tree_indent)
4631 clist = GTK_CMCLIST (ctree);
4632 ctree->tree_indent = indent;
4634 if (clist->column[ctree->tree_column].auto_resize &&
4635 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4636 gtk_cmclist_set_column_width
4637 (clist, ctree->tree_column,
4638 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
4640 CLIST_REFRESH (ctree);
4644 gtk_cmctree_set_spacing (GtkCMCTree *ctree,
4650 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4651 cm_return_if_fail (spacing >= 0);
4653 if (spacing == ctree->tree_spacing)
4656 clist = GTK_CMCLIST (ctree);
4658 old_spacing = ctree->tree_spacing;
4659 ctree->tree_spacing = spacing;
4661 if (clist->column[ctree->tree_column].auto_resize &&
4662 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4663 gtk_cmclist_set_column_width (clist, ctree->tree_column,
4664 clist->column[ctree->tree_column].width +
4665 spacing - old_spacing);
4667 CLIST_REFRESH (ctree);
4671 gtk_cmctree_set_show_stub (GtkCMCTree *ctree,
4674 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4676 show_stub = show_stub != FALSE;
4678 if (show_stub != ctree->show_stub)
4682 clist = GTK_CMCLIST (ctree);
4683 ctree->show_stub = show_stub;
4685 if (CLIST_UNFROZEN (clist) && clist->rows &&
4686 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
4687 GTK_CMCLIST_GET_CLASS (clist)->draw_row
4688 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list));
4693 gtk_cmctree_set_line_style (GtkCMCTree *ctree,
4694 GtkCMCTreeLineStyle line_style)
4699 gtk_cmctree_set_expander_style (GtkCMCTree *ctree,
4700 GtkCMCTreeExpanderStyle expander_style)
4703 GtkCMCTreeExpanderStyle old_style;
4705 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4707 if (expander_style == ctree->expander_style)
4710 clist = GTK_CMCLIST (ctree);
4712 old_style = ctree->expander_style;
4713 ctree->expander_style = expander_style;
4715 if (clist->column[ctree->tree_column].auto_resize &&
4716 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4720 new_width = clist->column[ctree->tree_column].width;
4723 case GTK_CMCTREE_EXPANDER_NONE:
4725 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4726 new_width -= PM_SIZE + 3;
4730 switch (expander_style)
4732 case GTK_CMCTREE_EXPANDER_NONE:
4734 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4735 new_width += PM_SIZE + 3;
4739 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width);
4742 if (gtk_widget_is_drawable (GTK_WIDGET(clist)))
4743 CLIST_REFRESH (clist);
4747 /***********************************************************
4748 * Tree sorting functions *
4749 ***********************************************************/
4753 tree_sort (GtkCMCTree *ctree,
4754 GtkCMCTreeNode *node,
4757 GtkCMCTreeNode *list_start;
4758 GtkCMCTreeNode *cmp;
4759 GtkCMCTreeNode *work;
4762 clist = GTK_CMCLIST (ctree);
4765 list_start = GTK_CMCTREE_ROW (node)->children;
4767 list_start = GTK_CMCTREE_NODE (clist->row_list);
4772 work = GTK_CMCTREE_ROW (cmp)->sibling;
4775 if (clist->sort_type == GTK_SORT_ASCENDING)
4778 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0)
4784 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0)
4787 work = GTK_CMCTREE_ROW (work)->sibling;
4789 if (cmp == list_start)
4790 list_start = GTK_CMCTREE_ROW (cmp)->sibling;
4793 gtk_cmctree_unlink (ctree, cmp, FALSE);
4794 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE);
4800 gtk_cmctree_sort_recursive (GtkCMCTree *ctree,
4801 GtkCMCTreeNode *node)
4804 GtkCMCTreeNode *focus_node = NULL;
4806 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4808 clist = GTK_CMCLIST (ctree);
4810 gtk_cmclist_freeze (clist);
4812 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4814 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4816 g_list_free (clist->undo_selection);
4817 g_list_free (clist->undo_unselection);
4818 clist->undo_selection = NULL;
4819 clist->undo_unselection = NULL;
4822 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4824 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
4826 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL);
4829 tree_sort (ctree, NULL, NULL);
4833 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4834 clist->undo_anchor = clist->focus_row;
4837 gtk_cmclist_thaw (clist);
4841 real_sort_list (GtkCMCList *clist)
4843 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL);
4847 gtk_cmctree_sort_node (GtkCMCTree *ctree,
4848 GtkCMCTreeNode *node)
4851 GtkCMCTreeNode *focus_node = NULL;
4853 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4855 clist = GTK_CMCLIST (ctree);
4857 gtk_cmclist_freeze (clist);
4859 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4861 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4863 g_list_free (clist->undo_selection);
4864 g_list_free (clist->undo_unselection);
4865 clist->undo_selection = NULL;
4866 clist->undo_unselection = NULL;
4869 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4870 focus_node = GTK_CMCTREE_NODE
4871 (g_list_nth (clist->row_list, clist->focus_row));
4873 tree_sort (ctree, node, NULL);
4877 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4878 clist->undo_anchor = clist->focus_row;
4881 gtk_cmclist_thaw (clist);
4884 /************************************************************************/
4887 fake_unselect_all (GtkCMCList *clist,
4891 GList *focus_node = NULL;
4893 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
4895 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
4896 GTK_CMCTREE_ROW (focus_node)->row.selectable)
4898 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
4900 if (CLIST_UNFROZEN (clist) &&
4901 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
4902 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
4903 GTK_CMCLIST_ROW (focus_node));
4907 clist->undo_selection = clist->selection;
4908 clist->selection = NULL;
4909 clist->selection_end = NULL;
4911 for (list = clist->undo_selection; list; list = list->next)
4913 if (list->data == focus_node)
4916 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
4917 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data));
4922 selection_find (GtkCMCList *clist,
4924 GList *row_list_element)
4926 return g_list_find (clist->selection, row_list_element);
4930 resync_selection (GtkCMCList *clist, GdkEvent *event)
4934 GtkCMCTreeNode *node;
4940 cm_return_if_fail (GTK_IS_CMCTREE (clist));
4942 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
4945 if (clist->anchor < 0 || clist->drag_pos < 0)
4948 ctree = GTK_CMCTREE (clist);
4950 clist->freeze_count++;
4952 i = MIN (clist->anchor, clist->drag_pos);
4953 e = MAX (clist->anchor, clist->drag_pos);
4955 if (clist->undo_selection)
4957 list = clist->selection;
4958 clist->selection = clist->undo_selection;
4959 clist->selection_end = g_list_last (clist->selection);
4960 clist->undo_selection = list;
4961 list = clist->selection;
4970 if (gtk_cmctree_is_viewable (ctree, node))
4972 row = g_list_position (clist->row_list, (GList *)node);
4973 if (row >= i && row <= e)
4976 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable)
4978 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4979 gtk_cmctree_unselect (ctree, node);
4980 clist->undo_selection = g_list_prepend (clist->undo_selection,
4986 if (clist->anchor < clist->drag_pos)
4988 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
4989 i++, node = GTK_CMCTREE_NODE_NEXT (node))
4990 if (GTK_CMCTREE_ROW (node)->row.selectable)
4992 if (g_list_find (clist->selection, node))
4994 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
4996 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
4997 gtk_cmctree_unselect (ctree, node);
4998 clist->undo_selection =
4999 g_list_prepend (clist->undo_selection, node);
5002 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5004 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5005 clist->undo_unselection =
5006 g_list_prepend (clist->undo_unselection, node);
5012 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
5013 e--, node = GTK_CMCTREE_NODE_PREV (node))
5014 if (GTK_CMCTREE_ROW (node)->row.selectable)
5016 if (g_list_find (clist->selection, node))
5018 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5020 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5021 gtk_cmctree_unselect (ctree, node);
5022 clist->undo_selection =
5023 g_list_prepend (clist->undo_selection, node);
5026 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5028 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5029 clist->undo_unselection =
5030 g_list_prepend (clist->undo_unselection, node);
5035 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
5036 for (list = clist->undo_unselection; list; list = list->next)
5037 gtk_cmctree_select (ctree, list->data);
5040 clist->drag_pos = -1;
5042 if (!CLIST_UNFROZEN (clist))
5043 clist->freeze_count--;
5047 real_undo_selection (GtkCMCList *clist)
5052 cm_return_if_fail (GTK_IS_CMCTREE (clist));
5054 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5057 if (!(clist->undo_selection || clist->undo_unselection))
5059 gtk_cmclist_unselect_all (clist);
5063 ctree = GTK_CMCTREE (clist);
5065 for (work = clist->undo_selection; work; work = work->next)
5066 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5067 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data));
5069 for (work = clist->undo_unselection; work; work = work->next)
5070 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5071 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data));
5073 if (gtk_widget_has_focus (GTK_WIDGET(clist)) &&
5074 clist->focus_row != clist->undo_anchor)
5076 clist->focus_row = clist->undo_anchor;
5077 gtk_widget_queue_draw (GTK_WIDGET (clist));
5080 clist->focus_row = clist->undo_anchor;
5082 clist->undo_anchor = -1;
5084 g_list_free (clist->undo_selection);
5085 g_list_free (clist->undo_unselection);
5086 clist->undo_selection = NULL;
5087 clist->undo_unselection = NULL;
5089 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5090 clist->clist_window_height)
5091 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
5092 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5093 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
5098 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree,
5099 GtkCMCTreeCompareDragFunc cmp_func)
5101 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
5103 ctree->drag_compare = cmp_func;
5107 check_drag (GtkCMCTree *ctree,
5108 GtkCMCTreeNode *drag_source,
5109 GtkCMCTreeNode *drag_target,
5110 GtkCMCListDragPos insert_pos)
5112 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5114 if (drag_source && drag_source != drag_target &&
5115 (!GTK_CMCTREE_ROW (drag_source)->children ||
5116 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target)))
5120 case GTK_CMCLIST_DRAG_NONE:
5122 case GTK_CMCLIST_DRAG_AFTER:
5123 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source)
5124 return (!ctree->drag_compare ||
5125 ctree->drag_compare (ctree,
5127 GTK_CMCTREE_ROW (drag_target)->parent,
5128 GTK_CMCTREE_ROW (drag_target)->sibling));
5130 case GTK_CMCLIST_DRAG_BEFORE:
5131 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target)
5132 return (!ctree->drag_compare ||
5133 ctree->drag_compare (ctree,
5135 GTK_CMCTREE_ROW (drag_target)->parent,
5138 case GTK_CMCLIST_DRAG_INTO:
5139 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf &&
5140 GTK_CMCTREE_ROW (drag_target)->children != drag_source)
5141 return (!ctree->drag_compare ||
5142 ctree->drag_compare (ctree,
5145 GTK_CMCTREE_ROW (drag_target)->children));
5154 /************************************/
5156 drag_dest_info_destroy (gpointer data)
5158 GtkCMCListDestInfo *info = data;
5164 drag_dest_cell (GtkCMCList *clist,
5167 GtkCMCListDestInfo *dest_info)
5173 widget = GTK_WIDGET (clist);
5174 style = gtk_widget_get_style (widget);
5176 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5178 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5179 y -= (border_width +
5180 style->ythickness + clist->column_title_area.height);
5181 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5183 if (dest_info->cell.row >= clist->rows)
5185 dest_info->cell.row = clist->rows - 1;
5186 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5188 if (dest_info->cell.row < -1)
5189 dest_info->cell.row = -1;
5191 x -= border_width + style->xthickness;
5193 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5195 if (dest_info->cell.row >= 0)
5200 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5202 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) &&
5203 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list,
5204 dest_info->cell.row))->is_leaf)
5206 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
5207 h = clist->row_height / 4;
5209 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5211 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5212 h = clist->row_height / 2;
5215 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5218 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5219 else if (clist->row_height - y_delta < h)
5220 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
5226 gtk_cmctree_drag_begin (GtkWidget *widget,
5227 GdkDragContext *context)
5233 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5234 cm_return_if_fail (context != NULL);
5236 clist = GTK_CMCLIST (widget);
5237 ctree = GTK_CMCTREE (widget);
5239 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist);
5240 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5241 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
5245 GtkCMCTreeNode *node;
5247 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5248 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5249 clist->click_cell.row));
5250 gtk_drag_set_icon_default (context);
5255 gtk_cmctree_drag_motion (GtkWidget *widget,
5256 GdkDragContext *context,
5263 GtkCMCListDestInfo new_info;
5264 GtkCMCListDestInfo *dest_info;
5266 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
5268 clist = GTK_CMCLIST (widget);
5269 ctree = GTK_CMCTREE (widget);
5271 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
5275 dest_info = g_new (GtkCMCListDestInfo, 1);
5277 dest_info->cell.row = -1;
5278 dest_info->cell.column = -1;
5279 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5281 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
5282 drag_dest_info_destroy);
5285 drag_dest_cell (clist, x, y, &new_info);
5287 if (GTK_CMCLIST_REORDERABLE (clist))
5289 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5290 GdkAtom found = gtk_drag_dest_find_target(widget, context, NULL);
5294 GtkCMCTreeNode *drag_source;
5295 GtkCMCTreeNode *drag_target;
5297 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5298 clist->click_cell.row));
5299 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5300 new_info.cell.row));
5302 if (gtk_drag_get_source_widget (context) != widget ||
5303 !check_drag (ctree, drag_source, drag_target,
5304 new_info.insert_pos))
5306 if (dest_info->cell.row < 0)
5308 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
5314 if (new_info.cell.row != dest_info->cell.row ||
5315 (new_info.cell.row == dest_info->cell.row &&
5316 dest_info->insert_pos != new_info.insert_pos))
5318 dest_info->insert_pos = new_info.insert_pos;
5319 dest_info->cell.row = new_info.cell.row;
5320 dest_info->cell.column = new_info.cell.column;
5322 clist->drag_highlight_row = dest_info->cell.row;
5323 clist->drag_highlight_pos = dest_info->insert_pos;
5325 gdk_drag_status (context,
5326 gdk_drag_context_get_suggested_action(context), time);
5332 dest_info->insert_pos = new_info.insert_pos;
5333 dest_info->cell.row = new_info.cell.row;
5334 dest_info->cell.column = new_info.cell.column;
5339 gtk_cmctree_drag_data_received (GtkWidget *widget,
5340 GdkDragContext *context,
5343 GtkSelectionData *selection_data,
5350 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5351 cm_return_if_fail (context != NULL);
5352 cm_return_if_fail (selection_data != NULL);
5354 ctree = GTK_CMCTREE (widget);
5355 clist = GTK_CMCLIST (widget);
5357 if (GTK_CMCLIST_REORDERABLE (clist) &&
5358 gtk_drag_get_source_widget (context) == widget &&
5359 gtk_selection_data_get_target (selection_data) ==
5360 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
5361 gtk_selection_data_get_format (selection_data) == 8 &&
5362 gtk_selection_data_get_length (selection_data) == sizeof (GtkCMCListCellInfo))
5364 GtkCMCListCellInfo *source_info;
5366 source_info = (GtkCMCListCellInfo *)(gtk_selection_data_get_data (selection_data));
5369 GtkCMCListDestInfo dest_info;
5370 GtkCMCTreeNode *source_node;
5371 GtkCMCTreeNode *dest_node;
5373 drag_dest_cell (clist, x, y, &dest_info);
5375 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5377 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5378 dest_info.cell.row));
5380 if (!source_node || !dest_node)
5383 switch (dest_info.insert_pos)
5385 case GTK_CMCLIST_DRAG_NONE:
5387 case GTK_CMCLIST_DRAG_INTO:
5388 if (check_drag (ctree, source_node, dest_node,
5389 dest_info.insert_pos))
5390 gtk_cmctree_move (ctree, source_node, dest_node,
5391 GTK_CMCTREE_ROW (dest_node)->children);
5392 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5394 case GTK_CMCLIST_DRAG_BEFORE:
5395 if (check_drag (ctree, source_node, dest_node,
5396 dest_info.insert_pos))
5397 gtk_cmctree_move (ctree, source_node,
5398 GTK_CMCTREE_ROW (dest_node)->parent, dest_node);
5399 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5401 case GTK_CMCLIST_DRAG_AFTER:
5402 if (check_drag (ctree, source_node, dest_node,
5403 dest_info.insert_pos))
5404 gtk_cmctree_move (ctree, source_node,
5405 GTK_CMCTREE_ROW (dest_node)->parent,
5406 GTK_CMCTREE_ROW (dest_node)->sibling);
5407 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5415 gtk_cmctree_node_get_type (void)
5417 static GType our_type = 0;
5420 our_type = g_pointer_type_register_static ("GtkCMCTreeNode");