[gnome-shell] Add support for inline styles
- From: Owen Taylor <otaylor src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] Add support for inline styles
- Date: Thu, 1 Oct 2009 18:54:33 +0000 (UTC)
commit 6527dbc8b71a14e0259cf6c26295f82e1acd8a5e
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Sat Sep 19 22:56:09 2009 -0400
Add support for inline styles
Add support for passing an inline-style string when creating a
StThemeNode.
Hook this up to a new 'style' property of StWidget.
Add a test case that demonstrates using this to update font sizes
on the fly.
https://bugzilla.gnome.org/show_bug.cgi?id=595991
src/st/st-theme-context.c | 2 +-
src/st/st-theme-node.c | 40 ++++++++++++++++++-
src/st/st-theme-node.h | 3 +-
src/st/st-theme-private.h | 6 +--
src/st/st-theme.c | 13 ++----
src/st/st-widget.c | 74 ++++++++++++++++++++++++++++++++++++-
src/st/st-widget.h | 3 +
src/st/test-theme.c | 28 ++++++++++----
tests/interactive/inline-style.js | 47 +++++++++++++++++++++++
9 files changed, 190 insertions(+), 26 deletions(-)
---
diff --git a/src/st/st-theme-context.c b/src/st/st-theme-context.c
index d162978..ce755d5 100644
--- a/src/st/st-theme-context.c
+++ b/src/st/st-theme-context.c
@@ -281,7 +281,7 @@ st_theme_context_get_root_node (StThemeContext *context)
{
if (context->root_node == NULL)
context->root_node = st_theme_node_new (context, NULL, context->theme,
- G_TYPE_NONE, NULL, NULL, NULL);
+ G_TYPE_NONE, NULL, NULL, NULL, NULL);
return context->root_node;
}
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index 2b1b8f2..26df22a 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -33,10 +33,14 @@ struct _StThemeNode {
char *element_id;
char *element_class;
char *pseudo_class;
+ char *inline_style;
CRDeclaration **properties;
int n_properties;
+ /* We hold onto these separately so we can destroy them on finalize */
+ CRDeclaration *inline_properties;
+
guint properties_computed : 1;
guint borders_computed : 1;
guint background_computed : 1;
@@ -76,6 +80,7 @@ st_theme_node_finalize (GObject *object)
g_free (node->element_id);
g_free (node->element_class);
g_free (node->pseudo_class);
+ g_free (node->inline_style);
if (node->properties)
{
@@ -84,6 +89,12 @@ st_theme_node_finalize (GObject *object)
node->n_properties = 0;
}
+ if (node->inline_properties)
+ {
+ /* This destroys the list, not just the head of the list */
+ cr_declaration_destroy (node->inline_properties);
+ }
+
if (node->font_desc)
{
pango_font_description_free (node->font_desc);
@@ -131,7 +142,8 @@ st_theme_node_new (StThemeContext *context,
GType element_type,
const char *element_id,
const char *element_class,
- const char *pseudo_class)
+ const char *pseudo_class,
+ const char *inline_style)
{
StThemeNode *node;
@@ -156,6 +168,7 @@ st_theme_node_new (StThemeContext *context,
node->element_id = g_strdup (element_id);
node->element_class = g_strdup (element_class);
node->pseudo_class = g_strdup (pseudo_class);
+ node->inline_style = g_strdup (inline_style);
return node;
}
@@ -230,11 +243,32 @@ ensure_properties (StThemeNode *node)
{
if (!node->properties_computed)
{
+ GPtrArray *properties = NULL;
+
node->properties_computed = TRUE;
if (node->theme)
- _st_theme_get_matched_properties (node->theme, node,
- &node->properties, &node->n_properties);
+ properties = _st_theme_get_matched_properties (node->theme, node);
+
+ if (node->inline_style)
+ {
+ CRDeclaration *cur_decl;
+
+ if (!properties)
+ properties = g_ptr_array_new ();
+
+ node->inline_properties = cr_declaration_parse_list_from_buf ((const guchar *)node->inline_style,
+ CR_UTF_8);
+
+ for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
+ g_ptr_array_add (properties, cur_decl);
+ }
+
+ if (properties)
+ {
+ node->n_properties = properties->len;
+ node->properties = (CRDeclaration **)g_ptr_array_free (properties, FALSE);
+ }
}
}
diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h
index 623cea8..981ccaa 100644
--- a/src/st/st-theme-node.h
+++ b/src/st/st-theme-node.h
@@ -58,7 +58,8 @@ StThemeNode *st_theme_node_new (StThemeContext *context,
GType element_type,
const char *element_id,
const char *element_class,
- const char *pseudo_class);
+ const char *pseudo_class,
+ const char *inline_style);
StThemeNode *st_theme_node_get_parent (StThemeNode *node);
diff --git a/src/st/st-theme-private.h b/src/st/st-theme-private.h
index c2478e4..a307b08 100644
--- a/src/st/st-theme-private.h
+++ b/src/st/st-theme-private.h
@@ -7,10 +7,8 @@
G_BEGIN_DECLS
-void _st_theme_get_matched_properties (StTheme *theme,
- StThemeNode *node,
- CRDeclaration ***properties,
- int *n_properties);
+GPtrArray *_st_theme_get_matched_properties (StTheme *theme,
+ StThemeNode *node);
/* Resolve an URL from the stylesheet to a filename */
char *_st_theme_resolve_url (StTheme *theme,
diff --git a/src/st/st-theme.c b/src/st/st-theme.c
index 013b65d..420f1fa 100644
--- a/src/st/st-theme.c
+++ b/src/st/st-theme.c
@@ -879,18 +879,16 @@ compare_declarations (gconstpointer a,
return 0;
}
-void
+GPtrArray *
_st_theme_get_matched_properties (StTheme *theme,
- StThemeNode *node,
- CRDeclaration ***properties,
- int *n_properties)
+ StThemeNode *node)
{
enum CRStyleOrigin origin = 0;
CRStyleSheet *sheet = NULL;
GPtrArray *props = g_ptr_array_new ();
- g_return_if_fail (ST_IS_THEME (theme));
- g_return_if_fail (ST_IS_THEME_NODE (node));
+ g_return_val_if_fail (ST_IS_THEME (theme), NULL);
+ g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin++)
{
@@ -905,8 +903,7 @@ _st_theme_get_matched_properties (StTheme *theme,
* after earlier declarations */
g_ptr_array_sort (props, compare_declarations);
- *n_properties = props->len;
- *properties = (CRDeclaration **) g_ptr_array_free (props, FALSE);
+ return props;
}
/* Resolve an url from an url() reference in a stylesheet into an absolute
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index 29cdb05..225948e 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -54,6 +54,7 @@ struct _StWidgetPrivate
StThemeNode *theme_node;
gchar *pseudo_class;
gchar *style_class;
+ gchar *inline_style;
ClutterActor *border_image;
ClutterActor *background_image;
@@ -84,6 +85,7 @@ enum
PROP_THEME,
PROP_PSEUDO_CLASS,
PROP_STYLE_CLASS,
+ PROP_STYLE,
PROP_STYLABLE,
@@ -126,6 +128,10 @@ st_widget_set_property (GObject *gobject,
st_widget_set_style_class_name (actor, g_value_get_string (value));
break;
+ case PROP_STYLE:
+ st_widget_set_style (actor, g_value_get_string (value));
+ break;
+
case PROP_STYLABLE:
if (actor->priv->is_stylable != g_value_get_boolean (value))
{
@@ -171,6 +177,10 @@ st_widget_get_property (GObject *gobject,
g_value_set_string (value, priv->style_class);
break;
+ case PROP_STYLE:
+ g_value_set_string (value, priv->inline_style);
+ break;
+
case PROP_STYLABLE:
g_value_set_boolean (value, priv->is_stylable);
break;
@@ -659,7 +669,8 @@ st_widget_get_theme_node (StWidget *widget)
G_OBJECT_TYPE (widget),
clutter_actor_get_name (CLUTTER_ACTOR (widget)),
priv->style_class,
- priv->pseudo_class);
+ priv->pseudo_class,
+ priv->inline_style);
}
return priv->theme_node;
@@ -764,6 +775,20 @@ st_widget_class_init (StWidgetClass *klass)
ST_PARAM_READWRITE));
/**
+ * StWidget:style:
+ *
+ * Inline style information for the actor as a ';'-separated list of
+ * CSS properties.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_STYLE,
+ g_param_spec_string ("style",
+ "Style",
+ "Inline style string",
+ "",
+ ST_PARAM_READWRITE));
+
+ /**
* StWidget:theme
*
* A theme set on this actor overriding the global theming for this actor
@@ -972,6 +997,53 @@ st_widget_set_style_pseudo_class (StWidget *actor,
}
}
+/**
+ * st_widget_set_style:
+ * @actor: a #StWidget
+ * @style_class: (allow-none): a inline style string, or %NULL
+ *
+ * Set the inline style string for this widget. The inline style string is an
+ * optional ';'-separated list of CSS properties that override the style as
+ * determined from the stylesheets of the current theme.
+ */
+void
+st_widget_set_style (StWidget *actor,
+ const gchar *style)
+{
+ StWidgetPrivate *priv = actor->priv;
+
+ g_return_if_fail (ST_IS_WIDGET (actor));
+
+ priv = actor->priv;
+
+ if (g_strcmp0 (style, priv->inline_style))
+ {
+ g_free (priv->inline_style);
+ priv->inline_style = g_strdup (style);
+
+ st_widget_style_changed (actor);
+
+ g_object_notify (G_OBJECT (actor), "style");
+ }
+}
+
+/**
+ * st_widget_get_style:
+ * @actor: a #StWidget
+ *
+ * Get the current inline style string. See st_widget_set_style().
+ *
+ * Returns: The inline style string, or %NULL. The string is owned by the
+ * #StWidget and should not be modified or freed.
+ */
+const gchar*
+st_widget_get_style (StWidget *actor)
+{
+ g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
+
+ return actor->priv->inline_style;
+}
+
static void
st_widget_name_notify (StWidget *widget,
GParamSpec *pspec,
diff --git a/src/st/st-widget.h b/src/st/st-widget.h
index 2c636c9..5128da0 100644
--- a/src/st/st-widget.h
+++ b/src/st/st-widget.h
@@ -86,6 +86,9 @@ G_CONST_RETURN gchar *st_widget_get_style_pseudo_class (StWidget *actor);
void st_widget_set_style_class_name (StWidget *actor,
const gchar *style_class);
G_CONST_RETURN gchar *st_widget_get_style_class_name (StWidget *actor);
+void st_widget_set_style (StWidget *actor,
+ const gchar *style);
+G_CONST_RETURN gchar *st_widget_get_style (StWidget *actor);
void st_widget_set_theme (StWidget *actor,
StTheme *theme);
StTheme * st_widget_get_theme (StWidget *actor);
diff --git a/src/st/test-theme.c b/src/st/test-theme.c
index 555931d..772981b 100644
--- a/src/st/test-theme.c
+++ b/src/st/test-theme.c
@@ -244,6 +244,16 @@ test_pseudo_class (void)
assert_text_decoration (group3, "group3", 0);
}
+static void
+test_inline_style (void)
+{
+ test = "inline_style";
+ /* These properties come from the inline-style specified when creating the node */
+ assert_foreground_color (text3, "text3", 0x00000ffff);
+ assert_length ("text3", "padding-bottom", 12.,
+ st_theme_node_get_padding (text3, ST_SIDE_BOTTOM));
+}
+
int
main (int argc, char **argv)
{
@@ -263,21 +273,22 @@ main (int argc, char **argv)
root = st_theme_context_get_root_node (context);
group1 = st_theme_node_new (context, root, NULL,
- CLUTTER_TYPE_GROUP, "group1", NULL, NULL);
+ CLUTTER_TYPE_GROUP, "group1", NULL, NULL, NULL);
text1 = st_theme_node_new (context, group1, NULL,
- CLUTTER_TYPE_TEXT, "text1", "special-text", NULL);
+ CLUTTER_TYPE_TEXT, "text1", "special-text", NULL, NULL);
text2 = st_theme_node_new (context, group1, NULL,
- CLUTTER_TYPE_TEXT, "text2", NULL, NULL);
+ CLUTTER_TYPE_TEXT, "text2", NULL, NULL, NULL);
group2 = st_theme_node_new (context, root, NULL,
- CLUTTER_TYPE_GROUP, "group2", NULL, NULL);
+ CLUTTER_TYPE_GROUP, "group2", NULL, NULL, NULL);
text3 = st_theme_node_new (context, group2, NULL,
- CLUTTER_TYPE_TEXT, "text3", NULL, NULL);
+ CLUTTER_TYPE_TEXT, "text3", NULL, NULL,
+ "color: #0000ff; padding-bottom: 12px;");
text4 = st_theme_node_new (context, group2, NULL,
- CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover");
+ CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
group3 = st_theme_node_new (context, group2, NULL,
- CLUTTER_TYPE_GROUP, "group3", NULL, "hover");
+ CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
cairo_texture = st_theme_node_new (context, root, NULL,
- CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL);
+ CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
test_defaults ();
test_lengths ();
@@ -287,6 +298,7 @@ main (int argc, char **argv)
test_background ();
test_font ();
test_pseudo_class ();
+ test_inline_style ();
return fail ? 1 : 0;
}
diff --git a/tests/interactive/inline-style.js b/tests/interactive/inline-style.js
new file mode 100644
index 0000000..2232c0d
--- /dev/null
+++ b/tests/interactive/inline-style.js
@@ -0,0 +1,47 @@
+/* -*- 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 vbox = new St.BoxLayout({ vertical: true,
+ width: stage.width,
+ height: stage.height });
+stage.add_actor(vbox);
+
+let hbox = new St.BoxLayout({ spacing: 12 });
+vbox.add(hbox);
+
+let text = new St.Label({ text: "Styled Text" });
+vbox.add (text);
+
+let size = 24;
+function update_size() {
+ text.style = 'font-size: ' + size + 'pt';
+}
+update_size();
+
+let button = new St.Button ({ label: 'Smaller',
+ style: 'padding: 4px; background: #eeddcc' });
+hbox.add (button);
+button.connect('clicked', function() {
+ size /= 1.2;
+ update_size ();
+ });
+
+let button = new St.Button ({ label: 'Bigger',
+ style: 'padding: 4px; background: #eeddcc' });
+hbox.add (button);
+button.connect('clicked', function() {
+ size *= 1.2;
+ update_size ();
+ });
+
+stage.show();
+Clutter.main();
+stage.destroy();
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]