gtkctree.c 160 KB
Newer Older
Tim Janik's avatar
Tim Janik committed
1 2 3 4 5 6 7 8
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 
 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>  
 *
 * GtkCTree widget for GTK+
 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
 *
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
Tim Janik's avatar
Tim Janik committed
10 11 12 13 14 15
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
Tim Janik's avatar
Tim Janik committed
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
Tim Janik's avatar
Tim Janik committed
19 20 21 22 23
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

24
/*
25
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
26 27 28 29 30
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Manish Singh's avatar
Manish Singh committed
31
#undef GDK_DISABLE_DEPRECATED
32
#undef GTK_DISABLE_DEPRECATED
Manish Singh's avatar
Manish Singh committed
33

34
#include <config.h>
Tim Janik's avatar
Tim Janik committed
35 36
#include <stdlib.h>
#include "gtkctree.h"
37
#include "gtkbindings.h"
Lars Hamann's avatar
Lars Hamann committed
38
#include "gtkmain.h"
39
#include "gtkmarshalers.h"
40
#include "gtkdnd.h"
Matthias Clasen's avatar
Matthias Clasen committed
41
#include "gtkintl.h"
42
#include <gdk/gdkkeysyms.h>
43
#include "gtkalias.h"
Tim Janik's avatar
Tim Janik committed
44 45

#define PM_SIZE                    8
46
#define TAB_SIZE                   (PM_SIZE + 6)
Tim Janik's avatar
Tim Janik committed
47
#define CELL_SPACING               1
48
#define CLIST_OPTIMUM_SIZE         64
49 50
#define COLUMN_INSET               3
#define DRAG_WIDTH                 6
Tim Janik's avatar
Tim Janik committed
51 52 53 54 55 56 57 58

#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
				    (((row) + 1) * CELL_SPACING) + \
				    (clist)->voffset)
#define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
                                    ((clist)->row_height + CELL_SPACING))
#define COLUMN_LEFT_XPIXEL(clist, col)  ((clist)->column[(col)].area.x \
                                    + (clist)->hoffset)
59
#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
Tim Janik's avatar
Tim Janik committed
60

61 62 63 64 65
static inline gint
COLUMN_FROM_XPIXEL (GtkCList * clist,
		    gint x)
{
  gint i, cx;
66

67 68 69 70
  for (i = 0; i < clist->columns; i++)
    if (clist->column[i].visible)
      {
	cx = clist->column[i].area.x + clist->hoffset;
71

72 73 74 75
	if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
	    x <= (cx + clist->column[i].area.width + COLUMN_INSET))
	  return i;
      }
76

77 78 79 80
  /* no match */
  return -1;
}

81 82 83
#define CLIST_UNFROZEN(clist)     (((GtkCList*) (clist))->freeze_count == 0)
#define CLIST_REFRESH(clist)    G_STMT_START { \
  if (CLIST_UNFROZEN (clist)) \
84
    GTK_CLIST_GET_CLASS (clist)->refresh ((GtkCList*) (clist)); \
85 86
} G_STMT_END

87

88 89 90 91 92 93 94 95 96 97 98
enum {
  ARG_0,
  ARG_N_COLUMNS,
  ARG_TREE_COLUMN,
  ARG_INDENT,
  ARG_SPACING,
  ARG_SHOW_STUB,
  ARG_LINE_STYLE,
  ARG_EXPANDER_STYLE
};

99

100 101 102 103 104
static void     gtk_ctree_class_init    (GtkCTreeClass         *klass);
static void     gtk_ctree_init          (GtkCTree              *ctree);
static GObject* gtk_ctree_constructor   (GType                  type,
				         guint                  n_construct_properties,
				         GObjectConstructParam *construct_params);
105 106 107 108 109 110
static void gtk_ctree_set_arg		(GtkObject      *object,
					 GtkArg         *arg,
					 guint           arg_id);
static void gtk_ctree_get_arg      	(GtkObject      *object,
					 GtkArg         *arg,
					 guint           arg_id);
111 112
static void gtk_ctree_realize           (GtkWidget      *widget);
static void gtk_ctree_unrealize         (GtkWidget      *widget);
Tim Janik's avatar
Tim Janik committed
113 114
static gint gtk_ctree_button_press      (GtkWidget      *widget,
					 GdkEventButton *event);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
static void ctree_attach_styles         (GtkCTree       *ctree,
					 GtkCTreeNode   *node,
					 gpointer        data);
static void ctree_detach_styles         (GtkCTree       *ctree,
					 GtkCTreeNode   *node, 
					 gpointer        data);
static gint draw_cell_pixmap            (GdkWindow      *window,
					 GdkRectangle   *clip_rectangle,
					 GdkGC          *fg_gc,
					 GdkPixmap      *pixmap,
					 GdkBitmap      *mask,
					 gint            x,
					 gint            y,
					 gint            width,
					 gint            height);
static void get_cell_style              (GtkCList       *clist,
					 GtkCListRow    *clist_row,
					 gint            state,
					 gint            column,
					 GtkStyle      **style,
					 GdkGC         **fg_gc,
					 GdkGC         **bg_gc);
static gint gtk_ctree_draw_expander     (GtkCTree       *ctree,
					 GtkCTreeRow    *ctree_row,
					 GtkStyle       *style,
					 GdkRectangle   *clip_rectangle,
					 gint            x);
static gint gtk_ctree_draw_lines        (GtkCTree       *ctree,
					 GtkCTreeRow    *ctree_row,
					 gint            row,
					 gint            column,
					 gint            state,
					 GdkRectangle   *clip_rectangle,
					 GdkRectangle   *cell_rectangle,
					 GdkRectangle   *crect,
					 GdkRectangle   *area,
					 GtkStyle       *style);
