gtktreeviewcolumn.c 96.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* gtktreeviewcolumn.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

Manish Singh's avatar
Manish Singh committed
20
#include <string.h>
21
#include "gtktreeviewcolumn.h"
22
#include "gtktreeview.h"
23 24 25
#include "gtktreeprivate.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
26
#include "gtklabel.h"
Havoc Pennington's avatar
Havoc Pennington committed
27
#include "gtkhbox.h"
28
#include "gtkmarshalers.h"
Havoc Pennington's avatar
Havoc Pennington committed
29
#include "gtkarrow.h"
30
#include "gtkintl.h"
Jonathan Blandford's avatar
Jonathan Blandford committed
31

32 33 34 35
enum
{
  PROP_0,
  PROP_VISIBLE,
36
  PROP_RESIZABLE,
37
  PROP_WIDTH,
38 39
  PROP_SIZING,
  PROP_FIXED_WIDTH,
40 41 42 43 44
  PROP_MIN_WIDTH,
  PROP_MAX_WIDTH,
  PROP_TITLE,
  PROP_CLICKABLE,
  PROP_WIDGET,
Havoc Pennington's avatar
Havoc Pennington committed
45
  PROP_ALIGNMENT,
46
  PROP_REORDERABLE,
Havoc Pennington's avatar
Havoc Pennington committed
47 48
  PROP_SORT_INDICATOR,
  PROP_SORT_ORDER
49 50 51 52
};

enum
{
53 54 55 56
  CLICKED,
  LAST_SIGNAL
};

57 58 59 60 61 62 63 64
typedef struct _GtkTreeViewColumnCellInfo GtkTreeViewColumnCellInfo;
struct _GtkTreeViewColumnCellInfo
{
  GtkCellRenderer *cell;
  GSList *attributes;
  GtkTreeCellDataFunc func;
  gpointer func_data;
  GtkDestroyNotify destroy;
65
  gint requested_width;
66
  gint real_width;
67 68
  guint expand : 1;
  guint pack : 1;
69
  guint has_focus : 1;
70
  guint in_editing_mode : 1;
71
};
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
/* Type methods */
static void gtk_tree_view_column_init                          (GtkTreeViewColumn       *tree_column);
static void gtk_tree_view_column_class_init                    (GtkTreeViewColumnClass  *klass);

/* GObject methods */
static void gtk_tree_view_column_set_property                  (GObject                 *object,
								guint                    prop_id,
								const GValue            *value,
								GParamSpec              *pspec);
static void gtk_tree_view_column_get_property                  (GObject                 *object,
								guint                    prop_id,
								GValue                  *value,
								GParamSpec              *pspec);
static void gtk_tree_view_column_finalize                      (GObject                 *object);

88
/* Button handling code */
89 90 91 92
static void gtk_tree_view_column_create_button                 (GtkTreeViewColumn       *tree_column);
static void gtk_tree_view_column_update_button                 (GtkTreeViewColumn       *tree_column);

/* Button signal handlers */
93
static gint gtk_tree_view_column_button_event                  (GtkWidget               *widget,
94 95 96 97
								GdkEvent                *event,
								gpointer                 data);
static void gtk_tree_view_column_button_clicked                (GtkWidget               *widget,
								gpointer                 data);
98 99 100
static gboolean gtk_tree_view_column_mnemonic_activate         (GtkWidget *widget,
					                        gboolean   group_cycling,
								gpointer   data);
101 102 103 104 105 106 107 108 109 110

/* Property handlers */
static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
								GtkTreeViewColumn       *tree_column);

/* Internal functions */
static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
								gpointer                 data);
static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
111
								GtkCellRenderer         *cell_renderer,
112
								va_list                  args);
113 114
static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
								      GtkCellRenderer   *cell_renderer);
115

116 117 118 119 120 121 122
/* cell list manipulation */
static GList *gtk_tree_view_column_cell_first                  (GtkTreeViewColumn      *tree_column);
static GList *gtk_tree_view_column_cell_last                   (GtkTreeViewColumn      *tree_column);
static GList *gtk_tree_view_column_cell_next                   (GtkTreeViewColumn      *tree_column,
								GList                  *current);
static GList *gtk_tree_view_column_cell_prev                   (GtkTreeViewColumn      *tree_column,
								GList                  *current);
123 124
static void gtk_tree_view_column_clear_attributes_by_info      (GtkTreeViewColumn      *tree_column,
					                        GtkTreeViewColumnCellInfo *info);
125 126 127 128 129

static GtkObjectClass *parent_class = NULL;
static guint tree_column_signals[LAST_SIGNAL] = { 0 };


Manish Singh's avatar
Manish Singh committed
130
GType
131 132
gtk_tree_view_column_get_type (void)
{
Manish Singh's avatar
Manish Singh committed
133
  static GType tree_column_type = 0;
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

  if (!tree_column_type)
    {
      static const GTypeInfo tree_column_info =
      {
	sizeof (GtkTreeViewColumnClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
	(GClassInitFunc) gtk_tree_view_column_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof (GtkTreeViewColumn),
	0,
	(GInstanceInitFunc) gtk_tree_view_column_init,
      };

Manish Singh's avatar
Manish Singh committed
150 151 152
      tree_column_type =
	g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn",
				&tree_column_info, 0);
153 154 155 156 157 158 159 160
    }

  return tree_column_type;
}

