X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellview.c;h=09840d4ecaf02e022d10b1f8c1c9deb4032d7862;hb=abcfd2d5ef4caaf2c903624a3c7e61d61f30411a;hp=1e9912f3d49bfe46d8f7c349aba5f7d81817e807;hpb=a9fbbcb5ec3a343b65513be33a935809b45b2a14;p=~andy%2Fgtk diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c index 1e9912f3d..09840d4ec 100644 --- a/gtk/gtkcellview.c +++ b/gtk/gtkcellview.c @@ -17,15 +17,18 @@ * Boston, MA 02111-1307, USA. */ -#include -#include "gtkalias.h" +#include "config.h" +#include #include "gtkcellview.h" #include "gtkcelllayout.h" #include "gtkintl.h" -#include "gtksignal.h" #include "gtkcellrenderertext.h" #include "gtkcellrendererpixbuf.h" +#include "gtkprivate.h" +#include "gtksizerequest.h" #include +#include "gtkbuildable.h" + typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo; struct _GtkCellViewCellInfo @@ -33,6 +36,7 @@ struct _GtkCellViewCellInfo GtkCellRenderer *cell; gint requested_width; + gint natural_width; gint real_width; guint expand : 1; guint pack : 1; @@ -51,12 +55,11 @@ struct _GtkCellViewPrivate GList *cell_list; gint spacing; - GdkColor background; + GdkRGBA background; gboolean background_set; }; -static void gtk_cell_view_class_init (GtkCellViewClass *klass); static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface); static void gtk_cell_view_get_property (GObject *object, guint param_id, @@ -66,19 +69,15 @@ static void gtk_cell_view_set_property (GObject *obj guint param_id, const GValue *value, GParamSpec *pspec); -static void gtk_cell_view_init (GtkCellView *cellview); static void gtk_cell_view_finalize (GObject *object); -static void gtk_cell_view_style_set (GtkWidget *widget, - GtkStyle *previous_style); -static void gtk_cell_view_size_request (GtkWidget *widget, - GtkRequisition *requisition); static void gtk_cell_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gboolean gtk_cell_view_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_cell_view_set_valuesv (GtkCellView *cellview, - GtkCellRenderer *renderer, - va_list args); +static gboolean gtk_cell_view_draw (GtkWidget *widget, + cairo_t *cr); +static void gtk_cell_view_set_value (GtkCellView *cell_view, + GtkCellRenderer *renderer, + gchar *property, + GValue *value); static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, GtkCellRenderer *renderer); static void gtk_cell_view_set_cell_data (GtkCellView *cell_view); @@ -105,57 +104,56 @@ static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout static void gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, GtkCellRenderer *cell, gint position); +static GList * gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout); + +/* 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); + +static void gtk_cell_view_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_cell_view_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_cell_view_get_preferred_width_for_height (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size); +static void gtk_cell_view_get_preferred_height_for_width (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size); + +static GtkBuildableIface *parent_buildable_iface; -#define GTK_CELL_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate)) - enum { PROP_0, PROP_BACKGROUND, PROP_BACKGROUND_GDK, - PROP_BACKGROUND_SET + PROP_BACKGROUND_RGBA, + PROP_BACKGROUND_SET, + PROP_MODEL }; -static GtkObjectClass *parent_class = NULL; - - -GType -gtk_cell_view_get_type (void) -{ - static GType cell_view_type = 0; - - if (!cell_view_type) - { - static const GTypeInfo cell_view_info = - { - sizeof (GtkCellViewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_cell_view_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkCellView), - 0, - (GInstanceInitFunc) gtk_cell_view_init - }; - - static const GInterfaceInfo cell_layout_info = - { - (GInterfaceInitFunc) gtk_cell_view_cell_layout_init, - NULL, - NULL - }; - - cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView", - &cell_view_info, 0); - - g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT, - &cell_layout_info); - } +G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, + gtk_cell_view_cell_layout_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + gtk_cell_view_buildable_init)) - return cell_view_type; -} static void gtk_cell_view_class_init (GtkCellViewClass *klass) @@ -163,16 +161,16 @@ gtk_cell_view_class_init (GtkCellViewClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - parent_class = g_type_class_peek_parent (klass); - 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; - widget_class->expose_event = gtk_cell_view_expose; - widget_class->size_allocate = gtk_cell_view_size_allocate; - widget_class->size_request = gtk_cell_view_size_request; - widget_class->style_set = gtk_cell_view_style_set; + widget_class->draw = gtk_cell_view_draw; + widget_class->size_allocate = gtk_cell_view_size_allocate; + 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; /* properties */ g_object_class_install_property (gobject_class, @@ -181,24 +179,62 @@ gtk_cell_view_class_init (GtkCellViewClass *klass) P_("Background color name"), P_("Background color as a string"), NULL, - G_PARAM_WRITABLE)); + GTK_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_BACKGROUND_GDK, - g_param_spec_boxed ("background_gdk", + g_param_spec_boxed ("background-gdk", P_("Background color"), P_("Background color as a GdkColor"), GDK_TYPE_COLOR, - G_PARAM_READABLE | G_PARAM_WRITABLE)); - -#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)) - - ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET, + GTK_PARAM_READWRITE)); + /** + * GtkCellView:background-rgba + * + * 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)); + + /** + * GtkCellView:model + * + * 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)); + +#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)) + + ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET, P_("Background set"), P_("Whether this tag affects the background color")); g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate)); } +static void +gtk_cell_view_buildable_init (GtkBuildableIface *iface) +{ + parent_buildable_iface = g_type_interface_peek_parent (iface); + iface->add_child = _gtk_cell_layout_buildable_add_child; + iface->custom_tag_start = gtk_cell_view_buildable_custom_tag_start; + iface->custom_tag_end = gtk_cell_view_buildable_custom_tag_end; +} + static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) { @@ -209,6 +245,7 @@ gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func; iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes; iface->reorder = gtk_cell_view_cell_layout_reorder; + iface->get_cells = gtk_cell_view_cell_layout_get_cells; } static void @@ -225,14 +262,23 @@ gtk_cell_view_get_property (GObject *object, { GdkColor color; - color = view->priv->background; + 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -260,16 +306,22 @@ gtk_cell_view_set_property (GObject *object, else g_warning ("Don't know color `%s'", g_value_get_string (value)); - g_object_notify (object, "background_gdk"); + g_object_notify (object, "background-gdk"); } break; case PROP_BACKGROUND_GDK: gtk_cell_view_set_background_color (view, g_value_get_boxed (value)); 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; - default: + case PROP_MODEL: + gtk_cell_view_set_model (view, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } @@ -278,18 +330,14 @@ gtk_cell_view_set_property (GObject *object, static void gtk_cell_view_init (GtkCellView *cellview) { - GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW); + GtkCellViewPrivate *priv; - cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview); -} + cellview->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellview, + GTK_TYPE_CELL_VIEW, + GtkCellViewPrivate); + priv = cellview->priv; -static void -gtk_cell_view_style_set (GtkWidget *widget, - GtkStyle *previous_style) -{ - if (previous_style && GTK_WIDGET_REALIZED (widget)) - gdk_window_set_background (widget->window, - &widget->style->base[GTK_WIDGET_STATE (widget)]); + gtk_widget_set_has_window (GTK_WIDGET (cellview), FALSE); } static void @@ -305,145 +353,128 @@ gtk_cell_view_finalize (GObject *object) if (cellview->priv->displayed_row) gtk_tree_row_reference_free (cellview->priv->displayed_row); - (* G_OBJECT_CLASS (parent_class)->finalize) (object); + G_OBJECT_CLASS (gtk_cell_view_parent_class)->finalize (object); } static void -gtk_cell_view_size_request (GtkWidget *widget, - GtkRequisition *requisition) +gtk_cell_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - GList *i; - gboolean first_cell = TRUE; - GtkCellView *cellview; + GtkCellView *cellview; + GtkRequestedSize *sizes; + GList *list; + gint n_visible_cells, n_expand_cells; + gint avail_width = 0; + gint extra_per_cell, extra_extra, i; + gboolean first_cell = TRUE; + + gtk_widget_set_allocation (widget, allocation); cellview = GTK_CELL_VIEW (widget); - requisition->width = 0; - requisition->height = 0; + avail_width = allocation->width; - if (cellview->priv->displayed_row) - gtk_cell_view_set_cell_data (cellview); - - for (i = cellview->priv->cell_list; i; i = i->next) + /* Count visible/expand children */ + for (n_visible_cells = 0, n_expand_cells = 0, list = cellview->priv->cell_list; + list; list = list->next) { - gint width, height; - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (!info->cell->visible) - continue; - - if (!first_cell) - requisition->width += cellview->priv->spacing; - - gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL, - &width, &height); + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; - info->requested_width = width; - requisition->width += width; - requisition->height = MAX (requisition->height, height); + n_visible_cells++; - first_cell = FALSE; + if (info->expand) + n_expand_cells++; } -} - -static void -gtk_cell_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GList *i; - gint expand_cell_count = 0; - gint full_requested_width = 0; - gint extra_space; - GtkCellView *cellview; - widget->allocation = *allocation; - - cellview = GTK_CELL_VIEW (widget); + sizes = g_new0 (GtkRequestedSize, n_visible_cells); /* checking how much extra space we have */ - for (i = cellview->priv->cell_list; i; i = i->next) + for (i = 0, list = cellview->priv->cell_list; list; list = list->next) { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; - if (!info->cell->visible) + if (!gtk_cell_renderer_get_visible (info->cell)) continue; - if (info->expand) - expand_cell_count++; + sizes[i].data = info; + sizes[i].minimum_size = info->requested_width; + sizes[i].natural_size = info->natural_width; - full_requested_width += info->requested_width; - } + if (!first_cell) + avail_width -= cellview->priv->spacing; - extra_space = widget->allocation.width - full_requested_width; - if (extra_space < 0) - extra_space = 0; - else if (extra_space > 0 && expand_cell_count > 0) - extra_space /= expand_cell_count; + avail_width -= sizes[i].minimum_size; - /* iterate list for PACK_START cells */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + first_cell = FALSE; - if (info->pack == GTK_PACK_END) - continue; + i++; + } - if (!info->cell->visible) - continue; + avail_width = gtk_distribute_natural_allocation (MAX (0, avail_width), n_visible_cells, sizes); - info->real_width = info->requested_width + (info->expand?extra_space:0); + /* Deal with any expand space... */ + if (n_expand_cells > 0) + { + extra_per_cell = avail_width / n_expand_cells; + extra_extra = avail_width % n_expand_cells; } + else + /* Everything just left-aligned if no cells expand */ + extra_per_cell = extra_extra = 0; - /* iterate list for PACK_END cells */ - for (i = cellview->priv->cell_list; i; i = i->next) + for (i = 0, list = cellview->priv->cell_list; list; list = list->next) { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; - if (info->pack == GTK_PACK_START) + if (!gtk_cell_renderer_get_visible (info->cell)) continue; - if (!info->cell->visible) - continue; + info->real_width = sizes[i].minimum_size; - info->real_width = info->requested_width + (info->expand?extra_space:0); + if (info->expand) + { + info->real_width += extra_per_cell; + + if (extra_extra) + { + info->real_width++; + extra_extra--; + } + } + + /* increment index into sizes for visible children */ + i++; } + + g_free (sizes); } static gboolean -gtk_cell_view_expose (GtkWidget *widget, - GdkEventExpose *event) +gtk_cell_view_draw (GtkWidget *widget, + cairo_t *cr) { - GList *i; + GList *list; GtkCellView *cellview; GdkRectangle area; GtkCellRendererState state; gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL); + GtkPackType packing; + int width; cellview = GTK_CELL_VIEW (widget); - if (! GTK_WIDGET_DRAWABLE (widget)) - return FALSE; + /* render cells */ + area.x = 0; + area.y = 0; + area.width = width = gtk_widget_get_allocated_width (widget); + area.height = gtk_widget_get_allocated_height (widget); /* "blank" background */ if (cellview->priv->background_set) { - GdkGC *gc; - - gc = gdk_gc_new (GTK_WIDGET (cellview)->window); - gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background); - - gdk_draw_rectangle (GTK_WIDGET (cellview)->window, - gc, - TRUE, - - /*0, 0,*/ - widget->allocation.x, - widget->allocation.y, - - widget->allocation.width, - widget->allocation.height); - - g_object_unref (gc); + gdk_cairo_rectangle (cr, &area); + gdk_cairo_set_source_rgba (cr, &cellview->priv->background); + cairo_fill (cr); } /* set cell data (if available) */ @@ -452,67 +483,51 @@ gtk_cell_view_expose (GtkWidget *widget, else if (cellview->priv->model) return FALSE; - /* render cells */ - area = widget->allocation; - - /* we draw on our very own window, initialize x and y to zero */ - area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); - area.y = widget->allocation.y; - - if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) + if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) state = GTK_CELL_RENDERER_PRELIT; + else if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) + state = GTK_CELL_RENDERER_INSENSITIVE; else state = 0; - /* PACK_START */ - for (i = cellview->priv->cell_list; i; i = i->next) + for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing) { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_END) - continue; - - if (!info->cell->visible) - continue; - - area.width = info->real_width; - if (rtl) - area.x -= area.width; - - gtk_cell_renderer_render (info->cell, - event->window, - widget, - /* FIXME! */ - &area, &area, &event->area, state); + if (packing == GTK_PACK_START) + area.x = rtl ? width : 0; + else + area.x = rtl ? 0 : width; - if (!rtl) - area.x += info->real_width; - } - - area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width); - - /* PACK_END */ - for (i = cellview->priv->cell_list; i; i = i->next) - { - GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; - - if (info->pack == GTK_PACK_START) - continue; - - if (!info->cell->visible) - continue; - - area.width = info->real_width; - if (!rtl) - area.x -= area.width; - - gtk_cell_renderer_render (info->cell, - widget->window, - widget, - /* FIXME ! */ - &area, &area, &event->area, state); - if (rtl) - area.x += info->real_width; + for (list = cellview->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + + if (info->pack != packing) + continue; + + if (!gtk_cell_renderer_get_visible (info->cell)) + continue; + + area.width = info->real_width; + + if ((packing == GTK_PACK_START && rtl) || + (packing == GTK_PACK_END && !rtl)) + area.x -= area.width; + + gtk_cell_renderer_render (info->cell, + cr, + widget, + /* FIXME! */ + &area, &area, state); + + if ((packing == GTK_PACK_START && !rtl) || + (packing == GTK_PACK_END && rtl)) + { + area.x += area.width; + area.x += cellview->priv->spacing; + } + else + area.x -= cellview->priv->spacing; + } } return FALSE; @@ -591,19 +606,18 @@ gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, GtkCellViewCellInfo *info; GtkCellView *cellview = GTK_CELL_VIEW (layout); - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); - g_object_ref (renderer); - gtk_object_sink (GTK_OBJECT (renderer)); + g_object_ref_sink (renderer); - info = g_new0 (GtkCellViewCellInfo, 1); + info = g_slice_new0 (GtkCellViewCellInfo); info->cell = renderer; info->expand = expand ? TRUE : FALSE; info->pack = GTK_PACK_START; cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); + + gtk_widget_queue_resize (GTK_WIDGET (cellview)); } static void @@ -614,19 +628,18 @@ gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, GtkCellViewCellInfo *info; GtkCellView *cellview = GTK_CELL_VIEW (layout); - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); - g_object_ref (renderer); - gtk_object_sink (GTK_OBJECT (renderer)); + g_object_ref_sink (renderer); - info = g_new0 (GtkCellViewCellInfo, 1); + info = g_slice_new0 (GtkCellViewCellInfo); info->cell = renderer; info->expand = expand ? TRUE : FALSE; info->pack = GTK_PACK_END; cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); + + gtk_widget_queue_resize (GTK_WIDGET (cellview)); } static void @@ -638,7 +651,6 @@ gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, GtkCellViewCellInfo *info; GtkCellView *cellview = GTK_CELL_VIEW (layout); - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); info = gtk_cell_view_get_cell_info (cellview, renderer); g_return_if_fail (info != NULL); @@ -653,15 +665,13 @@ gtk_cell_view_cell_layout_clear (GtkCellLayout *layout) { GtkCellView *cellview = GTK_CELL_VIEW (layout); - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - while (cellview->priv->cell_list) { GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data; gtk_cell_view_cell_layout_clear_attributes (layout, info->cell); g_object_unref (info->cell); - g_free (info); + g_slice_free (GtkCellViewCellInfo, info); cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, cellview->priv->cell_list); } @@ -677,8 +687,6 @@ gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, GtkCellView *cellview = GTK_CELL_VIEW (layout); GtkCellViewCellInfo *info; - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - info = gtk_cell_view_get_cell_info (cellview, cell); g_return_if_fail (info != NULL); @@ -699,13 +707,10 @@ static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, GtkCellRenderer *renderer) { - GtkCellViewCellInfo *info; GtkCellView *cellview = GTK_CELL_VIEW (layout); + GtkCellViewCellInfo *info; GSList *list; - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - info = gtk_cell_view_get_cell_info (cellview, renderer); if (info != NULL) { @@ -726,12 +731,9 @@ gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, GtkCellRenderer *cell, gint position) { - GList *link; - GtkCellViewCellInfo *info; GtkCellView *cellview = GTK_CELL_VIEW (layout); - - g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); - g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); + GtkCellViewCellInfo *info; + GList *link; info = gtk_cell_view_get_cell_info (cellview, cell); @@ -742,7 +744,7 @@ gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, g_return_if_fail (link != NULL); - cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list, + cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, link); cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list, info, position); @@ -795,7 +797,7 @@ gtk_cell_view_new_with_text (const gchar *text) g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, text); - gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL); + gtk_cell_view_set_value (cellview, renderer, "text", &value); g_value_unset (&value); return GTK_WIDGET (cellview); @@ -806,7 +808,7 @@ gtk_cell_view_new_with_text (const gchar *text) * @markup: the text to display in the cell view * * Creates a new #GtkCellView widget, adds a #GtkCellRendererText - * to it, and makes its show @markup. The text can text can be + * to it, and makes it show @markup. The text can be * marked up with the Pango text * markup language. * @@ -829,7 +831,7 @@ gtk_cell_view_new_with_markup (const gchar *markup) g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, markup); - gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL); + gtk_cell_view_set_value (cellview, renderer, "markup", &value); g_value_unset (&value); return GTK_WIDGET (cellview); @@ -861,7 +863,7 @@ gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) g_value_init (&value, GDK_TYPE_PIXBUF); g_value_set_object (&value, pixbuf); - gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL); + gtk_cell_view_set_value (cellview, renderer, "pixbuf", &value); g_value_unset (&value); return GTK_WIDGET (cellview); @@ -879,15 +881,12 @@ gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) * * Since: 2.6 */ -void +static void gtk_cell_view_set_value (GtkCellView *cell_view, GtkCellRenderer *renderer, gchar *property, GValue *value) { - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - g_object_set_property (G_OBJECT (renderer), property, value); /* force resize and redraw */ @@ -895,59 +894,13 @@ gtk_cell_view_set_value (GtkCellView *cell_view, gtk_widget_queue_draw (GTK_WIDGET (cell_view)); } -static void -gtk_cell_view_set_valuesv (GtkCellView *cell_view, - GtkCellRenderer *renderer, - va_list args) -{ - gchar *attribute; - GValue *value; - - attribute = va_arg (args, gchar *); - - while (attribute) - { - value = va_arg (args, GValue *); - gtk_cell_view_set_value (cell_view, renderer, attribute, value); - attribute = va_arg (args, gchar *); - } -} - -/** - * gtk_cell_view_set_values: - * @cell_view: a #GtkCellView widget - * @renderer: one of the renderers of @cell_view - * @Varargs: a list of pairs of property names and #GValues, - * finished by %NULL - * - * Sets multiple properties of a cell renderer of @cell_view, and - * makes sure the display of @cell_view is updated. - * - * Since: 2.6 - */ -void -gtk_cell_view_set_values (GtkCellView *cell_view, - GtkCellRenderer *renderer, - ...) -{ - va_list args; - - g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer)); - - va_start (args, renderer); - gtk_cell_view_set_valuesv (cell_view, renderer, args); - va_end (args); -} - /** * gtk_cell_view_set_model: * @cell_view: a #GtkCellView - * @model: a #GtkTreeModel + * @model: (allow-none): a #GtkTreeModel * * Sets the model for @cell_view. If @cell_view already has a model - * set, it will remove it before setting the new model. If @model is + * set, it will remove it before setting the new model. If @model is * %NULL, then it will unset the old model. * * Since: 2.6 @@ -957,7 +910,7 @@ gtk_cell_view_set_model (GtkCellView *cell_view, GtkTreeModel *model) { g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); - g_return_if_fail (GTK_IS_TREE_MODEL (model)); + g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model)); if (cell_view->priv->model) { @@ -975,11 +928,30 @@ gtk_cell_view_set_model (GtkCellView *cell_view, g_object_ref (cell_view->priv->model); } +/** + * gtk_cell_view_get_model: + * @cell_view: a #GtkCellView + * + * Returns the model for @cell_view. If no model is used %NULL is + * returned. + * + * Returns: (transfer none): a #GtkTreeModel used or %NULL + * + * 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; +} + /** * gtk_cell_view_set_displayed_row: * @cell_view: a #GtkCellView - * @path: a #GtkTreePath or %NULL to unset. - * + * @path: (allow-none): a #GtkTreePath or %NULL to unset. + * * Sets the row of the model that is currently displayed * by the #GtkCellView. If the path is unset, then the * contents of the cellview "stick" at their last value; @@ -1012,6 +984,18 @@ gtk_cell_view_set_displayed_row (GtkCellView *cell_view, gtk_widget_queue_draw (GTK_WIDGET (cell_view)); } +/** + * 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. + * + * Returns: the currently displayed row or %NULL + * + * Since: 2.6 + */ GtkTreePath * gtk_cell_view_get_displayed_row (GtkCellView *cell_view) { @@ -1035,32 +1019,108 @@ gtk_cell_view_get_displayed_row (GtkCellView *cell_view) * Return value: %TRUE * * Since: 2.6 + * + * Deprecated: 3.0: Use gtk_cell_view_get_desired_width_of_row() and + * gtk_cell_view_get_desired_height_for_width_of_row() instead. */ gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view, GtkTreePath *path, GtkRequisition *requisition) { - GtkTreeRowReference *tmp; GtkRequisition req; g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE); g_return_val_if_fail (path != NULL, FALSE); - g_return_val_if_fail (requisition != NULL, FALSE); + + /* Return the minimum height for the minimum width */ + gtk_cell_view_get_desired_width_of_row (cell_view, path, &req.width, NULL); + gtk_cell_view_get_desired_height_for_width_of_row (cell_view, path, req.width, &req.height, NULL); + + if (requisition) + *requisition = req; + + return TRUE; +} + + +/** + * gtk_cell_view_get_desired_width_of_row: + * @cell_view: a #GtkCellView + * @path: a #GtkTreePath + * @minimum_size: location to store the minimum size + * @natural_size: location to store the natural size + * + * Sets @minimum_size and @natural_size to the width desired by @cell_view + * to display the model row pointed to by @path. + * + * Since: 3.0 + */ +void +gtk_cell_view_get_desired_width_of_row (GtkCellView *cell_view, + GtkTreePath *path, + gint *minimum_size, + gint *natural_size) +{ + GtkTreeRowReference *tmp; + + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (path != NULL); + g_return_if_fail (minimum_size != NULL || natural_size != NULL); tmp = cell_view->priv->displayed_row; cell_view->priv->displayed_row = gtk_tree_row_reference_new (cell_view->priv->model, path); - gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition); + gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), minimum_size, natural_size); gtk_tree_row_reference_free (cell_view->priv->displayed_row); cell_view->priv->displayed_row = tmp; - /* restore actual size info */ - gtk_cell_view_size_request (GTK_WIDGET (cell_view), &req); + /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */ + gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL); +} - return TRUE; + +/** + * gtk_cell_view_get_desired_height_for_width_of_row: + * @cell_view: a #GtkCellView + * @path: a #GtkTreePath + * @avail_size: available width + * @minimum_size: location to store the minimum height + * @natural_size: location to store the natural height + * + * Sets @minimum_size and @natural_size to the height desired by @cell_view + * if it were allocated a width of @avail_size to display the model row + * pointed to by @path. + * + * Since: 3.0 + */ +void +gtk_cell_view_get_desired_height_for_width_of_row (GtkCellView *cell_view, + GtkTreePath *path, + gint avail_size, + gint *minimum_size, + gint *natural_size) +{ + GtkTreeRowReference *tmp; + + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + g_return_if_fail (path != NULL); + g_return_if_fail (minimum_size != NULL || natural_size != NULL); + + tmp = cell_view->priv->displayed_row; + cell_view->priv->displayed_row = + gtk_tree_row_reference_new (cell_view->priv->model, path); + + /* Then get the collective height_for_width based on the cached values */ + gtk_cell_view_get_preferred_height_for_width (GTK_WIDGET (cell_view), avail_size, minimum_size, natural_size); + + gtk_tree_row_reference_free (cell_view->priv->displayed_row); + cell_view->priv->displayed_row = tmp; + + /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */ + gtk_cell_view_get_preferred_width (GTK_WIDGET (cell_view), NULL, NULL); } /** @@ -1083,38 +1143,67 @@ gtk_cell_view_set_background_color (GtkCellView *cell_view, if (!cell_view->priv->background_set) { cell_view->priv->background_set = TRUE; - g_object_notify (G_OBJECT (cell_view), "background_set"); + g_object_notify (G_OBJECT (cell_view), "background-set"); } - cell_view->priv->background = *color; + cell_view->priv->background.red = color->red / 65535.; + cell_view->priv->background.green = color->green / 65535.; + cell_view->priv->background.blue = color->blue / 65535.; + cell_view->priv->background.alpha = 1; } else { if (cell_view->priv->background_set) { cell_view->priv->background_set = FALSE; - g_object_notify (G_OBJECT (cell_view), "background_set"); + g_object_notify (G_OBJECT (cell_view), "background-set"); } } - gtk_widget_queue_draw (GTK_WIDGET (cellview)); + gtk_widget_queue_draw (GTK_WIDGET (cell_view)); } /** - * gtk_cell_view_get_cell_renderers: + * gtk_cell_view_set_background_rgba: * @cell_view: a #GtkCellView - * - * Returns the cell renderers which have been added to @cell_view. + * @rgba: the new background color * - * Return value: a list of cell renderers. The list, but not the - * renderers has been newly allocated and should be freed with - * g_list_free() when no longer needed. - * - * Since: 2.6 + * Sets the background color of @cell_view. + * + * Since: 3.0 */ -GList * -gtk_cell_view_get_cell_renderers (GtkCellView *cell_view) +void +gtk_cell_view_set_background_rgba (GtkCellView *cell_view, + const GdkRGBA *rgba) { + g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); + + if (rgba) + { + if (!cell_view->priv->background_set) + { + cell_view->priv->background_set = TRUE; + g_object_notify (G_OBJECT (cell_view), "background-set"); + } + + cell_view->priv->background = *rgba; + } + else + { + if (cell_view->priv->background_set) + { + cell_view->priv->background_set = FALSE; + g_object_notify (G_OBJECT (cell_view), "background-set"); + } + } + + gtk_widget_queue_draw (GTK_WIDGET (cell_view)); +} + +static GList * +gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout) +{ + GtkCellView *cell_view = GTK_CELL_VIEW (layout); GList *retval = NULL, *list; g_return_val_if_fail (cell_view != NULL, NULL); @@ -1130,3 +1219,216 @@ gtk_cell_view_get_cell_renderers (GtkCellView *cell_view) return g_list_reverse (retval); } + +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) +{ + if (strcmp (tagname, "attributes") == 0) + _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, + data); + else if (parent_buildable_iface->custom_tag_end) + parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname, + data); +} + +static void +gtk_cell_view_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + GList *list; + gint cell_min, cell_nat; + gboolean first_cell = TRUE; + GtkCellView *cellview = GTK_CELL_VIEW (widget); + gint minimum, natural; + + minimum = natural = 0; + + if (cellview->priv->displayed_row) + gtk_cell_view_set_cell_data (cellview); + + for (list = cellview->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + + if (gtk_cell_renderer_get_visible (info->cell)) + { + + if (!first_cell) + { + minimum += cellview->priv->spacing; + natural += cellview->priv->spacing; + } + + gtk_cell_renderer_get_preferred_width (info->cell, + GTK_WIDGET (cellview), &cell_min, &cell_nat); + + info->requested_width = cell_min; + info->natural_width = cell_nat; + + minimum += info->requested_width; + natural += info->natural_width; + + first_cell = FALSE; + } + } + + if (minimum_size) + *minimum_size = minimum; + + if (natural_size) + *natural_size = natural; +} + +static void +gtk_cell_view_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gint minimum_width; + + /* CellViews only need to respond to height-for-width mode (cellview is pretty much + * an implementation detail of GtkComboBox) */ + gtk_cell_view_get_preferred_width (widget, &minimum_width, NULL); + gtk_cell_view_get_preferred_height_for_width (widget, minimum_width, minimum_size, natural_size); +} + +static void +gtk_cell_view_get_preferred_width_for_height (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + /* CellViews only need to respond to height-for-width mode (cellview is pretty much + * an implementation detail of GtkComboBox) */ + gtk_cell_view_get_preferred_width (widget, minimum_size, natural_size); +} + +static void +gtk_cell_view_get_preferred_height_for_width (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + GtkCellView *cellview = GTK_CELL_VIEW (widget); + GList *list; + GtkRequestedSize *sizes; + GArray *array; + gint minimum, natural, avail_size; + gboolean first_cell = TRUE; + gint n_expand_cells = 0; + gint extra_per_cell, extra_extra, i; + + minimum = natural = 0; + avail_size = for_size; + + array = g_array_new (0, TRUE, sizeof (GtkRequestedSize)); + + if (cellview->priv->displayed_row) + gtk_cell_view_set_cell_data (cellview); + + /* First allocate the right width to all cells */ + for (list = cellview->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + + if (gtk_cell_renderer_get_visible (info->cell)) + { + GtkRequestedSize requested; + + gtk_cell_renderer_get_preferred_width (GTK_CELL_RENDERER (info->cell), + GTK_WIDGET (cellview), + &requested.minimum_size, + &requested.natural_size); + + requested.data = info; + g_array_append_val (array, requested); + + avail_size -= requested.minimum_size; + + if (!first_cell) + avail_size -= cellview->priv->spacing; + + first_cell = FALSE; + + if (info->expand) + n_expand_cells++; + } + } + + sizes = (GtkRequestedSize *)array->data; + avail_size = gtk_distribute_natural_allocation (MAX (0, avail_size), array->len, sizes); + + /* Deal with any expand space... */ + if (n_expand_cells > 0) + { + extra_per_cell = avail_size / n_expand_cells; + extra_extra = avail_size % n_expand_cells; + } + else + /* Everything just left-aligned if no cells expand */ + extra_per_cell = extra_extra = 0; + + /* Now get the height for the real width of each cell */ + for (i = 0, list = cellview->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + gint cell_minimum, cell_natural; + + if (gtk_cell_renderer_get_visible (info->cell)) + { + gint cell_width = sizes[i].minimum_size; + + g_assert (sizes[i].data == info); + + if (info->expand) + { + cell_width += extra_per_cell; + if (extra_extra) + { + cell_width++; + extra_extra--; + } + } + + /* Get the height for the real width of this cell */ + gtk_cell_renderer_get_preferred_height_for_width (GTK_CELL_RENDERER (info->cell), + GTK_WIDGET (widget), + cell_width, &cell_minimum, &cell_natural); + + minimum = MAX (minimum, cell_minimum); + natural = MAX (natural, cell_natural); + + /* increment sizes[] index for visible cells */ + i++; + } + } + + g_array_free (array, TRUE); + + if (minimum_size) + *minimum_size = minimum; + if (natural_size) + *natural_size = natural; +}