gtkcellview.c 48.7 KB
Newer Older
1 2 3
/* gtkellview.c
 * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
 *
4 5 6 7
 * 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.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10 11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Library General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17
 */

18
#include "config.h"
19
#include <string.h>
Kristian Rietveld's avatar
Kristian Rietveld committed
20 21
#include "gtkcellview.h"
#include "gtkcelllayout.h"
22
#include "gtkcellareabox.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
23 24 25
#include "gtkintl.h"
#include "gtkcellrenderertext.h"
#include "gtkcellrendererpixbuf.h"
26
#include "gtkprivate.h"
27
#include "gtkorientableprivate.h"
28
#include "gtkrender.h"
29 30
#include "gtkcsscustomgadgetprivate.h"
#include "gtkwidgetprivate.h"
31
#include <gobject/gmarshal.h>
32
#include "gtkbuildable.h"
33

34

35 36 37 38 39
/**
 * SECTION:gtkcellview
 * @Short_description: A widget displaying a single row of a GtkTreeModel
 * @Title: GtkCellView
 *
40 41 42 43
 * A #GtkCellView displays a single row of a #GtkTreeModel using a #GtkCellArea
 * and #GtkCellAreaContext. A #GtkCellAreaContext can be provided to the 
 * #GtkCellView at construction time in order to keep the cellview in context
 * of a group of cell views, this ensures that the renderers displayed will
44 45
 * be properly aligned with eachother (like the aligned cells in the menus
 * of #GtkComboBox).
46 47
 *
 * #GtkCellView is #GtkOrientable in order to decide in which orientation
48 49
 * the underlying #GtkCellAreaContext should be allocated. Taking the #GtkComboBox
 * menu as an example, cellviews should be oriented horizontally if the menus are
50 51 52
 * listed top-to-bottom and thus all share the same width but may have separate
 * individual heights (left-to-right menus should be allocated vertically since
 * they all share the same height but may have variable widths).
53 54 55 56
 *
 * # CSS nodes
 *
 * GtkCellView has a single CSS node with name cellview.
57 58
 */

59 60
static void        gtk_cell_view_constructed              (GObject          *object);
static void        gtk_cell_view_get_property             (GObject          *object,
61 62 63 64 65 66 67 68
                                                           guint             param_id,
                                                           GValue           *value,
                                                           GParamSpec       *pspec);
static void        gtk_cell_view_set_property             (GObject          *object,
                                                           guint             param_id,
                                                           const GValue     *value,
                                                           GParamSpec       *pspec);
static void        gtk_cell_view_finalize                 (GObject          *object);
69
static void        gtk_cell_view_dispose                  (GObject          *object);
70 71
static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
                                                           GtkAllocation    *allocation);
72 73
static gboolean    gtk_cell_view_draw                     (GtkWidget        *widget,
                                                           cairo_t          *cr);
74 75 76 77
static void        gtk_cell_view_set_value                (GtkCellView     *cell_view,
                                                           GtkCellRenderer *renderer,
                                                           gchar           *property,
                                                           GValue          *value);
78
static void        gtk_cell_view_set_cell_data            (GtkCellView      *cell_view);
79

80 81
/* celllayout */
static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
82
static GtkCellArea *gtk_cell_view_cell_layout_get_area         (GtkCellLayout         *layout);
83

84

85 86 87 88 89 90 91 92 93 94 95 96 97 98
/* buildable */
static void       gtk_cell_view_buildable_init                 (GtkBuildableIface     *iface);
static gboolean   gtk_cell_view_buildable_custom_tag_start     (GtkBuildable  	      *buildable,
								GtkBuilder    	      *builder,
								GObject       	      *child,
								const gchar   	      *tagname,
								GMarkupParser 	      *parser,
								gpointer      	      *data);
static void       gtk_cell_view_buildable_custom_tag_end       (GtkBuildable  	      *buildable,
								GtkBuilder    	      *builder,
								GObject       	      *child,
								const gchar   	      *tagname,
								gpointer      	      *data);

99
static GtkSizeRequestMode gtk_cell_view_get_request_mode       (GtkWidget             *widget);
100
static void       gtk_cell_view_get_preferred_width            (GtkWidget             *widget,
101 102
								gint                  *minimum_size,
								gint                  *natural_size);
103
static void       gtk_cell_view_get_preferred_height           (GtkWidget             *widget,
104 105
								gint                  *minimum_size,
								gint                  *natural_size);
106
static void       gtk_cell_view_get_preferred_width_for_height (GtkWidget             *widget,
107 108 109
								gint                   avail_size,
								gint                  *minimum_size,
								gint                  *natural_size);
110
static void       gtk_cell_view_get_preferred_height_for_width (GtkWidget             *widget,
111 112 113 114
								gint                   avail_size,
								gint                  *minimum_size,
								gint                  *natural_size);

115 116 117
static void       context_size_changed_cb                      (GtkCellAreaContext   *context,
								GParamSpec           *pspec,
								GtkWidget            *view);
118 119 120 121
static void       row_changed_cb                               (GtkTreeModel         *model,
								GtkTreePath          *path,
								GtkTreeIter          *iter,
								GtkCellView          *view);
122

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
static void     gtk_cell_view_measure  (GtkCssGadget        *gadget,
                                        GtkOrientation       orientation,
                                        int                  for_size,
                                        int                 *minimum,
                                        int                 *natural,
                                        int                 *minimum_baseline,
                                        int                 *natural_baseline,
                                        gpointer             data);
static void     gtk_cell_view_allocate (GtkCssGadget        *gadget,
                                        const GtkAllocation *allocation,
                                        int                  baseline,
                                        GtkAllocation       *out_clip,
                                        gpointer             data);
static gboolean gtk_cell_view_render   (GtkCssGadget        *gadget,
                                        cairo_t             *cr,
                                        int                  x,
                                        int                  y,
                                        int                  width,
                                        int                  height,
                                        gpointer             data);
143 144 145 146 147 148 149 150 151

struct _GtkCellViewPrivate
{
  GtkTreeModel        *model;
  GtkTreeRowReference *displayed_row;

  GtkCellArea         *area;
  GtkCellAreaContext  *context;

152 153
  GtkCssGadget        *gadget;

154 155 156 157 158
  GdkRGBA              background;

  gulong               size_changed_id;
  gulong               row_changed_id;

159 160 161 162 163
  GtkOrientation       orientation;