152 153 154
static void draw_row                    (GtkCList       *clist,
					 GdkRectangle   *area,
					 gint            row,
155 156 157 158 159
					 GtkCListRow    *clist_row);
static void draw_drag_highlight         (GtkCList        *clist,
					 GtkCListRow     *dest_row,
					 gint             dest_row_number,
					 GtkCListDragPos  drag_pos);
160 161
static void tree_draw_node              (GtkCTree      *ctree,
					 GtkCTreeNode  *node);
162
static void set_cell_contents           (GtkCList      *clist,
Tim Janik's avatar
Tim Janik committed
163 164
					 GtkCListRow   *clist_row,
					 gint           column,
165
					 GtkCellType    type,
Tim Janik's avatar
Tim Janik committed
166
					 const gchar   *text,
Tim Janik's avatar
Tim Janik committed
167 168 169
					 guint8         spacing,
					 GdkPixmap     *pixmap,
					 GdkBitmap     *mask);
170
static void set_node_info               (GtkCTree      *ctree,
171
					 GtkCTreeNode  *node,
Tim Janik's avatar
Tim Janik committed
172
					 const gchar   *text,
173 174 175 176 177 178 179
					 guint8         spacing,
					 GdkPixmap     *pixmap_closed,
					 GdkBitmap     *mask_closed,
					 GdkPixmap     *pixmap_opened,
					 GdkBitmap     *mask_opened,
					 gboolean       is_leaf,
					 gboolean       expanded);
180 181 182 183
static GtkCTreeRow *row_new             (GtkCTree      *ctree);
static void row_delete                  (GtkCTree      *ctree,
				 	 GtkCTreeRow   *ctree_row);
static void tree_delete                 (GtkCTree      *ctree, 
184
					 GtkCTreeNode  *node, 
185 186
					 gpointer       data);
static void tree_delete_row             (GtkCTree      *ctree, 
187
					 GtkCTreeNode  *node, 
188
					 gpointer       data);
189
static void real_clear                  (GtkCList      *clist);
190
static void tree_update_level           (GtkCTree      *ctree, 
191
					 GtkCTreeNode  *node, 
192 193
					 gpointer       data);
static void tree_select                 (GtkCTree      *ctree, 
194
					 GtkCTreeNode  *node, 
195 196
					 gpointer       data);
static void tree_unselect               (GtkCTree      *ctree, 
197
					 GtkCTreeNode  *node, 
198
				         gpointer       data);
199 200
static void real_select_all             (GtkCList      *clist);
static void real_unselect_all           (GtkCList      *clist);
201
static void tree_expand                 (GtkCTree      *ctree, 
202
					 GtkCTreeNode  *node,
203 204
					 gpointer       data);
static void tree_collapse               (GtkCTree      *ctree, 
205
					 GtkCTreeNode  *node,
206
					 gpointer       data);
207
static void tree_collapse_to_depth      (GtkCTree      *ctree, 
208
					 GtkCTreeNode  *node, 
209
					 gint           depth);
210
static void tree_toggle_expansion       (GtkCTree      *ctree,
211
					 GtkCTreeNode  *node,
212 213
					 gpointer       data);
static void change_focus_row_expansion  (GtkCTree      *ctree,
214
				         GtkCTreeExpansionType expansion);
215 216 217 218 219 220 221 222
static void real_select_row             (GtkCList      *clist,
					 gint           row,
					 gint           column,
					 GdkEvent      *event);
static void real_unselect_row           (GtkCList      *clist,
					 gint           row,
					 gint           column,
					 GdkEvent      *event);
223
static void real_tree_select            (GtkCTree      *ctree,
224
					 GtkCTreeNode  *node,
225 226
					 gint           column);
static void real_tree_unselect          (GtkCTree      *ctree,
227
					 GtkCTreeNode  *node,
228 229
					 gint           column);
static void real_tree_expand            (GtkCTree      *ctree,
230
					 GtkCTreeNode  *node);
231
static void real_tree_collapse          (GtkCTree      *ctree,
232
					 GtkCTreeNode  *node);
233
static void real_tree_move              (GtkCTree      *ctree,
234 235 236
					 GtkCTreeNode  *node,
					 GtkCTreeNode  *new_parent, 
					 GtkCTreeNode  *new_sibling);
237 238 239
static void real_row_move               (GtkCList      *clist,
					 gint           source_row,
					 gint           dest_row);
240
static void gtk_ctree_link              (GtkCTree      *ctree,
241 242 243
					 GtkCTreeNode  *node,
					 GtkCTreeNode  *parent,
					 GtkCTreeNode  *sibling,
244
					 gboolean       update_focus_row);
245
static void gtk_ctree_unlink            (GtkCTree      *ctree, 
246
					 GtkCTreeNode  *node,
247
					 gboolean       update_focus_row);
248 249
static GtkCTreeNode * gtk_ctree_last_visible (GtkCTree     *ctree,
					      GtkCTreeNode *node);
250
static gboolean ctree_is_hot_spot       (GtkCTree      *ctree, 
251
					 GtkCTreeNode  *node,
252 253 254 255
					 gint           row, 
					 gint           x, 
					 gint           y);
static void tree_sort                   (GtkCTree      *ctree,
256
					 GtkCTreeNode  *node,
257
					 gpointer       data);
258 259
static void fake_unselect_all           (GtkCList      *clist,
					 gint           row);
260
static GList * selection_find           (GtkCList      *clist,
261 262 263 264 265 266
					 gint           row_number,
					 GList         *row_list_element);
static void resync_selection            (GtkCList      *clist,
					 GdkEvent      *event);
static void real_undo_selection         (GtkCList      *clist);
static void select_row_recursive        (GtkCTree      *ctree, 
267
					 GtkCTreeNode  *node, 
268
					 gpointer       data);
