* Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> * 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 <gtk/gtkversion.h> #if !GTK_CHECK_VERSION(2,6,0) #if GTK_CHECK_VERSION(2,4,0) #include <gtk/gtkcelllayout.h> #include "gtkcelllayout.h" #include <gtk/gtksignal.h> #include <gtk/gtkcellrenderertext.h> #include <gtk/gtkcellrendererpixbuf.h> #include <gobject/gmarshal.h> typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo; struct _GtkCellViewCellInfo GtkCellLayoutDataFunc func; struct _GtkCellViewPrivate GtkTreeRowReference *displayed_row; 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, static void gtk_cell_view_set_property (GObject *object, 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, static void gtk_cell_view_set_valuesv (GtkCellView *cellview, GtkCellRenderer *renderer, static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, GtkCellRenderer *renderer); static void gtk_cell_view_set_cell_data (GtkCellView *cellview); static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, GtkCellRenderer *renderer, static void gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, GtkCellRenderer *renderer, static void gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, GtkCellRenderer *renderer, static void gtk_cell_view_cell_layout_clear (GtkCellLayout *layout); static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, GtkCellRenderer *renderer); static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, GtkCellLayoutDataFunc func, static void gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, static GtkObjectClass *parent_class = NULL; gtk_cell_view_get_type (void) static GType cell_view_type = 0; static const GTypeInfo cell_view_info = sizeof (GtkCellViewClass), NULL, /* base_finalize */ (GClassInitFunc) gtk_cell_view_class_init, NULL, /* class_finalize */ (GInstanceInitFunc) gtk_cell_view_init static const GInterfaceInfo cell_layout_info = (GInterfaceInitFunc) gtk_cell_view_cell_layout_init, cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GaimGtkCellView", g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT, 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; g_object_class_install_property (gobject_class, g_param_spec_string ("background", P_("Background color name"), P_("Background color as a string"), g_object_class_install_property (gobject_class, g_param_spec_boxed ("background_gdk", P_("Background color as a GdkColor"), 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, P_("Whether this tag affects the background color")); gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) iface->pack_start = gtk_cell_view_cell_layout_pack_start; iface->pack_end = gtk_cell_view_cell_layout_pack_end; iface->clear = gtk_cell_view_cell_layout_clear; iface->add_attribute = gtk_cell_view_cell_layout_add_attribute; 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; gtk_cell_view_get_property (GObject *object, GtkCellView *view = GTK_CELL_VIEW (object); case PROP_BACKGROUND_GDK: color = view->priv->background; g_value_set_boxed (value, &color); case PROP_BACKGROUND_SET: g_value_set_boolean (value, view->priv->background_set); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); gtk_cell_view_set_property (GObject *object, GtkCellView *view = GTK_CELL_VIEW (object); if (!g_value_get_string (value)) gtk_cell_view_set_background_color (view, NULL); else if (gdk_color_parse (g_value_get_string (value), &color)) gtk_cell_view_set_background_color (view, &color); g_warning ("Don't know color `%s'", g_value_get_string (value)); g_object_notify (object, "background_gdk"); case PROP_BACKGROUND_GDK: gtk_cell_view_set_background_color (view, g_value_get_boxed (value)); case PROP_BACKGROUND_SET: view->priv->background_set = g_value_get_boolean (value); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); gtk_cell_view_init (GtkCellView *cellview) GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW); cellview->priv = g_new0(GtkCellViewPrivate,1); 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_cell_view_finalize (GObject *object) GtkCellView *cellview = GTK_CELL_VIEW (object); gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview)); if (cellview->priv->model) g_object_unref (cellview->priv->model); if (cellview->priv->displayed_row) gtk_tree_row_reference_free (cellview->priv->displayed_row); if (G_OBJECT_CLASS (parent_class)->finalize) (* G_OBJECT_CLASS (parent_class)->finalize) (object); gtk_cell_view_size_request (GtkWidget *widget, GtkRequisition *requisition) gboolean first_cell = TRUE; cellview = GTK_CELL_VIEW (widget); if (cellview->priv->displayed_row) gtk_cell_view_set_cell_data (cellview); for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (!info->cell->visible) requisition->width += cellview->priv->spacing; gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL, info->requested_width = width; requisition->width += width; requisition->height = MAX (requisition->height, height); gtk_cell_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) gint expand_cell_count = 0; gint full_requested_width = 0; widget->allocation = *allocation; cellview = GTK_CELL_VIEW (widget); /* checking how much extra space we have */ for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (!info->cell->visible) full_requested_width += info->requested_width; extra_space = widget->allocation.width - full_requested_width; else if (extra_space > 0 && expand_cell_count > 0) extra_space /= expand_cell_count; /* iterate list for PACK_START cells */ for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (info->pack == GTK_PACK_END) if (!info->cell->visible) info->real_width = info->requested_width + (info->expand ? extra_space : 0); /* iterate list for PACK_END cells */ for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (info->pack == GTK_PACK_START) if (!info->cell->visible) info->real_width = info->requested_width + (info->expand ? extra_space : 0); gtk_cell_view_expose (GtkWidget *widget, GtkCellRendererState state; gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL); cellview = GTK_CELL_VIEW (widget); if (! GTK_WIDGET_DRAWABLE (widget)) if (cellview->priv->background_set) 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, widget->allocation.width, widget->allocation.height); g_object_unref (G_OBJECT (gc)); /* set cell data (if available) */ if (cellview->priv->displayed_row) gtk_cell_view_set_cell_data (cellview); else if (cellview->priv->model) 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) state = GTK_CELL_RENDERER_PRELIT; for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (info->pack == GTK_PACK_END) if (!info->cell->visible) area.width = info->real_width; gtk_cell_renderer_render (info->cell, &area, &area, &event->area, state); area.x += info->real_width; area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width); for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (info->pack == GTK_PACK_START) if (!info->cell->visible) area.width = info->real_width; gtk_cell_renderer_render (info->cell, &area, &area, &event->area, state); area.x += info->real_width; static GtkCellViewCellInfo * gtk_cell_view_get_cell_info (GtkCellView *cellview, GtkCellRenderer *renderer) for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; if (info->cell == renderer) gtk_cell_view_set_cell_data (GtkCellView *cellview) g_return_if_fail (cellview->priv->displayed_row != NULL); path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row); gtk_tree_model_get_iter (cellview->priv->model, &iter, path); gtk_tree_path_free (path); for (i = cellview->priv->cell_list; i; i = i->next) GtkCellViewCellInfo *info = i->data; g_object_freeze_notify (G_OBJECT (info->cell)); for (j = info->attributes; j && j->next; j = j->next->next) gchar *property = j->data; gint column = GPOINTER_TO_INT (j->next->data); gtk_tree_model_get_value (cellview->priv->model, &iter, g_object_set_property (G_OBJECT (info->cell), (* info->func) (GTK_CELL_LAYOUT (cellview), g_object_thaw_notify (G_OBJECT (info->cell)); /* GtkCellLayout implementation */ gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, GtkCellRenderer *renderer, 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 (G_OBJECT (renderer)); gtk_object_sink (GTK_OBJECT (renderer)); info = g_new0 (GtkCellViewCellInfo, 1); info->expand = expand ? TRUE : FALSE; info->pack = GTK_PACK_START; cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, GtkCellRenderer *renderer, 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 (G_OBJECT (renderer)); gtk_object_sink (GTK_OBJECT (renderer)); info = g_new0 (GtkCellViewCellInfo, 1); info->expand = expand ? TRUE : FALSE; info->pack = GTK_PACK_END; cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, GtkCellRenderer *renderer, 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); info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column)); info->attributes = g_slist_prepend (info->attributes, 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 (G_OBJECT (info->cell)); cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, cellview->priv->cell_list); gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, GtkCellLayoutDataFunc func, 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); GDestroyNotify d = info->destroy; info->func_data = func_data; gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, GtkCellRenderer *renderer) 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)); info = gtk_cell_view_get_cell_info (cellview, renderer); while (list && list->next) g_slist_free (info->attributes); gtk_cell_view_cell_layout_reorder (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 (cell)); info = gtk_cell_view_get_cell_info (cellview, cell); g_return_if_fail (info != NULL); g_return_if_fail (position >= 0); link = g_list_find (cellview->priv->cell_list, info); g_return_if_fail (link != NULL); cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list, cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list, gtk_widget_queue_draw (GTK_WIDGET (cellview)); cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL)); return GTK_WIDGET (cellview); gtk_cell_view_new_with_text (const gchar *text) GtkCellRenderer *renderer; cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); renderer = gtk_cell_renderer_text_new (); gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, text); gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL); return GTK_WIDGET (cellview); gtk_cell_view_new_with_markup (const gchar *markup) GtkCellRenderer *renderer; cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); renderer = gtk_cell_renderer_text_new (); gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, markup); gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL); return GTK_WIDGET (cellview); gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) GtkCellRenderer *renderer; cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); renderer = gtk_cell_renderer_pixbuf_new (); gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), g_value_init (&value, GDK_TYPE_PIXBUF); g_value_set_object (&value, pixbuf); gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL); return GTK_WIDGET (cellview); gtk_cell_view_set_value (GtkCellView *cell_view, GtkCellRenderer *renderer, 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 */ gtk_widget_queue_resize (GTK_WIDGET (cell_view)); gtk_widget_queue_draw (GTK_WIDGET (cell_view)); gtk_cell_view_set_valuesv (GtkCellView *cell_view, GtkCellRenderer *renderer, attribute = va_arg (args, gchar *); 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 (GtkCellView *cell_view, GtkCellRenderer *renderer, 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); gtk_cell_view_set_model (GtkCellView *cell_view, g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); g_return_if_fail (GTK_IS_TREE_MODEL (model)); if (cell_view->priv->model) if (cell_view->priv->displayed_row) gtk_tree_row_reference_free (cell_view->priv->displayed_row); cell_view->priv->displayed_row = NULL; g_object_unref (G_OBJECT (cell_view->priv->model)); cell_view->priv->model = NULL; cell_view->priv->model = model; if (cell_view->priv->model) g_object_ref (G_OBJECT (cell_view->priv->model)); * gtk_cell_view_set_displayed_row: * @cell_view: a #GtkCellView * @path: 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; * this is not normally a desired result, but may be * a needed intermediate state if say, the model for * the #GtkCellView becomes temporarily empty. gtk_cell_view_set_displayed_row (GtkCellView *cell_view, g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model)); if (cell_view->priv->displayed_row) gtk_tree_row_reference_free (cell_view->priv->displayed_row); cell_view->priv->displayed_row = gtk_tree_row_reference_new (cell_view->priv->model, path); cell_view->priv->displayed_row = NULL; /* force resize and redraw */ gtk_widget_queue_resize (GTK_WIDGET (cell_view)); gtk_widget_queue_draw (GTK_WIDGET (cell_view)); gtk_cell_view_get_displayed_row (GtkCellView *cell_view) g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL); if (!cell_view->priv->displayed_row) return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row); gtk_cell_view_get_size_of_row (GtkCellView *cell_view, GtkRequisition *requisition) GtkTreeRowReference *tmp; 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); 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_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); gtk_cell_view_set_background_color (GtkCellView *view, g_return_if_fail (GTK_IS_CELL_VIEW (view)); if (!view->priv->background_set) view->priv->background_set = TRUE; g_object_notify (G_OBJECT (view), "background_set"); view->priv->background = *color; if (view->priv->background_set) view->priv->background_set = FALSE; g_object_notify (G_OBJECT (view), "background_set");