static void
gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
{
161
  GObjectClass *object_class;
162

163
  object_class = (GObjectClass*) class;
164 165 166

  parent_class = g_type_class_peek_parent (class);

167
  class->clicked = NULL;
168

169
  object_class->finalize = gtk_tree_view_column_finalize;
170 171 172
  object_class->set_property = gtk_tree_view_column_set_property;
  object_class->get_property = gtk_tree_view_column_get_property;
  
173
  tree_column_signals[CLICKED] =
174
    g_signal_new ("clicked",
Manish Singh's avatar
Manish Singh committed
175
                  G_OBJECT_CLASS_TYPE (object_class),
176 177 178
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
                  NULL, NULL,
179
                  _gtk_marshal_VOID__VOID,
Manish Singh's avatar
Manish Singh committed
180
                  G_TYPE_NONE, 0);
181 182 183 184 185

  g_object_class_install_property (object_class,
                                   PROP_VISIBLE,
                                   g_param_spec_boolean ("visible",
                                                        _("Visible"),
Kjartan Maraas's avatar
Kjartan Maraas committed
186
                                                        _("Whether to display the column"),
187 188 189
                                                         TRUE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  
190 191 192 193 194 195 196 197
  g_object_class_install_property (object_class,
                                   PROP_RESIZABLE,
                                   g_param_spec_boolean ("resizable",
							 _("Resizable"),
							 _("Column is user-resizable"),
                                                         FALSE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  
198 199 200 201 202 203 204 205 206
  g_object_class_install_property (object_class,
                                   PROP_WIDTH,
                                   g_param_spec_int ("width",
						     _("Width"),
						     _("Current width of the column"),
						     0,
						     G_MAXINT,
						     0,
						     G_PARAM_READABLE));
207 208 209 210 211 212 213 214 215 216
  g_object_class_install_property (object_class,
                                   PROP_SIZING,
                                   g_param_spec_enum ("sizing",
                                                      _("Sizing"),
                                                      _("Resize mode of the column"),
                                                      GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
                                                      GTK_TREE_VIEW_COLUMN_AUTOSIZE,
                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
  
  g_object_class_install_property (object_class,
217 218 219 220
                                   PROP_FIXED_WIDTH,
                                   g_param_spec_int ("fixed_width",
                                                     _("Fixed Width"),
                                                     _("Current fixed width of the column"),
221 222 223 224 225 226 227 228 229 230 231 232
                                                     1,
                                                     G_MAXINT,
                                                     1, /* not useful */
                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (object_class,
                                   PROP_MIN_WIDTH,
                                   g_param_spec_int ("min_width",
                                                     _("Minimum Width"),
                                                     _("Minimum allowed width of the column"),
                                                     -1,
                                                     G_MAXINT,
233
                                                     -1,
234 235 236 237 238 239 240 241 242
                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (object_class,
                                   PROP_MAX_WIDTH,
                                   g_param_spec_int ("max_width",
                                                     _("Maximum Width"),
                                                     _("Maximum allowed width of the column"),
                                                     -1,
                                                     G_MAXINT,
243
                                                     -1,
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (object_class,
                                   PROP_TITLE,
                                   g_param_spec_string ("title",
                                                        _("Title"),
                                                        _("Title to appear in column header"),
                                                        "",
                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
  
  g_object_class_install_property (object_class,
                                   PROP_CLICKABLE,
                                   g_param_spec_boolean ("clickable",
                                                        _("Clickable"),
                                                        _("Whether the header can be clicked"),
                                                         TRUE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
  

  g_object_class_install_property (object_class,
                                   PROP_WIDGET,
                                   g_param_spec_object ("widget",
                                                        _("Widget"),
                                                        _("Widget to put in column header button instead of column title"),
                                                        GTK_TYPE_WIDGET,
                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (object_class,
Havoc Pennington's avatar
Havoc Pennington committed
272 273 274
                                   PROP_ALIGNMENT,
                                   g_param_spec_float ("alignment",
                                                       _("Alignment"),
275
                                                       _("X Alignment of the column header text or widget"),
Havoc Pennington's avatar
Havoc Pennington committed
276 277 278 279 280
                                                       0.0,
                                                       1.0,
                                                       0.5,
                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));

281 282 283 284
  g_object_class_install_property (object_class,
                                   PROP_REORDERABLE,
                                   g_param_spec_boolean ("reorderable",
							 _("Reorderable"),
285
							 _("Whether the column can be reordered around the headers"),
286 287 288
							 FALSE,
							 G_PARAM_READABLE | G_PARAM_WRITABLE));

Havoc Pennington's avatar
Havoc Pennington committed
289 290 291 292 293 294 295 296 297 298 299 300 301
  g_object_class_install_property (object_class,
                                   PROP_SORT_INDICATOR,
                                   g_param_spec_boolean ("sort_indicator",
                                                        _("Sort indicator"),
                                                        _("Whether to show a sort indicator"),
                                                         FALSE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));

  g_object_class_install_property (object_class,
                                   PROP_SORT_ORDER,
                                   g_param_spec_enum ("sort_order",
                                                      _("Sort order"),
                                                      _("Sort direction the sort indicator should indicate"),
302 303
                                                      GTK_TYPE_SORT_TYPE,
                                                      GTK_SORT_ASCENDING,
304
                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
Havoc Pennington's avatar
Havoc Pennington committed
305
  
306 307 308 309 310 311
}

static void
gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
{
  tree_column->button = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
312
  tree_column->xalign = 0.0;
313
  tree_column->width = 0;
314
  tree_column->requested_width = -1;
315 316
  tree_column->min_width = -1;
  tree_column->max_width = -1;
Jonathan Blandford's avatar
Jonathan Blandford committed
317
  tree_column->resized_width = 0;
318
  tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
319
  tree_column->visible = TRUE;
320
  tree_column->resizable = FALSE;
321
  tree_column->clickable = FALSE;
322
  tree_column->dirty = TRUE;
323
  tree_column->sort_order = GTK_SORT_ASCENDING;
Havoc Pennington's avatar
Havoc Pennington committed
324
  tree_column->show_sort_indicator = FALSE;
325
  tree_column->property_changed_signal = 0;
326 327
  tree_column->sort_clicked_signal = 0;
  tree_column->sort_column_changed_signal = 0;
328
  tree_column->sort_column_id = -1;
329 330
  tree_column->reorderable = FALSE;
  tree_column->maybe_reordered = FALSE;
Jonathan Blandford's avatar
Jonathan Blandford committed
331
  tree_column->use_resized_width = FALSE;
332 333 334 335 336 337
}

static void
gtk_tree_view_column_finalize (GObject *object)
{
  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
338 339 340 341 342
  GList *list;

  for (list = tree_column->cell_list; list; list = list->next)
    {
      GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
343 344 345 346 347 348 349 350

      if (info->destroy)
	{
	  GtkDestroyNotify d = info->destroy;

	  info->destroy = NULL;
	  d (info->func_data);
	}
351
      gtk_tree_view_column_clear_attributes_by_info (tree_column, info);
Manish Singh's avatar
Manish Singh committed
352
      g_object_unref (info->cell);
353 354
      g_free (info);
    }
355 356

  g_free (tree_column->title);
357 358 359
  g_list_free (tree_column->cell_list);

  if (tree_column->child)
360
    g_object_unref (tree_column->child);
361 362

  G_OBJECT_CLASS (parent_class)->finalize (object);
363 364
}

365 366 367 368
static void
gtk_tree_view_column_set_property (GObject         *object,
                                   guint            prop_id,
                                   const GValue    *value,
Tim Janik's avatar
Tim Janik committed
369
                                   GParamSpec      *pspec)
370 371 372 373 374 375 376 377 378 379 380 381
{
  GtkTreeViewColumn *tree_column;

  tree_column = GTK_TREE_VIEW_COLUMN (object);

  switch (prop_id)
    {
    case PROP_VISIBLE:
      gtk_tree_view_column_set_visible (tree_column,
                                        g_value_get_boolean (value));
      break;

Jonathan Blandford's avatar
Jonathan Blandford committed
382 383 384 385 386
    case PROP_RESIZABLE:
      gtk_tree_view_column_set_resizable (tree_column,
					  g_value_get_boolean (value));
      break;

387 388 389 390 391
    case PROP_SIZING:
      gtk_tree_view_column_set_sizing (tree_column,
                                       g_value_get_enum (value));
      break;

392 393 394
    case PROP_FIXED_WIDTH:
      gtk_tree_view_column_set_fixed_width (tree_column,
					    g_value_get_int (value));
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
      break;

    case PROP_MIN_WIDTH:
      gtk_tree_view_column_set_min_width (tree_column,
                                          g_value_get_int (value));
      break;

    case PROP_MAX_WIDTH:
      gtk_tree_view_column_set_max_width (tree_column,
                                          g_value_get_int (value));
      break;

    case PROP_TITLE:
      gtk_tree_view_column_set_title (tree_column,
                                      g_value_get_string (value));
      break;

    case PROP_CLICKABLE:
      gtk_tree_view_column_set_clickable (tree_column,
                                          g_value_get_boolean (value));
      break;

    case PROP_WIDGET:
      gtk_tree_view_column_set_widget (tree_column,
                                       (GtkWidget*) g_value_get_object (value));
      break;

Havoc Pennington's avatar
Havoc Pennington committed
422 423 424 425 426
    case PROP_ALIGNMENT:
      gtk_tree_view_column_set_alignment (tree_column,
                                          g_value_get_float (value));
      break;

427 428 429 430 431
    case PROP_REORDERABLE:
      gtk_tree_view_column_set_reorderable (tree_column,
					    g_value_get_boolean (value));
      break;

Havoc Pennington's avatar
Havoc Pennington committed
432 433 434
    case PROP_SORT_INDICATOR:
      gtk_tree_view_column_set_sort_indicator (tree_column,
                                               g_value_get_boolean (value));
435 436
      break;

Havoc Pennington's avatar
Havoc Pennington committed
437 438 439 440 441
    case PROP_SORT_ORDER:
      gtk_tree_view_column_set_sort_order (tree_column,
                                           g_value_get_enum (value));
      break;
      
442 443 444 445 446 447 448 449 450 451
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_tree_view_column_get_property (GObject         *object,
                                   guint            prop_id,
                                   GValue          *value,
Tim Janik's avatar
Tim Janik committed
452
                                   GParamSpec      *pspec)
453 454 455 456 457 458 459 460
{
  GtkTreeViewColumn *tree_column;

  tree_column = GTK_TREE_VIEW_COLUMN (object);

  switch (prop_id)
    {
    case PROP_VISIBLE:
Havoc Pennington's avatar
Havoc Pennington committed
461 462
      g_value_set_boolean (value,
                           gtk_tree_view_column_get_visible (tree_column));
463 464
      break;

Jonathan Blandford's avatar
Jonathan Blandford committed
465 466 467 468 469
    case PROP_RESIZABLE:
      g_value_set_boolean (value,
                           gtk_tree_view_column_get_resizable (tree_column));
      break;

470 471 472 473 474
    case PROP_WIDTH:
      g_value_set_int (value,
                       gtk_tree_view_column_get_width (tree_column));
      break;

475
    case PROP_SIZING:
Havoc Pennington's avatar
Havoc Pennington committed
476 477
      g_value_set_enum (value,
                        gtk_tree_view_column_get_sizing (tree_column));
478 479
      break;

480
    case PROP_FIXED_WIDTH:
Havoc Pennington's avatar
Havoc Pennington committed
481
      g_value_set_int (value,
482
                       gtk_tree_view_column_get_fixed_width (tree_column));
483 484 485
      break;

    case PROP_MIN_WIDTH:
Havoc Pennington's avatar
Havoc Pennington committed
486 487
      g_value_set_int (value,
                       gtk_tree_view_column_get_min_width (tree_column));
488 489 490
      break;

    case PROP_MAX_WIDTH:
Havoc Pennington's avatar
Havoc Pennington committed
491 492
      g_value_set_int (value,
                       gtk_tree_view_column_get_max_width (tree_column));
493 494 495
      break;

    case PROP_TITLE:
Havoc Pennington's avatar
Havoc Pennington committed
496 497
      g_value_set_string (value,
                          gtk_tree_view_column_get_title (tree_column));
498 499 500
      break;

    case PROP_CLICKABLE:
Havoc Pennington's avatar
Havoc Pennington committed
501 502
      g_value_set_boolean (value,
                           gtk_tree_view_column_get_clickable (tree_column));
503 504 505
      break;

    case PROP_WIDGET:
Havoc Pennington's avatar
Havoc Pennington committed
506 507
      g_value_set_object (value,
                          (GObject*) gtk_tree_view_column_get_widget (tree_column));
508 509
      break;

Havoc Pennington's avatar
Havoc Pennington committed
510 511 512
    case PROP_ALIGNMENT:
      g_value_set_float (value,
                         gtk_tree_view_column_get_alignment (tree_column));
513 514
      break;

515 516 517 518 519
    case PROP_REORDERABLE:
      g_value_set_boolean (value,
			   gtk_tree_view_column_get_reorderable (tree_column));
      break;

Havoc Pennington's avatar
Havoc Pennington committed
520 521 522 523 524 525 526 527 528 529
    case PROP_SORT_INDICATOR:
      g_value_set_boolean (value,
                           gtk_tree_view_column_get_sort_indicator (tree_column));
      break;

    case PROP_SORT_ORDER:
      g_value_set_enum (value,
                        gtk_tree_view_column_get_sort_order (tree_column));
      break;
      
530 531 532 533 534 535
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

536 537 538 539 540
/* Helper functions
 */

/* Button handling code
 */
541
static void
542
gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
543
{
544 545 546
  GtkTreeView *tree_view;
  GtkWidget *child;
  GtkWidget *hbox;
547

548
  tree_view = (GtkTreeView *) tree_column->tree_view;
549

550 551 552 553 554
  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
  g_return_if_fail (tree_column->button == NULL);

  gtk_widget_push_composite_child ();
  tree_column->button = gtk_button_new ();
Jonathan Blandford's avatar
Jonathan Blandford committed
555
  gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
556 557 558
  gtk_widget_pop_composite_child ();

  /* make sure we own a reference to it as well. */
559 560
  if (tree_view->priv->header_window)
    gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
561
  gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
562

Manish Singh's avatar
Manish Singh committed
563
  g_signal_connect (tree_column->button, "event",
564
		    G_CALLBACK (gtk_tree_view_column_button_event),
Manish Singh's avatar
Manish Singh committed
565 566 567 568
		    tree_column);
  g_signal_connect (tree_column->button, "clicked",
		    G_CALLBACK (gtk_tree_view_column_button_clicked),
		    tree_column);
569 570 571 572 573 574 575 576 577 578 579 580 581 582

  tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);

  hbox = gtk_hbox_new (FALSE, 2);
  tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);

  if (tree_column->child)
    child = tree_column->child;
  else
    {
      child = gtk_label_new (tree_column->title);
      gtk_widget_show (child);
    }

Manish Singh's avatar
Manish Singh committed
583
  g_signal_connect (child, "mnemonic_activate",
584
		    G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
Manish Singh's avatar
Manish Singh committed
585
		    tree_column);
586

587 588 589 590 591 592 593 594 595 596 597 598 599
  if (tree_column->xalign <= 0.5)
    gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
  else
    gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);

  gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
        
  gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
  gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);

  gtk_widget_show (hbox);
  gtk_widget_show (tree_column->alignment);
  gtk_tree_view_column_update_button (tree_column);
600 601
}

602 603 604 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 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
static void 
gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
{
  GtkWidget *hbox;
  GtkWidget *alignment;
  GtkWidget *arrow;
  GtkWidget *current_child;

  /* Create a button if necessary */
  if (tree_column->visible &&
      tree_column->button == NULL &&
      tree_column->tree_view &&
      GTK_WIDGET_REALIZED (tree_column->tree_view))
    gtk_tree_view_column_create_button (tree_column);
  
  if (! tree_column->button)
    return;

  hbox = GTK_BIN (tree_column->button)->child;
  alignment = tree_column->alignment;
  arrow = tree_column->arrow;
  current_child = GTK_BIN (alignment)->child;

  /* Set up the actual button */
  gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
		     0.5, 0.0, 0.0);
      
  if (tree_column->child)
    {
      if (current_child != tree_column->child)
	{
	  gtk_container_remove (GTK_CONTAINER (alignment),
				current_child);
	  gtk_container_add (GTK_CONTAINER (alignment),
			     tree_column->child);
	}
    }
  else 
    {
      if (current_child == NULL)
	{
	  current_child = gtk_label_new (NULL);
	  gtk_widget_show (current_child);
	  gtk_container_add (GTK_CONTAINER (alignment),
			     current_child);
	}

      g_return_if_fail (GTK_IS_LABEL (current_child));

      if (tree_column->title)
652 653
	gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
					  tree_column->title);
654
      else
655 656
	gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
					  "");
657 658 659 660
    }

  switch (tree_column->sort_order)
    {
661
    case GTK_SORT_ASCENDING:
662 663 664 665 666
      gtk_arrow_set (GTK_ARROW (arrow),
		     GTK_ARROW_DOWN,
		     GTK_SHADOW_IN);
      break;

667
    case GTK_SORT_DESCENDING:
668 669 670 671 672 673 674 675 676 677
      gtk_arrow_set (GTK_ARROW (arrow),
		     GTK_ARROW_UP,
		     GTK_SHADOW_IN);
      break;
          
    default:
      g_warning (G_STRLOC": bad sort order");
      break;
    }

678 679 680 681
  /* Put arrow on the right if the text is left-or-center justified, and on the
   * left otherwise; do this by packing boxes, so flipping text direction will
   * reverse things
   */
Manish Singh's avatar
Manish Singh committed
682
  g_object_ref (arrow);
683 684 685 686 687 688 689 690 691 692 693 694
  gtk_container_remove (GTK_CONTAINER (hbox), arrow);

  if (tree_column->xalign <= 0.5)
    {
      gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
    }
  else
    {
      gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
      /* move it to the front */
      gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
    }
Manish Singh's avatar
Manish Singh committed
695
  g_object_unref (arrow);
696 697 698 699 700 701

  if (tree_column->show_sort_indicator)
    gtk_widget_show (arrow);
  else
    gtk_widget_hide (arrow);

702 703
  /* It's always safe to hide the button.  It isn't always safe to show it, as
   * if you show it before it's realized, it'll get the wrong window. */
704 705 706 707 708 709
  if (tree_column->button &&
      tree_column->tree_view != NULL &&
      GTK_WIDGET_REALIZED (tree_column->tree_view))
    {
      if (tree_column->visible)
	{
710
	  gtk_widget_show_now (tree_column->button);
711 712
	  if (tree_column->window)
	    {
713
	      if (tree_column->resizable)
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
		{
		  gdk_window_show (tree_column->window);
		  gdk_window_raise (tree_column->window);
		}
	      else
		{
		  gdk_window_hide (tree_column->window);
		}
	    }
	}
      else
	{
	  gtk_widget_hide (tree_column->button);
	  if (tree_column->window)
	    gdk_window_hide (tree_column->window);
	}
    }
731 732
  
  if (tree_column->reorderable || tree_column->clickable)
733 734 735
    {
      GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
    }
736
  else
737 738 739
    {
      GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
      if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
740 741 742
	{
	  GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
	  if (GTK_WIDGET_TOPLEVEL (toplevel))
743 744 745
	    {
	      gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
	    }
746
	}
747
    }
748 749 750 751 752 753
  /* Queue a resize on the assumption that we always want to catch all changes
   * and columns don't change all that often.
   */
  if (GTK_WIDGET_REALIZED (tree_column->tree_view))
     gtk_widget_queue_resize (tree_column->tree_view);

754 755 756 757
}

/* Button signal handlers
 */
758 759

static gint
760 761 762
gtk_tree_view_column_button_event (GtkWidget *widget,
				   GdkEvent  *event,
				   gpointer   data)
763
{
764 765
  GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;

766 767
  g_return_val_if_fail (event != NULL, FALSE);

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
  if (event->type == GDK_BUTTON_PRESS &&
      column->reorderable)
    {
      column->maybe_reordered = TRUE;
      gdk_window_get_pointer (widget->window,
			      &column->drag_x,
			      &column->drag_y,
			      NULL);
      gtk_widget_grab_focus (widget);
    }

  if (event->type == GDK_BUTTON_RELEASE &&
      column->maybe_reordered)
    column->maybe_reordered = FALSE;

  if (event->type == GDK_MOTION_NOTIFY &&
      (column->maybe_reordered) &&
      (gtk_drag_check_threshold (widget,
				 column->drag_x,
				 column->drag_y,
				 (gint) ((GdkEventMotion *)event)->x,
				 (gint) ((GdkEventMotion *)event)->y)))
790
    {
791
      column->maybe_reordered = FALSE;
792 793 794 795
      /* this is to change our drag_x to be relative to
       * tree_view->priv->bin_window, instead of our window.
       */
      column->drag_x -= column->button->allocation.x;
796
      _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
797
      return TRUE;
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    }
  if (column->clickable == FALSE)
    {
      switch (event->type)
	{
	case GDK_BUTTON_PRESS:
	case GDK_2BUTTON_PRESS:
	case GDK_3BUTTON_PRESS:
	case GDK_MOTION_NOTIFY:
	case GDK_BUTTON_RELEASE:
	case GDK_ENTER_NOTIFY:
	case GDK_LEAVE_NOTIFY:
	  return TRUE;
	default:
	  return FALSE;
	}
814 815 816 817 818
    }
  return FALSE;
}


819 820 821
static void
gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
{
Manish Singh's avatar
Manish Singh committed
822
  g_signal_emit_by_name (data, "clicked");
Jonathan Blandford's avatar
Jonathan Blandford committed
823
}
824

825 826 827 828 829 830 831 832 833
static gboolean
gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
					gboolean   group_cycling,
					gpointer   data)
{
  GtkTreeViewColumn *column = (GtkTreeViewColumn *)data;

  g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE);

834
  GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column;
835 836 837 838 839
  if (column->clickable)
    gtk_button_clicked (GTK_BUTTON (column->button));
  else if (GTK_WIDGET_CAN_FOCUS (column->button))
    gtk_widget_grab_focus (column->button);
  else
840
    gtk_widget_grab_focus (column->tree_view);
841 842 843 844

  return TRUE;
}

Jonathan Blandford's avatar
Jonathan Blandford committed
845
static void
846
gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
Jonathan Blandford's avatar
Jonathan Blandford committed
847
					 GtkTreeViewColumn *column)
Jonathan Blandford's avatar
Jonathan Blandford committed
848
{
849
  gint sort_column_id;
850
  GtkSortType order;
Jonathan Blandford's avatar
Jonathan Blandford committed
851

852 853 854 855 856 857 858 859 860 861 862 863 864 865
  if (gtk_tree_sortable_get_sort_column_id (sortable,
					    &sort_column_id,
					    &order))
    {
      if (sort_column_id == column->sort_column_id)
	{
	  gtk_tree_view_column_set_sort_indicator (column, TRUE);
	  gtk_tree_view_column_set_sort_order (column, order);
	}
      else
	{
	  gtk_tree_view_column_set_sort_indicator (column, FALSE);
	}
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
866 867 868 869
  else
    {
      gtk_tree_view_column_set_sort_indicator (column, FALSE);
    }
Jonathan Blandford's avatar
Jonathan Blandford committed
870 871
}

872 873 874
static void
gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
			   gpointer           data)
875
{
Jonathan Blandford's avatar
Jonathan Blandford committed
876 877 878 879
  gint sort_column_id;
  GtkSortType order;
  gboolean has_sort_column;
  gboolean has_default_sort_func;
880

881
  g_return_if_fail (tree_column->tree_view != NULL);
882

Jonathan Blandford's avatar
Jonathan Blandford committed
883 884 885 886 887 888 889 890 891
  has_sort_column =
    gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
					  &sort_column_id,
					  &order);
  has_default_sort_func =
    gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));

  if (has_sort_column &&
      sort_column_id == tree_column->sort_column_id)
892
    {
Jonathan Blandford's avatar
Jonathan Blandford committed
893 894 895 896 897 898 899 900
      if (order == GTK_SORT_ASCENDING)
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
					      tree_column->sort_column_id,
					      GTK_SORT_DESCENDING);
      else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
					      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
					      GTK_SORT_ASCENDING);
901
      else
Jonathan Blandford's avatar
Jonathan Blandford committed
902 903 904
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
					      tree_column->sort_column_id,
					      GTK_SORT_ASCENDING);
905 906 907
    }
  else
    {
Jonathan Blandford's avatar
Jonathan Blandford committed
908 909 910
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
					    tree_column->sort_column_id,
					    GTK_SORT_ASCENDING);
911 912
    }
}
913

914 915 916 917 918 919 920 921 922 923 924 925

static void
gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
{
  GtkTreeModel *model;

  if (tree_column->tree_view == NULL)
    return;

  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));

  if (model == NULL)
Jonathan Blandford's avatar
Jonathan Blandford committed
926
    return;
927

928 929 930 931
  if (GTK_IS_TREE_SORTABLE (model) &&
      tree_column->sort_column_id != -1)
    {
      gint real_sort_column_id;
932
      GtkSortType real_order;
933 934

      if (tree_column->sort_column_changed_signal == 0)
935
        tree_column->sort_column_changed_signal =
Manish Singh's avatar
Manish Singh committed
936 937 938
	  g_signal_connect (model, "sort_column_changed",
			    G_CALLBACK (gtk_tree_view_model_sort_column_changed),
			    tree_column);
939
      
940 941 942 943 944 945 946
      if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
						&real_sort_column_id,
						&real_order) &&
	  (real_sort_column_id == tree_column->sort_column_id))
	{
	  gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
	  gtk_tree_view_column_set_sort_order (tree_column, real_order);
947

948 949 950 951
	  return;
	}
    }
}
952 953


954 955 956
/* Exported Private Functions.
 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
 */
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971

void
_gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
{
  GtkTreeView *tree_view;
  GdkWindowAttr attr;
  guint attributes_mask;

  tree_view = (GtkTreeView *)column->tree_view;

  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
  g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
  g_return_if_fail (tree_view->priv->header_window != NULL);
  g_return_if_fail (column->button != NULL);

972 973 974 975 976
  gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);

  if (column->visible)
    gtk_widget_show (column->button);

977 978 979 980 981 982 983 984 985 986 987
  attr.window_type = GDK_WINDOW_CHILD;
  attr.wclass = GDK_INPUT_ONLY;
  attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
  attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
  attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
  attr.event_mask = (GDK_BUTTON_PRESS_MASK |
		     GDK_BUTTON_RELEASE_MASK |
		     GDK_POINTER_MOTION_MASK |
		     GDK_POINTER_MOTION_HINT_MASK |
		     GDK_KEY_PRESS_MASK);
  attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
988 989
  attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
					    GDK_SB_H_DOUBLE_ARROW);
990 991 992 993 994 995 996 997 998
  attr.y = 0;
  attr.width = TREE_VIEW_DRAG_WIDTH;
  attr.height = tree_view->priv->header_height;

  attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
          
  column->window = gdk_window_new (tree_view->priv->header_window,
				   &attr, attributes_mask);
  gdk_window_set_user_data (column->window, tree_view);
999 1000

  gtk_tree_view_column_update_button (column);
1001 1002

  gdk_cursor_unref (attr.cursor);
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
}

void
_gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
{
  g_return_if_fail (column != NULL);
  g_return_if_fail (column->window != NULL);

  gdk_window_set_user_data (column->window, NULL);
  gdk_window_destroy (column->window);
  column->window = NULL;
}

1016 1017 1018 1019 1020
void
_gtk_tree_view_column_unset_model (GtkTreeViewColumn *column,
				   GtkTreeModel      *old_model)
{
  if (column->sort_column_changed_signal)
Manish Singh's avatar
Manish Singh committed
1021 1022 1023 1024 1025
    {
      g_signal_handler_disconnect (old_model,
				   column->sort_column_changed_signal);
      column->sort_column_changed_signal = 0;
    }
1026 1027
}

1028 1029 1030 1031
void
_gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
				     GtkTreeView       *tree_view)
{
1032
  g_assert (column->tree_view == NULL);
1033

1034 1035
  column->tree_view = GTK_WIDGET (tree_view);
  gtk_tree_view_column_create_button (column);
1036

1037
  column->property_changed_signal =
Manish Singh's avatar
Manish Singh committed
1038
	  g_signal_connect_swapped (tree_view,
1039
				    "notify::model",
Manish Singh's avatar
Manish Singh committed
1040
				    G_CALLBACK (gtk_tree_view_column_setup_sort_column_id_callback),
1041
				    column);
1042

1043
  gtk_tree_view_column_setup_sort_column_id_callback (column);
1044 1045 1046 1047 1048 1049 1050 1051 1052
}