  guint                background_set : 1;
  guint                draw_sensitive : 1;
  guint                fit_model      : 1;
164 165
};

166 167
static GtkBuildableIface *parent_buildable_iface;

168 169 170
enum
{
  PROP_0,
171
  PROP_ORIENTATION,
172 173
  PROP_BACKGROUND,
  PROP_BACKGROUND_GDK,
174
  PROP_BACKGROUND_RGBA,
175
  PROP_BACKGROUND_SET,
176 177
  PROP_MODEL,
  PROP_CELL_AREA,
178 179 180
  PROP_CELL_AREA_CONTEXT,
  PROP_DRAW_SENSITIVE,
  PROP_FIT_MODEL
181 182
};

183 184
G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET,
                         G_ADD_PRIVATE (GtkCellView)
Matthias Clasen's avatar
Matthias Clasen committed
185
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
186 187
						gtk_cell_view_cell_layout_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
188
						gtk_cell_view_buildable_init)
189
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
190

191 192 193
static void
gtk_cell_view_class_init (GtkCellViewClass *klass)
{
194
  GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
195 196
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

197
  gobject_class->constructed = gtk_cell_view_constructed;
198 199 200
  gobject_class->get_property = gtk_cell_view_get_property;
  gobject_class->set_property = gtk_cell_view_set_property;
  gobject_class->finalize = gtk_cell_view_finalize;
201
  gobject_class->dispose = gtk_cell_view_dispose;
202

203 204
  widget_class->draw                           = gtk_cell_view_draw;
  widget_class->size_allocate                  = gtk_cell_view_size_allocate;
205
  widget_class->get_request_mode               = gtk_cell_view_get_request_mode;
206 207 208 209
  widget_class->get_preferred_width            = gtk_cell_view_get_preferred_width;
  widget_class->get_preferred_height           = gtk_cell_view_get_preferred_height;
  widget_class->get_preferred_width_for_height = gtk_cell_view_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = gtk_cell_view_get_preferred_height_for_width;
210 211

  /* properties */
212 213
  g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");

214 215 216
  g_object_class_install_property (gobject_class,
                                   PROP_BACKGROUND,
                                   g_param_spec_string ("background",
217 218
                                                        P_("Background color name"),
                                                        P_("Background color as a string"),
219
                                                        NULL,
220
                                                        GTK_PARAM_WRITABLE));
221 222

  /**
223
   * GtkCellView:background-gdk:
224 225 226 227 228
   *
   * The background color as a #GdkColor
   *
   * Deprecated: 3.4: Use #GtkCellView:background-rgba instead.
   */
Matthias Clasen's avatar
Matthias Clasen committed
229
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
230 231
  g_object_class_install_property (gobject_class,
                                   PROP_BACKGROUND_GDK,
232
                                   g_param_spec_boxed ("background-gdk",
233 234
                                                      P_("Background color"),
                                                      P_("Background color as a GdkColor"),
235
                                                      GDK_TYPE_COLOR,
236
                                                      GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
Matthias Clasen's avatar
Matthias Clasen committed
237
G_GNUC_END_IGNORE_DEPRECATIONS
238
  /**
239
   * GtkCellView:background-rgba:
240 241 242 243 244 245 246 247 248 249 250 251
   *
   * The background color as a #GdkRGBA
   *
   * Since: 3.0
   */
  g_object_class_install_property (gobject_class,
                                   PROP_BACKGROUND_RGBA,
                                   g_param_spec_boxed ("background-rgba",
                                                      P_("Background RGBA color"),
                                                      P_("Background color as a GdkRGBA"),
                                                      GDK_TYPE_RGBA,
                                                      GTK_PARAM_READWRITE));
252

253
  /**
254
   * GtkCellView:model:
255 256 257 258 259 260 261 262 263 264 265 266
   *
   * The model for cell view
   *
   * since 2.10
   */
  g_object_class_install_property (gobject_class,
				   PROP_MODEL,
				   g_param_spec_object  ("model",
							 P_("CellView model"),
							 P_("The model for cell view"),
							 GTK_TYPE_TREE_MODEL,
							 GTK_PARAM_READWRITE));
267 268 269


  /**
270
   * GtkCellView:cell-area:
271 272 273
   *
   * The #GtkCellArea rendering cells
   *
274 275 276
   * If no area is specified when creating the cell view with gtk_cell_view_new_with_context() 
   * a horizontally oriented #GtkCellAreaBox will be used.
   *
277 278 279 280 281 282 283 284 285 286 287
   * since 3.0
   */
   g_object_class_install_property (gobject_class,
                                    PROP_CELL_AREA,
                                    g_param_spec_object ("cell-area",
							 P_("Cell Area"),
							 P_("The GtkCellArea used to layout cells"),
							 GTK_TYPE_CELL_AREA,
							 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

  /**
288
   * GtkCellView:cell-area-context:
289 290 291
   *
   * The #GtkCellAreaContext used to compute the geometry of the cell view.
   *
292 293 294 295
   * A group of cell views can be assigned the same context in order to
   * ensure the sizes and cell alignments match across all the views with
   * the same context.
   *
296
   * #GtkComboBox menus uses this to assign the same context to all cell views
297
   * in the menu items for a single menu (each submenu creates its own
298 299 300
   * context since the size of each submenu does not depend on parent
   * or sibling menus).
   *
301 302 303
   * since 3.0
   */
   g_object_class_install_property (gobject_class,
304
                                    PROP_CELL_AREA_CONTEXT,
305 306 307 308 309 310 311
                                    g_param_spec_object ("cell-area-context",
							 P_("Cell Area Context"),
							 P_("The GtkCellAreaContext used to "
							    "compute the geometry of the cell view"),
							 GTK_TYPE_CELL_AREA_CONTEXT,
							 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

312
  /**
313
   * GtkCellView:draw-sensitive:
314 315 316 317 318 319 320 321 322 323 324 325 326 327
   *
   * Whether all cells should be draw as sensitive for this view regardless
   * of the actual cell properties (used to make menus with submenus appear
   * sensitive when the items in submenus might be insensitive).
   *
   * since 3.0
   */
   g_object_class_install_property (gobject_class,
                                    PROP_DRAW_SENSITIVE,
                                    g_param_spec_boolean ("draw-sensitive",
							  P_("Draw Sensitive"),
							  P_("Whether to force cells to be drawn in a "
							     "sensitive state"),
							  FALSE,
328
							  GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
329 330

  /**
331
   * GtkCellView:fit-model:
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
   *
   * Whether the view should request enough space to always fit
   * the size of every row in the model (used by the combo box to
   * ensure the combo box size doesnt change when different items
   * are selected).
   *
   * since 3.0
   */
   g_object_class_install_property (gobject_class,
                                    PROP_FIT_MODEL,
                                    g_param_spec_boolean ("fit-model",
							  P_("Fit Model"),
							  P_("Whether to request enough space for "
							     "every row in the model"),
							  FALSE,
347
							  GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
348

349
  
350
#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
351

352
  ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
353 354
                P_("Background set"),
                P_("Whether this tag affects the background color"));
355 356

  gtk_widget_class_set_css_name (widget_class, "cellview");
357 358
}

359 360 361 362
static void
gtk_cell_view_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
363
  iface->add_child = _gtk_cell_layout_buildable_add_child;
364 365 366 367
  iface->custom_tag_start = gtk_cell_view_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_cell_view_buildable_custom_tag_end;
}

368 369 370
static void
gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
{
371 372 373
  iface->get_area = gtk_cell_view_cell_layout_get_area;
}

374 375
static void
gtk_cell_view_constructed (GObject *object)
376
{
377 378
  GtkCellView *view = GTK_CELL_VIEW (object);
  GtkCellViewPrivate *priv = view->priv;
379

380
  G_OBJECT_CLASS (gtk_cell_view_parent_class)->constructed (object);
381

382
  if (!priv->area)
383
    {
384 385
      priv->area = gtk_cell_area_box_new ();
      g_object_ref_sink (priv->area);
386 387
    }

388 389
  if (!priv->context)
    priv->context = gtk_cell_area_create_context (priv->area);
390

391
  priv->size_changed_id =
392 393
    g_signal_connect (priv->context, "notify",
		      G_CALLBACK (context_size_changed_cb), view);
394 395
}

396 397 398 399 400 401 402 403 404 405
static void
gtk_cell_view_get_property (GObject    *object,
                            guint       param_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  GtkCellView *view = GTK_CELL_VIEW (object);

  switch (param_id)
    {
406 407 408
    case PROP_ORIENTATION:
      g_value_set_enum (value, view->priv->orientation);
      break;
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    case PROP_BACKGROUND_GDK:
      {
	GdkColor color;
	
	color.red = (guint) (view->priv->background.red * 65535);
	color.green = (guint) (view->priv->background.green * 65535);
	color.blue = (guint) (view->priv->background.blue * 65535);
	color.pixel = 0;
	
	g_value_set_boxed (value, &color);
      }
      break;
    case PROP_BACKGROUND_RGBA:
      g_value_set_boxed (value, &view->priv->background);
      break;
    case PROP_BACKGROUND_SET:
      g_value_set_boolean (value, view->priv->background_set);
      break;
    case PROP_MODEL:
      g_value_set_object (value, view->priv->model);
      break;
    case PROP_CELL_AREA:
      g_value_set_object (value, view->priv->area);
      break;
    case PROP_CELL_AREA_CONTEXT:
      g_value_set_object (value, view->priv->context);
      break;
    case PROP_DRAW_SENSITIVE:
      g_value_set_boolean (value, view->priv->draw_sensitive);
      break;
    case PROP_FIT_MODEL:
      g_value_set_boolean (value, view->priv->fit_model);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
      break;
445 446 447 448 449 450 451 452 453 454
    }
}

static void
gtk_cell_view_set_property (GObject      *object,
                            guint         param_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
  GtkCellView *view = GTK_CELL_VIEW (object);
455
  GtkCellViewPrivate *priv = view->priv;
456 457
  GtkCellArea *area;
  GtkCellAreaContext *context;
458 459 460

  switch (param_id)
    {
461
    case PROP_ORIENTATION:
462 463 464 465 466 467 468 469
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
          if (priv->context)
            gtk_cell_area_context_reset (priv->context);
          _gtk_orientable_set_style_classes (GTK_ORIENTABLE (object));
          g_object_notify_by_pspec (object, pspec);
        }
470
      break;
471 472
    case PROP_BACKGROUND:
      {
473 474
        GdkRGBA color;

475
	if (!g_value_get_string (value))
476 477 478
          gtk_cell_view_set_background_rgba (view, NULL);
	else if (gdk_rgba_parse (&color, g_value_get_string (value)))
          gtk_cell_view_set_background_rgba (view, &color);
479
	else
480
	  g_warning ("Don't know color '%s'", g_value_get_string (value));
481 482 483

        g_object_notify (object, "background-rgba");
        g_object_notify (object, "background-gdk");
484 485 486
      }
      break;
    case PROP_BACKGROUND_GDK:
487 488 489 490 491 492 493 494 495 496 497 498 499
      {
        GdkColor *color;
        GdkRGBA rgba;

        color = g_value_get_boxed (value);

        rgba.red = color->red / 65535.0;
        rgba.green = color->green / 65535.0;
        rgba.blue = color->blue / 65535.0;
        rgba.alpha = 1.0;

        gtk_cell_view_set_background_rgba (view, &rgba);
      }
500 501 502 503 504 505 506 507 508 509
      break;
    case PROP_BACKGROUND_RGBA:
      gtk_cell_view_set_background_rgba (view, g_value_get_boxed (value));
      break;
    case PROP_BACKGROUND_SET:
      view->priv->background_set = g_value_get_boolean (value);
      break;
    case PROP_MODEL:
      gtk_cell_view_set_model (view, g_value_get_object (value));
      break;
510 511 512
    case PROP_CELL_AREA:
      /* Construct-only, can only be assigned once */
      area = g_value_get_object (value);
513

514
      if (area)
515 516 517 518 519 520 521 522 523 524
        {
          if (priv->area != NULL)
            {
              g_warning ("cell-area has already been set, ignoring construct property");
              g_object_ref_sink (area);
              g_object_unref (area);
            }
          else
            priv->area = g_object_ref_sink (area);
        }
525 526 527 528
      break;
    case PROP_CELL_AREA_CONTEXT:
      /* Construct-only, can only be assigned once */
      context = g_value_get_object (value);
529

530
      if (context)
531 532 533 534 535 536 537 538 539 540
        {
          if (priv->context != NULL)
            {
              g_warning ("cell-area-context has already been set, ignoring construct property");
              g_object_ref_sink (context);
              g_object_unref (context);
            }
          else
            priv->context = g_object_ref (context);
        }
541 542
      break;

543 544 545 546 547 548 549 550
    case PROP_DRAW_SENSITIVE:
      gtk_cell_view_set_draw_sensitive (view, g_value_get_boolean (value));
      break;

    case PROP_FIT_MODEL:
      gtk_cell_view_set_fit_model (view, g_value_get_boolean (value));
      break;

551
    default:
552 553 554 555 556 557 558 559
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
        break;
    }
}

static void
gtk_cell_view_init (GtkCellView *cellview)
{
560 561
  GtkCssNode *widget_node;

562 563
  cellview->priv = gtk_cell_view_get_instance_private (cellview);
  cellview->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
564

565
  gtk_widget_set_has_window (GTK_WIDGET (cellview), FALSE);
566 567 568 569 570 571 572 573 574

  widget_node = gtk_widget_get_css_node (GTK_WIDGET (cellview));
  cellview->priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
                                                               GTK_WIDGET (cellview),
                                                               gtk_cell_view_measure,
                                                               gtk_cell_view_allocate,
                                                               gtk_cell_view_render,
                                                               NULL,
                                                               NULL);
575 576 577 578 579
}

static void
gtk_cell_view_finalize (GObject *object)
{
580 581 582 583
  GtkCellView *cellview = GTK_CELL_VIEW (object);

  if (cellview->priv->displayed_row)
     gtk_tree_row_reference_free (cellview->priv->displayed_row);
584

585 586
  g_clear_object (&cellview->priv->gadget);

587
  G_OBJECT_CLASS (gtk_cell_view_parent_class)->finalize (object);
588 589 590
}

static void
591
gtk_cell_view_dispose (GObject *object)
592
{
593
  GtkCellView *cellview = GTK_CELL_VIEW (object);
594

595
  gtk_cell_view_set_model (cellview, NULL);
596

597
  if (cellview->priv->area)
598
    {
599 600
      g_object_unref (cellview->priv->area);
      cellview->priv->area = NULL;
601
    }
602

603
  if (cellview->priv->context)
604
    {
605 606
      g_signal_handler_disconnect (cellview->priv->context, cellview->priv->size_changed_id);

607 608
      g_object_unref (cellview->priv->context);
      cellview->priv->context = NULL;
609
      cellview->priv->size_changed_id = 0;
610
    }
611

612 613
  G_OBJECT_CLASS (gtk_cell_view_parent_class)->dispose (object);
}
614

615
static void
616 617
gtk_cell_view_size_allocate (GtkWidget     *widget,
                             GtkAllocation *allocation)
618
{
619 620 621 622 623 624 625 626 627 628
  GtkAllocation clip;

  gtk_widget_set_allocation (widget, allocation);

  gtk_css_gadget_allocate (GTK_CELL_VIEW (widget)->priv->gadget,
                           allocation,
                           gtk_widget_get_allocated_baseline (widget),
                           &clip);

  gtk_widget_set_clip (widget, &clip);
629 630
}

631
static void
632 633 634 635 636
gtk_cell_view_allocate (GtkCssGadget        *gadget,
                        const GtkAllocation *allocation,
                        int                  baseline,
                        GtkAllocation       *out_clip,
                        gpointer             data)
637
{
638 639 640 641
  GtkWidget *widget;
  GtkCellView *cellview;
  GtkCellViewPrivate *priv;
  gint alloc_width, alloc_height, width, height;
642

643 644 645
  widget = gtk_css_gadget_get_owner (gadget);
  cellview = GTK_CELL_VIEW (widget);
  priv = cellview->priv;
646

647 648
  width = allocation->width;
  height = allocation->height;
649

650
  gtk_cell_area_context_get_allocation (priv->context, &alloc_width, &alloc_height);
651

652 653 654
  /* The first cell view in context is responsible for allocating the context at
   * allocate time (or the cellview has its own context and is not grouped with
   * any other cell views)
655
   *
656 657
   * If the cellview is in "fit model" mode, we assume it's not in context and
   * needs to allocate every time.
658
   */
659
  if (priv->fit_model)
660
    gtk_cell_area_context_allocate (priv->context, width, height);
661
  else if (alloc_width != allocation->width && priv->orientation == GTK_ORIENTATION_HORIZONTAL)
662
    gtk_cell_area_context_allocate (priv->context, width, -1);
663
  else if (alloc_height != allocation->height && priv->orientation == GTK_ORIENTATION_VERTICAL)
664
    gtk_cell_area_context_allocate (priv->context, -1, height);
665 666

  *out_clip = *allocation;
667 668
}

669 670 671 672 673 674 675 676 677 678 679 680
static void
gtk_cell_view_request_model (GtkCellView        *cellview,
			     GtkTreeIter        *parent,
			     GtkOrientation      orientation,
			     gint                for_size,
			     gint               *minimum_size,
			     gint               *natural_size)
{
  GtkCellViewPrivate *priv = cellview->priv;
  GtkTreeIter         iter;
  gboolean            valid;

681 682 683
  if (!priv->model)
    return;

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
  valid = gtk_tree_model_iter_children (priv->model, &iter, parent);
  while (valid)
    {
      gint min, nat;

      gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE);

      if (orientation == GTK_ORIENTATION_HORIZONTAL)
	{
	  if (for_size < 0)
	    gtk_cell_area_get_preferred_width (priv->area, priv->context, 
					       GTK_WIDGET (cellview), &min, &nat);
	  else
	    gtk_cell_area_get_preferred_width_for_height (priv->area, priv->context, 
							  GTK_WIDGET (cellview), for_size, &min, &nat);
	}
      else
	{
	  if (for_size < 0)
	    gtk_cell_area_get_preferred_height (priv->area, priv->context, 
						GTK_WIDGET (cellview), &min, &nat);
	  else
	    gtk_cell_area_get_preferred_height_for_width (priv->area, priv->context, 
							  GTK_WIDGET (cellview), for_size, &min, &nat);
	}

      *minimum_size = MAX (min, *minimum_size);
      *natural_size = MAX (nat, *natural_size);

      /* Recurse into children when they exist */
      gtk_cell_view_request_model (cellview, &iter, orientation, for_size, minimum_size, natural_size);

      valid = gtk_tree_model_iter_next (priv->model, &iter);
    }
}

720 721 722 723 724 725 726 727 728
static GtkSizeRequestMode 
gtk_cell_view_get_request_mode (GtkWidget *widget)
{
  GtkCellView        *cellview = GTK_CELL_VIEW (widget);
  GtkCellViewPrivate *priv = cellview->priv;

  return gtk_cell_area_get_request_mode (priv->area);
}

729
static void
730 731 732
gtk_cell_view_get_preferred_width (GtkWidget *widget,
                                   gint      *minimum,
                                   gint      *natural)
733
{
734 735 736 737 738 739
  gtk_css_gadget_get_preferred_size (GTK_CELL_VIEW (widget)->priv->gadget,
                                     GTK_ORIENTATION_HORIZONTAL,
                                     -1,
                                     minimum, natural,
                                     NULL, NULL);
}
740

741 742 743 744 745 746 747 748 749 750 751
static void
gtk_cell_view_get_preferred_width_for_height (GtkWidget *widget,
                                              gint       height,
                                              gint      *minimum,
                                              gint      *natural)
{
  gtk_css_gadget_get_preferred_size (GTK_CELL_VIEW (widget)->priv->gadget,
                                     GTK_ORIENTATION_HORIZONTAL,
                                     height,
                                     minimum, natural,
                                     NULL, NULL);
752 753
}

754
static void
755
gtk_cell_view_get_preferred_height (GtkWidget *widget,
756 757
                                    gint      *minimum,
                                    gint      *natural)
758
{
759 760 761 762 763 764
  gtk_css_gadget_get_preferred_size (GTK_CELL_VIEW (widget)->priv->gadget,
                                     GTK_ORIENTATION_VERTICAL,
                                     -1,
                                     minimum, natural,
                                     NULL, NULL);
}
765

766 767 768 769 770 771 772 773 774 775 776
static void
gtk_cell_view_get_preferred_height_for_width (GtkWidget *widget,
                                              gint       width,
                                              gint      *minimum,
                                              gint      *natural)
{
  gtk_css_gadget_get_preferred_size (GTK_CELL_VIEW (widget)->priv->gadget,
                                     GTK_ORIENTATION_VERTICAL,
                                     width,
                                     minimum, natural,
                                     NULL, NULL);
777 778
}

779 780 781 782 783 784 785 786 787
static void
gtk_cell_view_measure (GtkCssGadget   *gadget,
                       GtkOrientation  orientation,
                       int             for_size,
                       int            *minimum,
                       int            *natural,
                       int            *minimum_baseline,
                       int            *natural_baseline,
                       gpointer        data)
788
{
789 790 791
  GtkWidget *widget;
  GtkCellView *cellview;
  GtkCellViewPrivate *priv;
792

793 794 795
  widget = gtk_css_gadget_get_owner (gadget);
  cellview = GTK_CELL_VIEW (widget);
  priv = cellview->priv;
796

797
  g_signal_handler_block (priv->context, priv->size_changed_id);
798

799
  if (orientation == GTK_ORIENTATION_HORIZONTAL && for_size == -1)
800
    {
801 802 803 804 805 806 807 808 809
      if (priv->fit_model)
        {
          gint min = 0, nat = 0;
          gtk_cell_view_request_model (cellview, NULL, GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat);
        }
      else
        {
          if (cellview->priv->displayed_row)
            gtk_cell_view_set_cell_data (cellview);
810

811 812
          gtk_cell_area_get_preferred_width (priv->area, priv->context, widget, NULL, NULL);
        }
813

814 815 816 817 818 819 820 821 822 823 824 825 826
      gtk_cell_area_context_get_preferred_width (priv->context, minimum, natural);
    }
  else if (orientation == GTK_ORIENTATION_VERTICAL && for_size == -1)
    {
      if (priv->fit_model)
        {
          gint min = 0, nat = 0;
          gtk_cell_view_request_model (cellview, NULL, GTK_ORIENTATION_VERTICAL, -1, &min, &nat);
        }
      else
        {
          if (cellview->priv->displayed_row)
            gtk_cell_view_set_cell_data (cellview);
827

828 829
          gtk_cell_area_get_preferred_height (priv->area, priv->context, widget, NULL, NULL);
        }
830

831 832 833
      gtk_cell_area_context_get_preferred_height (priv->context, minimum, natural);
    }
  else if (orientation == GTK_ORIENTATION_HORIZONTAL && for_size >= 0)
834
    {
835 836 837 838 839 840 841 842 843 844 845 846
      if (priv->fit_model)
        {
          gint min = 0, nat = 0;
          gtk_cell_view_request_model (cellview, NULL, GTK_ORIENTATION_HORIZONTAL, for_size, &min, &nat);

          *minimum = min;
          *natural = nat;
        }
      else
        {
          if (cellview->priv->displayed_row)
            gtk_cell_view_set_cell_data (cellview);
847

848 849 850
          gtk_cell_area_get_preferred_width_for_height (priv->area, priv->context, widget,
                                                        for_size, minimum, natural);
        }
851 852
    }
  else
853 854 855 856 857
   {
      if (priv->fit_model)
        {
          gint min = 0, nat = 0;
          gtk_cell_view_request_model (cellview, NULL, GTK_ORIENTATION_VERTICAL, for_size, &min, &nat);
858

859 860 861 862 863 864 865 866 867 868 869
          *minimum = min;
          *natural = nat;
        }
      else
        {
          if (cellview->priv->displayed_row)
            gtk_cell_view_set_cell_data (cellview);

          gtk_cell_area_get_preferred_height_for_width (priv->area, priv->context, widget,
                                                        for_size, minimum, natural);
        }
870
    }
871

872
  g_signal_handler_unblock (priv->context, priv->size_changed_id);
873 874
}

875
static gboolean
876 877
gtk_cell_view_draw (GtkWidget *widget,
                    cairo_t   *cr)
878
{
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
  gtk_css_gadget_draw (GTK_CELL_VIEW (widget)->priv->gadget, cr);

  return FALSE;
}

static gboolean
gtk_cell_view_render (GtkCssGadget *gadget,
                      cairo_t      *cr,
                      int           x,
                      int           y,
                      int           width,
                      int           height,
                      gpointer      data)
{
  GtkWidget *widget;
894 895
  GtkCellView *cellview;
  GdkRectangle area;
896
  GtkCellRendererState state;
897

898
  widget = gtk_css_gadget_get_owner (gadget);
899 900
  cellview = GTK_CELL_VIEW (widget);

901
  /* render cells */
902 903 904 905
  area.x = x;
  area.y = y;
  area.width  = width;
  area.height = height;
906

907 908 909
  /* "blank" background */
  if (cellview->priv->background_set)
    {
910
      gdk_cairo_rectangle (cr, &area);
911
      gdk_cairo_set_source_rgba (cr, &cellview->priv->background);
912
      cairo_fill (cr);
913 914
    }

915 916 917 918
  /* set cell data (if available) */
  if (cellview->priv->displayed_row)
    gtk_cell_view_set_cell_data (cellview);
  else if (cellview->priv->model)
919
    return FALSE;
920

921
  if (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_PRELIGHT)
922 923 924
    state = GTK_CELL_RENDERER_PRELIT;
  else
    state = 0;
925

926
  /* Render the cells */
927
  gtk_cell_area_render (cellview->priv->area, cellview->priv->context,
928
			widget, cr, &area, &area, state, FALSE);
929 930 931 932

  return FALSE;
}

933
static void
934
gtk_cell_view_set_cell_data (GtkCellView *cell_view)
935 936 937 938
{
  GtkTreeIter iter;
  GtkTreePath *path;

939
  g_return_if_fail (cell_view->priv->displayed_row != NULL);
940

941
  path = gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
942 943 944
  if (!path)
    return;

945
  gtk_tree_model_get_iter (cell_view->priv->model, &iter, path);
946 947
  gtk_tree_path_free (path);

948
  gtk_cell_area_apply_attributes (cell_view->priv->area, 
949 950
				  cell_view->priv->model, 
				  &iter, FALSE, FALSE);
951 952 953 954 955 956 957 958 959 960 961 962 963 964

  if (cell_view->priv->draw_sensitive)
    {
      GList *l, *cells = 
	gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view->priv->area));

      for (l = cells; l; l = l->next)
	{
	  GObject *renderer = l->data;

	  g_object_set (renderer, "sensitive", TRUE, NULL);
	}
      g_list_free (cells);
    }
965 966 967
}

/* GtkCellLayout implementation */
968 969 970 971
static GtkCellArea *
gtk_cell_view_cell_layout_get_area (GtkCellLayout   *layout)
{
  GtkCellView *cellview = GTK_CELL_VIEW (layout);
972 973 974 975 976 977 978
  GtkCellViewPrivate *priv = cellview->priv;

  if (G_UNLIKELY (!priv->area))
    {
      priv->area = gtk_cell_area_box_new ();
      g_object_ref_sink (priv->area);
    }
Kristian Rietveld's avatar
Kristian Rietveld committed
979

980
  return priv->area;
Kristian Rietveld's avatar
Kristian Rietveld committed
981
}
982

983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
/* GtkBuildable implementation */
static gboolean
gtk_cell_view_buildable_custom_tag_start (GtkBuildable  *buildable,
					  GtkBuilder    *builder,
					  GObject       *child,
					  const gchar   *tagname,
					  GMarkupParser *parser,
					  gpointer      *data)
{
  if (parent_buildable_iface->custom_tag_start &&
      parent_buildable_iface->custom_tag_start (buildable, builder, child,
						tagname, parser, data))
    return TRUE;

  return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
						      tagname, parser, data);
}

static void
gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
					GtkBuilder   *builder,
					GObject      *child,
					const gchar  *tagname,
					gpointer     *data)
{
1008 1009 1010
  if (_gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
						 data))
    return;
1011 1012 1013 1014 1015
  else if (parent_buildable_iface->custom_tag_end)
    parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
					    data);
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
static void
context_size_changed_cb (GtkCellAreaContext  *context,
			 GParamSpec          *pspec,
			 GtkWidget           *view)
{
  if (!strcmp (pspec->name, "minimum-width") ||
      !strcmp (pspec->name, "natural-width") ||
      !strcmp (pspec->name, "minimum-height") ||
      !strcmp (pspec->name, "natural-height"))
    gtk_widget_queue_resize (view);
}

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
static void
row_changed_cb (GtkTreeModel         *model,
		GtkTreePath          *path,
		GtkTreeIter          *iter,
		GtkCellView          *view)
{
  GtkTreePath *row_path;

  if (view->priv->displayed_row)
    {
      row_path = 
	gtk_tree_row_reference_get_path (view->priv->displayed_row);

1041 1042 1043 1044
      if (row_path)
	{
	  /* Resize everything in our context if our row changed */
	  if (gtk_tree_path_compare (row_path, path) == 0)
1045
	    gtk_cell_area_context_reset (view->priv->context);
1046 1047 1048

	  gtk_tree_path_free (row_path);
	}
1049 1050
    }
}
1051