269 270 271 272 273 274
static gint real_insert_row             (GtkCList      *clist,
					 gint           row,
					 gchar         *text[]);
static void real_remove_row             (GtkCList      *clist,
					 gint           row);
static void real_sort_list              (GtkCList      *clist);
275 276 277 278 279 280 281 282
static void cell_size_request           (GtkCList       *clist,
					 GtkCListRow    *clist_row,
					 gint            column,
					 GtkRequisition *requisition);
static void column_auto_resize          (GtkCList       *clist,
					 GtkCListRow    *clist_row,
					 gint            column,
					 gint            old_width);
Lars Hamann's avatar
Lars Hamann committed
283
static void auto_resize_columns         (GtkCList       *clist);
284

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303

static gboolean check_drag               (GtkCTree         *ctree,
			                  GtkCTreeNode     *drag_source,
					  GtkCTreeNode     *drag_target,
					  GtkCListDragPos   insert_pos);
static void gtk_ctree_drag_begin         (GtkWidget        *widget,
					  GdkDragContext   *context);
static gint gtk_ctree_drag_motion        (GtkWidget        *widget,
					  GdkDragContext   *context,
					  gint              x,
					  gint              y,
					  guint             time);
static void gtk_ctree_drag_data_received (GtkWidget        *widget,
					  GdkDragContext   *context,
					  gint              x,
					  gint              y,
					  GtkSelectionData *selection_data,
					  guint             info,
					  guint32           time);
304
static void remove_grab                  (GtkCList         *clist);
Lars Hamann's avatar
Lars Hamann committed
305 306 307 308
static void drag_dest_cell               (GtkCList         *clist,
					  gint              x,
					  gint              y,
					  GtkCListDestInfo *dest_info);
309 310


Tim Janik's avatar
Tim Janik committed
311 312 313 314 315 316 317
enum
{
  TREE_SELECT_ROW,
  TREE_UNSELECT_ROW,
  TREE_EXPAND,
  TREE_COLLAPSE,
  TREE_MOVE,
318
  CHANGE_FOCUS_ROW_EXPANSION,
Tim Janik's avatar
Tim Janik committed
319 320 321 322 323 324 325 326 327
  LAST_SIGNAL
};

static GtkCListClass *parent_class = NULL;
static GtkContainerClass *container_class = NULL;
static guint ctree_signals[LAST_SIGNAL] = {0};


GtkType
328
gtk_ctree_get_type (void)
Tim Janik's avatar
Tim Janik committed
329 330
{
  static GtkType ctree_type = 0;
331

Tim Janik's avatar
Tim Janik committed
332 333
  if (!ctree_type)
    {
334
      static const GtkTypeInfo ctree_info =
Tim Janik's avatar
Tim Janik committed
335 336 337 338 339 340
      {
	"GtkCTree",
	sizeof (GtkCTree),
	sizeof (GtkCTreeClass),
	(GtkClassInitFunc) gtk_ctree_class_init,
	(GtkObjectInitFunc) gtk_ctree_init,
341 342
	/* reserved_1 */ NULL,
        /* reserved_2 */ NULL,
343
        (GtkClassInitFunc) NULL,
Tim Janik's avatar
Tim Janik committed
344
      };
345

Matthias Clasen's avatar
Matthias Clasen committed
346
      I_("GtkCTree");
347
      ctree_type = gtk_type_unique (GTK_TYPE_CLIST, &ctree_info);
Tim Janik's avatar
Tim Janik committed
348
    }
349

Tim Janik's avatar
Tim Janik committed
350 351 352 353 354 355
  return ctree_type;
}

