Add support for inline styles
Add support for passing an inline-style string when creating a ShellThemeNode. Hook this up to a new 'style' property of NbtkWidget. Add a test case that demonstrates using this to update font sizes on the fly.
This commit is contained in:
parent
9c3af62dc4
commit
0eca3efcb0
@ -54,6 +54,7 @@ struct _NbtkWidgetPrivate
|
|||||||
ShellThemeNode *theme_node;
|
ShellThemeNode *theme_node;
|
||||||
gchar *pseudo_class;
|
gchar *pseudo_class;
|
||||||
gchar *style_class;
|
gchar *style_class;
|
||||||
|
gchar *inline_style;
|
||||||
|
|
||||||
ClutterActor *border_image;
|
ClutterActor *border_image;
|
||||||
ClutterActor *background_image;
|
ClutterActor *background_image;
|
||||||
@ -84,6 +85,7 @@ enum
|
|||||||
PROP_THEME,
|
PROP_THEME,
|
||||||
PROP_PSEUDO_CLASS,
|
PROP_PSEUDO_CLASS,
|
||||||
PROP_STYLE_CLASS,
|
PROP_STYLE_CLASS,
|
||||||
|
PROP_STYLE,
|
||||||
|
|
||||||
PROP_STYLABLE,
|
PROP_STYLABLE,
|
||||||
|
|
||||||
@ -126,6 +128,10 @@ nbtk_widget_set_property (GObject *gobject,
|
|||||||
nbtk_widget_set_style_class_name (actor, g_value_get_string (value));
|
nbtk_widget_set_style_class_name (actor, g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_STYLE:
|
||||||
|
nbtk_widget_set_style (actor, g_value_get_string (value));
|
||||||
|
break;
|
||||||
|
|
||||||
case PROP_STYLABLE:
|
case PROP_STYLABLE:
|
||||||
if (actor->priv->is_stylable != g_value_get_boolean (value))
|
if (actor->priv->is_stylable != g_value_get_boolean (value))
|
||||||
{
|
{
|
||||||
@ -171,6 +177,10 @@ nbtk_widget_get_property (GObject *gobject,
|
|||||||
g_value_set_string (value, priv->style_class);
|
g_value_set_string (value, priv->style_class);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_STYLE:
|
||||||
|
g_value_set_string (value, priv->inline_style);
|
||||||
|
break;
|
||||||
|
|
||||||
case PROP_STYLABLE:
|
case PROP_STYLABLE:
|
||||||
g_value_set_boolean (value, priv->is_stylable);
|
g_value_set_boolean (value, priv->is_stylable);
|
||||||
break;
|
break;
|
||||||
@ -662,7 +672,8 @@ nbtk_widget_get_theme_node (NbtkWidget *widget)
|
|||||||
G_OBJECT_TYPE (widget),
|
G_OBJECT_TYPE (widget),
|
||||||
clutter_actor_get_name (CLUTTER_ACTOR (widget)),
|
clutter_actor_get_name (CLUTTER_ACTOR (widget)),
|
||||||
priv->style_class,
|
priv->style_class,
|
||||||
priv->pseudo_class);
|
priv->pseudo_class,
|
||||||
|
priv->inline_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
return priv->theme_node;
|
return priv->theme_node;
|
||||||
@ -766,6 +777,20 @@ nbtk_widget_class_init (NbtkWidgetClass *klass)
|
|||||||
"",
|
"",
|
||||||
NBTK_PARAM_READWRITE));
|
NBTK_PARAM_READWRITE));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NbtkWidget: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",
|
||||||
|
"",
|
||||||
|
NBTK_PARAM_READWRITE));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NbtkWidget:theme
|
* NbtkWidget:theme
|
||||||
*
|
*
|
||||||
@ -975,6 +1000,53 @@ nbtk_widget_set_style_pseudo_class (NbtkWidget *actor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nbtk_widget_set_style:
|
||||||
|
* @actor: a #NbtkWidget
|
||||||
|
* @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
|
||||||
|
nbtk_widget_set_style (NbtkWidget *actor,
|
||||||
|
const gchar *style)
|
||||||
|
{
|
||||||
|
NbtkWidgetPrivate *priv = actor->priv;
|
||||||
|
|
||||||
|
g_return_if_fail (NBTK_IS_WIDGET (actor));
|
||||||
|
|
||||||
|
priv = actor->priv;
|
||||||
|
|
||||||
|
if (g_strcmp0 (style, priv->inline_style))
|
||||||
|
{
|
||||||
|
g_free (priv->inline_style);
|
||||||
|
priv->inline_style = g_strdup (style);
|
||||||
|
|
||||||
|
nbtk_widget_style_changed (actor);
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (actor), "style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nbtk_widget_get_style:
|
||||||
|
* @actor: a #NbtkWidget
|
||||||
|
*
|
||||||
|
* Get the current inline style string. See nbtk_widget_set_style().
|
||||||
|
*
|
||||||
|
* Returns: The inline style string, or %NULL. The string is owned by the
|
||||||
|
* #NbtkWidget and should not be modified or freed.
|
||||||
|
*/
|
||||||
|
const gchar*
|
||||||
|
nbtk_widget_get_style (NbtkWidget *actor)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (NBTK_IS_WIDGET (actor), NULL);
|
||||||
|
|
||||||
|
return actor->priv->inline_style;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nbtk_widget_name_notify (NbtkWidget *widget,
|
nbtk_widget_name_notify (NbtkWidget *widget,
|
||||||
GParamSpec *pspec,
|
GParamSpec *pspec,
|
||||||
|
@ -85,6 +85,9 @@ G_CONST_RETURN gchar *nbtk_widget_get_style_pseudo_class (NbtkWidget *actor);
|
|||||||
void nbtk_widget_set_style_class_name (NbtkWidget *actor,
|
void nbtk_widget_set_style_class_name (NbtkWidget *actor,
|
||||||
const gchar *style_class);
|
const gchar *style_class);
|
||||||
G_CONST_RETURN gchar *nbtk_widget_get_style_class_name (NbtkWidget *actor);
|
G_CONST_RETURN gchar *nbtk_widget_get_style_class_name (NbtkWidget *actor);
|
||||||
|
void nbtk_widget_set_style (NbtkWidget *actor,
|
||||||
|
const gchar *style);
|
||||||
|
G_CONST_RETURN gchar *nbtk_widget_get_style (NbtkWidget *actor);
|
||||||
|
|
||||||
void nbtk_widget_set_theme (NbtkWidget *actor,
|
void nbtk_widget_set_theme (NbtkWidget *actor,
|
||||||
ShellTheme *theme);
|
ShellTheme *theme);
|
||||||
|
@ -212,7 +212,7 @@ shell_theme_context_get_root_node (ShellThemeContext *context)
|
|||||||
{
|
{
|
||||||
if (context->root_node == NULL)
|
if (context->root_node == NULL)
|
||||||
context->root_node = shell_theme_node_new (context, NULL, context->theme,
|
context->root_node = shell_theme_node_new (context, NULL, context->theme,
|
||||||
G_TYPE_NONE, NULL, NULL, NULL);
|
G_TYPE_NONE, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
return context->root_node;
|
return context->root_node;
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,15 @@ struct _ShellThemeNode {
|
|||||||
char *element_id;
|
char *element_id;
|
||||||
char *element_class;
|
char *element_class;
|
||||||
char *pseudo_class;
|
char *pseudo_class;
|
||||||
|
char *inline_style;
|
||||||
|
|
||||||
CRDeclaration **properties;
|
CRDeclaration **properties;
|
||||||
int n_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 properties_computed : 1;
|
||||||
guint borders_computed : 1;
|
guint borders_computed : 1;
|
||||||
guint background_computed : 1;
|
guint background_computed : 1;
|
||||||
@ -91,10 +96,12 @@ static void
|
|||||||
shell_theme_node_finalize (GObject *object)
|
shell_theme_node_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
ShellThemeNode *node = SHELL_THEME_NODE (object);
|
ShellThemeNode *node = SHELL_THEME_NODE (object);
|
||||||
|
CRDeclaration *cur_decl;
|
||||||
|
|
||||||
g_free (node->element_id);
|
g_free (node->element_id);
|
||||||
g_free (node->element_class);
|
g_free (node->element_class);
|
||||||
g_free (node->pseudo_class);
|
g_free (node->pseudo_class);
|
||||||
|
g_free (node->inline_style);
|
||||||
|
|
||||||
if (node->properties)
|
if (node->properties)
|
||||||
{
|
{
|
||||||
@ -103,6 +110,9 @@ shell_theme_node_finalize (GObject *object)
|
|||||||
node->n_properties = 0;
|
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)
|
if (node->font_desc)
|
||||||
{
|
{
|
||||||
pango_font_description_free (node->font_desc);
|
pango_font_description_free (node->font_desc);
|
||||||
@ -128,7 +138,8 @@ shell_theme_node_new (ShellThemeContext *context,
|
|||||||
GType element_type,
|
GType element_type,
|
||||||
const char *element_id,
|
const char *element_id,
|
||||||
const char *element_class,
|
const char *element_class,
|
||||||
const char *pseudo_class)
|
const char *pseudo_class,
|
||||||
|
const char *inline_style)
|
||||||
{
|
{
|
||||||
ShellThemeNode *node;
|
ShellThemeNode *node;
|
||||||
|
|
||||||
@ -153,6 +164,7 @@ shell_theme_node_new (ShellThemeContext *context,
|
|||||||
node->element_id = g_strdup (element_id);
|
node->element_id = g_strdup (element_id);
|
||||||
node->element_class = g_strdup (element_class);
|
node->element_class = g_strdup (element_class);
|
||||||
node->pseudo_class = g_strdup (pseudo_class);
|
node->pseudo_class = g_strdup (pseudo_class);
|
||||||
|
node->inline_style = g_strdup (inline_style);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -227,11 +239,32 @@ ensure_properties (ShellThemeNode *node)
|
|||||||
{
|
{
|
||||||
if (!node->properties_computed)
|
if (!node->properties_computed)
|
||||||
{
|
{
|
||||||
|
GPtrArray *properties = NULL;
|
||||||
|
|
||||||
node->properties_computed = TRUE;
|
node->properties_computed = TRUE;
|
||||||
|
|
||||||
if (node->theme)
|
if (node->theme)
|
||||||
_shell_theme_get_matched_properties (node->theme, node,
|
properties = _shell_theme_get_matched_properties (node->theme, node);
|
||||||
&node->properties, &node->n_properties);
|
|
||||||
|
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 @@ ShellThemeNode *shell_theme_node_new (ShellThemeContext *context,
|
|||||||
GType element_type,
|
GType element_type,
|
||||||
const char *element_id,
|
const char *element_id,
|
||||||
const char *element_class,
|
const char *element_class,
|
||||||
const char *pseudo_class);
|
const char *pseudo_class,
|
||||||
|
const char *inline_style);
|
||||||
|
|
||||||
ShellThemeNode *shell_theme_node_get_parent (ShellThemeNode *node);
|
ShellThemeNode *shell_theme_node_get_parent (ShellThemeNode *node);
|
||||||
|
|
||||||
|
@ -7,10 +7,8 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
void _shell_theme_get_matched_properties (ShellTheme *theme,
|
GPtrArray *_shell_theme_get_matched_properties (ShellTheme *theme,
|
||||||
ShellThemeNode *node,
|
ShellThemeNode *node);
|
||||||
CRDeclaration ***properties,
|
|
||||||
int *n_properties);
|
|
||||||
|
|
||||||
/* Resolve an URL from the stylesheet to a filename */
|
/* Resolve an URL from the stylesheet to a filename */
|
||||||
char *_shell_theme_resolve_url (ShellTheme *theme,
|
char *_shell_theme_resolve_url (ShellTheme *theme,
|
||||||
|
@ -940,18 +940,16 @@ compare_declarations (gconstpointer a,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
GPtrArray *
|
||||||
_shell_theme_get_matched_properties (ShellTheme *theme,
|
_shell_theme_get_matched_properties (ShellTheme *theme,
|
||||||
ShellThemeNode *node,
|
ShellThemeNode *node)
|
||||||
CRDeclaration ***properties,
|
|
||||||
int *n_properties)
|
|
||||||
{
|
{
|
||||||
enum CRStyleOrigin origin = 0;
|
enum CRStyleOrigin origin = 0;
|
||||||
CRStyleSheet *sheet = NULL;
|
CRStyleSheet *sheet = NULL;
|
||||||
GPtrArray *props = g_ptr_array_new ();
|
GPtrArray *props = g_ptr_array_new ();
|
||||||
|
|
||||||
g_return_if_fail (SHELL_IS_THEME (theme));
|
g_return_val_if_fail (SHELL_IS_THEME (theme), NULL);
|
||||||
g_return_if_fail (SHELL_IS_THEME_NODE (node));
|
g_return_val_if_fail (SHELL_IS_THEME_NODE (node), NULL);
|
||||||
|
|
||||||
for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin++)
|
for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin++)
|
||||||
{
|
{
|
||||||
@ -966,8 +964,7 @@ _shell_theme_get_matched_properties (ShellTheme *theme,
|
|||||||
* after earlier declarations */
|
* after earlier declarations */
|
||||||
g_ptr_array_sort (props, compare_declarations);
|
g_ptr_array_sort (props, compare_declarations);
|
||||||
|
|
||||||
*n_properties = props->len;
|
return props;
|
||||||
*properties = (CRDeclaration **) g_ptr_array_free (props, FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resolve an url from an url() reference in a stylesheet into an absolute
|
/* Resolve an url from an url() reference in a stylesheet into an absolute
|
||||||
|
@ -244,6 +244,16 @@ test_pseudo_class (void)
|
|||||||
assert_text_decoration (group3, "group3", 0);
|
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.,
|
||||||
|
shell_theme_node_get_padding (text3, SHELL_SIDE_BOTTOM));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -263,21 +273,22 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
root = shell_theme_context_get_root_node (context);
|
root = shell_theme_context_get_root_node (context);
|
||||||
group1 = shell_theme_node_new (context, root, NULL,
|
group1 = shell_theme_node_new (context, root, NULL,
|
||||||
CLUTTER_TYPE_GROUP, "group1", NULL, NULL);
|
CLUTTER_TYPE_GROUP, "group1", NULL, NULL, NULL);
|
||||||
text1 = shell_theme_node_new (context, group1, NULL,
|
text1 = shell_theme_node_new (context, group1, NULL,
|
||||||
CLUTTER_TYPE_TEXT, "text1", "special-text", NULL);
|
CLUTTER_TYPE_TEXT, "text1", "special-text", NULL, NULL);
|
||||||
text2 = shell_theme_node_new (context, group1, NULL,
|
text2 = shell_theme_node_new (context, group1, NULL,
|
||||||
CLUTTER_TYPE_TEXT, "text2", NULL, NULL);
|
CLUTTER_TYPE_TEXT, "text2", NULL, NULL, NULL);
|
||||||
group2 = shell_theme_node_new (context, root, NULL,
|
group2 = shell_theme_node_new (context, root, NULL,
|
||||||
CLUTTER_TYPE_GROUP, "group2", NULL, NULL);
|
CLUTTER_TYPE_GROUP, "group2", NULL, NULL, NULL);
|
||||||
text3 = shell_theme_node_new (context, group2, NULL,
|
text3 = shell_theme_node_new (context, group2, NULL,
|
||||||
CLUTTER_TYPE_TEXT, "text3", NULL, NULL);
|
CLUTTER_TYPE_TEXT, "text3", NULL, NULL,
|
||||||
|
"color: #0000ff; padding-bottom: 12px;");
|
||||||
text4 = shell_theme_node_new (context, group2, NULL,
|
text4 = shell_theme_node_new (context, group2, NULL,
|
||||||
CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover");
|
CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
|
||||||
group3 = shell_theme_node_new (context, group2, NULL,
|
group3 = shell_theme_node_new (context, group2, NULL,
|
||||||
CLUTTER_TYPE_GROUP, "group3", NULL, "hover");
|
CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
|
||||||
cairo_texture = shell_theme_node_new (context, root, NULL,
|
cairo_texture = shell_theme_node_new (context, root, NULL,
|
||||||
CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL);
|
CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
|
||||||
|
|
||||||
test_defaults ();
|
test_defaults ();
|
||||||
test_lengths ();
|
test_lengths ();
|
||||||
@ -287,6 +298,7 @@ main (int argc, char **argv)
|
|||||||
test_background ();
|
test_background ();
|
||||||
test_font ();
|
test_font ();
|
||||||
test_pseudo_class ();
|
test_pseudo_class ();
|
||||||
|
test_inline_style ();
|
||||||
|
|
||||||
return fail ? 1 : 0;
|
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 Nbtk = imports.gi.Nbtk;
|
||||||
|
|
||||||
|
const UI = imports.testcommon.ui;
|
||||||
|
|
||||||
|
UI.init();
|
||||||
|
let stage = Clutter.Stage.get_default();
|
||||||
|
|
||||||
|
let vbox = new Nbtk.BoxLayout({ vertical: true,
|
||||||
|
width: stage.width,
|
||||||
|
height: stage.height });
|
||||||
|
stage.add_actor(vbox);
|
||||||
|
|
||||||
|
let hbox = new Nbtk.BoxLayout({ spacing: 12 });
|
||||||
|
vbox.add(hbox);
|
||||||
|
|
||||||
|
let text = new Nbtk.Label({ text: "Styled Text" });
|
||||||
|
vbox.add (text);
|
||||||
|
|
||||||
|
let size = 24;
|
||||||
|
function update_size() {
|
||||||
|
text.style = 'font-size: ' + size + 'pt';
|
||||||
|
}
|
||||||
|
update_size();
|
||||||
|
|
||||||
|
let button = new Nbtk.Button ({ label: 'Smaller',
|
||||||
|
style: 'padding: 4px; background: #eeddcc' });
|
||||||
|
hbox.add (button);
|
||||||
|
button.connect('clicked', function() {
|
||||||
|
size /= 1.2;
|
||||||
|
update_size ();
|
||||||
|
});
|
||||||
|
|
||||||
|
let button = new Nbtk.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