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
This commit is contained in:
parent
ebbf304899
commit
7e678ef0d2
@ -212,7 +212,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;
|
||||
}
|
||||
|
@ -43,10 +43,15 @@ 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 unref them; the alternative
|
||||
* would be to ref everything in ->properties */
|
||||
CRDeclaration *inline_properties;
|
||||
|
||||
guint properties_computed : 1;
|
||||
guint borders_computed : 1;
|
||||
guint background_computed : 1;
|
||||
@ -91,10 +96,12 @@ static void
|
||||
st_theme_node_finalize (GObject *object)
|
||||
{
|
||||
StThemeNode *node = ST_THEME_NODE (object);
|
||||
CRDeclaration *cur_decl;
|
||||
|
||||
g_free (node->element_id);
|
||||
g_free (node->element_class);
|
||||
g_free (node->pseudo_class);
|
||||
g_free (node->inline_style);
|
||||
|
||||
if (node->properties)
|
||||
{
|
||||
@ -103,6 +110,9 @@ st_theme_node_finalize (GObject *object)
|
||||
node->n_properties = 0;
|
||||
}
|
||||
|
||||
for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
|
||||
cr_declaration_unref (cur_decl);
|
||||
|
||||
if (node->font_desc)
|
||||
{
|
||||
pango_font_description_free (node->font_desc);
|
||||
@ -128,7 +138,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;
|
||||
|
||||
@ -153,6 +164,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;
|
||||
}
|
||||
@ -227,11 +239,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -940,18 +940,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++)
|
||||
{
|
||||
@ -966,8 +964,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
|
||||
|
@ -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;
|
||||
@ -763,6 +774,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
|
||||
*
|
||||
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
47
tests/interactive/inline-style.js
Normal file
47
tests/interactive/inline-style.js
Normal file
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user