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 draw_drag_highlight (GtkCMCList *clist,
198 GtkCMCListRow *dest_row,
199 gint dest_row_number,
200 GtkCMCListDragPos drag_pos);
201 static void set_cell_contents (GtkCMCList *clist,
202 GtkCMCListRow *clist_row,
208 static void set_node_info (GtkCMCTree *ctree,
209 GtkCMCTreeNode *node,
212 GdkPixbuf *pixbuf_closed,
213 GdkPixbuf *pixbuf_opened,
216 static GtkCMCTreeRow *row_new (GtkCMCTree *ctree);
217 static void row_delete (GtkCMCTree *ctree,
218 GtkCMCTreeRow *ctree_row);
219 static void tree_delete (GtkCMCTree *ctree,
220 GtkCMCTreeNode *node,
222 static void tree_delete_row (GtkCMCTree *ctree,
223 GtkCMCTreeNode *node,
225 static void real_clear (GtkCMCList *clist);
226 static void tree_update_level (GtkCMCTree *ctree,
227 GtkCMCTreeNode *node,
229 static void tree_select (GtkCMCTree *ctree,
230 GtkCMCTreeNode *node,
232 static void tree_unselect (GtkCMCTree *ctree,
233 GtkCMCTreeNode *node,
235 static void real_select_all (GtkCMCList *clist);
236 static void real_unselect_all (GtkCMCList *clist);
237 static void tree_expand (GtkCMCTree *ctree,
238 GtkCMCTreeNode *node,
240 static void tree_collapse (GtkCMCTree *ctree,
241 GtkCMCTreeNode *node,
243 static void tree_collapse_to_depth (GtkCMCTree *ctree,
244 GtkCMCTreeNode *node,
246 static void tree_toggle_expansion (GtkCMCTree *ctree,
247 GtkCMCTreeNode *node,
249 static void change_focus_row_expansion (GtkCMCTree *ctree,
250 GtkCMCTreeExpansionType expansion);
251 static void real_select_row (GtkCMCList *clist,
255 static void real_unselect_row (GtkCMCList *clist,
259 static void real_tree_select (GtkCMCTree *ctree,
260 GtkCMCTreeNode *node,
262 static void real_tree_unselect (GtkCMCTree *ctree,
263 GtkCMCTreeNode *node,
265 static void real_tree_expand (GtkCMCTree *ctree,
266 GtkCMCTreeNode *node);
267 static void real_tree_collapse (GtkCMCTree *ctree,
268 GtkCMCTreeNode *node);
269 static void real_tree_move (GtkCMCTree *ctree,
270 GtkCMCTreeNode *node,
271 GtkCMCTreeNode *new_parent,
272 GtkCMCTreeNode *new_sibling);
273 static void real_row_move (GtkCMCList *clist,
276 static void gtk_cmctree_link (GtkCMCTree *ctree,
277 GtkCMCTreeNode *node,
278 GtkCMCTreeNode *parent,
279 GtkCMCTreeNode *sibling,
280 gboolean update_focus_row);
281 static void gtk_cmctree_unlink (GtkCMCTree *ctree,
282 GtkCMCTreeNode *node,
283 gboolean update_focus_row);
284 static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree,
285 GtkCMCTreeNode *node);
286 static gboolean ctree_is_hot_spot (GtkCMCTree *ctree,
287 GtkCMCTreeNode *node,
291 static void tree_sort (GtkCMCTree *ctree,
292 GtkCMCTreeNode *node,
294 static void fake_unselect_all (GtkCMCList *clist,
296 static GList * selection_find (GtkCMCList *clist,
298 GList *row_list_element);
299 static void resync_selection (GtkCMCList *clist,
301 static void real_undo_selection (GtkCMCList *clist);
302 static void select_row_recursive (GtkCMCTree *ctree,
303 GtkCMCTreeNode *node,
305 static gint real_insert_row (GtkCMCList *clist,
308 static void real_remove_row (GtkCMCList *clist,
310 static void real_sort_list (GtkCMCList *clist);
311 static void cell_size_request (GtkCMCList *clist,
312 GtkCMCListRow *clist_row,
314 GtkRequisition *requisition);
315 static void column_auto_resize (GtkCMCList *clist,
316 GtkCMCListRow *clist_row,
319 static void auto_resize_columns (GtkCMCList *clist);
322 static gboolean check_drag (GtkCMCTree *ctree,
323 GtkCMCTreeNode *drag_source,
324 GtkCMCTreeNode *drag_target,
325 GtkCMCListDragPos insert_pos);
326 static void gtk_cmctree_drag_begin (GtkWidget *widget,
327 GdkDragContext *context);
328 static gint gtk_cmctree_drag_motion (GtkWidget *widget,
329 GdkDragContext *context,
333 static void gtk_cmctree_drag_data_received (GtkWidget *widget,
334 GdkDragContext *context,
337 GtkSelectionData *selection_data,
340 static void remove_grab (GtkCMCList *clist);
341 static void drag_dest_cell (GtkCMCList *clist,
344 GtkCMCListDestInfo *dest_info);
354 CHANGE_FOCUS_ROW_EXPANSION,
358 static GtkCMCListClass *parent_class = NULL;
359 static GtkContainerClass *container_class = NULL;
360 static guint ctree_signals[LAST_SIGNAL] = {0};
364 gtk_cmctree_get_type (void)
366 static GType ctree_type = 0;
370 static const GTypeInfo ctree_info =
372 sizeof (GtkCMCTreeClass),
374 (GBaseInitFunc) NULL,
375 (GBaseFinalizeFunc) NULL,
377 (GClassInitFunc) gtk_cmctree_class_init,
378 (GClassFinalizeFunc) NULL,
379 NULL, /* class_data */
383 (GInstanceInitFunc) gtk_cmctree_init,
386 ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0);
393 draw_cell_pixbuf (GdkWindow *window,
394 GdkRectangle *clip_rectangle,
405 if (!pixbuf || (width == 0 && height == 0))
408 if (x < clip_rectangle->x)
410 xsrc = clip_rectangle->x - x;
412 x = clip_rectangle->x;
414 if (x + width > clip_rectangle->x + clip_rectangle->width)
415 width = clip_rectangle->x + clip_rectangle->width - x;
417 if (y < clip_rectangle->y)
419 ysrc = clip_rectangle->y - y;
421 y = clip_rectangle->y;
424 if (y + height > clip_rectangle->y + clip_rectangle->height)
425 height = clip_rectangle->y + clip_rectangle->height - y;
427 gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
430 return x + MAX (width, 0);
434 draw_expander (GtkCMCTree *ctree,
435 GtkCMCTreeRow *ctree_row,
437 GdkRectangle *clip_rectangle,
443 gint justification_factor;
446 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
449 clist = GTK_CMCLIST (ctree);
450 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
451 justification_factor = -1;
453 justification_factor = 1;
454 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
455 y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
456 (clip_rectangle->height + 1) % 2) + 1;
458 y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 -
459 (clip_rectangle->height/2 + 1) % 2) + 1;
461 if (!ctree_row->children)
463 return x + justification_factor * (PM_SIZE + 3);
466 if (ctree_row->expanded)
469 points[0].y = y + (PM_SIZE + 2) / 6;
470 points[1].x = points[0].x + justification_factor * (PM_SIZE + 2);
471 points[1].y = points[0].y;
472 points[2].x = (points[0].x +
473 justification_factor * (PM_SIZE + 2) / 2);
474 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
478 points[0].x = x + justification_factor * ((PM_SIZE + 2) / 6 + 2);
480 points[1].x = points[0].x;
481 points[1].y = points[0].y + (PM_SIZE + 2);
482 points[2].x = (points[0].x +
483 justification_factor * (2 * (PM_SIZE + 2) / 3 - 1));
484 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
489 cairo_set_source_rgb(cr, 255, 255, 255);
490 cairo_set_line_width(cr, 1);
491 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
492 cairo_move_to(cr, points[0].x, points[0].y);
493 cairo_line_to(cr, points[1].x, points[1].y);
494 cairo_line_to(cr, points[2].x, points[2].y);
495 cairo_close_path(cr);
499 gdk_cairo_set_source_color(cr, >k_widget_get_style(ctree)->fg[GTK_STATE_NORMAL]);
500 cairo_set_line_width(cr, 1);
501 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
502 cairo_move_to(cr, points[0].x, points[0].y);
503 cairo_line_to(cr, points[1].x, points[1].y);
504 cairo_line_to(cr, points[2].x, points[2].y);
505 cairo_close_path(cr);
507 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
509 x += justification_factor * (PM_SIZE + 3);
515 get_offset(GtkCMCTree *ctree,
516 GtkCMCTreeRow *ctree_row,
518 GdkRectangle *clip_rectangle)
521 justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
524 return (clip_rectangle->x + clip_rectangle->width - 1 -
525 ctree->tree_indent * (ctree_row->level - 1));
527 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
531 get_cell_style (GtkCMCList *clist,
532 GtkCMCListRow *clist_row,
539 gtkstyle = gtk_widget_get_style (GTK_WIDGET (clist));
541 if (clist_row->cell[column].style)
544 *style = clist_row->cell[column].style;
546 else if (clist_row->style)
549 *style = clist_row->style;
558 static gboolean filter_fg (PangoAttribute *attribute, gpointer data)
560 const PangoAttrClass *klass = attribute->klass;
561 if (klass->type == PANGO_ATTR_FOREGROUND)
568 create_cell_layout (GtkCMCList *clist,
569 GtkCMCListRow *clist_row,
577 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style);
580 cell = &clist_row->cell[column];
583 case GTK_CMCELL_TEXT:
584 case GTK_CMCELL_PIXTEXT:
585 text = ((cell->type == GTK_CMCELL_PIXTEXT) ?
586 GTK_CMCELL_PIXTEXT (*cell)->text :
587 GTK_CMCELL_TEXT (*cell)->text);
592 if (!GTK_SCTREE(clist)->use_markup[column]) {
593 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
594 ((cell->type == GTK_CMCELL_PIXTEXT) ?
595 GTK_CMCELL_PIXTEXT (*cell)->text :
596 GTK_CMCELL_TEXT (*cell)->text));
597 pango_layout_set_font_description (layout, style->font_desc);
599 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist));
600 layout = pango_layout_new (context);
601 pango_layout_set_markup (layout, text, -1);
602 pango_layout_set_font_description (layout, style->font_desc);
603 if (clist_row->state == GTK_STATE_SELECTED) {
604 /* for selected row, we should remove any forced foreground color
605 * or it looks like shit */
606 PangoAttrList *list = pango_layout_get_attributes(layout);
607 PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL);
609 pango_attr_list_unref(rem);
622 draw_row (GtkCMCList *clist,
625 GtkCMCListRow *clist_row)
632 GdkRectangle row_rectangle;
633 GdkRectangle cell_rectangle;
634 GdkRectangle clip_rectangle;
635 GdkRectangle intersect_rectangle;
637 gint column_left = 0;
638 gint column_right = 0;
642 static GdkColor greybg={0, 0, 0, 0};
643 static gboolean color_change = TRUE;
645 GdkColor *fgcolor, *bgcolor, *focuscolor;
647 cm_return_if_fail (clist != NULL);
648 widget = GTK_WIDGET (clist);
649 style = gtk_widget_get_style (widget);
651 if (greybg.pixel == 0 &&
655 GdkColor normalbg = {0, 0xffff, 0xffff, 0xffff};
657 normalbg = style->base[GTK_STATE_NORMAL];
659 if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
660 greybg.pixel = normalbg.pixel;
661 greybg.red = normalbg.red - prefs_common.stripes_color_offset;
662 greybg.green = normalbg.green - prefs_common.stripes_color_offset;
663 greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
664 } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
665 greybg.pixel = normalbg.pixel;
666 greybg.red = normalbg.red + prefs_common.stripes_color_offset;
667 greybg.green = normalbg.green + prefs_common.stripes_color_offset;
668 greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
670 color_change = FALSE;
674 /* bail now if we arn't drawable yet */
675 if (!gtk_widget_is_drawable (GTK_WIDGET(clist)) || row < 0 || row >= clist->rows)
678 ctree = GTK_CMCTREE (clist);
680 /* if the function is passed the pointer to the row instead of null,
681 * it avoids this expensive lookup */
683 clist_row = (g_list_nth (clist->row_list, row))->data;
685 /* rectangle of the entire row */
687 row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
688 row_rectangle.width = clist->clist_window_width;
689 row_rectangle.height = clist->row_height;
691 /* rectangle of the cell spacing above the row */
692 cell_rectangle.x = 0;
693 cell_rectangle.y = row_rectangle.y - CELL_SPACING;
694 cell_rectangle.width = row_rectangle.width;
695 cell_rectangle.height = CELL_SPACING;
697 /* rectangle used to clip drawing operations, its y and height
698 * positions only need to be set once, so we set them once here.
699 * the x and width are set withing the drawing loop below once per
701 clip_rectangle.y = row_rectangle.y;
702 clip_rectangle.height = row_rectangle.height;
704 if (prefs_common.use_stripes_everywhere && GTK_SCTREE(ctree)->show_stripes
705 && color_change && row % 2) {
707 focuscolor = &greybg;
709 bgcolor = &style->base[GTK_STATE_NORMAL];
710 focuscolor = &style->base[GTK_STATE_NORMAL];
712 state = clist_row->state;
714 cr = gdk_cairo_create(clist->clist_window);
715 fgcolor = &style->fg[clist_row->state];
716 /* draw the cell borders */
719 rect = &intersect_rectangle;
720 crect = &intersect_rectangle;
722 if (gdk_rectangle_intersect (area, &cell_rectangle, crect)) {
723 gdk_cairo_rectangle(cr, crect);
724 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
730 rect = &clip_rectangle;
731 crect = &cell_rectangle;
733 gdk_cairo_rectangle(cr, crect);
734 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
738 /* the last row has to clear its bottom cell spacing too */
739 if (clist_row == clist->row_list_end->data)
741 cell_rectangle.y += clist->row_height + CELL_SPACING;
743 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
745 gdk_cairo_rectangle(cr, crect);
746 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
751 for (last_column = clist->columns - 1;
752 last_column >= 0 && !clist->column[last_column].visible; last_column--)
755 /* iterate and draw all the columns (row cells) and draw their contents */
756 for (i = 0; i < clist->columns; i++)
759 PangoLayout *layout = NULL;
760 PangoRectangle logical_rect;
768 if (!clist->column[i].visible)
771 get_cell_style (clist, clist_row, state, i, &style);
773 /* calculate clipping region */
774 clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
775 clip_rectangle.width = clist->column[i].area.width;
777 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
778 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
779 (1 + (i == last_column)) * CELL_SPACING);
780 cell_rectangle.y = clip_rectangle.y;
781 cell_rectangle.height = clip_rectangle.height;
787 gdk_cairo_rectangle(cr, &cell_rectangle);
788 if (state == GTK_STATE_NORMAL)
789 gdk_cairo_set_source_color(cr, bgcolor);
791 gdk_cairo_set_source_color(cr, &style->base[state]);
793 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
794 &intersect_rectangle))
796 if (i != ctree->tree_column)
801 layout = create_cell_layout (clist, clist_row, i);
804 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
805 width = logical_rect.width;
810 switch (clist_row->cell[i].type)
812 case GTK_CMCELL_PIXBUF:
813 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
814 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf);
815 width += pixbuf_width;
817 case GTK_CMCELL_PIXTEXT:
818 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
820 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
821 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf);
822 width += pixbuf_width;
825 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text &&
826 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
827 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
829 if (i == ctree->tree_column)
830 width += (ctree->tree_indent *
831 ((GtkCMCTreeRow *)clist_row)->level);
837 switch (clist->column[i].justification)
839 case GTK_JUSTIFY_LEFT:
840 offset = clip_rectangle.x + clist_row->cell[i].horizontal;
842 case GTK_JUSTIFY_RIGHT:
843 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
844 clip_rectangle.width - width);
846 case GTK_JUSTIFY_CENTER:
847 case GTK_JUSTIFY_FILL:
848 offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
849 (clip_rectangle.width / 2) - (width / 2));
853 if (i != ctree->tree_column)
855 int start_y = (clip_rectangle.height - height) / 2;
856 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
857 start_y = (clip_rectangle.height/2 - height) / 2;
859 offset += clist_row->cell[i].horizontal;
860 switch (clist_row->cell[i].type)
862 case GTK_CMCELL_PIXBUF:
864 (clist->clist_window, &clip_rectangle, cr,
865 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf,
867 clip_rectangle.y + clist_row->cell[i].vertical +
869 pixbuf_width, height);
871 case GTK_CMCELL_PIXTEXT:
872 offset = draw_cell_pixbuf
873 (clist->clist_window, &clip_rectangle, cr,
874 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
876 clip_rectangle.y + clist_row->cell[i].vertical +
878 pixbuf_width, height);
879 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
882 case GTK_CMCELL_TEXT:
885 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
886 gdk_cairo_set_source_color(cr, fgcolor);
887 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
888 pango_cairo_show_layout(cr, layout);
889 g_object_unref (G_OBJECT (layout));
899 /* draw ctree->tree_column */
900 cell_rectangle.y -= CELL_SPACING;
901 cell_rectangle.height += CELL_SPACING;
903 if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
904 &intersect_rectangle))
907 g_object_unref (G_OBJECT (layout));
913 offset = get_offset (ctree, (GtkCMCTreeRow *)clist_row, i,
917 offset = draw_expander (ctree, (GtkCMCTreeRow *)clist_row,
918 style, &clip_rectangle, cr, offset);
920 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
921 offset -= ctree->tree_spacing;
923 offset += ctree->tree_spacing;
925 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
926 offset -= (pixbuf_width + clist_row->cell[i].horizontal);
928 offset += clist_row->cell[i].horizontal;
931 offset = draw_cell_pixbuf (clist->clist_window, &clip_rectangle, cr,
932 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf,
934 clip_rectangle.y + clist_row->cell[i].vertical
935 + (clip_rectangle.height - height) / 2,
936 pixbuf_width, height);
940 gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
942 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
944 offset = (old_offset - string_width);
945 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
946 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
950 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf)
951 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing;
954 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical);
955 gdk_cairo_set_source_color(cr, fgcolor);
956 pango_cairo_show_layout(cr, layout);
958 g_object_unref (G_OBJECT (layout));
965 gtk_cmctree_class_init (GtkCMCTreeClass *klass)
967 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
968 GtkObjectClass *object_class;
969 GtkWidgetClass *widget_class;
970 GtkCMCListClass *clist_class;
971 GtkBindingSet *binding_set;
973 gobject_class->constructor = gtk_cmctree_constructor;
975 object_class = (GtkObjectClass *) klass;
976 widget_class = (GtkWidgetClass *) klass;
977 container_class = (GtkContainerClass *) klass;
978 clist_class = (GtkCMCListClass *) klass;
980 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST);
981 container_class = g_type_class_peek (GTK_TYPE_CONTAINER);
983 gobject_class->set_property = gtk_cmctree_set_arg;
984 gobject_class->get_property = gtk_cmctree_get_arg;
986 widget_class->realize = gtk_cmctree_realize;
987 widget_class->unrealize = gtk_cmctree_unrealize;
988 widget_class->button_press_event = gtk_cmctree_button_press;
990 widget_class->drag_begin = gtk_cmctree_drag_begin;
991 widget_class->drag_motion = gtk_cmctree_drag_motion;
992 widget_class->drag_data_received = gtk_cmctree_drag_data_received;
994 clist_class->select_row = real_select_row;
995 clist_class->unselect_row = real_unselect_row;
996 clist_class->row_move = real_row_move;
997 clist_class->undo_selection = real_undo_selection;
998 clist_class->resync_selection = resync_selection;
999 clist_class->selection_find = selection_find;
1000 clist_class->click_column = NULL;
1001 clist_class->draw_row = draw_row;
1002 clist_class->draw_drag_highlight = draw_drag_highlight;
1003 clist_class->clear = real_clear;
1004 clist_class->select_all = real_select_all;
1005 clist_class->unselect_all = real_unselect_all;
1006 clist_class->fake_unselect_all = fake_unselect_all;
1007 clist_class->insert_row = real_insert_row;
1008 clist_class->remove_row = real_remove_row;
1009 clist_class->sort_list = real_sort_list;
1010 clist_class->set_cell_contents = set_cell_contents;
1011 clist_class->cell_size_request = cell_size_request;
1013 klass->tree_select_row = real_tree_select;
1014 klass->tree_unselect_row = real_tree_unselect;
1015 klass->tree_expand = real_tree_expand;
1016 klass->tree_collapse = real_tree_collapse;
1017 klass->tree_move = real_tree_move;
1018 klass->change_focus_row_expansion = change_focus_row_expansion;
1020 g_object_class_install_property (gobject_class,
1022 g_param_spec_uint ("n-columns",
1028 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1029 g_object_class_install_property (gobject_class,
1031 g_param_spec_uint ("tree-column",
1037 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1038 g_object_class_install_property (gobject_class,
1040 g_param_spec_uint ("indent",
1046 G_PARAM_READWRITE));
1047 g_object_class_install_property (gobject_class,
1049 g_param_spec_uint ("spacing",
1055 G_PARAM_READWRITE));
1056 g_object_class_install_property (gobject_class,
1058 g_param_spec_boolean ("show-stub",
1062 G_PARAM_READWRITE));
1063 g_object_class_install_property (gobject_class,
1065 g_param_spec_enum ("line-style",
1068 GTK_TYPE_CMCTREE_LINE_STYLE, 0,
1069 G_PARAM_READWRITE));
1070 g_object_class_install_property (gobject_class,
1072 g_param_spec_enum ("expander-style",
1075 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0,
1076 G_PARAM_READWRITE));
1078 ctree_signals[TREE_SELECT_ROW] =
1079 g_signal_new ("tree_select_row",
1080 G_TYPE_FROM_CLASS (object_class),
1082 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row),
1084 claws_marshal_VOID__POINTER_INT,
1086 GTK_TYPE_CMCTREE_NODE,
1088 ctree_signals[TREE_UNSELECT_ROW] =
1089 g_signal_new ("tree_unselect_row",
1090 G_TYPE_FROM_CLASS (object_class),
1092 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row),
1094 claws_marshal_VOID__POINTER_INT,
1096 GTK_TYPE_CMCTREE_NODE,
1098 ctree_signals[TREE_EXPAND] =
1099 g_signal_new ("tree_expand",
1100 G_TYPE_FROM_CLASS (object_class),
1102 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand),
1104 claws_marshal_VOID__POINTER,
1106 GTK_TYPE_CMCTREE_NODE);
1107 ctree_signals[TREE_COLLAPSE] =
1108 g_signal_new ("tree_collapse",
1109 G_TYPE_FROM_CLASS (object_class),
1111 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse),
1113 claws_marshal_VOID__POINTER,
1115 GTK_TYPE_CMCTREE_NODE);
1116 ctree_signals[TREE_MOVE] =
1117 g_signal_new ("tree_move",
1118 G_TYPE_FROM_CLASS (object_class),
1120 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move),
1122 claws_marshal_VOID__POINTER_POINTER_POINTER,
1124 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE);
1125 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
1126 g_signal_new ("change_focus_row_expansion",
1127 G_TYPE_FROM_CLASS (object_class),
1128 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1129 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion),
1131 claws_marshal_VOID__ENUM,
1132 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE);
1134 binding_set = gtk_binding_set_by_class (klass);
1135 gtk_binding_entry_add_signal (binding_set,
1137 "change_focus_row_expansion", 1,
1138 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1139 gtk_binding_entry_add_signal (binding_set,
1140 GDK_KEY_plus, GDK_CONTROL_MASK,
1141 "change_focus_row_expansion", 1,
1142 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1144 gtk_binding_entry_add_signal (binding_set,
1146 "change_focus_row_expansion", 1,
1147 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND);
1148 gtk_binding_entry_add_signal (binding_set,
1149 GDK_KEY_KP_Add, GDK_CONTROL_MASK,
1150 "change_focus_row_expansion", 1,
1151 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE);
1153 gtk_binding_entry_add_signal (binding_set,
1155 "change_focus_row_expansion", 1,
1156 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1157 gtk_binding_entry_add_signal (binding_set,
1158 GDK_KEY_minus, GDK_CONTROL_MASK,
1159 "change_focus_row_expansion", 1,
1161 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1162 gtk_binding_entry_add_signal (binding_set,
1163 GDK_KEY_KP_Subtract, 0,
1164 "change_focus_row_expansion", 1,
1165 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE);
1166 gtk_binding_entry_add_signal (binding_set,
1167 GDK_KEY_KP_Subtract, GDK_CONTROL_MASK,
1168 "change_focus_row_expansion", 1,
1170 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE);
1171 gtk_binding_entry_add_signal (binding_set,
1173 "change_focus_row_expansion", 1,
1174 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1175 gtk_binding_entry_add_signal (binding_set,
1176 GDK_KEY_KP_Equal, 0,
1177 "change_focus_row_expansion", 1,
1178 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1179 gtk_binding_entry_add_signal (binding_set,
1180 GDK_KEY_KP_Multiply, 0,
1181 "change_focus_row_expansion", 1,
1182 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1183 gtk_binding_entry_add_signal (binding_set,
1184 GDK_KEY_asterisk, 0,
1185 "change_focus_row_expansion", 1,
1186 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE);
1187 gtk_binding_entry_add_signal (binding_set,
1188 GDK_KEY_KP_Multiply, GDK_CONTROL_MASK,
1189 "change_focus_row_expansion", 1,
1191 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1192 gtk_binding_entry_add_signal (binding_set,
1193 GDK_KEY_asterisk, GDK_CONTROL_MASK,
1194 "change_focus_row_expansion", 1,
1196 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE);
1200 gtk_cmctree_set_arg (GObject *object,
1202 const GValue *value,
1208 ctree = GTK_CMCTREE (object);
1209 clist = GTK_CMCLIST (ctree);
1213 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
1214 #if !GLIB_CHECK_VERSION(2,10,0)
1215 cm_return_if_fail (clist->row_mem_chunk == NULL);
1217 clist->columns = MAX (1, g_value_get_uint (value));
1218 #if !GLIB_CHECK_VERSION(2,10,0)
1219 clist->row_mem_chunk = g_mem_chunk_new ("ctree row mem chunk",
1220 sizeof (GtkCMCTreeRow),
1221 sizeof (GtkCMCTreeRow)
1222 * CLIST_OPTIMUM_SIZE,
1224 clist->cell_mem_chunk = g_mem_chunk_new ("ctree cell mem chunk",
1225 sizeof (GtkCMCell) * clist->columns,
1226 sizeof (GtkCMCell) * clist->columns
1227 * CLIST_OPTIMUM_SIZE,
1230 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1232 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
1233 ctree->tree_column = g_value_get_uint (value);
1234 #if !GLIB_CHECK_VERSION(2,10,0)
1235 if (clist->row_mem_chunk)
1237 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
1240 gtk_cmctree_set_indent (ctree, g_value_get_uint (value));
1243 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value));
1246 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value));
1248 case ARG_LINE_STYLE:
1249 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value));
1251 case ARG_EXPANDER_STYLE:
1252 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value));
1260 gtk_cmctree_get_arg (GObject *object,
1267 ctree = GTK_CMCTREE (object);
1272 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns);
1274 case ARG_TREE_COLUMN:
1275 g_value_set_uint(value, ctree->tree_column);
1278 g_value_set_uint(value, ctree->tree_indent);
1281 g_value_set_uint(value, ctree->tree_spacing);
1284 g_value_set_boolean(value, ctree->show_stub);
1286 case ARG_LINE_STYLE:
1287 g_value_set_enum(value, ctree->line_style);
1289 case ARG_EXPANDER_STYLE:
1290 g_value_set_enum(value, ctree->expander_style);
1293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec);
1299 gtk_cmctree_init (GtkCMCTree *ctree)
1303 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT);
1304 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE);
1306 clist = GTK_CMCLIST (ctree);
1308 ctree->tree_indent = 20;
1309 ctree->tree_spacing = 5;
1310 ctree->tree_column = 0;
1311 ctree->line_style = GTK_CMCTREE_LINES_NONE;
1312 ctree->expander_style = GTK_CMCTREE_EXPANDER_TRIANGLE;
1313 ctree->drag_compare = NULL;
1314 ctree->show_stub = TRUE;
1316 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS;
1320 ctree_attach_styles (GtkCMCTree *ctree,
1321 GtkCMCTreeNode *node,
1327 clist = GTK_CMCLIST (ctree);
1329 if (GTK_CMCTREE_ROW (node)->row.style)
1330 GTK_CMCTREE_ROW (node)->row.style =
1331 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window);
1333 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set)
1335 GdkColormap *colormap;
1337 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
1338 if (GTK_CMCTREE_ROW (node)->row.fg_set)
1339 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE);
1340 if (GTK_CMCTREE_ROW (node)->row.bg_set)
1341 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE);
1344 for (i = 0; i < clist->columns; i++)
1345 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1346 GTK_CMCTREE_ROW (node)->row.cell[i].style =
1347 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style,
1348 clist->clist_window);
1352 ctree_detach_styles (GtkCMCTree *ctree,
1353 GtkCMCTreeNode *node,
1359 clist = GTK_CMCLIST (ctree);
1361 if (GTK_CMCTREE_ROW (node)->row.style)
1362 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
1363 for (i = 0; i < clist->columns; i++)
1364 if (GTK_CMCTREE_ROW (node)->row.cell[i].style)
1365 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style);
1369 gtk_cmctree_realize (GtkWidget *widget)
1373 GtkCMCTreeNode *node;
1374 GtkCMCTreeNode *child;
1378 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1380 GTK_WIDGET_CLASS (parent_class)->realize (widget);
1382 ctree = GTK_CMCTREE (widget);
1383 clist = GTK_CMCLIST (widget);
1385 node = GTK_CMCTREE_NODE (clist->row_list);
1386 for (i = 0; i < clist->rows; i++)
1388 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded)
1389 for (child = GTK_CMCTREE_ROW (node)->children; child;
1390 child = GTK_CMCTREE_ROW (child)->sibling)
1391 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
1392 node = GTK_CMCTREE_NODE_NEXT (node);
1395 style = gtk_widget_get_style(widget);
1399 gtk_cmctree_unrealize (GtkWidget *widget)
1404 cm_return_if_fail (GTK_IS_CMCTREE (widget));
1406 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1408 ctree = GTK_CMCTREE (widget);
1409 clist = GTK_CMCLIST (widget);
1411 if (gtk_widget_get_realized (widget))
1413 GtkCMCTreeNode *node;
1414 GtkCMCTreeNode *child;
1417 node = GTK_CMCTREE_NODE (clist->row_list);
1418 for (i = 0; i < clist->rows; i++)
1420 if (GTK_CMCTREE_ROW (node)->children &&
1421 !GTK_CMCTREE_ROW (node)->expanded)
1422 for (child = GTK_CMCTREE_ROW (node)->children; child;
1423 child = GTK_CMCTREE_ROW (child)->sibling)
1424 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
1425 node = GTK_CMCTREE_NODE_NEXT (node);
1431 gtk_cmctree_button_press (GtkWidget *widget,
1432 GdkEventButton *event)
1436 gint button_actions;
1438 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
1439 cm_return_val_if_fail (event != NULL, FALSE);
1441 ctree = GTK_CMCTREE (widget);
1442 clist = GTK_CMCLIST (widget);
1444 button_actions = clist->button_actions[event->button - 1];
1446 if (button_actions == GTK_CMBUTTON_IGNORED)
1449 if (event->window == clist->clist_window)
1451 GtkCMCTreeNode *work;
1460 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column))
1463 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
1465 if (button_actions & GTK_CMBUTTON_EXPANDS &&
1466 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf &&
1467 (event->type == GDK_2BUTTON_PRESS ||
1468 ctree_is_hot_spot (ctree, work, row, x, y))))
1470 if (GTK_CMCTREE_ROW (work)->expanded)
1471 gtk_cmctree_collapse (ctree, work);
1473 gtk_cmctree_expand (ctree, work);
1479 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
1483 draw_drag_highlight (GtkCMCList *clist,
1484 GtkCMCListRow *dest_row,
1485 gint dest_row_number,
1486 GtkCMCListDragPos drag_pos)
1488 GtkAllocation allocation;
1495 cm_return_if_fail (GTK_IS_CMCTREE (clist));
1497 ctree = GTK_CMCTREE (clist);
1498 gtk_widget_get_allocation(GTK_WIDGET(ctree), &allocation);
1500 level = ((GtkCMCTreeRow *)(dest_row))->level;
1502 y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
1506 case GTK_CMCLIST_DRAG_NONE:
1508 case GTK_CMCLIST_DRAG_AFTER:
1509 y += clist->row_height + 1;
1510 case GTK_CMCLIST_DRAG_BEFORE:
1512 if (clist->column[ctree->tree_column].visible)
1513 switch (clist->column[ctree->tree_column].justification)
1515 case GTK_JUSTIFY_CENTER:
1516 case GTK_JUSTIFY_FILL:
1517 case GTK_JUSTIFY_LEFT:
1518 if (ctree->tree_column > 0)
1519 gdk_draw_line (clist->clist_window, clist->xor_gc,
1520 COLUMN_LEFT_XPIXEL(clist, 0), y,
1521 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1)+
1522 clist->column[ctree->tree_column - 1].area.width,
1525 gdk_draw_line (clist->clist_window, clist->xor_gc,
1526 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
1527 ctree->tree_indent * level -
1528 (ctree->tree_indent - PM_SIZE) / 2, y,
1529 allocation.width, y);
1531 case GTK_JUSTIFY_RIGHT:
1532 if (ctree->tree_column < clist->columns - 1)
1533 gdk_draw_line (clist->clist_window, clist->xor_gc,
1534 COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1),
1536 COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) +
1537 clist->column[clist->columns - 1].area.width, y);
1539 gdk_draw_line (clist->clist_window, clist->xor_gc,
1540 0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column)
1541 + clist->column[ctree->tree_column].area.width -
1542 ctree->tree_indent * level +
1543 (ctree->tree_indent - PM_SIZE) / 2, y);
1547 gdk_draw_line (clist->clist_window, clist->xor_gc,
1548 0, y, clist->clist_window_width, y);
1550 case GTK_CMCLIST_DRAG_INTO:
1551 y = ROW_TOP_YPIXEL (clist, dest_row_number) + clist->row_height;
1553 if (clist->column[ctree->tree_column].visible)
1554 switch (clist->column[ctree->tree_column].justification)
1556 case GTK_JUSTIFY_CENTER:
1557 case GTK_JUSTIFY_FILL:
1558 case GTK_JUSTIFY_LEFT:
1559 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
1560 ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2;
1562 points[3].x = points[0].x;
1563 points[3].y = y - clist->row_height - 1;
1564 points[1].x = clist->clist_window_width - 1;
1565 points[1].y = points[0].y;
1566 points[2].x = points[1].x;
1567 points[2].y = points[3].y;
1569 for (i = 0; i < 3; i++)
1570 gdk_draw_line (clist->clist_window, clist->xor_gc,
1571 points[i].x, points[i].y,
1572 points[i+1].x, points[i+1].y);
1574 if (ctree->tree_column > 0)
1576 points[0].x = COLUMN_LEFT_XPIXEL(clist,
1577 ctree->tree_column - 1) +
1578 clist->column[ctree->tree_column - 1].area.width ;
1580 points[3].x = points[0].x;
1581 points[3].y = y - clist->row_height - 1;
1583 points[1].y = points[0].y;
1585 points[2].y = points[3].y;
1587 for (i = 0; i < 3; i++)
1588 gdk_draw_line (clist->clist_window, clist->xor_gc,
1589 points[i].x, points[i].y, points[i+1].x,
1593 case GTK_JUSTIFY_RIGHT:
1594 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) -
1595 ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2 +
1596 clist->column[ctree->tree_column].area.width;
1598 points[3].x = points[0].x;
1599 points[3].y = y - clist->row_height - 1;
1601 points[1].y = points[0].y;
1603 points[2].y = points[3].y;
1605 for (i = 0; i < 3; i++)
1606 gdk_draw_line (clist->clist_window, clist->xor_gc,
1607 points[i].x, points[i].y,
1608 points[i+1].x, points[i+1].y);
1610 if (ctree->tree_column < clist->columns - 1)
1612 points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column +1);
1614 points[3].x = points[0].x;
1615 points[3].y = y - clist->row_height - 1;
1616 points[1].x = clist->clist_window_width - 1;
1617 points[1].y = points[0].y;
1618 points[2].x = points[1].x;
1619 points[2].y = points[3].y;
1621 for (i = 0; i < 3; i++)
1622 gdk_draw_line (clist->clist_window, clist->xor_gc,
1623 points[i].x, points[i].y,
1624 points[i+1].x, points[i+1].y);
1629 gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
1630 0, y - clist->row_height,
1631 clist->clist_window_width - 1, clist->row_height);
1637 gtk_cmctree_get_offset(GtkCMCTree *ctree,
1638 GtkCMCTreeRow *ctree_row,
1640 GdkRectangle *clip_rectangle)
1642 gint justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT);
1645 return (clip_rectangle->x + clip_rectangle->width - 1 -
1646 ctree->tree_indent * (ctree_row->level - 1));
1648 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
1651 static GtkCMCTreeNode *
1652 gtk_cmctree_last_visible (GtkCMCTree *ctree,
1653 GtkCMCTreeNode *node)
1655 GtkCMCTreeNode *work;
1660 work = GTK_CMCTREE_ROW (node)->children;
1662 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1665 while (GTK_CMCTREE_ROW (work)->sibling)
1666 work = GTK_CMCTREE_ROW (work)->sibling;
1668 return gtk_cmctree_last_visible (ctree, work);
1672 gtk_cmctree_link (GtkCMCTree *ctree,
1673 GtkCMCTreeNode *node,
1674 GtkCMCTreeNode *parent,
1675 GtkCMCTreeNode *sibling,
1676 gboolean update_focus_row)
1682 gboolean visible = FALSE;
1686 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1687 cm_return_if_fail (node != NULL);
1688 cm_return_if_fail (node != sibling);
1689 cm_return_if_fail (node != parent);
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 for (rows = 1, list_end = (GList *)node; list_end->next;
1704 list_end = list_end->next)
1707 GTK_CMCTREE_ROW (node)->parent = parent;
1708 GTK_CMCTREE_ROW (node)->sibling = sibling;
1710 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1711 GTK_CMCTREE_ROW (parent)->expanded)))
1714 clist->rows += rows;
1718 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1720 work = clist->row_list;
1724 if (work != (GList *)sibling)
1726 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1727 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1728 GTK_CMCTREE_ROW (work)->sibling = node;
1731 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1732 clist->row_list = (GList *) node;
1733 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1734 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling)
1736 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1737 list->next = (GList *)node;
1740 list = (GList *)node;
1741 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1742 list_end->next = (GList *)sibling;
1743 list = (GList *)sibling;
1744 list->prev = list_end;
1745 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1746 GTK_CMCTREE_ROW (parent)->children = node;
1753 while (GTK_CMCTREE_ROW (work)->sibling)
1754 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1755 GTK_CMCTREE_ROW (work)->sibling = node;
1757 /* find last visible child of sibling */
1758 work = (GList *) gtk_cmctree_last_visible (ctree,
1759 GTK_CMCTREE_NODE (work));
1761 list_end->next = work->next;
1763 list = work->next->prev = list_end;
1764 work->next = (GList *)node;
1765 list = (GList *)node;
1772 GTK_CMCTREE_ROW (parent)->children = node;
1773 list = (GList *)node;
1774 list->prev = (GList *)parent;
1775 if (GTK_CMCTREE_ROW (parent)->expanded)
1777 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1778 if (GTK_CMCTREE_NODE_NEXT(parent))
1780 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1781 list->prev = list_end;
1783 list = (GList *)parent;
1784 list->next = (GList *)node;
1787 list_end->next = NULL;
1791 clist->row_list = (GList *)node;
1792 list = (GList *)node;
1794 list_end->next = NULL;
1799 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL);
1801 if (clist->row_list_end == NULL ||
1802 clist->row_list_end->next == (GList *)node)
1803 clist->row_list_end = list_end;
1805 if (visible && update_focus_row)
1809 pos = g_list_position (clist->row_list, (GList *)node);
1811 if (pos <= clist->focus_row)
1813 clist->focus_row += rows;
1814 clist->undo_anchor = clist->focus_row;
1820 gtk_cmctree_unlink (GtkCMCTree *ctree,
1821 GtkCMCTreeNode *node,
1822 gboolean update_focus_row)
1828 GtkCMCTreeNode *work;
1829 GtkCMCTreeNode *parent;
1832 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1833 cm_return_if_fail (node != NULL);
1835 clist = GTK_CMCLIST (ctree);
1837 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
1839 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1841 g_list_free (clist->undo_selection);
1842 g_list_free (clist->undo_unselection);
1843 clist->undo_selection = NULL;
1844 clist->undo_unselection = NULL;
1847 visible = gtk_cmctree_is_viewable (ctree, node);
1849 /* clist->row_list_end unlinked ? */
1851 (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1852 (GTK_CMCTREE_ROW (node)->children &&
1853 gtk_cmctree_is_ancestor (ctree, node,
1854 GTK_CMCTREE_NODE (clist->row_list_end)))))
1855 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1859 level = GTK_CMCTREE_ROW (node)->level;
1860 work = GTK_CMCTREE_NODE_NEXT (node);
1861 while (work && GTK_CMCTREE_ROW (work)->level > level)
1863 work = GTK_CMCTREE_NODE_NEXT (work);
1869 clist->rows -= (rows + 1);
1871 if (update_focus_row)
1875 pos = g_list_position (clist->row_list, (GList *)node);
1876 if (pos + rows < clist->focus_row)
1877 clist->focus_row -= (rows + 1);
1878 else if (pos <= clist->focus_row)
1880 if (!GTK_CMCTREE_ROW (node)->sibling)
1881 clist->focus_row = MAX (pos - 1, 0);
1883 clist->focus_row = pos;
1885 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1887 clist->undo_anchor = clist->focus_row;
1893 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1895 list = (GList *)work;
1896 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1899 if (GTK_CMCTREE_NODE_PREV (node) &&
1900 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node)
1902 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1903 list->next = (GList *)work;
1907 parent = GTK_CMCTREE_ROW (node)->parent;
1910 if (GTK_CMCTREE_ROW (parent)->children == node)
1912 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1913 if (!GTK_CMCTREE_ROW (parent)->children)
1914 gtk_cmctree_collapse (ctree, parent);
1918 GtkCMCTreeNode *sibling;
1920 sibling = GTK_CMCTREE_ROW (parent)->children;
1921 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1922 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1923 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1928 if (clist->row_list == (GList *)node)
1929 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1932 GtkCMCTreeNode *sibling;
1934 sibling = GTK_CMCTREE_NODE (clist->row_list);
1935 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1936 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1937 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1943 real_row_move (GtkCMCList *clist,
1948 GtkCMCTreeNode *node;
1950 cm_return_if_fail (GTK_IS_CMCTREE (clist));
1952 if (GTK_CMCLIST_AUTO_SORT (clist))
1955 if (source_row < 0 || source_row >= clist->rows ||
1956 dest_row < 0 || dest_row >= clist->rows ||
1957 source_row == dest_row)
1960 ctree = GTK_CMCTREE (clist);
1961 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row));
1963 if (source_row < dest_row)
1965 GtkCMCTreeNode *work;
1968 work = GTK_CMCTREE_ROW (node)->children;
1970 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level)
1972 work = GTK_CMCTREE_NODE_NEXT (work);
1976 if (dest_row > clist->rows)
1977 dest_row = clist->rows;
1980 if (dest_row < clist->rows)
1982 GtkCMCTreeNode *sibling;
1984 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row));
1985 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling);
1988 gtk_cmctree_move (ctree, node, NULL, NULL);
1992 real_tree_move (GtkCMCTree *ctree,
1993 GtkCMCTreeNode *node,
1994 GtkCMCTreeNode *new_parent,
1995 GtkCMCTreeNode *new_sibling)
1998 GtkCMCTreeNode *work;
1999 gboolean visible = FALSE;
2001 cm_return_if_fail (ctree != NULL);
2002 cm_return_if_fail (node != NULL);
2003 cm_return_if_fail (!new_sibling ||
2004 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
2006 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
2009 /* new_parent != child of child */
2010 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
2014 clist = GTK_CMCLIST (ctree);
2016 visible = gtk_cmctree_is_viewable (ctree, node);
2018 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
2020 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2022 g_list_free (clist->undo_selection);
2023 g_list_free (clist->undo_unselection);
2024 clist->undo_selection = NULL;
2025 clist->undo_unselection = NULL;
2028 if (GTK_CMCLIST_AUTO_SORT (clist))
2030 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
2034 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
2036 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
2038 while (new_sibling && clist->compare
2039 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
2040 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
2043 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
2044 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
2047 gtk_cmclist_freeze (clist);
2050 if (gtk_cmctree_is_viewable (ctree, node))
2051 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2053 gtk_cmctree_unlink (ctree, node, FALSE);
2054 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE);
2058 while (work && !gtk_cmctree_is_viewable (ctree, work))
2059 work = GTK_CMCTREE_ROW (work)->parent;
2060 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2061 clist->undo_anchor = clist->focus_row;
2064 if (clist->column[ctree->tree_column].auto_resize &&
2065 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
2066 (visible || gtk_cmctree_is_viewable (ctree, node)))
2067 gtk_cmclist_set_column_width
2068 (clist, ctree->tree_column,
2069 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
2071 gtk_cmclist_thaw (clist);
2075 change_focus_row_expansion (GtkCMCTree *ctree,
2076 GtkCMCTreeExpansionType action)
2079 GtkCMCTreeNode *node;
2081 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2083 clist = GTK_CMCLIST (ctree);
2085 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
2086 gtk_widget_has_grab (GTK_WIDGET(ctree)))
2090 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
2091 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
2096 case GTK_CMCTREE_EXPANSION_EXPAND:
2097 gtk_cmctree_expand (ctree, node);
2099 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
2100 gtk_cmctree_expand_recursive (ctree, node);
2102 case GTK_CMCTREE_EXPANSION_COLLAPSE:
2103 gtk_cmctree_collapse (ctree, node);
2105 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
2106 gtk_cmctree_collapse_recursive (ctree, node);
2108 case GTK_CMCTREE_EXPANSION_TOGGLE:
2109 gtk_cmctree_toggle_expansion (ctree, node);
2111 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
2112 gtk_cmctree_toggle_expansion_recursive (ctree, node);
2118 real_tree_expand (GtkCMCTree *ctree,
2119 GtkCMCTreeNode *node)
2122 GtkCMCTreeNode *work;
2123 GtkRequisition requisition;
2126 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2128 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
2131 clist = GTK_CMCLIST (ctree);
2133 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2135 GTK_CMCTREE_ROW (node)->expanded = TRUE;
2137 visible = gtk_cmctree_is_viewable (ctree, node);
2138 /* get cell width if tree_column is auto resized */
2139 if (visible && clist->column[ctree->tree_column].auto_resize &&
2140 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2141 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2142 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2144 /* unref/unset closed pixbuf */
2145 if (GTK_CMCELL_PIXTEXT
2146 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2150 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2153 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2156 /* set/ref opened pixbuf */
2157 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2160 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2161 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2165 work = GTK_CMCTREE_ROW (node)->children;
2168 GList *list = (GList *)work;
2169 gint *cell_width = NULL;
2174 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2176 cell_width = g_new0 (gint, clist->columns);
2177 if (clist->column[ctree->tree_column].auto_resize)
2178 cell_width[ctree->tree_column] = requisition.width;
2182 /* search maximum cell widths of auto_resize columns */
2183 for (i = 0; i < clist->columns; i++)
2184 if (clist->column[i].auto_resize)
2186 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2187 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
2188 cell_width[i] = MAX (requisition.width, cell_width[i]);
2191 list = (GList *)work;
2192 work = GTK_CMCTREE_NODE_NEXT (work);
2199 list = (GList *)work;
2200 work = GTK_CMCTREE_NODE_NEXT (work);
2204 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2206 if (GTK_CMCTREE_NODE_NEXT (node))
2210 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
2211 tmp_list->prev = list;
2214 clist->row_list_end = list;
2216 list = (GList *)node;
2217 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
2219 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2221 /* resize auto_resize columns if needed */
2222 for (i = 0; i < clist->columns; i++)
2223 if (clist->column[i].auto_resize &&
2224 cell_width[i] > clist->column[i].width)
2225 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
2226 g_free (cell_width);
2228 /* update focus_row position */
2229 row = g_list_position (clist->row_list, (GList *)node);
2230 if (row < clist->focus_row)
2231 clist->focus_row += tmp;
2234 CLIST_REFRESH (clist);
2237 else if (visible && clist->column[ctree->tree_column].auto_resize)
2238 /* resize tree_column if needed */
2239 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2244 real_tree_collapse (GtkCMCTree *ctree,
2245 GtkCMCTreeNode *node)
2248 GtkCMCTreeNode *work;
2249 GtkRequisition requisition;
2253 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2255 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
2256 GTK_CMCTREE_ROW (node)->is_leaf)
2259 clist = GTK_CMCLIST (ctree);
2261 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2263 GTK_CMCTREE_ROW (node)->expanded = FALSE;
2264 level = GTK_CMCTREE_ROW (node)->level;
2266 visible = gtk_cmctree_is_viewable (ctree, node);
2267 /* get cell width if tree_column is auto resized */
2268 if (visible && clist->column[ctree->tree_column].auto_resize &&
2269 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2270 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2271 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
2273 /* unref/unset opened pixbuf */
2274 if (GTK_CMCELL_PIXTEXT
2275 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
2279 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
2282 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
2285 /* set/ref closed pixbuf */
2286 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2289 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
2290 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2293 work = GTK_CMCTREE_ROW (node)->children;
2300 while (work && GTK_CMCTREE_ROW (work)->level > level)
2302 work = GTK_CMCTREE_NODE_NEXT (work);
2308 list = (GList *)node;
2309 list->next = (GList *)work;
2310 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
2312 list = (GList *)work;
2313 list->prev = (GList *)node;
2317 list = (GList *)node;
2319 clist->row_list_end = (GList *)node;
2324 /* resize auto_resize columns if needed */
2325 auto_resize_columns (clist);
2327 row = g_list_position (clist->row_list, (GList *)node);
2328 if (row < clist->focus_row)
2329 clist->focus_row -= tmp;
2331 CLIST_REFRESH (clist);
2334 else if (visible && clist->column[ctree->tree_column].auto_resize &&
2335 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2336 /* resize tree_column if needed */
2337 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
2343 column_auto_resize (GtkCMCList *clist,
2344 GtkCMCListRow *clist_row,
2348 /* resize column if needed for auto_resize */
2349 GtkRequisition requisition;
2351 if (!clist->column[column].auto_resize ||
2352 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2356 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2357 column, &requisition);
2359 requisition.width = 0;
2361 if (requisition.width > clist->column[column].width)
2362 gtk_cmclist_set_column_width (clist, column, requisition.width);
2363 else if (requisition.width < old_width &&
2364 old_width == clist->column[column].width)
2369 /* run a "gtk_cmclist_optimal_column_width" but break, if
2370 * the column doesn't shrink */
2371 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
2374 gtk_widget_get_requisition (clist->column[column].button, &req);
2375 new_width = (req.width -
2376 (CELL_SPACING + (2 * COLUMN_INSET)));
2381 for (list = clist->row_list; list; list = list->next)
2383 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
2384 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
2385 new_width = MAX (new_width, requisition.width);
2386 if (new_width == clist->column[column].width)
2389 if (new_width < clist->column[column].width)
2390 gtk_cmclist_set_column_width (clist, column, new_width);
2395 auto_resize_columns (GtkCMCList *clist)
2399 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2402 for (i = 0; i < clist->columns; i++)
2403 column_auto_resize (clist, NULL, i, clist->column[i].width);
2407 cell_size_request (GtkCMCList *clist,
2408 GtkCMCListRow *clist_row,
2410 GtkRequisition *requisition)
2415 PangoLayout *layout;
2416 PangoRectangle logical_rect;
2418 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2419 cm_return_if_fail (requisition != NULL);
2421 ctree = GTK_CMCTREE (clist);
2423 layout = create_cell_layout (clist, clist_row, column);
2426 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2428 requisition->width = logical_rect.width;
2429 requisition->height = logical_rect.height;
2431 g_object_unref (G_OBJECT (layout));
2435 requisition->width = 0;
2436 requisition->height = 0;
2439 switch (clist_row->cell[column].type)
2441 case GTK_CMCELL_PIXTEXT:
2442 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf)
2444 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2445 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf);
2446 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing;
2451 requisition->width += width;
2452 requisition->height = MAX (requisition->height, height);
2454 if (column == ctree->tree_column)
2456 requisition->width += (ctree->tree_spacing + ctree->tree_indent *
2457 (((GtkCMCTreeRow *) clist_row)->level - 1));
2458 switch (ctree->expander_style)
2460 case GTK_CMCTREE_EXPANDER_NONE:
2462 case GTK_CMCTREE_EXPANDER_TRIANGLE:
2463 requisition->width += PM_SIZE + 3;
2468 case GTK_CMCELL_PIXBUF:
2469 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2470 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf);
2471 requisition->width += width;
2472 requisition->height = MAX (requisition->height, height);
2478 requisition->width += clist_row->cell[column].horizontal;
2479 requisition->height += clist_row->cell[column].vertical;
2483 set_cell_contents (GtkCMCList *clist,
2484 GtkCMCListRow *clist_row,
2491 gboolean visible = FALSE;
2493 GtkRequisition requisition;
2494 gchar *old_text = NULL;
2495 GdkPixbuf *old_pixbuf = NULL;
2497 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2498 cm_return_if_fail (clist_row != NULL);
2500 ctree = GTK_CMCTREE (clist);
2502 if (clist->column[column].auto_resize &&
2503 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2505 GtkCMCTreeNode *parent;
2507 parent = ((GtkCMCTreeRow *)clist_row)->parent;
2508 if ((parent && GTK_CMCTREE_ROW (parent)->expanded &&
2509 gtk_cmctree_is_viewable (ctree, parent)))
2512 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2513 column, &requisition);
2517 switch (clist_row->cell[column].type)
2519 case GTK_CMCELL_EMPTY:
2521 case GTK_CMCELL_TEXT:
2522 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text;
2524 case GTK_CMCELL_PIXBUF:
2525 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf;
2527 case GTK_CMCELL_PIXTEXT:
2528 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text;
2529 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf;
2531 case GTK_CMCELL_WIDGET:
2539 clist_row->cell[column].type = GTK_CMCELL_EMPTY;
2540 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY)
2541 type = GTK_CMCELL_PIXTEXT;
2543 /* Note that pixbuf and mask were already ref'ed by the caller
2547 case GTK_CMCELL_TEXT:
2550 clist_row->cell[column].type = GTK_CMCELL_TEXT;
2551 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2554 case GTK_CMCELL_PIXBUF:
2557 clist_row->cell[column].type = GTK_CMCELL_PIXBUF;
2558 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf;
2561 case GTK_CMCELL_PIXTEXT:
2562 if (column == ctree->tree_column)
2564 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2565 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2567 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2569 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL;
2572 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2576 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = NULL;
2579 else if (text && pixbuf)
2581 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT;
2582 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2583 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2584 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf;
2591 if (visible && clist->column[column].auto_resize &&
2592 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
2593 column_auto_resize (clist, clist_row, column, requisition.width);
2597 g_object_unref (old_pixbuf);
2601 set_node_info (GtkCMCTree *ctree,
2602 GtkCMCTreeNode *node,
2605 GdkPixbuf *pixbuf_closed,
2606 GdkPixbuf *pixbuf_opened,
2610 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
2612 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
2614 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
2616 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
2619 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
2620 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
2624 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
2628 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
2631 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
2632 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
2634 if (GTK_CMCTREE_ROW (node)->expanded)
2635 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2636 text, spacing, pixbuf_opened);
2638 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
2639 text, spacing, pixbuf_closed);
2643 tree_delete (GtkCMCTree *ctree,
2644 GtkCMCTreeNode *node,
2647 tree_unselect (ctree, node, NULL);
2648 row_delete (ctree, GTK_CMCTREE_ROW (node));
2649 g_list_free_1 ((GList *)node);
2653 tree_delete_row (GtkCMCTree *ctree,
2654 GtkCMCTreeNode *node,
2657 row_delete (ctree, GTK_CMCTREE_ROW (node));
2658 g_list_free_1 ((GList *)node);
2662 tree_update_level (GtkCMCTree *ctree,
2663 GtkCMCTreeNode *node,
2669 if (GTK_CMCTREE_ROW (node)->parent)
2670 GTK_CMCTREE_ROW (node)->level =
2671 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
2673 GTK_CMCTREE_ROW (node)->level = 1;
2677 tree_select (GtkCMCTree *ctree,
2678 GtkCMCTreeNode *node,
2681 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
2682 GTK_CMCTREE_ROW (node)->row.selectable)
2683 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
2688 tree_unselect (GtkCMCTree *ctree,
2689 GtkCMCTreeNode *node,
2692 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
2693 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
2698 tree_expand (GtkCMCTree *ctree,
2699 GtkCMCTreeNode *node,
2702 if (node && !GTK_CMCTREE_ROW (node)->expanded)
2703 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2707 tree_collapse (GtkCMCTree *ctree,
2708 GtkCMCTreeNode *node,
2711 if (node && GTK_CMCTREE_ROW (node)->expanded)
2712 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2716 tree_collapse_to_depth (GtkCMCTree *ctree,
2717 GtkCMCTreeNode *node,
2720 if (node && GTK_CMCTREE_ROW (node)->level == depth)
2721 gtk_cmctree_collapse_recursive (ctree, node);
2725 tree_toggle_expansion (GtkCMCTree *ctree,
2726 GtkCMCTreeNode *node,
2732 if (GTK_CMCTREE_ROW (node)->expanded)
2733 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node);
2735 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node);
2738 static GtkCMCTreeRow *
2739 row_new (GtkCMCTree *ctree)
2742 GtkCMCTreeRow *ctree_row;
2745 clist = GTK_CMCLIST (ctree);
2746 #if GLIB_CHECK_VERSION(2,10,0)
2747 ctree_row = g_slice_new (GtkCMCTreeRow);
2748 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
2750 ctree_row = g_chunk_new (GtkCMCTreeRow, (GMemChunk *)clist->row_mem_chunk);
2751 ctree_row->row.cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk);
2754 for (i = 0; i < clist->columns; i++)
2756 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
2757 ctree_row->row.cell[i].vertical = 0;
2758 ctree_row->row.cell[i].horizontal = 0;
2759 ctree_row->row.cell[i].style = NULL;
2761 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
2763 ctree_row->row.fg_set = FALSE;
2764 ctree_row->row.bg_set = FALSE;
2765 ctree_row->row.style = NULL;
2766 ctree_row->row.selectable = TRUE;
2767 ctree_row->row.state = GTK_STATE_NORMAL;
2768 ctree_row->row.data = NULL;
2769 ctree_row->row.destroy = NULL;
2771 ctree_row->level = 0;
2772 ctree_row->expanded = FALSE;
2773 ctree_row->parent = NULL;
2774 ctree_row->sibling = NULL;
2775 ctree_row->children = NULL;
2776 ctree_row->pixbuf_closed = NULL;
2777 ctree_row->pixbuf_opened = NULL;
2783 row_delete (GtkCMCTree *ctree,
2784 GtkCMCTreeRow *ctree_row)
2789 clist = GTK_CMCLIST (ctree);
2791 for (i = 0; i < clist->columns; i++)
2793 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
2794 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
2795 if (ctree_row->row.cell[i].style)
2797 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2798 gtk_style_detach (ctree_row->row.cell[i].style);
2799 g_object_unref (ctree_row->row.cell[i].style);
2803 if (ctree_row->row.style)
2805 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
2806 gtk_style_detach (ctree_row->row.style);
2807 g_object_unref (ctree_row->row.style);
2810 if (ctree_row->pixbuf_closed)
2812 g_object_unref (ctree_row->pixbuf_closed);
2815 if (ctree_row->pixbuf_opened)
2817 g_object_unref (ctree_row->pixbuf_opened);
2820 if (ctree_row->row.destroy)
2822 GDestroyNotify dnotify = ctree_row->row.destroy;
2823 gpointer ddata = ctree_row->row.data;
2825 ctree_row->row.destroy = NULL;
2826 ctree_row->row.data = NULL;
2831 #if GLIB_CHECK_VERSION(2,10,0)
2832 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
2833 g_slice_free (GtkCMCTreeRow, ctree_row);
2835 g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
2836 g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
2841 real_select_row (GtkCMCList *clist,
2848 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2850 if ((node = g_list_nth (clist->row_list, row)) &&
2851 GTK_CMCTREE_ROW (node)->row.selectable)
2852 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0,
2857 real_unselect_row (GtkCMCList *clist,
2864 cm_return_if_fail (GTK_IS_CMCTREE (clist));
2866 if ((node = g_list_nth (clist->row_list, row)))
2867 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0,
2872 tree_draw_node (GtkCMCTree *ctree,
2873 GtkCMCTreeNode *node)
2877 clist = GTK_CMCLIST (ctree);
2879 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node))
2881 GtkCMCTreeNode *work;
2884 work = GTK_CMCTREE_NODE (clist->row_list);
2885 while (work && work != node)
2887 work = GTK_CMCTREE_NODE_NEXT (work);
2890 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2891 GTK_CMCLIST_GET_CLASS(ctree)->draw_row
2892 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node));
2897 real_tree_select (GtkCMCTree *ctree,
2898 GtkCMCTreeNode *node,
2903 GtkCMCTreeNode *sel_row;
2904 gboolean node_selected;
2906 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2908 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2909 !GTK_CMCTREE_ROW (node)->row.selectable)
2912 clist = GTK_CMCLIST (ctree);
2914 switch (clist->selection_mode)
2916 case GTK_SELECTION_SINGLE:
2917 case GTK_SELECTION_BROWSE:
2919 node_selected = FALSE;
2920 list = clist->selection;
2924 sel_row = list->data;
2927 if (node == sel_row)
2928 node_selected = TRUE;
2930 g_signal_emit (G_OBJECT (ctree),
2931 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column);
2941 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
2943 if (!clist->selection)
2945 clist->selection = g_list_append (clist->selection, node);
2946 clist->selection_end = clist->selection;
2949 clist->selection_end = g_list_append (clist->selection_end, node)->next;
2951 tree_draw_node (ctree, node);
2955 real_tree_unselect (GtkCMCTree *ctree,
2956 GtkCMCTreeNode *node,
2961 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
2963 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
2966 clist = GTK_CMCLIST (ctree);
2968 if (clist->selection_end && clist->selection_end->data == node)
2969 clist->selection_end = clist->selection_end->prev;
2971 clist->selection = g_list_remove (clist->selection, node);
2973 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
2975 tree_draw_node (ctree, node);
2979 select_row_recursive (GtkCMCTree *ctree,
2980 GtkCMCTreeNode *node,
2983 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
2984 !GTK_CMCTREE_ROW (node)->row.selectable)
2987 GTK_CMCLIST (ctree)->undo_unselection =
2988 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node);
2989 gtk_cmctree_select (ctree, node);
2993 real_select_all (GtkCMCList *clist)
2996 GtkCMCTreeNode *node;
2998 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3000 ctree = GTK_CMCTREE (clist);
3002 switch (clist->selection_mode)
3004 case GTK_SELECTION_SINGLE:
3005 case GTK_SELECTION_BROWSE:
3008 case GTK_SELECTION_MULTIPLE:
3010 gtk_cmclist_freeze (clist);
3012 g_list_free (clist->undo_selection);
3013 g_list_free (clist->undo_unselection);
3014 clist->undo_selection = NULL;
3015 clist->undo_unselection = NULL;
3017 clist->anchor_state = GTK_STATE_SELECTED;
3019 clist->drag_pos = -1;
3020 clist->undo_anchor = clist->focus_row;
3022 for (node = GTK_CMCTREE_NODE (clist->row_list); node;
3023 node = GTK_CMCTREE_NODE_NEXT (node))
3024 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL);
3026 gtk_cmclist_thaw (clist);
3036 real_unselect_all (GtkCMCList *clist)
3039 GtkCMCTreeNode *node;
3042 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3044 ctree = GTK_CMCTREE (clist);
3046 switch (clist->selection_mode)
3048 case GTK_SELECTION_BROWSE:
3049 if (clist->focus_row >= 0)
3053 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
3058 case GTK_SELECTION_MULTIPLE:
3059 g_list_free (clist->undo_selection);
3060 g_list_free (clist->undo_unselection);
3061 clist->undo_selection = NULL;
3062 clist->undo_unselection = NULL;
3065 clist->drag_pos = -1;
3066 clist->undo_anchor = clist->focus_row;
3073 list = clist->selection;
3079 gtk_cmctree_unselect (ctree, node);
3084 ctree_is_hot_spot (GtkCMCTree *ctree,
3085 GtkCMCTreeNode *node,
3090 GtkCMCTreeRow *tree_row;
3095 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3096 cm_return_val_if_fail (node != NULL, FALSE);
3098 clist = GTK_CMCLIST (ctree);
3100 if (!clist->column[ctree->tree_column].visible ||
3101 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
3104 tree_row = GTK_CMCTREE_ROW (node);
3106 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
3107 (clist->row_height - 1) % 2);
3109 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
3110 xl = (clist->column[ctree->tree_column].area.x +
3111 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
3112 (tree_row->level - 1) * ctree->tree_indent - PM_SIZE);
3114 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
3115 (tree_row->level - 1) * ctree->tree_indent);
3117 return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
3120 /***********************************************************
3121 ***********************************************************
3122 *** Public interface ***
3123 ***********************************************************
3124 ***********************************************************/
3127 /***********************************************************
3128 * Creation, insertion, deletion *
3129 ***********************************************************/
3132 gtk_cmctree_constructor (GType type,
3133 guint n_construct_properties,
3134 GObjectConstructParam *construct_properties)
3136 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
3137 n_construct_properties,
3138 construct_properties);
3144 gtk_cmctree_new_with_titles (gint columns,
3150 cm_return_val_if_fail (columns > 0, NULL);
3151 cm_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3153 widget = gtk_widget_new (GTK_TYPE_CMCTREE,
3154 "n_columns", columns,
3155 "tree_column", tree_column,
3159 GtkCMCList *clist = GTK_CMCLIST (widget);
3162 for (i = 0; i < columns; i++)
3163 gtk_cmclist_set_column_title (clist, i, titles[i]);
3164 gtk_cmclist_column_titles_show (clist);
3171 gtk_cmctree_new (gint columns,
3174 return gtk_cmctree_new_with_titles (columns, tree_column, NULL);
3178 real_insert_row (GtkCMCList *clist,
3182 GtkCMCTreeNode *parent = NULL;
3183 GtkCMCTreeNode *sibling;
3184 GtkCMCTreeNode *node;
3186 cm_return_val_if_fail (GTK_IS_CMCTREE (clist), -1);
3188 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3190 parent = GTK_CMCTREE_ROW (sibling)->parent;
3192 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5,
3193 NULL, NULL, TRUE, FALSE);
3195 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling)
3196 return g_list_position (clist->row_list, (GList *) node);
3202 gtk_cmctree_insert_node (GtkCMCTree *ctree,
3203 GtkCMCTreeNode *parent,
3204 GtkCMCTreeNode *sibling,
3207 GdkPixbuf *pixbuf_closed,
3208 GdkPixbuf *pixbuf_opened,
3213 GtkCMCTreeRow *new_row;
3214 GtkCMCTreeNode *node;
3218 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3220 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3222 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
3225 clist = GTK_CMCLIST (ctree);
3227 /* create the row */
3228 new_row = row_new (ctree);
3229 list = g_list_alloc ();
3230 list->data = new_row;
3231 node = GTK_CMCTREE_NODE (list);
3234 for (i = 0; i < clist->columns; i++)
3235 if (text[i] && i != ctree->tree_column)
3236 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
3237 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
3239 set_node_info (ctree, node, text ?
3240 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
3241 pixbuf_opened, is_leaf, expanded);
3243 /* sorted insertion */
3244 if (GTK_CMCLIST_AUTO_SORT (clist))
3247 sibling = GTK_CMCTREE_ROW (parent)->children;
3249 sibling = GTK_CMCTREE_NODE (clist->row_list);
3251 while (sibling && clist->compare
3252 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
3253 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3256 gtk_cmctree_link (ctree, node, parent, sibling, TRUE);
3258 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
3259 gtk_cmctree_is_viewable (ctree, node))
3261 for (i = 0; i < clist->columns; i++)
3262 if (clist->column[i].auto_resize)
3263 column_auto_resize (clist, &(new_row->row), i, 0);
3266 if (clist->rows == 1)
3268 clist->focus_row = 0;
3269 if (clist->selection_mode == GTK_SELECTION_BROWSE)
3270 gtk_cmctree_select (ctree, node);
3274 CLIST_REFRESH (clist);
3280 gtk_cmctree_insert_gnode (GtkCMCTree *ctree,
3281 GtkCMCTreeNode *parent,
3282 GtkCMCTreeNode *sibling,
3284 GtkCMCTreeGNodeFunc func,
3288 GtkCMCTreeNode *cnode = NULL;
3289 GtkCMCTreeNode *child = NULL;
3290 GtkCMCTreeNode *new_child;
3295 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3296 cm_return_val_if_fail (gnode != NULL, NULL);
3297 cm_return_val_if_fail (func != NULL, NULL);
3299 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
3301 clist = GTK_CMCLIST (ctree);
3304 depth = GTK_CMCTREE_ROW (parent)->level + 1;
3306 list = g_list_alloc ();
3307 list->data = row_new (ctree);
3308 cnode = GTK_CMCTREE_NODE (list);
3310 gtk_cmclist_freeze (clist);
3312 set_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
3314 if (!func (ctree, depth, gnode, cnode, data))
3316 tree_delete_row (ctree, cnode, NULL);
3317 gtk_cmclist_thaw (clist);
3321 if (GTK_CMCLIST_AUTO_SORT (clist))
3324 sibling = GTK_CMCTREE_ROW (parent)->children;
3326 sibling = GTK_CMCTREE_NODE (clist->row_list);
3328 while (sibling && clist->compare
3329 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
3330 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
3333 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE);
3335 for (work = g_node_last_child (gnode); work; work = work->prev)
3337 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child,
3343 gtk_cmclist_thaw (clist);
3349 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree,
3352 GtkCMCTreeNode *node,
3353 GtkCMCTreeGNodeFunc func,
3356 GtkCMCTreeNode *work;
3360 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3361 cm_return_val_if_fail (node != NULL, NULL);
3362 cm_return_val_if_fail (func != NULL, NULL);
3365 cm_return_val_if_fail (parent != NULL, NULL);
3366 cm_return_val_if_fail (sibling->parent == parent, NULL);
3369 gnode = g_node_new (NULL);
3370 depth = g_node_depth (parent) + 1;
3372 if (!func (ctree, depth, gnode, node, data))
3374 g_node_destroy (gnode);
3379 g_node_insert_before (parent, sibling, gnode);
3381 if (!GTK_CMCTREE_ROW (node)->is_leaf)
3383 GNode *new_sibling = NULL;
3385 for (work = GTK_CMCTREE_ROW (node)->children; work;
3386 work = GTK_CMCTREE_ROW (work)->sibling)
3387 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling,
3390 g_node_reverse_children (gnode);
3397 real_remove_row (GtkCMCList *clist,
3400 GtkCMCTreeNode *node;
3402 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3404 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row));
3407 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node);
3411 gtk_cmctree_remove_node (GtkCMCTree *ctree,
3412 GtkCMCTreeNode *node)
3416 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3418 clist = GTK_CMCLIST (ctree);
3420 gtk_cmclist_freeze (clist);
3424 gtk_cmctree_unlink (ctree, node, TRUE);
3425 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete),
3427 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3428 clist->focus_row >= 0)
3429 gtk_cmclist_select_row (clist, clist->focus_row, -1);
3431 auto_resize_columns (clist);
3434 gtk_cmclist_clear (clist);
3436 gtk_cmclist_thaw (clist);
3440 real_clear (GtkCMCList *clist)
3443 GtkCMCTreeNode *work;
3444 GtkCMCTreeNode *ptr;
3446 cm_return_if_fail (GTK_IS_CMCTREE (clist));
3448 ctree = GTK_CMCTREE (clist);
3450 /* remove all rows */
3451 work = GTK_CMCTREE_NODE (clist->row_list);
3452 clist->row_list = NULL;
3453 clist->row_list_end = NULL;
3455 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3459 work = GTK_CMCTREE_ROW (work)->sibling;
3460 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row),
3463 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3465 parent_class->clear (clist);
3469 /***********************************************************
3470 * Generic recursive functions, querying / finding tree *
3472 ***********************************************************/
3476 gtk_cmctree_post_recursive (GtkCMCTree *ctree,
3477 GtkCMCTreeNode *node,
3478 GtkCMCTreeFunc func,
3481 GtkCMCTreeNode *work;
3482 GtkCMCTreeNode *tmp;
3484 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3485 cm_return_if_fail (func != NULL);
3488 work = GTK_CMCTREE_ROW (node)->children;
3490 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3494 tmp = GTK_CMCTREE_ROW (work)->sibling;
3495 gtk_cmctree_post_recursive (ctree, work, func, data);
3500 func (ctree, node, data);
3504 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree,
3505 GtkCMCTreeNode *node,
3507 GtkCMCTreeFunc func,
3510 GtkCMCTreeNode *work;
3511 GtkCMCTreeNode *tmp;
3513 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3514 cm_return_if_fail (func != NULL);
3518 gtk_cmctree_post_recursive (ctree, node, func, data);
3523 work = GTK_CMCTREE_ROW (node)->children;
3525 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3527 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3531 tmp = GTK_CMCTREE_ROW (work)->sibling;
3532 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data);
3537 if (node && GTK_CMCTREE_ROW (node)->level <= depth)
3538 func (ctree, node, data);
3542 gtk_cmctree_pre_recursive (GtkCMCTree *ctree,
3543 GtkCMCTreeNode *node,
3544 GtkCMCTreeFunc func,
3547 GtkCMCTreeNode *work;
3548 GtkCMCTreeNode *tmp;
3550 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3551 cm_return_if_fail (func != NULL);
3555 work = GTK_CMCTREE_ROW (node)->children;
3556 func (ctree, node, data);
3559 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3563 tmp = GTK_CMCTREE_ROW (work)->sibling;
3564 gtk_cmctree_pre_recursive (ctree, work, func, data);
3570 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree,
3571 GtkCMCTreeNode *node,
3573 GtkCMCTreeFunc func,
3576 GtkCMCTreeNode *work;
3577 GtkCMCTreeNode *tmp;
3579 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3580 cm_return_if_fail (func != NULL);
3584 gtk_cmctree_pre_recursive (ctree, node, func, data);
3590 work = GTK_CMCTREE_ROW (node)->children;
3591 if (GTK_CMCTREE_ROW (node)->level <= depth)
3592 func (ctree, node, data);
3595 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3597 if (work && GTK_CMCTREE_ROW (work)->level <= depth)
3601 tmp = GTK_CMCTREE_ROW (work)->sibling;
3602 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data);
3609 gtk_cmctree_is_viewable (GtkCMCTree *ctree,
3610 GtkCMCTreeNode *node)
3612 GtkCMCTreeRow *work;
3614 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3615 cm_return_val_if_fail (node != NULL, FALSE);
3617 work = GTK_CMCTREE_ROW (node);
3619 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded)
3620 work = GTK_CMCTREE_ROW (work->parent);
3629 gtk_cmctree_last (GtkCMCTree *ctree,
3630 GtkCMCTreeNode *node)
3632 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3637 while (GTK_CMCTREE_ROW (node)->sibling)
3638 node = GTK_CMCTREE_ROW (node)->sibling;
3640 if (GTK_CMCTREE_ROW (node)->children)
3641 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children);
3647 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree,
3648 GtkCMCTreeRow *ctree_row)
3650 GtkCMCTreeNode *node;
3652 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3653 cm_return_val_if_fail (ctree_row != NULL, NULL);
3655 if (ctree_row->parent)
3656 node = GTK_CMCTREE_ROW (ctree_row->parent)->children;
3658 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3660 while (GTK_CMCTREE_ROW (node) != ctree_row)
3661 node = GTK_CMCTREE_ROW (node)->sibling;
3667 gtk_cmctree_node_nth (GtkCMCTree *ctree,
3670 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3672 if ((row >= GTK_CMCLIST(ctree)->rows))
3675 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row));
3679 gtk_cmctree_find (GtkCMCTree *ctree,
3680 GtkCMCTreeNode *node,
3681 GtkCMCTreeNode *child)
3687 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3693 if (GTK_CMCTREE_ROW (node)->children)
3695 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child))
3698 node = GTK_CMCTREE_ROW (node)->sibling;
3704 gtk_cmctree_is_ancestor (GtkCMCTree *ctree,
3705 GtkCMCTreeNode *node,
3706 GtkCMCTreeNode *child)
3708 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3709 cm_return_val_if_fail (node != NULL, FALSE);
3711 if (GTK_CMCTREE_ROW (node)->children)
3712 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child);
3718 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree,
3719 GtkCMCTreeNode *node,
3722 GtkCMCTreeNode *work;
3725 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3729 if (GTK_CMCTREE_ROW (node)->row.data == data)
3731 if (GTK_CMCTREE_ROW (node)->children &&
3732 (work = gtk_cmctree_find_by_row_data
3733 (ctree, GTK_CMCTREE_ROW (node)->children, data)))
3735 node = GTK_CMCTREE_ROW (node)->sibling;
3741 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree,
3742 GtkCMCTreeNode *node,
3747 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3749 /* if node == NULL then look in the whole tree */
3751 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3755 if (GTK_CMCTREE_ROW (node)->row.data == data)
3756 list = g_list_append (list, node);
3758 if (GTK_CMCTREE_ROW (node)->children)
3762 sub_list = gtk_cmctree_find_all_by_row_data (ctree,
3766 list = g_list_concat (list, sub_list);
3768 node = GTK_CMCTREE_ROW (node)->sibling;
3774 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree,
3775 GtkCMCTreeNode *node,
3779 GtkCMCTreeNode *work;
3781 cm_return_val_if_fail (func != NULL, NULL);
3784 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3788 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3790 if (GTK_CMCTREE_ROW (node)->children &&
3791 (work = gtk_cmctree_find_by_row_data_custom
3792 (ctree, GTK_CMCTREE_ROW (node)->children, data, func)))
3794 node = GTK_CMCTREE_ROW (node)->sibling;
3800 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree,
3801 GtkCMCTreeNode *node,
3807 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
3808 cm_return_val_if_fail (func != NULL, NULL);
3810 /* if node == NULL then look in the whole tree */
3812 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list);
3816 if (!func (GTK_CMCTREE_ROW (node)->row.data, data))
3817 list = g_list_append (list, node);
3819 if (GTK_CMCTREE_ROW (node)->children)
3823 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree,
3828 list = g_list_concat (list, sub_list);
3830 node = GTK_CMCTREE_ROW (node)->sibling;
3836 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree,
3840 GtkCMCTreeNode *node;
3844 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
3846 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
3847 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
3848 return ctree_is_hot_spot (ctree, node, row, x, y);
3854 /***********************************************************
3855 * Tree signals : move, expand, collapse, (un)select *
3856 ***********************************************************/
3860 gtk_cmctree_move (GtkCMCTree *ctree,
3861 GtkCMCTreeNode *node,
3862 GtkCMCTreeNode *new_parent,
3863 GtkCMCTreeNode *new_sibling)
3865 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3866 cm_return_if_fail (node != NULL);
3868 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node,
3869 new_parent, new_sibling);
3873 gtk_cmctree_expand (GtkCMCTree *ctree,
3874 GtkCMCTreeNode *node)
3876 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3877 cm_return_if_fail (node != NULL);
3879 if (GTK_CMCTREE_ROW (node)->is_leaf)
3882 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node);
3886 gtk_cmctree_expand_recursive (GtkCMCTree *ctree,
3887 GtkCMCTreeNode *node)
3890 gboolean thaw = FALSE;
3892 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3894 clist = GTK_CMCLIST (ctree);
3896 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3899 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3901 gtk_cmclist_freeze (clist);
3905 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL);
3908 gtk_cmclist_thaw (clist);
3912 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree,
3913 GtkCMCTreeNode *node,
3917 gboolean thaw = FALSE;
3919 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3921 clist = GTK_CMCLIST (ctree);
3923 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3926 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3928 gtk_cmclist_freeze (clist);
3932 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
3933 GTK_CMCTREE_FUNC (tree_expand), NULL);
3936 gtk_cmclist_thaw (clist);
3940 gtk_cmctree_collapse (GtkCMCTree *ctree,
3941 GtkCMCTreeNode *node)
3943 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3944 cm_return_if_fail (node != NULL);
3946 if (GTK_CMCTREE_ROW (node)->is_leaf)
3949 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node);
3953 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree,
3954 GtkCMCTreeNode *node)
3957 gboolean thaw = FALSE;
3960 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3962 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3965 clist = GTK_CMCLIST (ctree);
3967 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
3969 gtk_cmclist_freeze (clist);
3973 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3974 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL);
3975 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
3976 for (i = 0; i < clist->columns; i++)
3977 if (clist->column[i].auto_resize)
3978 gtk_cmclist_set_column_width (clist, i,
3979 gtk_cmclist_optimal_column_width (clist, i));
3982 gtk_cmclist_thaw (clist);
3986 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree,
3987 GtkCMCTreeNode *node,
3991 gboolean thaw = FALSE;
3994 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
3996 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
3999 clist = GTK_CMCLIST (ctree);
4001 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4003 gtk_cmclist_freeze (clist);
4007 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4008 gtk_cmctree_post_recursive_to_depth (ctree, node, depth,
4009 GTK_CMCTREE_FUNC (tree_collapse_to_depth),
4010 GINT_TO_POINTER (depth));
4011 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED);
4012 for (i = 0; i < clist->columns; i++)
4013 if (clist->column[i].auto_resize)
4014 gtk_cmclist_set_column_width (clist, i,
4015 gtk_cmclist_optimal_column_width (clist, i));
4018 gtk_cmclist_thaw (clist);
4022 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree,
4023 GtkCMCTreeNode *node)
4025 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4026 cm_return_if_fail (node != NULL);
4028 if (GTK_CMCTREE_ROW (node)->is_leaf)
4031 tree_toggle_expansion (ctree, node, NULL);
4035 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree,
4036 GtkCMCTreeNode *node)
4039 gboolean thaw = FALSE;
4041 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4043 if (node && GTK_CMCTREE_ROW (node)->is_leaf)
4046 clist = GTK_CMCLIST (ctree);
4048 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4050 gtk_cmclist_freeze (clist);
4054 gtk_cmctree_post_recursive (ctree, node,
4055 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL);
4058 gtk_cmclist_thaw (clist);
4062 gtk_cmctree_select (GtkCMCTree *ctree,
4063 GtkCMCTreeNode *node)
4065 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4066 cm_return_if_fail (node != NULL);
4068 if (GTK_CMCTREE_ROW (node)->row.selectable)
4069 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0,
4074 gtk_cmctree_unselect (GtkCMCTree *ctree,
4075 GtkCMCTreeNode *node)
4077 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4078 cm_return_if_fail (node != NULL);
4080 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0,
4085 gtk_cmctree_select_recursive (GtkCMCTree *ctree,
4086 GtkCMCTreeNode *node)
4088 gtk_cmctree_real_select_recursive (ctree, node, TRUE);
4092 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree,
4093 GtkCMCTreeNode *node)
4095 gtk_cmctree_real_select_recursive (ctree, node, FALSE);
4099 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree,
4100 GtkCMCTreeNode *node,
4104 gboolean thaw = FALSE;
4106 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4108 clist = GTK_CMCLIST (ctree);
4111 (clist->selection_mode == GTK_SELECTION_BROWSE ||
4112 clist->selection_mode == GTK_SELECTION_SINGLE)) ||
4113 (!state && clist->selection_mode == GTK_SELECTION_BROWSE))
4116 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node)))
4118 gtk_cmclist_freeze (clist);
4122 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4124 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4126 g_list_free (clist->undo_selection);
4127 g_list_free (clist->undo_unselection);
4128 clist->undo_selection = NULL;
4129 clist->undo_unselection = NULL;
4133 gtk_cmctree_post_recursive (ctree, node,
4134 GTK_CMCTREE_FUNC (tree_select), NULL);
4136 gtk_cmctree_post_recursive (ctree, node,
4137 GTK_CMCTREE_FUNC (tree_unselect), NULL);
4140 gtk_cmclist_thaw (clist);
4144 /***********************************************************
4145 * Analogons of GtkCMCList functions *
4146 ***********************************************************/
4150 gtk_cmctree_node_set_text (GtkCMCTree *ctree,
4151 GtkCMCTreeNode *node,
4157 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4158 cm_return_if_fail (node != NULL);
4160 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4163 clist = GTK_CMCLIST (ctree);
4165 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4166 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT,
4169 tree_draw_node (ctree, node);
4173 gtk_cmctree_node_set_pixbuf (GtkCMCTree *ctree,
4174 GtkCMCTreeNode *node,
4180 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4181 cm_return_if_fail (node != NULL);
4182 cm_return_if_fail (pixbuf != NULL);
4184 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4187 g_object_ref (pixbuf);
4189 clist = GTK_CMCLIST (ctree);
4191 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4192 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXBUF,
4195 tree_draw_node (ctree, node);
4199 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree,
4200 GtkCMCTreeNode *node,
4208 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4209 cm_return_if_fail (node != NULL);
4210 if (column != ctree->tree_column)
4211 cm_return_if_fail (pixbuf != NULL);
4212 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4215 clist = GTK_CMCLIST (ctree);
4219 g_object_ref (pixbuf);
4222 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
4223 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT,
4224 text, spacing, pixbuf);
4226 tree_draw_node (ctree, node);
4230 gtk_cmctree_set_node_info (GtkCMCTree *ctree,
4231 GtkCMCTreeNode *node,
4234 GdkPixbuf *pixbuf_closed,
4235 GdkPixbuf *pixbuf_opened,
4240 gboolean old_expanded;
4242 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4243 cm_return_if_fail (node != NULL);
4245 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4246 old_expanded = GTK_CMCTREE_ROW (node)->expanded;
4248 if (is_leaf && GTK_CMCTREE_ROW (node)->children)
4250 GtkCMCTreeNode *work;
4251 GtkCMCTreeNode *ptr;
4253 work = GTK_CMCTREE_ROW (node)->children;
4257 work = GTK_CMCTREE_ROW (work)->sibling;
4258 gtk_cmctree_remove_node (ctree, ptr);
4262 set_node_info (ctree, node, text, spacing, pixbuf_closed,
4263 pixbuf_opened, is_leaf, expanded);
4265 if (!is_leaf && !old_leaf)
4267 GTK_CMCTREE_ROW (node)->expanded = old_expanded;
4268 if (expanded && !old_expanded)
4269 gtk_cmctree_expand (ctree, node);
4270 else if (!expanded && old_expanded)
4271 gtk_cmctree_collapse (ctree, node);
4274 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4276 tree_draw_node (ctree, node);
4280 gtk_cmctree_node_set_shift (GtkCMCTree *ctree,
4281 GtkCMCTreeNode *node,
4287 GtkRequisition requisition;
4288 gboolean visible = FALSE;
4290 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4291 cm_return_if_fail (node != NULL);
4293 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4296 clist = GTK_CMCLIST (ctree);
4298 if (clist->column[column].auto_resize &&
4299 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4301 visible = gtk_cmctree_is_viewable (ctree, node);
4303 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4304 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4307 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical;
4308 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4311 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row,
4312 column, requisition.width);
4314 tree_draw_node (ctree, node);
4318 remove_grab (GtkCMCList *clist)
4320 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4321 gtk_widget_has_grab (GTK_WIDGET(clist)))
4323 gtk_grab_remove (GTK_WIDGET (clist));
4324 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4330 g_source_remove (clist->htimer);
4336 g_source_remove (clist->vtimer);
4342 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree,
4343 GtkCMCTreeNode *node,
4344 gboolean selectable)
4346 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4347 cm_return_if_fail (node != NULL);
4349 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable)
4352 GTK_CMCTREE_ROW (node)->row.selectable = selectable;
4354 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4358 clist = GTK_CMCLIST (ctree);
4360 if (clist->anchor >= 0 &&
4361 clist->selection_mode == GTK_SELECTION_MULTIPLE)
4363 clist->drag_button = 0;
4364 remove_grab (clist);
4366 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4368 gtk_cmctree_unselect (ctree, node);
4373 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree,
4374 GtkCMCTreeNode *node)
4376 cm_return_val_if_fail (node != NULL, FALSE);
4378 return GTK_CMCTREE_ROW (node)->row.selectable;
4382 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree,
4383 GtkCMCTreeNode *node,
4386 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1);
4387 cm_return_val_if_fail (node != NULL, -1);
4389 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4392 return GTK_CMCTREE_ROW (node)->row.cell[column].type;
4396 gtk_cmctree_node_get_text (GtkCMCTree *ctree,
4397 GtkCMCTreeNode *node,
4401 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4402 cm_return_val_if_fail (node != NULL, FALSE);
4404 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4407 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT)
4411 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4417 gtk_cmctree_node_get_pixbuf (GtkCMCTree *ctree,
4418 GtkCMCTreeNode *node,
4422 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4423 cm_return_val_if_fail (node != NULL, FALSE);
4425 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4428 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXBUF)
4432 *pixbuf = GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node)->row.cell[column])->pixbuf;
4438 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree,
4439 GtkCMCTreeNode *node,
4445 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4446 cm_return_val_if_fail (node != NULL, FALSE);
4448 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4451 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT)
4455 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text;
4457 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4458 (node)->row.cell[column])->spacing;
4460 *pixbuf = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4461 (node)->row.cell[column])->pixbuf;
4467 gtk_cmctree_get_node_info (GtkCMCTree *ctree,
4468 GtkCMCTreeNode *node,
4471 GdkPixbuf **pixbuf_closed,
4472 GdkPixbuf **pixbuf_opened,
4476 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
4477 cm_return_val_if_fail (node != NULL, FALSE);
4480 *text = GTK_CMCELL_PIXTEXT
4481 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4483 *spacing = GTK_CMCELL_PIXTEXT
4484 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4486 *pixbuf_closed = GTK_CMCTREE_ROW (node)->pixbuf_closed;
4488 *pixbuf_opened = GTK_CMCTREE_ROW (node)->pixbuf_opened;
4490 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf;
4492 *expanded = GTK_CMCTREE_ROW (node)->expanded;
4498 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree,
4499 GtkCMCTreeNode *node,
4504 GtkRequisition requisition;
4505 gboolean visible = FALSE;
4507 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4508 cm_return_if_fail (node != NULL);
4510 clist = GTK_CMCLIST (ctree);
4512 if (column < 0 || column >= clist->columns)
4515 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style)
4518 if (clist->column[column].auto_resize &&
4519 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4521 visible = gtk_cmctree_is_viewable (ctree, node);
4523 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4524 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition);
4527 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4529 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4530 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4531 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4534 GTK_CMCTREE_ROW (node)->row.cell[column].style = style;
4536 if (GTK_CMCTREE_ROW (node)->row.cell[column].style)
4538 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style);
4540 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4541 GTK_CMCTREE_ROW (node)->row.cell[column].style =
4542 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style,
4543 clist->clist_window);
4547 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column,
4550 tree_draw_node (ctree, node);
4554 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree,
4555 GtkCMCTreeNode *node,
4558 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4559 cm_return_val_if_fail (node != NULL, NULL);
4561 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns)
4564 return GTK_CMCTREE_ROW (node)->row.cell[column].style;
4568 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree,
4569 GtkCMCTreeNode *node,
4573 GtkRequisition requisition;
4575 gint *old_width = NULL;
4578 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4579 cm_return_if_fail (node != NULL);
4581 clist = GTK_CMCLIST (ctree);
4583 if (GTK_CMCTREE_ROW (node)->row.style == style)
4586 visible = gtk_cmctree_is_viewable (ctree, node);
4587 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4589 old_width = g_new (gint, clist->columns);
4590 for (i = 0; i < clist->columns; i++)
4591 if (clist->column[i].auto_resize)
4593 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
4594 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition);
4595 old_width[i] = requisition.width;
4599 if (GTK_CMCTREE_ROW (node)->row.style)
4601 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4602 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style);
4603 g_object_unref (GTK_CMCTREE_ROW (node)->row.style);
4606 GTK_CMCTREE_ROW (node)->row.style = style;
4608 if (GTK_CMCTREE_ROW (node)->row.style)
4610 g_object_ref (GTK_CMCTREE_ROW (node)->row.style);
4612 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4613 GTK_CMCTREE_ROW (node)->row.style =
4614 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style,
4615 clist->clist_window);
4618 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4620 for (i = 0; i < clist->columns; i++)
4621 if (clist->column[i].auto_resize)
4622 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i,
4626 tree_draw_node (ctree, node);
4630 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree,
4631 GtkCMCTreeNode *node)
4633 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4634 cm_return_val_if_fail (node != NULL, NULL);
4636 return GTK_CMCTREE_ROW (node)->row.style;
4640 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree,
4641 GtkCMCTreeNode *node,
4642 const GdkColor *color)
4644 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4645 cm_return_if_fail (node != NULL);
4649 GTK_CMCTREE_ROW (node)->row.foreground = *color;
4650 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE;
4651 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4652 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4653 >K_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE);
4656 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE;
4658 tree_draw_node (ctree, node);
4662 gtk_cmctree_node_set_background (GtkCMCTree *ctree,
4663 GtkCMCTreeNode *node,
4664 const GdkColor *color)
4666 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4667 cm_return_if_fail (node != NULL);
4671 GTK_CMCTREE_ROW (node)->row.background = *color;
4672 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE;
4673 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
4674 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
4675 >K_CMCTREE_ROW (node)->row.background, TRUE, TRUE);
4678 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE;
4680 tree_draw_node (ctree, node);
4684 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree,
4685 GtkCMCTreeNode *node,
4688 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL);
4692 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree,
4693 GtkCMCTreeNode *node,
4695 GDestroyNotify destroy)
4697 GDestroyNotify dnotify;
4700 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4701 cm_return_if_fail (node != NULL);
4703 dnotify = GTK_CMCTREE_ROW (node)->row.destroy;
4704 ddata = GTK_CMCTREE_ROW (node)->row.data;
4706 GTK_CMCTREE_ROW (node)->row.data = data;
4707 GTK_CMCTREE_ROW (node)->row.destroy = destroy;
4714 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree,
4715 GtkCMCTreeNode *node)
4717 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
4719 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL;
4723 gtk_cmctree_node_moveto (GtkCMCTree *ctree,
4724 GtkCMCTreeNode *node,
4732 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4734 clist = GTK_CMCLIST (ctree);
4736 while (node && !gtk_cmctree_is_viewable (ctree, node))
4737 node = GTK_CMCTREE_ROW (node)->parent;
4740 row = g_list_position (clist->row_list, (GList *)node);
4742 gtk_cmclist_moveto (clist, row, column, row_align, col_align);
4746 gtk_cmctree_node_is_visible (GtkCMCTree *ctree,
4747 GtkCMCTreeNode *node)
4751 cm_return_val_if_fail (ctree != NULL, 0);
4752 cm_return_val_if_fail (node != NULL, 0);
4754 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node);
4755 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row);
4759 /***********************************************************
4760 * GtkCMCTree specific functions *
4761 ***********************************************************/
4764 gtk_cmctree_set_indent (GtkCMCTree *ctree,
4769 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4770 cm_return_if_fail (indent >= 0);
4772 if (indent == ctree->tree_indent)
4775 clist = GTK_CMCLIST (ctree);
4776 ctree->tree_indent = indent;
4778 if (clist->column[ctree->tree_column].auto_resize &&
4779 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4780 gtk_cmclist_set_column_width
4781 (clist, ctree->tree_column,
4782 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
4784 CLIST_REFRESH (ctree);
4788 gtk_cmctree_set_spacing (GtkCMCTree *ctree,
4794 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4795 cm_return_if_fail (spacing >= 0);
4797 if (spacing == ctree->tree_spacing)
4800 clist = GTK_CMCLIST (ctree);
4802 old_spacing = ctree->tree_spacing;
4803 ctree->tree_spacing = spacing;
4805 if (clist->column[ctree->tree_column].auto_resize &&
4806 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4807 gtk_cmclist_set_column_width (clist, ctree->tree_column,
4808 clist->column[ctree->tree_column].width +
4809 spacing - old_spacing);
4811 CLIST_REFRESH (ctree);
4815 gtk_cmctree_set_show_stub (GtkCMCTree *ctree,
4818 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4820 show_stub = show_stub != FALSE;
4822 if (show_stub != ctree->show_stub)
4826 clist = GTK_CMCLIST (ctree);
4827 ctree->show_stub = show_stub;
4829 if (CLIST_UNFROZEN (clist) && clist->rows &&
4830 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
4831 GTK_CMCLIST_GET_CLASS (clist)->draw_row
4832 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list));
4837 gtk_cmctree_set_line_style (GtkCMCTree *ctree,
4838 GtkCMCTreeLineStyle line_style)
4843 gtk_cmctree_set_expander_style (GtkCMCTree *ctree,
4844 GtkCMCTreeExpanderStyle expander_style)
4847 GtkCMCTreeExpanderStyle old_style;
4849 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4851 if (expander_style == ctree->expander_style)
4854 clist = GTK_CMCLIST (ctree);
4856 old_style = ctree->expander_style;
4857 ctree->expander_style = expander_style;
4859 if (clist->column[ctree->tree_column].auto_resize &&
4860 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
4864 new_width = clist->column[ctree->tree_column].width;
4867 case GTK_CMCTREE_EXPANDER_NONE:
4869 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4870 new_width -= PM_SIZE + 3;
4874 switch (expander_style)
4876 case GTK_CMCTREE_EXPANDER_NONE:
4878 case GTK_CMCTREE_EXPANDER_TRIANGLE:
4879 new_width += PM_SIZE + 3;
4883 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width);
4886 if (gtk_widget_is_drawable (GTK_WIDGET(clist)))
4887 CLIST_REFRESH (clist);
4891 /***********************************************************
4892 * Tree sorting functions *
4893 ***********************************************************/
4897 tree_sort (GtkCMCTree *ctree,
4898 GtkCMCTreeNode *node,
4901 GtkCMCTreeNode *list_start;
4902 GtkCMCTreeNode *cmp;
4903 GtkCMCTreeNode *work;
4906 clist = GTK_CMCLIST (ctree);
4909 list_start = GTK_CMCTREE_ROW (node)->children;
4911 list_start = GTK_CMCTREE_NODE (clist->row_list);
4916 work = GTK_CMCTREE_ROW (cmp)->sibling;
4919 if (clist->sort_type == GTK_SORT_ASCENDING)
4922 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0)
4928 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0)
4931 work = GTK_CMCTREE_ROW (work)->sibling;
4933 if (cmp == list_start)
4934 list_start = GTK_CMCTREE_ROW (cmp)->sibling;
4937 gtk_cmctree_unlink (ctree, cmp, FALSE);
4938 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE);
4944 gtk_cmctree_sort_recursive (GtkCMCTree *ctree,
4945 GtkCMCTreeNode *node)
4948 GtkCMCTreeNode *focus_node = NULL;
4950 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4952 clist = GTK_CMCLIST (ctree);
4954 gtk_cmclist_freeze (clist);
4956 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4958 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4960 g_list_free (clist->undo_selection);
4961 g_list_free (clist->undo_unselection);
4962 clist->undo_selection = NULL;
4963 clist->undo_unselection = NULL;
4966 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
4968 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
4970 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL);
4973 tree_sort (ctree, NULL, NULL);
4977 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
4978 clist->undo_anchor = clist->focus_row;
4981 gtk_cmclist_thaw (clist);
4985 real_sort_list (GtkCMCList *clist)
4987 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL);
4991 gtk_cmctree_sort_node (GtkCMCTree *ctree,
4992 GtkCMCTreeNode *node)
4995 GtkCMCTreeNode *focus_node = NULL;
4997 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
4999 clist = GTK_CMCLIST (ctree);
5001 gtk_cmclist_freeze (clist);
5003 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
5005 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
5007 g_list_free (clist->undo_selection);
5008 g_list_free (clist->undo_unselection);
5009 clist->undo_selection = NULL;
5010 clist->undo_unselection = NULL;
5013 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
5014 focus_node = GTK_CMCTREE_NODE
5015 (g_list_nth (clist->row_list, clist->focus_row));
5017 tree_sort (ctree, node, NULL);
5021 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5022 clist->undo_anchor = clist->focus_row;
5025 gtk_cmclist_thaw (clist);
5028 /************************************************************************/
5031 fake_unselect_all (GtkCMCList *clist,
5035 GList *focus_node = NULL;
5037 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
5039 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
5040 GTK_CMCTREE_ROW (focus_node)->row.selectable)
5042 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
5044 if (CLIST_UNFROZEN (clist) &&
5045 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5046 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
5047 GTK_CMCLIST_ROW (focus_node));
5051 clist->undo_selection = clist->selection;
5052 clist->selection = NULL;
5053 clist->selection_end = NULL;
5055 for (list = clist->undo_selection; list; list = list->next)
5057 if (list->data == focus_node)
5060 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
5061 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data));
5066 selection_find (GtkCMCList *clist,
5068 GList *row_list_element)
5070 return g_list_find (clist->selection, row_list_element);
5074 resync_selection (GtkCMCList *clist, GdkEvent *event)
5078 GtkCMCTreeNode *node;
5084 cm_return_if_fail (GTK_IS_CMCTREE (clist));
5086 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5089 if (clist->anchor < 0 || clist->drag_pos < 0)
5092 ctree = GTK_CMCTREE (clist);
5094 clist->freeze_count++;
5096 i = MIN (clist->anchor, clist->drag_pos);
5097 e = MAX (clist->anchor, clist->drag_pos);
5099 if (clist->undo_selection)
5101 list = clist->selection;
5102 clist->selection = clist->undo_selection;
5103 clist->selection_end = g_list_last (clist->selection);
5104 clist->undo_selection = list;
5105 list = clist->selection;
5114 if (gtk_cmctree_is_viewable (ctree, node))
5116 row = g_list_position (clist->row_list, (GList *)node);
5117 if (row >= i && row <= e)
5120 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable)
5122 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5123 gtk_cmctree_unselect (ctree, node);
5124 clist->undo_selection = g_list_prepend (clist->undo_selection,
5130 if (clist->anchor < clist->drag_pos)
5132 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
5133 i++, node = GTK_CMCTREE_NODE_NEXT (node))
5134 if (GTK_CMCTREE_ROW (node)->row.selectable)
5136 if (g_list_find (clist->selection, node))
5138 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5140 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5141 gtk_cmctree_unselect (ctree, node);
5142 clist->undo_selection =
5143 g_list_prepend (clist->undo_selection, node);
5146 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5148 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5149 clist->undo_unselection =
5150 g_list_prepend (clist->undo_unselection, node);
5156 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
5157 e--, node = GTK_CMCTREE_NODE_PREV (node))
5158 if (GTK_CMCTREE_ROW (node)->row.selectable)
5160 if (g_list_find (clist->selection, node))
5162 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5164 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5165 gtk_cmctree_unselect (ctree, node);
5166 clist->undo_selection =
5167 g_list_prepend (clist->undo_selection, node);
5170 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5172 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5173 clist->undo_unselection =
5174 g_list_prepend (clist->undo_unselection, node);
5179 clist->undo_unselection = g_list_reverse (clist->undo_unselection);
5180 for (list = clist->undo_unselection; list; list = list->next)
5181 gtk_cmctree_select (ctree, list->data);
5184 clist->drag_pos = -1;
5186 if (!CLIST_UNFROZEN (clist))
5187 clist->freeze_count--;
5191 real_undo_selection (GtkCMCList *clist)
5196 cm_return_if_fail (GTK_IS_CMCTREE (clist));
5198 if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5201 if (!(clist->undo_selection || clist->undo_unselection))
5203 gtk_cmclist_unselect_all (clist);
5207 ctree = GTK_CMCTREE (clist);
5209 for (work = clist->undo_selection; work; work = work->next)
5210 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5211 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data));
5213 for (work = clist->undo_unselection; work; work = work->next)
5214 if (GTK_CMCTREE_ROW (work->data)->row.selectable)
5215 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data));
5217 if (gtk_widget_has_focus (GTK_WIDGET(clist)) &&
5218 clist->focus_row != clist->undo_anchor)
5220 clist->focus_row = clist->undo_anchor;
5221 gtk_widget_queue_draw (GTK_WIDGET (clist));
5224 clist->focus_row = clist->undo_anchor;
5226 clist->undo_anchor = -1;
5228 g_list_free (clist->undo_selection);
5229 g_list_free (clist->undo_unselection);
5230 clist->undo_selection = NULL;
5231 clist->undo_unselection = NULL;
5233 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5234 clist->clist_window_height)
5235 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0);
5236 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5237 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0);
5242 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree,
5243 GtkCMCTreeCompareDragFunc cmp_func)
5245 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
5247 ctree->drag_compare = cmp_func;
5251 check_drag (GtkCMCTree *ctree,
5252 GtkCMCTreeNode *drag_source,
5253 GtkCMCTreeNode *drag_target,
5254 GtkCMCListDragPos insert_pos)
5256 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE);
5258 if (drag_source && drag_source != drag_target &&
5259 (!GTK_CMCTREE_ROW (drag_source)->children ||
5260 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target)))
5264 case GTK_CMCLIST_DRAG_NONE:
5266 case GTK_CMCLIST_DRAG_AFTER:
5267 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source)
5268 return (!ctree->drag_compare ||
5269 ctree->drag_compare (ctree,
5271 GTK_CMCTREE_ROW (drag_target)->parent,
5272 GTK_CMCTREE_ROW (drag_target)->sibling));
5274 case GTK_CMCLIST_DRAG_BEFORE:
5275 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target)
5276 return (!ctree->drag_compare ||
5277 ctree->drag_compare (ctree,
5279 GTK_CMCTREE_ROW (drag_target)->parent,
5282 case GTK_CMCLIST_DRAG_INTO:
5283 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf &&
5284 GTK_CMCTREE_ROW (drag_target)->children != drag_source)
5285 return (!ctree->drag_compare ||
5286 ctree->drag_compare (ctree,
5289 GTK_CMCTREE_ROW (drag_target)->children));
5298 /************************************/
5300 drag_dest_info_destroy (gpointer data)
5302 GtkCMCListDestInfo *info = data;
5308 drag_dest_cell (GtkCMCList *clist,
5311 GtkCMCListDestInfo *dest_info)
5317 widget = GTK_WIDGET (clist);
5318 style = gtk_widget_get_style (widget);
5320 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5322 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5323 y -= (border_width +
5324 style->ythickness + clist->column_title_area.height);
5325 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5327 if (dest_info->cell.row >= clist->rows)
5329 dest_info->cell.row = clist->rows - 1;
5330 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5332 if (dest_info->cell.row < -1)
5333 dest_info->cell.row = -1;
5335 x -= border_width + style->xthickness;
5337 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5339 if (dest_info->cell.row >= 0)
5344 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5346 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) &&
5347 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list,
5348 dest_info->cell.row))->is_leaf)
5350 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO;
5351 h = clist->row_height / 4;
5353 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5355 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5356 h = clist->row_height / 2;
5359 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist))
5362 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE;
5363 else if (clist->row_height - y_delta < h)
5364 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER;
5370 gtk_cmctree_drag_begin (GtkWidget *widget,
5371 GdkDragContext *context)
5377 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5378 cm_return_if_fail (context != NULL);
5380 clist = GTK_CMCLIST (widget);
5381 ctree = GTK_CMCTREE (widget);
5383 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist);
5384 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5385 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
5389 GtkCMCTreeNode *node;
5391 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS);
5392 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5393 clist->click_cell.row));
5394 gtk_drag_set_icon_default (context);
5399 gtk_cmctree_drag_motion (GtkWidget *widget,
5400 GdkDragContext *context,
5407 GtkCMCListDestInfo new_info;
5408 GtkCMCListDestInfo *dest_info;
5410 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE);
5412 clist = GTK_CMCLIST (widget);
5413 ctree = GTK_CMCTREE (widget);
5415 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
5419 dest_info = g_new (GtkCMCListDestInfo, 1);
5421 dest_info->cell.row = -1;
5422 dest_info->cell.column = -1;
5423 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE;
5425 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
5426 drag_dest_info_destroy);
5429 drag_dest_cell (clist, x, y, &new_info);
5431 if (GTK_CMCLIST_REORDERABLE (clist))
5433 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5434 GdkAtom found = gtk_drag_dest_find_target(widget, context, NULL);
5438 GtkCMCTreeNode *drag_source;
5439 GtkCMCTreeNode *drag_target;
5441 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5442 clist->click_cell.row));
5443 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5444 new_info.cell.row));
5446 if (gtk_drag_get_source_widget (context) != widget ||
5447 !check_drag (ctree, drag_source, drag_target,
5448 new_info.insert_pos))
5450 if (dest_info->cell.row < 0)
5452 gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
5458 if (new_info.cell.row != dest_info->cell.row ||
5459 (new_info.cell.row == dest_info->cell.row &&
5460 dest_info->insert_pos != new_info.insert_pos))
5462 if (dest_info->cell.row >= 0)
5463 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
5465 g_list_nth (clist->row_list, dest_info->cell.row)->data,
5466 dest_info->cell.row, dest_info->insert_pos);
5468 dest_info->insert_pos = new_info.insert_pos;
5469 dest_info->cell.row = new_info.cell.row;
5470 dest_info->cell.column = new_info.cell.column;
5472 GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight
5474 g_list_nth (clist->row_list, dest_info->cell.row)->data,
5475 dest_info->cell.row, dest_info->insert_pos);
5477 clist->drag_highlight_row = dest_info->cell.row;
5478 clist->drag_highlight_pos = dest_info->insert_pos;
5480 gdk_drag_status (context,
5481 gdk_drag_context_get_suggested_action(context), time);
5487 dest_info->insert_pos = new_info.insert_pos;
5488 dest_info->cell.row = new_info.cell.row;
5489 dest_info->cell.column = new_info.cell.column;
5494 gtk_cmctree_drag_data_received (GtkWidget *widget,
5495 GdkDragContext *context,
5498 GtkSelectionData *selection_data,
5505 cm_return_if_fail (GTK_IS_CMCTREE (widget));
5506 cm_return_if_fail (context != NULL);
5507 cm_return_if_fail (selection_data != NULL);
5509 ctree = GTK_CMCTREE (widget);
5510 clist = GTK_CMCLIST (widget);
5512 if (GTK_CMCLIST_REORDERABLE (clist) &&
5513 gtk_drag_get_source_widget (context) == widget &&
5514 gtk_selection_data_get_target (selection_data) ==
5515 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
5516 gtk_selection_data_get_format (selection_data) == 8 &&
5517 gtk_selection_data_get_length (selection_data) == sizeof (GtkCMCListCellInfo))
5519 GtkCMCListCellInfo *source_info;
5521 source_info = (GtkCMCListCellInfo *)(gtk_selection_data_get_data (selection_data));
5524 GtkCMCListDestInfo dest_info;
5525 GtkCMCTreeNode *source_node;
5526 GtkCMCTreeNode *dest_node;
5528 drag_dest_cell (clist, x, y, &dest_info);
5530 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5532 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list,
5533 dest_info.cell.row));
5535 if (!source_node || !dest_node)
5538 switch (dest_info.insert_pos)
5540 case GTK_CMCLIST_DRAG_NONE:
5542 case GTK_CMCLIST_DRAG_INTO:
5543 if (check_drag (ctree, source_node, dest_node,
5544 dest_info.insert_pos))
5545 gtk_cmctree_move (ctree, source_node, dest_node,
5546 GTK_CMCTREE_ROW (dest_node)->children);
5547 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5549 case GTK_CMCLIST_DRAG_BEFORE:
5550 if (check_drag (ctree, source_node, dest_node,
5551 dest_info.insert_pos))
5552 gtk_cmctree_move (ctree, source_node,
5553 GTK_CMCTREE_ROW (dest_node)->parent, dest_node);
5554 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5556 case GTK_CMCLIST_DRAG_AFTER:
5557 if (check_drag (ctree, source_node, dest_node,
5558 dest_info.insert_pos))
5559 gtk_cmctree_move (ctree, source_node,
5560 GTK_CMCTREE_ROW (dest_node)->parent,
5561 GTK_CMCTREE_ROW (dest_node)->sibling);
5562 g_dataset_remove_data (context, "gtk-clist-drag-dest");
5570 gtk_cmctree_node_get_type (void)
5572 static GType our_type = 0;
5575 our_type = g_pointer_type_register_static ("GtkCMCTreeNode");