Matthias Clasen's avatar
Matthias Clasen committed
1052 1053 1054 1055 1056
/**
 * gtk_cell_view_new:
 *
 * Creates a new #GtkCellView widget.
 *
1057
 * Returns: A newly created #GtkCellView widget.
Matthias Clasen's avatar
Matthias Clasen committed
1058 1059 1060
 *
 * Since: 2.6
 */
1061 1062
GtkWidget *
gtk_cell_view_new (void)
1063
{
1064
  GtkCellView *cellview;
1065

1066
  cellview = g_object_new (gtk_cell_view_get_type (), NULL);
1067

1068 1069
  return GTK_WIDGET (cellview);
}
1070

1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084

/**
 * gtk_cell_view_new_with_context:
 * @area: the #GtkCellArea to layout cells
 * @context: the #GtkCellAreaContext in which to calculate cell geometry
 *
 * Creates a new #GtkCellView widget with a specific #GtkCellArea
 * to layout cells and a specific #GtkCellAreaContext.
 *
 * Specifying the same context for a handfull of cells lets
 * the underlying area synchronize the geometry for those cells,
 * in this way alignments with cellviews for other rows are
 * possible.
 *
1085
 * Returns: A newly created #GtkCellView widget.
1086 1087 1088 1089 1090 1091 1092
 *
 * Since: 2.6
 */