void
_gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
{
  if (column->tree_view && column->button)
    {
      gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
    }
1053 1054
  if (column->property_changed_signal)
    {
Manish Singh's avatar
Manish Singh committed
1055
      g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1056 1057 1058 1059 1060
      column->property_changed_signal = 0;
    }

  if (column->sort_column_changed_signal)
    {
Manish Singh's avatar
Manish Singh committed
1061
      g_signal_handler_disconnect (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view)),
Jonathan Blandford's avatar
Jonathan Blandford committed
1062
				   column->sort_column_changed_signal);
1063 1064 1065
      column->sort_column_changed_signal = 0;
    }

1066 1067 1068 1069
  column->tree_view = NULL;
  column->button = NULL;
}

Kristian Rietveld's avatar
Kristian Rietveld committed
1070 1071 1072 1073 1074
gboolean
_gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
{
  GList *list;

Kristian Rietveld's avatar
Kristian Rietveld committed
1075
  for (list = column->cell_list; list; list = list->next)
Kristian Rietveld's avatar
Kristian Rietveld committed
1076 1077 1078 1079 1080 1081 1082
    if (((GtkTreeViewColumnCellInfo *)list->data)->cell->mode ==
	GTK_CELL_RENDERER_MODE_EDITABLE)
      return TRUE;

  return FALSE;
}

