forked from AuroraMiddleware/gtk
468a1d3e7c
Added the child list to GtkCellAreaBox, added _pack_start() and _pack_end() apis to GtkCellAreaBox since they are appropriate there and implemented GtkCellLayoutIface to override the _pack_start()/end() methods (since the base GtkCellArea class simply forwards these apis to the generic ->add() api on the base class).
746 lines
22 KiB
C
746 lines
22 KiB
C
/* gtkcellarea.c
|
|
*
|
|
* Copyright (C) 2010 Openismus GmbH
|
|
*
|
|
* Authors:
|
|
* Tristan Van Berkom <tristanvb@openismus.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.
|
|
*/
|
|
|
|
#include "gtkcelllayout.h"
|
|
#include "gtkcellarea.h"
|
|
|
|
/* GObjectClass */
|
|
static void gtk_cell_area_dispose (GObject *object);
|
|
static void gtk_cell_area_finalize (GObject *object);
|
|
|
|
/* GtkCellAreaClass */
|
|
static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint width,
|
|
gint *minimum_height,
|
|
gint *natural_height);
|
|
static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint height,
|
|
gint *minimum_width,
|
|
gint *natural_width);
|
|
|
|
/* GtkCellLayoutIface */
|
|
static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
|
|
static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer,
|
|
gboolean expand);
|
|
static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
|
|
static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer,
|
|
const gchar *attribute,
|
|
gint column);
|
|
static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkCellLayoutDataFunc func,
|
|
gpointer func_data,
|
|
GDestroyNotify destroy);
|
|
static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer);
|
|
static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
gint position);
|
|
static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
|
|
|
|
/* Attribute/Cell metadata */
|
|
typedef struct {
|
|
const gchar *attribute;
|
|
gint column;
|
|
} CellAttribute;
|
|
|
|
typedef struct {
|
|
GSList *attributes;
|
|
|
|
GtkCellLayoutDataFunc func;
|
|
gpointer data;
|
|
GDestroyNotify destroy;
|
|
} CellInfo;
|
|
|
|
static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
|
|
gpointer data,
|
|
GDestroyNotify destroy);
|
|
static void cell_info_free (CellInfo *info);
|
|
static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
|
|
const gchar *attribute,
|
|
gint column);
|
|
static void cell_attribute_free (CellAttribute *attribute);
|
|
static gint cell_attribute_find (CellAttribute *cell_attribute,
|
|
const gchar *attribute);
|
|
|
|
/* Struct to pass data along while looping over
|
|
* cell renderers to apply attributes
|
|
*/
|
|
typedef struct {
|
|
GtkCellArea *area;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter *iter;
|
|
} AttributeData;
|
|
|
|
struct _GtkCellAreaPrivate
|
|
{
|
|
GHashTable *cell_info;
|
|
};
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
|
|
gtk_cell_area_cell_layout_init));
|
|
|
|
static void
|
|
gtk_cell_area_init (GtkCellArea *area)
|
|
{
|
|
GtkCellAreaPrivate *priv;
|
|
|
|
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
|
|
GTK_TYPE_CELL_AREA,
|
|
GtkCellAreaPrivate);
|
|
priv = area->priv;
|
|
|
|
priv->cell_info = g_hash_table_new_full (g_direct_hash,
|
|
g_direct_equal,
|
|
NULL,
|
|
(GDestroyNotify)cell_info_free);
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_class_init (GtkCellAreaClass *class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
/* GObjectClass */
|
|
object_class->dispose = gtk_cell_area_dispose;
|
|
object_class->finalize = gtk_cell_area_finalize;
|
|
|
|
/* general */
|
|
class->add = NULL;
|
|
class->remove = NULL;
|
|
class->forall = NULL;
|
|
class->event = NULL;
|
|
class->render = NULL;
|
|
|
|
/* geometry */
|
|
class->get_request_mode = NULL;
|
|
class->get_preferred_width = NULL;
|
|
class->get_preferred_height = NULL;
|
|
class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
|
|
class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
|
|
|
|
g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
|
|
}
|
|
|
|
/*************************************************************
|
|
* CellInfo Basics *
|
|
*************************************************************/
|
|
static CellInfo *
|
|
cell_info_new (GtkCellLayoutDataFunc func,
|
|
gpointer data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
CellInfo *info = g_slice_new (CellInfo);
|
|
|
|
info->attributes = NULL;
|
|
info->func = func;
|
|
info->data = data;
|
|
info->destroy = destroy;
|
|
|
|
return info;
|
|
}
|
|
|
|
static void
|
|
cell_info_free (CellInfo *info)
|
|
{
|
|
if (info->destroy)
|
|
info->destroy (info->data);
|
|
|
|
g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
|
|
g_slist_free (info->attributes);
|
|
|
|
g_slice_free (CellInfo, info);
|
|
}
|
|
|
|
static CellAttribute *
|
|
cell_attribute_new (GtkCellRenderer *renderer,
|
|
const gchar *attribute,
|
|
gint column)
|
|
{
|
|
GParamSpec *pspec;
|
|
|
|
/* Check if the attribute really exists and point to
|
|
* the property string installed on the cell renderer
|
|
* class (dont dup the string)
|
|
*/
|
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
|
|
|
|
if (pspec)
|
|
{
|
|
CellAttribute *cell_attribute = g_slice_new (CellAttribute);
|
|
|
|
cell_attribute->attribute = pspec->name;
|
|
cell_attribute->column = column;
|
|
|
|
return cell_attribute;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
cell_attribute_free (CellAttribute *attribute)
|
|
{
|
|
g_slice_free (CellAttribute, attribute);
|
|
}
|
|
|
|
/* GCompareFunc for g_slist_find_custom() */
|
|
static gint
|
|
cell_attribute_find (CellAttribute *cell_attribute,
|
|
const gchar *attribute)
|
|
{
|
|
return g_strcmp0 (cell_attribute->attribute, attribute);
|
|
}
|
|
|
|
/*************************************************************
|
|
* GObjectClass *
|
|
*************************************************************/
|
|
static void
|
|
gtk_cell_area_finalize (GObject *object)
|
|
{
|
|
GtkCellArea *area = GTK_CELL_AREA (object);
|
|
GtkCellAreaPrivate *priv = area->priv;
|
|
|
|
/* All cell renderers should already be removed at this point,
|
|
* just kill our hash table here.
|
|
*/
|
|
g_hash_table_destroy (priv->cell_info);
|
|
|
|
G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
|
|
}
|
|
|
|
|
|
static void
|
|
gtk_cell_area_dispose (GObject *object)
|
|
{
|
|
/* This removes every cell renderer that may be added to the GtkCellArea,
|
|
* subclasses should be breaking references to the GtkCellRenderers
|
|
* at this point.
|
|
*/
|
|
gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
|
|
|
|
G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
* GtkCellAreaClass *
|
|
*************************************************************/
|
|
static void
|
|
gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint width,
|
|
gint *minimum_height,
|
|
gint *natural_height)
|
|
{
|
|
/* If the area doesnt do height-for-width, fallback on base preferred height */
|
|
GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_height, natural_height);
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint height,
|
|
gint *minimum_width,
|
|
gint *natural_width)
|
|
{
|
|
/* If the area doesnt do width-for-height, fallback on base preferred width */
|
|
GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_width, natural_width);
|
|
}
|
|
|
|
/*************************************************************
|
|
* GtkCellLayoutIface *
|
|
*************************************************************/
|
|
static void
|
|
gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
|
|
{
|
|
iface->pack_start = gtk_cell_area_pack_default;
|
|
iface->pack_end = gtk_cell_area_pack_default;
|
|
iface->clear = gtk_cell_area_clear;
|
|
iface->add_attribute = gtk_cell_area_add_attribute;
|
|
iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
|
|
iface->clear_attributes = gtk_cell_area_clear_attributes;
|
|
iface->reorder = gtk_cell_area_reorder;
|
|
iface->get_cells = gtk_cell_area_get_cells;
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer,
|
|
gboolean expand)
|
|
{
|
|
gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_clear (GtkCellLayout *cell_layout)
|
|
{
|
|
GtkCellArea *area = GTK_CELL_AREA (cell_layout);
|
|
GList *l, *cells =
|
|
gtk_cell_layout_get_cells (cell_layout);
|
|
|
|
for (l = cells; l; l = l->next)
|
|
{
|
|
GtkCellRenderer *renderer = l->data;
|
|
gtk_cell_area_remove (area, renderer);
|
|
}
|
|
|
|
g_list_free (cells);
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer,
|
|
const gchar *attribute,
|
|
gint column)
|
|
{
|
|
gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
|
|
renderer, attribute, column);
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer,
|
|
GtkCellLayoutDataFunc func,
|
|
gpointer func_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
GtkCellArea *area = GTK_CELL_AREA (cell_layout);
|
|
GtkCellAreaPrivate *priv = area->priv;
|
|
CellInfo *info;
|
|
|
|
info = g_hash_table_lookup (priv->cell_info, renderer);
|
|
|
|
if (info)
|
|
{
|
|
if (info->destroy && info->data)
|
|
info->destroy (info->data);
|
|
|
|
if (func)
|
|
{
|
|
info->func = func;
|
|
info->data = func_data;
|
|
info->destroy = destroy;
|
|
}
|
|
else
|
|
{
|
|
info->func = NULL;
|
|
info->data = NULL;
|
|
info->destroy = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info = cell_info_new (func, func_data, destroy);
|
|
|
|
g_hash_table_insert (priv->cell_info, renderer, info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *renderer)
|
|
{
|
|
GtkCellArea *area = GTK_CELL_AREA (cell_layout);
|
|
GtkCellAreaPrivate *priv = area->priv;
|
|
CellInfo *info;
|
|
|
|
info = g_hash_table_lookup (priv->cell_info, renderer);
|
|
|
|
if (info)
|
|
{
|
|
g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
|
|
g_slist_free (info->attributes);
|
|
|
|
info->attributes = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_cell_area_reorder (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
gint position)
|
|
{
|
|
g_warning ("GtkCellLayout::reorder not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
|
|
}
|
|
|
|
static void
|
|
accum_cells (GtkCellRenderer *renderer,
|
|
GList **accum)
|
|
{
|
|
*accum = g_list_prepend (*accum, renderer);
|
|
}
|
|
|
|
static GList *
|
|
gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
|
|
{
|
|
GList *cells = NULL;
|
|
|
|
gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
|
|
(GtkCellCallback)accum_cells,
|
|
&cells);
|
|
|
|
return g_list_reverse (cells);
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
* API *
|
|
*************************************************************/
|
|
|
|
void
|
|
gtk_cell_area_add (GtkCellArea *area,
|
|
GtkCellRenderer *renderer)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->add)
|
|
class->add (area, renderer);
|
|
else
|
|
g_warning ("GtkCellAreaClass::add not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_remove (GtkCellArea *area,
|
|
GtkCellRenderer *renderer)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
GtkCellAreaPrivate *priv;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
priv = area->priv;
|
|
|
|
/* Remove any custom attributes and custom cell data func here first */
|
|
g_hash_table_remove (priv->cell_info, renderer);
|
|
|
|
if (class->remove)
|
|
class->remove (area, renderer);
|
|
else
|
|
g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_forall (GtkCellArea *area,
|
|
GtkCellCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->forall)
|
|
class->forall (area, callback, callback_data);
|
|
else
|
|
g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
gint
|
|
gtk_cell_area_event (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
GdkEvent *event,
|
|
const GdkRectangle *cell_area)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
|
|
g_return_val_if_fail (event != NULL, 0);
|
|
g_return_val_if_fail (cell_area != NULL, 0);
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->event)
|
|
return class->event (area, widget, event, cell_area);
|
|
|
|
g_warning ("GtkCellAreaClass::event not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_render (GtkCellArea *area,
|
|
cairo_t *cr,
|
|
GtkWidget *widget,
|
|
const GdkRectangle *cell_area)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (cr != NULL);
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
g_return_if_fail (cell_area != NULL);
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->render)
|
|
class->render (area, cr, widget, cell_area);
|
|
else
|
|
g_warning ("GtkCellAreaClass::render not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
/* Geometry */
|
|
GtkSizeRequestMode
|
|
gtk_cell_area_get_request_mode (GtkCellArea *area)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_val_if_fail (GTK_IS_CELL_AREA (area),
|
|
GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->get_request_mode)
|
|
return class->get_request_mode (area);
|
|
|
|
g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
|
|
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_get_preferred_width (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint *minimum_size,
|
|
gint *natural_size)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->get_preferred_width)
|
|
class->get_preferred_width (area, widget, minimum_size, natural_size);
|
|
else
|
|
g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint width,
|
|
gint *minimum_height,
|
|
gint *natural_height)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
class->get_preferred_height_for_width (area, widget, width, minimum_height, natural_height);
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_get_preferred_height (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint *minimum_size,
|
|
gint *natural_size)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
|
|
if (class->get_preferred_height)
|
|
class->get_preferred_height (area, widget, minimum_size, natural_size);
|
|
else
|
|
g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
|
|
GtkWidget *widget,
|
|
gint height,
|
|
gint *minimum_width,
|
|
gint *natural_width)
|
|
{
|
|
GtkCellAreaClass *class;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
class = GTK_CELL_AREA_GET_CLASS (area);
|
|
class->get_preferred_width_for_height (area, widget, height, minimum_width, natural_width);
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_attribute_connect (GtkCellArea *area,
|
|
GtkCellRenderer *renderer,
|
|
const gchar *attribute,
|
|
gint column)
|
|
{
|
|
GtkCellAreaPrivate *priv;
|
|
CellInfo *info;
|
|
CellAttribute *cell_attribute;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
|
|
g_return_if_fail (attribute != NULL);
|
|
|
|
priv = area->priv;
|
|
info = g_hash_table_lookup (priv->cell_info, renderer);
|
|
|
|
if (!info)
|
|
{
|
|
info = cell_info_new (NULL, NULL, NULL);
|
|
|
|
g_hash_table_insert (priv->cell_info, renderer, info);
|
|
}
|
|
else
|
|
{
|
|
GSList *node;
|
|
|
|
/* Check we are not adding the same attribute twice */
|
|
if ((node = g_slist_find_custom (info->attributes, attribute,
|
|
(GCompareFunc)cell_attribute_find)) != NULL)
|
|
{
|
|
cell_attribute = node->data;
|
|
|
|
g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
|
|
"since `%s' is already attributed to column %d",
|
|
attribute,
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)),
|
|
attribute, cell_attribute->column);
|
|
return;
|
|
}
|
|
}
|
|
|
|
cell_attribute = cell_attribute_new (renderer, attribute, column);
|
|
|
|
if (!cell_attribute)
|
|
{
|
|
g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
|
|
"since attribute does not exist",
|
|
attribute,
|
|
g_type_name (G_TYPE_FROM_INSTANCE (area)));
|
|
return;
|
|
}
|
|
|
|
info->attributes = g_slist_prepend (info->attributes, cell_attribute);
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_attribute_disconnect (GtkCellArea *area,
|
|
GtkCellRenderer *renderer,
|
|
const gchar *attribute)
|
|
{
|
|
GtkCellAreaPrivate *priv;
|
|
CellInfo *info;
|
|
CellAttribute *cell_attribute;
|
|
GSList *node;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
|
|
g_return_if_fail (attribute != NULL);
|
|
|
|
priv = area->priv;
|
|
info = g_hash_table_lookup (priv->cell_info, renderer);
|
|
|
|
if (info)
|
|
{
|
|
node = g_slist_find_custom (info->attributes, attribute,
|
|
(GCompareFunc)cell_attribute_find);
|
|
if (node)
|
|
{
|
|
cell_attribute = node->data;
|
|
|
|
cell_attribute_free (cell_attribute);
|
|
|
|
info->attributes = g_slist_delete_link (info->attributes, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
apply_cell_attributes (GtkCellRenderer *renderer,
|
|
CellInfo *info,
|
|
AttributeData *data)
|
|
{
|
|
CellAttribute *attribute;
|
|
GSList *list;
|
|
GValue value = { 0, };
|
|
|
|
/* Apply the attributes directly to the renderer */
|
|
for (list = info->attributes; list; list = list->next)
|
|
{
|
|
attribute = list->data;
|
|
|
|
gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
|
|
g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
|
|
g_value_unset (&value);
|
|
}
|
|
|
|
/* Call any GtkCellLayoutDataFunc that may have been set by the user
|
|
*/
|
|
if (info->func)
|
|
info->func (GTK_CELL_LAYOUT (data->area), renderer,
|
|
data->model, data->iter, info->data);
|
|
}
|
|
|
|
void
|
|
gtk_cell_area_apply_attributes (GtkCellArea *area,
|
|
GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkCellAreaPrivate *priv;
|
|
AttributeData data;
|
|
|
|
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
|
g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
|
|
g_return_if_fail (iter != NULL);
|
|
|
|
priv = area->priv;
|
|
|
|
/* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
|
|
* apply the data from the treemodel */
|
|
g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
|
|
}
|