GtkWidget *
gtk_cell_view_new_with_context (GtkCellArea        *area,
				GtkCellAreaContext *context)
{
1093 1094 1095
  g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
  g_return_val_if_fail (context == NULL || GTK_IS_CELL_AREA_CONTEXT (context), NULL);

1096 1097 1098 1099 1100 1101
  return (GtkWidget *)g_object_new (GTK_TYPE_CELL_VIEW, 
				    "cell-area", area,
				    "cell-area-context", context,
				    NULL);
}

Matthias Clasen's avatar
Matthias Clasen committed
1102 1103 1104 1105 1106
/**
 * gtk_cell_view_new_with_text:
 * @text: the text to display in the cell view
 *
 * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
1107
 * to it, and makes it show @text.
Matthias Clasen's avatar
Matthias Clasen committed
1108
 *
1109
 * Returns: A newly created #GtkCellView widget.
Matthias Clasen's avatar
Matthias Clasen committed
1110 1111 1112
 *
 * Since: 2.6
 */
1113 1114 1115 1116 1117
GtkWidget *
gtk_cell_view_new_with_text (const gchar *text)
{
  GtkCellView *cellview;
  GtkCellRenderer *renderer;
Javier Jardón's avatar
Javier Jardón committed
1118
  GValue value = G_VALUE_INIT;
1119 1120 1121 1122

  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());

  renderer = gtk_cell_renderer_text_new ();