static void
gtk_ctree_class_init (GtkCTreeClass *klass)
{
356
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Tim Janik's avatar
Tim Janik committed
357 358 359
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkCListClass *clist_class;
360
  GtkBindingSet *binding_set;
361

362 363
  gobject_class->constructor = gtk_ctree_constructor;

Tim Janik's avatar
Tim Janik committed
364 365 366 367
  object_class = (GtkObjectClass *) klass;
  widget_class = (GtkWidgetClass *) klass;
  container_class = (GtkContainerClass *) klass;
  clist_class = (GtkCListClass *) klass;
368

369 370
  parent_class = gtk_type_class (GTK_TYPE_CLIST);
  container_class = gtk_type_class (GTK_TYPE_CONTAINER);
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
  object_class->set_arg = gtk_ctree_set_arg;
  object_class->get_arg = gtk_ctree_get_arg;

  widget_class->realize = gtk_ctree_realize;
  widget_class->unrealize = gtk_ctree_unrealize;
  widget_class->button_press_event = gtk_ctree_button_press;

  widget_class->drag_begin = gtk_ctree_drag_begin;
  widget_class->drag_motion = gtk_ctree_drag_motion;
  widget_class->drag_data_received = gtk_ctree_drag_data_received;

  clist_class->select_row = real_select_row;
  clist_class->unselect_row = real_unselect_row;
  clist_class->row_move = real_row_move;
  clist_class->undo_selection = real_undo_selection;
  clist_class->resync_selection = resync_selection;
  clist_class->selection_find = selection_find;
  clist_class->click_column = NULL;
  clist_class->draw_row = draw_row;
  clist_class->draw_drag_highlight = draw_drag_highlight;
  clist_class->clear = real_clear;
  clist_class->select_all = real_select_all;
  clist_class->unselect_all = real_unselect_all;
  clist_class->fake_unselect_all = fake_unselect_all;
  clist_class->insert_row = real_insert_row;
  clist_class->remove_row = real_remove_row;
  clist_class->sort_list = real_sort_list;
  clist_class->set_cell_contents = set_cell_contents;
  clist_class->cell_size_request = cell_size_request;

  klass->tree_select_row = real_tree_select;
  klass->tree_unselect_row = real_tree_unselect;
  klass->tree_expand = real_tree_expand;
  klass->tree_collapse = real_tree_collapse;
  klass->tree_move = real_tree_move;
  klass->change_focus_row_expansion = change_focus_row_expansion;

409
  gtk_object_add_arg_type ("GtkCTree::n-columns", /* overrides GtkCList::n_columns!! */
410
			   GTK_TYPE_UINT,
411
			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME,
412
			   ARG_N_COLUMNS);
413
  gtk_object_add_arg_type ("GtkCTree::tree-column",
414
			   GTK_TYPE_UINT,
415
			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME,
416 417 418
			   ARG_TREE_COLUMN);
  gtk_object_add_arg_type ("GtkCTree::indent",
			   GTK_TYPE_UINT,
419
			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
420 421 422
			   ARG_INDENT);
  gtk_object_add_arg_type ("GtkCTree::spacing",
			   GTK_TYPE_UINT,
423
			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
424
			   ARG_SPACING);
425
  gtk_object_add_arg_type ("GtkCTree::show-stub",
426
			   GTK_TYPE_BOOL,
427
			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
428
			   ARG_SHOW_STUB);
429
  gtk_object_add_arg_type ("GtkCTree::line-style",
430
			   GTK_TYPE_CTREE_LINE_STYLE,
431
			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
432
			   ARG_LINE_STYLE);
433
  gtk_object_add_arg_type ("GtkCTree::expander-style",
434
			   GTK_TYPE_CTREE_EXPANDER_STYLE,
435
			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
436
			   ARG_EXPANDER_STYLE);
437

Tim Janik's avatar
Tim Janik committed
438
  ctree_signals[TREE_SELECT_ROW] =
Matthias Clasen's avatar
Matthias Clasen committed
439
    gtk_signal_new (I_("tree_select_row"),
Tim Janik's avatar
Tim Janik committed
440
		    GTK_RUN_FIRST,
441
		    GTK_CLASS_TYPE (object_class),
Tim Janik's avatar
Tim Janik committed
442
		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_select_row),
443
		    _gtk_marshal_VOID__POINTER_INT,
444
		    GTK_TYPE_NONE, 2,
445
		    GTK_TYPE_CTREE_NODE,
446
		    GTK_TYPE_INT);
Tim Janik's avatar
Tim Janik committed
447
  ctree_signals[TREE_UNSELECT_ROW] =
Matthias Clasen's avatar
Matthias Clasen committed
448
    gtk_signal_new (I_("tree_unselect_row"),
Tim Janik's avatar
Tim Janik committed
449
		    GTK_RUN_FIRST,
450
		    GTK_CLASS_TYPE (object_class),
Tim Janik's avatar
Tim Janik committed
451
		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_unselect_row),
452
		    _gtk_marshal_VOID__POINTER_INT,
453
		    GTK_TYPE_NONE, 2,
454
		    GTK_TYPE_CTREE_NODE,
455
		    GTK_TYPE_INT);
Tim Janik's avatar
Tim Janik committed
456
  ctree_signals[TREE_EXPAND] =
Matthias Clasen's avatar
Matthias Clasen committed
457
    gtk_signal_new (I_("tree_expand"),
Tim Janik's avatar
Tim Janik committed
458
		    GTK_RUN_LAST,
459
		    GTK_CLASS_TYPE (object_class),
Tim Janik's avatar
Tim Janik committed
460
		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_expand),
461
		    _gtk_marshal_VOID__POINTER,
462
		    GTK_TYPE_NONE, 1,
463
		    GTK_TYPE_CTREE_NODE);
Tim Janik's avatar
Tim Janik committed
464
  ctree_signals[TREE_COLLAPSE] =
Matthias Clasen's avatar
Matthias Clasen committed
465
    gtk_signal_new (I_("tree_collapse"),
Tim Janik's avatar
Tim Janik committed
466
		    GTK_RUN_LAST,
467
		    GTK_CLASS_TYPE (object_class),
Tim Janik's avatar
Tim Janik committed
468
		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_collapse),
469
		    _gtk_marshal_VOID__POINTER,
470
		    GTK_TYPE_NONE, 1,
471
		    GTK_TYPE_CTREE_NODE);
Tim Janik's avatar
Tim Janik committed
472
  ctree_signals[TREE_MOVE] =
Matthias Clasen's avatar
Matthias Clasen committed
473
    gtk_signal_new (I_("tree_move"),
Tim Janik's avatar
Tim Janik committed
474
		    GTK_RUN_LAST,
475
		    GTK_CLASS_TYPE (object_class),
Tim Janik's avatar
Tim Janik committed
476
		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_move),
477
		    _gtk_marshal_VOID__POINTER_POINTER_POINTER,
478
		    GTK_TYPE_NONE, 3,
479 480 481
		    GTK_TYPE_CTREE_NODE,
		    GTK_TYPE_CTREE_NODE,
		    GTK_TYPE_CTREE_NODE);
482
  ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
Matthias Clasen's avatar
Matthias Clasen committed
483
    gtk_signal_new (I_("change_focus_row_expansion"),
484
		    GTK_RUN_LAST | GTK_RUN_ACTION,
485
		    GTK_CLASS_TYPE (object_class),
486 487
		    GTK_SIGNAL_OFFSET (GtkCTreeClass,
				       change_focus_row_expansion),
488
		    _gtk_marshal_VOID__ENUM,
489
		    GTK_TYPE_NONE, 1, GTK_TYPE_CTREE_EXPANSION_TYPE);
490

491
  binding_set = gtk_binding_set_by_class (klass);
