gtkcmctree.c (144322B)
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> 4 * 5 * GtkCMCTree widget for GTK+ 6 * Copyright (C) 1998 Lars Hamann and Stefan Jeske 7 * 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. 12 * 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. 17 * 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. 22 */ 23 24 /* 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/. 29 */ 30 31 #include <stdlib.h> 32 33 #include <gtk/gtk.h> 34 #include <gdk/gdkkeysyms.h> 35 36 #include "claws-marshal.h" 37 #include "gtkcmctree.h" 38 #include "gtkutils.h" 39 #include "prefs_common.h" 40 #include "utils.h" 41 42 #define PM_SIZE 8 43 #define TAB_SIZE (PM_SIZE + 6) 44 #define CELL_SPACING 1 45 #define CLIST_OPTIMUM_SIZE 64 46 #define COLUMN_INSET 3 47 #define DRAG_WIDTH 6 48 49 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \ 50 (((row) + 1) * CELL_SPACING) + \ 51 (clist)->voffset) 52 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ 53 ((clist)->row_height + CELL_SPACING)) 54 #define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \ 55 + (clist)->hoffset) 56 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) 57 58 GType 59 gtk_cmctree_pos_get_type (void) 60 { 61 static GType etype = 0; 62 if (etype == 0) { 63 static const GEnumValue values[] = { 64 { GTK_CMCTREE_POS_BEFORE, "GTK_CMCTREE_POS_BEFORE", "before" }, 65 { GTK_CMCTREE_POS_AS_CHILD, "GTK_CMCTREE_POS_AS_CHILD", "as-child" }, 66 { GTK_CMCTREE_POS_AFTER, "GTK_CMCTREE_POS_AFTER", "after" }, 67 { 0, NULL, NULL } 68 }; 69 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values); 70 } 71 return etype; 72 } 73 GType 74 gtk_cmctree_line_style_get_type (void) 75 { 76 static GType etype = 0; 77 if (etype == 0) { 78 static const GEnumValue values[] = { 79 { GTK_CMCTREE_LINES_NONE, "GTK_CMCTREE_LINES_NONE", "none" }, 80 { 0, NULL, NULL } 81 }; 82 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values); 83 } 84 return etype; 85 } 86 GType 87 gtk_cmctree_expander_style_get_type (void) 88 { 89 static GType etype = 0; 90 if (etype == 0) { 91 static const GEnumValue values[] = { 92 { GTK_CMCTREE_EXPANDER_NONE, "GTK_CMCTREE_EXPANDER_NONE", "none" }, 93 { GTK_CMCTREE_EXPANDER_TRIANGLE, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" }, 94 { 0, NULL, NULL } 95 }; 96 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values); 97 } 98 return etype; 99 } 100 GType 101 gtk_cmctree_expansion_type_get_type (void) 102 { 103 static GType etype = 0; 104 if (etype == 0) { 105 static const GEnumValue values[] = { 106 { GTK_CMCTREE_EXPANSION_EXPAND, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" }, 107 { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" }, 108 { GTK_CMCTREE_EXPANSION_COLLAPSE, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" }, 109 { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" }, 110 { GTK_CMCTREE_EXPANSION_TOGGLE, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" }, 111 { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" }, 112 { 0, NULL, NULL } 113 }; 114 etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values); 115 } 116 return etype; 117 } 118 119 120 static inline gint 121 COLUMN_FROM_XPIXEL (GtkCMCList * clist, 122 gint x) 123 { 124 gint i, cx; 125 126 for (i = 0; i < clist->columns; i++) 127 if (clist->column[i].visible) 128 { 129 cx = clist->column[i].area.x + clist->hoffset; 130 131 if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) && 132 x <= (cx + clist->column[i].area.width + COLUMN_INSET)) 133 return i; 134 } 135 136 /* no match */ 137 return -1; 138 } 139 140 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0) 141 #define CLIST_REFRESH(clist) G_STMT_START { \ 142 if (CLIST_UNFROZEN (clist)) \ 143 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \ 144 } G_STMT_END 145 146 147 enum { 148 ARG_0, 149 ARG_N_COLUMNS, 150 ARG_TREE_COLUMN, 151 ARG_INDENT, 152 ARG_SPACING, 153 ARG_SHOW_STUB, 154 ARG_LINE_STYLE, 155 ARG_EXPANDER_STYLE 156 }; 157 158 159 static void gtk_cmctree_class_init (GtkCMCTreeClass *klass); 160 static void gtk_cmctree_init (GtkCMCTree *ctree); 161 static GObject* gtk_cmctree_constructor (GType type, 162 guint n_construct_properties, 163 GObjectConstructParam *construct_params); 164 static void gtk_cmctree_set_arg (GObject *object, 165 guint arg_id, 166 const GValue *value, 167 GParamSpec *spec); 168 static void gtk_cmctree_get_arg (GObject *object, 169 guint arg_id, 170 GValue *value, 171 GParamSpec *spec); 172 static void gtk_cmctree_realize (GtkWidget *widget); 173 static void gtk_cmctree_unrealize (GtkWidget *widget); 174 static gint gtk_cmctree_button_press (GtkWidget *widget, 175 GdkEventButton *event); 176 static void ctree_attach_styles (GtkCMCTree *ctree, 177 GtkCMCTreeNode *node, 178 gpointer data); 179 static void ctree_detach_styles (GtkCMCTree *ctree, 180 GtkCMCTreeNode *node, 181 gpointer data); 182 static void set_cell_contents (GtkCMCList *clist, 183 GtkCMCListRow *clist_row, 184 gint column, 185 GtkCMCellType type, 186 const gchar *text, 187 guint8 spacing, 188 GdkPixbuf *pixbuf); 189 static void set_node_info (GtkCMCTree *ctree, 190 GtkCMCTreeNode *node, 191 const gchar *text, 192 guint8 spacing, 193 GdkPixbuf *pixbuf_closed, 194 GdkPixbuf *pixbuf_opened, 195 gboolean is_leaf, 196 gboolean expanded); 197 static GtkCMCTreeRow *row_new (GtkCMCTree *ctree); 198 static void row_delete (GtkCMCTree *ctree, 199 GtkCMCTreeRow *ctree_row); 200 static void tree_delete (GtkCMCTree *ctree, 201 GtkCMCTreeNode *node, 202 gpointer data); 203 static void tree_delete_row (GtkCMCTree *ctree, 204 GtkCMCTreeNode *node, 205 gpointer data); 206 static void real_clear (GtkCMCList *clist); 207 static void tree_update_level (GtkCMCTree *ctree, 208 GtkCMCTreeNode *node, 209 gpointer data); 210 static void tree_select (GtkCMCTree *ctree, 211 GtkCMCTreeNode *node, 212 gpointer data); 213 static void tree_unselect (GtkCMCTree *ctree, 214 GtkCMCTreeNode *node, 215 gpointer data); 216 static void real_select_all (GtkCMCList *clist); 217 static void real_unselect_all (GtkCMCList *clist); 218 static void tree_expand (GtkCMCTree *ctree, 219 GtkCMCTreeNode *node, 220 gpointer data); 221 static void tree_collapse (GtkCMCTree *ctree, 222 GtkCMCTreeNode *node, 223 gpointer data); 224 static void tree_collapse_to_depth (GtkCMCTree *ctree, 225 GtkCMCTreeNode *node, 226 gint depth); 227 static void tree_toggle_expansion (GtkCMCTree *ctree, 228 GtkCMCTreeNode *node, 229 gpointer data); 230 static void change_focus_row_expansion (GtkCMCTree *ctree, 231 GtkCMCTreeExpansionType expansion); 232 static void real_select_row (GtkCMCList *clist, 233 gint row, 234 gint column, 235 GdkEvent *event); 236 static void real_unselect_row (GtkCMCList *clist, 237 gint row, 238 gint column, 239 GdkEvent *event); 240 static void real_tree_select (GtkCMCTree *ctree, 241 GtkCMCTreeNode *node, 242 gint column); 243 static void real_tree_unselect (GtkCMCTree *ctree, 244 GtkCMCTreeNode *node, 245 gint column); 246 static void real_tree_expand (GtkCMCTree *ctree, 247 GtkCMCTreeNode *node); 248 static void real_tree_collapse (GtkCMCTree *ctree, 249 GtkCMCTreeNode *node); 250 static void real_tree_move (GtkCMCTree *ctree, 251 GtkCMCTreeNode *node, 252 GtkCMCTreeNode *new_parent, 253 GtkCMCTreeNode *new_sibling); 254 static void real_row_move (GtkCMCList *clist, 255 gint source_row, 256 gint dest_row); 257 static void gtk_cmctree_link (GtkCMCTree *ctree, 258 GtkCMCTreeNode *node, 259 GtkCMCTreeNode *parent, 260 GtkCMCTreeNode *sibling, 261 gboolean update_focus_row); 262 static void gtk_cmctree_unlink (GtkCMCTree *ctree, 263 GtkCMCTreeNode *node, 264 gboolean update_focus_row); 265 static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree, 266 GtkCMCTreeNode *node); 267 static gboolean ctree_is_hot_spot (GtkCMCTree *ctree, 268 GtkCMCTreeNode *node, 269 gint row, 270 gint x, 271 gint y); 272 static void tree_sort (GtkCMCTree *ctree, 273 GtkCMCTreeNode *node, 274 gpointer data); 275 static void fake_unselect_all (GtkCMCList *clist, 276 gint row); 277 static GList * selection_find (GtkCMCList *clist, 278 gint row_number, 279 GList *row_list_element); 280 static void resync_selection (GtkCMCList *clist, 281 GdkEvent *event); 282 static void real_undo_selection (GtkCMCList *clist); 283 static void select_row_recursive (GtkCMCTree *ctree, 284 GtkCMCTreeNode *node, 285 gpointer data); 286 static gint real_insert_row (GtkCMCList *clist, 287 gint row, 288 gchar *text[]); 289 static void real_remove_row (GtkCMCList *clist, 290 gint row); 291 static void real_sort_list (GtkCMCList *clist); 292 static void cell_size_request (GtkCMCList *clist, 293 GtkCMCListRow *clist_row, 294 gint column, 295 GtkRequisition *requisition); 296 static void column_auto_resize (GtkCMCList *clist, 297 GtkCMCListRow *clist_row, 298 gint column, 299 gint old_width); 300 static void auto_resize_columns (GtkCMCList *clist); 301 302 303 static gboolean check_drag (GtkCMCTree *ctree, 304 GtkCMCTreeNode *drag_source, 305 GtkCMCTreeNode *drag_target, 306 GtkCMCListDragPos insert_pos); 307 static void gtk_cmctree_drag_begin (GtkWidget *widget, 308 GdkDragContext *context); 309 static gint gtk_cmctree_drag_motion (GtkWidget *widget, 310 GdkDragContext *context, 311 gint x, 312 gint y, 313 guint time); 314 static void gtk_cmctree_drag_data_received (GtkWidget *widget, 315 GdkDragContext *context, 316 gint x, 317 gint y, 318 GtkSelectionData *selection_data, 319 guint info, 320 guint32 time); 321 static void remove_grab (GtkCMCList *clist); 322 static void drag_dest_cell (GtkCMCList *clist, 323 gint x, 324 gint y, 325 GtkCMCListDestInfo *dest_info); 326 327 328 enum 329 { 330 TREE_SELECT_ROW, 331 TREE_UNSELECT_ROW, 332 TREE_EXPAND, 333 TREE_COLLAPSE, 334 TREE_MOVE, 335 CHANGE_FOCUS_ROW_EXPANSION, 336 LAST_SIGNAL 337 }; 338 339 static GtkCMCListClass *parent_class = NULL; 340 static GtkContainerClass *container_class = NULL; 341 static guint ctree_signals[LAST_SIGNAL] = {0}; 342 343 344 GType 345 gtk_cmctree_get_type (void) 346 { 347 static GType ctree_type = 0; 348 349 if (!ctree_type) 350 { 351 static const GTypeInfo ctree_info = 352 { 353 sizeof (GtkCMCTreeClass), 354 355 (GBaseInitFunc) NULL, 356 (GBaseFinalizeFunc) NULL, 357 358 (GClassInitFunc) gtk_cmctree_class_init, 359 (GClassFinalizeFunc) NULL, 360 NULL, /* class_data */ 361 362 sizeof (GtkCMCTree), 363 0, /* n_preallocs */ 364 (GInstanceInitFunc) gtk_cmctree_init, 365 366 (const GTypeValueTable *) NULL /* value table */ 367 }; 368 369 ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0); 370 } 371 372 return ctree_type; 373 } 374 375 static gint 376 draw_cell_pixbuf (GdkWindow *window, 377 GdkRectangle *clip_rectangle, 378 cairo_t *cr, 379 GdkPixbuf *pixbuf, 380 gint x, 381 gint y, 382 gint width, 383 gint height) 384 { 385 gint xsrc = 0; 386 gint ysrc = 0; 387 388 if (!pixbuf || (width == 0 && height == 0)) 389 return x; 390 391 if (x < clip_rectangle->x) 392 { 393 xsrc = clip_rectangle->x - x; 394 width -= xsrc; 395 x = clip_rectangle->x; 396 } 397 if (x + width > clip_rectangle->x + clip_rectangle->width) 398 width = clip_rectangle->x + clip_rectangle->width - x; 399 400 if (y < clip_rectangle->y) 401 { 402 ysrc = clip_rectangle->y - y; 403 height -= ysrc; 404 y = clip_rectangle->y; 405 } 406 407 if (y + height > clip_rectangle->y + clip_rectangle->height) 408 height = clip_rectangle->y + clip_rectangle->height - y; 409 410 gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y); 411 cairo_paint(cr); 412 413 return x + MAX (width, 0); 414 } 415 416 static gint 417 draw_expander (GtkCMCTree *ctree, 418 GtkCMCTreeRow *ctree_row, 419 GtkStyle *style, 420 GdkRectangle *clip_rectangle, 421 cairo_t *cr, 422 gint x) 423 { 424 GtkCMCList *clist; 425 gint justification_factor; 426 gint y; 427 428 if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) 429 return x; 430 431 clist = GTK_CMCLIST (ctree); 432 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) 433 justification_factor = -1; 434 else 435 justification_factor = 1; 436 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) 437 y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 - 438 (clip_rectangle->height + 1) % 2) + 1; 439 else 440 y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 - 441 (clip_rectangle->height/2 + 1) % 2) + 1; 442 443 if (!ctree_row->children) 444 { 445 return x + justification_factor * (PM_SIZE + 3); 446 } 447 448 /* pixel offsets +/- 1 or +/- justification_factor here and there .. 449 * to fill correctly, somewhat ... what do I do wrong? 450 */ 451 gdk_cairo_set_source_color(cr, >k_widget_get_style(GTK_WIDGET(ctree))->text[GTK_STATE_NORMAL]); 452 if (ctree_row->expanded) 453 { 454 gint tmp3 = PM_SIZE / 2; 455 gint tmp6 = PM_SIZE / 6; 456 cairo_move_to(cr, x + justification_factor * (tmp3 + tmp6) + (PM_SIZE / 2), y + 1); 457 cairo_rel_line_to(cr, 0, tmp3 + tmp6 + 1); 458 cairo_rel_line_to(cr, -justification_factor * (tmp3 + tmp6) - justification_factor, -1); 459 } 460 else 461 { 462 gint tmp3 = PM_SIZE / 2; 463 gint tmp6 = PM_SIZE / 6; 464 cairo_move_to(cr, x + tmp6 - justification_factor + (PM_SIZE / 2), y + tmp6 - 1); 465 cairo_rel_line_to(cr, justification_factor * tmp3, tmp3); 466 cairo_rel_line_to(cr, -justification_factor * tmp3, tmp3); 467 } 468 cairo_fill(cr); 469 470 x += justification_factor * (PM_SIZE + 3); 471 472 return x; 473 } 474 475 static gint 476 get_offset(GtkCMCTree *ctree, 477 GtkCMCTreeRow *ctree_row, 478 gint column, 479 GdkRectangle *clip_rectangle) 480 { 481 gint justify_right; 482 justify_right = (GTK_CMCLIST (ctree)->column[column].justification == GTK_JUSTIFY_RIGHT); 483 484 if (justify_right) 485 return (clip_rectangle->x + clip_rectangle->width - 1 - 486 ctree->tree_indent * (ctree_row->level - 1)); 487 488 return clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1); 489 } 490 491 static void 492 get_cell_style (GtkCMCList *clist, 493 GtkCMCListRow *clist_row, 494 gint state, 495 gint column, 496 GtkStyle **style) 497 { 498 GtkStyle *gtkstyle; 499 500 gtkstyle = gtk_widget_get_style (GTK_WIDGET (clist)); 501 502 if (clist_row->cell[column].style) 503 { 504 if (style) 505 *style = clist_row->cell[column].style; 506 } 507 else if (clist_row->style) 508 { 509 if (style) 510 *style = clist_row->style; 511 } 512 else 513 { 514 if (style) 515 *style = gtkstyle; 516 } 517 } 518 519 static gboolean filter_fg (PangoAttribute *attribute, gpointer data) 520 { 521 const PangoAttrClass *klass = attribute->klass; 522 if (klass->type == PANGO_ATTR_FOREGROUND) 523 return TRUE; 524 525 return FALSE; 526 } 527 528 static PangoLayout * 529 create_cell_layout (GtkCMCList *clist, 530 GtkCMCListRow *clist_row, 531 gint column) 532 { 533 PangoLayout *layout; 534 GtkStyle *style; 535 GtkCMCell *cell; 536 gchar *text; 537 538 get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style); 539 540 541 cell = &clist_row->cell[column]; 542 switch (cell->type) 543 { 544 case GTK_CMCELL_TEXT: 545 case GTK_CMCELL_PIXTEXT: 546 text = ((cell->type == GTK_CMCELL_PIXTEXT) ? 547 GTK_CMCELL_PIXTEXT (*cell)->text : 548 GTK_CMCELL_TEXT (*cell)->text); 549 550 if (!text) 551 return NULL; 552 553 if (!GTK_SCTREE(clist)->use_markup[column]) { 554 layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist), 555 ((cell->type == GTK_CMCELL_PIXTEXT) ? 556 GTK_CMCELL_PIXTEXT (*cell)->text : 557 GTK_CMCELL_TEXT (*cell)->text)); 558 pango_layout_set_font_description (layout, style->font_desc); 559 } else { 560 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist)); 561 layout = pango_layout_new (context); 562 pango_layout_set_markup (layout, text, -1); 563 pango_layout_set_font_description (layout, style->font_desc); 564 if (clist_row->state == GTK_STATE_SELECTED) { 565 /* for selected row, we should remove any forced foreground color 566 * or it looks like shit */ 567 PangoAttrList *list = pango_layout_get_attributes(layout); 568 PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL); 569 if (rem) 570 pango_attr_list_unref(rem); 571 } 572 } 573 574 return layout; 575 576 default: 577 return NULL; 578 } 579 } 580 581 582 static void 583 draw_row (GtkCMCList *clist, 584 GdkRectangle *area, 585 gint row, 586 GtkCMCListRow *clist_row) 587 { 588 GtkWidget *widget; 589 GtkStyle *style; 590 GtkCMCTree *ctree; 591 GdkRectangle *crect; 592 GdkRectangle row_rectangle; 593 GdkRectangle cell_rectangle; 594 GdkRectangle clip_rectangle; 595 GdkRectangle intersect_rectangle; 596 gint last_column; 597 gint offset = 0; 598 gint state; 599 gint i; 600 static GdkColor greybg={0, 0, 0, 0}; 601 static gboolean color_change = TRUE; 602 cairo_t *cr; 603 GdkColor *fgcolor, *bgcolor; 604 605 cm_return_if_fail (clist != NULL); 606 607 if (clist->draw_now) { 608 gtk_widget_queue_draw(GTK_WIDGET (clist)); 609 return; 610 } 611 612 widget = GTK_WIDGET (clist); 613 614 /* if the function is passed the pointer to the row instead of null, 615 * it avoids this expensive lookup */ 616 if (!clist_row) 617 clist_row = (g_list_nth (clist->row_list, row))->data; 618 619 style = clist_row->style ? clist_row->style : gtk_widget_get_style (widget); 620 621 if (greybg.pixel == 0 && 622 greybg.red == 0 && 623 greybg.green == 0 && 624 greybg.blue == 0) { 625 GdkColor normalbg = {0, 0xffff, 0xffff, 0xffff}; 626 if (style) { 627 normalbg = style->base[GTK_STATE_NORMAL]; 628 } 629 if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) { 630 greybg.pixel = normalbg.pixel; 631 greybg.red = normalbg.red - prefs_common.stripes_color_offset; 632 greybg.green = normalbg.green - prefs_common.stripes_color_offset; 633 greybg.blue = normalbg.blue - prefs_common.stripes_color_offset; 634 } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) { 635 greybg.pixel = normalbg.pixel; 636 greybg.red = normalbg.red + prefs_common.stripes_color_offset; 637 greybg.green = normalbg.green + prefs_common.stripes_color_offset; 638 greybg.blue = normalbg.blue + prefs_common.stripes_color_offset; 639 } else { 640 color_change = FALSE; 641 } 642 } 643 644 /* bail now if we arn't drawable yet */ 645 if (!gtk_widget_is_drawable (GTK_WIDGET(clist)) || row < 0 || row >= clist->rows) 646 return; 647 648 ctree = GTK_CMCTREE (clist); 649 650 /* rectangle of the entire row */ 651 row_rectangle.x = 0; 652 row_rectangle.y = ROW_TOP_YPIXEL (clist, row); 653 row_rectangle.width = clist->clist_window_width; 654 row_rectangle.height = clist->row_height; 655 656 /* rectangle of the cell spacing above the row */ 657 cell_rectangle.x = 0; 658 cell_rectangle.y = row_rectangle.y - CELL_SPACING; 659 cell_rectangle.width = row_rectangle.width; 660 cell_rectangle.height = CELL_SPACING; 661 662 /* rectangle used to clip drawing operations, its y and height 663 * positions only need to be set once, so we set them once here. 664 * the x and width are set withing the drawing loop below once per 665 * column */ 666 clip_rectangle.y = row_rectangle.y; 667 clip_rectangle.height = row_rectangle.height; 668 669 if (prefs_common.use_stripes_everywhere && GTK_SCTREE(ctree)->show_stripes 670 && color_change && row % 2) { 671 bgcolor = &greybg; 672 } else { 673 bgcolor = &style->base[GTK_STATE_NORMAL]; 674 } 675 state = clist_row->state; 676 677 cr = gdk_cairo_create(clist->clist_window); 678 679 if (clist_row->fg_set && state != GTK_STATE_SELECTED) 680 fgcolor = &clist_row->foreground; 681 else 682 fgcolor = &style->text[clist_row->state]; 683 /* draw the cell borders */ 684 if (area) 685 { 686 crect = &intersect_rectangle; 687 688 if (gdk_rectangle_intersect (area, &cell_rectangle, crect)) { 689 gdk_cairo_rectangle(cr, &cell_rectangle); 690 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]); 691 cairo_fill(cr); 692 cairo_rectangle(cr, cell_rectangle.x, cell_rectangle.y + row_rectangle.height + 1,cell_rectangle.width,cell_rectangle.height); 693 cairo_fill(cr); 694 } 695 } 696 else 697 { 698 crect = &cell_rectangle; 699 700 gdk_cairo_rectangle(cr, &cell_rectangle); 701 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]); 702 cairo_fill(cr); 703 cairo_rectangle(cr, cell_rectangle.x, cell_rectangle.y + row_rectangle.height + 1,cell_rectangle.width,cell_rectangle.height); 704 cairo_fill(cr); 705 } 706 707 /* the last row has to clear its bottom cell spacing too */ 708 if (clist_row == clist->row_list_end->data) 709 { 710 cell_rectangle.y += clist->row_height + CELL_SPACING; 711 712 if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect)) 713 { 714 gdk_cairo_rectangle(cr, crect); 715 gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]); 716 cairo_fill(cr); 717 } 718 } 719 720 for (last_column = clist->columns - 1; 721 last_column >= 0 && !clist->column[last_column].visible; last_column--) 722 ; 723 724 /* iterate and draw all the columns (row cells) and draw their contents */ 725 for (i = 0; i < clist->columns; i++) 726 { 727 GtkStyle *style; 728 PangoLayout *layout = NULL; 729 PangoRectangle logical_rect; 730 731 gint width; 732 gint height; 733 gint pixbuf_width; 734 gint string_width; 735 gint old_offset; 736 737 if (!clist->column[i].visible) 738 continue; 739 740 get_cell_style (clist, clist_row, state, i, &style); 741 742 /* calculate clipping region */ 743 clip_rectangle.x = clist->column[i].area.x + clist->hoffset; 744 clip_rectangle.width = clist->column[i].area.width; 745 746 cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING; 747 cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET + 748 (1 + (i == last_column)) * CELL_SPACING); 749 cell_rectangle.y = clip_rectangle.y; 750 cell_rectangle.height = clip_rectangle.height; 751 752 string_width = 0; 753 pixbuf_width = 0; 754 height = 0; 755 756 if (area && !gdk_rectangle_intersect (area, &cell_rectangle, 757 &intersect_rectangle)) 758 { 759 if (i != ctree->tree_column) 760 continue; 761 } 762 else 763 { 764 gdk_cairo_rectangle(cr, &cell_rectangle); 765 if (state == GTK_STATE_NORMAL) 766 gdk_cairo_set_source_color(cr, bgcolor); 767 else 768 gdk_cairo_set_source_color(cr, &style->base[state]); 769 cairo_fill(cr); 770 layout = create_cell_layout (clist, clist_row, i); 771 if (layout) 772 { 773 pango_layout_get_pixel_extents (layout, NULL, &logical_rect); 774 width = logical_rect.width; 775 } 776 else 777 width = 0; 778 779 switch (clist_row->cell[i].type) 780 { 781 case GTK_CMCELL_PIXBUF: 782 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf); 783 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf); 784 width += pixbuf_width; 785 break; 786 case GTK_CMCELL_PIXTEXT: 787 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf) 788 { 789 pixbuf_width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf); 790 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf); 791 width += pixbuf_width; 792 } 793 794 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text && 795 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf) 796 width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; 797 798 if (i == ctree->tree_column) 799 width += (ctree->tree_indent * 800 ((GtkCMCTreeRow *)clist_row)->level); 801 break; 802 default: 803 break; 804 } 805 806 switch (clist->column[i].justification) 807 { 808 case GTK_JUSTIFY_LEFT: 809 offset = clip_rectangle.x + clist_row->cell[i].horizontal; 810 break; 811 case GTK_JUSTIFY_RIGHT: 812 offset = (clip_rectangle.x + clist_row->cell[i].horizontal + 813 clip_rectangle.width - width); 814 break; 815 case GTK_JUSTIFY_CENTER: 816 case GTK_JUSTIFY_FILL: 817 offset = (clip_rectangle.x + clist_row->cell[i].horizontal + 818 (clip_rectangle.width / 2) - (width / 2)); 819 break; 820 }; 821 822 if (i != ctree->tree_column) 823 { 824 int start_y = (clip_rectangle.height - height) / 2; 825 if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) 826 start_y = (clip_rectangle.height/2 - height) / 2; 827 828 offset += clist_row->cell[i].horizontal; 829 switch (clist_row->cell[i].type) 830 { 831 case GTK_CMCELL_PIXBUF: 832 draw_cell_pixbuf 833 (clist->clist_window, &clip_rectangle, cr, 834 GTK_CMCELL_PIXBUF (clist_row->cell[i])->pixbuf, 835 offset, 836 clip_rectangle.y + clist_row->cell[i].vertical + 837 start_y, 838 pixbuf_width, height); 839 break; 840 case GTK_CMCELL_PIXTEXT: 841 offset = draw_cell_pixbuf 842 (clist->clist_window, &clip_rectangle, cr, 843 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf, 844 offset, 845 clip_rectangle.y + clist_row->cell[i].vertical + 846 start_y, 847 pixbuf_width, height); 848 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; 849 850 /* Fall through */ 851 case GTK_CMCELL_TEXT: 852 if (layout) 853 { 854 gint row_center_offset = (clist->row_height - logical_rect.height) / 2; 855 gdk_cairo_set_source_color(cr, fgcolor); 856 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical); 857 pango_cairo_show_layout(cr, layout); 858 g_object_unref (G_OBJECT (layout)); 859 } 860 break; 861 default: 862 break; 863 } 864 continue; 865 } 866 } 867 868 /* draw ctree->tree_column */ 869 cell_rectangle.y -= CELL_SPACING; 870 cell_rectangle.height += CELL_SPACING; 871 872 if (area && !gdk_rectangle_intersect (area, &cell_rectangle, 873 &intersect_rectangle)) 874 { 875 if (layout) 876 g_object_unref (G_OBJECT (layout)); 877 continue; 878 } 879 880 881 /* draw lines */ 882 offset = get_offset (ctree, (GtkCMCTreeRow *)clist_row, i, 883 &clip_rectangle); 884 885 /* draw expander */ 886 offset = draw_expander (ctree, (GtkCMCTreeRow *)clist_row, 887 style, &clip_rectangle, cr, offset); 888 889 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) 890 offset -= ctree->tree_spacing; 891 else 892 offset += ctree->tree_spacing; 893 894 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) 895 offset -= (pixbuf_width + clist_row->cell[i].horizontal); 896 else 897 offset += clist_row->cell[i].horizontal; 898 899 old_offset = offset; 900 offset = draw_cell_pixbuf (clist->clist_window, &clip_rectangle, cr, 901 GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf, 902 offset, 903 clip_rectangle.y + clist_row->cell[i].vertical 904 + (clip_rectangle.height - height) / 2, 905 pixbuf_width, height); 906 907 if (layout) 908 { 909 gint row_center_offset = (clist->row_height - logical_rect.height) / 2; 910 911 if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) 912 { 913 offset = (old_offset - string_width); 914 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf) 915 offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; 916 } 917 else 918 { 919 if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixbuf) 920 offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; 921 } 922 923 cairo_move_to(cr, offset, row_rectangle.y + row_center_offset + clist_row->cell[i].vertical); 924 gdk_cairo_set_source_color(cr, fgcolor); 925 pango_cairo_show_layout(cr, layout); 926 g_object_unref (G_OBJECT (layout)); 927 } 928 } 929 /* draw focus rectangle */ 930 if (clist->focus_row == row && 931 gtk_widget_get_can_focus (widget) && gtk_widget_has_focus (widget) 932 && state == GTK_STATE_SELECTED) 933 { 934 if (!area || gdk_rectangle_intersect (area, &row_rectangle, 935 &intersect_rectangle)) 936 { 937 cairo_set_line_width(cr, 1.0); 938 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); 939 gdk_cairo_set_source_color(cr, &style->text[GTK_STATE_NORMAL]); 940 cairo_move_to (cr, row_rectangle.x, row_rectangle.y + 0.5); 941 cairo_line_to (cr, row_rectangle.x + row_rectangle.width, row_rectangle.y + 0.5); 942 cairo_move_to (cr, row_rectangle.x, row_rectangle.y + row_rectangle.height - 0.5); 943 cairo_line_to (cr, row_rectangle.x + row_rectangle.width, row_rectangle.y + row_rectangle.height - 0.5); 944 cairo_stroke(cr); 945 } 946 } 947 cairo_destroy(cr); 948 } 949 950 static void 951 gtk_cmctree_class_init (GtkCMCTreeClass *klass) 952 { 953 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 954 #if !GTK_CHECK_VERSION(3, 0, 0) 955 GtkObjectClass *object_class; 956 #else /* for simplicity */ 957 GtkWidgetClass *object_class; 958 #endif 959 GtkWidgetClass *widget_class; 960 GtkCMCListClass *clist_class; 961 GtkBindingSet *binding_set; 962 963 gobject_class->constructor = gtk_cmctree_constructor; 964 965 #if !GTK_CHECK_VERSION(3, 0, 0) 966 object_class = (GtkObjectClass *) klass; 967 #else /* for simplicity */ 968 object_class = (GtkWidgetClass *) klass; 969 #endif 970 widget_class = (GtkWidgetClass *) klass; 971 container_class = (GtkContainerClass *) klass; 972 clist_class = (GtkCMCListClass *) klass; 973 974 parent_class = g_type_class_peek (GTK_TYPE_CMCLIST); 975 container_class = g_type_class_peek (GTK_TYPE_CONTAINER); 976 977 gobject_class->set_property = gtk_cmctree_set_arg; 978 gobject_class->get_property = gtk_cmctree_get_arg; 979 980 widget_class->realize = gtk_cmctree_realize; 981 widget_class->unrealize = gtk_cmctree_unrealize; 982 widget_class->button_press_event = gtk_cmctree_button_press; 983 984 widget_class->drag_begin = gtk_cmctree_drag_begin; 985 widget_class->drag_motion = gtk_cmctree_drag_motion; 986 widget_class->drag_data_received = gtk_cmctree_drag_data_received; 987 988 clist_class->select_row = real_select_row; 989 clist_class->unselect_row = real_unselect_row; 990 clist_class->row_move = real_row_move; 991 clist_class->undo_selection = real_undo_selection; 992 clist_class->resync_selection = resync_selection; 993 clist_class->selection_find = selection_find; 994 clist_class->click_column = NULL; 995 clist_class->draw_row = draw_row; 996 clist_class->clear = real_clear; 997 clist_class->select_all = real_select_all; 998 clist_class->unselect_all = real_unselect_all; 999 clist_class->fake_unselect_all = fake_unselect_all; 1000 clist_class->insert_row = real_insert_row; 1001 clist_class->remove_row = real_remove_row; 1002 clist_class->sort_list = real_sort_list; 1003 clist_class->set_cell_contents = set_cell_contents; 1004 clist_class->cell_size_request = cell_size_request; 1005 1006 klass->tree_select_row = real_tree_select; 1007 klass->tree_unselect_row = real_tree_unselect; 1008 klass->tree_expand = real_tree_expand; 1009 klass->tree_collapse = real_tree_collapse; 1010 klass->tree_move = real_tree_move; 1011 klass->change_focus_row_expansion = change_focus_row_expansion; 1012 1013 g_object_class_install_property (gobject_class, 1014 ARG_N_COLUMNS, 1015 g_param_spec_uint ("n-columns", 1016 "N-Columns", 1017 "N-Columns", 1018 1, 1019 G_MAXINT, 1020 1, 1021 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); 1022 g_object_class_install_property (gobject_class, 1023 ARG_TREE_COLUMN, 1024 g_param_spec_uint ("tree-column", 1025 "tree-column", 1026 "tree-column", 1027 0, 1028 G_MAXINT, 1029 0, 1030 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); 1031 g_object_class_install_property (gobject_class, 1032 ARG_INDENT, 1033 g_param_spec_uint ("indent", 1034 "indent", 1035 "indent", 1036 1, 1037 G_MAXINT, 1038 1, 1039 G_PARAM_READWRITE)); 1040 g_object_class_install_property (gobject_class, 1041 ARG_SPACING, 1042 g_param_spec_uint ("spacing", 1043 "spacing", 1044 "spacing", 1045 1, 1046 G_MAXINT, 1047 1, 1048 G_PARAM_READWRITE)); 1049 g_object_class_install_property (gobject_class, 1050 ARG_SHOW_STUB, 1051 g_param_spec_boolean ("show-stub", 1052 "show-stub", 1053 "show-stub", 1054 TRUE, 1055 G_PARAM_READWRITE)); 1056 g_object_class_install_property (gobject_class, 1057 ARG_LINE_STYLE, 1058 g_param_spec_enum ("line-style", 1059 "line-style", 1060 "line-style", 1061 GTK_TYPE_CMCTREE_LINE_STYLE, 0, 1062 G_PARAM_READWRITE)); 1063 g_object_class_install_property (gobject_class, 1064 ARG_EXPANDER_STYLE, 1065 g_param_spec_enum ("expander-style", 1066 "expander-style", 1067 "expander-style", 1068 GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0, 1069 G_PARAM_READWRITE)); 1070 1071 ctree_signals[TREE_SELECT_ROW] = 1072 g_signal_new ("tree_select_row", 1073 G_TYPE_FROM_CLASS (object_class), 1074 G_SIGNAL_RUN_FIRST, 1075 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row), 1076 NULL, NULL, 1077 claws_marshal_VOID__POINTER_INT, 1078 G_TYPE_NONE, 2, 1079 GTK_TYPE_CMCTREE_NODE, 1080 G_TYPE_INT); 1081 ctree_signals[TREE_UNSELECT_ROW] = 1082 g_signal_new ("tree_unselect_row", 1083 G_TYPE_FROM_CLASS (object_class), 1084 G_SIGNAL_RUN_FIRST, 1085 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row), 1086 NULL, NULL, 1087 claws_marshal_VOID__POINTER_INT, 1088 G_TYPE_NONE, 2, 1089 GTK_TYPE_CMCTREE_NODE, 1090 G_TYPE_INT); 1091 ctree_signals[TREE_EXPAND] = 1092 g_signal_new ("tree_expand", 1093 G_TYPE_FROM_CLASS (object_class), 1094 G_SIGNAL_RUN_LAST, 1095 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand), 1096 NULL, NULL, 1097 claws_marshal_VOID__POINTER, 1098 G_TYPE_NONE, 1, 1099 GTK_TYPE_CMCTREE_NODE); 1100 ctree_signals[TREE_COLLAPSE] = 1101 g_signal_new ("tree_collapse", 1102 G_TYPE_FROM_CLASS (object_class), 1103 G_SIGNAL_RUN_LAST, 1104 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse), 1105 NULL, NULL, 1106 claws_marshal_VOID__POINTER, 1107 G_TYPE_NONE, 1, 1108 GTK_TYPE_CMCTREE_NODE); 1109 ctree_signals[TREE_MOVE] = 1110 g_signal_new ("tree_move", 1111 G_TYPE_FROM_CLASS (object_class), 1112 G_SIGNAL_RUN_LAST, 1113 G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move), 1114 NULL, NULL, 1115 claws_marshal_VOID__POINTER_POINTER_POINTER, 1116 G_TYPE_NONE, 3, 1117 GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE); 1118 ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] = 1119 g_signal_new ("change_focus_row_expansion", 1120 G_TYPE_FROM_CLASS (object_class), 1121 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 1122 G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion), 1123 NULL, NULL, 1124 claws_marshal_VOID__ENUM, 1125 G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE); 1126 1127 binding_set = gtk_binding_set_by_class (klass); 1128 gtk_binding_entry_add_signal (binding_set, 1129 GDK_KEY_plus, 0, 1130 "change_focus_row_expansion", 1, 1131 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND); 1132 gtk_binding_entry_add_signal (binding_set, 1133 GDK_KEY_plus, GDK_CONTROL_MASK, 1134 "change_focus_row_expansion", 1, 1135 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE); 1136 1137 gtk_binding_entry_add_signal (binding_set, 1138 GDK_KEY_KP_Add, 0, 1139 "change_focus_row_expansion", 1, 1140 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND); 1141 gtk_binding_entry_add_signal (binding_set, 1142 GDK_KEY_KP_Add, GDK_CONTROL_MASK, 1143 "change_focus_row_expansion", 1, 1144 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE); 1145 1146 gtk_binding_entry_add_signal (binding_set, 1147 GDK_KEY_minus, 0, 1148 "change_focus_row_expansion", 1, 1149 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE); 1150 gtk_binding_entry_add_signal (binding_set, 1151 GDK_KEY_minus, GDK_CONTROL_MASK, 1152 "change_focus_row_expansion", 1, 1153 G_TYPE_ENUM, 1154 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE); 1155 gtk_binding_entry_add_signal (binding_set, 1156 GDK_KEY_KP_Subtract, 0, 1157 "change_focus_row_expansion", 1, 1158 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE); 1159 gtk_binding_entry_add_signal (binding_set, 1160 GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, 1161 "change_focus_row_expansion", 1, 1162 G_TYPE_ENUM, 1163 GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE); 1164 gtk_binding_entry_add_signal (binding_set, 1165 GDK_KEY_equal, 0, 1166 "change_focus_row_expansion", 1, 1167 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); 1168 gtk_binding_entry_add_signal (binding_set, 1169 GDK_KEY_KP_Equal, 0, 1170 "change_focus_row_expansion", 1, 1171 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); 1172 gtk_binding_entry_add_signal (binding_set, 1173 GDK_KEY_KP_Multiply, 0, 1174 "change_focus_row_expansion", 1, 1175 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); 1176 gtk_binding_entry_add_signal (binding_set, 1177 GDK_KEY_asterisk, 0, 1178 "change_focus_row_expansion", 1, 1179 G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); 1180 gtk_binding_entry_add_signal (binding_set, 1181 GDK_KEY_KP_Multiply, GDK_CONTROL_MASK, 1182 "change_focus_row_expansion", 1, 1183 G_TYPE_ENUM, 1184 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE); 1185 gtk_binding_entry_add_signal (binding_set, 1186 GDK_KEY_asterisk, GDK_CONTROL_MASK, 1187 "change_focus_row_expansion", 1, 1188 G_TYPE_ENUM, 1189 GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE); 1190 } 1191 1192 static void 1193 gtk_cmctree_set_arg (GObject *object, 1194 guint arg_id, 1195 const GValue *value, 1196 GParamSpec *spec) 1197 { 1198 GtkCMCTree *ctree; 1199 GtkCMCList *clist; 1200 1201 ctree = GTK_CMCTREE (object); 1202 clist = GTK_CMCLIST (ctree); 1203 1204 switch (arg_id) 1205 { 1206 case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */ 1207 clist->columns = MAX (1, g_value_get_uint (value)); 1208 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns); 1209 break; 1210 case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */ 1211 ctree->tree_column = g_value_get_uint (value); 1212 ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns); 1213 break; 1214 case ARG_INDENT: 1215 gtk_cmctree_set_indent (ctree, g_value_get_uint (value)); 1216 break; 1217 case ARG_SPACING: 1218 gtk_cmctree_set_spacing (ctree, g_value_get_uint (value)); 1219 break; 1220 case ARG_SHOW_STUB: 1221 gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value)); 1222 break; 1223 case ARG_LINE_STYLE: 1224 gtk_cmctree_set_line_style (ctree, g_value_get_enum (value)); 1225 break; 1226 case ARG_EXPANDER_STYLE: 1227 gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value)); 1228 break; 1229 default: 1230 break; 1231 } 1232 } 1233 1234 static void 1235 gtk_cmctree_get_arg (GObject *object, 1236 guint arg_id, 1237 GValue *value, 1238 GParamSpec *spec) 1239 { 1240 GtkCMCTree *ctree; 1241 1242 ctree = GTK_CMCTREE (object); 1243 1244 switch (arg_id) 1245 { 1246 case ARG_N_COLUMNS: 1247 g_value_set_uint(value, GTK_CMCLIST (ctree)->columns); 1248 break; 1249 case ARG_TREE_COLUMN: 1250 g_value_set_uint(value, ctree->tree_column); 1251 break; 1252 case ARG_INDENT: 1253 g_value_set_uint(value, ctree->tree_indent); 1254 break; 1255 case ARG_SPACING: 1256 g_value_set_uint(value, ctree->tree_spacing); 1257 break; 1258 case ARG_SHOW_STUB: 1259 g_value_set_boolean(value, ctree->show_stub); 1260 break; 1261 case ARG_LINE_STYLE: 1262 g_value_set_enum(value, ctree->line_style); 1263 break; 1264 case ARG_EXPANDER_STYLE: 1265 g_value_set_enum(value, ctree->expander_style); 1266 break; 1267 default: 1268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec); 1269 break; 1270 } 1271 } 1272 1273 static void 1274 gtk_cmctree_init (GtkCMCTree *ctree) 1275 { 1276 GtkCMCList *clist; 1277 1278 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT); 1279 GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE); 1280 1281 clist = GTK_CMCLIST (ctree); 1282 1283 ctree->tree_indent = 20; 1284 ctree->tree_spacing = 5; 1285 ctree->tree_column = 0; 1286 ctree->line_style = GTK_CMCTREE_LINES_NONE; 1287 ctree->expander_style = GTK_CMCTREE_EXPANDER_TRIANGLE; 1288 ctree->drag_compare = NULL; 1289 ctree->show_stub = TRUE; 1290 1291 clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS; 1292 } 1293 1294 static void 1295 ctree_attach_styles (GtkCMCTree *ctree, 1296 GtkCMCTreeNode *node, 1297 gpointer data) 1298 { 1299 GtkCMCList *clist; 1300 gint i; 1301 1302 clist = GTK_CMCLIST (ctree); 1303 1304 if (GTK_CMCTREE_ROW (node)->row.style) 1305 GTK_CMCTREE_ROW (node)->row.style = 1306 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window); 1307 1308 #if !GTK_CHECK_VERSION(3, 0, 0) 1309 if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set) 1310 { 1311 GdkColormap *colormap; 1312 1313 colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree)); 1314 if (GTK_CMCTREE_ROW (node)->row.fg_set) 1315 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE); 1316 if (GTK_CMCTREE_ROW (node)->row.bg_set) 1317 gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE); 1318 } 1319 #endif 1320 1321 for (i = 0; i < clist->columns; i++) 1322 if (GTK_CMCTREE_ROW (node)->row.cell[i].style) 1323 GTK_CMCTREE_ROW (node)->row.cell[i].style = 1324 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style, 1325 clist->clist_window); 1326 } 1327 1328 static void 1329 ctree_detach_styles (GtkCMCTree *ctree, 1330 GtkCMCTreeNode *node, 1331 gpointer data) 1332 { 1333 GtkCMCList *clist; 1334 gint i; 1335 1336 clist = GTK_CMCLIST (ctree); 1337 1338 if (GTK_CMCTREE_ROW (node)->row.style) 1339 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style); 1340 for (i = 0; i < clist->columns; i++) 1341 if (GTK_CMCTREE_ROW (node)->row.cell[i].style) 1342 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style); 1343 } 1344 1345 static void 1346 gtk_cmctree_realize (GtkWidget *widget) 1347 { 1348 GtkCMCTree *ctree; 1349 GtkCMCList *clist; 1350 GtkCMCTreeNode *node; 1351 GtkCMCTreeNode *child; 1352 gint i; 1353 1354 cm_return_if_fail (GTK_IS_CMCTREE (widget)); 1355 1356 GTK_WIDGET_CLASS (parent_class)->realize (widget); 1357 1358 ctree = GTK_CMCTREE (widget); 1359 clist = GTK_CMCLIST (widget); 1360 1361 node = GTK_CMCTREE_NODE (clist->row_list); 1362 for (i = 0; i < clist->rows; i++) 1363 { 1364 if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded) 1365 for (child = GTK_CMCTREE_ROW (node)->children; child; 1366 child = GTK_CMCTREE_ROW (child)->sibling) 1367 gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL); 1368 node = GTK_CMCTREE_NODE_NEXT (node); 1369 } 1370 } 1371 1372 static void 1373 gtk_cmctree_unrealize (GtkWidget *widget) 1374 { 1375 GtkCMCTree *ctree; 1376 GtkCMCList *clist; 1377 1378 cm_return_if_fail (GTK_IS_CMCTREE (widget)); 1379 1380 GTK_WIDGET_CLASS (parent_class)->unrealize (widget); 1381 1382 ctree = GTK_CMCTREE (widget); 1383 clist = GTK_CMCLIST (widget); 1384 1385 if (gtk_widget_get_realized (widget)) 1386 { 1387 GtkCMCTreeNode *node; 1388 GtkCMCTreeNode *child; 1389 gint i; 1390 1391 node = GTK_CMCTREE_NODE (clist->row_list); 1392 for (i = 0; i < clist->rows; i++) 1393 { 1394 if (GTK_CMCTREE_ROW (node)->children && 1395 !GTK_CMCTREE_ROW (node)->expanded) 1396 for (child = GTK_CMCTREE_ROW (node)->children; child; 1397 child = GTK_CMCTREE_ROW (child)->sibling) 1398 gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL); 1399 node = GTK_CMCTREE_NODE_NEXT (node); 1400 } 1401 } 1402 } 1403 1404 static gint 1405 gtk_cmctree_button_press (GtkWidget *widget, 1406 GdkEventButton *event) 1407 { 1408 GtkCMCTree *ctree; 1409 GtkCMCList *clist; 1410 gint button_actions; 1411 1412 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE); 1413 cm_return_val_if_fail (event != NULL, FALSE); 1414 1415 ctree = GTK_CMCTREE (widget); 1416 clist = GTK_CMCLIST (widget); 1417 1418 button_actions = clist->button_actions[event->button - 1]; 1419 1420 if (button_actions == GTK_CMBUTTON_IGNORED) 1421 return FALSE; 1422 1423 if (event->window == clist->clist_window) 1424 { 1425 GtkCMCTreeNode *work; 1426 gint x; 1427 gint y; 1428 gint row; 1429 gint column; 1430 1431 x = event->x; 1432 y = event->y; 1433 1434 if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column)) 1435 return FALSE; 1436 1437 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); 1438 1439 if (button_actions & GTK_CMBUTTON_EXPANDS && 1440 (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf && 1441 (event->type == GDK_2BUTTON_PRESS || 1442 ctree_is_hot_spot (ctree, work, row, x, y)))) 1443 { 1444 if (GTK_CMCTREE_ROW (work)->expanded) 1445 gtk_cmctree_collapse (ctree, work); 1446 else 1447 gtk_cmctree_expand (ctree, work); 1448 1449 return TRUE; 1450 } 1451 } 1452 1453 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); 1454 } 1455 1456 static GtkCMCTreeNode * 1457 gtk_cmctree_last_visible (GtkCMCTree *ctree, 1458 GtkCMCTreeNode *node) 1459 { 1460 GtkCMCTreeNode *work; 1461 1462 if (!node) 1463 return NULL; 1464 1465 work = GTK_CMCTREE_ROW (node)->children; 1466 1467 if (!work || !GTK_CMCTREE_ROW (node)->expanded) 1468 return node; 1469 1470 while (GTK_CMCTREE_ROW (work)->sibling) 1471 work = GTK_CMCTREE_ROW (work)->sibling; 1472 1473 return gtk_cmctree_last_visible (ctree, work); 1474 } 1475 1476 static void 1477 gtk_cmctree_link (GtkCMCTree *ctree, 1478 GtkCMCTreeNode *node, 1479 GtkCMCTreeNode *parent, 1480 GtkCMCTreeNode *sibling, 1481 gboolean update_focus_row) 1482 { 1483 GtkCMCList *clist; 1484 GList *list_end; 1485 GList *list; 1486 GList *work; 1487 gboolean visible = FALSE; 1488 gint rows = 0; 1489 1490 if (sibling) 1491 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent); 1492 cm_return_if_fail (node != NULL); 1493 cm_return_if_fail (node != sibling); 1494 cm_return_if_fail (node != parent); 1495 1496 clist = GTK_CMCLIST (ctree); 1497 1498 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) 1499 { 1500 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1501 1502 g_list_free (clist->undo_selection); 1503 g_list_free (clist->undo_unselection); 1504 clist->undo_selection = NULL; 1505 clist->undo_unselection = NULL; 1506 } 1507 1508 for (rows = 1, list_end = (GList *)node; list_end->next; 1509 list_end = list_end->next) 1510 rows++; 1511 1512 GTK_CMCTREE_ROW (node)->parent = parent; 1513 GTK_CMCTREE_ROW (node)->sibling = sibling; 1514 1515 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) && 1516 GTK_CMCTREE_ROW (parent)->expanded))) 1517 { 1518 visible = TRUE; 1519 clist->rows += rows; 1520 } 1521 1522 if (parent) 1523 work = (GList *)(GTK_CMCTREE_ROW (parent)->children); 1524 else 1525 work = clist->row_list; 1526 1527 if (sibling) 1528 { 1529 if (work != (GList *)sibling) 1530 { 1531 while (GTK_CMCTREE_ROW (work)->sibling != sibling) 1532 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); 1533 GTK_CMCTREE_ROW (work)->sibling = node; 1534 } 1535 1536 if (sibling == GTK_CMCTREE_NODE (clist->row_list)) 1537 clist->row_list = (GList *) node; 1538 if (GTK_CMCTREE_NODE_PREV (sibling) && 1539 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) 1540 { 1541 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling); 1542 list->next = (GList *)node; 1543 } 1544 1545 list = (GList *)node; 1546 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling); 1547 list_end->next = (GList *)sibling; 1548 list = (GList *)sibling; 1549 list->prev = list_end; 1550 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling) 1551 GTK_CMCTREE_ROW (parent)->children = node; 1552 } 1553 else 1554 { 1555 if (work) 1556 { 1557 /* find sibling */ 1558 while (GTK_CMCTREE_ROW (work)->sibling) 1559 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); 1560 GTK_CMCTREE_ROW (work)->sibling = node; 1561 1562 /* find last visible child of sibling */ 1563 work = (GList *) gtk_cmctree_last_visible (ctree, 1564 GTK_CMCTREE_NODE (work)); 1565 1566 list_end->next = work->next; 1567 if (work->next) 1568 work->next->prev = list_end; 1569 work->next = (GList *)node; 1570 list = (GList *)node; 1571 list->prev = work; 1572 } 1573 else 1574 { 1575 if (parent) 1576 { 1577 GTK_CMCTREE_ROW (parent)->children = node; 1578 list = (GList *)node; 1579 list->prev = (GList *)parent; 1580 if (GTK_CMCTREE_ROW (parent)->expanded) 1581 { 1582 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent); 1583 if (GTK_CMCTREE_NODE_NEXT(parent)) 1584 { 1585 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent); 1586 list->prev = list_end; 1587 } 1588 list = (GList *)parent; 1589 list->next = (GList *)node; 1590 } 1591 else 1592 list_end->next = NULL; 1593 } 1594 else 1595 { 1596 clist->row_list = (GList *)node; 1597 list = (GList *)node; 1598 list->prev = NULL; 1599 list_end->next = NULL; 1600 } 1601 } 1602 } 1603 1604 gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL); 1605 1606 if (clist->row_list_end == NULL || 1607 clist->row_list_end->next == (GList *)node) 1608 clist->row_list_end = list_end; 1609 1610 if (visible && update_focus_row) 1611 { 1612 gint pos; 1613 1614 pos = g_list_position (clist->row_list, (GList *)node); 1615 1616 if (pos <= clist->focus_row) 1617 { 1618 clist->focus_row += rows; 1619 clist->undo_anchor = clist->focus_row; 1620 } 1621 } 1622 } 1623 1624 static void 1625 gtk_cmctree_unlink (GtkCMCTree *ctree, 1626 GtkCMCTreeNode *node, 1627 gboolean update_focus_row) 1628 { 1629 GtkCMCList *clist; 1630 gint rows; 1631 gint level; 1632 gint visible; 1633 GtkCMCTreeNode *work; 1634 GtkCMCTreeNode *parent; 1635 GList *list; 1636 1637 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1638 cm_return_if_fail (node != NULL); 1639 1640 clist = GTK_CMCLIST (ctree); 1641 1642 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) 1643 { 1644 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1645 1646 g_list_free (clist->undo_selection); 1647 g_list_free (clist->undo_unselection); 1648 clist->undo_selection = NULL; 1649 clist->undo_unselection = NULL; 1650 } 1651 1652 visible = gtk_cmctree_is_viewable (ctree, node); 1653 1654 /* clist->row_list_end unlinked ? */ 1655 if (visible && 1656 (GTK_CMCTREE_NODE_NEXT (node) == NULL || 1657 (GTK_CMCTREE_ROW (node)->children && 1658 gtk_cmctree_is_ancestor (ctree, node, 1659 GTK_CMCTREE_NODE (clist->row_list_end))))) 1660 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node)); 1661 1662 /* update list */ 1663 rows = 0; 1664 level = GTK_CMCTREE_ROW (node)->level; 1665 work = GTK_CMCTREE_NODE_NEXT (node); 1666 while (work && GTK_CMCTREE_ROW (work)->level > level) 1667 { 1668 work = GTK_CMCTREE_NODE_NEXT (work); 1669 rows++; 1670 } 1671 1672 if (visible) 1673 { 1674 clist->rows -= (rows + 1); 1675 1676 if (update_focus_row) 1677 { 1678 gint pos; 1679 1680 pos = g_list_position (clist->row_list, (GList *)node); 1681 if (pos + rows < clist->focus_row) 1682 clist->focus_row -= (rows + 1); 1683 else if (pos <= clist->focus_row) 1684 { 1685 if (!GTK_CMCTREE_ROW (node)->sibling) 1686 clist->focus_row = MAX (pos - 1, 0); 1687 else 1688 clist->focus_row = pos; 1689 1690 clist->focus_row = MIN (clist->focus_row, clist->rows - 1); 1691 } 1692 clist->undo_anchor = clist->focus_row; 1693 } 1694 } 1695 1696 if (work) 1697 { 1698 list = (GList *)GTK_CMCTREE_NODE_PREV (work); 1699 list->next = NULL; 1700 list = (GList *)work; 1701 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node); 1702 } 1703 1704 if (GTK_CMCTREE_NODE_PREV (node) && 1705 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) 1706 { 1707 list = (GList *)GTK_CMCTREE_NODE_PREV (node); 1708 list->next = (GList *)work; 1709 } 1710 1711 /* update tree */ 1712 parent = GTK_CMCTREE_ROW (node)->parent; 1713 if (parent) 1714 { 1715 if (GTK_CMCTREE_ROW (parent)->children == node) 1716 { 1717 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling; 1718 if (!GTK_CMCTREE_ROW (parent)->children) 1719 gtk_cmctree_collapse (ctree, parent); 1720 } 1721 else 1722 { 1723 GtkCMCTreeNode *sibling; 1724 1725 sibling = GTK_CMCTREE_ROW (parent)->children; 1726 while (GTK_CMCTREE_ROW (sibling)->sibling != node) 1727 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1728 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; 1729 } 1730 } 1731 else 1732 { 1733 if (clist->row_list == (GList *)node) 1734 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling); 1735 else 1736 { 1737 GtkCMCTreeNode *sibling; 1738 1739 sibling = GTK_CMCTREE_NODE (clist->row_list); 1740 while (GTK_CMCTREE_ROW (sibling)->sibling != node) 1741 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1742 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; 1743 } 1744 } 1745 } 1746 1747 static void 1748 real_row_move (GtkCMCList *clist, 1749 gint source_row, 1750 gint dest_row) 1751 { 1752 GtkCMCTree *ctree; 1753 GtkCMCTreeNode *node; 1754 1755 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 1756 1757 if (GTK_CMCLIST_AUTO_SORT (clist)) 1758 return; 1759 1760 if (source_row < 0 || source_row >= clist->rows || 1761 dest_row < 0 || dest_row >= clist->rows || 1762 source_row == dest_row) 1763 return; 1764 1765 ctree = GTK_CMCTREE (clist); 1766 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row)); 1767 1768 if (source_row < dest_row) 1769 { 1770 GtkCMCTreeNode *work; 1771 1772 dest_row++; 1773 work = GTK_CMCTREE_ROW (node)->children; 1774 1775 while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level) 1776 { 1777 work = GTK_CMCTREE_NODE_NEXT (work); 1778 dest_row++; 1779 } 1780 1781 if (dest_row > clist->rows) 1782 dest_row = clist->rows; 1783 } 1784 1785 if (dest_row < clist->rows) 1786 { 1787 GtkCMCTreeNode *sibling; 1788 1789 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row)); 1790 gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling); 1791 } 1792 else 1793 gtk_cmctree_move (ctree, node, NULL, NULL); 1794 } 1795 1796 static void 1797 real_tree_move (GtkCMCTree *ctree, 1798 GtkCMCTreeNode *node, 1799 GtkCMCTreeNode *new_parent, 1800 GtkCMCTreeNode *new_sibling) 1801 { 1802 GtkCMCList *clist; 1803 GtkCMCTreeNode *work; 1804 gboolean visible = FALSE; 1805 1806 cm_return_if_fail (ctree != NULL); 1807 cm_return_if_fail (node != NULL); 1808 cm_return_if_fail (!new_sibling || 1809 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent); 1810 1811 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf) 1812 return; 1813 1814 /* new_parent != child of child */ 1815 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent) 1816 if (work == node) 1817 return; 1818 1819 clist = GTK_CMCLIST (ctree); 1820 1821 visible = gtk_cmctree_is_viewable (ctree, node); 1822 1823 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) 1824 { 1825 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1826 1827 g_list_free (clist->undo_selection); 1828 g_list_free (clist->undo_unselection); 1829 clist->undo_selection = NULL; 1830 clist->undo_unselection = NULL; 1831 } 1832 1833 if (GTK_CMCLIST_AUTO_SORT (clist)) 1834 { 1835 if (new_parent == GTK_CMCTREE_ROW (node)->parent) 1836 return; 1837 1838 if (new_parent) 1839 new_sibling = GTK_CMCTREE_ROW (new_parent)->children; 1840 else 1841 new_sibling = GTK_CMCTREE_NODE (clist->row_list); 1842 1843 while (new_sibling && clist->compare 1844 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0) 1845 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling; 1846 } 1847 1848 if (new_parent == GTK_CMCTREE_ROW (node)->parent && 1849 new_sibling == GTK_CMCTREE_ROW (node)->sibling) 1850 return; 1851 1852 gtk_cmclist_freeze (clist); 1853 1854 work = NULL; 1855 if (gtk_cmctree_is_viewable (ctree, node)) 1856 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); 1857 1858 gtk_cmctree_unlink (ctree, node, FALSE); 1859 gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE); 1860 1861 if (work) 1862 { 1863 while (work && !gtk_cmctree_is_viewable (ctree, work)) 1864 work = GTK_CMCTREE_ROW (work)->parent; 1865 clist->focus_row = g_list_position (clist->row_list, (GList *)work); 1866 clist->undo_anchor = clist->focus_row; 1867 } 1868 1869 if (clist->column[ctree->tree_column].auto_resize && 1870 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && 1871 (visible || gtk_cmctree_is_viewable (ctree, node))) 1872 gtk_cmclist_set_column_width 1873 (clist, ctree->tree_column, 1874 gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); 1875 1876 gtk_cmclist_thaw (clist); 1877 } 1878 1879 static void 1880 change_focus_row_expansion (GtkCMCTree *ctree, 1881 GtkCMCTreeExpansionType action) 1882 { 1883 GtkCMCList *clist; 1884 GtkCMCTreeNode *node; 1885 1886 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1887 1888 clist = GTK_CMCLIST (ctree); 1889 1890 if (gtkut_pointer_is_grabbed (GTK_WIDGET (ctree)) && 1891 gtk_widget_has_grab (GTK_WIDGET(ctree))) 1892 return; 1893 1894 if (!(node = 1895 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) || 1896 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children)) 1897 return; 1898 1899 switch (action) 1900 { 1901 case GTK_CMCTREE_EXPANSION_EXPAND: 1902 gtk_cmctree_expand (ctree, node); 1903 break; 1904 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE: 1905 gtk_cmctree_expand_recursive (ctree, node); 1906 break; 1907 case GTK_CMCTREE_EXPANSION_COLLAPSE: 1908 gtk_cmctree_collapse (ctree, node); 1909 break; 1910 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE: 1911 gtk_cmctree_collapse_recursive (ctree, node); 1912 break; 1913 case GTK_CMCTREE_EXPANSION_TOGGLE: 1914 gtk_cmctree_toggle_expansion (ctree, node); 1915 break; 1916 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE: 1917 gtk_cmctree_toggle_expansion_recursive (ctree, node); 1918 break; 1919 } 1920 } 1921 1922 static void 1923 real_tree_expand (GtkCMCTree *ctree, 1924 GtkCMCTreeNode *node) 1925 { 1926 GtkCMCList *clist; 1927 GtkCMCTreeNode *work; 1928 GtkRequisition requisition; 1929 gboolean visible; 1930 1931 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1932 1933 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf) 1934 return; 1935 1936 clist = GTK_CMCLIST (ctree); 1937 1938 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1939 1940 GTK_CMCTREE_ROW (node)->expanded = TRUE; 1941 1942 visible = gtk_cmctree_is_viewable (ctree, node); 1943 /* get cell width if tree_column is auto resized */ 1944 if (visible && clist->column[ctree->tree_column].auto_resize && 1945 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 1946 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 1947 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); 1948 1949 /* unref/unset closed pixbuf */ 1950 if (GTK_CMCELL_PIXTEXT 1951 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf) 1952 { 1953 g_object_unref 1954 (GTK_CMCELL_PIXTEXT 1955 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf); 1956 1957 GTK_CMCELL_PIXTEXT 1958 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL; 1959 } 1960 1961 /* set/ref opened pixbuf */ 1962 if (GTK_CMCTREE_ROW (node)->pixbuf_opened) 1963 { 1964 GTK_CMCELL_PIXTEXT 1965 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 1966 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened); 1967 } 1968 1969 1970 work = GTK_CMCTREE_ROW (node)->children; 1971 if (work) 1972 { 1973 GList *list = (GList *)work; 1974 gint *cell_width = NULL; 1975 gint tmp = 0; 1976 gint row; 1977 gint i; 1978 1979 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 1980 { 1981 cell_width = g_new0 (gint, clist->columns); 1982 if (clist->column[ctree->tree_column].auto_resize) 1983 cell_width[ctree->tree_column] = requisition.width; 1984 1985 while (work) 1986 { 1987 /* search maximum cell widths of auto_resize columns */ 1988 for (i = 0; i < clist->columns; i++) 1989 if (clist->column[i].auto_resize) 1990 { 1991 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 1992 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition); 1993 cell_width[i] = MAX (requisition.width, cell_width[i]); 1994 } 1995 1996 list = (GList *)work; 1997 work = GTK_CMCTREE_NODE_NEXT (work); 1998 tmp++; 1999 } 2000 } 2001 else 2002 while (work) 2003 { 2004 list = (GList *)work; 2005 work = GTK_CMCTREE_NODE_NEXT (work); 2006 tmp++; 2007 } 2008 2009 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node); 2010 2011 if (GTK_CMCTREE_NODE_NEXT (node)) 2012 { 2013 GList *tmp_list; 2014 2015 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node); 2016 tmp_list->prev = list; 2017 } 2018 else 2019 clist->row_list_end = list; 2020 2021 list = (GList *)node; 2022 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children); 2023 2024 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2025 { 2026 /* resize auto_resize columns if needed */ 2027 for (i = 0; i < clist->columns; i++) 2028 if (clist->column[i].auto_resize && 2029 cell_width[i] > clist->column[i].width) 2030 gtk_cmclist_set_column_width (clist, i, cell_width[i]); 2031 g_free (cell_width); 2032 2033 /* update focus_row position */ 2034 row = g_list_position (clist->row_list, (GList *)node); 2035 if (row < clist->focus_row) 2036 clist->focus_row += tmp; 2037 2038 clist->rows += tmp; 2039 CLIST_REFRESH (clist); 2040 } 2041 } 2042 else if (visible && clist->column[ctree->tree_column].auto_resize) 2043 /* resize tree_column if needed */ 2044 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, 2045 requisition.width); 2046 } 2047 2048 static void 2049 real_tree_collapse (GtkCMCTree *ctree, 2050 GtkCMCTreeNode *node) 2051 { 2052 GtkCMCList *clist; 2053 GtkCMCTreeNode *work; 2054 GtkRequisition requisition; 2055 gboolean visible; 2056 gint level; 2057 2058 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 2059 2060 if (!node || !GTK_CMCTREE_ROW (node)->expanded || 2061 GTK_CMCTREE_ROW (node)->is_leaf) 2062 return; 2063 2064 clist = GTK_CMCLIST (ctree); 2065 2066 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 2067 2068 GTK_CMCTREE_ROW (node)->expanded = FALSE; 2069 level = GTK_CMCTREE_ROW (node)->level; 2070 2071 visible = gtk_cmctree_is_viewable (ctree, node); 2072 /* get cell width if tree_column is auto resized */ 2073 if (visible && clist->column[ctree->tree_column].auto_resize && 2074 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2075 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 2076 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); 2077 2078 /* unref/unset opened pixbuf */ 2079 if (GTK_CMCELL_PIXTEXT 2080 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf) 2081 { 2082 g_object_unref 2083 (GTK_CMCELL_PIXTEXT 2084 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf); 2085 2086 GTK_CMCELL_PIXTEXT 2087 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL; 2088 } 2089 2090 /* set/ref closed pixbuf */ 2091 if (GTK_CMCTREE_ROW (node)->pixbuf_closed) 2092 { 2093 GTK_CMCELL_PIXTEXT 2094 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 2095 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed); 2096 } 2097 2098 work = GTK_CMCTREE_ROW (node)->children; 2099 if (work) 2100 { 2101 gint tmp = 0; 2102 gint row; 2103 GList *list; 2104 2105 while (work && GTK_CMCTREE_ROW (work)->level > level) 2106 { 2107 work = GTK_CMCTREE_NODE_NEXT (work); 2108 tmp++; 2109 } 2110 2111 if (work) 2112 { 2113 list = (GList *)node; 2114 list->next = (GList *)work; 2115 list = (GList *)GTK_CMCTREE_NODE_PREV (work); 2116 list->next = NULL; 2117 list = (GList *)work; 2118 list->prev = (GList *)node; 2119 } 2120 else 2121 { 2122 list = (GList *)node; 2123 list->next = NULL; 2124 clist->row_list_end = (GList *)node; 2125 } 2126 2127 if (visible) 2128 { 2129 /* resize auto_resize columns if needed */ 2130 auto_resize_columns (clist); 2131 2132 row = g_list_position (clist->row_list, (GList *)node); 2133 if (row < clist->focus_row) 2134 clist->focus_row -= tmp; 2135 clist->rows -= tmp; 2136 CLIST_REFRESH (clist); 2137 } 2138 } 2139 else if (visible && clist->column[ctree->tree_column].auto_resize && 2140 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2141 /* resize tree_column if needed */ 2142 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, 2143 requisition.width); 2144 2145 } 2146 2147 static void 2148 column_auto_resize (GtkCMCList *clist, 2149 GtkCMCListRow *clist_row, 2150 gint column, 2151 gint old_width) 2152 { 2153 /* resize column if needed for auto_resize */ 2154 GtkRequisition requisition; 2155 2156 if (!clist->column[column].auto_resize || 2157 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2158 return; 2159 2160 if (clist_row) 2161 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, 2162 column, &requisition); 2163 else 2164 requisition.width = 0; 2165 2166 if (requisition.width > clist->column[column].width) 2167 gtk_cmclist_set_column_width (clist, column, requisition.width); 2168 else if (requisition.width < old_width && 2169 old_width == clist->column[column].width) 2170 { 2171 GList *list; 2172 gint new_width; 2173 2174 /* run a "gtk_cmclist_optimal_column_width" but break, if 2175 * the column doesn't shrink */ 2176 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button) 2177 { 2178 GtkRequisition req; 2179 gtk_widget_get_requisition (clist->column[column].button, &req); 2180 new_width = (req.width - 2181 (CELL_SPACING + (2 * COLUMN_INSET))); 2182 } 2183 else 2184 new_width = 0; 2185 2186 for (list = clist->row_list; list; list = list->next) 2187 { 2188 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 2189 (clist, GTK_CMCLIST_ROW (list), column, &requisition); 2190 new_width = MAX (new_width, requisition.width); 2191 if (new_width == clist->column[column].width) 2192 break; 2193 } 2194 if (new_width < clist->column[column].width) 2195 gtk_cmclist_set_column_width (clist, column, new_width); 2196 } 2197 } 2198 2199 static void 2200 auto_resize_columns (GtkCMCList *clist) 2201 { 2202 gint i; 2203 2204 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2205 return; 2206 2207 for (i = 0; i < clist->columns; i++) 2208 column_auto_resize (clist, NULL, i, clist->column[i].width); 2209 } 2210 2211 static void 2212 cell_size_request (GtkCMCList *clist, 2213 GtkCMCListRow *clist_row, 2214 gint column, 2215 GtkRequisition *requisition) 2216 { 2217 GtkCMCTree *ctree; 2218 gint width; 2219 gint height; 2220 PangoLayout *layout; 2221 PangoRectangle logical_rect; 2222 2223 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2224 cm_return_if_fail (requisition != NULL); 2225 2226 ctree = GTK_CMCTREE (clist); 2227 2228 layout = create_cell_layout (clist, clist_row, column); 2229 if (layout) 2230 { 2231 pango_layout_get_pixel_extents (layout, NULL, &logical_rect); 2232 2233 requisition->width = logical_rect.width; 2234 requisition->height = logical_rect.height; 2235 2236 g_object_unref (G_OBJECT (layout)); 2237 } 2238 else 2239 { 2240 requisition->width = 0; 2241 requisition->height = 0; 2242 } 2243 2244 switch (clist_row->cell[column].type) 2245 { 2246 case GTK_CMCELL_PIXTEXT: 2247 if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf) 2248 { 2249 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf); 2250 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf); 2251 width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing; 2252 } 2253 else 2254 width = height = 0; 2255 2256 requisition->width += width; 2257 requisition->height = MAX (requisition->height, height); 2258 2259 if (column == ctree->tree_column) 2260 { 2261 requisition->width += (ctree->tree_spacing + ctree->tree_indent * 2262 (((GtkCMCTreeRow *) clist_row)->level - 1)); 2263 switch (ctree->expander_style) 2264 { 2265 case GTK_CMCTREE_EXPANDER_NONE: 2266 break; 2267 case GTK_CMCTREE_EXPANDER_TRIANGLE: 2268 requisition->width += PM_SIZE + 3; 2269 break; 2270 } 2271 } 2272 break; 2273 case GTK_CMCELL_PIXBUF: 2274 width = gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf); 2275 height = gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf); 2276 requisition->width += width; 2277 requisition->height = MAX (requisition->height, height); 2278 break; 2279 default: 2280 break; 2281 } 2282 2283 requisition->width += clist_row->cell[column].horizontal; 2284 requisition->height += clist_row->cell[column].vertical; 2285 } 2286 2287 static void 2288 set_cell_contents (GtkCMCList *clist, 2289 GtkCMCListRow *clist_row, 2290 gint column, 2291 GtkCMCellType type, 2292 const gchar *text, 2293 guint8 spacing, 2294 GdkPixbuf *pixbuf) 2295 { 2296 gboolean visible = FALSE; 2297 GtkCMCTree *ctree; 2298 GtkRequisition requisition; 2299 gchar *old_text = NULL; 2300 GdkPixbuf *old_pixbuf = NULL; 2301 2302 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2303 cm_return_if_fail (clist_row != NULL); 2304 2305 ctree = GTK_CMCTREE (clist); 2306 2307 if (clist->column[column].auto_resize && 2308 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2309 { 2310 GtkCMCTreeNode *parent; 2311 2312 parent = ((GtkCMCTreeRow *)clist_row)->parent; 2313 if ((parent && GTK_CMCTREE_ROW (parent)->expanded && 2314 gtk_cmctree_is_viewable (ctree, parent))) 2315 { 2316 visible = TRUE; 2317 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, 2318 column, &requisition); 2319 } 2320 } 2321 2322 switch (clist_row->cell[column].type) 2323 { 2324 case GTK_CMCELL_EMPTY: 2325 break; 2326 case GTK_CMCELL_TEXT: 2327 old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text; 2328 break; 2329 case GTK_CMCELL_PIXBUF: 2330 old_pixbuf = GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf; 2331 break; 2332 case GTK_CMCELL_PIXTEXT: 2333 old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text; 2334 old_pixbuf = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf; 2335 break; 2336 case GTK_CMCELL_WIDGET: 2337 /* unimplemented */ 2338 break; 2339 2340 default: 2341 break; 2342 } 2343 2344 clist_row->cell[column].type = GTK_CMCELL_EMPTY; 2345 if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY) 2346 type = GTK_CMCELL_PIXTEXT; 2347 2348 /* Note that pixbuf and mask were already ref'ed by the caller 2349 */ 2350 switch (type) 2351 { 2352 case GTK_CMCELL_TEXT: 2353 if (text) 2354 { 2355 clist_row->cell[column].type = GTK_CMCELL_TEXT; 2356 GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text); 2357 } 2358 break; 2359 case GTK_CMCELL_PIXBUF: 2360 if (pixbuf) 2361 { 2362 clist_row->cell[column].type = GTK_CMCELL_PIXBUF; 2363 GTK_CMCELL_PIXBUF (clist_row->cell[column])->pixbuf = pixbuf; 2364 } 2365 break; 2366 case GTK_CMCELL_PIXTEXT: 2367 if (column == ctree->tree_column) 2368 { 2369 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT; 2370 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; 2371 if (text) 2372 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); 2373 else 2374 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL; 2375 if (pixbuf) 2376 { 2377 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf; 2378 } 2379 else 2380 { 2381 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = NULL; 2382 } 2383 } 2384 else if (text && pixbuf) 2385 { 2386 clist_row->cell[column].type = GTK_CMCELL_PIXTEXT; 2387 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); 2388 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; 2389 GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixbuf = pixbuf; 2390 } 2391 break; 2392 default: 2393 break; 2394 } 2395 2396 if (visible && clist->column[column].auto_resize && 2397 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 2398 column_auto_resize (clist, clist_row, column, requisition.width); 2399 2400 g_free (old_text); 2401 if (old_pixbuf) 2402 g_object_unref (old_pixbuf); 2403 } 2404 2405 static void 2406 set_node_info (GtkCMCTree *ctree, 2407 GtkCMCTreeNode *node, 2408 const gchar *text, 2409 guint8 spacing, 2410 GdkPixbuf *pixbuf_closed, 2411 GdkPixbuf *pixbuf_opened, 2412 gboolean is_leaf, 2413 gboolean expanded) 2414 { 2415 if (GTK_CMCTREE_ROW (node)->pixbuf_opened) 2416 { 2417 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened); 2418 } 2419 if (GTK_CMCTREE_ROW (node)->pixbuf_closed) 2420 { 2421 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed); 2422 } 2423 2424 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL; 2425 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL; 2426 2427 if (pixbuf_closed) 2428 { 2429 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed); 2430 } 2431 if (pixbuf_opened) 2432 { 2433 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened); 2434 } 2435 2436 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf; 2437 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; 2438 2439 if (GTK_CMCTREE_ROW (node)->expanded) 2440 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, 2441 text, spacing, pixbuf_opened); 2442 else 2443 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, 2444 text, spacing, pixbuf_closed); 2445 } 2446 2447 static void 2448 tree_delete (GtkCMCTree *ctree, 2449 GtkCMCTreeNode *node, 2450 gpointer data) 2451 { 2452 tree_unselect (ctree, node, NULL); 2453 row_delete (ctree, GTK_CMCTREE_ROW (node)); 2454 g_list_free_1 ((GList *)node); 2455 } 2456 2457 static void 2458 tree_delete_row (GtkCMCTree *ctree, 2459 GtkCMCTreeNode *node, 2460 gpointer data) 2461 { 2462 row_delete (ctree, GTK_CMCTREE_ROW (node)); 2463 g_list_free_1 ((GList *)node); 2464 } 2465 2466 static void 2467 tree_update_level (GtkCMCTree *ctree, 2468 GtkCMCTreeNode *node, 2469 gpointer data) 2470 { 2471 if (!node) 2472 return; 2473 2474 if (GTK_CMCTREE_ROW (node)->parent) 2475 GTK_CMCTREE_ROW (node)->level = 2476 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1; 2477 else 2478 GTK_CMCTREE_ROW (node)->level = 1; 2479 } 2480 2481 static void 2482 tree_select (GtkCMCTree *ctree, 2483 GtkCMCTreeNode *node, 2484 gpointer data) 2485 { 2486 if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED && 2487 GTK_CMCTREE_ROW (node)->row.selectable) 2488 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0, 2489 node, -1); 2490 } 2491 2492 static void 2493 tree_unselect (GtkCMCTree *ctree, 2494 GtkCMCTreeNode *node, 2495 gpointer data) 2496 { 2497 if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) 2498 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0, 2499 node, -1); 2500 } 2501 2502 static void 2503 tree_expand (GtkCMCTree *ctree, 2504 GtkCMCTreeNode *node, 2505 gpointer data) 2506 { 2507 if (node && !GTK_CMCTREE_ROW (node)->expanded) 2508 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node); 2509 } 2510 2511 static void 2512 tree_collapse (GtkCMCTree *ctree, 2513 GtkCMCTreeNode *node, 2514 gpointer data) 2515 { 2516 if (node && GTK_CMCTREE_ROW (node)->expanded) 2517 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node); 2518 } 2519 2520 static void 2521 tree_collapse_to_depth (GtkCMCTree *ctree, 2522 GtkCMCTreeNode *node, 2523 gint depth) 2524 { 2525 if (node && GTK_CMCTREE_ROW (node)->level == depth) 2526 gtk_cmctree_collapse_recursive (ctree, node); 2527 } 2528 2529 static void 2530 tree_toggle_expansion (GtkCMCTree *ctree, 2531 GtkCMCTreeNode *node, 2532 gpointer data) 2533 { 2534 if (!node) 2535 return; 2536 2537 if (GTK_CMCTREE_ROW (node)->expanded) 2538 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node); 2539 else 2540 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node); 2541 } 2542 2543 static GtkCMCTreeRow * 2544 row_new (GtkCMCTree *ctree) 2545 { 2546 GtkCMCList *clist; 2547 GtkCMCTreeRow *ctree_row; 2548 int i; 2549 2550 clist = GTK_CMCLIST (ctree); 2551 ctree_row = g_slice_new (GtkCMCTreeRow); 2552 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns); 2553 2554 for (i = 0; i < clist->columns; i++) 2555 { 2556 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY; 2557 ctree_row->row.cell[i].vertical = 0; 2558 ctree_row->row.cell[i].horizontal = 0; 2559 ctree_row->row.cell[i].style = NULL; 2560 } 2561 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL; 2562 2563 ctree_row->row.fg_set = FALSE; 2564 ctree_row->row.bg_set = FALSE; 2565 ctree_row->row.style = NULL; 2566 ctree_row->row.selectable = TRUE; 2567 ctree_row->row.state = GTK_STATE_NORMAL; 2568 ctree_row->row.data = NULL; 2569 ctree_row->row.destroy = NULL; 2570 2571 ctree_row->level = 0; 2572 ctree_row->expanded = FALSE; 2573 ctree_row->parent = NULL; 2574 ctree_row->sibling = NULL; 2575 ctree_row->children = NULL; 2576 ctree_row->pixbuf_closed = NULL; 2577 ctree_row->pixbuf_opened = NULL; 2578 2579 return ctree_row; 2580 } 2581 2582 static void 2583 row_delete (GtkCMCTree *ctree, 2584 GtkCMCTreeRow *ctree_row) 2585 { 2586 GtkCMCList *clist; 2587 gint i; 2588 2589 clist = GTK_CMCLIST (ctree); 2590 2591 for (i = 0; i < clist->columns; i++) 2592 { 2593 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 2594 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL); 2595 if (ctree_row->row.cell[i].style) 2596 { 2597 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 2598 gtk_style_detach (ctree_row->row.cell[i].style); 2599 g_object_unref (ctree_row->row.cell[i].style); 2600 } 2601 } 2602 2603 if (ctree_row->row.style) 2604 { 2605 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 2606 gtk_style_detach (ctree_row->row.style); 2607 g_object_unref (ctree_row->row.style); 2608 } 2609 2610 if (ctree_row->pixbuf_closed) 2611 { 2612 g_object_unref (ctree_row->pixbuf_closed); 2613 } 2614 2615 if (ctree_row->pixbuf_opened) 2616 { 2617 g_object_unref (ctree_row->pixbuf_opened); 2618 } 2619 2620 if (ctree_row->row.destroy) 2621 { 2622 GDestroyNotify dnotify = ctree_row->row.destroy; 2623 gpointer ddata = ctree_row->row.data; 2624 2625 ctree_row->row.destroy = NULL; 2626 ctree_row->row.data = NULL; 2627 2628 dnotify (ddata); 2629 } 2630 2631 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell); 2632 g_slice_free (GtkCMCTreeRow, ctree_row); 2633 } 2634 2635 static void 2636 real_select_row (GtkCMCList *clist, 2637 gint row, 2638 gint column, 2639 GdkEvent *event) 2640 { 2641 GList *node; 2642 2643 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2644 2645 if ((node = g_list_nth (clist->row_list, row)) && 2646 GTK_CMCTREE_ROW (node)->row.selectable) 2647 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0, 2648 node, column); 2649 } 2650 2651 static void 2652 real_unselect_row (GtkCMCList *clist, 2653 gint row, 2654 gint column, 2655 GdkEvent *event) 2656 { 2657 GList *node; 2658 2659 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2660 2661 if ((node = g_list_nth (clist->row_list, row))) 2662 g_signal_emit (G_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0, 2663 node, column); 2664 } 2665 2666 static void 2667 tree_draw_node (GtkCMCTree *ctree, 2668 GtkCMCTreeNode *node) 2669 { 2670 GtkCMCList *clist; 2671 2672 clist = GTK_CMCLIST (ctree); 2673 2674 if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node)) 2675 { 2676 GtkCMCTreeNode *work; 2677 gint num = 0; 2678 2679 work = GTK_CMCTREE_NODE (clist->row_list); 2680 while (work && work != node) 2681 { 2682 work = GTK_CMCTREE_NODE_NEXT (work); 2683 num++; 2684 } 2685 if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE) 2686 GTK_CMCLIST_GET_CLASS(ctree)->draw_row 2687 (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node)); 2688 } 2689 } 2690 2691 static void 2692 real_tree_select (GtkCMCTree *ctree, 2693 GtkCMCTreeNode *node, 2694 gint column) 2695 { 2696 GtkCMCList *clist; 2697 GList *list; 2698 GtkCMCTreeNode *sel_row; 2699 gboolean node_selected; 2700 2701 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 2702 2703 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED || 2704 !GTK_CMCTREE_ROW (node)->row.selectable) 2705 return; 2706 2707 clist = GTK_CMCLIST (ctree); 2708 2709 switch (clist->selection_mode) 2710 { 2711 case GTK_SELECTION_SINGLE: 2712 case GTK_SELECTION_BROWSE: 2713 2714 node_selected = FALSE; 2715 list = clist->selection; 2716 2717 while (list) 2718 { 2719 sel_row = list->data; 2720 list = list->next; 2721 2722 if (node == sel_row) 2723 node_selected = TRUE; 2724 else 2725 g_signal_emit (G_OBJECT (ctree), 2726 ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column); 2727 } 2728 2729 if (node_selected) 2730 return; 2731 2732 default: 2733 break; 2734 } 2735 2736 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; 2737 2738 if (!clist->selection) 2739 { 2740 clist->selection = g_list_append (clist->selection, node); 2741 clist->selection_end = clist->selection; 2742 } 2743 else 2744 clist->selection_end = g_list_append (clist->selection_end, node)->next; 2745 2746 tree_draw_node (ctree, node); 2747 } 2748 2749 static void 2750 real_tree_unselect (GtkCMCTree *ctree, 2751 GtkCMCTreeNode *node, 2752 gint column) 2753 { 2754 GtkCMCList *clist; 2755 2756 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 2757 2758 if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED) 2759 return; 2760 2761 clist = GTK_CMCLIST (ctree); 2762 2763 if (clist->selection_end && clist->selection_end->data == node) 2764 clist->selection_end = clist->selection_end->prev; 2765 2766 clist->selection = g_list_remove (clist->selection, node); 2767 2768 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; 2769 2770 tree_draw_node (ctree, node); 2771 } 2772 2773 static void 2774 select_row_recursive (GtkCMCTree *ctree, 2775 GtkCMCTreeNode *node, 2776 gpointer data) 2777 { 2778 if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED || 2779 !GTK_CMCTREE_ROW (node)->row.selectable) 2780 return; 2781 2782 GTK_CMCLIST (ctree)->undo_unselection = 2783 g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node); 2784 gtk_cmctree_select (ctree, node); 2785 } 2786 2787 static void 2788 real_select_all (GtkCMCList *clist) 2789 { 2790 GtkCMCTree *ctree; 2791 GtkCMCTreeNode *node; 2792 2793 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2794 2795 ctree = GTK_CMCTREE (clist); 2796 2797 switch (clist->selection_mode) 2798 { 2799 case GTK_SELECTION_SINGLE: 2800 case GTK_SELECTION_BROWSE: 2801 return; 2802 2803 case GTK_SELECTION_MULTIPLE: 2804 2805 gtk_cmclist_freeze (clist); 2806 2807 g_list_free (clist->undo_selection); 2808 g_list_free (clist->undo_unselection); 2809 clist->undo_selection = NULL; 2810 clist->undo_unselection = NULL; 2811 2812 clist->anchor_state = GTK_STATE_SELECTED; 2813 clist->anchor = -1; 2814 clist->drag_pos = -1; 2815 clist->undo_anchor = clist->focus_row; 2816 2817 for (node = GTK_CMCTREE_NODE (clist->row_list); node; 2818 node = GTK_CMCTREE_NODE_NEXT (node)) 2819 gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL); 2820 2821 gtk_cmclist_thaw (clist); 2822 break; 2823 2824 default: 2825 /* do nothing */ 2826 break; 2827 } 2828 } 2829 2830 static void 2831 real_unselect_all (GtkCMCList *clist) 2832 { 2833 GtkCMCTree *ctree; 2834 GtkCMCTreeNode *node; 2835 GList *list; 2836 2837 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 2838 2839 ctree = GTK_CMCTREE (clist); 2840 2841 switch (clist->selection_mode) 2842 { 2843 case GTK_SELECTION_BROWSE: 2844 if (clist->focus_row >= 0) 2845 { 2846 gtk_cmctree_select 2847 (ctree, 2848 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))); 2849 return; 2850 } 2851 break; 2852 2853 case GTK_SELECTION_MULTIPLE: 2854 g_list_free (clist->undo_selection); 2855 g_list_free (clist->undo_unselection); 2856 clist->undo_selection = NULL; 2857 clist->undo_unselection = NULL; 2858 2859 clist->anchor = -1; 2860 clist->drag_pos = -1; 2861 clist->undo_anchor = clist->focus_row; 2862 break; 2863 2864 default: 2865 break; 2866 } 2867 2868 list = clist->selection; 2869 2870 while (list) 2871 { 2872 node = list->data; 2873 list = list->next; 2874 gtk_cmctree_unselect (ctree, node); 2875 } 2876 } 2877 2878 static gboolean 2879 ctree_is_hot_spot (GtkCMCTree *ctree, 2880 GtkCMCTreeNode *node, 2881 gint row, 2882 gint x, 2883 gint y) 2884 { 2885 GtkCMCTreeRow *tree_row; 2886 GtkCMCList *clist; 2887 gint xl; 2888 gint yu; 2889 gint hotspot_size; 2890 2891 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 2892 cm_return_val_if_fail (node != NULL, FALSE); 2893 2894 clist = GTK_CMCLIST (ctree); 2895 2896 if (!clist->column[ctree->tree_column].visible || 2897 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) 2898 return FALSE; 2899 2900 tree_row = GTK_CMCTREE_ROW (node); 2901 2902 hotspot_size = clist->row_height-2; 2903 if (hotspot_size > clist->column[ctree->tree_column].area.width - 2) 2904 hotspot_size = clist->column[ctree->tree_column].area.width - 2; 2905 2906 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - hotspot_size) / 2 - 2907 (clist->row_height - 1) % 2); 2908 2909 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) 2910 xl = (clist->column[ctree->tree_column].area.x + 2911 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset - 2912 (tree_row->level - 1) * ctree->tree_indent - hotspot_size); 2913 else 2914 xl = (clist->column[ctree->tree_column].area.x + clist->hoffset + 2915 (tree_row->level - 1) * ctree->tree_indent); 2916 2917 return (x >= xl && x <= xl + hotspot_size && y >= yu && y <= yu + hotspot_size); 2918 } 2919 2920 /*********************************************************** 2921 *********************************************************** 2922 *** Public interface *** 2923 *********************************************************** 2924 ***********************************************************/ 2925 2926 2927 /*********************************************************** 2928 * Creation, insertion, deletion * 2929 ***********************************************************/ 2930 2931 static GObject* 2932 gtk_cmctree_constructor (GType type, 2933 guint n_construct_properties, 2934 GObjectConstructParam *construct_properties) 2935 { 2936 GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type, 2937 n_construct_properties, 2938 construct_properties); 2939 2940 return object; 2941 } 2942 2943 GtkWidget* 2944 gtk_cmctree_new_with_titles (gint columns, 2945 gint tree_column, 2946 gchar *titles[]) 2947 { 2948 GtkWidget *widget; 2949 2950 cm_return_val_if_fail (columns > 0, NULL); 2951 cm_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL); 2952 2953 widget = gtk_widget_new (GTK_TYPE_CMCTREE, 2954 "n_columns", columns, 2955 "tree_column", tree_column, 2956 NULL); 2957 if (titles) 2958 { 2959 GtkCMCList *clist = GTK_CMCLIST (widget); 2960 guint i; 2961 2962 for (i = 0; i < columns; i++) 2963 gtk_cmclist_set_column_title (clist, i, titles[i]); 2964 gtk_cmclist_column_titles_show (clist); 2965 } 2966 2967 return widget; 2968 } 2969 2970 GtkWidget * 2971 gtk_cmctree_new (gint columns, 2972 gint tree_column) 2973 { 2974 return gtk_cmctree_new_with_titles (columns, tree_column, NULL); 2975 } 2976 2977 static gint 2978 real_insert_row (GtkCMCList *clist, 2979 gint row, 2980 gchar *text[]) 2981 { 2982 GtkCMCTreeNode *parent = NULL; 2983 GtkCMCTreeNode *sibling; 2984 GtkCMCTreeNode *node; 2985 2986 cm_return_val_if_fail (GTK_IS_CMCTREE (clist), -1); 2987 2988 sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); 2989 if (sibling) 2990 parent = GTK_CMCTREE_ROW (sibling)->parent; 2991 2992 node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5, 2993 NULL, NULL, TRUE, FALSE); 2994 2995 if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling) 2996 return g_list_position (clist->row_list, (GList *) node); 2997 2998 return row; 2999 } 3000 3001 GtkCMCTreeNode * 3002 gtk_cmctree_insert_node (GtkCMCTree *ctree, 3003 GtkCMCTreeNode *parent, 3004 GtkCMCTreeNode *sibling, 3005 gchar *text[], 3006 guint8 spacing, 3007 GdkPixbuf *pixbuf_closed, 3008 GdkPixbuf *pixbuf_opened, 3009 gboolean is_leaf, 3010 gboolean expanded) 3011 { 3012 GtkCMCList *clist; 3013 GtkCMCTreeRow *new_row; 3014 GtkCMCTreeNode *node; 3015 GList *list; 3016 gint i; 3017 3018 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3019 if (sibling) 3020 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); 3021 3022 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf) 3023 return NULL; 3024 3025 clist = GTK_CMCLIST (ctree); 3026 3027 /* create the row */ 3028 new_row = row_new (ctree); 3029 list = g_list_alloc (); 3030 list->data = new_row; 3031 node = GTK_CMCTREE_NODE (list); 3032 3033 if (text) 3034 for (i = 0; i < clist->columns; i++) 3035 if (text[i] && i != ctree->tree_column) 3036 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 3037 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL); 3038 3039 set_node_info (ctree, node, text ? 3040 text[ctree->tree_column] : NULL, spacing, pixbuf_closed, 3041 pixbuf_opened, is_leaf, expanded); 3042 3043 /* sorted insertion */ 3044 if (GTK_CMCLIST_AUTO_SORT (clist)) 3045 { 3046 if (parent) 3047 sibling = GTK_CMCTREE_ROW (parent)->children; 3048 else 3049 sibling = GTK_CMCTREE_NODE (clist->row_list); 3050 3051 while (sibling && clist->compare 3052 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0) 3053 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 3054 } 3055 3056 gtk_cmctree_link (ctree, node, parent, sibling, TRUE); 3057 3058 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && 3059 gtk_cmctree_is_viewable (ctree, node)) 3060 { 3061 for (i = 0; i < clist->columns; i++) 3062 if (clist->column[i].auto_resize) 3063 column_auto_resize (clist, &(new_row->row), i, 0); 3064 } 3065 3066 if (clist->rows == 1) 3067 { 3068 clist->focus_row = 0; 3069 if (clist->selection_mode == GTK_SELECTION_BROWSE) 3070 gtk_cmctree_select (ctree, node); 3071 } 3072 3073 3074 CLIST_REFRESH (clist); 3075 3076 return node; 3077 } 3078 3079 GtkCMCTreeNode * 3080 gtk_cmctree_insert_gnode (GtkCMCTree *ctree, 3081 GtkCMCTreeNode *parent, 3082 GtkCMCTreeNode *sibling, 3083 GNode *gnode, 3084 GtkCMCTreeGNodeFunc func, 3085 gpointer data) 3086 { 3087 GtkCMCList *clist; 3088 GtkCMCTreeNode *cnode = NULL; 3089 GtkCMCTreeNode *child = NULL; 3090 GtkCMCTreeNode *new_child; 3091 GList *list; 3092 GNode *work; 3093 guint depth = 1; 3094 3095 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3096 cm_return_val_if_fail (gnode != NULL, NULL); 3097 cm_return_val_if_fail (func != NULL, NULL); 3098 if (sibling) 3099 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); 3100 3101 clist = GTK_CMCLIST (ctree); 3102 3103 if (parent) 3104 depth = GTK_CMCTREE_ROW (parent)->level + 1; 3105 3106 list = g_list_alloc (); 3107 list->data = row_new (ctree); 3108 cnode = GTK_CMCTREE_NODE (list); 3109 3110 gtk_cmclist_freeze (clist); 3111 3112 set_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE); 3113 3114 if (!func (ctree, depth, gnode, cnode, data)) 3115 { 3116 tree_delete_row (ctree, cnode, NULL); 3117 gtk_cmclist_thaw (clist); 3118 return NULL; 3119 } 3120 3121 if (GTK_CMCLIST_AUTO_SORT (clist)) 3122 { 3123 if (parent) 3124 sibling = GTK_CMCTREE_ROW (parent)->children; 3125 else 3126 sibling = GTK_CMCTREE_NODE (clist->row_list); 3127 3128 while (sibling && clist->compare 3129 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0) 3130 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 3131 } 3132 3133 gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE); 3134 3135 for (work = g_node_last_child (gnode); work; work = work->prev) 3136 { 3137 new_child = gtk_cmctree_insert_gnode (ctree, cnode, child, 3138 work, func, data); 3139 if (new_child) 3140 child = new_child; 3141 } 3142 3143 gtk_cmclist_thaw (clist); 3144 3145 return cnode; 3146 } 3147 3148 GNode * 3149 gtk_cmctree_export_to_gnode (GtkCMCTree *ctree, 3150 GNode *parent, 3151 GNode *sibling, 3152 GtkCMCTreeNode *node, 3153 GtkCMCTreeGNodeFunc func, 3154 gpointer data) 3155 { 3156 GtkCMCTreeNode *work; 3157 GNode *gnode; 3158 gint depth; 3159 3160 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3161 cm_return_val_if_fail (node != NULL, NULL); 3162 cm_return_val_if_fail (func != NULL, NULL); 3163 if (sibling) 3164 { 3165 cm_return_val_if_fail (parent != NULL, NULL); 3166 cm_return_val_if_fail (sibling->parent == parent, NULL); 3167 } 3168 3169 gnode = g_node_new (NULL); 3170 depth = g_node_depth (parent) + 1; 3171 3172 if (!func (ctree, depth, gnode, node, data)) 3173 { 3174 g_node_destroy (gnode); 3175 return NULL; 3176 } 3177 3178 if (parent) 3179 g_node_insert_before (parent, sibling, gnode); 3180 3181 if (!GTK_CMCTREE_ROW (node)->is_leaf) 3182 { 3183 GNode *new_sibling = NULL; 3184 3185 for (work = GTK_CMCTREE_ROW (node)->children; work; 3186 work = GTK_CMCTREE_ROW (work)->sibling) 3187 new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling, 3188 work, func, data); 3189 3190 g_node_reverse_children (gnode); 3191 } 3192 3193 return gnode; 3194 } 3195 3196 static void 3197 real_remove_row (GtkCMCList *clist, 3198 gint row) 3199 { 3200 GtkCMCTreeNode *node; 3201 3202 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 3203 3204 node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); 3205 3206 if (node) 3207 gtk_cmctree_remove_node (GTK_CMCTREE (clist), node); 3208 } 3209 3210 void 3211 gtk_cmctree_remove_node (GtkCMCTree *ctree, 3212 GtkCMCTreeNode *node) 3213 { 3214 GtkCMCList *clist; 3215 3216 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3217 3218 clist = GTK_CMCLIST (ctree); 3219 3220 gtk_cmclist_freeze (clist); 3221 3222 if (node) 3223 { 3224 gtk_cmctree_unlink (ctree, node, TRUE); 3225 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete), 3226 NULL); 3227 if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection && 3228 clist->focus_row >= 0) 3229 gtk_cmclist_select_row (clist, clist->focus_row, -1); 3230 3231 auto_resize_columns (clist); 3232 } 3233 else 3234 gtk_cmclist_clear (clist); 3235 3236 gtk_cmclist_thaw (clist); 3237 } 3238 3239 static void 3240 real_clear (GtkCMCList *clist) 3241 { 3242 GtkCMCTree *ctree; 3243 GtkCMCTreeNode *work; 3244 GtkCMCTreeNode *ptr; 3245 3246 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 3247 3248 ctree = GTK_CMCTREE (clist); 3249 3250 /* remove all rows */ 3251 work = GTK_CMCTREE_NODE (clist->row_list); 3252 clist->row_list = NULL; 3253 clist->row_list_end = NULL; 3254 3255 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3256 while (work) 3257 { 3258 ptr = work; 3259 work = GTK_CMCTREE_ROW (work)->sibling; 3260 gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row), 3261 NULL); 3262 } 3263 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3264 3265 parent_class->clear (clist); 3266 } 3267 3268 3269 /*********************************************************** 3270 * Generic recursive functions, querying / finding tree * 3271 * information * 3272 ***********************************************************/ 3273 3274 3275 void 3276 gtk_cmctree_post_recursive (GtkCMCTree *ctree, 3277 GtkCMCTreeNode *node, 3278 GtkCMCTreeFunc func, 3279 gpointer data) 3280 { 3281 GtkCMCTreeNode *work; 3282 GtkCMCTreeNode *tmp; 3283 3284 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3285 cm_return_if_fail (func != NULL); 3286 3287 if (node) 3288 work = GTK_CMCTREE_ROW (node)->children; 3289 else 3290 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3291 3292 while (work) 3293 { 3294 tmp = GTK_CMCTREE_ROW (work)->sibling; 3295 gtk_cmctree_post_recursive (ctree, work, func, data); 3296 work = tmp; 3297 } 3298 3299 if (node) 3300 func (ctree, node, data); 3301 } 3302 3303 void 3304 gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree, 3305 GtkCMCTreeNode *node, 3306 gint depth, 3307 GtkCMCTreeFunc func, 3308 gpointer data) 3309 { 3310 GtkCMCTreeNode *work; 3311 GtkCMCTreeNode *tmp; 3312 3313 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3314 cm_return_if_fail (func != NULL); 3315 3316 if (depth < 0) 3317 { 3318 gtk_cmctree_post_recursive (ctree, node, func, data); 3319 return; 3320 } 3321 3322 if (node) 3323 work = GTK_CMCTREE_ROW (node)->children; 3324 else 3325 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3326 3327 if (work && GTK_CMCTREE_ROW (work)->level <= depth) 3328 { 3329 while (work) 3330 { 3331 tmp = GTK_CMCTREE_ROW (work)->sibling; 3332 gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data); 3333 work = tmp; 3334 } 3335 } 3336 3337 if (node && GTK_CMCTREE_ROW (node)->level <= depth) 3338 func (ctree, node, data); 3339 } 3340 3341 void 3342 gtk_cmctree_pre_recursive (GtkCMCTree *ctree, 3343 GtkCMCTreeNode *node, 3344 GtkCMCTreeFunc func, 3345 gpointer data) 3346 { 3347 GtkCMCTreeNode *work; 3348 GtkCMCTreeNode *tmp; 3349 3350 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3351 cm_return_if_fail (func != NULL); 3352 3353 if (node) 3354 { 3355 work = GTK_CMCTREE_ROW (node)->children; 3356 func (ctree, node, data); 3357 } 3358 else 3359 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3360 3361 while (work) 3362 { 3363 tmp = GTK_CMCTREE_ROW (work)->sibling; 3364 gtk_cmctree_pre_recursive (ctree, work, func, data); 3365 work = tmp; 3366 } 3367 } 3368 3369 void 3370 gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree, 3371 GtkCMCTreeNode *node, 3372 gint depth, 3373 GtkCMCTreeFunc func, 3374 gpointer data) 3375 { 3376 GtkCMCTreeNode *work; 3377 GtkCMCTreeNode *tmp; 3378 3379 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3380 cm_return_if_fail (func != NULL); 3381 3382 if (depth < 0) 3383 { 3384 gtk_cmctree_pre_recursive (ctree, node, func, data); 3385 return; 3386 } 3387 3388 if (node) 3389 { 3390 work = GTK_CMCTREE_ROW (node)->children; 3391 if (GTK_CMCTREE_ROW (node)->level <= depth) 3392 func (ctree, node, data); 3393 } 3394 else 3395 work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3396 3397 if (work && GTK_CMCTREE_ROW (work)->level <= depth) 3398 { 3399 while (work) 3400 { 3401 tmp = GTK_CMCTREE_ROW (work)->sibling; 3402 gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data); 3403 work = tmp; 3404 } 3405 } 3406 } 3407 3408 gboolean 3409 gtk_cmctree_is_viewable (GtkCMCTree *ctree, 3410 GtkCMCTreeNode *node) 3411 { 3412 GtkCMCTreeRow *work; 3413 3414 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 3415 cm_return_val_if_fail (node != NULL, FALSE); 3416 3417 work = GTK_CMCTREE_ROW (node); 3418 3419 while (work && work->parent && GTK_CMCTREE_ROW (work->parent)->expanded) 3420 work = GTK_CMCTREE_ROW (work->parent); 3421 3422 if (!work->parent) 3423 return TRUE; 3424 3425 return FALSE; 3426 } 3427 3428 GtkCMCTreeNode * 3429 gtk_cmctree_last (GtkCMCTree *ctree, 3430 GtkCMCTreeNode *node) 3431 { 3432 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3433 3434 if (!node) 3435 return NULL; 3436 3437 while (GTK_CMCTREE_ROW (node)->sibling) 3438 node = GTK_CMCTREE_ROW (node)->sibling; 3439 3440 if (GTK_CMCTREE_ROW (node)->children) 3441 return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children); 3442 3443 return node; 3444 } 3445 3446 GtkCMCTreeNode * 3447 gtk_cmctree_find_node_ptr (GtkCMCTree *ctree, 3448 GtkCMCTreeRow *ctree_row) 3449 { 3450 GtkCMCTreeNode *node; 3451 3452 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3453 cm_return_val_if_fail (ctree_row != NULL, NULL); 3454 3455 if (ctree_row->parent) 3456 node = GTK_CMCTREE_ROW (ctree_row->parent)->children; 3457 else 3458 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3459 3460 while (GTK_CMCTREE_ROW (node) != ctree_row) 3461 node = GTK_CMCTREE_ROW (node)->sibling; 3462 3463 return node; 3464 } 3465 3466 GtkCMCTreeNode * 3467 gtk_cmctree_node_nth (GtkCMCTree *ctree, 3468 guint row) 3469 { 3470 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3471 3472 if ((row >= GTK_CMCLIST(ctree)->rows)) 3473 return NULL; 3474 3475 return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row)); 3476 } 3477 3478 gboolean 3479 gtk_cmctree_find (GtkCMCTree *ctree, 3480 GtkCMCTreeNode *node, 3481 GtkCMCTreeNode *child) 3482 { 3483 if (!child) 3484 return FALSE; 3485 3486 if (!node) 3487 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3488 3489 while (node) 3490 { 3491 if (node == child) 3492 return TRUE; 3493 if (GTK_CMCTREE_ROW (node)->children) 3494 { 3495 if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child)) 3496 return TRUE; 3497 } 3498 node = GTK_CMCTREE_ROW (node)->sibling; 3499 } 3500 return FALSE; 3501 } 3502 3503 gboolean 3504 gtk_cmctree_is_ancestor (GtkCMCTree *ctree, 3505 GtkCMCTreeNode *node, 3506 GtkCMCTreeNode *child) 3507 { 3508 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 3509 cm_return_val_if_fail (node != NULL, FALSE); 3510 3511 if (GTK_CMCTREE_ROW (node)->children) 3512 return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child); 3513 3514 return FALSE; 3515 } 3516 3517 GtkCMCTreeNode * 3518 gtk_cmctree_find_by_row_data (GtkCMCTree *ctree, 3519 GtkCMCTreeNode *node, 3520 gpointer data) 3521 { 3522 GtkCMCTreeNode *work; 3523 3524 if (!node) 3525 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3526 3527 while (node) 3528 { 3529 if (GTK_CMCTREE_ROW (node)->row.data == data) 3530 return node; 3531 if (GTK_CMCTREE_ROW (node)->children && 3532 (work = gtk_cmctree_find_by_row_data 3533 (ctree, GTK_CMCTREE_ROW (node)->children, data))) 3534 return work; 3535 node = GTK_CMCTREE_ROW (node)->sibling; 3536 } 3537 return NULL; 3538 } 3539 3540 GList * 3541 gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree, 3542 GtkCMCTreeNode *node, 3543 gpointer data) 3544 { 3545 GList *list = NULL; 3546 3547 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3548 3549 /* if node == NULL then look in the whole tree */ 3550 if (!node) 3551 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3552 3553 while (node) 3554 { 3555 if (GTK_CMCTREE_ROW (node)->row.data == data) 3556 list = g_list_append (list, node); 3557 3558 if (GTK_CMCTREE_ROW (node)->children) 3559 { 3560 GList *sub_list; 3561 3562 sub_list = gtk_cmctree_find_all_by_row_data (ctree, 3563 GTK_CMCTREE_ROW 3564 (node)->children, 3565 data); 3566 list = g_list_concat (list, sub_list); 3567 } 3568 node = GTK_CMCTREE_ROW (node)->sibling; 3569 } 3570 return list; 3571 } 3572 3573 GtkCMCTreeNode * 3574 gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree, 3575 GtkCMCTreeNode *node, 3576 gpointer data, 3577 GCompareFunc func) 3578 { 3579 GtkCMCTreeNode *work; 3580 3581 cm_return_val_if_fail (func != NULL, NULL); 3582 3583 if (!node) 3584 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3585 3586 while (node) 3587 { 3588 if (!func (GTK_CMCTREE_ROW (node)->row.data, data)) 3589 return node; 3590 if (GTK_CMCTREE_ROW (node)->children && 3591 (work = gtk_cmctree_find_by_row_data_custom 3592 (ctree, GTK_CMCTREE_ROW (node)->children, data, func))) 3593 return work; 3594 node = GTK_CMCTREE_ROW (node)->sibling; 3595 } 3596 return NULL; 3597 } 3598 3599 GList * 3600 gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree, 3601 GtkCMCTreeNode *node, 3602 gpointer data, 3603 GCompareFunc func) 3604 { 3605 GList *list = NULL; 3606 3607 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 3608 cm_return_val_if_fail (func != NULL, NULL); 3609 3610 /* if node == NULL then look in the whole tree */ 3611 if (!node) 3612 node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); 3613 3614 while (node) 3615 { 3616 if (!func (GTK_CMCTREE_ROW (node)->row.data, data)) 3617 list = g_list_append (list, node); 3618 3619 if (GTK_CMCTREE_ROW (node)->children) 3620 { 3621 GList *sub_list; 3622 3623 sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree, 3624 GTK_CMCTREE_ROW 3625 (node)->children, 3626 data, 3627 func); 3628 list = g_list_concat (list, sub_list); 3629 } 3630 node = GTK_CMCTREE_ROW (node)->sibling; 3631 } 3632 return list; 3633 } 3634 3635 gboolean 3636 gtk_cmctree_is_hot_spot (GtkCMCTree *ctree, 3637 gint x, 3638 gint y) 3639 { 3640 GtkCMCTreeNode *node; 3641 gint column; 3642 gint row; 3643 3644 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 3645 3646 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column)) 3647 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row)))) 3648 return ctree_is_hot_spot (ctree, node, row, x, y); 3649 3650 return FALSE; 3651 } 3652 3653 3654 /*********************************************************** 3655 * Tree signals : move, expand, collapse, (un)select * 3656 ***********************************************************/ 3657 3658 3659 void 3660 gtk_cmctree_move (GtkCMCTree *ctree, 3661 GtkCMCTreeNode *node, 3662 GtkCMCTreeNode *new_parent, 3663 GtkCMCTreeNode *new_sibling) 3664 { 3665 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3666 cm_return_if_fail (node != NULL); 3667 3668 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node, 3669 new_parent, new_sibling); 3670 } 3671 3672 void 3673 gtk_cmctree_expand (GtkCMCTree *ctree, 3674 GtkCMCTreeNode *node) 3675 { 3676 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3677 cm_return_if_fail (node != NULL); 3678 3679 if (GTK_CMCTREE_ROW (node)->is_leaf) 3680 return; 3681 3682 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node); 3683 } 3684 3685 void 3686 gtk_cmctree_expand_recursive (GtkCMCTree *ctree, 3687 GtkCMCTreeNode *node) 3688 { 3689 GtkCMCList *clist; 3690 gboolean thaw = FALSE; 3691 3692 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3693 3694 clist = GTK_CMCLIST (ctree); 3695 3696 if (node && GTK_CMCTREE_ROW (node)->is_leaf) 3697 return; 3698 3699 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3700 { 3701 gtk_cmclist_freeze (clist); 3702 thaw = TRUE; 3703 } 3704 3705 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL); 3706 3707 if (thaw) 3708 gtk_cmclist_thaw (clist); 3709 } 3710 3711 void 3712 gtk_cmctree_expand_to_depth (GtkCMCTree *ctree, 3713 GtkCMCTreeNode *node, 3714 gint depth) 3715 { 3716 GtkCMCList *clist; 3717 gboolean thaw = FALSE; 3718 3719 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3720 3721 clist = GTK_CMCLIST (ctree); 3722 3723 if (node && GTK_CMCTREE_ROW (node)->is_leaf) 3724 return; 3725 3726 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3727 { 3728 gtk_cmclist_freeze (clist); 3729 thaw = TRUE; 3730 } 3731 3732 gtk_cmctree_post_recursive_to_depth (ctree, node, depth, 3733 GTK_CMCTREE_FUNC (tree_expand), NULL); 3734 3735 if (thaw) 3736 gtk_cmclist_thaw (clist); 3737 } 3738 3739 void 3740 gtk_cmctree_collapse (GtkCMCTree *ctree, 3741 GtkCMCTreeNode *node) 3742 { 3743 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3744 cm_return_if_fail (node != NULL); 3745 3746 if (GTK_CMCTREE_ROW (node)->is_leaf) 3747 return; 3748 3749 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node); 3750 } 3751 3752 void 3753 gtk_cmctree_collapse_recursive (GtkCMCTree *ctree, 3754 GtkCMCTreeNode *node) 3755 { 3756 GtkCMCList *clist; 3757 gboolean thaw = FALSE; 3758 gint i; 3759 3760 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3761 3762 if (node && GTK_CMCTREE_ROW (node)->is_leaf) 3763 return; 3764 3765 clist = GTK_CMCLIST (ctree); 3766 3767 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3768 { 3769 gtk_cmclist_freeze (clist); 3770 thaw = TRUE; 3771 } 3772 3773 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3774 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL); 3775 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3776 for (i = 0; i < clist->columns; i++) 3777 if (clist->column[i].auto_resize) 3778 gtk_cmclist_set_column_width (clist, i, 3779 gtk_cmclist_optimal_column_width (clist, i)); 3780 3781 if (thaw) 3782 gtk_cmclist_thaw (clist); 3783 } 3784 3785 void 3786 gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree, 3787 GtkCMCTreeNode *node, 3788 gint depth) 3789 { 3790 GtkCMCList *clist; 3791 gboolean thaw = FALSE; 3792 gint i; 3793 3794 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3795 3796 if (node && GTK_CMCTREE_ROW (node)->is_leaf) 3797 return; 3798 3799 clist = GTK_CMCLIST (ctree); 3800 3801 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3802 { 3803 gtk_cmclist_freeze (clist); 3804 thaw = TRUE; 3805 } 3806 3807 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3808 gtk_cmctree_post_recursive_to_depth (ctree, node, depth, 3809 GTK_CMCTREE_FUNC (tree_collapse_to_depth), 3810 GINT_TO_POINTER (depth)); 3811 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); 3812 for (i = 0; i < clist->columns; i++) 3813 if (clist->column[i].auto_resize) 3814 gtk_cmclist_set_column_width (clist, i, 3815 gtk_cmclist_optimal_column_width (clist, i)); 3816 3817 if (thaw) 3818 gtk_cmclist_thaw (clist); 3819 } 3820 3821 void 3822 gtk_cmctree_toggle_expansion (GtkCMCTree *ctree, 3823 GtkCMCTreeNode *node) 3824 { 3825 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3826 cm_return_if_fail (node != NULL); 3827 3828 if (GTK_CMCTREE_ROW (node)->is_leaf) 3829 return; 3830 3831 tree_toggle_expansion (ctree, node, NULL); 3832 } 3833 3834 void 3835 gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree, 3836 GtkCMCTreeNode *node) 3837 { 3838 GtkCMCList *clist; 3839 gboolean thaw = FALSE; 3840 3841 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3842 3843 if (node && GTK_CMCTREE_ROW (node)->is_leaf) 3844 return; 3845 3846 clist = GTK_CMCLIST (ctree); 3847 3848 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3849 { 3850 gtk_cmclist_freeze (clist); 3851 thaw = TRUE; 3852 } 3853 3854 gtk_cmctree_post_recursive (ctree, node, 3855 GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL); 3856 3857 if (thaw) 3858 gtk_cmclist_thaw (clist); 3859 } 3860 3861 void 3862 gtk_cmctree_select (GtkCMCTree *ctree, 3863 GtkCMCTreeNode *node) 3864 { 3865 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3866 cm_return_if_fail (node != NULL); 3867 3868 if (GTK_CMCTREE_ROW (node)->row.selectable) 3869 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0, 3870 node, -1); 3871 } 3872 3873 void 3874 gtk_cmctree_unselect (GtkCMCTree *ctree, 3875 GtkCMCTreeNode *node) 3876 { 3877 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3878 cm_return_if_fail (node != NULL); 3879 3880 g_signal_emit (G_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0, 3881 node, -1); 3882 } 3883 3884 void 3885 gtk_cmctree_select_recursive (GtkCMCTree *ctree, 3886 GtkCMCTreeNode *node) 3887 { 3888 gtk_cmctree_real_select_recursive (ctree, node, TRUE); 3889 } 3890 3891 void 3892 gtk_cmctree_unselect_recursive (GtkCMCTree *ctree, 3893 GtkCMCTreeNode *node) 3894 { 3895 gtk_cmctree_real_select_recursive (ctree, node, FALSE); 3896 } 3897 3898 void 3899 gtk_cmctree_real_select_recursive (GtkCMCTree *ctree, 3900 GtkCMCTreeNode *node, 3901 gint state) 3902 { 3903 GtkCMCList *clist; 3904 gboolean thaw = FALSE; 3905 3906 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3907 3908 clist = GTK_CMCLIST (ctree); 3909 3910 if ((state && 3911 (clist->selection_mode == GTK_SELECTION_BROWSE || 3912 clist->selection_mode == GTK_SELECTION_SINGLE)) || 3913 (!state && clist->selection_mode == GTK_SELECTION_BROWSE)) 3914 return; 3915 3916 if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) 3917 { 3918 gtk_cmclist_freeze (clist); 3919 thaw = TRUE; 3920 } 3921 3922 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) 3923 { 3924 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 3925 3926 g_list_free (clist->undo_selection); 3927 g_list_free (clist->undo_unselection); 3928 clist->undo_selection = NULL; 3929 clist->undo_unselection = NULL; 3930 } 3931 3932 if (state) 3933 gtk_cmctree_post_recursive (ctree, node, 3934 GTK_CMCTREE_FUNC (tree_select), NULL); 3935 else 3936 gtk_cmctree_post_recursive (ctree, node, 3937 GTK_CMCTREE_FUNC (tree_unselect), NULL); 3938 3939 if (thaw) 3940 gtk_cmclist_thaw (clist); 3941 } 3942 3943 3944 /*********************************************************** 3945 * Analogons of GtkCMCList functions * 3946 ***********************************************************/ 3947 3948 3949 void 3950 gtk_cmctree_node_set_text (GtkCMCTree *ctree, 3951 GtkCMCTreeNode *node, 3952 gint column, 3953 const gchar *text) 3954 { 3955 GtkCMCList *clist; 3956 3957 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3958 cm_return_if_fail (node != NULL); 3959 3960 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 3961 return; 3962 3963 clist = GTK_CMCLIST (ctree); 3964 3965 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 3966 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT, 3967 text, 0, NULL); 3968 3969 tree_draw_node (ctree, node); 3970 } 3971 3972 void 3973 gtk_cmctree_node_set_pixbuf (GtkCMCTree *ctree, 3974 GtkCMCTreeNode *node, 3975 gint column, 3976 GdkPixbuf *pixbuf) 3977 { 3978 GtkCMCList *clist; 3979 3980 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 3981 cm_return_if_fail (node != NULL); 3982 cm_return_if_fail (pixbuf != NULL); 3983 3984 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 3985 return; 3986 3987 g_object_ref (pixbuf); 3988 3989 clist = GTK_CMCLIST (ctree); 3990 3991 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 3992 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXBUF, 3993 NULL, 0, pixbuf); 3994 3995 tree_draw_node (ctree, node); 3996 } 3997 3998 void 3999 gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree, 4000 GtkCMCTreeNode *node, 4001 gint column, 4002 const gchar *text, 4003 guint8 spacing, 4004 GdkPixbuf *pixbuf) 4005 { 4006 GtkCMCList *clist; 4007 4008 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4009 cm_return_if_fail (node != NULL); 4010 if (column != ctree->tree_column) 4011 cm_return_if_fail (pixbuf != NULL); 4012 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4013 return; 4014 4015 clist = GTK_CMCLIST (ctree); 4016 4017 if (pixbuf) 4018 { 4019 g_object_ref (pixbuf); 4020 } 4021 4022 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 4023 (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT, 4024 text, spacing, pixbuf); 4025 4026 tree_draw_node (ctree, node); 4027 } 4028 4029 void 4030 gtk_cmctree_set_node_info (GtkCMCTree *ctree, 4031 GtkCMCTreeNode *node, 4032 const gchar *text, 4033 guint8 spacing, 4034 GdkPixbuf *pixbuf_closed, 4035 GdkPixbuf *pixbuf_opened, 4036 gboolean is_leaf, 4037 gboolean expanded) 4038 { 4039 gboolean old_leaf; 4040 gboolean old_expanded; 4041 4042 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4043 cm_return_if_fail (node != NULL); 4044 4045 old_leaf = GTK_CMCTREE_ROW (node)->is_leaf; 4046 old_expanded = GTK_CMCTREE_ROW (node)->expanded; 4047 4048 if (is_leaf && GTK_CMCTREE_ROW (node)->children) 4049 { 4050 GtkCMCTreeNode *work; 4051 GtkCMCTreeNode *ptr; 4052 4053 work = GTK_CMCTREE_ROW (node)->children; 4054 while (work) 4055 { 4056 ptr = work; 4057 work = GTK_CMCTREE_ROW (work)->sibling; 4058 gtk_cmctree_remove_node (ctree, ptr); 4059 } 4060 } 4061 4062 set_node_info (ctree, node, text, spacing, pixbuf_closed, 4063 pixbuf_opened, is_leaf, expanded); 4064 4065 if (!is_leaf && !old_leaf) 4066 { 4067 GTK_CMCTREE_ROW (node)->expanded = old_expanded; 4068 if (expanded && !old_expanded) 4069 gtk_cmctree_expand (ctree, node); 4070 else if (!expanded && old_expanded) 4071 gtk_cmctree_collapse (ctree, node); 4072 } 4073 4074 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; 4075 4076 tree_draw_node (ctree, node); 4077 } 4078 4079 void 4080 gtk_cmctree_node_set_shift (GtkCMCTree *ctree, 4081 GtkCMCTreeNode *node, 4082 gint column, 4083 gint vertical, 4084 gint horizontal) 4085 { 4086 GtkCMCList *clist; 4087 GtkRequisition requisition; 4088 gboolean visible = FALSE; 4089 4090 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4091 cm_return_if_fail (node != NULL); 4092 4093 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4094 return; 4095 4096 clist = GTK_CMCLIST (ctree); 4097 4098 if (clist->column[column].auto_resize && 4099 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4100 { 4101 visible = gtk_cmctree_is_viewable (ctree, node); 4102 if (visible) 4103 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 4104 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition); 4105 } 4106 4107 GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical; 4108 GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal; 4109 4110 if (visible) 4111 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, 4112 column, requisition.width); 4113 4114 tree_draw_node (ctree, node); 4115 } 4116 4117 static void 4118 remove_grab (GtkCMCList *clist) 4119 { 4120 if (gtkut_pointer_is_grabbed (GTK_WIDGET (clist)) && 4121 gtk_widget_has_grab (GTK_WIDGET(clist))) 4122 { 4123 gtk_grab_remove (GTK_WIDGET (clist)); 4124 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)), 4125 GDK_CURRENT_TIME); 4126 } 4127 4128 if (clist->htimer) 4129 { 4130 g_source_remove (clist->htimer); 4131 clist->htimer = 0; 4132 } 4133 4134 if (clist->vtimer) 4135 { 4136 g_source_remove (clist->vtimer); 4137 clist->vtimer = 0; 4138 } 4139 } 4140 4141 void 4142 gtk_cmctree_node_set_selectable (GtkCMCTree *ctree, 4143 GtkCMCTreeNode *node, 4144 gboolean selectable) 4145 { 4146 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4147 cm_return_if_fail (node != NULL); 4148 4149 if (selectable == GTK_CMCTREE_ROW (node)->row.selectable) 4150 return; 4151 4152 GTK_CMCTREE_ROW (node)->row.selectable = selectable; 4153 4154 if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) 4155 { 4156 GtkCMCList *clist; 4157 4158 clist = GTK_CMCLIST (ctree); 4159 4160 if (clist->anchor >= 0 && 4161 clist->selection_mode == GTK_SELECTION_MULTIPLE) 4162 { 4163 clist->drag_button = 0; 4164 remove_grab (clist); 4165 4166 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 4167 } 4168 gtk_cmctree_unselect (ctree, node); 4169 } 4170 } 4171 4172 gboolean 4173 gtk_cmctree_node_get_selectable (GtkCMCTree *ctree, 4174 GtkCMCTreeNode *node) 4175 { 4176 cm_return_val_if_fail (node != NULL, FALSE); 4177 4178 return GTK_CMCTREE_ROW (node)->row.selectable; 4179 } 4180 4181 GtkCMCellType 4182 gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree, 4183 GtkCMCTreeNode *node, 4184 gint column) 4185 { 4186 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1); 4187 cm_return_val_if_fail (node != NULL, -1); 4188 4189 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4190 return -1; 4191 4192 return GTK_CMCTREE_ROW (node)->row.cell[column].type; 4193 } 4194 4195 gboolean 4196 gtk_cmctree_node_get_text (GtkCMCTree *ctree, 4197 GtkCMCTreeNode *node, 4198 gint column, 4199 gchar **text) 4200 { 4201 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 4202 cm_return_val_if_fail (node != NULL, FALSE); 4203 4204 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4205 return FALSE; 4206 4207 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT) 4208 return FALSE; 4209 4210 if (text) 4211 *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text; 4212 4213 return TRUE; 4214 } 4215 4216 gboolean 4217 gtk_cmctree_node_get_pixbuf (GtkCMCTree *ctree, 4218 GtkCMCTreeNode *node, 4219 gint column, 4220 GdkPixbuf **pixbuf) 4221 { 4222 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 4223 cm_return_val_if_fail (node != NULL, FALSE); 4224 4225 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4226 return FALSE; 4227 4228 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXBUF) 4229 return FALSE; 4230 4231 if (pixbuf) 4232 *pixbuf = GTK_CMCELL_PIXBUF (GTK_CMCTREE_ROW (node)->row.cell[column])->pixbuf; 4233 4234 return TRUE; 4235 } 4236 4237 gboolean 4238 gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree, 4239 GtkCMCTreeNode *node, 4240 gint column, 4241 gchar **text, 4242 guint8 *spacing, 4243 GdkPixbuf **pixbuf) 4244 { 4245 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 4246 cm_return_val_if_fail (node != NULL, FALSE); 4247 4248 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4249 return FALSE; 4250 4251 if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT) 4252 return FALSE; 4253 4254 if (text) 4255 *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text; 4256 if (spacing) 4257 *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW 4258 (node)->row.cell[column])->spacing; 4259 if (pixbuf) 4260 *pixbuf = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW 4261 (node)->row.cell[column])->pixbuf; 4262 4263 return TRUE; 4264 } 4265 4266 gboolean 4267 gtk_cmctree_get_node_info (GtkCMCTree *ctree, 4268 GtkCMCTreeNode *node, 4269 gchar **text, 4270 guint8 *spacing, 4271 GdkPixbuf **pixbuf_closed, 4272 GdkPixbuf **pixbuf_opened, 4273 gboolean *is_leaf, 4274 gboolean *expanded) 4275 { 4276 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 4277 cm_return_val_if_fail (node != NULL, FALSE); 4278 4279 if (text) 4280 *text = GTK_CMCELL_PIXTEXT 4281 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text; 4282 if (spacing) 4283 *spacing = GTK_CMCELL_PIXTEXT 4284 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing; 4285 if (pixbuf_closed) 4286 *pixbuf_closed = GTK_CMCTREE_ROW (node)->pixbuf_closed; 4287 if (pixbuf_opened) 4288 *pixbuf_opened = GTK_CMCTREE_ROW (node)->pixbuf_opened; 4289 if (is_leaf) 4290 *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf; 4291 if (expanded) 4292 *expanded = GTK_CMCTREE_ROW (node)->expanded; 4293 4294 return TRUE; 4295 } 4296 4297 void 4298 gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree, 4299 GtkCMCTreeNode *node, 4300 gint column, 4301 GtkStyle *style) 4302 { 4303 GtkCMCList *clist; 4304 GtkRequisition requisition; 4305 gboolean visible = FALSE; 4306 4307 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4308 cm_return_if_fail (node != NULL); 4309 4310 clist = GTK_CMCLIST (ctree); 4311 4312 if (column < 0 || column >= clist->columns) 4313 return; 4314 4315 if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style) 4316 return; 4317 4318 if (clist->column[column].auto_resize && 4319 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4320 { 4321 visible = gtk_cmctree_is_viewable (ctree, node); 4322 if (visible) 4323 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 4324 (clist, >K_CMCTREE_ROW (node)->row, column, &requisition); 4325 } 4326 4327 if (GTK_CMCTREE_ROW (node)->row.cell[column].style) 4328 { 4329 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 4330 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style); 4331 g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style); 4332 } 4333 4334 GTK_CMCTREE_ROW (node)->row.cell[column].style = style; 4335 4336 if (GTK_CMCTREE_ROW (node)->row.cell[column].style) 4337 { 4338 g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style); 4339 4340 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 4341 GTK_CMCTREE_ROW (node)->row.cell[column].style = 4342 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style, 4343 clist->clist_window); 4344 } 4345 4346 if (visible) 4347 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, column, 4348 requisition.width); 4349 4350 tree_draw_node (ctree, node); 4351 } 4352 4353 GtkStyle * 4354 gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree, 4355 GtkCMCTreeNode *node, 4356 gint column) 4357 { 4358 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 4359 cm_return_val_if_fail (node != NULL, NULL); 4360 4361 if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) 4362 return NULL; 4363 4364 return GTK_CMCTREE_ROW (node)->row.cell[column].style; 4365 } 4366 4367 void 4368 gtk_cmctree_node_set_row_style (GtkCMCTree *ctree, 4369 GtkCMCTreeNode *node, 4370 GtkStyle *style) 4371 { 4372 GtkCMCList *clist; 4373 GtkRequisition requisition; 4374 gboolean visible; 4375 gint *old_width = NULL; 4376 gint i; 4377 4378 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4379 cm_return_if_fail (node != NULL); 4380 4381 clist = GTK_CMCLIST (ctree); 4382 4383 if (GTK_CMCTREE_ROW (node)->row.style == style) 4384 return; 4385 4386 visible = gtk_cmctree_is_viewable (ctree, node); 4387 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4388 { 4389 old_width = g_new (gint, clist->columns); 4390 for (i = 0; i < clist->columns; i++) 4391 if (clist->column[i].auto_resize) 4392 { 4393 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 4394 (clist, >K_CMCTREE_ROW (node)->row, i, &requisition); 4395 old_width[i] = requisition.width; 4396 } 4397 } 4398 4399 if (GTK_CMCTREE_ROW (node)->row.style) 4400 { 4401 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 4402 gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style); 4403 g_object_unref (GTK_CMCTREE_ROW (node)->row.style); 4404 } 4405 4406 GTK_CMCTREE_ROW (node)->row.style = style; 4407 4408 if (GTK_CMCTREE_ROW (node)->row.style) 4409 { 4410 g_object_ref (GTK_CMCTREE_ROW (node)->row.style); 4411 4412 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 4413 GTK_CMCTREE_ROW (node)->row.style = 4414 gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, 4415 clist->clist_window); 4416 } 4417 4418 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4419 { 4420 for (i = 0; i < clist->columns; i++) 4421 if (clist->column[i].auto_resize) 4422 column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, i, 4423 old_width[i]); 4424 g_free (old_width); 4425 } 4426 tree_draw_node (ctree, node); 4427 } 4428 4429 GtkStyle * 4430 gtk_cmctree_node_get_row_style (GtkCMCTree *ctree, 4431 GtkCMCTreeNode *node) 4432 { 4433 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 4434 cm_return_val_if_fail (node != NULL, NULL); 4435 4436 return GTK_CMCTREE_ROW (node)->row.style; 4437 } 4438 4439 void 4440 gtk_cmctree_node_set_foreground (GtkCMCTree *ctree, 4441 GtkCMCTreeNode *node, 4442 const GdkRGBA *color) 4443 { 4444 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4445 cm_return_if_fail (node != NULL); 4446 4447 if (color) 4448 { 4449 GdkColor gdk_color; 4450 4451 GTKUT_GDKRGBA_TO_GDKCOLOR((*color), gdk_color); 4452 GTK_CMCTREE_ROW (node)->row.foreground = gdk_color; 4453 GTK_CMCTREE_ROW (node)->row.fg_set = TRUE; 4454 } 4455 else 4456 GTK_CMCTREE_ROW (node)->row.fg_set = FALSE; 4457 4458 tree_draw_node (ctree, node); 4459 } 4460 4461 void 4462 gtk_cmctree_node_set_background (GtkCMCTree *ctree, 4463 GtkCMCTreeNode *node, 4464 const GdkRGBA *color) 4465 { 4466 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4467 cm_return_if_fail (node != NULL); 4468 4469 if (color) 4470 { 4471 GdkColor gdk_color; 4472 4473 GTKUT_GDKRGBA_TO_GDKCOLOR((*color), gdk_color); 4474 GTK_CMCTREE_ROW (node)->row.background = gdk_color; 4475 GTK_CMCTREE_ROW (node)->row.bg_set = TRUE; 4476 } 4477 else 4478 GTK_CMCTREE_ROW (node)->row.bg_set = FALSE; 4479 4480 tree_draw_node (ctree, node); 4481 } 4482 4483 void 4484 gtk_cmctree_node_set_row_data (GtkCMCTree *ctree, 4485 GtkCMCTreeNode *node, 4486 gpointer data) 4487 { 4488 gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL); 4489 } 4490 4491 void 4492 gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree, 4493 GtkCMCTreeNode *node, 4494 gpointer data, 4495 GDestroyNotify destroy) 4496 { 4497 GDestroyNotify dnotify; 4498 gpointer ddata; 4499 4500 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4501 cm_return_if_fail (node != NULL); 4502 4503 dnotify = GTK_CMCTREE_ROW (node)->row.destroy; 4504 ddata = GTK_CMCTREE_ROW (node)->row.data; 4505 4506 GTK_CMCTREE_ROW (node)->row.data = data; 4507 GTK_CMCTREE_ROW (node)->row.destroy = destroy; 4508 4509 if (dnotify) 4510 dnotify (ddata); 4511 } 4512 4513 gpointer 4514 gtk_cmctree_node_get_row_data (GtkCMCTree *ctree, 4515 GtkCMCTreeNode *node) 4516 { 4517 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 4518 4519 return node ? GTK_CMCTREE_ROW (node)->row.data : NULL; 4520 } 4521 4522 void 4523 gtk_cmctree_node_moveto (GtkCMCTree *ctree, 4524 GtkCMCTreeNode *node, 4525 gint column, 4526 gfloat row_align, 4527 gfloat col_align) 4528 { 4529 gint row = -1; 4530 GtkCMCList *clist; 4531 4532 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4533 4534 clist = GTK_CMCLIST (ctree); 4535 4536 while (node && !gtk_cmctree_is_viewable (ctree, node)) 4537 node = GTK_CMCTREE_ROW (node)->parent; 4538 4539 if (node) 4540 row = g_list_position (clist->row_list, (GList *)node); 4541 4542 gtk_cmclist_moveto (clist, row, column, row_align, col_align); 4543 } 4544 4545 GtkVisibility 4546 gtk_cmctree_node_is_visible (GtkCMCTree *ctree, 4547 GtkCMCTreeNode *node) 4548 { 4549 gint row; 4550 4551 cm_return_val_if_fail (ctree != NULL, 0); 4552 cm_return_val_if_fail (node != NULL, 0); 4553 4554 row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node); 4555 return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row); 4556 } 4557 4558 4559 /*********************************************************** 4560 * GtkCMCTree specific functions * 4561 ***********************************************************/ 4562 4563 void 4564 gtk_cmctree_set_indent (GtkCMCTree *ctree, 4565 gint indent) 4566 { 4567 GtkCMCList *clist; 4568 4569 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4570 cm_return_if_fail (indent >= 0); 4571 4572 if (indent == ctree->tree_indent) 4573 return; 4574 4575 clist = GTK_CMCLIST (ctree); 4576 ctree->tree_indent = indent; 4577 4578 if (clist->column[ctree->tree_column].auto_resize && 4579 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4580 gtk_cmclist_set_column_width 4581 (clist, ctree->tree_column, 4582 gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); 4583 else 4584 CLIST_REFRESH (ctree); 4585 } 4586 4587 void 4588 gtk_cmctree_set_spacing (GtkCMCTree *ctree, 4589 gint spacing) 4590 { 4591 GtkCMCList *clist; 4592 gint old_spacing; 4593 4594 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4595 cm_return_if_fail (spacing >= 0); 4596 4597 if (spacing == ctree->tree_spacing) 4598 return; 4599 4600 clist = GTK_CMCLIST (ctree); 4601 4602 old_spacing = ctree->tree_spacing; 4603 ctree->tree_spacing = spacing; 4604 4605 if (clist->column[ctree->tree_column].auto_resize && 4606 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4607 gtk_cmclist_set_column_width (clist, ctree->tree_column, 4608 clist->column[ctree->tree_column].width + 4609 spacing - old_spacing); 4610 else 4611 CLIST_REFRESH (ctree); 4612 } 4613 4614 void 4615 gtk_cmctree_set_show_stub (GtkCMCTree *ctree, 4616 gboolean show_stub) 4617 { 4618 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4619 4620 show_stub = show_stub != FALSE; 4621 4622 if (show_stub != ctree->show_stub) 4623 { 4624 GtkCMCList *clist; 4625 4626 clist = GTK_CMCLIST (ctree); 4627 ctree->show_stub = show_stub; 4628 4629 if (CLIST_UNFROZEN (clist) && clist->rows && 4630 gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE) 4631 GTK_CMCLIST_GET_CLASS (clist)->draw_row 4632 (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list)); 4633 } 4634 } 4635 4636 void 4637 gtk_cmctree_set_line_style (GtkCMCTree *ctree, 4638 GtkCMCTreeLineStyle line_style) 4639 { 4640 } 4641 4642 void 4643 gtk_cmctree_set_expander_style (GtkCMCTree *ctree, 4644 GtkCMCTreeExpanderStyle expander_style) 4645 { 4646 GtkCMCList *clist; 4647 GtkCMCTreeExpanderStyle old_style; 4648 4649 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4650 4651 if (expander_style == ctree->expander_style) 4652 return; 4653 4654 clist = GTK_CMCLIST (ctree); 4655 4656 old_style = ctree->expander_style; 4657 ctree->expander_style = expander_style; 4658 4659 if (clist->column[ctree->tree_column].auto_resize && 4660 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 4661 { 4662 gint new_width; 4663 4664 new_width = clist->column[ctree->tree_column].width; 4665 switch (old_style) 4666 { 4667 case GTK_CMCTREE_EXPANDER_NONE: 4668 break; 4669 case GTK_CMCTREE_EXPANDER_TRIANGLE: 4670 new_width -= PM_SIZE + 3; 4671 break; 4672 } 4673 4674 switch (expander_style) 4675 { 4676 case GTK_CMCTREE_EXPANDER_NONE: 4677 break; 4678 case GTK_CMCTREE_EXPANDER_TRIANGLE: 4679 new_width += PM_SIZE + 3; 4680 break; 4681 } 4682 4683 gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width); 4684 } 4685 4686 if (gtk_widget_is_drawable (GTK_WIDGET(clist))) 4687 CLIST_REFRESH (clist); 4688 } 4689 4690 4691 /*********************************************************** 4692 * Tree sorting functions * 4693 ***********************************************************/ 4694 4695 4696 static void 4697 tree_sort (GtkCMCTree *ctree, 4698 GtkCMCTreeNode *node, 4699 gpointer data) 4700 { 4701 GtkCMCTreeNode *list_start; 4702 GtkCMCTreeNode *cmp; 4703 GtkCMCTreeNode *work; 4704 GtkCMCList *clist; 4705 4706 clist = GTK_CMCLIST (ctree); 4707 4708 if (node) 4709 list_start = GTK_CMCTREE_ROW (node)->children; 4710 else 4711 list_start = GTK_CMCTREE_NODE (clist->row_list); 4712 4713 while (list_start) 4714 { 4715 cmp = list_start; 4716 work = GTK_CMCTREE_ROW (cmp)->sibling; 4717 while (work) 4718 { 4719 if (clist->sort_type == GTK_SORT_ASCENDING) 4720 { 4721 if (clist->compare 4722 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0) 4723 cmp = work; 4724 } 4725 else 4726 { 4727 if (clist->compare 4728 (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0) 4729 cmp = work; 4730 } 4731 work = GTK_CMCTREE_ROW (work)->sibling; 4732 } 4733 if (cmp == list_start) 4734 list_start = GTK_CMCTREE_ROW (cmp)->sibling; 4735 else 4736 { 4737 gtk_cmctree_unlink (ctree, cmp, FALSE); 4738 gtk_cmctree_link (ctree, cmp, node, list_start, FALSE); 4739 } 4740 } 4741 } 4742 4743 void 4744 gtk_cmctree_sort_recursive (GtkCMCTree *ctree, 4745 GtkCMCTreeNode *node) 4746 { 4747 GtkCMCList *clist; 4748 GtkCMCTreeNode *focus_node = NULL; 4749 4750 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4751 4752 clist = GTK_CMCLIST (ctree); 4753 4754 gtk_cmclist_freeze (clist); 4755 4756 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) 4757 { 4758 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 4759 4760 g_list_free (clist->undo_selection); 4761 g_list_free (clist->undo_unselection); 4762 clist->undo_selection = NULL; 4763 clist->undo_unselection = NULL; 4764 } 4765 4766 if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) 4767 focus_node = 4768 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); 4769 4770 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL); 4771 4772 if (!node) 4773 tree_sort (ctree, NULL, NULL); 4774 4775 if (focus_node) 4776 { 4777 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); 4778 clist->undo_anchor = clist->focus_row; 4779 } 4780 4781 gtk_cmclist_thaw (clist); 4782 } 4783 4784 static void 4785 real_sort_list (GtkCMCList *clist) 4786 { 4787 gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL); 4788 } 4789 4790 void 4791 gtk_cmctree_sort_node (GtkCMCTree *ctree, 4792 GtkCMCTreeNode *node) 4793 { 4794 GtkCMCList *clist; 4795 GtkCMCTreeNode *focus_node = NULL; 4796 4797 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 4798 4799 clist = GTK_CMCLIST (ctree); 4800 4801 gtk_cmclist_freeze (clist); 4802 4803 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) 4804 { 4805 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 4806 4807 g_list_free (clist->undo_selection); 4808 g_list_free (clist->undo_unselection); 4809 clist->undo_selection = NULL; 4810 clist->undo_unselection = NULL; 4811 } 4812 4813 if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) 4814 focus_node = GTK_CMCTREE_NODE 4815 (g_list_nth (clist->row_list, clist->focus_row)); 4816 4817 tree_sort (ctree, node, NULL); 4818 4819 if (focus_node) 4820 { 4821 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); 4822 clist->undo_anchor = clist->focus_row; 4823 } 4824 4825 gtk_cmclist_thaw (clist); 4826 } 4827 4828 /************************************************************************/ 4829 4830 static void 4831 fake_unselect_all (GtkCMCList *clist, 4832 gint row) 4833 { 4834 GList *list; 4835 GList *focus_node = NULL; 4836 4837 if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row))) 4838 { 4839 if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL && 4840 GTK_CMCTREE_ROW (focus_node)->row.selectable) 4841 { 4842 GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED; 4843 4844 if (CLIST_UNFROZEN (clist) && 4845 gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) 4846 GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, 4847 GTK_CMCLIST_ROW (focus_node)); 4848 } 4849 } 4850 4851 clist->undo_selection = clist->selection; 4852 clist->selection = NULL; 4853 clist->selection_end = NULL; 4854 4855 for (list = clist->undo_selection; list; list = list->next) 4856 { 4857 if (list->data == focus_node) 4858 continue; 4859 4860 GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL; 4861 tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data)); 4862 } 4863 } 4864 4865 static GList * 4866 selection_find (GtkCMCList *clist, 4867 gint row_number, 4868 GList *row_list_element) 4869 { 4870 return g_list_find (clist->selection, row_list_element); 4871 } 4872 4873 static void 4874 resync_selection (GtkCMCList *clist, GdkEvent *event) 4875 { 4876 GtkCMCTree *ctree; 4877 GList *list; 4878 GtkCMCTreeNode *node; 4879 gint i; 4880 gint e; 4881 gint row; 4882 gboolean unselect; 4883 4884 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 4885 4886 if (clist->selection_mode != GTK_SELECTION_MULTIPLE) 4887 return; 4888 4889 if (clist->anchor < 0 || clist->drag_pos < 0) 4890 return; 4891 4892 ctree = GTK_CMCTREE (clist); 4893 4894 clist->freeze_count++; 4895 4896 i = MIN (clist->anchor, clist->drag_pos); 4897 e = MAX (clist->anchor, clist->drag_pos); 4898 4899 if (clist->undo_selection) 4900 { 4901 list = clist->selection; 4902 clist->selection = clist->undo_selection; 4903 clist->selection_end = g_list_last (clist->selection); 4904 clist->undo_selection = list; 4905 list = clist->selection; 4906 4907 while (list) 4908 { 4909 node = list->data; 4910 list = list->next; 4911 4912 unselect = TRUE; 4913 4914 if (gtk_cmctree_is_viewable (ctree, node)) 4915 { 4916 row = g_list_position (clist->row_list, (GList *)node); 4917 if (row >= i && row <= e) 4918 unselect = FALSE; 4919 } 4920 if (unselect && GTK_CMCTREE_ROW (node)->row.selectable) 4921 { 4922 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; 4923 gtk_cmctree_unselect (ctree, node); 4924 clist->undo_selection = g_list_prepend (clist->undo_selection, 4925 node); 4926 } 4927 } 4928 } 4929 4930 if (clist->anchor < clist->drag_pos) 4931 { 4932 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e; 4933 i++, node = GTK_CMCTREE_NODE_NEXT (node)) 4934 if (GTK_CMCTREE_ROW (node)->row.selectable) 4935 { 4936 if (g_list_find (clist->selection, node)) 4937 { 4938 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL) 4939 { 4940 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; 4941 gtk_cmctree_unselect (ctree, node); 4942 clist->undo_selection = 4943 g_list_prepend (clist->undo_selection, node); 4944 } 4945 } 4946 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) 4947 { 4948 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; 4949 clist->undo_unselection = 4950 g_list_prepend (clist->undo_unselection, node); 4951 } 4952 } 4953 } 4954 else 4955 { 4956 for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e; 4957 e--, node = GTK_CMCTREE_NODE_PREV (node)) 4958 if (GTK_CMCTREE_ROW (node)->row.selectable) 4959 { 4960 if (g_list_find (clist->selection, node)) 4961 { 4962 if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL) 4963 { 4964 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; 4965 gtk_cmctree_unselect (ctree, node); 4966 clist->undo_selection = 4967 g_list_prepend (clist->undo_selection, node); 4968 } 4969 } 4970 else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) 4971 { 4972 GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; 4973 clist->undo_unselection = 4974 g_list_prepend (clist->undo_unselection, node); 4975 } 4976 } 4977 } 4978 4979 clist->undo_unselection = g_list_reverse (clist->undo_unselection); 4980 for (list = clist->undo_unselection; list; list = list->next) 4981 gtk_cmctree_select (ctree, list->data); 4982 4983 clist->anchor = -1; 4984 clist->drag_pos = -1; 4985 4986 if (!CLIST_UNFROZEN (clist)) 4987 clist->freeze_count--; 4988 } 4989 4990 static void 4991 real_undo_selection (GtkCMCList *clist) 4992 { 4993 GtkCMCTree *ctree; 4994 GList *work; 4995 4996 cm_return_if_fail (GTK_IS_CMCTREE (clist)); 4997 4998 if (clist->selection_mode != GTK_SELECTION_MULTIPLE) 4999 return; 5000 5001 if (!(clist->undo_selection || clist->undo_unselection)) 5002 { 5003 gtk_cmclist_unselect_all (clist); 5004 return; 5005 } 5006 5007 ctree = GTK_CMCTREE (clist); 5008 5009 for (work = clist->undo_selection; work; work = work->next) 5010 if (GTK_CMCTREE_ROW (work->data)->row.selectable) 5011 gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data)); 5012 5013 for (work = clist->undo_unselection; work; work = work->next) 5014 if (GTK_CMCTREE_ROW (work->data)->row.selectable) 5015 gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data)); 5016 5017 if (gtk_widget_has_focus (GTK_WIDGET(clist)) && 5018 clist->focus_row != clist->undo_anchor) 5019 { 5020 clist->focus_row = clist->undo_anchor; 5021 gtk_widget_queue_draw (GTK_WIDGET (clist)); 5022 } 5023 else 5024 clist->focus_row = clist->undo_anchor; 5025 5026 clist->undo_anchor = -1; 5027 5028 g_list_free (clist->undo_selection); 5029 g_list_free (clist->undo_unselection); 5030 clist->undo_selection = NULL; 5031 clist->undo_unselection = NULL; 5032 5033 if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > 5034 clist->clist_window_height) 5035 gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); 5036 else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) 5037 gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); 5038 5039 } 5040 5041 void 5042 gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree, 5043 GtkCMCTreeCompareDragFunc cmp_func) 5044 { 5045 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 5046 5047 ctree->drag_compare = cmp_func; 5048 } 5049 5050 static gboolean 5051 check_drag (GtkCMCTree *ctree, 5052 GtkCMCTreeNode *drag_source, 5053 GtkCMCTreeNode *drag_target, 5054 GtkCMCListDragPos insert_pos) 5055 { 5056 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); 5057 5058 if (drag_source && drag_source != drag_target && 5059 (!GTK_CMCTREE_ROW (drag_source)->children || 5060 !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target))) 5061 { 5062 switch (insert_pos) 5063 { 5064 case GTK_CMCLIST_DRAG_NONE: 5065 return FALSE; 5066 case GTK_CMCLIST_DRAG_AFTER: 5067 if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source) 5068 return (!ctree->drag_compare || 5069 ctree->drag_compare (ctree, 5070 drag_source, 5071 GTK_CMCTREE_ROW (drag_target)->parent, 5072 GTK_CMCTREE_ROW (drag_target)->sibling)); 5073 break; 5074 case GTK_CMCLIST_DRAG_BEFORE: 5075 if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target) 5076 return (!ctree->drag_compare || 5077 ctree->drag_compare (ctree, 5078 drag_source, 5079 GTK_CMCTREE_ROW (drag_target)->parent, 5080 drag_target)); 5081 break; 5082 case GTK_CMCLIST_DRAG_INTO: 5083 if (!GTK_CMCTREE_ROW (drag_target)->is_leaf && 5084 GTK_CMCTREE_ROW (drag_target)->children != drag_source) 5085 return (!ctree->drag_compare || 5086 ctree->drag_compare (ctree, 5087 drag_source, 5088 drag_target, 5089 GTK_CMCTREE_ROW (drag_target)->children)); 5090 break; 5091 } 5092 } 5093 return FALSE; 5094 } 5095 5096 5097 5098 /************************************/ 5099 static void 5100 drag_dest_info_destroy (gpointer data) 5101 { 5102 GtkCMCListDestInfo *info = data; 5103 5104 g_free (info); 5105 } 5106 5107 static void 5108 drag_dest_cell (GtkCMCList *clist, 5109 gint x, 5110 gint y, 5111 GtkCMCListDestInfo *dest_info) 5112 { 5113 GtkStyle *style; 5114 GtkWidget *widget; 5115 guint border_width; 5116 5117 widget = GTK_WIDGET (clist); 5118 style = gtk_widget_get_style (widget); 5119 5120 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; 5121 5122 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); 5123 y -= (border_width + 5124 style->ythickness + clist->column_title_area.height); 5125 dest_info->cell.row = ROW_FROM_YPIXEL (clist, y); 5126 5127 if (dest_info->cell.row >= clist->rows) 5128 { 5129 dest_info->cell.row = clist->rows - 1; 5130 y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height; 5131 } 5132 if (dest_info->cell.row < -1) 5133 dest_info->cell.row = -1; 5134 5135 x -= border_width + style->xthickness; 5136 5137 dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x); 5138 5139 if (dest_info->cell.row >= 0) 5140 { 5141 gint y_delta; 5142 gint h = 0; 5143 5144 y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row); 5145 5146 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) && 5147 !GTK_CMCTREE_ROW (g_list_nth (clist->row_list, 5148 dest_info->cell.row))->is_leaf) 5149 { 5150 dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO; 5151 h = clist->row_height / 4; 5152 } 5153 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) 5154 { 5155 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; 5156 h = clist->row_height / 2; 5157 } 5158 5159 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) 5160 { 5161 if (y_delta < h) 5162 dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; 5163 else if (clist->row_height - y_delta < h) 5164 dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER; 5165 } 5166 } 5167 } 5168 5169 static void 5170 gtk_cmctree_drag_begin (GtkWidget *widget, 5171 GdkDragContext *context) 5172 { 5173 GtkCMCList *clist; 5174 gboolean use_icons; 5175 5176 cm_return_if_fail (GTK_IS_CMCTREE (widget)); 5177 cm_return_if_fail (context != NULL); 5178 5179 clist = GTK_CMCLIST (widget); 5180 5181 use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist); 5182 GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); 5183 GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context); 5184 5185 if (use_icons) 5186 { 5187 GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); 5188 gtk_drag_set_icon_default (context); 5189 } 5190 } 5191 5192 static gint 5193 gtk_cmctree_drag_motion (GtkWidget *widget, 5194 GdkDragContext *context, 5195 gint x, 5196 gint y, 5197 guint time) 5198 { 5199 GtkCMCList *clist; 5200 GtkCMCTree *ctree; 5201 GtkCMCListDestInfo new_info; 5202 GtkCMCListDestInfo *dest_info; 5203 5204 cm_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE); 5205 5206 clist = GTK_CMCLIST (widget); 5207 ctree = GTK_CMCTREE (widget); 5208 5209 dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); 5210 5211 if (!dest_info) 5212 { 5213 dest_info = g_new (GtkCMCListDestInfo, 1); 5214 5215 dest_info->cell.row = -1; 5216 dest_info->cell.column = -1; 5217 dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; 5218 5219 g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info, 5220 drag_dest_info_destroy); 5221 } 5222 5223 drag_dest_cell (clist, x, y, &new_info); 5224 5225 if (GTK_CMCLIST_REORDERABLE (clist)) 5226 { 5227 GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder"); 5228 GdkAtom found = gtk_drag_dest_find_target(widget, context, NULL); 5229 5230 if (atom == found) 5231 { 5232 GtkCMCTreeNode *drag_source; 5233 GtkCMCTreeNode *drag_target; 5234 5235 drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, 5236 clist->click_cell.row)); 5237 drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, 5238 new_info.cell.row)); 5239 5240 if (gtk_drag_get_source_widget (context) != widget || 5241 !check_drag (ctree, drag_source, drag_target, 5242 new_info.insert_pos)) 5243 { 5244 if (dest_info->cell.row < 0) 5245 { 5246 gdk_drag_status (context, GDK_ACTION_DEFAULT, time); 5247 return FALSE; 5248 } 5249 return TRUE; 5250 } 5251 5252 if (new_info.cell.row != dest_info->cell.row || 5253 (new_info.cell.row == dest_info->cell.row && 5254 dest_info->insert_pos != new_info.insert_pos)) 5255 { 5256 dest_info->insert_pos = new_info.insert_pos; 5257 dest_info->cell.row = new_info.cell.row; 5258 dest_info->cell.column = new_info.cell.column; 5259 5260 clist->drag_highlight_row = dest_info->cell.row; 5261 clist->drag_highlight_pos = dest_info->insert_pos; 5262 5263 gdk_drag_status (context, 5264 gdk_drag_context_get_suggested_action(context), time); 5265 } 5266 return TRUE; 5267 } 5268 } 5269 5270 dest_info->insert_pos = new_info.insert_pos; 5271 dest_info->cell.row = new_info.cell.row; 5272 dest_info->cell.column = new_info.cell.column; 5273 return TRUE; 5274 } 5275 5276 static void 5277 gtk_cmctree_drag_data_received (GtkWidget *widget, 5278 GdkDragContext *context, 5279 gint x, 5280 gint y, 5281 GtkSelectionData *selection_data, 5282 guint info, 5283 guint32 time) 5284 { 5285 GtkCMCTree *ctree; 5286 GtkCMCList *clist; 5287 5288 cm_return_if_fail (GTK_IS_CMCTREE (widget)); 5289 cm_return_if_fail (context != NULL); 5290 cm_return_if_fail (selection_data != NULL); 5291 5292 ctree = GTK_CMCTREE (widget); 5293 clist = GTK_CMCLIST (widget); 5294 5295 if (GTK_CMCLIST_REORDERABLE (clist) && 5296 gtk_drag_get_source_widget (context) == widget && 5297 gtk_selection_data_get_target (selection_data) == 5298 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") && 5299 gtk_selection_data_get_format (selection_data) == 8 && 5300 gtk_selection_data_get_length (selection_data) == sizeof (GtkCMCListCellInfo)) 5301 { 5302 GtkCMCListCellInfo *source_info; 5303 5304 source_info = (GtkCMCListCellInfo *)(gtk_selection_data_get_data (selection_data)); 5305 if (source_info) 5306 { 5307 GtkCMCListDestInfo dest_info; 5308 GtkCMCTreeNode *source_node; 5309 GtkCMCTreeNode *dest_node; 5310 5311 drag_dest_cell (clist, x, y, &dest_info); 5312 5313 source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, 5314 source_info->row)); 5315 dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, 5316 dest_info.cell.row)); 5317 5318 if (!source_node || !dest_node) 5319 return; 5320 5321 switch (dest_info.insert_pos) 5322 { 5323 case GTK_CMCLIST_DRAG_NONE: 5324 break; 5325 case GTK_CMCLIST_DRAG_INTO: 5326 if (check_drag (ctree, source_node, dest_node, 5327 dest_info.insert_pos)) 5328 gtk_cmctree_move (ctree, source_node, dest_node, 5329 GTK_CMCTREE_ROW (dest_node)->children); 5330 g_dataset_remove_data (context, "gtk-clist-drag-dest"); 5331 break; 5332 case GTK_CMCLIST_DRAG_BEFORE: 5333 if (check_drag (ctree, source_node, dest_node, 5334 dest_info.insert_pos)) 5335 gtk_cmctree_move (ctree, source_node, 5336 GTK_CMCTREE_ROW (dest_node)->parent, dest_node); 5337 g_dataset_remove_data (context, "gtk-clist-drag-dest"); 5338 break; 5339 case GTK_CMCLIST_DRAG_AFTER: 5340 if (check_drag (ctree, source_node, dest_node, 5341 dest_info.insert_pos)) 5342 gtk_cmctree_move (ctree, source_node, 5343 GTK_CMCTREE_ROW (dest_node)->parent, 5344 GTK_CMCTREE_ROW (dest_node)->sibling); 5345 g_dataset_remove_data (context, "gtk-clist-drag-dest"); 5346 break; 5347 } 5348 } 5349 } 5350 } 5351 5352 GType 5353 gtk_cmctree_node_get_type (void) 5354 { 5355 static GType our_type = 0; 5356 5357 if (our_type == 0) 5358 our_type = g_pointer_type_register_static ("GtkCMCTreeNode"); 5359 5360 return our_type; 5361 }