1123 1124
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
			      renderer, TRUE);
1125 1126 1127

  g_value_init (&value, G_TYPE_STRING);
  g_value_set_string (&value, text);
1128
  gtk_cell_view_set_value (cellview, renderer, "text", &value);
1129 1130 1131
  g_value_unset (&value);

  return GTK_WIDGET (cellview);
1132 1133
}

Matthias Clasen's avatar
Matthias Clasen committed
1134 1135 1136 1137 1138
/**
 * gtk_cell_view_new_with_markup:
 * @markup: the text to display in the cell view
 *
 * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
1139
 * to it, and makes it show @markup. The text can be
1140
 * marked up with the [Pango text markup language][PangoMarkupFormat].
Matthias Clasen's avatar
Matthias Clasen committed
1141
 *
1142
 * Returns: A newly created #GtkCellView widget.
Matthias Clasen's avatar
Matthias Clasen committed
1143 1144 1145
 *
 * Since: 2.6
 */
1146 1147
GtkWidget *
gtk_cell_view_new_with_markup (const gchar *markup)
1148
{
1149 1150
  GtkCellView *cellview;
  GtkCellRenderer *renderer;
Javier Jardón's avatar
Javier Jardón committed
1151
  GValue value = G_VALUE_INIT;
1152

1153
  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
1154

1155
  renderer = gtk_cell_renderer_text_new ();
1156 1157
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
			      renderer, TRUE);