1083
/* gets cell being edited */
1084
GtkCellRenderer *
1085
_gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column)
1086 1087 1088
{
  GList *list;

Kristian Rietveld's avatar
Kristian Rietveld committed
1089
  for (list = column->cell_list; list; list = list->next)
1090
    if (((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode)
1091 1092 1093 1094 1095
      return ((GtkTreeViewColumnCellInfo *)list->data)->cell;

  return NULL;
}

Kristian Rietveld's avatar
Kristian Rietveld committed
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
gint
_gtk_tree_view_column_count_special_cells (GtkTreeViewColumn *column)
{
  gint i = 0;
  GList *list;

  for (list = column->cell_list; list; list = list->next)
    {
      GtkTreeViewColumnCellInfo *cellinfo = list->data;

1106 1107 1108
      if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
	  cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
	  cellinfo->cell->visible)
Kristian Rietveld's avatar
Kristian Rietveld committed
1109 1110 1111 1112 1113 1114
	i++;
    }

  return i;
}

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
GtkCellRenderer *
_gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column,
				       gint               x)
{
  GList *list;
  gint current_x = 0;

  list = gtk_tree_view_column_cell_first (column);
  for (; list; list = gtk_tree_view_column_cell_next (column, list))
   {
     GtkTreeViewColumnCellInfo *cellinfo = list->data;
     if (current_x <= x && x <= current_x + cellinfo->real_width)
       return cellinfo->cell;
     current_x += cellinfo->real_width;
   }

  return NULL;
}