492
  gtk_binding_entry_add_signal (binding_set,
493
				GDK_plus, 0,
494 495 496
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
  gtk_binding_entry_add_signal (binding_set,
497
				GDK_plus, GDK_CONTROL_MASK,
498 499
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND_RECURSIVE);
500

501 502 503 504 505 506 507
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Add, 0,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Add, GDK_CONTROL_MASK,
				"change_focus_row_expansion", 1,
508 509
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND_RECURSIVE);
  
510
  gtk_binding_entry_add_signal (binding_set,
511
				GDK_minus, 0,
512 513
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
514
  gtk_binding_entry_add_signal (binding_set,
515
                                GDK_minus, GDK_CONTROL_MASK,
516 517 518
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM,
				GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE);
519 520 521 522 523 524 525 526 527 528
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Subtract, 0,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Subtract, GDK_CONTROL_MASK,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM,
				GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE);
  gtk_binding_entry_add_signal (binding_set,
529
				GDK_equal, 0,
530 531
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
532
  gtk_binding_entry_add_signal (binding_set,
533 534 535
				GDK_KP_Equal, 0,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
536 537 538 539
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Multiply, 0,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
540 541 542 543
  gtk_binding_entry_add_signal (binding_set,
				GDK_asterisk, 0,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
544 545 546 547 548
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Multiply, GDK_CONTROL_MASK,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM,
				GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE);
549 550 551 552 553
  gtk_binding_entry_add_signal (binding_set,
				GDK_asterisk, GDK_CONTROL_MASK,
				"change_focus_row_expansion", 1,
				GTK_TYPE_ENUM,
				GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE);  
Tim Janik's avatar
Tim Janik committed
554 555
}

556 557 558 559 560 561
static void
gtk_ctree_set_arg (GtkObject      *object,
		   GtkArg         *arg,
		   guint           arg_id)
{
  GtkCTree *ctree;
562
  GtkCList *clist;
563

564
  ctree = GTK_CTREE (object);
565
  clist = GTK_CLIST (ctree);
566

567 568
  switch (arg_id)
    {
569 570 571
    case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
      clist->columns = MAX (1, GTK_VALUE_UINT (*arg));
      ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
572
      break;
573 574
    case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
      ctree->tree_column = GTK_VALUE_UINT (*arg);
575
      ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
      break;
    case ARG_INDENT:
      gtk_ctree_set_indent (ctree, GTK_VALUE_UINT (*arg));
      break;
    case ARG_SPACING:
      gtk_ctree_set_spacing (ctree, GTK_VALUE_UINT (*arg));
      break;
    case ARG_SHOW_STUB:
      gtk_ctree_set_show_stub (ctree, GTK_VALUE_BOOL (*arg));
      break;
    case ARG_LINE_STYLE:
      gtk_ctree_set_line_style (ctree, GTK_VALUE_ENUM (*arg));
      break;
    case ARG_EXPANDER_STYLE:
      gtk_ctree_set_expander_style (ctree, GTK_VALUE_ENUM (*arg));
      break;
    default:
      break;
    }
}

static void
gtk_ctree_get_arg (GtkObject      *object,
		   GtkArg         *arg,
		   guint           arg_id)
{
  GtkCTree *ctree;
603

604
  ctree = GTK_CTREE (object);
605

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
  switch (arg_id)
    {
    case ARG_N_COLUMNS:
      GTK_VALUE_UINT (*arg) = GTK_CLIST (ctree)->columns;
      break;
    case ARG_TREE_COLUMN:
      GTK_VALUE_UINT (*arg) = ctree->tree_column;
      break;
    case ARG_INDENT:
      GTK_VALUE_UINT (*arg) = ctree->tree_indent;
      break;
    case ARG_SPACING:
      GTK_VALUE_UINT (*arg) = ctree->tree_spacing;
      break;
    case ARG_SHOW_STUB:
      GTK_VALUE_BOOL (*arg) = ctree->show_stub;
      break;
    case ARG_LINE_STYLE:
      GTK_VALUE_ENUM (*arg) = ctree->line_style;
      break;
    case ARG_EXPANDER_STYLE:
      GTK_VALUE_ENUM (*arg) = ctree->expander_style;
      break;
    default:
      arg->type = GTK_TYPE_INVALID;
      break;
    }
}

Tim Janik's avatar
Tim Janik committed
635 636 637
static void
gtk_ctree_init (GtkCTree *ctree)
{
638
  GtkCList *clist;
639

640 641
  GTK_CLIST_SET_FLAG (ctree, CLIST_DRAW_DRAG_RECT);
  GTK_CLIST_SET_FLAG (ctree, CLIST_DRAW_DRAG_LINE);
642

643
  clist = GTK_CLIST (ctree);
644

Tim Janik's avatar
Tim Janik committed
645
  ctree->tree_indent    = 20;
646
  ctree->tree_spacing   = 5;
Tim Janik's avatar
Tim Janik committed
647
  ctree->tree_column    = 0;
648
  ctree->line_style     = GTK_CTREE_LINES_SOLID;
649
  ctree->expander_style = GTK_CTREE_EXPANDER_SQUARE;
650
  ctree->drag_compare   = NULL;
651
  ctree->show_stub      = TRUE;
652

653
  clist->button_actions[0] |= GTK_BUTTON_EXPANDS;
Tim Janik's avatar
Tim Janik committed
654 655
}

656 657 658 659 660 661 662
static void
ctree_attach_styles (GtkCTree     *ctree,
		     GtkCTreeNode *node,
		     gpointer      data)
{
  GtkCList *clist;
  gint i;
663

664
  clist = GTK_CLIST (ctree);
665

666 667 668
  if (GTK_CTREE_ROW (node)->row.style)
    GTK_CTREE_ROW (node)->row.style =
      gtk_style_attach (GTK_CTREE_ROW (node)->row.style, clist->clist_window);
669

670 671 672
  if (GTK_CTREE_ROW (node)->row.fg_set || GTK_CTREE_ROW (node)->row.bg_set)
    {
      GdkColormap *colormap;
673

674 675 676 677 678 679
      colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
      if (GTK_CTREE_ROW (node)->row.fg_set)
	gdk_color_alloc (colormap, &(GTK_CTREE_ROW (node)->row.foreground));
      if (GTK_CTREE_ROW (node)->row.bg_set)
	gdk_color_alloc (colormap, &(GTK_CTREE_ROW (node)->row.background));
    }
680

681 682 683 684 685 686 687 688 689 690 691 692 693 694
  for (i = 0; i < clist->columns; i++)
    if  (GTK_CTREE_ROW (node)->row.cell[i].style)
      GTK_CTREE_ROW (node)->row.cell[i].style =
	gtk_style_attach (GTK_CTREE_ROW (node)->row.cell[i].style,
			  clist->clist_window);
}

static void
ctree_detach_styles (GtkCTree     *ctree,
		     GtkCTreeNode *node,
		     gpointer      data)
{
  GtkCList *clist;
  gint i;
695

696
  clist = GTK_CLIST (ctree);
697

698 699 700 701 702 703 704
  if (GTK_CTREE_ROW (node)->row.style)
    gtk_style_detach (GTK_CTREE_ROW (node)->row.style);
  for (i = 0; i < clist->columns; i++)
    if  (GTK_CTREE_ROW (node)->row.cell[i].style)
      gtk_style_detach (GTK_CTREE_ROW (node)->row.cell[i].style);
}

Tim Janik's avatar
Tim Janik committed
705 706 707 708
static void
gtk_ctree_realize (GtkWidget *widget)
{
  GtkCTree *ctree;
709
  GtkCList *clist;
Tim Janik's avatar
Tim Janik committed
710
  GdkGCValues values;
711 712 713
  GtkCTreeNode *node;
  GtkCTreeNode *child;
  gint i;
714

715
  g_return_if_fail (GTK_IS_CTREE (widget));
716

717
  GTK_WIDGET_CLASS (parent_class)->realize (widget);
718

719
  ctree = GTK_CTREE (widget);
720
  clist = GTK_CLIST (widget);
721

722 723 724 725 726 727 728 729 730
  node = GTK_CTREE_NODE (clist->row_list);
  for (i = 0; i < clist->rows; i++)
    {
      if (GTK_CTREE_ROW (node)->children && !GTK_CTREE_ROW (node)->expanded)
	for (child = GTK_CTREE_ROW (node)->children; child;
	     child = GTK_CTREE_ROW (child)->sibling)
	  gtk_ctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
      node = GTK_CTREE_NODE_NEXT (node);
    }
731

Tim Janik's avatar
Tim Janik committed
732
  values.foreground = widget->style->fg[GTK_STATE_NORMAL];
733
  values.background = widget->style->base[GTK_STATE_NORMAL];
Tim Janik's avatar
Tim Janik committed
734 735 736 737 738 739 740 741
  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
  values.line_style = GDK_LINE_SOLID;
  ctree->lines_gc = gdk_gc_new_with_values (GTK_CLIST(widget)->clist_window, 
					    &values,
					    GDK_GC_FOREGROUND |
					    GDK_GC_BACKGROUND |
					    GDK_GC_SUBWINDOW |
					    GDK_GC_LINE_STYLE);
742

Tim Janik's avatar
Tim Janik committed
743 744 745
  if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
    {
      gdk_gc_set_line_attributes (ctree->lines_gc, 1, 
746
				  GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER);
747
      gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2);
Tim Janik's avatar
Tim Janik committed
748 749 750 751 752 753 754
    }
}