1158 1159 1160

  g_value_init (&value, G_TYPE_STRING);
  g_value_set_string (&value, markup);
1161
  gtk_cell_view_set_value (cellview, renderer, "markup", &value);
1162 1163 1164 1165 1166
  g_value_unset (&value);

  return GTK_WIDGET (cellview);
}

Matthias Clasen's avatar
Matthias Clasen committed
1167 1168 1169 1170
/**
 * gtk_cell_view_new_with_pixbuf:
 * @pixbuf: the image to display in the cell view
 *
1171 1172
 * Creates a new #GtkCellView widget, adds a #GtkCellRendererPixbuf
 * to it, and makes it show @pixbuf.
Matthias Clasen's avatar
Matthias Clasen committed
1173
 *
1174
 * Returns: A newly created #GtkCellView widget.
Matthias Clasen's avatar
Matthias Clasen committed
1175 1176 1177
 *
 * Since: 2.6
 */
1178 1179 1180 1181 1182
GtkWidget *
gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
{
  GtkCellView *cellview;
  GtkCellRenderer *renderer;
Javier Jardón's avatar
Javier Jardón committed
1183
  GValue value = G_VALUE_INIT;
1184 1185 1186 1187

  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());

  renderer = gtk_cell_renderer_pixbuf_new ();