1134 1135 1136
/* Public Functions */


1137 1138 1139 1140 1141 1142 1143
/**
 * gtk_tree_view_column_new:
 * 
 * Creates a new #GtkTreeViewColumn.
 * 
 * Return value: A newly created #GtkTreeViewColumn.
 **/
1144
GtkTreeViewColumn *
1145 1146
gtk_tree_view_column_new (void)
{
1147
  GtkTreeViewColumn *tree_column;
1148

Manish Singh's avatar
Manish Singh committed
1149
  tree_column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, NULL);
1150

1151
  return tree_column;
1152 1153
}

1154 1155 1156 1157
/**
 * gtk_tree_view_column_new_with_attributes:
 * @title: The title to set the header to.
 * @cell: The #GtkCellRenderer.
Matthias Clasen's avatar
Matthias Clasen committed
1158
 * @Varargs: A %NULL-terminated list of attributes.
1159 1160
 * 
 * Creates a new #GtkTreeViewColumn with a number of default values.  This is
Matthias Clasen's avatar
Matthias Clasen committed
1161 1162 1163
 * equivalent to calling gtk_tree_view_column_set_title(),
 * gtk_tree_view_column_pack_start(), and
 * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1164 1165 1166
 *
 * Here's a simple example:
 * <informalexample><programlisting>
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
 *  enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
 *  ...
 *  {
 *    GtkTreeViewColumn *column;
 *    GtkCellRenderer   *renderer = gtk_cell_renderer_text_new (<!-- -->);
 *  
 *    column = gtk_tree_view_column_new_with_attributes ("Title",
 *                                                       renderer,
 *                                                       "text", TEXT_COLUMN,
 *                                                       "foreground", COLOR_COLUMN,
 *                                                       NULL);
 *  }
1179
 * </programlisting></informalexample>
1180 1181 1182
 * 
 * Return value: A newly created #GtkTreeViewColumn.
 **/