static void
gtk_ctree_unrealize (GtkWidget *widget)
{
  GtkCTree *ctree;
755
  GtkCList *clist;
756

757
  g_return_if_fail (GTK_IS_CTREE (widget));
758

759
  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
760

761
  ctree = GTK_CTREE (widget);
762
  clist = GTK_CLIST (widget);
763

764 765 766 767 768
  if (GTK_WIDGET_REALIZED (widget))
    {
      GtkCTreeNode *node;
      GtkCTreeNode *child;
      gint i;
769

770 771 772 773 774 775 776 777 778 779 780
      node = GTK_CTREE_NODE (clist->row_list);
      for (i = 0; i < clist->rows; i++)
	{
	  if (GTK_CTREE_ROW (node)->children &&
	      !GTK_CTREE_ROW (node)->expanded)
	    for (child = GTK_CTREE_ROW (node)->children; child;
		 child = GTK_CTREE_ROW (child)->sibling)
	      gtk_ctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
	  node = GTK_CTREE_NODE_NEXT (node);
	}
    }
781

Tim Janik's avatar
Tim Janik committed
782 783 784 785 786 787 788 789 790
  gdk_gc_destroy (ctree->lines_gc);
}

static gint
gtk_ctree_button_press (GtkWidget      *widget,
			GdkEventButton *event)
{
  GtkCTree *ctree;
  GtkCList *clist;
791
  gint button_actions;
792

Tim Janik's avatar
Tim Janik committed
793 794
  g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);
795

Tim Janik's avatar
Tim Janik committed
796 797
  ctree = GTK_CTREE (widget);
  clist = GTK_CLIST (widget);
798

799
  button_actions = clist->button_actions[event->button - 1];
800

801 802
  if (button_actions == GTK_BUTTON_IGNORED)
    return FALSE;
803

