2015-12-16 03:08:08 +00:00
|
|
|
/*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gtkbuiltiniconprivate.h"
|
|
|
|
|
|
|
|
#include "gtkcssnodeprivate.h"
|
2015-12-16 03:44:52 +00:00
|
|
|
#include "gtkcssnumbervalueprivate.h"
|
2015-12-16 03:08:08 +00:00
|
|
|
#include "gtkrendericonprivate.h"
|
|
|
|
|
2015-12-22 19:09:36 +00:00
|
|
|
/* 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
|
2016-10-04 17:53:36 +00:00
|
|
|
* size for the icon.
|
2015-12-22 19:09:36 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2015-12-16 03:08:08 +00:00
|
|
|
typedef struct _GtkBuiltinIconPrivate GtkBuiltinIconPrivate;
|
|
|
|
struct _GtkBuiltinIconPrivate {
|
|
|
|
GtkCssImageBuiltinType image_type;
|
|
|
|
int default_size;
|
2016-04-25 07:22:54 +00:00
|
|
|
int strikethrough;
|
|
|
|
gboolean strikethrough_valid;
|
2015-12-16 03:08:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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));
|
2015-12-16 03:44:52 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-01-18 02:02:18 +00:00
|
|
|
*minimum = *natural = min_size;
|
2015-12-16 03:44:52 +00:00
|
|
|
}
|
2016-01-18 02:02:18 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*minimum = *natural = priv->default_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (minimum_baseline)
|
2016-04-25 07:22:54 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-01-18 02:02:18 +00:00
|
|
|
if (natural_baseline)
|
|
|
|
*natural_baseline = *minimum_baseline;
|
2015-12-16 03:08:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2015-12-16 17:44:58 +00:00
|
|
|
cairo_t *cr,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height)
|
2015-12-16 03:08:08 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-16 19:51:53 +00:00
|
|
|
static gboolean
|
|
|
|
gtk_builtin_icon_snapshot (GtkCssGadget *gadget,
|
|
|
|
GtkSnapshot *snapshot,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
GtkBuiltinIconPrivate *priv = gtk_builtin_icon_get_instance_private (GTK_BUILTIN_ICON (gadget));
|
|
|
|
|
|
|
|
gtk_snapshot_translate_2d (snapshot, x, y);
|
|
|
|
gtk_css_style_snapshot_icon (gtk_css_gadget_get_style (gadget),
|
|
|
|
snapshot,
|
|
|
|
width, height,
|
|
|
|
priv->image_type);
|
|
|
|
gtk_snapshot_translate_2d (snapshot, -x, -y);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-04-25 07:22:54 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-12-16 03:08:08 +00:00
|
|
|
static void
|
|
|
|
gtk_builtin_icon_class_init (GtkBuiltinIconClass *klass)
|
|
|
|
{
|
|
|
|
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
|
|
|
|
|
|
|
|
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;
|
2016-11-16 19:51:53 +00:00
|
|
|
gadget_class->snapshot = gtk_builtin_icon_snapshot;
|
2016-04-25 07:22:54 +00:00
|
|
|
gadget_class->style_changed = gtk_builtin_icon_style_changed;
|
2015-12-16 03:08:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|