1183
GtkTreeViewColumn *
1184
gtk_tree_view_column_new_with_attributes (const gchar     *title,
1185 1186 1187
					  GtkCellRenderer *cell,
					  ...)
{
1188
  GtkTreeViewColumn *retval;
1189 1190 1191 1192
  va_list args;

  retval = gtk_tree_view_column_new ();

1193
  gtk_tree_view_column_set_title (retval, title);
1194
  gtk_tree_view_column_pack_start (retval, cell, TRUE);
1195 1196

  va_start (args, cell);
1197
  gtk_tree_view_column_set_attributesv (retval, cell, args);
1198 1199 1200 1201 1202
  va_end (args);

  return retval;
}

1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
static GtkTreeViewColumnCellInfo *
gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
				    GtkCellRenderer   *cell_renderer)
{
  GList *list;
  for (list = tree_column->cell_list; list; list = list->next)
    if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
      return (GtkTreeViewColumnCellInfo *) list->data;
  return NULL;
}

1214

1215
/**
1216
 * gtk_tree_view_column_pack_start:
1217
 * @tree_column: A #GtkTreeViewColumn.
Matthias Clasen's avatar
Matthias Clasen committed
1218 1219
 * @cell: The #GtkCellRenderer. 
 * @expand: %TRUE if @cell is to be given extra space allocated to box.
1220
 *
1221 1222 1223
 * Packs the @cell into the beginning of the column. If @expand is FALSE, then
 * the @cell is allocated no more space than it needs. Any unused space is divided
 * evenly between cells for which @expand is TRUE.
1224 1225
 **/