1188 1189
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
			      renderer, TRUE);
1190 1191 1192

  g_value_init (&value, GDK_TYPE_PIXBUF);
  g_value_set_object (&value, pixbuf);
1193
  gtk_cell_view_set_value (cellview, renderer, "pixbuf", &value);
1194 1195 1196
  g_value_unset (&value);

  return GTK_WIDGET (cellview);
1197 1198
}

Matthias Clasen's avatar
Matthias Clasen committed
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
/**
 * gtk_cell_view_set_value:
 * @cell_view: a #GtkCellView widget
 * @renderer: one of the renderers of @cell_view
 * @property: the name of the property of @renderer to set
 * @value: the new value to set the property to
 * 
 * Sets a property of a cell renderer of @cell_view, and
 * makes sure the display of @cell_view is updated.
 *
 * Since: 2.6
 */
1211
static void
1212
gtk_cell_view_set_value (GtkCellView     *cell_view,
1213 1214 1215 1216 1217 1218
                         GtkCellRenderer *renderer,
                         gchar           *property,
                         GValue          *value)
{
  g_object_set_property (G_OBJECT (renderer), property, value);

1219 1220 1221
  /* force resize and redraw */
  gtk_widget_queue_resize (GTK_WIDGET (cell_view));
  gtk_widget_queue_draw (GTK_WIDGET (cell_view));
1222 1223
}

Matthias Clasen's avatar
Matthias Clasen committed
1224 1225 1226
/**
 * gtk_cell_view_set_model:
 * @cell_view: a #GtkCellView
1227
 * @model: (allow-none): a #GtkTreeModel
Matthias Clasen's avatar
Matthias Clasen committed
1228 1229
 *
 * Sets the model for @cell_view.  If @cell_view already has a model
1230
 * set, it will remove it before setting the new model.  If @model is
Matthias Clasen's avatar
Matthias Clasen committed
1231 1232 1233 1234
 * %NULL, then it will unset the old model.
 *
 * Since: 2.6
 */
