From 439d7f036f92f1fd744b5d908973b2afdb0efd86 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sun, 31 Oct 2010 16:02:24 -0400 Subject: [PATCH] Port StIcon from MX framework to St framework Make StIcon compile and work in St. Changes: * ::icon-type and st_icon_set_icon_type are added to allow specifying SYMBOLIC/FULLCOLOR for an icon. * Ability to set the icon name from the theme is removed; it wouldn't easily fit into our framework and two levels of abstraction between code and image doesn't seem that useful. * size CSS property is renamed from x-st-icon-size to icon-size to correspond to what we are doing elsewhere. * CSS and property based icon sizing are cleanly layered - if you set the icon-size property, the CSS size is ignored. * Add a simple JS test of StIcon. https://bugzilla.gnome.org/show_bug.cgi?id=633865 --- src/st/st-icon.c | 290 +++++++++++++++++++------------------ src/st/st-icon.h | 7 +- tests/Makefile.am | 1 + tests/interactive/icons.js | 53 +++++++ 4 files changed, 213 insertions(+), 138 deletions(-) create mode 100644 tests/interactive/icons.js diff --git a/src/st/st-icon.c b/src/st/st-icon.c index f17511762..ebcf0f823 100644 --- a/src/st/st-icon.c +++ b/src/st/st-icon.c @@ -3,6 +3,7 @@ * st-icon.c: icon widget * * Copyright 2009, 2010 Intel Corporation. + * Copyright 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, @@ -25,10 +26,9 @@ * a stylesheet. */ +#include "st-enum-types.h" #include "st-icon.h" -#include "st-icon-theme.h" -#include "st-stylable.h" - +#include "st-texture-cache.h" #include "st-private.h" enum @@ -36,14 +36,11 @@ enum PROP_0, PROP_ICON_NAME, + PROP_ICON_TYPE, PROP_ICON_SIZE }; -static void st_stylable_iface_init (StStylableIface *iface); - -G_DEFINE_TYPE_WITH_CODE (StIcon, st_icon, ST_TYPE_WIDGET, - G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - st_stylable_iface_init)) +G_DEFINE_TYPE (StIcon, st_icon, ST_TYPE_WIDGET) #define ST_ICON_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_ICON, StIconPrivate)) @@ -53,37 +50,17 @@ struct _StIconPrivate ClutterActor *icon_texture; gchar *icon_name; - gint icon_size; + StIconType icon_type; + gint prop_icon_size; /* icon size set as property */ + gint theme_icon_size; /* icon size from theme node */ + gint icon_size; /* icon size we are using */ }; -static void st_icon_update (StIcon *icon); +static void st_icon_update (StIcon *icon); +static void st_icon_update_icon_size (StIcon *icon); -static void -st_stylable_iface_init (StStylableIface *iface) -{ - static gboolean is_initialized = FALSE; - - if (G_UNLIKELY (!is_initialized)) - { - GParamSpec *pspec; - - is_initialized = TRUE; - - pspec = g_param_spec_string ("x-st-icon-name", - "Icon name", - "Icon name to load from the theme", - NULL, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_ICON, pspec); - - pspec = g_param_spec_int ("x-st-icon-size", - "Icon size", - "Size to use for icon", - -1, G_MAXINT, -1, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_ICON, pspec); - } -} +#define DEFAULT_ICON_SIZE 48 +#define DEFAULT_ICON_TYPE ST_ICON_SYMBOLIC static void st_icon_set_property (GObject *gobject, @@ -99,6 +76,10 @@ st_icon_set_property (GObject *gobject, st_icon_set_icon_name (icon, g_value_get_string (value)); break; + case PROP_ICON_TYPE: + st_icon_set_icon_type (icon, g_value_get_enum (value)); + break; + case PROP_ICON_SIZE: st_icon_set_icon_size (icon, g_value_get_int (value)); break; @@ -123,6 +104,10 @@ st_icon_get_property (GObject *gobject, g_value_set_string (value, st_icon_get_icon_name (icon)); break; + case PROP_ICON_TYPE: + g_value_set_enum (value, st_icon_get_icon_type (icon)); + break; + case PROP_ICON_SIZE: g_value_set_int (value, st_icon_get_icon_size (icon)); break; @@ -133,18 +118,9 @@ st_icon_get_property (GObject *gobject, } } -static void -st_icon_notify_theme_name_cb (StIconTheme *theme, - GParamSpec *pspec, - StIcon *self) -{ - st_icon_update (self); -} - static void st_icon_dispose (GObject *gobject) { - StIconTheme *theme; StIconPrivate *priv = ST_ICON (gobject)->priv; if (priv->icon_texture) @@ -153,13 +129,6 @@ st_icon_dispose (GObject *gobject) priv->icon_texture = NULL; } - if ((theme = st_icon_theme_get_default ())) - { - g_signal_handlers_disconnect_by_func (st_icon_theme_get_default (), - st_icon_notify_theme_name_cb, - gobject); - } - G_OBJECT_CLASS (st_icon_parent_class)->dispose (gobject); } @@ -169,10 +138,9 @@ st_icon_get_preferred_height (ClutterActor *actor, gfloat *min_height_p, gfloat *nat_height_p) { - StPadding padding; - gfloat pref_height; - StIconPrivate *priv = ST_ICON (actor)->priv; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); + gfloat pref_height; if (priv->icon_texture) { @@ -189,14 +157,13 @@ st_icon_get_preferred_height (ClutterActor *actor, else pref_height = 0; - st_widget_get_padding (ST_WIDGET (actor), &padding); - pref_height += padding.top + padding.bottom; - if (min_height_p) *min_height_p = pref_height; if (nat_height_p) *nat_height_p = pref_height; + + st_theme_node_adjust_preferred_height (theme_node, min_height_p, nat_height_p); } static void @@ -205,10 +172,9 @@ st_icon_get_preferred_width (ClutterActor *actor, gfloat *min_width_p, gfloat *nat_width_p) { - StPadding padding; - gfloat pref_width; - StIconPrivate *priv = ST_ICON (actor)->priv; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); + gfloat pref_width; if (priv->icon_texture) { @@ -225,14 +191,13 @@ st_icon_get_preferred_width (ClutterActor *actor, else pref_width = 0; - st_widget_get_padding (ST_WIDGET (actor), &padding); - pref_width += padding.left + padding.right; - if (min_width_p) *min_width_p = pref_width; if (nat_width_p) *nat_width_p = pref_width; + + st_theme_node_adjust_preferred_width (theme_node, min_width_p, nat_width_p); } static void @@ -241,21 +206,16 @@ st_icon_allocate (ClutterActor *actor, ClutterAllocationFlags flags) { StIconPrivate *priv = ST_ICON (actor)->priv; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); CLUTTER_ACTOR_CLASS (st_icon_parent_class)->allocate (actor, box, flags); if (priv->icon_texture) { - StPadding padding; - ClutterActorBox child_box; + ClutterActorBox content_box; - st_widget_get_padding (ST_WIDGET (actor), &padding); - child_box.x1 = padding.left; - child_box.y1 = padding.top; - child_box.x2 = box->x2 - box->x1 - padding.right; - child_box.y2 = box->y2 - box->y1 - padding.bottom; - - clutter_actor_allocate (priv->icon_texture, &child_box, flags); + st_theme_node_get_content_box (theme_node, box, &content_box); + clutter_actor_allocate (priv->icon_texture, &content_box, flags); } } @@ -293,6 +253,17 @@ st_icon_unmap (ClutterActor *actor) clutter_actor_unmap (priv->icon_texture); } +static void +st_icon_style_changed (StWidget *widget) +{ + StIcon *self = ST_ICON (widget); + StThemeNode *theme_node = st_widget_get_theme_node (widget); + StIconPrivate *priv = self->priv; + + priv->theme_icon_size = st_theme_node_get_length (theme_node, "icon-size"); + st_icon_update_icon_size (self); +} + static void st_icon_class_init (StIconClass *klass) { @@ -300,6 +271,7 @@ st_icon_class_init (StIconClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); g_type_class_add_private (klass, sizeof (StIconPrivate)); @@ -314,20 +286,40 @@ st_icon_class_init (StIconClass *klass) actor_class->map = st_icon_map; actor_class->unmap = st_icon_unmap; + widget_class->style_changed = st_icon_style_changed; + pspec = g_param_spec_string ("icon-name", "Icon name", "An icon name", NULL, ST_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_ICON_NAME, pspec); + pspec = g_param_spec_enum ("icon-type", + "Icon type", + "The type of icon that should be used", + ST_TYPE_ICON_TYPE, + DEFAULT_ICON_TYPE, + ST_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ICON_TYPE, pspec); + pspec = g_param_spec_int ("icon-size", "Icon size", - "Size of the icon", - 1, G_MAXINT, 48, + "The size if the icon, if positive. Otherwise the size will be derived from the current style", + -1, G_MAXINT, -1, ST_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_ICON_SIZE, pspec); } +static void +st_icon_init (StIcon *self) +{ + self->priv = ST_ICON_GET_PRIVATE (self); + + self->priv->icon_size = DEFAULT_ICON_SIZE; + self->priv->prop_icon_size = -1; + self->priv->icon_type = DEFAULT_ICON_TYPE; +} + static void st_icon_update (StIcon *icon) { @@ -343,16 +335,12 @@ st_icon_update (StIcon *icon) /* Try to lookup the new one */ if (priv->icon_name) { - StIconTheme *theme = st_icon_theme_get_default (); - priv->icon_texture = (ClutterActor *) - st_icon_theme_lookup_texture (theme, priv->icon_name, priv->icon_size); + StTextureCache *cache = st_texture_cache_get_default (); - /* If the icon is missing, use the image-missing icon */ - if (!priv->icon_texture) - priv->icon_texture = (ClutterActor *) - st_icon_theme_lookup_texture (theme, - "image-missing", - priv->icon_size); + priv->icon_texture = st_texture_cache_load_icon_name (cache, + priv->icon_name, + priv->icon_type, + priv->icon_size); if (priv->icon_texture) clutter_actor_set_parent (priv->icon_texture, CLUTTER_ACTOR (icon)); @@ -362,58 +350,23 @@ st_icon_update (StIcon *icon) } static void -st_icon_style_changed_cb (StWidget *widget) +st_icon_update_icon_size (StIcon *icon) { - StIcon *self = ST_ICON (widget); - StIconPrivate *priv = self->priv; + StIconPrivate *priv = icon->priv; + int new_size; - gboolean changed = FALSE; - gchar *icon_name = NULL; - gint icon_size = -1; + if (priv->prop_icon_size > 0) + new_size = priv->prop_icon_size; + else if (priv->theme_icon_size > 0) + new_size = priv->theme_icon_size; + else + new_size = DEFAULT_ICON_SIZE; - st_stylable_get (ST_STYLABLE (widget), - "x-st-icon-name", &icon_name, - "x-st-icon-size", &icon_size, - NULL); - - if (icon_name && (!priv->icon_name || - !g_str_equal (icon_name, priv->icon_name))) + if (new_size != priv->icon_size) { - g_free (priv->icon_name); - priv->icon_name = g_strdup (icon_name); - changed = TRUE; - - g_object_notify (G_OBJECT (self), "icon-name"); + priv->icon_size = new_size; + st_icon_update (icon); } - - if ((icon_size > 0) && (priv->icon_size != icon_size)) - { - priv->icon_size = icon_size; - changed = TRUE; - - g_object_notify (G_OBJECT (self), "icon-size"); - } - - if (changed) - st_icon_update (self); -} - -static void -st_icon_init (StIcon *self) -{ - self->priv = ST_ICON_GET_PRIVATE (self); - - self->priv->icon_size = 48; - - g_signal_connect (self, "style-changed", - G_CALLBACK (st_icon_style_changed_cb), NULL); - - /* make sure we are not reactive */ - clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE); - - /* Reload the icon when the theme changes */ - g_signal_connect (st_icon_theme_get_default (), "notify::theme-name", - G_CALLBACK (st_icon_notify_theme_name_cb), self); } /** @@ -429,7 +382,6 @@ st_icon_new (void) return g_object_new (ST_TYPE_ICON, NULL); } - const gchar * st_icon_get_icon_name (StIcon *icon) { @@ -460,13 +412,77 @@ st_icon_set_icon_name (StIcon *icon, g_object_notify (G_OBJECT (icon), "icon-name"); } +/** + * st_icon_get_icon_type: + * @icon: a #StIcon + * + * Gets the type of icon we'll look up to display in the actor. + * See st_icon_set_icon_type(). + * + * Return value: the icon type. + */ +StIconType +st_icon_get_icon_type (StIcon *icon) +{ + g_return_val_if_fail (ST_IS_ICON (icon), DEFAULT_ICON_TYPE); + + return icon->priv->icon_type; +} + +/** + * st_icon_set_icon_type: + * @icon: a #StIcon + * @icon_type: the type of icon to use + * + * Sets the type of icon we'll look up to display in the actor. + * The icon type determines whether we use a symbolic icon or + * a full color icon and also is used for specific handling for + * application and document icons. + */ +void +st_icon_set_icon_type (StIcon *icon, + StIconType icon_type) +{ + StIconPrivate *priv; + + g_return_if_fail (ST_IS_ICON (icon)); + + priv = icon->priv; + + if (icon_type == priv->icon_type) + return; + + priv->icon_type = icon_type; + st_icon_update (icon); + + g_object_notify (G_OBJECT (icon), "icon-type"); +} + +/** + * st_icon_get_icon_size: + * @icon: an icon + * + * Gets the size explicit size on the icon. This is not necesariily + * the size that the icon will actually be displayed at. + * + * Return value: the size explicitly set, or -1 if no size has been set + */ gint st_icon_get_icon_size (StIcon *icon) { g_return_val_if_fail (ST_IS_ICON (icon), -1); - return icon->priv->icon_size; + return icon->priv->prop_icon_size; } + +/** + * st_icon_set_icon_size: + * @icon: an icon + * @size: if positive, the new size, otherwise the size will be + * derived from the current style + * + * Sets an explicit size for the icon. + */ void st_icon_set_icon_size (StIcon *icon, gint size) @@ -474,13 +490,13 @@ st_icon_set_icon_size (StIcon *icon, StIconPrivate *priv; g_return_if_fail (ST_IS_ICON (icon)); - g_return_if_fail (size > 0); priv = icon->priv; - if (priv->icon_size != size) + if (priv->prop_icon_size != size) { - priv->icon_size = size; - st_icon_update (icon); + priv->prop_icon_size = size; + st_icon_update_icon_size (icon); + g_object_notify (G_OBJECT (icon), "icon-size"); } } diff --git a/src/st/st-icon.h b/src/st/st-icon.h index 4fcde24f3..bddb41d89 100644 --- a/src/st/st-icon.h +++ b/src/st/st-icon.h @@ -29,7 +29,9 @@ #define _ST_ICON #include -#include "st-widget.h" +#include + +#include G_BEGIN_DECLS @@ -85,6 +87,9 @@ ClutterActor* st_icon_new (void); const gchar *st_icon_get_icon_name (StIcon *icon); void st_icon_set_icon_name (StIcon *icon, const gchar *icon_name); +void st_icon_set_icon_type (StIcon *icon, StIconType icon_type); +StIconType st_icon_get_icon_type (StIcon *icon); + gint st_icon_get_icon_size (StIcon *icon); void st_icon_set_icon_size (StIcon *icon, gint size); diff --git a/tests/Makefile.am b/tests/Makefile.am index ea2164587..42a92a3a1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,7 @@ TEST_JS = \ interactive/calendar.js \ interactive/css-fonts.js \ interactive/entry.js \ + interactive/icons.js \ interactive/inline-style.js \ interactive/scrolling.js \ interactive/scroll-view-sizing.js \ diff --git a/tests/interactive/icons.js b/tests/interactive/icons.js new file mode 100644 index 000000000..0c5a879ce --- /dev/null +++ b/tests/interactive/icons.js @@ -0,0 +1,53 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; + +const UI = imports.testcommon.ui; + +UI.init(); +let stage = Clutter.Stage.get_default(); + +let b = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); +stage.add_actor(b); + +function addTest(label, icon_props) { + if (b.get_children().length > 0) + b.add (new St.BoxLayout({ style: 'background: #cccccc; border: 10px transparent white; height: 1px; ' })); + + let hb = new St.BoxLayout({ vertical: false }); + + hb.add(new St.Label({ text: label })); + hb.add(new St.Icon(icon_props)); + + b.add(hb); +} + +addTest("Symbolic", + { icon_name: 'zoom-in', + icon_type: St.IconType.SYMBOLIC, + icon_size: 48 }); +addTest("Full color", + { icon_name: 'zoom-in', + icon_type: St.IconType.FULLCOLOR, + icon_size: 48 }); +addTest("Default size", + { icon_name: 'zoom-in', + icon_type: St.IconType.SYMBOLIC }); +addTest("Size set by property", + { icon_name: 'zoom-in', + icon_type: St.IconType.SYMBOLIC, + icon_size: 32 }); +addTest("Size set by style", + { icon_name: 'zoom-in', + icon_type: St.IconType.SYMBOLIC, + style: 'icon-size: 1em;' }); +addTest("16px icon in 48px icon widget", + { icon_name: 'zoom-in', + icon_type: St.IconType.SYMBOLIC, + style: 'icon-size: 16px; width: 48px; height: 48px;' }); + +stage.show(); +Clutter.main();