From 468a1d3e7c51a7b1964ccfcc680c24a04322338e Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Sun, 24 Oct 2010 20:01:04 +0900 Subject: [PATCH] Implemented basic child list handling on GtkCellAreaBox 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). --- gtk/gtkcellarea.c | 121 +++++++++++++++--------------- gtk/gtkcellareabox.c | 174 ++++++++++++++++++++++++++++++++++++++++++- gtk/gtkcellareabox.h | 10 ++- 3 files changed, 243 insertions(+), 62 deletions(-) diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c index be474232b0..c8a2c3e71d 100644 --- a/gtk/gtkcellarea.c +++ b/gtk/gtkcellarea.c @@ -84,6 +84,8 @@ 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 @@ -145,65 +147,8 @@ gtk_cell_area_class_init (GtkCellAreaClass *class) g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate)); } - /************************************************************* - * 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 * + * CellInfo Basics * *************************************************************/ static CellInfo * cell_info_new (GtkCellLayoutDataFunc func, @@ -264,6 +209,7 @@ 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) @@ -271,6 +217,65 @@ cell_attribute_find (CellAttribute *cell_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) { diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index a635df233e..75e004a9db 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -22,6 +22,7 @@ */ #include "gtkorientable.h" +#include "gtkcelllayout.h" #include "gtkcellareabox.h" /* GObjectClass */ @@ -73,11 +74,37 @@ static void gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea gint *minimum_width, gint *natural_width); +/* GtkCellLayoutIface */ +static void gtk_cell_area_box_cell_layout_init (GtkCellLayoutIface *iface); +static void gtk_cell_area_box_layout_pack_start (GtkCellLayout *cell_layout, + GtkCellRenderer *renderer, + gboolean expand); +static void gtk_cell_area_box_layout_pack_end (GtkCellLayout *cell_layout, + GtkCellRenderer *renderer, + gboolean expand); + + +/* CellInfo metadata handling */ +typedef struct { + GtkCellRenderer *renderer; + + guint expand : 1; + guint pack : 1; +} CellInfo; + +static CellInfo *cell_info_new (GtkCellRenderer *renderer, + gboolean expand, + GtkPackType pack); +static void cell_info_free (CellInfo *info); +static gint cell_info_find (CellInfo *info, + GtkCellRenderer *renderer); + struct _GtkCellAreaBoxPrivate { GtkOrientation orientation; + GList *cells; }; enum { @@ -86,9 +113,10 @@ enum { }; G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA, + G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, + gtk_cell_area_box_cell_layout_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)); - static void gtk_cell_area_box_init (GtkCellAreaBox *box) { @@ -100,6 +128,7 @@ gtk_cell_area_box_init (GtkCellAreaBox *box) priv = box->priv; priv->orientation = GTK_ORIENTATION_HORIZONTAL; + priv->cells = NULL; } static void @@ -134,6 +163,38 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class) } +/************************************************************* + * CellInfo Basics * + *************************************************************/ +static CellInfo * +cell_info_new (GtkCellRenderer *renderer, + gboolean expand, + GtkPackType pack) +{ + CellInfo *info = g_slice_new (CellInfo); + + info->renderer = g_object_ref_sink (renderer); + info->expand = expand; + info->pack = pack; + + return info; +} + +static void +cell_info_free (CellInfo *info) +{ + g_object_unref (info->renderer); + + g_slice_free (CellInfo, info); +} + +static gint +cell_info_find (CellInfo *info, + GtkCellRenderer *renderer) +{ + return (info->renderer == renderer) ? 0 : -1; +} + /************************************************************* * GObjectClass * *************************************************************/ @@ -174,14 +235,31 @@ static void gtk_cell_area_box_add (GtkCellArea *area, GtkCellRenderer *renderer) { - + gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), + renderer, FALSE); } static void gtk_cell_area_box_remove (GtkCellArea *area, GtkCellRenderer *renderer) { + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); + GtkCellAreaBoxPrivate *priv = box->priv; + GList *node; + node = g_list_find_custom (priv->cells, renderer, + (GCompareFunc)cell_info_find); + + if (node) + { + CellInfo *info = node->data; + + cell_info_free (info); + + priv->cells = g_list_delete_link (priv->cells, node); + } + else + g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox"); } static void @@ -189,7 +267,16 @@ gtk_cell_area_box_forall (GtkCellArea *area, GtkCellCallback callback, gpointer callback_data) { + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); + GtkCellAreaBoxPrivate *priv = box->priv; + GList *list; + for (list = priv->cells; list; list = list->next) + { + CellInfo *info = list->data; + + callback (info->renderer, callback_data); + } } static gint @@ -262,6 +349,89 @@ gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea *area, } + + +/************************************************************* + * GtkCellLayoutIface * + *************************************************************/ +static void +gtk_cell_area_box_cell_layout_init (GtkCellLayoutIface *iface) +{ + iface->pack_start = gtk_cell_area_box_layout_pack_start; + iface->pack_end = gtk_cell_area_box_layout_pack_end; +} + +static void +gtk_cell_area_box_layout_pack_start (GtkCellLayout *cell_layout, + GtkCellRenderer *renderer, + gboolean expand) +{ + gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand); +} + +static void +gtk_cell_area_box_layout_pack_end (GtkCellLayout *cell_layout, + GtkCellRenderer *renderer, + gboolean expand) +{ + gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand); +} + /************************************************************* * API * *************************************************************/ +GtkCellArea * +gtk_cell_area_box_new (void) +{ + return (GtkCellArea *)g_object_new (GTK_TYPE_CELL_AREA_BOX, NULL); +} + +void +gtk_cell_area_box_pack_start (GtkCellAreaBox *box, + GtkCellRenderer *renderer, + gboolean expand) +{ + GtkCellAreaBoxPrivate *priv; + CellInfo *info; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX (box)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box->priv; + + if (g_list_find_custom (priv->cells, renderer, + (GCompareFunc)cell_info_find)) + { + g_warning ("Refusing to add the same cell renderer to a GtkCellAreaBox twice"); + return; + } + + info = cell_info_new (renderer, expand, GTK_PACK_START); + + priv->cells = g_list_append (priv->cells, info); +} + +void +gtk_cell_area_box_pack_end (GtkCellAreaBox *box, + GtkCellRenderer *renderer, + gboolean expand) +{ + GtkCellAreaBoxPrivate *priv; + CellInfo *info; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX (box)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box->priv; + + if (g_list_find_custom (priv->cells, renderer, + (GCompareFunc)cell_info_find)) + { + g_warning ("Refusing to add the same cell renderer to a GtkCellArea twice"); + return; + } + + info = cell_info_new (renderer, expand, GTK_PACK_END); + + priv->cells = g_list_append (priv->cells, info); +} diff --git a/gtk/gtkcellareabox.h b/gtk/gtkcellareabox.h index 1e188cecb2..1913995ce4 100644 --- a/gtk/gtkcellareabox.h +++ b/gtk/gtkcellareabox.h @@ -62,9 +62,15 @@ struct _GtkCellAreaBoxClass void (*_gtk_reserved4) (void); }; -GType gtk_cell_area_box_get_type (void) G_GNUC_CONST; - +GType gtk_cell_area_box_get_type (void) G_GNUC_CONST; +GtkCellArea *gtk_cell_area_box_new (void); +void gtk_cell_area_box_pack_start (GtkCellAreaBox *box, + GtkCellRenderer *renderer, + gboolean expand); +void gtk_cell_area_box_pack_end (GtkCellAreaBox *box, + GtkCellRenderer *renderer, + gboolean expand); G_END_DECLS