void
1226 1227
gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
				 GtkCellRenderer   *cell,
1228
				 gboolean           expand)
1229 1230 1231
{
  GtkTreeViewColumnCellInfo *cell_info;

1232
  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1233 1234
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
  g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
Havoc Pennington's avatar
Havoc Pennington committed
1235

Manish Singh's avatar
Manish Singh committed
1236
  g_object_ref (cell);
1237
  gtk_object_sink (GTK_OBJECT (cell));
1238

1239 1240 1241 1242
  cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
  cell_info->cell = cell;
  cell_info->expand = expand ? TRUE : FALSE;
  cell_info->pack = GTK_PACK_START;
1243
  cell_info->has_focus = 0;
1244
  cell_info->attributes = NULL;
1245

1246 1247
  tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
}
1248

1249 1250 1251 1252 1253 1254
/**
 * gtk_tree_view_column_pack_end:
 * @tree_column: A #GtkTreeViewColumn.
 * @cell: The #GtkCellRenderer. 
 * @expand: %TRUE if @cell is to be given extra space allocated to box.
 *
1255 1256 1257
 * Adds the @cell to end of the column. If @expand is FALSE, then the @cell
 * is allocated no more space than it needs. Any unused space is divided
 * evenly between cells for which @expand is TRUE.
1258
 **/
