/* * Copyright © 2015 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Benjamin Otte */ #include "config.h" #include "gtkbuiltiniconprivate.h" #include "gtkcssnodeprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkrendericonprivate.h" /* GtkBuiltinIcon is a gadget implementation that is meant to replace * all calls to gtk_render_ functions to render arrows, expanders, checks * radios, handles, separators, etc. See the GtkCssImageBuiltinType * enumeration for the full set of builtin icons that this gadget can * render. * * Use gtk_builtin_icon_set_image to set which of the builtin icons * is rendered. * * Use gtk_builtin_icon_set_default_size to set a non-zero default * size for the icon. If you need to support a legacy size style property, * use gtk_builtin_icon_set_default_size_property. * * Themes can override the acutal image that is used with the * -gtk-icon-source property. If it is not specified, a builtin * fallback is used. */ typedef struct _GtkBuiltinIconPrivate GtkBuiltinIconPrivate; struct _GtkBuiltinIconPrivate { GtkCssImageBuiltinType image_type; int default_size; int strikethrough; gboolean strikethrough_valid; char * default_size_property; }; G_DEFINE_TYPE_WITH_CODE (GtkBuiltinIcon, gtk_builtin_icon, GTK_TYPE_CSS_GADGET, G_ADD_PRIVATE (GtkBuiltinIcon)) static void gtk_builtin_icon_get_preferred_size (GtkCssGadget *gadget, GtkOrientation orientation, gint for_size, gint *minimum, gint *natural, gint *minimum_baseline, gint *natural_baseline) { GtkBuiltinIconPrivate *priv = gtk_builtin_icon_get_instance_private (GTK_BUILTIN_ICON (gadget)); double min_size; guint property; if (orientation == GTK_ORIENTATION_HORIZONTAL) property = GTK_CSS_PROPERTY_MIN_WIDTH; else property = GTK_CSS_PROPERTY_MIN_HEIGHT; min_size = _gtk_css_number_value_get (gtk_css_style_get_value (gtk_css_gadget_get_style (gadget), property), 100); if (min_size > 0.0) { *minimum = *natural = min_size; } else if (priv->default_size_property) { GValue value = G_VALUE_INIT; /* Do it a bit more complicated here so we get warnings when * somebody sets a non-int proerty. */ g_value_init (&value, G_TYPE_INT); gtk_widget_style_get_property (gtk_css_gadget_get_owner (gadget), priv->default_size_property, &value); *minimum = *natural = g_value_get_int (&value); g_value_unset (&value); } else { *minimum = *natural = priv->default_size; } if (minimum_baseline) { if (!priv->strikethrough_valid) { GtkWidget *widget; PangoContext *pango_context; const PangoFontDescription *font_desc; PangoFontMetrics *metrics; widget = gtk_css_gadget_get_owner (gadget); pango_context = gtk_widget_get_pango_context (widget); font_desc = pango_context_get_font_description (pango_context); metrics = pango_context_get_metrics (pango_context, font_desc, pango_context_get_language (pango_context)); priv->strikethrough = pango_font_metrics_get_strikethrough_position (metrics); priv->strikethrough_valid = TRUE; pango_font_metrics_unref (metrics); } *minimum_baseline = *minimum * 0.5 + PANGO_PIXELS (priv->strikethrough); } if (natural_baseline) *natural_baseline = *minimum_baseline; } static void gtk_builtin_icon_allocate (GtkCssGadget *gadget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip) { GdkRectangle icon_clip; GTK_CSS_GADGET_CLASS (gtk_builtin_icon_parent_class)->allocate (gadget, allocation, baseline, out_clip); gtk_css_style_render_icon_get_extents (gtk_css_gadget_get_style (gadget), &icon_clip, allocation->x, allocation->y, allocation->width, allocation->height); gdk_rectangle_union (out_clip, &icon_clip, out_clip); } static gboolean gtk_builtin_icon_draw (GtkCssGadget *gadget, cairo_t *cr, int x, int y, int width, int height) { GtkBuiltinIconPrivate *priv = gtk_builtin_icon_get_instance_private (GTK_BUILTIN_ICON (gadget)); gtk_css_style_render_icon (gtk_css_gadget_get_style (gadget), cr, x, y, width, height, priv->image_type); return FALSE; } static void gtk_builtin_icon_style_changed (GtkCssGadget *gadget, GtkCssStyleChange *change) { GtkBuiltinIconPrivate *priv = gtk_builtin_icon_get_instance_private (GTK_BUILTIN_ICON (gadget)); if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_FONT)) priv->strikethrough_valid = FALSE; GTK_CSS_GADGET_CLASS (gtk_builtin_icon_parent_class)->style_changed (gadget, change); } static void gtk_builtin_icon_finalize (GObject *object) { GtkBuiltinIconPrivate *priv = gtk_builtin_icon_get_instance_private (GTK_BUILTIN_ICON (object)); g_free (priv->default_size_property); G_OBJECT_CLASS (gtk_builtin_icon_parent_class)->finalize (object); } static void gtk_builtin_icon_class_init (GtkBuiltinIconClass *klass) { GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gtk_builtin_icon_finalize; gadget_class->get_preferred_size = gtk_builtin_icon_get_preferred_size; gadget_class->allocate = gtk_builtin_icon_allocate; gadget_class->draw = gtk_builtin_icon_draw; gadget_class->style_changed = gtk_builtin_icon_style_changed; } static void gtk_builtin_icon_init (GtkBuiltinIcon *custom_gadget) { } GtkCssGadget * gtk_builtin_icon_new_for_node (GtkCssNode *node, GtkWidget *owner) { return g_object_new (GTK_TYPE_BUILTIN_ICON, "node", node, "owner", owner, NULL); } GtkCssGadget * gtk_builtin_icon_new (const char *name, GtkWidget *owner, GtkCssGadget *parent, GtkCssGadget *next_sibling) { GtkCssNode *node; GtkCssGadget *result; node = gtk_css_node_new (); gtk_css_node_set_name (node, g_intern_string (name)); if (parent) gtk_css_node_insert_before (gtk_css_gadget_get_node (parent), node, next_sibling ? gtk_css_gadget_get_node (next_sibling) : NULL); result = gtk_builtin_icon_new_for_node (node, owner); g_object_unref (node); return result; } void gtk_builtin_icon_set_image (GtkBuiltinIcon *icon, GtkCssImageBuiltinType image) { GtkBuiltinIconPrivate *priv; g_return_if_fail (GTK_IS_BUILTIN_ICON (icon)); priv = gtk_builtin_icon_get_instance_private (icon); if (priv->image_type != image) { priv->image_type = image; gtk_widget_queue_draw (gtk_css_gadget_get_owner (GTK_CSS_GADGET (icon))); } } GtkCssImageBuiltinType gtk_builtin_icon_get_image (GtkBuiltinIcon *icon) { GtkBuiltinIconPrivate *priv; g_return_val_if_fail (GTK_IS_BUILTIN_ICON (icon), GTK_CSS_IMAGE_BUILTIN_NONE); priv = gtk_builtin_icon_get_instance_private (icon); return priv->image_type; } void gtk_builtin_icon_set_default_size (GtkBuiltinIcon *icon, int default_size) { GtkBuiltinIconPrivate *priv; g_return_if_fail (GTK_IS_BUILTIN_ICON (icon)); priv = gtk_builtin_icon_get_instance_private (icon); if (priv->default_size != default_size) { priv->default_size = default_size; gtk_widget_queue_resize (gtk_css_gadget_get_owner (GTK_CSS_GADGET (icon))); } } int gtk_builtin_icon_get_default_size (GtkBuiltinIcon *icon) { GtkBuiltinIconPrivate *priv; g_return_val_if_fail (GTK_IS_BUILTIN_ICON (icon), GTK_CSS_IMAGE_BUILTIN_NONE); priv = gtk_builtin_icon_get_instance_private (icon); return priv->default_size; } /** * gtk_builtin_icon_set_default_size_property: * @icon: icon to set the property for * @property_name: Name of the style property * * Sets the name of a widget style property to use to compute the default size * of the icon. If it is set to no %NULL, it will be used instead of the value * set via gtk_builtin_icon_set_default_size() to set the default size of the * icon. * * @property_name must refer to a style property that is of integer type. * * This function is intended strictly for backwards compatibility reasons. */ void gtk_builtin_icon_set_default_size_property (GtkBuiltinIcon *icon, const char *property_name) { GtkBuiltinIconPrivate *priv; g_return_if_fail (GTK_IS_BUILTIN_ICON (icon)); priv = gtk_builtin_icon_get_instance_private (icon); if (g_strcmp0 (priv->default_size_property, property_name)) { priv->default_size_property = g_strdup (property_name); gtk_widget_queue_resize (gtk_css_gadget_get_owner (GTK_CSS_GADGET (icon))); } } const char * gtk_builtin_icon_get_default_size_property (GtkBuiltinIcon *icon) { GtkBuiltinIconPrivate *priv; g_return_val_if_fail (GTK_IS_BUILTIN_ICON (icon), NULL); priv = gtk_builtin_icon_get_instance_private (icon); return priv->default_size_property; }