1235
void
1236
gtk_cell_view_set_model (GtkCellView  *cell_view,
1237 1238
                         GtkTreeModel *model)
{
1239
  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
Matthias Clasen's avatar
Matthias Clasen committed
1240
  g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
1241

1242
  if (cell_view->priv->model)
1243
    {
1244 1245 1246 1247
      g_signal_handler_disconnect (cell_view->priv->model, 
				   cell_view->priv->row_changed_id);
      cell_view->priv->row_changed_id = 0;

1248 1249 1250
      if (cell_view->priv->displayed_row)
        gtk_tree_row_reference_free (cell_view->priv->displayed_row);
      cell_view->priv->displayed_row = NULL;
1251

1252
      g_object_unref (cell_view->priv->model);
1253 1254
    }

1255
  cell_view->priv->model = model;
1256

1257
  if (cell_view->priv->model)
1258 1259 1260 1261 1262 1263 1264
    {
      g_object_ref (cell_view->priv->model);

      cell_view->priv->row_changed_id = 
	g_signal_connect (cell_view->priv->model, "row-changed",
			  G_CALLBACK (row_changed_cb), cell_view);
    }
1265 1266
}

1267 1268 1269 1270 1271 1272 1273
/**
 * gtk_cell_view_get_model:
 * @cell_view: a #GtkCellView
 *
 * Returns the model for @cell_view. If no model is used %NULL is
 * returned.
 *
1274
 * Returns: (nullable) (transfer none): a #GtkTreeModel used or %NULL
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
 *
 * Since: 2.16
 **/
GtkTreeModel *
gtk_cell_view_get_model (GtkCellView *cell_view)
{
  g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);

  return cell_view->priv->model;
}

1286 1287 1288
/**
 * gtk_cell_view_set_displayed_row:
 * @cell_view: a #GtkCellView
1289 1290
 * @path: (allow-none): a #GtkTreePath or %NULL to unset.
 *
1291 1292
 * Sets the row of the model that is currently displayed
 * by the #GtkCellView. If the path is unset, then the
1293
 * contents of the cellview “stick” at their last value;
1294 1295 1296
 * this is not normally a desired result, but may be
 * a needed intermediate state if say, the model for
 * the #GtkCellView becomes temporarily empty.
Matthias Clasen's avatar
Matthias Clasen committed
1297 1298
 *
 * Since: 2.6
1299
 **/
1300
void
1301
gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
1302 1303
                                 GtkTreePath *path)
{
1304 1305
  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
  g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
1306

1307 1308
  if (cell_view->priv->displayed_row)
    gtk_tree_row_reference_free (cell_view->priv->displayed_row);
1309

1310 1311 1312 1313 1314 1315 1316
  if (path)
    {
      cell_view->priv->displayed_row =
	gtk_tree_row_reference_new (cell_view->priv->model, path);
    }
  else
    cell_view->priv->displayed_row = NULL;
1317

1318 1319 1320
  /* force resize and redraw */
  gtk_widget_queue_resize (GTK_WIDGET (cell_view));
  gtk_widget_queue_draw (GTK_WIDGET (cell_view));
1321 1322
}

1323 1324 1325 1326 1327 1328 1329 1330
/**
 * gtk_cell_view_get_displayed_row:
 * @cell_view: a #GtkCellView
 *
 * Returns a #GtkTreePath referring to the currently 
 * displayed row. If no row is currently displayed, 
 * %NULL is returned.
 *
1331
 * Returns: (nullable) (transfer full): the currently displayed row or %NULL
1332 1333 1334
 *
 * Since: 2.6
 */
1335
GtkTreePath *
1336
gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
1337
{
1338
  g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
1339

1340
  if (!cell_view->priv->displayed_row)
1341 1342
    return NULL;

1343 1344 1345
  return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
}

Matthias Clasen's avatar
Matthias Clasen committed
1346 1347 1348 1349
/**
 * gtk_cell_view_get_size_of_row:
 * @cell_view: a #GtkCellView
 * @path: a #GtkTreePath 
1350
 * @requisition: (out): return location for the size 
Matthias Clasen's avatar
Matthias Clasen committed
1351 1352 1353 1354
 *
 * Sets @requisition to the size needed by @cell_view to display 
 * the model row pointed to by @path.
 * 
1355
 * Returns: %TRUE
Matthias Clasen's avatar
Matthias Clasen committed
1356 1357
 *
 * Since: 2.6
1358
 * 
1359 1360 1361 1362
 * Deprecated: 3.0: Combo box formerly used this to calculate the
 * sizes for cellviews, now you can achieve this by either using
 * the #GtkCellView:fit-model property or by setting the currently
 * displayed row of the #GtkCellView and using gtk_widget_get_preferred_size().
Matthias Clasen's avatar
Matthias Clasen committed
1363
 */
1364 1365 1366 1367 1368
gboolean
gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
                               GtkTreePath    *path,
                               GtkRequisition *requisition)
{
1369
  GtkTreeRowReference *tmp;
1370
  GtkRequisition req;
1371 1372 1373

  g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
  g_return_val_if_fail (path != NULL, FALSE);
1374

1375 1376 1377 1378
  tmp = cell_view->priv->displayed_row;
  cell_view->priv->displayed_row =
    gtk_tree_row_reference_new (cell_view->priv->model, path);

1379 1380
  gtk_widget_get_preferred_width (GTK_WIDGET (cell_view), &req.width, NULL);
  gtk_widget_get_preferred_height_for_width (GTK_WIDGET (cell_view), req.width, &req.height, NULL);
1381 1382 1383 1384

  gtk_tree_row_reference_free (cell_view->priv->displayed_row);
  cell_view->priv->displayed_row = tmp;

1385 1386
  if (requisition)
    *requisition = req;
1387

1388
  return TRUE;
1389 1390
}

Matthias Clasen's avatar
Matthias Clasen committed
1391 1392
/**
 * gtk_cell_view_set_background_color:
1393
 * @cell_view: a #GtkCellView
Matthias Clasen's avatar
Matthias Clasen committed
1394 1395 1396 1397 1398
 * @color: the new background color
 *
 * Sets the background color of @view.
 *
 * Since: 2.6
1399 1400
 *
 * Deprecated: 3.4: Use gtk_cell_view_set_background_rgba() instead.
Matthias Clasen's avatar
Matthias Clasen committed
1401
 */
1402
void
1403
gtk_cell_view_set_background_color (GtkCellView    *cell_view,
1404
                                    const GdkColor *color)
1405
{
1406
  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1407 1408 1409

  if (color)
    {
1410
      if (!cell_view->priv->background_set)
1411
        {
1412
          cell_view->priv->background_set = TRUE;
1413
          g_object_notify (G_OBJECT (cell_view), "background-set");