Tim Janik's avatar
Tim Janik committed
804 805
  if (event->window == clist->clist_window)
    {
806
      GtkCTreeNode *work;
Tim Janik's avatar
Tim Janik committed
807 808 809 810
      gint x;
      gint y;
      gint row;
      gint column;
811

Tim Janik's avatar
Tim Janik committed
812 813
      x = event->x;
      y = event->y;
814

815 816
      if (!gtk_clist_get_selection_info (clist, x, y, &row, &column))
	return FALSE;
817

818
      work = GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
819
	  
820 821 822 823
      if (button_actions & GTK_BUTTON_EXPANDS &&
	  (GTK_CTREE_ROW (work)->children && !GTK_CTREE_ROW (work)->is_leaf  &&
	   (event->type == GDK_2BUTTON_PRESS ||
	    ctree_is_hot_spot (ctree, work, row, x, y))))
824 825 826 827 828
	{
	  if (GTK_CTREE_ROW (work)->expanded)
	    gtk_ctree_collapse (ctree, work);
	  else
	    gtk_ctree_expand (ctree, work);
829

830
	  return TRUE;
Tim Janik's avatar
Tim Janik committed
831 832
	}
    }
833
  
834
  return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
Tim Janik's avatar
Tim Janik committed
835 836 837
}

static void
838 839 840 841
draw_drag_highlight (GtkCList        *clist,
		     GtkCListRow     *dest_row,
		     gint             dest_row_number,
		     GtkCListDragPos  drag_pos)
Tim Janik's avatar
Tim Janik committed
842
{
843 844
  GtkCTree *ctree;
  GdkPoint points[4];
Tim Janik's avatar
Tim Janik committed
845
  gint level;
846
  gint i;
Tim Janik's avatar
Tim Janik committed
847
  gint y = 0;
848

849
  g_return_if_fail (GTK_IS_CTREE (clist));
850

851
  ctree = GTK_CTREE (clist);
852

853
  level = ((GtkCTreeRow *)(dest_row))->level;
854

855
  y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
856

857 858 859 860 861 862 863
  switch (drag_pos)
    {
    case GTK_CLIST_DRAG_NONE:
      break;
    case GTK_CLIST_DRAG_AFTER:
      y += clist->row_height + 1;
    case GTK_CLIST_DRAG_BEFORE:
864
      
865 866 867 868 869 870 871 872 873 874 875 876
      if (clist->column[ctree->tree_column].visible)
	switch (clist->column[ctree->tree_column].justification)
	  {
	  case GTK_JUSTIFY_CENTER:
	  case GTK_JUSTIFY_FILL:
	  case GTK_JUSTIFY_LEFT:
	    if (ctree->tree_column > 0)
	      gdk_draw_line (clist->clist_window, clist->xor_gc, 
			     COLUMN_LEFT_XPIXEL(clist, 0), y,
			     COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1)+
			     clist->column[ctree->tree_column - 1].area.width,
			     y);
877

878 879 880 881 882 883 884 885 886 887 888 889 890
	    gdk_draw_line (clist->clist_window, clist->xor_gc, 
			   COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + 
			   ctree->tree_indent * level -
			   (ctree->tree_indent - PM_SIZE) / 2, y,
			   GTK_WIDGET (ctree)->allocation.width, y);
	    break;
	  case GTK_JUSTIFY_RIGHT:
	    if (ctree->tree_column < clist->columns - 1)
	      gdk_draw_line (clist->clist_window, clist->xor_gc, 
			     COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1),
			     y,
			     COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) +
			     clist->column[clist->columns - 1].area.width, y);
891
      
892 893 894 895 896 897 898 899
	    gdk_draw_line (clist->clist_window, clist->xor_gc, 
			   0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column)
			   + clist->column[ctree->tree_column].area.width -
			   ctree->tree_indent * level +
			   (ctree->tree_indent - PM_SIZE) / 2, y);
	    break;
	  }
      else
900
	gdk_draw_line (clist->clist_window, clist->xor_gc, 
901 902 903 904
		       0, y, clist->clist_window_width, y);
      break;
    case GTK_CLIST_DRAG_INTO:
      y = ROW_TOP_YPIXEL (clist, dest_row_number) + clist->row_height;
905

906 907
      if (clist->column[ctree->tree_column].visible)
	switch (clist->column[ctree->tree_column].justification)
908
	  {
909 910 911 912 913
	  case GTK_JUSTIFY_CENTER:
	  case GTK_JUSTIFY_FILL:
	  case GTK_JUSTIFY_LEFT:
	    points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + 
	      ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2;
914 915 916
	    points[0].y = y;
	    points[3].x = points[0].x;
	    points[3].y = y - clist->row_height - 1;
917
	    points[1].x = clist->clist_window_width - 1;
918
	    points[1].y = points[0].y;
919
	    points[2].x = points[1].x;
920
	    points[2].y = points[3].y;
921

922
	    for (i = 0; i < 3; i++)
923
	      gdk_draw_line (clist->clist_window, clist->xor_gc,
924 925
			     points[i].x, points[i].y,
			     points[i+1].x, points[i+1].y);
926

927 928 929 930 931 932 933 934 935 936 937 938
	    if (ctree->tree_column > 0)
	      {
		points[0].x = COLUMN_LEFT_XPIXEL(clist,
						 ctree->tree_column - 1) +
		  clist->column[ctree->tree_column - 1].area.width ;
		points[0].y = y;
		points[3].x = points[0].x;
		points[3].y = y - clist->row_height - 1;
		points[1].x = 0;
		points[1].y = points[0].y;
		points[2].x = 0;
		points[2].y = points[3].y;
939

940 941 942 943 944 945 946 947 948 949
		for (i = 0; i < 3; i++)
		  gdk_draw_line (clist->clist_window, clist->xor_gc,
				 points[i].x, points[i].y, points[i+1].x, 
				 points[i+1].y);
	      }
	    break;
	  case GTK_JUSTIFY_RIGHT:
	    points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) - 
	      ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2 +
	      clist->column[ctree->tree_column].area.width;