1259
void
1260 1261
gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
			       GtkCellRenderer    *cell,
1262
			       gboolean            expand)
1263 1264
{
  GtkTreeViewColumnCellInfo *cell_info;
1265

1266 1267 1268 1269
  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
  g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));

Manish Singh's avatar
Manish Singh committed
1270
  g_object_ref (cell);
1271
  gtk_object_sink (GTK_OBJECT (cell));
1272

1273
  cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1274 1275 1276
  cell_info->cell = cell;
  cell_info->expand = expand ? TRUE : FALSE;
  cell_info->pack = GTK_PACK_END;
1277
  cell_info->has_focus = 0;
1278 1279 1280 1281 1282 1283
  cell_info->attributes = NULL;

  tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
}


Jonathan Blandford's avatar
Jonathan Blandford committed
1284 1285 1286 1287 1288 1289
/**
 * gtk_tree_view_column_clear:
 * @tree_column: A #GtkTreeViewColumn
 * 
 * Unsets all the mappings on all renderers on the @tree_column.
 **/
1290
void
1291
gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1292 1293 1294 1295 1296
{
  GList *list;
  g_return_if_fail (tree_column != NULL);

  for (list = tree_column->cell_list; list; list = list->next)
1297
    {
1298 1299 1300
      GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;

      gtk_tree_view_column_clear_attributes (tree_column, info->cell);
Manish Singh's avatar
Manish Singh committed
1301
      g_object_unref (info->cell);
1302
      g_free (info);
1303 1304
    }

1305 1306
  g_list_free (tree_column->cell_list);
  tree_column->cell_list = NULL;
1307 1308
}

Jonathan Blandford's avatar
Jonathan Blandford committed
1309 1310 1311 1312
/**
 * gtk_tree_view_column_get_cell_renderers:
 * @tree_column: A #GtkTreeViewColumn
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1313 1314
 * Returns a newly-allocated #GList of all the cell renderers in the column, 
 * in no particular order.  The list must be freed with g_list_free().
Jonathan Blandford's avatar
Jonathan Blandford committed
1315 1316 1317
 * 
 * Return value: A list of #GtkCellRenderers
 **/
1318 1319
GList *
gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
Havoc Pennington's avatar
Havoc Pennington committed
1320
{
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
  GList *retval = NULL, *list;

  g_return_val_if_fail (tree_column != NULL, NULL);

  for (list = tree_column->cell_list; list; list = list->next)
    {
      GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;

      retval = g_list_append (retval, info->cell);
    }

  return retval;
Havoc Pennington's avatar
Havoc Pennington committed
1333 1334
}

1335 1336 1337
/**
 * gtk_tree_view_column_add_attribute:
 * @tree_column: A #GtkTreeViewColumn.
1338 1339
 * @cell_renderer: the #GtkCellRenderer to set attributes on
 * @attribute: An attribute on the renderer
1340 1341 1342
 * @column: The column position on the model to get the attribute from.
 * 
 * Adds an attribute mapping to the list in @tree_column.  The @column is the
1343 1344 1345 1346 1347
 * column of the model to get a value from, and the @attribute is the
 * parameter on @cell_renderer to be set from the value. So for example
 * if column 2 of the model contains strings, you could have the
 * "text" attribute of a #GtkCellRendererText get its values from
 * column 2.
1348
 **/
1349 1350
void
gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1351
				    GtkCellRenderer   *cell_renderer,
1352
				    const gchar       *attribute,
1353 1354
				    gint               column)
{
1355 1356
  GtkTreeViewColumnCellInfo *info;