Mercurial > geeqie
view src/cellrenderericon.c @ 111:3a69a7a3f461
Wed Nov 15 02:05:27 2006 John Ellis <johne@verizon.net>
* view_file_icon.c: Fix odd crash when removing files, it seems the
high priority idle sync is no longer called before the treeview tries
to redraw itself, so fix the cleanup of removed pointers so that they
are always valid or NULL (I wonder if the priorities used by
GtkTreeView have changed in newer versions of GTK?).
* view_file_list.c: Fix progress bar warning when files are removed
before thumbnail generation is finished.
author | gqview |
---|---|
date | Wed, 15 Nov 2006 07:19:16 +0000 |
parents | d907d608745f |
children | 4b2d7f9af171 |
line wrap: on
line source
/* cellrenderericon.c, based on: * * gtkcellrendererpixbuf.c * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.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 <stdlib.h> #include "cellrenderericon.h" #include "intl.h" #define FIXED_ICON_SIZE_MAX 512 static void gqv_cell_renderer_icon_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void gqv_cell_renderer_icon_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void gqv_cell_renderer_icon_init(GQvCellRendererIcon *celltext); static void gqv_cell_renderer_icon_class_init(GQvCellRendererIconClass *class); static void gqv_cell_renderer_icon_finalize(GObject *object); static void gqv_cell_renderer_icon_get_size(GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *rectangle, gint *x_offset, gint *y_offset, gint *width, gint *height); static void gqv_cell_renderer_icon_render(GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags); enum { PROP_ZERO, PROP_PIXBUF, PROP_TEXT, PROP_BACKGROUND_GDK, PROP_FOREGROUND_GDK, PROP_FOCUSED, PROP_FIXED_WIDTH, PROP_FIXED_HEIGHT, PROP_BACKGROUND_SET, PROP_FOREGROUND_SET, PROP_SHOW_TEXT }; static gpointer parent_class; GType gqv_cell_renderer_icon_get_type (void) { static GType cell_icon_type = 0; if (!cell_icon_type) { static const GTypeInfo cell_icon_info = { sizeof (GQvCellRendererIconClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) gqv_cell_renderer_icon_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GQvCellRendererIcon), 0, /* n_preallocs */ (GInstanceInitFunc) gqv_cell_renderer_icon_init, }; cell_icon_type = g_type_register_static(GTK_TYPE_CELL_RENDERER, "GQvCellRendererIcon", &cell_icon_info, 0); } return cell_icon_type; } static void gqv_cell_renderer_icon_init (GQvCellRendererIcon *cellicon) { GTK_CELL_RENDERER(cellicon)->xpad = 2; GTK_CELL_RENDERER(cellicon)->ypad = 2; } static void gqv_cell_renderer_icon_class_init (GQvCellRendererIconClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class); parent_class = g_type_class_peek_parent (class); object_class->finalize = gqv_cell_renderer_icon_finalize; object_class->get_property = gqv_cell_renderer_icon_get_property; object_class->set_property = gqv_cell_renderer_icon_set_property; cell_class->get_size = gqv_cell_renderer_icon_get_size; cell_class->render = gqv_cell_renderer_icon_render; g_object_class_install_property(object_class, PROP_PIXBUF, g_param_spec_object("pixbuf", _("Pixbuf Object"), _("The pixbuf to render"), GDK_TYPE_PIXBUF, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_TEXT, g_param_spec_string("text", _("Text"), _("Text to render"), NULL, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BACKGROUND_GDK, g_param_spec_boxed("background_gdk", _("Background color"), _("Background color as a GdkColor"), GDK_TYPE_COLOR, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_FOREGROUND_GDK, g_param_spec_boxed("foreground_gdk", _("Foreground color"), _("Foreground color as a GdkColor"), GDK_TYPE_COLOR, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_FOCUSED, g_param_spec_boolean ("has_focus", _("Focus"), _("Draw focus indicator"), FALSE, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_FIXED_WIDTH, g_param_spec_int("fixed_width", _("Fixed width"), _("Width of cell"), -1, FIXED_ICON_SIZE_MAX, -1, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_FIXED_HEIGHT, g_param_spec_int("fixed_height", _("Fixed height"), _("Height of icon excluding text"), -1, FIXED_ICON_SIZE_MAX, -1, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BACKGROUND_SET, g_param_spec_boolean("background_set", _("Background set"), _("Whether this tag affects the background color"), FALSE, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_FOREGROUND_SET, g_param_spec_boolean ("foreground_set", _("Foreground set"), _("Whether this tag affects the foreground color"), FALSE, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_SHOW_TEXT, g_param_spec_boolean("show_text", _("Show text"), _("Whether the text is displayed"), TRUE, G_PARAM_READWRITE)); } static void gqv_cell_renderer_icon_finalize (GObject *object) { GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON (object); if (cellicon->pixbuf) g_object_unref (cellicon->pixbuf); g_free(cellicon->text); (* G_OBJECT_CLASS (parent_class)->finalize) (object); } static void gqv_cell_renderer_icon_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON (object); switch (param_id) { case PROP_PIXBUF: g_value_set_object(value, cellicon->pixbuf ? G_OBJECT (cellicon->pixbuf) : NULL); break; case PROP_TEXT: g_value_set_string (value, cellicon->text); break; case PROP_BACKGROUND_GDK: { GdkColor color; color.red = cellicon->background.red; color.green = cellicon->background.green; color.blue = cellicon->background.blue; g_value_set_boxed (value, &color); } break; case PROP_FOREGROUND_GDK: { GdkColor color; color.red = cellicon->foreground.red; color.green = cellicon->foreground.green; color.blue = cellicon->foreground.blue; g_value_set_boxed (value, &color); } break; case PROP_FOCUSED: g_value_set_boolean (value, cellicon->focused); break; case PROP_FIXED_WIDTH: g_value_set_int(value, cellicon->fixed_width); break; case PROP_FIXED_HEIGHT: g_value_set_int(value, cellicon->fixed_height); break; case PROP_BACKGROUND_SET: g_value_set_boolean(value, cellicon->background_set); break; case PROP_FOREGROUND_SET: g_value_set_boolean(value, cellicon->foreground_set); break; case PROP_SHOW_TEXT: g_value_set_boolean(value, cellicon->show_text); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static void set_bg_color (GQvCellRendererIcon *cellicon, GdkColor *color) { if (color) { if (!cellicon->background_set) { cellicon->background_set = TRUE; g_object_notify(G_OBJECT(cellicon), "background_set"); } cellicon->background.red = color->red; cellicon->background.green = color->green; cellicon->background.blue = color->blue; } else { if (cellicon->background_set) { cellicon->background_set = FALSE; g_object_notify(G_OBJECT(cellicon), "background_set"); } } } static void set_fg_color (GQvCellRendererIcon *cellicon, GdkColor *color) { if (color) { if (!cellicon->foreground_set) { cellicon->foreground_set = TRUE; g_object_notify(G_OBJECT(cellicon), "foreground_set"); } cellicon->foreground.red = color->red; cellicon->foreground.green = color->green; cellicon->foreground.blue = color->blue; } else { if (cellicon->foreground_set) { cellicon->foreground_set = FALSE; g_object_notify(G_OBJECT(cellicon), "foreground_set"); } } } static void gqv_cell_renderer_icon_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON (object); switch (param_id) { case PROP_PIXBUF: { GdkPixbuf *pixbuf; pixbuf = (GdkPixbuf*) g_value_get_object (value); if (pixbuf) g_object_ref (pixbuf); if (cellicon->pixbuf) g_object_unref (cellicon->pixbuf); cellicon->pixbuf = pixbuf; } break; case PROP_TEXT: { gchar *text; text = cellicon->text; cellicon->text = g_strdup(g_value_get_string(value)); g_free(text); g_object_notify(object, "text"); } break; case PROP_BACKGROUND_GDK: set_bg_color(cellicon, g_value_get_boxed(value)); break; case PROP_FOREGROUND_GDK: set_fg_color(cellicon, g_value_get_boxed(value)); break; case PROP_FOCUSED: cellicon->focused = g_value_get_boolean(value); break; case PROP_FIXED_WIDTH: cellicon->fixed_width = g_value_get_int(value); break; case PROP_FIXED_HEIGHT: cellicon->fixed_height = g_value_get_int(value); break; case PROP_BACKGROUND_SET: cellicon->background_set = g_value_get_boolean(value); break; case PROP_FOREGROUND_SET: cellicon->foreground_set = g_value_get_boolean(value); break; case PROP_SHOW_TEXT: cellicon->show_text = g_value_get_boolean(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } static PangoLayout * gqv_cell_renderer_icon_get_layout(GQvCellRendererIcon *cellicon, GtkWidget *widget, gboolean will_render) { PangoLayout *layout; gint width; width = (cellicon->fixed_width > 0) ? cellicon->fixed_width * PANGO_SCALE : -1; layout = gtk_widget_create_pango_layout(widget, cellicon->text); pango_layout_set_width(layout, width); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); if (will_render) { PangoAttrList *attr_list; attr_list = pango_attr_list_new(); if (cellicon->foreground_set) { PangoColor color; PangoAttribute *attr; color = cellicon->foreground; attr = pango_attr_foreground_new(color.red, color.green, color.blue); attr->start_index = 0; attr->end_index = G_MAXINT; pango_attr_list_insert(attr_list, attr); } pango_layout_set_attributes(layout, attr_list); pango_attr_list_unref(attr_list); } return layout; } /** * gqv_cell_renderer_icon_new: * * Creates a new #GQvCellRendererIcon. Adjust rendering * parameters using object properties. Object properties can be set * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you * can bind a property to a value in a #GtkTreeModel. For example, you * can bind the "pixbuf" property on the cell renderer to a pixbuf value * in the model, thus rendering a different image in each row of the * #GtkTreeView. * * Return value: the new cell renderer **/ GtkCellRenderer * gqv_cell_renderer_icon_new(void) { return g_object_new (GQV_TYPE_CELL_RENDERER_ICON, NULL); } static void gqv_cell_renderer_icon_get_size(GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height) { GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell; gint calc_width; gint calc_height; if (cellicon->fixed_width > 0) { calc_width = cellicon->fixed_width; } else { calc_width = (cellicon->pixbuf) ? gdk_pixbuf_get_width(cellicon->pixbuf) : 0; } if (cellicon->fixed_height > 0) { calc_height = cellicon->fixed_height; } else { calc_height = (cellicon->pixbuf) ? gdk_pixbuf_get_height(cellicon->pixbuf) : 0; } if (cellicon->show_text && cellicon->text) { PangoLayout *layout; PangoRectangle rect; layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, FALSE); pango_layout_get_pixel_extents(layout, NULL, &rect); g_object_unref(layout); calc_width = MAX(calc_width, rect.width); calc_height += rect.height; } calc_width += (gint)cell->xpad * 2; calc_height += (gint)cell->ypad * 2; if (x_offset) *x_offset = 0; if (y_offset) *y_offset = 0; if (cell_area && calc_width > 0 && calc_height > 0) { if (x_offset) { *x_offset = (cell->xalign * (cell_area->width - calc_width - 2 * cell->xpad)); *x_offset = MAX (*x_offset, 0) + cell->xpad; } if (y_offset) { *y_offset = (cell->yalign * (cell_area->height - calc_height - 2 * cell->ypad)); *y_offset = MAX (*y_offset, 0) + cell->ypad; } } if (width) *width = calc_width; if (height) *height = calc_height; } static void gqv_cell_renderer_icon_render(GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) { GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell; GdkPixbuf *pixbuf; const gchar *text; GdkRectangle cell_rect; GtkStateType state; pixbuf = cellicon->pixbuf; text = cellicon->text; if (!pixbuf && !text) return; gqv_cell_renderer_icon_get_size(cell, widget, cell_area, &cell_rect.x, &cell_rect.y, &cell_rect.width, &cell_rect.height); cell_rect.x += cell->xpad; cell_rect.y += cell->ypad; cell_rect.width -= cell->xpad * 2; cell_rect.height -= cell->ypad * 2; if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { if (GTK_WIDGET_HAS_FOCUS(widget)) state = GTK_STATE_SELECTED; else state = GTK_STATE_ACTIVE; } else { if (GTK_WIDGET_STATE(widget) == GTK_STATE_INSENSITIVE) state = GTK_STATE_INSENSITIVE; else state = GTK_STATE_NORMAL; } if (pixbuf) { GdkRectangle pix_rect; GdkRectangle draw_rect; pix_rect.width = gdk_pixbuf_get_width(pixbuf); pix_rect.height = gdk_pixbuf_get_height(pixbuf); pix_rect.x = cell_area->x + (cell_area->width - pix_rect.width) / 2; if (cellicon->fixed_height > 0) { pix_rect.y = cell_area->y + cell->ypad + (cellicon->fixed_height - pix_rect.height) / 2; } else { pix_rect.y = cell_area->y + cell_rect.y; } if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect) && gdk_rectangle_intersect(expose_area, &draw_rect, &draw_rect)) { gdk_draw_pixbuf(window, widget->style->black_gc, pixbuf, /* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */ draw_rect.x - pix_rect.x, draw_rect.y - pix_rect.y, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height, GDK_RGB_DITHER_NORMAL, 0, 0); } } if (cellicon->show_text && text) { PangoLayout *layout; PangoRectangle text_rect; GdkRectangle pix_rect; GdkRectangle draw_rect; layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, TRUE); pango_layout_get_pixel_extents(layout, NULL, &text_rect); pix_rect.width = text_rect.width; pix_rect.height = text_rect.height; pix_rect.x = cell_area->x + cell->xpad + (cell_rect.width - text_rect.width + 1) / 2; pix_rect.y = cell_area->y + cell->ypad + (cell_rect.height - text_rect.height); if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect) && gdk_rectangle_intersect(expose_area, &draw_rect, &draw_rect)) { gtk_paint_layout(widget->style, window, state, TRUE, cell_area, widget, "cellrenderertext", pix_rect.x - text_rect.x, pix_rect.y, layout); } g_object_unref(layout); } if (cellicon->focused && GTK_WIDGET_HAS_FOCUS(widget)) { gtk_paint_focus(widget->style, window, state, cell_area, widget, "cellrendererfocus", cell_area->x, cell_area->y, cell_area->width, cell_area->height); } }