950 951 952
	    points[0].y = y;
	    points[3].x = points[0].x;
	    points[3].y = y - clist->row_height - 1;
953
	    points[1].x = 0;
954
	    points[1].y = points[0].y;
955
	    points[2].x = 0;
956
	    points[2].y = points[3].y;
957

958
	    for (i = 0; i < 3; i++)
959
	      gdk_draw_line (clist->clist_window, clist->xor_gc,
960 961
			     points[i].x, points[i].y,
			     points[i+1].x, points[i+1].y);
962

963 964 965 966 967 968 969 970 971 972
	    if (ctree->tree_column < clist->columns - 1)
	      {
		points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column +1);
		points[0].y = y;
		points[3].x = points[0].x;
		points[3].y = y - clist->row_height - 1;
		points[1].x = clist->clist_window_width - 1;
		points[1].y = points[0].y;
		points[2].x = points[1].x;
		points[2].y = points[3].y;
973

974 975 976 977 978 979
		for (i = 0; i < 3; i++)
		  gdk_draw_line (clist->clist_window, clist->xor_gc,
				 points[i].x, points[i].y,
				 points[i+1].x, points[i+1].y);
	      }
	    break;
980
	  }
981 982 983 984 985 986
      else
	gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
			    0, y - clist->row_height,
			    clist->clist_window_width - 1, clist->row_height);
      break;
    }
Tim Janik's avatar
Tim Janik committed
987 988
}

989 990 991 992 993 994 995 996 997 998
static gint
draw_cell_pixmap (GdkWindow    *window,
		  GdkRectangle *clip_rectangle,
		  GdkGC        *fg_gc,
		  GdkPixmap    *pixmap,
		  GdkBitmap    *mask,
		  gint          x,
		  gint          y,
		  gint          width,
		  gint          height)
Tim Janik's avatar
Tim Janik committed
999
{
1000 1001
  gint xsrc = 0;
  gint ysrc = 0;
1002

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
  if (mask)
    {
      gdk_gc_set_clip_mask (fg_gc, mask);
      gdk_gc_set_clip_origin (fg_gc, x, y);
    }
  if (x < clip_rectangle->x)
    {
      xsrc = clip_rectangle->x - x;
      width -= xsrc;
      x = clip_rectangle->x;
    }
  if (x + width > clip_rectangle->x + clip_rectangle->width)
    width = clip_rectangle->x + clip_rectangle->width - x;
1016

1017 1018 1019 1020 1021 1022 1023 1024
  if (y < clip_rectangle->y)
    {
      ysrc = clip_rectangle->y - y;
      height -= ysrc;
      y = clip_rectangle->y;
    }
  if (y + height > clip_rectangle->y + clip_rectangle->height)
    height = clip_rectangle->y + clip_rectangle->height - y;
1025

1026 1027
  if (width > 0 && height > 0)
    gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
1028

1029 1030 1031 1032 1033
  if (mask)
    {
      gdk_gc_set_clip_rectangle (fg_gc, NULL);
      gdk_gc_set_clip_origin (fg_gc, 0, 0);
    }
1034

1035 1036
  return x + MAX (width, 0);
}
Tim Janik's avatar
Tim Janik committed
1037

1038 1039 1040 1041 1042 1043 1044 1045 1046
static void
get_cell_style (GtkCList     *clist,
		GtkCListRow  *clist_row,
		gint          state,
		gint          column,
		GtkStyle    **style,
		GdkGC       **fg_gc,
		GdkGC       **bg_gc)
{
1047
  gint fg_state;
1048

1049 1050 1051 1052 1053
  if ((state == GTK_STATE_NORMAL) &&
      (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE))
    fg_state = GTK_STATE_INSENSITIVE;
  else
    fg_state = state;
1054

1055 1056 1057 1058 1059
  if (clist_row->cell[column].style)
    {
      if (style)
	*style = clist_row->cell[column].style;
      if (fg_gc)
1060 1061 1062 1063 1064 1065 1066
	*fg_gc = clist_row->cell[column].style->fg_gc[fg_state];
      if (bg_gc) {
	if (state == GTK_STATE_SELECTED)
	  *bg_gc = clist_row->cell[column].style->bg_gc[state];
	else
	  *bg_gc = clist_row->cell[column].style->base_gc[state];
      }
1067 1068 1069 1070 1071 1072
    }
  else if (clist_row->style)
    {
      if (style)
	*style = clist_row->style;
      if (fg_gc)
1073 1074 1075 1076 1077 1078 1079
	*fg_gc = clist_row->style->fg_gc[fg_state];
      if (bg_gc) {
	if (state == GTK_STATE_SELECTED)
	  *bg_gc = clist_row->style->bg_gc[state];
	else
	  *bg_gc = clist_row->style->base_gc[state];
      }
1080 1081 1082 1083 1084 1085
    }
  else
    {
      if (style)
	*style = GTK_WIDGET (clist)->style;
      if (fg_gc)
1086 1087 1088 1089 1090 1091 1092
	*fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state];
      if (bg_gc) {
	if (state == GTK_STATE_SELECTED)
	  *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
	else
	  *bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
      }
1093

1094 1095 1096 1097 1098 1099 1100 1101 1102
      if (state != GTK_STATE_SELECTED)
	{
	  if (fg_gc && clist_row->fg_set)
	    *fg_gc = clist->fg_gc;
	  if (bg_gc && clist_row->bg_set)
	    *bg_gc = clist->bg_gc;
	}
    }
}
Tim Janik's avatar
Tim Janik committed
1103

1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114