1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * GtkCMCTree widget for GTK+
6 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
35 #include <gdk/gdkkeysyms.h>
36 #include "gtkcmctree.h"
37 #include "claws-marshal.h"
42 #define TAB_SIZE (PM_SIZE + 6)
43 #define CELL_SPACING 1
44 #define CLIST_OPTIMUM_SIZE 64
45 #define COLUMN_INSET 3
48 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
49 (((row) + 1) * CELL_SPACING) + \
51 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
52 ((clist)->row_height + CELL_SPACING))
53 #define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \
55 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
58 gtk_cmctree_pos_get_type (void)
60 static GType etype
= 0;
62 static const GEnumValue values
[] = {
63 { GTK_CMCTREE_POS_BEFORE
, "GTK_CMCTREE_POS_BEFORE", "before" },
64 { GTK_CMCTREE_POS_AS_CHILD
, "GTK_CMCTREE_POS_AS_CHILD", "as-child" },
65 { GTK_CMCTREE_POS_AFTER
, "GTK_CMCTREE_POS_AFTER", "after" },
68 etype
= g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values
);
73 gtk_cmctree_line_style_get_type (void)
75 static GType etype
= 0;
77 static const GEnumValue values
[] = {
78 { GTK_CMCTREE_LINES_NONE
, "GTK_CMCTREE_LINES_NONE", "none" },
81 etype
= g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values
);
86 gtk_cmctree_expander_style_get_type (void)
88 static GType etype
= 0;
90 static const GEnumValue values
[] = {
91 { GTK_CMCTREE_EXPANDER_NONE
, "GTK_CMCTREE_EXPANDER_NONE", "none" },
92 { GTK_CMCTREE_EXPANDER_TRIANGLE
, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" },
95 etype
= g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values
);
100 gtk_cmctree_expansion_type_get_type (void)
102 static GType etype
= 0;
104 static const GEnumValue values
[] = {
105 { GTK_CMCTREE_EXPANSION_EXPAND
, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" },
106 { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE
, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" },
107 { GTK_CMCTREE_EXPANSION_COLLAPSE
, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" },
108 { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE
, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" },
109 { GTK_CMCTREE_EXPANSION_TOGGLE
, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" },
110 { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE
, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" },
113 etype
= g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values
);
120 COLUMN_FROM_XPIXEL (GtkCMCList
* clist
,
125 for (i
= 0; i
< clist
->columns
; i
++)
126 if (clist
->column
[i
].visible
)
128 cx
= clist
->column
[i
].area
.x
+ clist
->hoffset
;
130 if (x
>= (cx
- (COLUMN_INSET
+ CELL_SPACING
)) &&
131 x
<= (cx
+ clist
->column
[i
].area
.width
+ COLUMN_INSET
))
139 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
140 #define CLIST_REFRESH(clist) G_STMT_START { \
141 if (CLIST_UNFROZEN (clist)) \
142 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
158 static void gtk_cmctree_class_init (GtkCMCTreeClass
*klass
);
159 static void gtk_cmctree_init (GtkCMCTree
*ctree
);
160 static GObject
* gtk_cmctree_constructor (GType type
,
161 guint n_construct_properties
,
162 GObjectConstructParam
*construct_params
);
163 static void gtk_cmctree_set_arg (GObject
*object
,
167 static void gtk_cmctree_get_arg (GObject
*object
,
171 static void gtk_cmctree_realize (GtkWidget
*widget
);
172 static void gtk_cmctree_unrealize (GtkWidget
*widget
);
173 static gint
gtk_cmctree_button_press (GtkWidget
*widget
,
174 GdkEventButton
*event
);
175 static void ctree_attach_styles (GtkCMCTree
*ctree
,
176 GtkCMCTreeNode
*node
,
178 static void ctree_detach_styles (GtkCMCTree
*ctree
,
179 GtkCMCTreeNode
*node
,
181 static void set_cell_contents (GtkCMCList
*clist
,
182 GtkCMCListRow
*clist_row
,
188 static void set_node_info (GtkCMCTree
*ctree
,
189 GtkCMCTreeNode
*node
,
192 GdkPixbuf
*pixbuf_closed
,
193 GdkPixbuf
*pixbuf_opened
,
196 static GtkCMCTreeRow
*row_new (GtkCMCTree
*ctree
);
197 static void row_delete (GtkCMCTree
*ctree
,
198 GtkCMCTreeRow
*ctree_row
);
199 static void tree_delete (GtkCMCTree
*ctree
,
200 GtkCMCTreeNode
*node
,
202 static void tree_delete_row (GtkCMCTree
*ctree
,
203 GtkCMCTreeNode
*node
,
205 static void real_clear (GtkCMCList
*clist
);
206 static void tree_update_level (GtkCMCTree
*ctree
,
207 GtkCMCTreeNode
*node
,
209 static void tree_select (GtkCMCTree
*ctree
,
210 GtkCMCTreeNode
*node
,
212 static void tree_unselect (GtkCMCTree
*ctree
,
213 GtkCMCTreeNode
*node
,
215 static void real_select_all (GtkCMCList
*clist
);
216 static void real_unselect_all (GtkCMCList
*clist
);
217 static void tree_expand (GtkCMCTree
*ctree
,
218 GtkCMCTreeNode
*node
,
220 static void tree_collapse (GtkCMCTree
*ctree
,
221 GtkCMCTreeNode
*node
,
223 static void tree_collapse_to_depth (GtkCMCTree
*ctree
,
224 GtkCMCTreeNode
*node
,
226 static void tree_toggle_expansion (GtkCMCTree
*ctree
,
227 GtkCMCTreeNode
*node
,
229 static void change_focus_row_expansion (GtkCMCTree
*ctree
,
230 GtkCMCTreeExpansionType expansion
);
231 static void real_select_row (GtkCMCList
*clist
,
235 static void real_unselect_row (GtkCMCList
*clist
,
239 static void real_tree_select (GtkCMCTree
*ctree
,
240 GtkCMCTreeNode
*node
,
242 static void real_tree_unselect (GtkCMCTree
*ctree
,
243 GtkCMCTreeNode
*node
,
245 static void real_tree_expand (GtkCMCTree
*ctree
,
246 GtkCMCTreeNode
*node
);
247 static void real_tree_collapse (GtkCMCTree
*ctree
,
248 GtkCMCTreeNode
*node
);
249 static void real_tree_move (GtkCMCTree
*ctree
,
250 GtkCMCTreeNode
*node
,
251 GtkCMCTreeNode
*new_parent
,
252 GtkCMCTreeNode
*new_sibling
);
253 static void real_row_move (GtkCMCList
*clist
,
256 static void gtk_cmctree_link (GtkCMCTree
*ctree
,
257 GtkCMCTreeNode
*node
,
258 GtkCMCTreeNode
*parent
,
259 GtkCMCTreeNode
*sibling
,
260 gboolean update_focus_row
);
261 static void gtk_cmctree_unlink (GtkCMCTree
*ctree
,
262 GtkCMCTreeNode
*node
,
263 gboolean update_focus_row
);
264 static GtkCMCTreeNode
* gtk_cmctree_last_visible (GtkCMCTree
*ctree
,
265 GtkCMCTreeNode
*node
);
266 static gboolean
ctree_is_hot_spot (GtkCMCTree
*ctree
,
267 GtkCMCTreeNode
*node
,
271 static void tree_sort (GtkCMCTree
*ctree
,
272 GtkCMCTreeNode
*node
,
274 static void fake_unselect_all (GtkCMCList
*clist
,
276 static GList
* selection_find (GtkCMCList
*clist
,
278 GList
*row_list_element
);
279 static void resync_selection (GtkCMCList
*clist
,
281 static void real_undo_selection (GtkCMCList
*clist
);
282 static void select_row_recursive (GtkCMCTree
*ctree
,
283 GtkCMCTreeNode
*node
,
285 static gint
real_insert_row (GtkCMCList
*clist
,
288 static void real_remove_row (GtkCMCList
*clist
,
290 static void real_sort_list (GtkCMCList
*clist
);
291 static void cell_size_request (GtkCMCList
*clist
,
292 GtkCMCListRow
*clist_row
,
294 GtkRequisition
*requisition
);
295 static void column_auto_resize (GtkCMCList
*clist
,
296 GtkCMCListRow
*clist_row
,
299 static void auto_resize_columns (GtkCMCList
*clist
);
302 static gboolean
check_drag (GtkCMCTree
*ctree
,
303 GtkCMCTreeNode
*drag_source
,
304 GtkCMCTreeNode
*drag_target
,
305 GtkCMCListDragPos insert_pos
);
306 static void gtk_cmctree_drag_begin (GtkWidget
*widget
,
307 GdkDragContext
*context
);
308 static gint
gtk_cmctree_drag_motion (GtkWidget
*widget
,
309 GdkDragContext
*context
,
313 static void gtk_cmctree_drag_data_received (GtkWidget
*widget
,
314 GdkDragContext
*context
,
317 GtkSelectionData
*selection_data
,
320 static void remove_grab (GtkCMCList
*clist
);
321 static void drag_dest_cell (GtkCMCList
*clist
,
324 GtkCMCListDestInfo
*dest_info
);
334 CHANGE_FOCUS_ROW_EXPANSION
,
338 static GtkCMCListClass
*parent_class
= NULL
;
339 static GtkContainerClass
*container_class
= NULL
;
340 static guint ctree_signals
[LAST_SIGNAL
] = {0};
344 gtk_cmctree_get_type (void)
346 static GType ctree_type
= 0;
350 static const GTypeInfo ctree_info
=
352 sizeof (GtkCMCTreeClass
),
354 (GBaseInitFunc
) NULL
,
355 (GBaseFinalizeFunc
) NULL
,
357 (GClassInitFunc
) gtk_cmctree_class_init
,
358 (GClassFinalizeFunc
) NULL
,
359 NULL
, /* class_data */
363 (GInstanceInitFunc
) gtk_cmctree_init
,
365 (const GTypeValueTable
*) NULL
/* value table */
368 ctree_type
= g_type_register_static (GTK_TYPE_CMCLIST
, "GtkCMCTree", &ctree_info
, (GTypeFlags
)0);
375 draw_cell_pixbuf (GdkWindow
*window
,
376 GdkRectangle
*clip_rectangle
,
387 if (!pixbuf
|| (width
== 0 && height
== 0))
390 if (x
< clip_rectangle
->x
)
392 xsrc
= clip_rectangle
->x
- x
;
394 x
= clip_rectangle
->x
;
396 if (x
+ width
> clip_rectangle
->x
+ clip_rectangle
->width
)
397 width
= clip_rectangle
->x
+ clip_rectangle
->width
- x
;
399 if (y
< clip_rectangle
->y
)
401 ysrc
= clip_rectangle
->y
- y
;
403 y
= clip_rectangle
->y
;
406 if (y
+ height
> clip_rectangle
->y
+ clip_rectangle
->height
)
407 height
= clip_rectangle
->y
+ clip_rectangle
->height
- y
;
409 gdk_cairo_set_source_pixbuf(cr
, pixbuf
, x
, y
);
412 return x
+ MAX (width
, 0);
416 draw_expander (GtkCMCTree
*ctree
,
417 GtkCMCTreeRow
*ctree_row
,
419 GdkRectangle
*clip_rectangle
,
424 gint justification_factor
;
427 if (ctree
->expander_style
== GTK_CMCTREE_EXPANDER_NONE
)
430 clist
= GTK_CMCLIST (ctree
);
431 if (clist
->column
[ctree
->tree_column
].justification
== GTK_JUSTIFY_RIGHT
)
432 justification_factor
= -1;
434 justification_factor
= 1;
435 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist
)))
436 y
= (clip_rectangle
->y
+ (clip_rectangle
->height
- PM_SIZE
) / 2 -
437 (clip_rectangle
->height
+ 1) % 2) + 1;
439 y
= (clip_rectangle
->y
+ (clip_rectangle
->height
/2 - PM_SIZE
) / 2 -
440 (clip_rectangle
->height
/2 + 1) % 2) + 1;
442 if (!ctree_row
->children
)
444 return x
+ justification_factor
* (PM_SIZE
+ 3);
447 /* pixel offsets +/- 1 or +/- justification_factor here and there ..
448 * to fill correctly, somewhat ... what do I do wrong?
450 gdk_cairo_set_source_color(cr
, >k_widget_get_style(GTK_WIDGET(ctree
))->text
[GTK_STATE_NORMAL
]);
451 if (ctree_row
->expanded
)
453 gint tmp3
= PM_SIZE
/ 2;
454 gint tmp6
= PM_SIZE
/ 6;
455 cairo_move_to(cr
, x
+ justification_factor
* (tmp3
+ tmp6
) + (PM_SIZE
/ 2), y
+ 1);
456 cairo_rel_line_to(cr
, 0, tmp3
+ tmp6
+ 1);
457 cairo_rel_line_to(cr
, -justification_factor
* (tmp3
+ tmp6
) - justification_factor
, -1);
461 gint tmp3
= PM_SIZE
/ 2;
462 gint tmp6
= PM_SIZE
/ 6;
463 cairo_move_to(cr
, x
+ tmp6
- justification_factor
+ (PM_SIZE
/ 2), y
+ tmp6
- 1);
464 cairo_rel_line_to(cr
, justification_factor
* tmp3
, tmp3
);
465 cairo_rel_line_to(cr
, -justification_factor
* tmp3
, tmp3
);
469 x
+= justification_factor
* (PM_SIZE
+ 3);
475 get_offset(GtkCMCTree
*ctree
,
476 GtkCMCTreeRow
*ctree_row
,
478 GdkRectangle
*clip_rectangle
)
481 justify_right
= (GTK_CMCLIST (ctree
)->column
[column
].justification
== GTK_JUSTIFY_RIGHT
);
484 return (clip_rectangle
->x
+ clip_rectangle
->width
- 1 -
485 ctree
->tree_indent
* (ctree_row
->level
- 1));
487 return clip_rectangle
->x
+ ctree
->tree_indent
* (ctree_row
->level
- 1);
491 get_cell_style (GtkCMCList
*clist
,
492 GtkCMCListRow
*clist_row
,
499 gtkstyle
= gtk_widget_get_style (GTK_WIDGET (clist
));
501 if (clist_row
->cell
[column
].style
)
504 *style
= clist_row
->cell
[column
].style
;
506 else if (clist_row
->style
)
509 *style
= clist_row
->style
;
518 static gboolean
filter_fg (PangoAttribute
*attribute
, gpointer data
)
520 const PangoAttrClass
*klass
= attribute
->klass
;
521 if (klass
->type
== PANGO_ATTR_FOREGROUND
)
528 create_cell_layout (GtkCMCList
*clist
,
529 GtkCMCListRow
*clist_row
,
537 get_cell_style (clist
, clist_row
, GTK_STATE_NORMAL
, column
, &style
);
540 cell
= &clist_row
->cell
[column
];
543 case GTK_CMCELL_TEXT
:
544 case GTK_CMCELL_PIXTEXT
:
545 text
= ((cell
->type
== GTK_CMCELL_PIXTEXT
) ?
546 GTK_CMCELL_PIXTEXT (*cell
)->text
:
547 GTK_CMCELL_TEXT (*cell
)->text
);
552 if (!GTK_SCTREE(clist
)->use_markup
[column
]) {
553 layout
= gtk_widget_create_pango_layout (GTK_WIDGET (clist
),
554 ((cell
->type
== GTK_CMCELL_PIXTEXT
) ?
555 GTK_CMCELL_PIXTEXT (*cell
)->text
:
556 GTK_CMCELL_TEXT (*cell
)->text
));
557 pango_layout_set_font_description (layout
, style
->font_desc
);
559 PangoContext
*context
= gtk_widget_get_pango_context (GTK_WIDGET(clist
));
560 layout
= pango_layout_new (context
);
561 pango_layout_set_markup (layout
, text
, -1);
562 pango_layout_set_font_description (layout
, style
->font_desc
);
563 if (clist_row
->state
== GTK_STATE_SELECTED
) {
564 /* for selected row, we should remove any forced foreground color
565 * or it looks like shit */
566 PangoAttrList
*list
= pango_layout_get_attributes(layout
);
567 PangoAttrList
*rem
= pango_attr_list_filter(list
, filter_fg
, NULL
);
569 pango_attr_list_unref(rem
);
582 draw_row (GtkCMCList
*clist
,
585 GtkCMCListRow
*clist_row
)
591 GdkRectangle row_rectangle
;
592 GdkRectangle cell_rectangle
;
593 GdkRectangle clip_rectangle
;
594 GdkRectangle intersect_rectangle
;
599 static GdkColor greybg
={0, 0, 0, 0};
600 static gboolean color_change
= TRUE
;
602 GdkColor
*fgcolor
, *bgcolor
;
604 cm_return_if_fail (clist
!= NULL
);
606 if (clist
->draw_now
) {
607 gtk_widget_queue_draw(GTK_WIDGET (clist
));
611 widget
= GTK_WIDGET (clist
);
613 /* if the function is passed the pointer to the row instead of null,
614 * it avoids this expensive lookup */
616 clist_row
= (g_list_nth (clist
->row_list
, row
))->data
;
618 style
= clist_row
->style
? clist_row
->style
: gtk_widget_get_style (widget
);
620 if (greybg
.pixel
== 0 &&
624 GdkColor normalbg
= {0, 0xffff, 0xffff, 0xffff};
626 normalbg
= style
->base
[GTK_STATE_NORMAL
];
628 if (normalbg
.red
> 0x8888 && normalbg
.green
> 0x8888 && normalbg
.blue
> 0x8888) {
629 greybg
.pixel
= normalbg
.pixel
;
630 greybg
.red
= normalbg
.red
- prefs_common
.stripes_color_offset
;
631 greybg
.green
= normalbg
.green
- prefs_common
.stripes_color_offset
;
632 greybg
.blue
= normalbg
.blue
- prefs_common
.stripes_color_offset
;
633 } else if (normalbg
.red
< 0x8888 && normalbg
.green
< 0x8888 && normalbg
.blue
< 0x8888) {
634 greybg
.pixel
= normalbg
.pixel
;
635 greybg
.red
= normalbg
.red
+ prefs_common
.stripes_color_offset
;
636 greybg
.green
= normalbg
.green
+ prefs_common
.stripes_color_offset
;
637 greybg
.blue
= normalbg
.blue
+ prefs_common
.stripes_color_offset
;
639 color_change
= FALSE
;
643 /* bail now if we arn't drawable yet */
644 if (!gtk_widget_is_drawable (GTK_WIDGET(clist
)) || row
< 0 || row
>= clist
->rows
)
647 ctree
= GTK_CMCTREE (clist
);
649 /* rectangle of the entire row */
651 row_rectangle
.y
= ROW_TOP_YPIXEL (clist
, row
);
652 row_rectangle
.width
= clist
->clist_window_width
;
653 row_rectangle
.height
= clist
->row_height
;
655 /* rectangle of the cell spacing above the row */
656 cell_rectangle
.x
= 0;
657 cell_rectangle
.y
= row_rectangle
.y
- CELL_SPACING
;
658 cell_rectangle
.width
= row_rectangle
.width
;
659 cell_rectangle
.height
= CELL_SPACING
;
661 /* rectangle used to clip drawing operations, its y and height
662 * positions only need to be set once, so we set them once here.
663 * the x and width are set withing the drawing loop below once per
665 clip_rectangle
.y
= row_rectangle
.y
;
666 clip_rectangle
.height
= row_rectangle
.height
;
668 if (prefs_common
.use_stripes_everywhere
&& GTK_SCTREE(ctree
)->show_stripes
669 && color_change
&& row
% 2) {
672 bgcolor
= &style
->base
[GTK_STATE_NORMAL
];
674 state
= clist_row
->state
;
676 cr
= gdk_cairo_create(clist
->clist_window
);
678 if (clist_row
->fg_set
&& state
!= GTK_STATE_SELECTED
)
679 fgcolor
= &clist_row
->foreground
;
681 fgcolor
= &style
->text
[clist_row
->state
];
682 /* draw the cell borders */
685 crect
= &intersect_rectangle
;
687 if (gdk_rectangle_intersect (area
, &cell_rectangle
, crect
)) {
688 gdk_cairo_rectangle(cr
, &cell_rectangle
);
689 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
691 cairo_rectangle(cr
, cell_rectangle
.x
, cell_rectangle
.y
+ row_rectangle
.height
+ 1,cell_rectangle
.width
,cell_rectangle
.height
);
697 crect
= &cell_rectangle
;
699 gdk_cairo_rectangle(cr
, &cell_rectangle
);
700 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
702 cairo_rectangle(cr
, cell_rectangle
.x
, cell_rectangle
.y
+ row_rectangle
.height
+ 1,cell_rectangle
.width
,cell_rectangle
.height
);
706 /* the last row has to clear its bottom cell spacing too */
707 if (clist_row
== clist
->row_list_end
->data
)
709 cell_rectangle
.y
+= clist
->row_height
+ CELL_SPACING
;
711 if (!area
|| gdk_rectangle_intersect (area
, &cell_rectangle
, crect
))
713 gdk_cairo_rectangle(cr
, crect
);
714 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
719 for (last_column
= clist
->columns
- 1;
720 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--)
723 /* iterate and draw all the columns (row cells) and draw their contents */
724 for (i
= 0; i
< clist
->columns
; i
++)
727 PangoLayout
*layout
= NULL
;
728 PangoRectangle logical_rect
;
736 if (!clist
->column
[i
].visible
)
739 get_cell_style (clist
, clist_row
, state
, i
, &style
);
741 /* calculate clipping region */
742 clip_rectangle
.x
= clist
->column
[i
].area
.x
+ clist
->hoffset
;
743 clip_rectangle
.width
= clist
->column
[i
].area
.width
;
745 cell_rectangle
.x
= clip_rectangle
.x
- COLUMN_INSET
- CELL_SPACING
;
746 cell_rectangle
.width
= (clip_rectangle
.width
+ 2 * COLUMN_INSET
+
747 (1 + (i
== last_column
)) * CELL_SPACING
);
748 cell_rectangle
.y
= clip_rectangle
.y
;
749 cell_rectangle
.height
= clip_rectangle
.height
;
755 if (area
&& !gdk_rectangle_intersect (area
, &cell_rectangle
,
756 &intersect_rectangle
))
758 if (i
!= ctree
->tree_column
)
763 gdk_cairo_rectangle(cr
, &cell_rectangle
);
764 if (state
== GTK_STATE_NORMAL
)
765 gdk_cairo_set_source_color(cr
, bgcolor
);
767 gdk_cairo_set_source_color(cr
, &style
->base
[state
]);
769 layout
= create_cell_layout (clist
, clist_row
, i
);
772 pango_layout_get_pixel_extents (layout
, NULL
, &logical_rect
);
773 width
= logical_rect
.width
;
778 switch (clist_row
->cell
[i
].type
)
780 case GTK_CMCELL_PIXBUF
:
781 pixbuf_width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
);
782 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
);
783 width
+= pixbuf_width
;
785 case GTK_CMCELL_PIXTEXT
:
786 if (GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
)
788 pixbuf_width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
);
789 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
);
790 width
+= pixbuf_width
;
793 if (GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->text
&&
794 GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
)
795 width
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
797 if (i
== ctree
->tree_column
)
798 width
+= (ctree
->tree_indent
*
799 ((GtkCMCTreeRow
*)clist_row
)->level
);
805 switch (clist
->column
[i
].justification
)
807 case GTK_JUSTIFY_LEFT
:
808 offset
= clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
;
810 case GTK_JUSTIFY_RIGHT
:
811 offset
= (clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
+
812 clip_rectangle
.width
- width
);
814 case GTK_JUSTIFY_CENTER
:
815 case GTK_JUSTIFY_FILL
:
816 offset
= (clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
+
817 (clip_rectangle
.width
/ 2) - (width
/ 2));
821 if (i
!= ctree
->tree_column
)
823 int start_y
= (clip_rectangle
.height
- height
) / 2;
824 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist
)))
825 start_y
= (clip_rectangle
.height
/2 - height
) / 2;
827 offset
+= clist_row
->cell
[i
].horizontal
;
828 switch (clist_row
->cell
[i
].type
)
830 case GTK_CMCELL_PIXBUF
:
832 (clist
->clist_window
, &clip_rectangle
, cr
,
833 GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
,
835 clip_rectangle
.y
+ clist_row
->cell
[i
].vertical
+
837 pixbuf_width
, height
);
839 case GTK_CMCELL_PIXTEXT
:
840 offset
= draw_cell_pixbuf
841 (clist
->clist_window
, &clip_rectangle
, cr
,
842 GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
,
844 clip_rectangle
.y
+ clist_row
->cell
[i
].vertical
+
846 pixbuf_width
, height
);
847 offset
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
850 case GTK_CMCELL_TEXT
:
853 gint row_center_offset
= (clist
->row_height
- logical_rect
.height
) / 2;
854 gdk_cairo_set_source_color(cr
, fgcolor
);
855 cairo_move_to(cr
, offset
, row_rectangle
.y
+ row_center_offset
+ clist_row
->cell
[i
].vertical
);
856 pango_cairo_show_layout(cr
, layout
);
857 g_object_unref (G_OBJECT (layout
));
867 /* draw ctree->tree_column */
868 cell_rectangle
.y
-= CELL_SPACING
;
869 cell_rectangle
.height
+= CELL_SPACING
;
871 if (area
&& !gdk_rectangle_intersect (area
, &cell_rectangle
,
872 &intersect_rectangle
))
875 g_object_unref (G_OBJECT (layout
));
881 offset
= get_offset (ctree
, (GtkCMCTreeRow
*)clist_row
, i
,
885 offset
= draw_expander (ctree
, (GtkCMCTreeRow
*)clist_row
,
886 style
, &clip_rectangle
, cr
, offset
);
888 if (clist
->column
[i
].justification
== GTK_JUSTIFY_RIGHT
)
889 offset
-= ctree
->tree_spacing
;
891 offset
+= ctree
->tree_spacing
;
893 if (clist
->column
[i
].justification
== GTK_JUSTIFY_RIGHT
)
894 offset
-= (pixbuf_width
+ clist_row
->cell
[i
].horizontal
);
896 offset
+= clist_row
->cell
[i
].horizontal
;
899 offset
= draw_cell_pixbuf (clist
->clist_window
, &clip_rectangle
, cr
,
900 GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
,
902 clip_rectangle
.y
+ clist_row
->cell
[i
].vertical
903 + (clip_rectangle
.height
- height
) / 2,
904 pixbuf_width
, height
);
908 gint row_center_offset
= (clist
->row_height
- logical_rect
.height
) / 2;
910 if (clist
->column
[i
].justification
== GTK_JUSTIFY_RIGHT
)
912 offset
= (old_offset
- string_width
);
913 if (GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
)
914 offset
-= GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
918 if (GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
)
919 offset
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
922 cairo_move_to(cr
, offset
, row_rectangle
.y
+ row_center_offset
+ clist_row
->cell
[i
].vertical
);
923 gdk_cairo_set_source_color(cr
, fgcolor
);
924 pango_cairo_show_layout(cr
, layout
);
925 g_object_unref (G_OBJECT (layout
));
928 /* draw focus rectangle */
929 if (clist
->focus_row
== row
&&
930 gtk_widget_get_can_focus (widget
) && gtk_widget_has_focus (widget
)
931 && state
== GTK_STATE_SELECTED
)
933 if (!area
|| gdk_rectangle_intersect (area
, &row_rectangle
,
934 &intersect_rectangle
))
936 cairo_set_line_width(cr
, 1.0);
937 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
938 gdk_cairo_set_source_color(cr
, &style
->text
[GTK_STATE_NORMAL
]);
939 cairo_move_to (cr
, row_rectangle
.x
, row_rectangle
.y
+ 0.5);
940 cairo_line_to (cr
, row_rectangle
.x
+ row_rectangle
.width
, row_rectangle
.y
+ 0.5);
941 cairo_move_to (cr
, row_rectangle
.x
, row_rectangle
.y
+ row_rectangle
.height
- 0.5);
942 cairo_line_to (cr
, row_rectangle
.x
+ row_rectangle
.width
, row_rectangle
.y
+ row_rectangle
.height
- 0.5);
950 gtk_cmctree_class_init (GtkCMCTreeClass
*klass
)
952 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
953 #if !GTK_CHECK_VERSION(3, 0, 0)
954 GtkObjectClass
*object_class
;
955 #else /* for simplicity */
956 GtkWidgetClass
*object_class
;
958 GtkWidgetClass
*widget_class
;
959 GtkCMCListClass
*clist_class
;
960 GtkBindingSet
*binding_set
;
962 gobject_class
->constructor
= gtk_cmctree_constructor
;
964 #if !GTK_CHECK_VERSION(3, 0, 0)
965 object_class
= (GtkObjectClass
*) klass
;
966 #else /* for simplicity */
967 object_class
= (GtkWidgetClass
*) klass
;
969 widget_class
= (GtkWidgetClass
*) klass
;
970 container_class
= (GtkContainerClass
*) klass
;
971 clist_class
= (GtkCMCListClass
*) klass
;
973 parent_class
= g_type_class_peek (GTK_TYPE_CMCLIST
);
974 container_class
= g_type_class_peek (GTK_TYPE_CONTAINER
);
976 gobject_class
->set_property
= gtk_cmctree_set_arg
;
977 gobject_class
->get_property
= gtk_cmctree_get_arg
;
979 widget_class
->realize
= gtk_cmctree_realize
;
980 widget_class
->unrealize
= gtk_cmctree_unrealize
;
981 widget_class
->button_press_event
= gtk_cmctree_button_press
;
983 widget_class
->drag_begin
= gtk_cmctree_drag_begin
;
984 widget_class
->drag_motion
= gtk_cmctree_drag_motion
;
985 widget_class
->drag_data_received
= gtk_cmctree_drag_data_received
;
987 clist_class
->select_row
= real_select_row
;
988 clist_class
->unselect_row
= real_unselect_row
;
989 clist_class
->row_move
= real_row_move
;
990 clist_class
->undo_selection
= real_undo_selection
;
991 clist_class
->resync_selection
= resync_selection
;
992 clist_class
->selection_find
= selection_find
;
993 clist_class
->click_column
= NULL
;
994 clist_class
->draw_row
= draw_row
;
995 clist_class
->clear
= real_clear
;
996 clist_class
->select_all
= real_select_all
;
997 clist_class
->unselect_all
= real_unselect_all
;
998 clist_class
->fake_unselect_all
= fake_unselect_all
;
999 clist_class
->insert_row
= real_insert_row
;
1000 clist_class
->remove_row
= real_remove_row
;
1001 clist_class
->sort_list
= real_sort_list
;
1002 clist_class
->set_cell_contents
= set_cell_contents
;
1003 clist_class
->cell_size_request
= cell_size_request
;
1005 klass
->tree_select_row
= real_tree_select
;
1006 klass
->tree_unselect_row
= real_tree_unselect
;
1007 klass
->tree_expand
= real_tree_expand
;
1008 klass
->tree_collapse
= real_tree_collapse
;
1009 klass
->tree_move
= real_tree_move
;
1010 klass
->change_focus_row_expansion
= change_focus_row_expansion
;
1012 g_object_class_install_property (gobject_class
,
1014 g_param_spec_uint ("n-columns",
1020 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT_ONLY
));
1021 g_object_class_install_property (gobject_class
,
1023 g_param_spec_uint ("tree-column",
1029 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT_ONLY
));
1030 g_object_class_install_property (gobject_class
,
1032 g_param_spec_uint ("indent",
1038 G_PARAM_READWRITE
));
1039 g_object_class_install_property (gobject_class
,
1041 g_param_spec_uint ("spacing",
1047 G_PARAM_READWRITE
));
1048 g_object_class_install_property (gobject_class
,
1050 g_param_spec_boolean ("show-stub",
1054 G_PARAM_READWRITE
));
1055 g_object_class_install_property (gobject_class
,
1057 g_param_spec_enum ("line-style",
1060 GTK_TYPE_CMCTREE_LINE_STYLE
, 0,
1061 G_PARAM_READWRITE
));
1062 g_object_class_install_property (gobject_class
,
1064 g_param_spec_enum ("expander-style",
1067 GTK_TYPE_CMCTREE_EXPANDER_STYLE
, 0,
1068 G_PARAM_READWRITE
));
1070 ctree_signals
[TREE_SELECT_ROW
] =
1071 g_signal_new ("tree_select_row",
1072 G_TYPE_FROM_CLASS (object_class
),
1074 G_STRUCT_OFFSET (GtkCMCTreeClass
, tree_select_row
),
1076 claws_marshal_VOID__POINTER_INT
,
1078 GTK_TYPE_CMCTREE_NODE
,
1080 ctree_signals
[TREE_UNSELECT_ROW
] =
1081 g_signal_new ("tree_unselect_row",
1082 G_TYPE_FROM_CLASS (object_class
),
1084 G_STRUCT_OFFSET (GtkCMCTreeClass
, tree_unselect_row
),
1086 claws_marshal_VOID__POINTER_INT
,
1088 GTK_TYPE_CMCTREE_NODE
,
1090 ctree_signals
[TREE_EXPAND
] =
1091 g_signal_new ("tree_expand",
1092 G_TYPE_FROM_CLASS (object_class
),
1094 G_STRUCT_OFFSET (GtkCMCTreeClass
, tree_expand
),
1096 claws_marshal_VOID__POINTER
,
1098 GTK_TYPE_CMCTREE_NODE
);
1099 ctree_signals
[TREE_COLLAPSE
] =
1100 g_signal_new ("tree_collapse",
1101 G_TYPE_FROM_CLASS (object_class
),
1103 G_STRUCT_OFFSET (GtkCMCTreeClass
, tree_collapse
),
1105 claws_marshal_VOID__POINTER
,
1107 GTK_TYPE_CMCTREE_NODE
);
1108 ctree_signals
[TREE_MOVE
] =
1109 g_signal_new ("tree_move",
1110 G_TYPE_FROM_CLASS (object_class
),
1112 G_STRUCT_OFFSET (GtkCMCTreeClass
, tree_move
),
1114 claws_marshal_VOID__POINTER_POINTER_POINTER
,
1116 GTK_TYPE_CMCTREE_NODE
,GTK_TYPE_CMCTREE_NODE
,GTK_TYPE_CMCTREE_NODE
);
1117 ctree_signals
[CHANGE_FOCUS_ROW_EXPANSION
] =
1118 g_signal_new ("change_focus_row_expansion",
1119 G_TYPE_FROM_CLASS (object_class
),
1120 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
1121 G_STRUCT_OFFSET (GtkCMCTreeClass
, change_focus_row_expansion
),
1123 claws_marshal_VOID__ENUM
,
1124 G_TYPE_NONE
, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE
);
1126 binding_set
= gtk_binding_set_by_class (klass
);
1127 gtk_binding_entry_add_signal (binding_set
,
1129 "change_focus_row_expansion", 1,
1130 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_EXPAND
);
1131 gtk_binding_entry_add_signal (binding_set
,
1132 GDK_KEY_plus
, GDK_CONTROL_MASK
,
1133 "change_focus_row_expansion", 1,
1134 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE
);
1136 gtk_binding_entry_add_signal (binding_set
,
1138 "change_focus_row_expansion", 1,
1139 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_EXPAND
);
1140 gtk_binding_entry_add_signal (binding_set
,
1141 GDK_KEY_KP_Add
, GDK_CONTROL_MASK
,
1142 "change_focus_row_expansion", 1,
1143 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE
);
1145 gtk_binding_entry_add_signal (binding_set
,
1147 "change_focus_row_expansion", 1,
1148 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_COLLAPSE
);
1149 gtk_binding_entry_add_signal (binding_set
,
1150 GDK_KEY_minus
, GDK_CONTROL_MASK
,
1151 "change_focus_row_expansion", 1,
1153 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE
);
1154 gtk_binding_entry_add_signal (binding_set
,
1155 GDK_KEY_KP_Subtract
, 0,
1156 "change_focus_row_expansion", 1,
1157 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_COLLAPSE
);
1158 gtk_binding_entry_add_signal (binding_set
,
1159 GDK_KEY_KP_Subtract
, GDK_CONTROL_MASK
,
1160 "change_focus_row_expansion", 1,
1162 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE
);
1163 gtk_binding_entry_add_signal (binding_set
,
1165 "change_focus_row_expansion", 1,
1166 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_TOGGLE
);
1167 gtk_binding_entry_add_signal (binding_set
,
1168 GDK_KEY_KP_Equal
, 0,
1169 "change_focus_row_expansion", 1,
1170 G_TYPE_ENUM
, GTK_CMCTREE_EXPANSION_TOGGLE
);
1171 gtk_binding_entry_add_signal (binding_set
,
1172 GDK_KEY_KP_Multiply
, 0,
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_asterisk
, 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
, GDK_CONTROL_MASK
,
1181 "change_focus_row_expansion", 1,
1183 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE
);
1184 gtk_binding_entry_add_signal (binding_set
,
1185 GDK_KEY_asterisk
, GDK_CONTROL_MASK
,
1186 "change_focus_row_expansion", 1,
1188 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE
);
1192 gtk_cmctree_set_arg (GObject
*object
,
1194 const GValue
*value
,
1200 ctree
= GTK_CMCTREE (object
);
1201 clist
= GTK_CMCLIST (ctree
);
1205 case ARG_N_COLUMNS
: /* construct-only arg, only set at construction time */
1206 clist
->columns
= MAX (1, g_value_get_uint (value
));
1207 ctree
->tree_column
= CLAMP (ctree
->tree_column
, 0, clist
->columns
);
1209 case ARG_TREE_COLUMN
: /* construct-only arg, only set at construction time */
1210 ctree
->tree_column
= g_value_get_uint (value
);
1211 ctree
->tree_column
= CLAMP (ctree
->tree_column
, 0, clist
->columns
);
1214 gtk_cmctree_set_indent (ctree
, g_value_get_uint (value
));
1217 gtk_cmctree_set_spacing (ctree
, g_value_get_uint (value
));
1220 gtk_cmctree_set_show_stub (ctree
, g_value_get_boolean (value
));
1222 case ARG_LINE_STYLE
:
1223 gtk_cmctree_set_line_style (ctree
, g_value_get_enum (value
));
1225 case ARG_EXPANDER_STYLE
:
1226 gtk_cmctree_set_expander_style (ctree
, g_value_get_enum (value
));
1234 gtk_cmctree_get_arg (GObject
*object
,
1241 ctree
= GTK_CMCTREE (object
);
1246 g_value_set_uint(value
, GTK_CMCLIST (ctree
)->columns
);
1248 case ARG_TREE_COLUMN
:
1249 g_value_set_uint(value
, ctree
->tree_column
);
1252 g_value_set_uint(value
, ctree
->tree_indent
);
1255 g_value_set_uint(value
, ctree
->tree_spacing
);
1258 g_value_set_boolean(value
, ctree
->show_stub
);
1260 case ARG_LINE_STYLE
:
1261 g_value_set_enum(value
, ctree
->line_style
);
1263 case ARG_EXPANDER_STYLE
:
1264 g_value_set_enum(value
, ctree
->expander_style
);
1267 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, arg_id
, spec
);
1273 gtk_cmctree_init (GtkCMCTree
*ctree
)
1277 GTK_CMCLIST_SET_FLAG (ctree
, CMCLIST_DRAW_DRAG_RECT
);
1278 GTK_CMCLIST_SET_FLAG (ctree
, CMCLIST_DRAW_DRAG_LINE
);
1280 clist
= GTK_CMCLIST (ctree
);
1282 ctree
->tree_indent
= 20;
1283 ctree
->tree_spacing
= 5;
1284 ctree
->tree_column
= 0;
1285 ctree
->line_style
= GTK_CMCTREE_LINES_NONE
;
1286 ctree
->expander_style
= GTK_CMCTREE_EXPANDER_TRIANGLE
;
1287 ctree
->drag_compare
= NULL
;
1288 ctree
->show_stub
= TRUE
;
1290 clist
->button_actions
[0] |= GTK_CMBUTTON_EXPANDS
;
1294 ctree_attach_styles (GtkCMCTree
*ctree
,
1295 GtkCMCTreeNode
*node
,
1301 clist
= GTK_CMCLIST (ctree
);
1303 if (GTK_CMCTREE_ROW (node
)->row
.style
)
1304 GTK_CMCTREE_ROW (node
)->row
.style
=
1305 gtk_style_attach (GTK_CMCTREE_ROW (node
)->row
.style
, clist
->clist_window
);
1307 #if !GTK_CHECK_VERSION(3, 0, 0)
1308 if (GTK_CMCTREE_ROW (node
)->row
.fg_set
|| GTK_CMCTREE_ROW (node
)->row
.bg_set
)
1310 GdkColormap
*colormap
;
1312 colormap
= gtk_widget_get_colormap (GTK_WIDGET (ctree
));
1313 if (GTK_CMCTREE_ROW (node
)->row
.fg_set
)
1314 gdk_colormap_alloc_color (colormap
, &(GTK_CMCTREE_ROW (node
)->row
.foreground
), TRUE
, TRUE
);
1315 if (GTK_CMCTREE_ROW (node
)->row
.bg_set
)
1316 gdk_colormap_alloc_color (colormap
, &(GTK_CMCTREE_ROW (node
)->row
.background
), TRUE
, TRUE
);
1320 for (i
= 0; i
< clist
->columns
; i
++)
1321 if (GTK_CMCTREE_ROW (node
)->row
.cell
[i
].style
)
1322 GTK_CMCTREE_ROW (node
)->row
.cell
[i
].style
=
1323 gtk_style_attach (GTK_CMCTREE_ROW (node
)->row
.cell
[i
].style
,
1324 clist
->clist_window
);
1328 ctree_detach_styles (GtkCMCTree
*ctree
,
1329 GtkCMCTreeNode
*node
,
1335 clist
= GTK_CMCLIST (ctree
);
1337 if (GTK_CMCTREE_ROW (node
)->row
.style
)
1338 gtk_style_detach (GTK_CMCTREE_ROW (node
)->row
.style
);
1339 for (i
= 0; i
< clist
->columns
; i
++)
1340 if (GTK_CMCTREE_ROW (node
)->row
.cell
[i
].style
)
1341 gtk_style_detach (GTK_CMCTREE_ROW (node
)->row
.cell
[i
].style
);
1345 gtk_cmctree_realize (GtkWidget
*widget
)
1349 GtkCMCTreeNode
*node
;
1350 GtkCMCTreeNode
*child
;
1353 cm_return_if_fail (GTK_IS_CMCTREE (widget
));
1355 GTK_WIDGET_CLASS (parent_class
)->realize (widget
);
1357 ctree
= GTK_CMCTREE (widget
);
1358 clist
= GTK_CMCLIST (widget
);
1360 node
= GTK_CMCTREE_NODE (clist
->row_list
);
1361 for (i
= 0; i
< clist
->rows
; i
++)
1363 if (GTK_CMCTREE_ROW (node
)->children
&& !GTK_CMCTREE_ROW (node
)->expanded
)
1364 for (child
= GTK_CMCTREE_ROW (node
)->children
; child
;
1365 child
= GTK_CMCTREE_ROW (child
)->sibling
)
1366 gtk_cmctree_pre_recursive (ctree
, child
, ctree_attach_styles
, NULL
);
1367 node
= GTK_CMCTREE_NODE_NEXT (node
);
1372 gtk_cmctree_unrealize (GtkWidget
*widget
)
1377 cm_return_if_fail (GTK_IS_CMCTREE (widget
));
1379 GTK_WIDGET_CLASS (parent_class
)->unrealize (widget
);
1381 ctree
= GTK_CMCTREE (widget
);
1382 clist
= GTK_CMCLIST (widget
);
1384 if (gtk_widget_get_realized (widget
))
1386 GtkCMCTreeNode
*node
;
1387 GtkCMCTreeNode
*child
;
1390 node
= GTK_CMCTREE_NODE (clist
->row_list
);
1391 for (i
= 0; i
< clist
->rows
; i
++)
1393 if (GTK_CMCTREE_ROW (node
)->children
&&
1394 !GTK_CMCTREE_ROW (node
)->expanded
)
1395 for (child
= GTK_CMCTREE_ROW (node
)->children
; child
;
1396 child
= GTK_CMCTREE_ROW (child
)->sibling
)
1397 gtk_cmctree_pre_recursive(ctree
, child
, ctree_detach_styles
, NULL
);
1398 node
= GTK_CMCTREE_NODE_NEXT (node
);
1404 gtk_cmctree_button_press (GtkWidget
*widget
,
1405 GdkEventButton
*event
)
1409 gint button_actions
;
1411 cm_return_val_if_fail (GTK_IS_CMCTREE (widget
), FALSE
);
1412 cm_return_val_if_fail (event
!= NULL
, FALSE
);
1414 ctree
= GTK_CMCTREE (widget
);
1415 clist
= GTK_CMCLIST (widget
);
1417 button_actions
= clist
->button_actions
[event
->button
- 1];
1419 if (button_actions
== GTK_CMBUTTON_IGNORED
)
1422 if (event
->window
== clist
->clist_window
)
1424 GtkCMCTreeNode
*work
;
1433 if (!gtk_cmclist_get_selection_info (clist
, x
, y
, &row
, &column
))
1436 work
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, row
));
1438 if (button_actions
& GTK_CMBUTTON_EXPANDS
&&
1439 (GTK_CMCTREE_ROW (work
)->children
&& !GTK_CMCTREE_ROW (work
)->is_leaf
&&
1440 (event
->type
== GDK_2BUTTON_PRESS
||
1441 ctree_is_hot_spot (ctree
, work
, row
, x
, y
))))
1443 if (GTK_CMCTREE_ROW (work
)->expanded
)
1444 gtk_cmctree_collapse (ctree
, work
);
1446 gtk_cmctree_expand (ctree
, work
);
1452 return GTK_WIDGET_CLASS (parent_class
)->button_press_event (widget
, event
);
1455 static GtkCMCTreeNode
*
1456 gtk_cmctree_last_visible (GtkCMCTree
*ctree
,
1457 GtkCMCTreeNode
*node
)
1459 GtkCMCTreeNode
*work
;
1464 work
= GTK_CMCTREE_ROW (node
)->children
;
1466 if (!work
|| !GTK_CMCTREE_ROW (node
)->expanded
)
1469 while (GTK_CMCTREE_ROW (work
)->sibling
)
1470 work
= GTK_CMCTREE_ROW (work
)->sibling
;
1472 return gtk_cmctree_last_visible (ctree
, work
);
1476 gtk_cmctree_link (GtkCMCTree
*ctree
,
1477 GtkCMCTreeNode
*node
,
1478 GtkCMCTreeNode
*parent
,
1479 GtkCMCTreeNode
*sibling
,
1480 gboolean update_focus_row
)
1486 gboolean visible
= FALSE
;
1490 cm_return_if_fail (GTK_CMCTREE_ROW (sibling
)->parent
== parent
);
1491 cm_return_if_fail (node
!= NULL
);
1492 cm_return_if_fail (node
!= sibling
);
1493 cm_return_if_fail (node
!= parent
);
1495 clist
= GTK_CMCLIST (ctree
);
1497 if (update_focus_row
&& clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
1499 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
1501 g_list_free (clist
->undo_selection
);
1502 g_list_free (clist
->undo_unselection
);
1503 clist
->undo_selection
= NULL
;
1504 clist
->undo_unselection
= NULL
;
1507 for (rows
= 1, list_end
= (GList
*)node
; list_end
->next
;
1508 list_end
= list_end
->next
)
1511 GTK_CMCTREE_ROW (node
)->parent
= parent
;
1512 GTK_CMCTREE_ROW (node
)->sibling
= sibling
;
1514 if (!parent
|| (parent
&& (gtk_cmctree_is_viewable (ctree
, parent
) &&
1515 GTK_CMCTREE_ROW (parent
)->expanded
)))
1518 clist
->rows
+= rows
;
1522 work
= (GList
*)(GTK_CMCTREE_ROW (parent
)->children
);
1524 work
= clist
->row_list
;
1528 if (work
!= (GList
*)sibling
)
1530 while (GTK_CMCTREE_ROW (work
)->sibling
!= sibling
)
1531 work
= (GList
*)(GTK_CMCTREE_ROW (work
)->sibling
);
1532 GTK_CMCTREE_ROW (work
)->sibling
= node
;
1535 if (sibling
== GTK_CMCTREE_NODE (clist
->row_list
))
1536 clist
->row_list
= (GList
*) node
;
1537 if (GTK_CMCTREE_NODE_PREV (sibling
) &&
1538 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling
)) == sibling
)
1540 list
= (GList
*)GTK_CMCTREE_NODE_PREV (sibling
);
1541 list
->next
= (GList
*)node
;
1544 list
= (GList
*)node
;
1545 list
->prev
= (GList
*)GTK_CMCTREE_NODE_PREV (sibling
);
1546 list_end
->next
= (GList
*)sibling
;
1547 list
= (GList
*)sibling
;
1548 list
->prev
= list_end
;
1549 if (parent
&& GTK_CMCTREE_ROW (parent
)->children
== sibling
)
1550 GTK_CMCTREE_ROW (parent
)->children
= node
;
1557 while (GTK_CMCTREE_ROW (work
)->sibling
)
1558 work
= (GList
*)(GTK_CMCTREE_ROW (work
)->sibling
);
1559 GTK_CMCTREE_ROW (work
)->sibling
= node
;
1561 /* find last visible child of sibling */
1562 work
= (GList
*) gtk_cmctree_last_visible (ctree
,
1563 GTK_CMCTREE_NODE (work
));
1565 list_end
->next
= work
->next
;
1567 work
->next
->prev
= list_end
;
1568 work
->next
= (GList
*)node
;
1569 list
= (GList
*)node
;
1576 GTK_CMCTREE_ROW (parent
)->children
= node
;
1577 list
= (GList
*)node
;
1578 list
->prev
= (GList
*)parent
;
1579 if (GTK_CMCTREE_ROW (parent
)->expanded
)
1581 list_end
->next
= (GList
*)GTK_CMCTREE_NODE_NEXT (parent
);
1582 if (GTK_CMCTREE_NODE_NEXT(parent
))
1584 list
= (GList
*)GTK_CMCTREE_NODE_NEXT (parent
);
1585 list
->prev
= list_end
;
1587 list
= (GList
*)parent
;
1588 list
->next
= (GList
*)node
;
1591 list_end
->next
= NULL
;
1595 clist
->row_list
= (GList
*)node
;
1596 list
= (GList
*)node
;
1598 list_end
->next
= NULL
;
1603 gtk_cmctree_pre_recursive (ctree
, node
, tree_update_level
, NULL
);
1605 if (clist
->row_list_end
== NULL
||
1606 clist
->row_list_end
->next
== (GList
*)node
)
1607 clist
->row_list_end
= list_end
;
1609 if (visible
&& update_focus_row
)
1613 pos
= g_list_position (clist
->row_list
, (GList
*)node
);
1615 if (pos
<= clist
->focus_row
)
1617 clist
->focus_row
+= rows
;
1618 clist
->undo_anchor
= clist
->focus_row
;
1624 gtk_cmctree_unlink (GtkCMCTree
*ctree
,
1625 GtkCMCTreeNode
*node
,
1626 gboolean update_focus_row
)
1632 GtkCMCTreeNode
*work
;
1633 GtkCMCTreeNode
*parent
;
1636 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
1637 cm_return_if_fail (node
!= NULL
);
1639 clist
= GTK_CMCLIST (ctree
);
1641 if (update_focus_row
&& clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
1643 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
1645 g_list_free (clist
->undo_selection
);
1646 g_list_free (clist
->undo_unselection
);
1647 clist
->undo_selection
= NULL
;
1648 clist
->undo_unselection
= NULL
;
1651 visible
= gtk_cmctree_is_viewable (ctree
, node
);
1653 /* clist->row_list_end unlinked ? */
1655 (GTK_CMCTREE_NODE_NEXT (node
) == NULL
||
1656 (GTK_CMCTREE_ROW (node
)->children
&&
1657 gtk_cmctree_is_ancestor (ctree
, node
,
1658 GTK_CMCTREE_NODE (clist
->row_list_end
)))))
1659 clist
->row_list_end
= (GList
*) (GTK_CMCTREE_NODE_PREV (node
));
1663 level
= GTK_CMCTREE_ROW (node
)->level
;
1664 work
= GTK_CMCTREE_NODE_NEXT (node
);
1665 while (work
&& GTK_CMCTREE_ROW (work
)->level
> level
)
1667 work
= GTK_CMCTREE_NODE_NEXT (work
);
1673 clist
->rows
-= (rows
+ 1);
1675 if (update_focus_row
)
1679 pos
= g_list_position (clist
->row_list
, (GList
*)node
);
1680 if (pos
+ rows
< clist
->focus_row
)
1681 clist
->focus_row
-= (rows
+ 1);
1682 else if (pos
<= clist
->focus_row
)
1684 if (!GTK_CMCTREE_ROW (node
)->sibling
)
1685 clist
->focus_row
= MAX (pos
- 1, 0);
1687 clist
->focus_row
= pos
;
1689 clist
->focus_row
= MIN (clist
->focus_row
, clist
->rows
- 1);
1691 clist
->undo_anchor
= clist
->focus_row
;
1697 list
= (GList
*)GTK_CMCTREE_NODE_PREV (work
);
1699 list
= (GList
*)work
;
1700 list
->prev
= (GList
*)GTK_CMCTREE_NODE_PREV (node
);
1703 if (GTK_CMCTREE_NODE_PREV (node
) &&
1704 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node
)) == node
)
1706 list
= (GList
*)GTK_CMCTREE_NODE_PREV (node
);
1707 list
->next
= (GList
*)work
;
1711 parent
= GTK_CMCTREE_ROW (node
)->parent
;
1714 if (GTK_CMCTREE_ROW (parent
)->children
== node
)
1716 GTK_CMCTREE_ROW (parent
)->children
= GTK_CMCTREE_ROW (node
)->sibling
;
1717 if (!GTK_CMCTREE_ROW (parent
)->children
)
1718 gtk_cmctree_collapse (ctree
, parent
);
1722 GtkCMCTreeNode
*sibling
;
1724 sibling
= GTK_CMCTREE_ROW (parent
)->children
;
1725 while (GTK_CMCTREE_ROW (sibling
)->sibling
!= node
)
1726 sibling
= GTK_CMCTREE_ROW (sibling
)->sibling
;
1727 GTK_CMCTREE_ROW (sibling
)->sibling
= GTK_CMCTREE_ROW (node
)->sibling
;
1732 if (clist
->row_list
== (GList
*)node
)
1733 clist
->row_list
= (GList
*) (GTK_CMCTREE_ROW (node
)->sibling
);
1736 GtkCMCTreeNode
*sibling
;
1738 sibling
= GTK_CMCTREE_NODE (clist
->row_list
);
1739 while (GTK_CMCTREE_ROW (sibling
)->sibling
!= node
)
1740 sibling
= GTK_CMCTREE_ROW (sibling
)->sibling
;
1741 GTK_CMCTREE_ROW (sibling
)->sibling
= GTK_CMCTREE_ROW (node
)->sibling
;
1747 real_row_move (GtkCMCList
*clist
,
1752 GtkCMCTreeNode
*node
;
1754 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
1756 if (GTK_CMCLIST_AUTO_SORT (clist
))
1759 if (source_row
< 0 || source_row
>= clist
->rows
||
1760 dest_row
< 0 || dest_row
>= clist
->rows
||
1761 source_row
== dest_row
)
1764 ctree
= GTK_CMCTREE (clist
);
1765 node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, source_row
));
1767 if (source_row
< dest_row
)
1769 GtkCMCTreeNode
*work
;
1772 work
= GTK_CMCTREE_ROW (node
)->children
;
1774 while (work
&& GTK_CMCTREE_ROW (work
)->level
> GTK_CMCTREE_ROW (node
)->level
)
1776 work
= GTK_CMCTREE_NODE_NEXT (work
);
1780 if (dest_row
> clist
->rows
)
1781 dest_row
= clist
->rows
;
1784 if (dest_row
< clist
->rows
)
1786 GtkCMCTreeNode
*sibling
;
1788 sibling
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, dest_row
));
1789 gtk_cmctree_move (ctree
, node
, GTK_CMCTREE_ROW (sibling
)->parent
, sibling
);
1792 gtk_cmctree_move (ctree
, node
, NULL
, NULL
);
1796 real_tree_move (GtkCMCTree
*ctree
,
1797 GtkCMCTreeNode
*node
,
1798 GtkCMCTreeNode
*new_parent
,
1799 GtkCMCTreeNode
*new_sibling
)
1802 GtkCMCTreeNode
*work
;
1803 gboolean visible
= FALSE
;
1805 cm_return_if_fail (ctree
!= NULL
);
1806 cm_return_if_fail (node
!= NULL
);
1807 cm_return_if_fail (!new_sibling
||
1808 GTK_CMCTREE_ROW (new_sibling
)->parent
== new_parent
);
1810 if (new_parent
&& GTK_CMCTREE_ROW (new_parent
)->is_leaf
)
1813 /* new_parent != child of child */
1814 for (work
= new_parent
; work
; work
= GTK_CMCTREE_ROW (work
)->parent
)
1818 clist
= GTK_CMCLIST (ctree
);
1820 visible
= gtk_cmctree_is_viewable (ctree
, node
);
1822 if (clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
1824 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
1826 g_list_free (clist
->undo_selection
);
1827 g_list_free (clist
->undo_unselection
);
1828 clist
->undo_selection
= NULL
;
1829 clist
->undo_unselection
= NULL
;
1832 if (GTK_CMCLIST_AUTO_SORT (clist
))
1834 if (new_parent
== GTK_CMCTREE_ROW (node
)->parent
)
1838 new_sibling
= GTK_CMCTREE_ROW (new_parent
)->children
;
1840 new_sibling
= GTK_CMCTREE_NODE (clist
->row_list
);
1842 while (new_sibling
&& clist
->compare
1843 (clist
, GTK_CMCTREE_ROW (node
), GTK_CMCTREE_ROW (new_sibling
)) > 0)
1844 new_sibling
= GTK_CMCTREE_ROW (new_sibling
)->sibling
;
1847 if (new_parent
== GTK_CMCTREE_ROW (node
)->parent
&&
1848 new_sibling
== GTK_CMCTREE_ROW (node
)->sibling
)
1851 gtk_cmclist_freeze (clist
);
1854 if (gtk_cmctree_is_viewable (ctree
, node
))
1855 work
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, clist
->focus_row
));
1857 gtk_cmctree_unlink (ctree
, node
, FALSE
);
1858 gtk_cmctree_link (ctree
, node
, new_parent
, new_sibling
, FALSE
);
1862 while (work
&& !gtk_cmctree_is_viewable (ctree
, work
))
1863 work
= GTK_CMCTREE_ROW (work
)->parent
;
1864 clist
->focus_row
= g_list_position (clist
->row_list
, (GList
*)work
);
1865 clist
->undo_anchor
= clist
->focus_row
;
1868 if (clist
->column
[ctree
->tree_column
].auto_resize
&&
1869 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
) &&
1870 (visible
|| gtk_cmctree_is_viewable (ctree
, node
)))
1871 gtk_cmclist_set_column_width
1872 (clist
, ctree
->tree_column
,
1873 gtk_cmclist_optimal_column_width (clist
, ctree
->tree_column
));
1875 gtk_cmclist_thaw (clist
);
1879 change_focus_row_expansion (GtkCMCTree
*ctree
,
1880 GtkCMCTreeExpansionType action
)
1883 GtkCMCTreeNode
*node
;
1885 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
1887 clist
= GTK_CMCLIST (ctree
);
1889 if (gtkut_pointer_is_grabbed (GTK_WIDGET (ctree
)) &&
1890 gtk_widget_has_grab (GTK_WIDGET(ctree
)))
1894 GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, clist
->focus_row
))) ||
1895 GTK_CMCTREE_ROW (node
)->is_leaf
|| !(GTK_CMCTREE_ROW (node
)->children
))
1900 case GTK_CMCTREE_EXPANSION_EXPAND
:
1901 gtk_cmctree_expand (ctree
, node
);
1903 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE
:
1904 gtk_cmctree_expand_recursive (ctree
, node
);
1906 case GTK_CMCTREE_EXPANSION_COLLAPSE
:
1907 gtk_cmctree_collapse (ctree
, node
);
1909 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE
:
1910 gtk_cmctree_collapse_recursive (ctree
, node
);
1912 case GTK_CMCTREE_EXPANSION_TOGGLE
:
1913 gtk_cmctree_toggle_expansion (ctree
, node
);
1915 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE
:
1916 gtk_cmctree_toggle_expansion_recursive (ctree
, node
);
1922 real_tree_expand (GtkCMCTree
*ctree
,
1923 GtkCMCTreeNode
*node
)
1926 GtkCMCTreeNode
*work
;
1927 GtkRequisition requisition
;
1930 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
1932 if (!node
|| GTK_CMCTREE_ROW (node
)->expanded
|| GTK_CMCTREE_ROW (node
)->is_leaf
)
1935 clist
= GTK_CMCLIST (ctree
);
1937 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
1939 GTK_CMCTREE_ROW (node
)->expanded
= TRUE
;
1941 visible
= gtk_cmctree_is_viewable (ctree
, node
);
1942 /* get cell width if tree_column is auto resized */
1943 if (visible
&& clist
->column
[ctree
->tree_column
].auto_resize
&&
1944 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
1945 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
1946 (clist
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
, &requisition
);
1948 /* unref/unset closed pixbuf */
1949 if (GTK_CMCELL_PIXTEXT
1950 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
)
1954 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
);
1957 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
= NULL
;
1960 /* set/ref opened pixbuf */
1961 if (GTK_CMCTREE_ROW (node
)->pixbuf_opened
)
1964 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
=
1965 g_object_ref (GTK_CMCTREE_ROW (node
)->pixbuf_opened
);
1969 work
= GTK_CMCTREE_ROW (node
)->children
;
1972 GList
*list
= (GList
*)work
;
1973 gint
*cell_width
= NULL
;
1978 if (visible
&& !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
1980 cell_width
= g_new0 (gint
, clist
->columns
);
1981 if (clist
->column
[ctree
->tree_column
].auto_resize
)
1982 cell_width
[ctree
->tree_column
] = requisition
.width
;
1986 /* search maximum cell widths of auto_resize columns */
1987 for (i
= 0; i
< clist
->columns
; i
++)
1988 if (clist
->column
[i
].auto_resize
)
1990 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
1991 (clist
, >K_CMCTREE_ROW (work
)->row
, i
, &requisition
);
1992 cell_width
[i
] = MAX (requisition
.width
, cell_width
[i
]);
1995 list
= (GList
*)work
;
1996 work
= GTK_CMCTREE_NODE_NEXT (work
);
2003 list
= (GList
*)work
;
2004 work
= GTK_CMCTREE_NODE_NEXT (work
);
2008 list
->next
= (GList
*)GTK_CMCTREE_NODE_NEXT (node
);
2010 if (GTK_CMCTREE_NODE_NEXT (node
))
2014 tmp_list
= (GList
*)GTK_CMCTREE_NODE_NEXT (node
);
2015 tmp_list
->prev
= list
;
2018 clist
->row_list_end
= list
;
2020 list
= (GList
*)node
;
2021 list
->next
= (GList
*)(GTK_CMCTREE_ROW (node
)->children
);
2023 if (visible
&& !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2025 /* resize auto_resize columns if needed */
2026 for (i
= 0; i
< clist
->columns
; i
++)
2027 if (clist
->column
[i
].auto_resize
&&
2028 cell_width
[i
] > clist
->column
[i
].width
)
2029 gtk_cmclist_set_column_width (clist
, i
, cell_width
[i
]);
2030 g_free (cell_width
);
2032 /* update focus_row position */
2033 row
= g_list_position (clist
->row_list
, (GList
*)node
);
2034 if (row
< clist
->focus_row
)
2035 clist
->focus_row
+= tmp
;
2038 CLIST_REFRESH (clist
);
2041 else if (visible
&& clist
->column
[ctree
->tree_column
].auto_resize
)
2042 /* resize tree_column if needed */
2043 column_auto_resize (clist
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
,
2048 real_tree_collapse (GtkCMCTree
*ctree
,
2049 GtkCMCTreeNode
*node
)
2052 GtkCMCTreeNode
*work
;
2053 GtkRequisition requisition
;
2057 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
2059 if (!node
|| !GTK_CMCTREE_ROW (node
)->expanded
||
2060 GTK_CMCTREE_ROW (node
)->is_leaf
)
2063 clist
= GTK_CMCLIST (ctree
);
2065 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
2067 GTK_CMCTREE_ROW (node
)->expanded
= FALSE
;
2068 level
= GTK_CMCTREE_ROW (node
)->level
;
2070 visible
= gtk_cmctree_is_viewable (ctree
, node
);
2071 /* get cell width if tree_column is auto resized */
2072 if (visible
&& clist
->column
[ctree
->tree_column
].auto_resize
&&
2073 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2074 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
2075 (clist
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
, &requisition
);
2077 /* unref/unset opened pixbuf */
2078 if (GTK_CMCELL_PIXTEXT
2079 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
)
2083 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
);
2086 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
= NULL
;
2089 /* set/ref closed pixbuf */
2090 if (GTK_CMCTREE_ROW (node
)->pixbuf_closed
)
2093 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
=
2094 g_object_ref (GTK_CMCTREE_ROW (node
)->pixbuf_closed
);
2097 work
= GTK_CMCTREE_ROW (node
)->children
;
2104 while (work
&& GTK_CMCTREE_ROW (work
)->level
> level
)
2106 work
= GTK_CMCTREE_NODE_NEXT (work
);
2112 list
= (GList
*)node
;
2113 list
->next
= (GList
*)work
;
2114 list
= (GList
*)GTK_CMCTREE_NODE_PREV (work
);
2116 list
= (GList
*)work
;
2117 list
->prev
= (GList
*)node
;
2121 list
= (GList
*)node
;
2123 clist
->row_list_end
= (GList
*)node
;
2128 /* resize auto_resize columns if needed */
2129 auto_resize_columns (clist
);
2131 row
= g_list_position (clist
->row_list
, (GList
*)node
);
2132 if (row
< clist
->focus_row
)
2133 clist
->focus_row
-= tmp
;
2135 CLIST_REFRESH (clist
);
2138 else if (visible
&& clist
->column
[ctree
->tree_column
].auto_resize
&&
2139 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2140 /* resize tree_column if needed */
2141 column_auto_resize (clist
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
,
2147 column_auto_resize (GtkCMCList
*clist
,
2148 GtkCMCListRow
*clist_row
,
2152 /* resize column if needed for auto_resize */
2153 GtkRequisition requisition
;
2155 if (!clist
->column
[column
].auto_resize
||
2156 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2160 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
2161 column
, &requisition
);
2163 requisition
.width
= 0;
2165 if (requisition
.width
> clist
->column
[column
].width
)
2166 gtk_cmclist_set_column_width (clist
, column
, requisition
.width
);
2167 else if (requisition
.width
< old_width
&&
2168 old_width
== clist
->column
[column
].width
)
2173 /* run a "gtk_cmclist_optimal_column_width" but break, if
2174 * the column doesn't shrink */
2175 if (GTK_CMCLIST_SHOW_TITLES (clist
) && clist
->column
[column
].button
)
2178 gtk_widget_get_requisition (clist
->column
[column
].button
, &req
);
2179 new_width
= (req
.width
-
2180 (CELL_SPACING
+ (2 * COLUMN_INSET
)));
2185 for (list
= clist
->row_list
; list
; list
= list
->next
)
2187 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
2188 (clist
, GTK_CMCLIST_ROW (list
), column
, &requisition
);
2189 new_width
= MAX (new_width
, requisition
.width
);
2190 if (new_width
== clist
->column
[column
].width
)
2193 if (new_width
< clist
->column
[column
].width
)
2194 gtk_cmclist_set_column_width (clist
, column
, new_width
);
2199 auto_resize_columns (GtkCMCList
*clist
)
2203 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2206 for (i
= 0; i
< clist
->columns
; i
++)
2207 column_auto_resize (clist
, NULL
, i
, clist
->column
[i
].width
);
2211 cell_size_request (GtkCMCList
*clist
,
2212 GtkCMCListRow
*clist_row
,
2214 GtkRequisition
*requisition
)
2219 PangoLayout
*layout
;
2220 PangoRectangle logical_rect
;
2222 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2223 cm_return_if_fail (requisition
!= NULL
);
2225 ctree
= GTK_CMCTREE (clist
);
2227 layout
= create_cell_layout (clist
, clist_row
, column
);
2230 pango_layout_get_pixel_extents (layout
, NULL
, &logical_rect
);
2232 requisition
->width
= logical_rect
.width
;
2233 requisition
->height
= logical_rect
.height
;
2235 g_object_unref (G_OBJECT (layout
));
2239 requisition
->width
= 0;
2240 requisition
->height
= 0;
2243 switch (clist_row
->cell
[column
].type
)
2245 case GTK_CMCELL_PIXTEXT
:
2246 if (GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
)
2248 width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
);
2249 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
);
2250 width
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
;
2255 requisition
->width
+= width
;
2256 requisition
->height
= MAX (requisition
->height
, height
);
2258 if (column
== ctree
->tree_column
)
2260 requisition
->width
+= (ctree
->tree_spacing
+ ctree
->tree_indent
*
2261 (((GtkCMCTreeRow
*) clist_row
)->level
- 1));
2262 switch (ctree
->expander_style
)
2264 case GTK_CMCTREE_EXPANDER_NONE
:
2266 case GTK_CMCTREE_EXPANDER_TRIANGLE
:
2267 requisition
->width
+= PM_SIZE
+ 3;
2272 case GTK_CMCELL_PIXBUF
:
2273 width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
);
2274 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
);
2275 requisition
->width
+= width
;
2276 requisition
->height
= MAX (requisition
->height
, height
);
2282 requisition
->width
+= clist_row
->cell
[column
].horizontal
;
2283 requisition
->height
+= clist_row
->cell
[column
].vertical
;
2287 set_cell_contents (GtkCMCList
*clist
,
2288 GtkCMCListRow
*clist_row
,
2295 gboolean visible
= FALSE
;
2297 GtkRequisition requisition
;
2298 gchar
*old_text
= NULL
;
2299 GdkPixbuf
*old_pixbuf
= NULL
;
2301 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2302 cm_return_if_fail (clist_row
!= NULL
);
2304 ctree
= GTK_CMCTREE (clist
);
2306 if (clist
->column
[column
].auto_resize
&&
2307 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2309 GtkCMCTreeNode
*parent
;
2311 parent
= ((GtkCMCTreeRow
*)clist_row
)->parent
;
2312 if ((parent
&& GTK_CMCTREE_ROW (parent
)->expanded
&&
2313 gtk_cmctree_is_viewable (ctree
, parent
)))
2316 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
2317 column
, &requisition
);
2321 switch (clist_row
->cell
[column
].type
)
2323 case GTK_CMCELL_EMPTY
:
2325 case GTK_CMCELL_TEXT
:
2326 old_text
= GTK_CMCELL_TEXT (clist_row
->cell
[column
])->text
;
2328 case GTK_CMCELL_PIXBUF
:
2329 old_pixbuf
= GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
;
2331 case GTK_CMCELL_PIXTEXT
:
2332 old_text
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
;
2333 old_pixbuf
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
;
2335 case GTK_CMCELL_WIDGET
:
2343 clist_row
->cell
[column
].type
= GTK_CMCELL_EMPTY
;
2344 if (column
== ctree
->tree_column
&& type
!= GTK_CMCELL_EMPTY
)
2345 type
= GTK_CMCELL_PIXTEXT
;
2347 /* Note that pixbuf and mask were already ref'ed by the caller
2351 case GTK_CMCELL_TEXT
:
2354 clist_row
->cell
[column
].type
= GTK_CMCELL_TEXT
;
2355 GTK_CMCELL_TEXT (clist_row
->cell
[column
])->text
= g_strdup (text
);
2358 case GTK_CMCELL_PIXBUF
:
2361 clist_row
->cell
[column
].type
= GTK_CMCELL_PIXBUF
;
2362 GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
= pixbuf
;
2365 case GTK_CMCELL_PIXTEXT
:
2366 if (column
== ctree
->tree_column
)
2368 clist_row
->cell
[column
].type
= GTK_CMCELL_PIXTEXT
;
2369 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
= spacing
;
2371 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
= g_strdup (text
);
2373 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
= NULL
;
2376 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
= pixbuf
;
2380 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
= NULL
;
2383 else if (text
&& pixbuf
)
2385 clist_row
->cell
[column
].type
= GTK_CMCELL_PIXTEXT
;
2386 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
= g_strdup (text
);
2387 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
= spacing
;
2388 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
= pixbuf
;
2395 if (visible
&& clist
->column
[column
].auto_resize
&&
2396 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2397 column_auto_resize (clist
, clist_row
, column
, requisition
.width
);
2401 g_object_unref (old_pixbuf
);
2405 set_node_info (GtkCMCTree
*ctree
,
2406 GtkCMCTreeNode
*node
,
2409 GdkPixbuf
*pixbuf_closed
,
2410 GdkPixbuf
*pixbuf_opened
,
2414 if (GTK_CMCTREE_ROW (node
)->pixbuf_opened
)
2416 g_object_unref (GTK_CMCTREE_ROW (node
)->pixbuf_opened
);
2418 if (GTK_CMCTREE_ROW (node
)->pixbuf_closed
)
2420 g_object_unref (GTK_CMCTREE_ROW (node
)->pixbuf_closed
);
2423 GTK_CMCTREE_ROW (node
)->pixbuf_opened
= NULL
;
2424 GTK_CMCTREE_ROW (node
)->pixbuf_closed
= NULL
;
2428 GTK_CMCTREE_ROW (node
)->pixbuf_closed
= g_object_ref (pixbuf_closed
);
2432 GTK_CMCTREE_ROW (node
)->pixbuf_opened
= g_object_ref (pixbuf_opened
);
2435 GTK_CMCTREE_ROW (node
)->is_leaf
= is_leaf
;
2436 GTK_CMCTREE_ROW (node
)->expanded
= (is_leaf
) ? FALSE
: expanded
;
2438 if (GTK_CMCTREE_ROW (node
)->expanded
)
2439 gtk_cmctree_node_set_pixtext (ctree
, node
, ctree
->tree_column
,
2440 text
, spacing
, pixbuf_opened
);
2442 gtk_cmctree_node_set_pixtext (ctree
, node
, ctree
->tree_column
,
2443 text
, spacing
, pixbuf_closed
);
2447 tree_delete (GtkCMCTree
*ctree
,
2448 GtkCMCTreeNode
*node
,
2451 tree_unselect (ctree
, node
, NULL
);
2452 row_delete (ctree
, GTK_CMCTREE_ROW (node
));
2453 g_list_free_1 ((GList
*)node
);
2457 tree_delete_row (GtkCMCTree
*ctree
,
2458 GtkCMCTreeNode
*node
,
2461 row_delete (ctree
, GTK_CMCTREE_ROW (node
));
2462 g_list_free_1 ((GList
*)node
);
2466 tree_update_level (GtkCMCTree
*ctree
,
2467 GtkCMCTreeNode
*node
,
2473 if (GTK_CMCTREE_ROW (node
)->parent
)
2474 GTK_CMCTREE_ROW (node
)->level
=
2475 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node
)->parent
)->level
+ 1;
2477 GTK_CMCTREE_ROW (node
)->level
= 1;
2481 tree_select (GtkCMCTree
*ctree
,
2482 GtkCMCTreeNode
*node
,
2485 if (node
&& GTK_CMCTREE_ROW (node
)->row
.state
!= GTK_STATE_SELECTED
&&
2486 GTK_CMCTREE_ROW (node
)->row
.selectable
)
2487 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_SELECT_ROW
], 0,
2492 tree_unselect (GtkCMCTree
*ctree
,
2493 GtkCMCTreeNode
*node
,
2496 if (node
&& GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
)
2497 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_UNSELECT_ROW
], 0,
2502 tree_expand (GtkCMCTree
*ctree
,
2503 GtkCMCTreeNode
*node
,
2506 if (node
&& !GTK_CMCTREE_ROW (node
)->expanded
)
2507 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_EXPAND
], 0,node
);
2511 tree_collapse (GtkCMCTree
*ctree
,
2512 GtkCMCTreeNode
*node
,
2515 if (node
&& GTK_CMCTREE_ROW (node
)->expanded
)
2516 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_COLLAPSE
], 0,node
);
2520 tree_collapse_to_depth (GtkCMCTree
*ctree
,
2521 GtkCMCTreeNode
*node
,
2524 if (node
&& GTK_CMCTREE_ROW (node
)->level
== depth
)
2525 gtk_cmctree_collapse_recursive (ctree
, node
);
2529 tree_toggle_expansion (GtkCMCTree
*ctree
,
2530 GtkCMCTreeNode
*node
,
2536 if (GTK_CMCTREE_ROW (node
)->expanded
)
2537 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_COLLAPSE
], 0,node
);
2539 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_EXPAND
], 0,node
);
2542 static GtkCMCTreeRow
*
2543 row_new (GtkCMCTree
*ctree
)
2546 GtkCMCTreeRow
*ctree_row
;
2549 clist
= GTK_CMCLIST (ctree
);
2550 ctree_row
= g_slice_new (GtkCMCTreeRow
);
2551 ctree_row
->row
.cell
= g_slice_alloc (sizeof (GtkCMCell
) * clist
->columns
);
2553 for (i
= 0; i
< clist
->columns
; i
++)
2555 ctree_row
->row
.cell
[i
].type
= GTK_CMCELL_EMPTY
;
2556 ctree_row
->row
.cell
[i
].vertical
= 0;
2557 ctree_row
->row
.cell
[i
].horizontal
= 0;
2558 ctree_row
->row
.cell
[i
].style
= NULL
;
2560 GTK_CMCELL_PIXTEXT (ctree_row
->row
.cell
[ctree
->tree_column
])->text
= NULL
;
2562 ctree_row
->row
.fg_set
= FALSE
;
2563 ctree_row
->row
.bg_set
= FALSE
;
2564 ctree_row
->row
.style
= NULL
;
2565 ctree_row
->row
.selectable
= TRUE
;
2566 ctree_row
->row
.state
= GTK_STATE_NORMAL
;
2567 ctree_row
->row
.data
= NULL
;
2568 ctree_row
->row
.destroy
= NULL
;
2570 ctree_row
->level
= 0;
2571 ctree_row
->expanded
= FALSE
;
2572 ctree_row
->parent
= NULL
;
2573 ctree_row
->sibling
= NULL
;
2574 ctree_row
->children
= NULL
;
2575 ctree_row
->pixbuf_closed
= NULL
;
2576 ctree_row
->pixbuf_opened
= NULL
;
2582 row_delete (GtkCMCTree
*ctree
,
2583 GtkCMCTreeRow
*ctree_row
)
2588 clist
= GTK_CMCLIST (ctree
);
2590 for (i
= 0; i
< clist
->columns
; i
++)
2592 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
2593 (clist
, &(ctree_row
->row
), i
, GTK_CMCELL_EMPTY
, NULL
, 0, NULL
);
2594 if (ctree_row
->row
.cell
[i
].style
)
2596 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
2597 gtk_style_detach (ctree_row
->row
.cell
[i
].style
);
2598 g_object_unref (ctree_row
->row
.cell
[i
].style
);
2602 if (ctree_row
->row
.style
)
2604 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
2605 gtk_style_detach (ctree_row
->row
.style
);
2606 g_object_unref (ctree_row
->row
.style
);
2609 if (ctree_row
->pixbuf_closed
)
2611 g_object_unref (ctree_row
->pixbuf_closed
);
2614 if (ctree_row
->pixbuf_opened
)
2616 g_object_unref (ctree_row
->pixbuf_opened
);
2619 if (ctree_row
->row
.destroy
)
2621 GDestroyNotify dnotify
= ctree_row
->row
.destroy
;
2622 gpointer ddata
= ctree_row
->row
.data
;
2624 ctree_row
->row
.destroy
= NULL
;
2625 ctree_row
->row
.data
= NULL
;
2630 g_slice_free1 (sizeof (GtkCMCell
) * clist
->columns
, ctree_row
->row
.cell
);
2631 g_slice_free (GtkCMCTreeRow
, ctree_row
);
2635 real_select_row (GtkCMCList
*clist
,
2642 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2644 if ((node
= g_list_nth (clist
->row_list
, row
)) &&
2645 GTK_CMCTREE_ROW (node
)->row
.selectable
)
2646 g_signal_emit (G_OBJECT (clist
), ctree_signals
[TREE_SELECT_ROW
],0,
2651 real_unselect_row (GtkCMCList
*clist
,
2658 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2660 if ((node
= g_list_nth (clist
->row_list
, row
)))
2661 g_signal_emit (G_OBJECT (clist
), ctree_signals
[TREE_UNSELECT_ROW
],0,
2666 tree_draw_node (GtkCMCTree
*ctree
,
2667 GtkCMCTreeNode
*node
)
2671 clist
= GTK_CMCLIST (ctree
);
2673 if (CLIST_UNFROZEN (clist
) && gtk_cmctree_is_viewable (ctree
, node
))
2675 GtkCMCTreeNode
*work
;
2678 work
= GTK_CMCTREE_NODE (clist
->row_list
);
2679 while (work
&& work
!= node
)
2681 work
= GTK_CMCTREE_NODE_NEXT (work
);
2684 if (work
&& gtk_cmclist_row_is_visible (clist
, num
) != GTK_VISIBILITY_NONE
)
2685 GTK_CMCLIST_GET_CLASS(ctree
)->draw_row
2686 (clist
, NULL
, num
, GTK_CMCLIST_ROW ((GList
*) node
));
2691 real_tree_select (GtkCMCTree
*ctree
,
2692 GtkCMCTreeNode
*node
,
2697 GtkCMCTreeNode
*sel_row
;
2698 gboolean node_selected
;
2700 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
2702 if (!node
|| GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
||
2703 !GTK_CMCTREE_ROW (node
)->row
.selectable
)
2706 clist
= GTK_CMCLIST (ctree
);
2708 switch (clist
->selection_mode
)
2710 case GTK_SELECTION_SINGLE
:
2711 case GTK_SELECTION_BROWSE
:
2713 node_selected
= FALSE
;
2714 list
= clist
->selection
;
2718 sel_row
= list
->data
;
2721 if (node
== sel_row
)
2722 node_selected
= TRUE
;
2724 g_signal_emit (G_OBJECT (ctree
),
2725 ctree_signals
[TREE_UNSELECT_ROW
], 0, sel_row
, column
);
2735 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_SELECTED
;
2737 if (!clist
->selection
)
2739 clist
->selection
= g_list_append (clist
->selection
, node
);
2740 clist
->selection_end
= clist
->selection
;
2743 clist
->selection_end
= g_list_append (clist
->selection_end
, node
)->next
;
2745 tree_draw_node (ctree
, node
);
2749 real_tree_unselect (GtkCMCTree
*ctree
,
2750 GtkCMCTreeNode
*node
,
2755 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
2757 if (!node
|| GTK_CMCTREE_ROW (node
)->row
.state
!= GTK_STATE_SELECTED
)
2760 clist
= GTK_CMCLIST (ctree
);
2762 if (clist
->selection_end
&& clist
->selection_end
->data
== node
)
2763 clist
->selection_end
= clist
->selection_end
->prev
;
2765 clist
->selection
= g_list_remove (clist
->selection
, node
);
2767 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_NORMAL
;
2769 tree_draw_node (ctree
, node
);
2773 select_row_recursive (GtkCMCTree
*ctree
,
2774 GtkCMCTreeNode
*node
,
2777 if (!node
|| GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
||
2778 !GTK_CMCTREE_ROW (node
)->row
.selectable
)
2781 GTK_CMCLIST (ctree
)->undo_unselection
=
2782 g_list_prepend (GTK_CMCLIST (ctree
)->undo_unselection
, node
);
2783 gtk_cmctree_select (ctree
, node
);
2787 real_select_all (GtkCMCList
*clist
)
2790 GtkCMCTreeNode
*node
;
2792 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2794 ctree
= GTK_CMCTREE (clist
);
2796 switch (clist
->selection_mode
)
2798 case GTK_SELECTION_SINGLE
:
2799 case GTK_SELECTION_BROWSE
:
2802 case GTK_SELECTION_MULTIPLE
:
2804 gtk_cmclist_freeze (clist
);
2806 g_list_free (clist
->undo_selection
);
2807 g_list_free (clist
->undo_unselection
);
2808 clist
->undo_selection
= NULL
;
2809 clist
->undo_unselection
= NULL
;
2811 clist
->anchor_state
= GTK_STATE_SELECTED
;
2813 clist
->drag_pos
= -1;
2814 clist
->undo_anchor
= clist
->focus_row
;
2816 for (node
= GTK_CMCTREE_NODE (clist
->row_list
); node
;
2817 node
= GTK_CMCTREE_NODE_NEXT (node
))
2818 gtk_cmctree_pre_recursive (ctree
, node
, select_row_recursive
, NULL
);
2820 gtk_cmclist_thaw (clist
);
2830 real_unselect_all (GtkCMCList
*clist
)
2833 GtkCMCTreeNode
*node
;
2836 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
2838 ctree
= GTK_CMCTREE (clist
);
2840 switch (clist
->selection_mode
)
2842 case GTK_SELECTION_BROWSE
:
2843 if (clist
->focus_row
>= 0)
2847 GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, clist
->focus_row
)));
2852 case GTK_SELECTION_MULTIPLE
:
2853 g_list_free (clist
->undo_selection
);
2854 g_list_free (clist
->undo_unselection
);
2855 clist
->undo_selection
= NULL
;
2856 clist
->undo_unselection
= NULL
;
2859 clist
->drag_pos
= -1;
2860 clist
->undo_anchor
= clist
->focus_row
;
2867 list
= clist
->selection
;
2873 gtk_cmctree_unselect (ctree
, node
);
2878 ctree_is_hot_spot (GtkCMCTree
*ctree
,
2879 GtkCMCTreeNode
*node
,
2884 GtkCMCTreeRow
*tree_row
;
2890 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
2891 cm_return_val_if_fail (node
!= NULL
, FALSE
);
2893 clist
= GTK_CMCLIST (ctree
);
2895 if (!clist
->column
[ctree
->tree_column
].visible
||
2896 ctree
->expander_style
== GTK_CMCTREE_EXPANDER_NONE
)
2899 tree_row
= GTK_CMCTREE_ROW (node
);
2901 hotspot_size
= clist
->row_height
-2;
2902 if (hotspot_size
> clist
->column
[ctree
->tree_column
].area
.width
- 2)
2903 hotspot_size
= clist
->column
[ctree
->tree_column
].area
.width
- 2;
2905 yu
= (ROW_TOP_YPIXEL (clist
, row
) + (clist
->row_height
- hotspot_size
) / 2 -
2906 (clist
->row_height
- 1) % 2);
2908 if (clist
->column
[ctree
->tree_column
].justification
== GTK_JUSTIFY_RIGHT
)
2909 xl
= (clist
->column
[ctree
->tree_column
].area
.x
+
2910 clist
->column
[ctree
->tree_column
].area
.width
- 1 + clist
->hoffset
-
2911 (tree_row
->level
- 1) * ctree
->tree_indent
- hotspot_size
);
2913 xl
= (clist
->column
[ctree
->tree_column
].area
.x
+ clist
->hoffset
+
2914 (tree_row
->level
- 1) * ctree
->tree_indent
);
2916 return (x
>= xl
&& x
<= xl
+ hotspot_size
&& y
>= yu
&& y
<= yu
+ hotspot_size
);
2919 /***********************************************************
2920 ***********************************************************
2921 *** Public interface ***
2922 ***********************************************************
2923 ***********************************************************/
2926 /***********************************************************
2927 * Creation, insertion, deletion *
2928 ***********************************************************/
2931 gtk_cmctree_constructor (GType type
,
2932 guint n_construct_properties
,
2933 GObjectConstructParam
*construct_properties
)
2935 GObject
*object
= G_OBJECT_CLASS (parent_class
)->constructor (type
,
2936 n_construct_properties
,
2937 construct_properties
);
2943 gtk_cmctree_new_with_titles (gint columns
,
2949 cm_return_val_if_fail (columns
> 0, NULL
);
2950 cm_return_val_if_fail (tree_column
>= 0 && tree_column
< columns
, NULL
);
2952 widget
= gtk_widget_new (GTK_TYPE_CMCTREE
,
2953 "n_columns", columns
,
2954 "tree_column", tree_column
,
2958 GtkCMCList
*clist
= GTK_CMCLIST (widget
);
2961 for (i
= 0; i
< columns
; i
++)
2962 gtk_cmclist_set_column_title (clist
, i
, titles
[i
]);
2963 gtk_cmclist_column_titles_show (clist
);
2970 gtk_cmctree_new (gint columns
,
2973 return gtk_cmctree_new_with_titles (columns
, tree_column
, NULL
);
2977 real_insert_row (GtkCMCList
*clist
,
2981 GtkCMCTreeNode
*parent
= NULL
;
2982 GtkCMCTreeNode
*sibling
;
2983 GtkCMCTreeNode
*node
;
2985 cm_return_val_if_fail (GTK_IS_CMCTREE (clist
), -1);
2987 sibling
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, row
));
2989 parent
= GTK_CMCTREE_ROW (sibling
)->parent
;
2991 node
= gtk_cmctree_insert_node (GTK_CMCTREE (clist
), parent
, sibling
, text
, 5,
2992 NULL
, NULL
, TRUE
, FALSE
);
2994 if (GTK_CMCLIST_AUTO_SORT (clist
) || !sibling
)
2995 return g_list_position (clist
->row_list
, (GList
*) node
);
3001 gtk_cmctree_insert_node (GtkCMCTree
*ctree
,
3002 GtkCMCTreeNode
*parent
,
3003 GtkCMCTreeNode
*sibling
,
3006 GdkPixbuf
*pixbuf_closed
,
3007 GdkPixbuf
*pixbuf_opened
,
3012 GtkCMCTreeRow
*new_row
;
3013 GtkCMCTreeNode
*node
;
3017 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3019 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling
)->parent
== parent
, NULL
);
3021 if (parent
&& GTK_CMCTREE_ROW (parent
)->is_leaf
)
3024 clist
= GTK_CMCLIST (ctree
);
3026 /* create the row */
3027 new_row
= row_new (ctree
);
3028 list
= g_list_alloc ();
3029 list
->data
= new_row
;
3030 node
= GTK_CMCTREE_NODE (list
);
3033 for (i
= 0; i
< clist
->columns
; i
++)
3034 if (text
[i
] && i
!= ctree
->tree_column
)
3035 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
3036 (clist
, &(new_row
->row
), i
, GTK_CMCELL_TEXT
, text
[i
], 0, NULL
);
3038 set_node_info (ctree
, node
, text
?
3039 text
[ctree
->tree_column
] : NULL
, spacing
, pixbuf_closed
,
3040 pixbuf_opened
, is_leaf
, expanded
);
3042 /* sorted insertion */
3043 if (GTK_CMCLIST_AUTO_SORT (clist
))
3046 sibling
= GTK_CMCTREE_ROW (parent
)->children
;
3048 sibling
= GTK_CMCTREE_NODE (clist
->row_list
);
3050 while (sibling
&& clist
->compare
3051 (clist
, GTK_CMCTREE_ROW (node
), GTK_CMCTREE_ROW (sibling
)) > 0)
3052 sibling
= GTK_CMCTREE_ROW (sibling
)->sibling
;
3055 gtk_cmctree_link (ctree
, node
, parent
, sibling
, TRUE
);
3057 if (text
&& !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
) &&
3058 gtk_cmctree_is_viewable (ctree
, node
))
3060 for (i
= 0; i
< clist
->columns
; i
++)
3061 if (clist
->column
[i
].auto_resize
)
3062 column_auto_resize (clist
, &(new_row
->row
), i
, 0);
3065 if (clist
->rows
== 1)
3067 clist
->focus_row
= 0;
3068 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
)
3069 gtk_cmctree_select (ctree
, node
);
3073 CLIST_REFRESH (clist
);
3079 gtk_cmctree_insert_gnode (GtkCMCTree
*ctree
,
3080 GtkCMCTreeNode
*parent
,
3081 GtkCMCTreeNode
*sibling
,
3083 GtkCMCTreeGNodeFunc func
,
3087 GtkCMCTreeNode
*cnode
= NULL
;
3088 GtkCMCTreeNode
*child
= NULL
;
3089 GtkCMCTreeNode
*new_child
;
3094 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3095 cm_return_val_if_fail (gnode
!= NULL
, NULL
);
3096 cm_return_val_if_fail (func
!= NULL
, NULL
);
3098 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling
)->parent
== parent
, NULL
);
3100 clist
= GTK_CMCLIST (ctree
);
3103 depth
= GTK_CMCTREE_ROW (parent
)->level
+ 1;
3105 list
= g_list_alloc ();
3106 list
->data
= row_new (ctree
);
3107 cnode
= GTK_CMCTREE_NODE (list
);
3109 gtk_cmclist_freeze (clist
);
3111 set_node_info (ctree
, cnode
, "", 0, NULL
, NULL
, TRUE
, FALSE
);
3113 if (!func (ctree
, depth
, gnode
, cnode
, data
))
3115 tree_delete_row (ctree
, cnode
, NULL
);
3116 gtk_cmclist_thaw (clist
);
3120 if (GTK_CMCLIST_AUTO_SORT (clist
))
3123 sibling
= GTK_CMCTREE_ROW (parent
)->children
;
3125 sibling
= GTK_CMCTREE_NODE (clist
->row_list
);
3127 while (sibling
&& clist
->compare
3128 (clist
, GTK_CMCTREE_ROW (cnode
), GTK_CMCTREE_ROW (sibling
)) > 0)
3129 sibling
= GTK_CMCTREE_ROW (sibling
)->sibling
;
3132 gtk_cmctree_link (ctree
, cnode
, parent
, sibling
, TRUE
);
3134 for (work
= g_node_last_child (gnode
); work
; work
= work
->prev
)
3136 new_child
= gtk_cmctree_insert_gnode (ctree
, cnode
, child
,
3142 gtk_cmclist_thaw (clist
);
3148 gtk_cmctree_export_to_gnode (GtkCMCTree
*ctree
,
3151 GtkCMCTreeNode
*node
,
3152 GtkCMCTreeGNodeFunc func
,
3155 GtkCMCTreeNode
*work
;
3159 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3160 cm_return_val_if_fail (node
!= NULL
, NULL
);
3161 cm_return_val_if_fail (func
!= NULL
, NULL
);
3164 cm_return_val_if_fail (parent
!= NULL
, NULL
);
3165 cm_return_val_if_fail (sibling
->parent
== parent
, NULL
);
3168 gnode
= g_node_new (NULL
);
3169 depth
= g_node_depth (parent
) + 1;
3171 if (!func (ctree
, depth
, gnode
, node
, data
))
3173 g_node_destroy (gnode
);
3178 g_node_insert_before (parent
, sibling
, gnode
);
3180 if (!GTK_CMCTREE_ROW (node
)->is_leaf
)
3182 GNode
*new_sibling
= NULL
;
3184 for (work
= GTK_CMCTREE_ROW (node
)->children
; work
;
3185 work
= GTK_CMCTREE_ROW (work
)->sibling
)
3186 new_sibling
= gtk_cmctree_export_to_gnode (ctree
, gnode
, new_sibling
,
3189 g_node_reverse_children (gnode
);
3196 real_remove_row (GtkCMCList
*clist
,
3199 GtkCMCTreeNode
*node
;
3201 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
3203 node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, row
));
3206 gtk_cmctree_remove_node (GTK_CMCTREE (clist
), node
);
3210 gtk_cmctree_remove_node (GtkCMCTree
*ctree
,
3211 GtkCMCTreeNode
*node
)
3215 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3217 clist
= GTK_CMCLIST (ctree
);
3219 gtk_cmclist_freeze (clist
);
3223 gtk_cmctree_unlink (ctree
, node
, TRUE
);
3224 gtk_cmctree_post_recursive (ctree
, node
, GTK_CMCTREE_FUNC (tree_delete
),
3226 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
&& !clist
->selection
&&
3227 clist
->focus_row
>= 0)
3228 gtk_cmclist_select_row (clist
, clist
->focus_row
, -1);
3230 auto_resize_columns (clist
);
3233 gtk_cmclist_clear (clist
);
3235 gtk_cmclist_thaw (clist
);
3239 real_clear (GtkCMCList
*clist
)
3242 GtkCMCTreeNode
*work
;
3243 GtkCMCTreeNode
*ptr
;
3245 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
3247 ctree
= GTK_CMCTREE (clist
);
3249 /* remove all rows */
3250 work
= GTK_CMCTREE_NODE (clist
->row_list
);
3251 clist
->row_list
= NULL
;
3252 clist
->row_list_end
= NULL
;
3254 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3258 work
= GTK_CMCTREE_ROW (work
)->sibling
;
3259 gtk_cmctree_post_recursive (ctree
, ptr
, GTK_CMCTREE_FUNC (tree_delete_row
),
3262 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3264 parent_class
->clear (clist
);
3268 /***********************************************************
3269 * Generic recursive functions, querying / finding tree *
3271 ***********************************************************/
3275 gtk_cmctree_post_recursive (GtkCMCTree
*ctree
,
3276 GtkCMCTreeNode
*node
,
3277 GtkCMCTreeFunc func
,
3280 GtkCMCTreeNode
*work
;
3281 GtkCMCTreeNode
*tmp
;
3283 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3284 cm_return_if_fail (func
!= NULL
);
3287 work
= GTK_CMCTREE_ROW (node
)->children
;
3289 work
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3293 tmp
= GTK_CMCTREE_ROW (work
)->sibling
;
3294 gtk_cmctree_post_recursive (ctree
, work
, func
, data
);
3299 func (ctree
, node
, data
);
3303 gtk_cmctree_post_recursive_to_depth (GtkCMCTree
*ctree
,
3304 GtkCMCTreeNode
*node
,
3306 GtkCMCTreeFunc func
,
3309 GtkCMCTreeNode
*work
;
3310 GtkCMCTreeNode
*tmp
;
3312 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3313 cm_return_if_fail (func
!= NULL
);
3317 gtk_cmctree_post_recursive (ctree
, node
, func
, data
);
3322 work
= GTK_CMCTREE_ROW (node
)->children
;
3324 work
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3326 if (work
&& GTK_CMCTREE_ROW (work
)->level
<= depth
)
3330 tmp
= GTK_CMCTREE_ROW (work
)->sibling
;
3331 gtk_cmctree_post_recursive_to_depth (ctree
, work
, depth
, func
, data
);
3336 if (node
&& GTK_CMCTREE_ROW (node
)->level
<= depth
)
3337 func (ctree
, node
, data
);
3341 gtk_cmctree_pre_recursive (GtkCMCTree
*ctree
,
3342 GtkCMCTreeNode
*node
,
3343 GtkCMCTreeFunc func
,
3346 GtkCMCTreeNode
*work
;
3347 GtkCMCTreeNode
*tmp
;
3349 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3350 cm_return_if_fail (func
!= NULL
);
3354 work
= GTK_CMCTREE_ROW (node
)->children
;
3355 func (ctree
, node
, data
);
3358 work
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3362 tmp
= GTK_CMCTREE_ROW (work
)->sibling
;
3363 gtk_cmctree_pre_recursive (ctree
, work
, func
, data
);
3369 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree
*ctree
,
3370 GtkCMCTreeNode
*node
,
3372 GtkCMCTreeFunc func
,
3375 GtkCMCTreeNode
*work
;
3376 GtkCMCTreeNode
*tmp
;
3378 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3379 cm_return_if_fail (func
!= NULL
);
3383 gtk_cmctree_pre_recursive (ctree
, node
, func
, data
);
3389 work
= GTK_CMCTREE_ROW (node
)->children
;
3390 if (GTK_CMCTREE_ROW (node
)->level
<= depth
)
3391 func (ctree
, node
, data
);
3394 work
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3396 if (work
&& GTK_CMCTREE_ROW (work
)->level
<= depth
)
3400 tmp
= GTK_CMCTREE_ROW (work
)->sibling
;
3401 gtk_cmctree_pre_recursive_to_depth (ctree
, work
, depth
, func
, data
);
3408 gtk_cmctree_is_viewable (GtkCMCTree
*ctree
,
3409 GtkCMCTreeNode
*node
)
3411 GtkCMCTreeRow
*work
;
3413 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
3414 cm_return_val_if_fail (node
!= NULL
, FALSE
);
3416 work
= GTK_CMCTREE_ROW (node
);
3418 while (work
&& work
->parent
&& GTK_CMCTREE_ROW (work
->parent
)->expanded
)
3419 work
= GTK_CMCTREE_ROW (work
->parent
);
3428 gtk_cmctree_last (GtkCMCTree
*ctree
,
3429 GtkCMCTreeNode
*node
)
3431 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3436 while (GTK_CMCTREE_ROW (node
)->sibling
)
3437 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3439 if (GTK_CMCTREE_ROW (node
)->children
)
3440 return gtk_cmctree_last (ctree
, GTK_CMCTREE_ROW (node
)->children
);
3446 gtk_cmctree_find_node_ptr (GtkCMCTree
*ctree
,
3447 GtkCMCTreeRow
*ctree_row
)
3449 GtkCMCTreeNode
*node
;
3451 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3452 cm_return_val_if_fail (ctree_row
!= NULL
, NULL
);
3454 if (ctree_row
->parent
)
3455 node
= GTK_CMCTREE_ROW (ctree_row
->parent
)->children
;
3457 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3459 while (GTK_CMCTREE_ROW (node
) != ctree_row
)
3460 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3466 gtk_cmctree_node_nth (GtkCMCTree
*ctree
,
3469 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3471 if ((row
>= GTK_CMCLIST(ctree
)->rows
))
3474 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree
)->row_list
, row
));
3478 gtk_cmctree_find (GtkCMCTree
*ctree
,
3479 GtkCMCTreeNode
*node
,
3480 GtkCMCTreeNode
*child
)
3486 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3492 if (GTK_CMCTREE_ROW (node
)->children
)
3494 if (gtk_cmctree_find (ctree
, GTK_CMCTREE_ROW (node
)->children
, child
))
3497 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3503 gtk_cmctree_is_ancestor (GtkCMCTree
*ctree
,
3504 GtkCMCTreeNode
*node
,
3505 GtkCMCTreeNode
*child
)
3507 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
3508 cm_return_val_if_fail (node
!= NULL
, FALSE
);
3510 if (GTK_CMCTREE_ROW (node
)->children
)
3511 return gtk_cmctree_find (ctree
, GTK_CMCTREE_ROW (node
)->children
, child
);
3517 gtk_cmctree_find_by_row_data (GtkCMCTree
*ctree
,
3518 GtkCMCTreeNode
*node
,
3521 GtkCMCTreeNode
*work
;
3524 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3528 if (GTK_CMCTREE_ROW (node
)->row
.data
== data
)
3530 if (GTK_CMCTREE_ROW (node
)->children
&&
3531 (work
= gtk_cmctree_find_by_row_data
3532 (ctree
, GTK_CMCTREE_ROW (node
)->children
, data
)))
3534 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3540 gtk_cmctree_find_all_by_row_data (GtkCMCTree
*ctree
,
3541 GtkCMCTreeNode
*node
,
3546 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3548 /* if node == NULL then look in the whole tree */
3550 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3554 if (GTK_CMCTREE_ROW (node
)->row
.data
== data
)
3555 list
= g_list_append (list
, node
);
3557 if (GTK_CMCTREE_ROW (node
)->children
)
3561 sub_list
= gtk_cmctree_find_all_by_row_data (ctree
,
3565 list
= g_list_concat (list
, sub_list
);
3567 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3573 gtk_cmctree_find_by_row_data_custom (GtkCMCTree
*ctree
,
3574 GtkCMCTreeNode
*node
,
3578 GtkCMCTreeNode
*work
;
3580 cm_return_val_if_fail (func
!= NULL
, NULL
);
3583 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3587 if (!func (GTK_CMCTREE_ROW (node
)->row
.data
, data
))
3589 if (GTK_CMCTREE_ROW (node
)->children
&&
3590 (work
= gtk_cmctree_find_by_row_data_custom
3591 (ctree
, GTK_CMCTREE_ROW (node
)->children
, data
, func
)))
3593 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3599 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree
*ctree
,
3600 GtkCMCTreeNode
*node
,
3606 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
3607 cm_return_val_if_fail (func
!= NULL
, NULL
);
3609 /* if node == NULL then look in the whole tree */
3611 node
= GTK_CMCTREE_NODE (GTK_CMCLIST (ctree
)->row_list
);
3615 if (!func (GTK_CMCTREE_ROW (node
)->row
.data
, data
))
3616 list
= g_list_append (list
, node
);
3618 if (GTK_CMCTREE_ROW (node
)->children
)
3622 sub_list
= gtk_cmctree_find_all_by_row_data_custom (ctree
,
3627 list
= g_list_concat (list
, sub_list
);
3629 node
= GTK_CMCTREE_ROW (node
)->sibling
;
3635 gtk_cmctree_is_hot_spot (GtkCMCTree
*ctree
,
3639 GtkCMCTreeNode
*node
;
3643 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
3645 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree
), x
, y
, &row
, &column
))
3646 if ((node
= GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree
)->row_list
, row
))))
3647 return ctree_is_hot_spot (ctree
, node
, row
, x
, y
);
3653 /***********************************************************
3654 * Tree signals : move, expand, collapse, (un)select *
3655 ***********************************************************/
3659 gtk_cmctree_move (GtkCMCTree
*ctree
,
3660 GtkCMCTreeNode
*node
,
3661 GtkCMCTreeNode
*new_parent
,
3662 GtkCMCTreeNode
*new_sibling
)
3664 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3665 cm_return_if_fail (node
!= NULL
);
3667 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_MOVE
], 0, node
,
3668 new_parent
, new_sibling
);
3672 gtk_cmctree_expand (GtkCMCTree
*ctree
,
3673 GtkCMCTreeNode
*node
)
3675 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3676 cm_return_if_fail (node
!= NULL
);
3678 if (GTK_CMCTREE_ROW (node
)->is_leaf
)
3681 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_EXPAND
], 0, node
);
3685 gtk_cmctree_expand_recursive (GtkCMCTree
*ctree
,
3686 GtkCMCTreeNode
*node
)
3689 gboolean thaw
= FALSE
;
3691 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3693 clist
= GTK_CMCLIST (ctree
);
3695 if (node
&& GTK_CMCTREE_ROW (node
)->is_leaf
)
3698 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3700 gtk_cmclist_freeze (clist
);
3704 gtk_cmctree_post_recursive (ctree
, node
, GTK_CMCTREE_FUNC (tree_expand
), NULL
);
3707 gtk_cmclist_thaw (clist
);
3711 gtk_cmctree_expand_to_depth (GtkCMCTree
*ctree
,
3712 GtkCMCTreeNode
*node
,
3716 gboolean thaw
= FALSE
;
3718 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3720 clist
= GTK_CMCLIST (ctree
);
3722 if (node
&& GTK_CMCTREE_ROW (node
)->is_leaf
)
3725 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3727 gtk_cmclist_freeze (clist
);
3731 gtk_cmctree_post_recursive_to_depth (ctree
, node
, depth
,
3732 GTK_CMCTREE_FUNC (tree_expand
), NULL
);
3735 gtk_cmclist_thaw (clist
);
3739 gtk_cmctree_collapse (GtkCMCTree
*ctree
,
3740 GtkCMCTreeNode
*node
)
3742 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3743 cm_return_if_fail (node
!= NULL
);
3745 if (GTK_CMCTREE_ROW (node
)->is_leaf
)
3748 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_COLLAPSE
], 0, node
);
3752 gtk_cmctree_collapse_recursive (GtkCMCTree
*ctree
,
3753 GtkCMCTreeNode
*node
)
3756 gboolean thaw
= FALSE
;
3759 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3761 if (node
&& GTK_CMCTREE_ROW (node
)->is_leaf
)
3764 clist
= GTK_CMCLIST (ctree
);
3766 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3768 gtk_cmclist_freeze (clist
);
3772 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3773 gtk_cmctree_post_recursive (ctree
, node
, GTK_CMCTREE_FUNC (tree_collapse
), NULL
);
3774 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3775 for (i
= 0; i
< clist
->columns
; i
++)
3776 if (clist
->column
[i
].auto_resize
)
3777 gtk_cmclist_set_column_width (clist
, i
,
3778 gtk_cmclist_optimal_column_width (clist
, i
));
3781 gtk_cmclist_thaw (clist
);
3785 gtk_cmctree_collapse_to_depth (GtkCMCTree
*ctree
,
3786 GtkCMCTreeNode
*node
,
3790 gboolean thaw
= FALSE
;
3793 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3795 if (node
&& GTK_CMCTREE_ROW (node
)->is_leaf
)
3798 clist
= GTK_CMCLIST (ctree
);
3800 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3802 gtk_cmclist_freeze (clist
);
3806 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3807 gtk_cmctree_post_recursive_to_depth (ctree
, node
, depth
,
3808 GTK_CMCTREE_FUNC (tree_collapse_to_depth
),
3809 GINT_TO_POINTER (depth
));
3810 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
3811 for (i
= 0; i
< clist
->columns
; i
++)
3812 if (clist
->column
[i
].auto_resize
)
3813 gtk_cmclist_set_column_width (clist
, i
,
3814 gtk_cmclist_optimal_column_width (clist
, i
));
3817 gtk_cmclist_thaw (clist
);
3821 gtk_cmctree_toggle_expansion (GtkCMCTree
*ctree
,
3822 GtkCMCTreeNode
*node
)
3824 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3825 cm_return_if_fail (node
!= NULL
);
3827 if (GTK_CMCTREE_ROW (node
)->is_leaf
)
3830 tree_toggle_expansion (ctree
, node
, NULL
);
3834 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree
*ctree
,
3835 GtkCMCTreeNode
*node
)
3838 gboolean thaw
= FALSE
;
3840 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3842 if (node
&& GTK_CMCTREE_ROW (node
)->is_leaf
)
3845 clist
= GTK_CMCLIST (ctree
);
3847 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3849 gtk_cmclist_freeze (clist
);
3853 gtk_cmctree_post_recursive (ctree
, node
,
3854 GTK_CMCTREE_FUNC (tree_toggle_expansion
), NULL
);
3857 gtk_cmclist_thaw (clist
);
3861 gtk_cmctree_select (GtkCMCTree
*ctree
,
3862 GtkCMCTreeNode
*node
)
3864 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3865 cm_return_if_fail (node
!= NULL
);
3867 if (GTK_CMCTREE_ROW (node
)->row
.selectable
)
3868 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_SELECT_ROW
], 0,
3873 gtk_cmctree_unselect (GtkCMCTree
*ctree
,
3874 GtkCMCTreeNode
*node
)
3876 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3877 cm_return_if_fail (node
!= NULL
);
3879 g_signal_emit (G_OBJECT (ctree
), ctree_signals
[TREE_UNSELECT_ROW
], 0,
3884 gtk_cmctree_select_recursive (GtkCMCTree
*ctree
,
3885 GtkCMCTreeNode
*node
)
3887 gtk_cmctree_real_select_recursive (ctree
, node
, TRUE
);
3891 gtk_cmctree_unselect_recursive (GtkCMCTree
*ctree
,
3892 GtkCMCTreeNode
*node
)
3894 gtk_cmctree_real_select_recursive (ctree
, node
, FALSE
);
3898 gtk_cmctree_real_select_recursive (GtkCMCTree
*ctree
,
3899 GtkCMCTreeNode
*node
,
3903 gboolean thaw
= FALSE
;
3905 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3907 clist
= GTK_CMCLIST (ctree
);
3910 (clist
->selection_mode
== GTK_SELECTION_BROWSE
||
3911 clist
->selection_mode
== GTK_SELECTION_SINGLE
)) ||
3912 (!state
&& clist
->selection_mode
== GTK_SELECTION_BROWSE
))
3915 if (CLIST_UNFROZEN (clist
) && (!node
|| gtk_cmctree_is_viewable (ctree
, node
)))
3917 gtk_cmclist_freeze (clist
);
3921 if (clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
3923 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
3925 g_list_free (clist
->undo_selection
);
3926 g_list_free (clist
->undo_unselection
);
3927 clist
->undo_selection
= NULL
;
3928 clist
->undo_unselection
= NULL
;
3932 gtk_cmctree_post_recursive (ctree
, node
,
3933 GTK_CMCTREE_FUNC (tree_select
), NULL
);
3935 gtk_cmctree_post_recursive (ctree
, node
,
3936 GTK_CMCTREE_FUNC (tree_unselect
), NULL
);
3939 gtk_cmclist_thaw (clist
);
3943 /***********************************************************
3944 * Analogons of GtkCMCList functions *
3945 ***********************************************************/
3949 gtk_cmctree_node_set_text (GtkCMCTree
*ctree
,
3950 GtkCMCTreeNode
*node
,
3956 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3957 cm_return_if_fail (node
!= NULL
);
3959 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
3962 clist
= GTK_CMCLIST (ctree
);
3964 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
3965 (clist
, &(GTK_CMCTREE_ROW (node
)->row
), column
, GTK_CMCELL_TEXT
,
3968 tree_draw_node (ctree
, node
);
3972 gtk_cmctree_node_set_pixbuf (GtkCMCTree
*ctree
,
3973 GtkCMCTreeNode
*node
,
3979 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
3980 cm_return_if_fail (node
!= NULL
);
3981 cm_return_if_fail (pixbuf
!= NULL
);
3983 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
3986 g_object_ref (pixbuf
);
3988 clist
= GTK_CMCLIST (ctree
);
3990 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
3991 (clist
, &(GTK_CMCTREE_ROW (node
)->row
), column
, GTK_CMCELL_PIXBUF
,
3994 tree_draw_node (ctree
, node
);
3998 gtk_cmctree_node_set_pixtext (GtkCMCTree
*ctree
,
3999 GtkCMCTreeNode
*node
,
4007 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4008 cm_return_if_fail (node
!= NULL
);
4009 if (column
!= ctree
->tree_column
)
4010 cm_return_if_fail (pixbuf
!= NULL
);
4011 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4014 clist
= GTK_CMCLIST (ctree
);
4018 g_object_ref (pixbuf
);
4021 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
4022 (clist
, &(GTK_CMCTREE_ROW (node
)->row
), column
, GTK_CMCELL_PIXTEXT
,
4023 text
, spacing
, pixbuf
);
4025 tree_draw_node (ctree
, node
);
4029 gtk_cmctree_set_node_info (GtkCMCTree
*ctree
,
4030 GtkCMCTreeNode
*node
,
4033 GdkPixbuf
*pixbuf_closed
,
4034 GdkPixbuf
*pixbuf_opened
,
4039 gboolean old_expanded
;
4041 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4042 cm_return_if_fail (node
!= NULL
);
4044 old_leaf
= GTK_CMCTREE_ROW (node
)->is_leaf
;
4045 old_expanded
= GTK_CMCTREE_ROW (node
)->expanded
;
4047 if (is_leaf
&& GTK_CMCTREE_ROW (node
)->children
)
4049 GtkCMCTreeNode
*work
;
4050 GtkCMCTreeNode
*ptr
;
4052 work
= GTK_CMCTREE_ROW (node
)->children
;
4056 work
= GTK_CMCTREE_ROW (work
)->sibling
;
4057 gtk_cmctree_remove_node (ctree
, ptr
);
4061 set_node_info (ctree
, node
, text
, spacing
, pixbuf_closed
,
4062 pixbuf_opened
, is_leaf
, expanded
);
4064 if (!is_leaf
&& !old_leaf
)
4066 GTK_CMCTREE_ROW (node
)->expanded
= old_expanded
;
4067 if (expanded
&& !old_expanded
)
4068 gtk_cmctree_expand (ctree
, node
);
4069 else if (!expanded
&& old_expanded
)
4070 gtk_cmctree_collapse (ctree
, node
);
4073 GTK_CMCTREE_ROW (node
)->expanded
= (is_leaf
) ? FALSE
: expanded
;
4075 tree_draw_node (ctree
, node
);
4079 gtk_cmctree_node_set_shift (GtkCMCTree
*ctree
,
4080 GtkCMCTreeNode
*node
,
4086 GtkRequisition requisition
;
4087 gboolean visible
= FALSE
;
4089 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4090 cm_return_if_fail (node
!= NULL
);
4092 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4095 clist
= GTK_CMCLIST (ctree
);
4097 if (clist
->column
[column
].auto_resize
&&
4098 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4100 visible
= gtk_cmctree_is_viewable (ctree
, node
);
4102 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
4103 (clist
, >K_CMCTREE_ROW (node
)->row
, column
, &requisition
);
4106 GTK_CMCTREE_ROW (node
)->row
.cell
[column
].vertical
= vertical
;
4107 GTK_CMCTREE_ROW (node
)->row
.cell
[column
].horizontal
= horizontal
;
4110 column_auto_resize (clist
, >K_CMCTREE_ROW (node
)->row
,
4111 column
, requisition
.width
);
4113 tree_draw_node (ctree
, node
);
4117 remove_grab (GtkCMCList
*clist
)
4119 if (gtkut_pointer_is_grabbed (GTK_WIDGET (clist
)) &&
4120 gtk_widget_has_grab (GTK_WIDGET(clist
)))
4122 gtk_grab_remove (GTK_WIDGET (clist
));
4123 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist
)),
4129 g_source_remove (clist
->htimer
);
4135 g_source_remove (clist
->vtimer
);
4141 gtk_cmctree_node_set_selectable (GtkCMCTree
*ctree
,
4142 GtkCMCTreeNode
*node
,
4143 gboolean selectable
)
4145 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4146 cm_return_if_fail (node
!= NULL
);
4148 if (selectable
== GTK_CMCTREE_ROW (node
)->row
.selectable
)
4151 GTK_CMCTREE_ROW (node
)->row
.selectable
= selectable
;
4153 if (!selectable
&& GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
)
4157 clist
= GTK_CMCLIST (ctree
);
4159 if (clist
->anchor
>= 0 &&
4160 clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
4162 clist
->drag_button
= 0;
4163 remove_grab (clist
);
4165 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
4167 gtk_cmctree_unselect (ctree
, node
);
4172 gtk_cmctree_node_get_selectable (GtkCMCTree
*ctree
,
4173 GtkCMCTreeNode
*node
)
4175 cm_return_val_if_fail (node
!= NULL
, FALSE
);
4177 return GTK_CMCTREE_ROW (node
)->row
.selectable
;
4181 gtk_cmctree_node_get_cell_type (GtkCMCTree
*ctree
,
4182 GtkCMCTreeNode
*node
,
4185 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), -1);
4186 cm_return_val_if_fail (node
!= NULL
, -1);
4188 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4191 return GTK_CMCTREE_ROW (node
)->row
.cell
[column
].type
;
4195 gtk_cmctree_node_get_text (GtkCMCTree
*ctree
,
4196 GtkCMCTreeNode
*node
,
4200 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
4201 cm_return_val_if_fail (node
!= NULL
, FALSE
);
4203 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4206 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].type
!= GTK_CMCELL_TEXT
)
4210 *text
= GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node
)->row
.cell
[column
])->text
;
4216 gtk_cmctree_node_get_pixbuf (GtkCMCTree
*ctree
,
4217 GtkCMCTreeNode
*node
,
4221 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
4222 cm_return_val_if_fail (node
!= NULL
, FALSE
);
4224 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4227 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].type
!= GTK_CMCELL_PIXBUF
)
4231 *pixbuf
= GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node
)->row
.cell
[column
])->pixbuf
;
4237 gtk_cmctree_node_get_pixtext (GtkCMCTree
*ctree
,
4238 GtkCMCTreeNode
*node
,
4244 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
4245 cm_return_val_if_fail (node
!= NULL
, FALSE
);
4247 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4250 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].type
!= GTK_CMCELL_PIXTEXT
)
4254 *text
= GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node
)->row
.cell
[column
])->text
;
4256 *spacing
= GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4257 (node
)->row
.cell
[column
])->spacing
;
4259 *pixbuf
= GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW
4260 (node
)->row
.cell
[column
])->pixbuf
;
4266 gtk_cmctree_get_node_info (GtkCMCTree
*ctree
,
4267 GtkCMCTreeNode
*node
,
4270 GdkPixbuf
**pixbuf_closed
,
4271 GdkPixbuf
**pixbuf_opened
,
4275 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
4276 cm_return_val_if_fail (node
!= NULL
, FALSE
);
4279 *text
= GTK_CMCELL_PIXTEXT
4280 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->text
;
4282 *spacing
= GTK_CMCELL_PIXTEXT
4283 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->spacing
;
4285 *pixbuf_closed
= GTK_CMCTREE_ROW (node
)->pixbuf_closed
;
4287 *pixbuf_opened
= GTK_CMCTREE_ROW (node
)->pixbuf_opened
;
4289 *is_leaf
= GTK_CMCTREE_ROW (node
)->is_leaf
;
4291 *expanded
= GTK_CMCTREE_ROW (node
)->expanded
;
4297 gtk_cmctree_node_set_cell_style (GtkCMCTree
*ctree
,
4298 GtkCMCTreeNode
*node
,
4303 GtkRequisition requisition
;
4304 gboolean visible
= FALSE
;
4306 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4307 cm_return_if_fail (node
!= NULL
);
4309 clist
= GTK_CMCLIST (ctree
);
4311 if (column
< 0 || column
>= clist
->columns
)
4314 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
== style
)
4317 if (clist
->column
[column
].auto_resize
&&
4318 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4320 visible
= gtk_cmctree_is_viewable (ctree
, node
);
4322 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
4323 (clist
, >K_CMCTREE_ROW (node
)->row
, column
, &requisition
);
4326 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
)
4328 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
4329 gtk_style_detach (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
);
4330 g_object_unref (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
);
4333 GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
= style
;
4335 if (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
)
4337 g_object_ref (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
);
4339 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
4340 GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
=
4341 gtk_style_attach (GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
,
4342 clist
->clist_window
);
4346 column_auto_resize (clist
, >K_CMCTREE_ROW (node
)->row
, column
,
4349 tree_draw_node (ctree
, node
);
4353 gtk_cmctree_node_get_cell_style (GtkCMCTree
*ctree
,
4354 GtkCMCTreeNode
*node
,
4357 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
4358 cm_return_val_if_fail (node
!= NULL
, NULL
);
4360 if (column
< 0 || column
>= GTK_CMCLIST (ctree
)->columns
)
4363 return GTK_CMCTREE_ROW (node
)->row
.cell
[column
].style
;
4367 gtk_cmctree_node_set_row_style (GtkCMCTree
*ctree
,
4368 GtkCMCTreeNode
*node
,
4372 GtkRequisition requisition
;
4374 gint
*old_width
= NULL
;
4377 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4378 cm_return_if_fail (node
!= NULL
);
4380 clist
= GTK_CMCLIST (ctree
);
4382 if (GTK_CMCTREE_ROW (node
)->row
.style
== style
)
4385 visible
= gtk_cmctree_is_viewable (ctree
, node
);
4386 if (visible
&& !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4388 old_width
= g_new (gint
, clist
->columns
);
4389 for (i
= 0; i
< clist
->columns
; i
++)
4390 if (clist
->column
[i
].auto_resize
)
4392 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
4393 (clist
, >K_CMCTREE_ROW (node
)->row
, i
, &requisition
);
4394 old_width
[i
] = requisition
.width
;
4398 if (GTK_CMCTREE_ROW (node
)->row
.style
)
4400 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
4401 gtk_style_detach (GTK_CMCTREE_ROW (node
)->row
.style
);
4402 g_object_unref (GTK_CMCTREE_ROW (node
)->row
.style
);
4405 GTK_CMCTREE_ROW (node
)->row
.style
= style
;
4407 if (GTK_CMCTREE_ROW (node
)->row
.style
)
4409 g_object_ref (GTK_CMCTREE_ROW (node
)->row
.style
);
4411 if (gtk_widget_get_realized (GTK_WIDGET(ctree
)))
4412 GTK_CMCTREE_ROW (node
)->row
.style
=
4413 gtk_style_attach (GTK_CMCTREE_ROW (node
)->row
.style
,
4414 clist
->clist_window
);
4417 if (visible
&& !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4419 for (i
= 0; i
< clist
->columns
; i
++)
4420 if (clist
->column
[i
].auto_resize
)
4421 column_auto_resize (clist
, >K_CMCTREE_ROW (node
)->row
, i
,
4425 tree_draw_node (ctree
, node
);
4429 gtk_cmctree_node_get_row_style (GtkCMCTree
*ctree
,
4430 GtkCMCTreeNode
*node
)
4432 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
4433 cm_return_val_if_fail (node
!= NULL
, NULL
);
4435 return GTK_CMCTREE_ROW (node
)->row
.style
;
4439 gtk_cmctree_node_set_foreground (GtkCMCTree
*ctree
,
4440 GtkCMCTreeNode
*node
,
4441 const GdkRGBA
*color
)
4443 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4444 cm_return_if_fail (node
!= NULL
);
4450 GTKUT_GDKRGBA_TO_GDKCOLOR((*color
), gdk_color
);
4451 GTK_CMCTREE_ROW (node
)->row
.foreground
= gdk_color
;
4452 GTK_CMCTREE_ROW (node
)->row
.fg_set
= TRUE
;
4455 GTK_CMCTREE_ROW (node
)->row
.fg_set
= FALSE
;
4457 tree_draw_node (ctree
, node
);
4461 gtk_cmctree_node_set_background (GtkCMCTree
*ctree
,
4462 GtkCMCTreeNode
*node
,
4463 const GdkRGBA
*color
)
4465 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4466 cm_return_if_fail (node
!= NULL
);
4472 GTKUT_GDKRGBA_TO_GDKCOLOR((*color
), gdk_color
);
4473 GTK_CMCTREE_ROW (node
)->row
.background
= gdk_color
;
4474 GTK_CMCTREE_ROW (node
)->row
.bg_set
= TRUE
;
4477 GTK_CMCTREE_ROW (node
)->row
.bg_set
= FALSE
;
4479 tree_draw_node (ctree
, node
);
4483 gtk_cmctree_node_set_row_data (GtkCMCTree
*ctree
,
4484 GtkCMCTreeNode
*node
,
4487 gtk_cmctree_node_set_row_data_full (ctree
, node
, data
, NULL
);
4491 gtk_cmctree_node_set_row_data_full (GtkCMCTree
*ctree
,
4492 GtkCMCTreeNode
*node
,
4494 GDestroyNotify destroy
)
4496 GDestroyNotify dnotify
;
4499 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4500 cm_return_if_fail (node
!= NULL
);
4502 dnotify
= GTK_CMCTREE_ROW (node
)->row
.destroy
;
4503 ddata
= GTK_CMCTREE_ROW (node
)->row
.data
;
4505 GTK_CMCTREE_ROW (node
)->row
.data
= data
;
4506 GTK_CMCTREE_ROW (node
)->row
.destroy
= destroy
;
4513 gtk_cmctree_node_get_row_data (GtkCMCTree
*ctree
,
4514 GtkCMCTreeNode
*node
)
4516 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
4518 return node
? GTK_CMCTREE_ROW (node
)->row
.data
: NULL
;
4522 gtk_cmctree_node_moveto (GtkCMCTree
*ctree
,
4523 GtkCMCTreeNode
*node
,
4531 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4533 clist
= GTK_CMCLIST (ctree
);
4535 while (node
&& !gtk_cmctree_is_viewable (ctree
, node
))
4536 node
= GTK_CMCTREE_ROW (node
)->parent
;
4539 row
= g_list_position (clist
->row_list
, (GList
*)node
);
4541 gtk_cmclist_moveto (clist
, row
, column
, row_align
, col_align
);
4545 gtk_cmctree_node_is_visible (GtkCMCTree
*ctree
,
4546 GtkCMCTreeNode
*node
)
4550 cm_return_val_if_fail (ctree
!= NULL
, 0);
4551 cm_return_val_if_fail (node
!= NULL
, 0);
4553 row
= g_list_position (GTK_CMCLIST (ctree
)->row_list
, (GList
*) node
);
4554 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree
), row
);
4558 /***********************************************************
4559 * GtkCMCTree specific functions *
4560 ***********************************************************/
4563 gtk_cmctree_set_indent (GtkCMCTree
*ctree
,
4568 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4569 cm_return_if_fail (indent
>= 0);
4571 if (indent
== ctree
->tree_indent
)
4574 clist
= GTK_CMCLIST (ctree
);
4575 ctree
->tree_indent
= indent
;
4577 if (clist
->column
[ctree
->tree_column
].auto_resize
&&
4578 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4579 gtk_cmclist_set_column_width
4580 (clist
, ctree
->tree_column
,
4581 gtk_cmclist_optimal_column_width (clist
, ctree
->tree_column
));
4583 CLIST_REFRESH (ctree
);
4587 gtk_cmctree_set_spacing (GtkCMCTree
*ctree
,
4593 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4594 cm_return_if_fail (spacing
>= 0);
4596 if (spacing
== ctree
->tree_spacing
)
4599 clist
= GTK_CMCLIST (ctree
);
4601 old_spacing
= ctree
->tree_spacing
;
4602 ctree
->tree_spacing
= spacing
;
4604 if (clist
->column
[ctree
->tree_column
].auto_resize
&&
4605 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4606 gtk_cmclist_set_column_width (clist
, ctree
->tree_column
,
4607 clist
->column
[ctree
->tree_column
].width
+
4608 spacing
- old_spacing
);
4610 CLIST_REFRESH (ctree
);
4614 gtk_cmctree_set_show_stub (GtkCMCTree
*ctree
,
4617 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4619 show_stub
= show_stub
!= FALSE
;
4621 if (show_stub
!= ctree
->show_stub
)
4625 clist
= GTK_CMCLIST (ctree
);
4626 ctree
->show_stub
= show_stub
;
4628 if (CLIST_UNFROZEN (clist
) && clist
->rows
&&
4629 gtk_cmclist_row_is_visible (clist
, 0) != GTK_VISIBILITY_NONE
)
4630 GTK_CMCLIST_GET_CLASS (clist
)->draw_row
4631 (clist
, NULL
, 0, GTK_CMCLIST_ROW (clist
->row_list
));
4636 gtk_cmctree_set_line_style (GtkCMCTree
*ctree
,
4637 GtkCMCTreeLineStyle line_style
)
4642 gtk_cmctree_set_expander_style (GtkCMCTree
*ctree
,
4643 GtkCMCTreeExpanderStyle expander_style
)
4646 GtkCMCTreeExpanderStyle old_style
;
4648 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4650 if (expander_style
== ctree
->expander_style
)
4653 clist
= GTK_CMCLIST (ctree
);
4655 old_style
= ctree
->expander_style
;
4656 ctree
->expander_style
= expander_style
;
4658 if (clist
->column
[ctree
->tree_column
].auto_resize
&&
4659 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4663 new_width
= clist
->column
[ctree
->tree_column
].width
;
4666 case GTK_CMCTREE_EXPANDER_NONE
:
4668 case GTK_CMCTREE_EXPANDER_TRIANGLE
:
4669 new_width
-= PM_SIZE
+ 3;
4673 switch (expander_style
)
4675 case GTK_CMCTREE_EXPANDER_NONE
:
4677 case GTK_CMCTREE_EXPANDER_TRIANGLE
:
4678 new_width
+= PM_SIZE
+ 3;
4682 gtk_cmclist_set_column_width (clist
, ctree
->tree_column
, new_width
);
4685 if (gtk_widget_is_drawable (GTK_WIDGET(clist
)))
4686 CLIST_REFRESH (clist
);
4690 /***********************************************************
4691 * Tree sorting functions *
4692 ***********************************************************/
4696 tree_sort (GtkCMCTree
*ctree
,
4697 GtkCMCTreeNode
*node
,
4700 GtkCMCTreeNode
*list_start
;
4701 GtkCMCTreeNode
*cmp
;
4702 GtkCMCTreeNode
*work
;
4705 clist
= GTK_CMCLIST (ctree
);
4708 list_start
= GTK_CMCTREE_ROW (node
)->children
;
4710 list_start
= GTK_CMCTREE_NODE (clist
->row_list
);
4715 work
= GTK_CMCTREE_ROW (cmp
)->sibling
;
4718 if (clist
->sort_type
== GTK_SORT_ASCENDING
)
4721 (clist
, GTK_CMCTREE_ROW (work
), GTK_CMCTREE_ROW (cmp
)) < 0)
4727 (clist
, GTK_CMCTREE_ROW (work
), GTK_CMCTREE_ROW (cmp
)) > 0)
4730 work
= GTK_CMCTREE_ROW (work
)->sibling
;
4732 if (cmp
== list_start
)
4733 list_start
= GTK_CMCTREE_ROW (cmp
)->sibling
;
4736 gtk_cmctree_unlink (ctree
, cmp
, FALSE
);
4737 gtk_cmctree_link (ctree
, cmp
, node
, list_start
, FALSE
);
4743 gtk_cmctree_sort_recursive (GtkCMCTree
*ctree
,
4744 GtkCMCTreeNode
*node
)
4747 GtkCMCTreeNode
*focus_node
= NULL
;
4749 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4751 clist
= GTK_CMCLIST (ctree
);
4753 gtk_cmclist_freeze (clist
);
4755 if (clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
4757 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
4759 g_list_free (clist
->undo_selection
);
4760 g_list_free (clist
->undo_unselection
);
4761 clist
->undo_selection
= NULL
;
4762 clist
->undo_unselection
= NULL
;
4765 if (!node
|| (node
&& gtk_cmctree_is_viewable (ctree
, node
)))
4767 GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, clist
->focus_row
));
4769 gtk_cmctree_post_recursive (ctree
, node
, GTK_CMCTREE_FUNC (tree_sort
), NULL
);
4772 tree_sort (ctree
, NULL
, NULL
);
4776 clist
->focus_row
= g_list_position (clist
->row_list
,(GList
*)focus_node
);
4777 clist
->undo_anchor
= clist
->focus_row
;
4780 gtk_cmclist_thaw (clist
);
4784 real_sort_list (GtkCMCList
*clist
)
4786 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist
), NULL
);
4790 gtk_cmctree_sort_node (GtkCMCTree
*ctree
,
4791 GtkCMCTreeNode
*node
)
4794 GtkCMCTreeNode
*focus_node
= NULL
;
4796 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
4798 clist
= GTK_CMCLIST (ctree
);
4800 gtk_cmclist_freeze (clist
);
4802 if (clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
4804 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
4806 g_list_free (clist
->undo_selection
);
4807 g_list_free (clist
->undo_unselection
);
4808 clist
->undo_selection
= NULL
;
4809 clist
->undo_unselection
= NULL
;
4812 if (!node
|| (node
&& gtk_cmctree_is_viewable (ctree
, node
)))
4813 focus_node
= GTK_CMCTREE_NODE
4814 (g_list_nth (clist
->row_list
, clist
->focus_row
));
4816 tree_sort (ctree
, node
, NULL
);
4820 clist
->focus_row
= g_list_position (clist
->row_list
,(GList
*)focus_node
);
4821 clist
->undo_anchor
= clist
->focus_row
;
4824 gtk_cmclist_thaw (clist
);
4827 /************************************************************************/
4830 fake_unselect_all (GtkCMCList
*clist
,
4834 GList
*focus_node
= NULL
;
4836 if (row
>= 0 && (focus_node
= g_list_nth (clist
->row_list
, row
)))
4838 if (GTK_CMCTREE_ROW (focus_node
)->row
.state
== GTK_STATE_NORMAL
&&
4839 GTK_CMCTREE_ROW (focus_node
)->row
.selectable
)
4841 GTK_CMCTREE_ROW (focus_node
)->row
.state
= GTK_STATE_SELECTED
;
4843 if (CLIST_UNFROZEN (clist
) &&
4844 gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
4845 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
,
4846 GTK_CMCLIST_ROW (focus_node
));
4850 clist
->undo_selection
= clist
->selection
;
4851 clist
->selection
= NULL
;
4852 clist
->selection_end
= NULL
;
4854 for (list
= clist
->undo_selection
; list
; list
= list
->next
)
4856 if (list
->data
== focus_node
)
4859 GTK_CMCTREE_ROW ((GList
*)(list
->data
))->row
.state
= GTK_STATE_NORMAL
;
4860 tree_draw_node (GTK_CMCTREE (clist
), GTK_CMCTREE_NODE (list
->data
));
4865 selection_find (GtkCMCList
*clist
,
4867 GList
*row_list_element
)
4869 return g_list_find (clist
->selection
, row_list_element
);
4873 resync_selection (GtkCMCList
*clist
, GdkEvent
*event
)
4877 GtkCMCTreeNode
*node
;
4883 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
4885 if (clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
4888 if (clist
->anchor
< 0 || clist
->drag_pos
< 0)
4891 ctree
= GTK_CMCTREE (clist
);
4893 clist
->freeze_count
++;
4895 i
= MIN (clist
->anchor
, clist
->drag_pos
);
4896 e
= MAX (clist
->anchor
, clist
->drag_pos
);
4898 if (clist
->undo_selection
)
4900 list
= clist
->selection
;
4901 clist
->selection
= clist
->undo_selection
;
4902 clist
->selection_end
= g_list_last (clist
->selection
);
4903 clist
->undo_selection
= list
;
4904 list
= clist
->selection
;
4913 if (gtk_cmctree_is_viewable (ctree
, node
))
4915 row
= g_list_position (clist
->row_list
, (GList
*)node
);
4916 if (row
>= i
&& row
<= e
)
4919 if (unselect
&& GTK_CMCTREE_ROW (node
)->row
.selectable
)
4921 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_SELECTED
;
4922 gtk_cmctree_unselect (ctree
, node
);
4923 clist
->undo_selection
= g_list_prepend (clist
->undo_selection
,
4929 if (clist
->anchor
< clist
->drag_pos
)
4931 for (node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, i
)); i
<= e
;
4932 i
++, node
= GTK_CMCTREE_NODE_NEXT (node
))
4933 if (GTK_CMCTREE_ROW (node
)->row
.selectable
)
4935 if (g_list_find (clist
->selection
, node
))
4937 if (GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_NORMAL
)
4939 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_SELECTED
;
4940 gtk_cmctree_unselect (ctree
, node
);
4941 clist
->undo_selection
=
4942 g_list_prepend (clist
->undo_selection
, node
);
4945 else if (GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
)
4947 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_NORMAL
;
4948 clist
->undo_unselection
=
4949 g_list_prepend (clist
->undo_unselection
, node
);
4955 for (node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
, e
)); i
<= e
;
4956 e
--, node
= GTK_CMCTREE_NODE_PREV (node
))
4957 if (GTK_CMCTREE_ROW (node
)->row
.selectable
)
4959 if (g_list_find (clist
->selection
, node
))
4961 if (GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_NORMAL
)
4963 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_SELECTED
;
4964 gtk_cmctree_unselect (ctree
, node
);
4965 clist
->undo_selection
=
4966 g_list_prepend (clist
->undo_selection
, node
);
4969 else if (GTK_CMCTREE_ROW (node
)->row
.state
== GTK_STATE_SELECTED
)
4971 GTK_CMCTREE_ROW (node
)->row
.state
= GTK_STATE_NORMAL
;
4972 clist
->undo_unselection
=
4973 g_list_prepend (clist
->undo_unselection
, node
);
4978 clist
->undo_unselection
= g_list_reverse (clist
->undo_unselection
);
4979 for (list
= clist
->undo_unselection
; list
; list
= list
->next
)
4980 gtk_cmctree_select (ctree
, list
->data
);
4983 clist
->drag_pos
= -1;
4985 if (!CLIST_UNFROZEN (clist
))
4986 clist
->freeze_count
--;
4990 real_undo_selection (GtkCMCList
*clist
)
4995 cm_return_if_fail (GTK_IS_CMCTREE (clist
));
4997 if (clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
5000 if (!(clist
->undo_selection
|| clist
->undo_unselection
))
5002 gtk_cmclist_unselect_all (clist
);
5006 ctree
= GTK_CMCTREE (clist
);
5008 for (work
= clist
->undo_selection
; work
; work
= work
->next
)
5009 if (GTK_CMCTREE_ROW (work
->data
)->row
.selectable
)
5010 gtk_cmctree_select (ctree
, GTK_CMCTREE_NODE (work
->data
));
5012 for (work
= clist
->undo_unselection
; work
; work
= work
->next
)
5013 if (GTK_CMCTREE_ROW (work
->data
)->row
.selectable
)
5014 gtk_cmctree_unselect (ctree
, GTK_CMCTREE_NODE (work
->data
));
5016 if (gtk_widget_has_focus (GTK_WIDGET(clist
)) &&
5017 clist
->focus_row
!= clist
->undo_anchor
)
5019 clist
->focus_row
= clist
->undo_anchor
;
5020 gtk_widget_queue_draw (GTK_WIDGET (clist
));
5023 clist
->focus_row
= clist
->undo_anchor
;
5025 clist
->undo_anchor
= -1;
5027 g_list_free (clist
->undo_selection
);
5028 g_list_free (clist
->undo_unselection
);
5029 clist
->undo_selection
= NULL
;
5030 clist
->undo_unselection
= NULL
;
5032 if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) + clist
->row_height
>
5033 clist
->clist_window_height
)
5034 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
5035 else if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) < 0)
5036 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
5041 gtk_cmctree_set_drag_compare_func (GtkCMCTree
*ctree
,
5042 GtkCMCTreeCompareDragFunc cmp_func
)
5044 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
5046 ctree
->drag_compare
= cmp_func
;
5050 check_drag (GtkCMCTree
*ctree
,
5051 GtkCMCTreeNode
*drag_source
,
5052 GtkCMCTreeNode
*drag_target
,
5053 GtkCMCListDragPos insert_pos
)
5055 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), FALSE
);
5057 if (drag_source
&& drag_source
!= drag_target
&&
5058 (!GTK_CMCTREE_ROW (drag_source
)->children
||
5059 !gtk_cmctree_is_ancestor (ctree
, drag_source
, drag_target
)))
5063 case GTK_CMCLIST_DRAG_NONE
:
5065 case GTK_CMCLIST_DRAG_AFTER
:
5066 if (GTK_CMCTREE_ROW (drag_target
)->sibling
!= drag_source
)
5067 return (!ctree
->drag_compare
||
5068 ctree
->drag_compare (ctree
,
5070 GTK_CMCTREE_ROW (drag_target
)->parent
,
5071 GTK_CMCTREE_ROW (drag_target
)->sibling
));
5073 case GTK_CMCLIST_DRAG_BEFORE
:
5074 if (GTK_CMCTREE_ROW (drag_source
)->sibling
!= drag_target
)
5075 return (!ctree
->drag_compare
||
5076 ctree
->drag_compare (ctree
,
5078 GTK_CMCTREE_ROW (drag_target
)->parent
,
5081 case GTK_CMCLIST_DRAG_INTO
:
5082 if (!GTK_CMCTREE_ROW (drag_target
)->is_leaf
&&
5083 GTK_CMCTREE_ROW (drag_target
)->children
!= drag_source
)
5084 return (!ctree
->drag_compare
||
5085 ctree
->drag_compare (ctree
,
5088 GTK_CMCTREE_ROW (drag_target
)->children
));
5097 /************************************/
5099 drag_dest_info_destroy (gpointer data
)
5101 GtkCMCListDestInfo
*info
= data
;
5107 drag_dest_cell (GtkCMCList
*clist
,
5110 GtkCMCListDestInfo
*dest_info
)
5116 widget
= GTK_WIDGET (clist
);
5117 style
= gtk_widget_get_style (widget
);
5119 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_NONE
;
5121 border_width
= gtk_container_get_border_width (GTK_CONTAINER (widget
));
5122 y
-= (border_width
+
5123 style
->ythickness
+ clist
->column_title_area
.height
);
5124 dest_info
->cell
.row
= ROW_FROM_YPIXEL (clist
, y
);
5126 if (dest_info
->cell
.row
>= clist
->rows
)
5128 dest_info
->cell
.row
= clist
->rows
- 1;
5129 y
= ROW_TOP_YPIXEL (clist
, dest_info
->cell
.row
) + clist
->row_height
;
5131 if (dest_info
->cell
.row
< -1)
5132 dest_info
->cell
.row
= -1;
5134 x
-= border_width
+ style
->xthickness
;
5136 dest_info
->cell
.column
= COLUMN_FROM_XPIXEL (clist
, x
);
5138 if (dest_info
->cell
.row
>= 0)
5143 y_delta
= y
- ROW_TOP_YPIXEL (clist
, dest_info
->cell
.row
);
5145 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist
) &&
5146 !GTK_CMCTREE_ROW (g_list_nth (clist
->row_list
,
5147 dest_info
->cell
.row
))->is_leaf
)
5149 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_INTO
;
5150 h
= clist
->row_height
/ 4;
5152 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist
))
5154 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_BEFORE
;
5155 h
= clist
->row_height
/ 2;
5158 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist
))
5161 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_BEFORE
;
5162 else if (clist
->row_height
- y_delta
< h
)
5163 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_AFTER
;
5169 gtk_cmctree_drag_begin (GtkWidget
*widget
,
5170 GdkDragContext
*context
)
5175 cm_return_if_fail (GTK_IS_CMCTREE (widget
));
5176 cm_return_if_fail (context
!= NULL
);
5178 clist
= GTK_CMCLIST (widget
);
5180 use_icons
= GTK_CMCLIST_USE_DRAG_ICONS (clist
);
5181 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_USE_DRAG_ICONS
);
5182 GTK_WIDGET_CLASS (parent_class
)->drag_begin (widget
, context
);
5186 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_USE_DRAG_ICONS
);
5187 gtk_drag_set_icon_default (context
);
5192 gtk_cmctree_drag_motion (GtkWidget
*widget
,
5193 GdkDragContext
*context
,
5200 GtkCMCListDestInfo new_info
;
5201 GtkCMCListDestInfo
*dest_info
;
5203 cm_return_val_if_fail (GTK_IS_CMCTREE (widget
), FALSE
);
5205 clist
= GTK_CMCLIST (widget
);
5206 ctree
= GTK_CMCTREE (widget
);
5208 dest_info
= g_dataset_get_data (context
, "gtk-clist-drag-dest");
5212 dest_info
= g_new (GtkCMCListDestInfo
, 1);
5214 dest_info
->cell
.row
= -1;
5215 dest_info
->cell
.column
= -1;
5216 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_NONE
;
5218 g_dataset_set_data_full (context
, "gtk-clist-drag-dest", dest_info
,
5219 drag_dest_info_destroy
);
5222 drag_dest_cell (clist
, x
, y
, &new_info
);
5224 if (GTK_CMCLIST_REORDERABLE (clist
))
5226 GdkAtom atom
= gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5227 GdkAtom found
= gtk_drag_dest_find_target(widget
, context
, NULL
);
5231 GtkCMCTreeNode
*drag_source
;
5232 GtkCMCTreeNode
*drag_target
;
5234 drag_source
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
,
5235 clist
->click_cell
.row
));
5236 drag_target
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
,
5237 new_info
.cell
.row
));
5239 if (gtk_drag_get_source_widget (context
) != widget
||
5240 !check_drag (ctree
, drag_source
, drag_target
,
5241 new_info
.insert_pos
))
5243 if (dest_info
->cell
.row
< 0)
5245 gdk_drag_status (context
, GDK_ACTION_DEFAULT
, time
);
5251 if (new_info
.cell
.row
!= dest_info
->cell
.row
||
5252 (new_info
.cell
.row
== dest_info
->cell
.row
&&
5253 dest_info
->insert_pos
!= new_info
.insert_pos
))
5255 dest_info
->insert_pos
= new_info
.insert_pos
;
5256 dest_info
->cell
.row
= new_info
.cell
.row
;
5257 dest_info
->cell
.column
= new_info
.cell
.column
;
5259 clist
->drag_highlight_row
= dest_info
->cell
.row
;
5260 clist
->drag_highlight_pos
= dest_info
->insert_pos
;
5262 gdk_drag_status (context
,
5263 gdk_drag_context_get_suggested_action(context
), time
);
5269 dest_info
->insert_pos
= new_info
.insert_pos
;
5270 dest_info
->cell
.row
= new_info
.cell
.row
;
5271 dest_info
->cell
.column
= new_info
.cell
.column
;
5276 gtk_cmctree_drag_data_received (GtkWidget
*widget
,
5277 GdkDragContext
*context
,
5280 GtkSelectionData
*selection_data
,
5287 cm_return_if_fail (GTK_IS_CMCTREE (widget
));
5288 cm_return_if_fail (context
!= NULL
);
5289 cm_return_if_fail (selection_data
!= NULL
);
5291 ctree
= GTK_CMCTREE (widget
);
5292 clist
= GTK_CMCLIST (widget
);
5294 if (GTK_CMCLIST_REORDERABLE (clist
) &&
5295 gtk_drag_get_source_widget (context
) == widget
&&
5296 gtk_selection_data_get_target (selection_data
) ==
5297 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
5298 gtk_selection_data_get_format (selection_data
) == 8 &&
5299 gtk_selection_data_get_length (selection_data
) == sizeof (GtkCMCListCellInfo
))
5301 GtkCMCListCellInfo
*source_info
;
5303 source_info
= (GtkCMCListCellInfo
*)(gtk_selection_data_get_data (selection_data
));
5306 GtkCMCListDestInfo dest_info
;
5307 GtkCMCTreeNode
*source_node
;
5308 GtkCMCTreeNode
*dest_node
;
5310 drag_dest_cell (clist
, x
, y
, &dest_info
);
5312 source_node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
,
5314 dest_node
= GTK_CMCTREE_NODE (g_list_nth (clist
->row_list
,
5315 dest_info
.cell
.row
));
5317 if (!source_node
|| !dest_node
)
5320 switch (dest_info
.insert_pos
)
5322 case GTK_CMCLIST_DRAG_NONE
:
5324 case GTK_CMCLIST_DRAG_INTO
:
5325 if (check_drag (ctree
, source_node
, dest_node
,
5326 dest_info
.insert_pos
))
5327 gtk_cmctree_move (ctree
, source_node
, dest_node
,
5328 GTK_CMCTREE_ROW (dest_node
)->children
);
5329 g_dataset_remove_data (context
, "gtk-clist-drag-dest");
5331 case GTK_CMCLIST_DRAG_BEFORE
:
5332 if (check_drag (ctree
, source_node
, dest_node
,
5333 dest_info
.insert_pos
))
5334 gtk_cmctree_move (ctree
, source_node
,
5335 GTK_CMCTREE_ROW (dest_node
)->parent
, dest_node
);
5336 g_dataset_remove_data (context
, "gtk-clist-drag-dest");
5338 case GTK_CMCLIST_DRAG_AFTER
:
5339 if (check_drag (ctree
, source_node
, dest_node
,
5340 dest_info
.insert_pos
))
5341 gtk_cmctree_move (ctree
, source_node
,
5342 GTK_CMCTREE_ROW (dest_node
)->parent
,
5343 GTK_CMCTREE_ROW (dest_node
)->sibling
);
5344 g_dataset_remove_data (context
, "gtk-clist-drag-dest");
5352 gtk_cmctree_node_get_type (void)
5354 static GType our_type
= 0;
5357 our_type
= g_pointer_type_register_static ("GtkCMCTreeNode");