Port st-theme-context.[ch] to eek-theme-context.[ch].
This commit is contained in:
@ -47,7 +47,8 @@ libeek_private_headers = \
|
||||
$(srcdir)/eek-special-keysym-entries.h \
|
||||
$(srcdir)/eek-unicode-keysym-entries.h \
|
||||
$(srcdir)/eek-xkeysym-keysym-entries.h \
|
||||
$(srcdir)/eek-marshalers.h \
|
||||
$(srcdir)/eek-marshalers.h \
|
||||
$(srcdir)/eek-theme-context.h \
|
||||
$(srcdir)/eek-theme-node.h
|
||||
|
||||
libeek_sources = \
|
||||
@ -66,6 +67,7 @@ libeek_sources = \
|
||||
$(srcdir)/eek-renderer.c \
|
||||
$(srcdir)/eek-keyboard-drawing.c \
|
||||
$(srcdir)/eek-theme.c \
|
||||
$(srcdir)/eek-theme-context.c \
|
||||
$(srcdir)/eek-theme-node.c
|
||||
|
||||
libeek_keysym_sources = \
|
||||
|
||||
@ -1256,6 +1256,7 @@ eek_renderer_find_key_by_position (EekRenderer *renderer,
|
||||
}
|
||||
|
||||
struct _CreateThemeNodeData {
|
||||
EekThemeContext *context;
|
||||
EekThemeNode *parent;
|
||||
EekRenderer *renderer;
|
||||
};
|
||||
@ -1263,7 +1264,7 @@ typedef struct _CreateThemeNodeData CreateThemeNodeData;
|
||||
|
||||
void
|
||||
create_theme_node_key_callback (EekElement *element,
|
||||
gpointer user_data)
|
||||
gpointer user_data)
|
||||
{
|
||||
CreateThemeNodeData *data = user_data;
|
||||
EekRendererPrivate *priv;
|
||||
@ -1271,7 +1272,8 @@ create_theme_node_key_callback (EekElement *element,
|
||||
|
||||
priv = EEK_RENDERER_GET_PRIVATE(data->renderer);
|
||||
|
||||
theme_node = eek_theme_node_new (data->parent,
|
||||
theme_node = eek_theme_node_new (data->context,
|
||||
data->parent,
|
||||
priv->theme,
|
||||
EEK_TYPE_KEY,
|
||||
eek_element_get_name (element),
|
||||
@ -1283,7 +1285,8 @@ create_theme_node_key_callback (EekElement *element,
|
||||
theme_node,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
|
||||
theme_node = eek_theme_node_new (data->parent,
|
||||
theme_node = eek_theme_node_new (data->context,
|
||||
data->parent,
|
||||
priv->theme,
|
||||
EEK_TYPE_KEY,
|
||||
eek_element_get_name (element),
|
||||
@ -1306,7 +1309,8 @@ create_theme_node_section_callback (EekElement *element,
|
||||
|
||||
priv = EEK_RENDERER_GET_PRIVATE(data->renderer);
|
||||
|
||||
theme_node = eek_theme_node_new (data->parent,
|
||||
theme_node = eek_theme_node_new (data->context,
|
||||
data->parent,
|
||||
priv->theme,
|
||||
EEK_TYPE_SECTION,
|
||||
eek_element_get_name (element),
|
||||
@ -1331,6 +1335,7 @@ eek_renderer_set_theme (EekRenderer *renderer,
|
||||
EekTheme *theme)
|
||||
{
|
||||
EekRendererPrivate *priv;
|
||||
EekThemeContext *theme_context;
|
||||
EekThemeNode *theme_node;
|
||||
CreateThemeNodeData data;
|
||||
|
||||
@ -1344,7 +1349,9 @@ eek_renderer_set_theme (EekRenderer *renderer,
|
||||
g_object_unref (priv->theme);
|
||||
priv->theme = g_object_ref (theme);
|
||||
|
||||
theme_node = eek_theme_node_new (NULL,
|
||||
theme_context = eek_theme_context_new ();
|
||||
theme_node = eek_theme_node_new (theme_context,
|
||||
NULL,
|
||||
priv->theme,
|
||||
EEK_TYPE_KEYBOARD,
|
||||
"keyboard",
|
||||
@ -1356,6 +1363,7 @@ eek_renderer_set_theme (EekRenderer *renderer,
|
||||
theme_node,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
|
||||
data.context = theme_context;
|
||||
data.parent = theme_node;
|
||||
data.renderer = renderer;
|
||||
eek_container_foreach_child (EEK_CONTAINER(priv->keyboard),
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "eek-keysym.h"
|
||||
#include "eek-types.h"
|
||||
#include "eek-theme.h"
|
||||
#include "eek-theme-context.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
288
eek/eek-theme-context.c
Normal file
288
eek/eek-theme-context.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/*
|
||||
* eek-theme-context.c: holds global information about a tree of styled objects
|
||||
*
|
||||
* Copyright 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2009 Florian Müllner
|
||||
*
|
||||
* This program 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 program is distributed in the hope 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "eek-theme.h"
|
||||
#include "eek-theme-context.h"
|
||||
|
||||
struct _EekThemeContext {
|
||||
GObject parent;
|
||||
|
||||
double resolution;
|
||||
PangoFontDescription *font;
|
||||
EekThemeNode *root_node;
|
||||
EekTheme *theme;
|
||||
};
|
||||
|
||||
struct _EekThemeContextClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
#define DEFAULT_RESOLUTION 96.
|
||||
#define DEFAULT_FONT "sans-serif 10"
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE (EekThemeContext, eek_theme_context, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
eek_theme_context_finalize (GObject *object)
|
||||
{
|
||||
EekThemeContext *context = EEK_THEME_CONTEXT (object);
|
||||
|
||||
if (context->root_node)
|
||||
g_object_unref (context->root_node);
|
||||
if (context->theme)
|
||||
g_object_unref (context->theme);
|
||||
|
||||
pango_font_description_free (context->font);
|
||||
|
||||
G_OBJECT_CLASS (eek_theme_context_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
eek_theme_context_class_init (EekThemeContextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = eek_theme_context_finalize;
|
||||
|
||||
signals[CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, /* no default handler slot */
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
eek_theme_context_init (EekThemeContext *context)
|
||||
{
|
||||
context->resolution = DEFAULT_RESOLUTION;
|
||||
context->font = pango_font_description_from_string (DEFAULT_FONT);
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_new:
|
||||
*
|
||||
* Create a new theme context.
|
||||
*/
|
||||
EekThemeContext *
|
||||
eek_theme_context_new (void)
|
||||
{
|
||||
EekThemeContext *context;
|
||||
|
||||
context = g_object_new (EEK_TYPE_THEME_CONTEXT, NULL);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static void
|
||||
eek_theme_context_changed (EekThemeContext *context)
|
||||
{
|
||||
EekThemeNode *old_root = context->root_node;
|
||||
context->root_node = NULL;
|
||||
|
||||
g_signal_emit (context, signals[CHANGED], 0);
|
||||
|
||||
if (old_root)
|
||||
g_object_unref (old_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_set_theme:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Sets the default set of theme stylesheets for the context. This theme will
|
||||
* be used for the root node and for nodes descending from it, unless some other
|
||||
* style is explicitely specified.
|
||||
*/
|
||||
void
|
||||
eek_theme_context_set_theme (EekThemeContext *context,
|
||||
EekTheme *theme)
|
||||
{
|
||||
g_return_if_fail (EEK_IS_THEME_CONTEXT (context));
|
||||
g_return_if_fail (theme == NULL || EEK_IS_THEME (theme));
|
||||
|
||||
if (context->theme != theme)
|
||||
{
|
||||
if (context->theme)
|
||||
g_object_unref (context->theme);
|
||||
|
||||
context->theme = theme;
|
||||
|
||||
if (context->theme)
|
||||
g_object_ref (context->theme);
|
||||
|
||||
eek_theme_context_changed (context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_get_theme:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Gets the default theme for the context. See eek_theme_context_set_theme()
|
||||
*
|
||||
* Return value: (transfer none): the default theme for the context
|
||||
*/
|
||||
EekTheme *
|
||||
eek_theme_context_get_theme (EekThemeContext *context)
|
||||
{
|
||||
g_return_val_if_fail (EEK_IS_THEME_CONTEXT (context), NULL);
|
||||
|
||||
return context->theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_set_resolution:
|
||||
* @context: a #EekThemeContext
|
||||
* @resolution: resolution of the context (number of pixels in an "inch")
|
||||
*
|
||||
* Sets the resolution of the theme context. This is the scale factor
|
||||
* used to convert between points and the length units pt, in, and cm.
|
||||
* This does not necessarily need to correspond to the actual number
|
||||
* resolution of the device. A value of 72. means that points and
|
||||
* pixels are identical. The default value is 96.
|
||||
*/
|
||||
void
|
||||
eek_theme_context_set_resolution (EekThemeContext *context,
|
||||
double resolution)
|
||||
{
|
||||
g_return_if_fail (EEK_IS_THEME_CONTEXT (context));
|
||||
|
||||
if (resolution == context->resolution)
|
||||
return;
|
||||
|
||||
context->resolution = resolution;
|
||||
eek_theme_context_changed (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_set_default_resolution:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Sets the resolution of the theme context to the default value of 96.
|
||||
* See eek_theme_context_set_resolution().
|
||||
*/
|
||||
void
|
||||
eek_theme_context_set_default_resolution (EekThemeContext *context)
|
||||
{
|
||||
g_return_if_fail (EEK_IS_THEME_CONTEXT (context));
|
||||
|
||||
if (context->resolution == DEFAULT_RESOLUTION)
|
||||
return;
|
||||
|
||||
context->resolution = DEFAULT_RESOLUTION;
|
||||
eek_theme_context_changed (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_get_resolution:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Gets the current resolution of the theme context.
|
||||
* See eek_theme_context_set_resolution().
|
||||
*
|
||||
* Return value: the resolution (in dots-per-"inch")
|
||||
*/
|
||||
double
|
||||
eek_theme_context_get_resolution (EekThemeContext *context)
|
||||
{
|
||||
g_return_val_if_fail (EEK_IS_THEME_CONTEXT (context), DEFAULT_RESOLUTION);
|
||||
|
||||
return context->resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_set_font:
|
||||
* @context: a #EekThemeContext
|
||||
* @font: the default font for theme context
|
||||
*
|
||||
* Sets the default font for the theme context. This is the font that
|
||||
* is inherited by the root node of the tree of theme nodes. If the
|
||||
* font is not overriden, then this font will be used. If the font is
|
||||
* partially modified (for example, with 'font-size: 110%', then that
|
||||
* modification is based on this font.
|
||||
*/
|
||||
void
|
||||
eek_theme_context_set_font (EekThemeContext *context,
|
||||
const PangoFontDescription *font)
|
||||
{
|
||||
g_return_if_fail (EEK_IS_THEME_CONTEXT (context));
|
||||
g_return_if_fail (font != NULL);
|
||||
|
||||
if (context->font == font ||
|
||||
pango_font_description_equal (context->font, font))
|
||||
return;
|
||||
|
||||
pango_font_description_free (context->font);
|
||||
context->font = pango_font_description_copy (font);
|
||||
eek_theme_context_changed (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_get_font:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Gets the default font for the theme context. See eek_theme_context_set_font().
|
||||
*
|
||||
* Return value: the default font for the theme context.
|
||||
*/
|
||||
const PangoFontDescription *
|
||||
eek_theme_context_get_font (EekThemeContext *context)
|
||||
{
|
||||
g_return_val_if_fail (EEK_IS_THEME_CONTEXT (context), NULL);
|
||||
|
||||
return context->font;
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_theme_context_get_root_node:
|
||||
* @context: a #EekThemeContext
|
||||
*
|
||||
* Gets the root node of the tree of theme style nodes that associated with this
|
||||
* context. For the node tree associated with a stage, this node represents
|
||||
* styles applied to the stage itself.
|
||||
*
|
||||
* Return value: (transfer none): the root node of the context's style tree
|
||||
*/
|
||||
EekThemeNode *
|
||||
eek_theme_context_get_root_node (EekThemeContext *context)
|
||||
{
|
||||
if (context->root_node == NULL)
|
||||
context->root_node = eek_theme_node_new (context, NULL, context->theme,
|
||||
G_TYPE_NONE, NULL, NULL, NULL, NULL);
|
||||
|
||||
return context->root_node;
|
||||
}
|
||||
78
eek/eek-theme-context.h
Normal file
78
eek/eek-theme-context.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* eek-theme-context.c: holds global information about a tree of styled objects
|
||||
*
|
||||
* Copyright 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2009 Florian Müllner
|
||||
*
|
||||
* This program 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 program is distributed in the hope 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __EEK_THEME_CONTEXT_H__
|
||||
#define __EEK_THEME_CONTEXT_H__
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include "eek-theme-node.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* SECTION:EekThemeContext
|
||||
* @short_description: holds global information about a tree of styled objects
|
||||
*
|
||||
* #EekThemeContext is responsible for managing information global to
|
||||
* a tree of styled objects, such as the set of stylesheets or the
|
||||
* default font.
|
||||
*/
|
||||
|
||||
typedef struct _EekThemeContextClass EekThemeContextClass;
|
||||
|
||||
#define EEK_TYPE_THEME_CONTEXT (eek_theme_context_get_type ())
|
||||
#define EEK_THEME_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), EEK_TYPE_THEME_CONTEXT, EekThemeContext))
|
||||
#define EEK_THEME_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_THEME_CONTEXT, EekThemeContextClass))
|
||||
#define EEK_IS_THEME_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), EEK_TYPE_THEME_CONTEXT))
|
||||
#define EEK_IS_THEME_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_THEME_CONTEXT))
|
||||
#define EEK_THEME_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_THEME_CONTEXT, EekThemeContextClass))
|
||||
|
||||
GType eek_theme_context_get_type
|
||||
(void) G_GNUC_CONST;
|
||||
|
||||
EekThemeContext *eek_theme_context_new
|
||||
(void);
|
||||
|
||||
void eek_theme_context_set_theme
|
||||
(EekThemeContext *context,
|
||||
EekTheme *theme);
|
||||
EekTheme * eek_theme_context_get_theme
|
||||
(EekThemeContext *context);
|
||||
|
||||
void eek_theme_context_set_resolution
|
||||
(EekThemeContext *context,
|
||||
gdouble resolution);
|
||||
void eek_theme_context_set_default_resolution
|
||||
(EekThemeContext *context);
|
||||
double eek_theme_context_get_resolution
|
||||
(EekThemeContext *context);
|
||||
void eek_theme_context_set_font
|
||||
(EekThemeContext *context,
|
||||
const PangoFontDescription *font);
|
||||
const PangoFontDescription *eek_theme_context_get_font
|
||||
(EekThemeContext *context);
|
||||
|
||||
EekThemeNode * eek_theme_context_get_root_node
|
||||
(EekThemeContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __EEK_THEME_CONTEXT_H__ */
|
||||
@ -31,15 +31,19 @@
|
||||
#include <string.h>
|
||||
#include <libcroco/libcroco.h>
|
||||
|
||||
#include "eek-theme-context.h"
|
||||
#include "eek-theme-node.h"
|
||||
#include "eek-theme-private.h"
|
||||
|
||||
struct _EekThemeNode {
|
||||
GObject parent;
|
||||
|
||||
EekThemeContext *context;
|
||||
EekThemeNode *parent_node;
|
||||
EekTheme *theme;
|
||||
|
||||
PangoFontDescription *font_desc;
|
||||
|
||||
EekGradientType background_gradient_type;
|
||||
|
||||
EekColor background_color;
|
||||
@ -108,6 +112,12 @@ eek_theme_node_dispose (GObject *gobject)
|
||||
{
|
||||
EekThemeNode *node = EEK_THEME_NODE (gobject);
|
||||
|
||||
if (node->context)
|
||||
{
|
||||
g_object_unref (node->context);
|
||||
node->context = NULL;
|
||||
}
|
||||
|
||||
if (node->theme)
|
||||
{
|
||||
g_object_unref (node->theme);
|
||||
@ -146,6 +156,12 @@ eek_theme_node_finalize (GObject *object)
|
||||
cr_declaration_destroy (node->inline_properties);
|
||||
}
|
||||
|
||||
if (node->font_desc)
|
||||
{
|
||||
pango_font_description_free (node->font_desc);
|
||||
node->font_desc = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (eek_theme_node_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -171,20 +187,23 @@ eek_theme_node_finalize (GObject *object)
|
||||
* Return value: (transfer full): the theme node
|
||||
*/
|
||||
EekThemeNode *
|
||||
eek_theme_node_new (EekThemeNode *parent_node,
|
||||
EekTheme *theme,
|
||||
GType element_type,
|
||||
const char *element_id,
|
||||
const char *element_class,
|
||||
const char *pseudo_class,
|
||||
const char *inline_style)
|
||||
eek_theme_node_new (EekThemeContext *context,
|
||||
EekThemeNode *parent_node,
|
||||
EekTheme *theme,
|
||||
GType element_type,
|
||||
const char *element_id,
|
||||
const char *element_class,
|
||||
const char *pseudo_class,
|
||||
const char *inline_style)
|
||||
{
|
||||
EekThemeNode *node;
|
||||
|
||||
g_return_val_if_fail (EEK_IS_THEME_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (parent_node == NULL || EEK_IS_THEME_NODE (parent_node), NULL);
|
||||
|
||||
node = g_object_new (EEK_TYPE_THEME_NODE, NULL);
|
||||
|
||||
node->context = g_object_ref (context);
|
||||
if (parent_node != NULL)
|
||||
node->parent_node = g_object_ref (parent_node);
|
||||
else
|
||||
@ -635,6 +654,15 @@ eek_theme_node_get_double (EekThemeNode *node,
|
||||
}
|
||||
}
|
||||
|
||||
static const PangoFontDescription *
|
||||
get_parent_font (EekThemeNode *node)
|
||||
{
|
||||
if (node->parent_node)
|
||||
return eek_theme_node_get_font (node->parent_node);
|
||||
else
|
||||
return eek_theme_context_get_font (node->context);
|
||||
}
|
||||
|
||||
static GetFromTermResult
|
||||
get_length_from_term (EekThemeNode *node,
|
||||
CRTerm *term,
|
||||
@ -750,16 +778,11 @@ get_length_from_term (EekThemeNode *node,
|
||||
*length = num->val * multiplier;
|
||||
break;
|
||||
case POINTS:
|
||||
#if 0
|
||||
{
|
||||
double resolution = eek_theme_context_get_resolution (node->context);
|
||||
*length = num->val * multiplier * (resolution / 72.);
|
||||
}
|
||||
#else
|
||||
*length = num->val * multiplier;
|
||||
#endif
|
||||
break;
|
||||
#if 0
|
||||
case FONT_RELATIVE:
|
||||
{
|
||||
const PangoFontDescription *desc;
|
||||
@ -783,7 +806,7 @@ get_length_from_term (EekThemeNode *node,
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@ -1392,3 +1415,455 @@ eek_theme_node_get_background_gradient (EekThemeNode *node,
|
||||
*end = node->background_gradient_end;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_family_from_terms (CRTerm *term,
|
||||
char **family)
|
||||
{
|
||||
GString *family_string;
|
||||
gboolean result = FALSE;
|
||||
gboolean last_was_quoted = FALSE;
|
||||
|
||||
if (!term)
|
||||
return FALSE;
|
||||
|
||||
family_string = g_string_new (NULL);
|
||||
|
||||
while (term)
|
||||
{
|
||||
if (term->type != TERM_STRING && term->type != TERM_IDENT)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (family_string->len > 0)
|
||||
{
|
||||
if (term->the_operator != COMMA && term->the_operator != NO_OP)
|
||||
goto out;
|
||||
/* Can concatenate two bare words, but not two quoted strings */
|
||||
if ((term->the_operator == NO_OP && last_was_quoted) || term->type == TERM_STRING)
|
||||
goto out;
|
||||
|
||||
if (term->the_operator == NO_OP)
|
||||
g_string_append (family_string, " ");
|
||||
else
|
||||
g_string_append (family_string, ", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (term->the_operator != NO_OP)
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_string_append (family_string, term->content.str->stryng->str);
|
||||
|
||||
term = term->next;
|
||||
}
|
||||
|
||||
result = TRUE;
|
||||
|
||||
out:
|
||||
if (result)
|
||||
{
|
||||
*family = g_string_free (family_string, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*family = g_string_free (family_string, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* In points */
|
||||
static int font_sizes[] = {
|
||||
6 * 1024, /* xx-small */
|
||||
8 * 1024, /* x-small */
|
||||
10 * 1024, /* small */
|
||||
12 * 1024, /* medium */
|
||||
16 * 1024, /* large */
|
||||
20 * 1024, /* x-large */
|
||||
24 * 1024, /* xx-large */
|
||||
};
|
||||
|
||||
static gboolean
|
||||
font_size_from_term (EekThemeNode *node,
|
||||
CRTerm *term,
|
||||
double *size)
|
||||
{
|
||||
if (term->type == TERM_IDENT)
|
||||
{
|
||||
double resolution = eek_theme_context_get_resolution (node->context);
|
||||
/* We work in integers to avoid double comparisons when converting back
|
||||
* from a size in pixels to a logical size.
|
||||
*/
|
||||
int size_points = (int)(0.5 + *size * (72. / resolution));
|
||||
|
||||
if (strcmp (term->content.str->stryng->str, "xx-small") == 0)
|
||||
size_points = font_sizes[0];
|
||||
else if (strcmp (term->content.str->stryng->str, "x-small") == 0)
|
||||
size_points = font_sizes[1];
|
||||
else if (strcmp (term->content.str->stryng->str, "small") == 0)
|
||||
size_points = font_sizes[2];
|
||||
else if (strcmp (term->content.str->stryng->str, "medium") == 0)
|
||||
size_points = font_sizes[3];
|
||||
else if (strcmp (term->content.str->stryng->str, "large") == 0)
|
||||
size_points = font_sizes[4];
|
||||
else if (strcmp (term->content.str->stryng->str, "x-large") == 0)
|
||||
size_points = font_sizes[5];
|
||||
else if (strcmp (term->content.str->stryng->str, "xx-large") == 0)
|
||||
size_points = font_sizes[6];
|
||||
else if (strcmp (term->content.str->stryng->str, "smaller") == 0)
|
||||
{
|
||||
/* Find the standard size equal to or smaller than the current size */
|
||||
int i = 0;
|
||||
|
||||
while (i <= 6 && font_sizes[i] < size_points)
|
||||
i++;
|
||||
|
||||
if (i > 6)
|
||||
{
|
||||
/* original size greater than any standard size */
|
||||
size_points = (int)(0.5 + size_points / 1.2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Go one smaller than that, if possible */
|
||||
if (i > 0)
|
||||
i--;
|
||||
|
||||
size_points = font_sizes[i];
|
||||
}
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "larger") == 0)
|
||||
{
|
||||
/* Find the standard size equal to or larger than the current size */
|
||||
int i = 6;
|
||||
|
||||
while (i >= 0 && font_sizes[i] > size_points)
|
||||
i--;
|
||||
|
||||
if (i < 0) /* original size smaller than any standard size */
|
||||
i = 0;
|
||||
|
||||
/* Go one larger than that, if possible */
|
||||
if (i < 6)
|
||||
i++;
|
||||
|
||||
size_points = font_sizes[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*size = size_points * (resolution / 72.);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
else if (term->type == TERM_NUMBER && term->content.num->type == NUM_PERCENTAGE)
|
||||
{
|
||||
*size *= term->content.num->val / 100.;
|
||||
return TRUE;
|
||||
}
|
||||
else if (get_length_from_term (node, term, TRUE, size) == VALUE_FOUND)
|
||||
{
|
||||
/* Convert from pixels to Pango units */
|
||||
*size *= 1024;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_weight_from_term (CRTerm *term,
|
||||
PangoWeight *weight,
|
||||
gboolean *weight_absolute)
|
||||
{
|
||||
if (term->type == TERM_NUMBER)
|
||||
{
|
||||
int weight_int;
|
||||
|
||||
/* The spec only allows numeric weights from 100-900, though Pango
|
||||
* will handle any number. We just let anything through.
|
||||
*/
|
||||
if (term->content.num->type != NUM_GENERIC)
|
||||
return FALSE;
|
||||
|
||||
weight_int = (int)(0.5 + term->content.num->val);
|
||||
|
||||
*weight = weight_int;
|
||||
*weight_absolute = TRUE;
|
||||
|
||||
}
|
||||
else if (term->type == TERM_IDENT)
|
||||
{
|
||||
/* FIXME: handle INHERIT */
|
||||
|
||||
if (strcmp (term->content.str->stryng->str, "bold") == 0)
|
||||
{
|
||||
*weight = PANGO_WEIGHT_BOLD;
|
||||
*weight_absolute = TRUE;
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
||||
{
|
||||
*weight = PANGO_WEIGHT_NORMAL;
|
||||
*weight_absolute = TRUE;
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "bolder") == 0)
|
||||
{
|
||||
*weight = PANGO_WEIGHT_BOLD;
|
||||
*weight_absolute = FALSE;
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "lighter") == 0)
|
||||
{
|
||||
*weight = PANGO_WEIGHT_LIGHT;
|
||||
*weight_absolute = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_style_from_term (CRTerm *term,
|
||||
PangoStyle *style)
|
||||
{
|
||||
if (term->type != TERM_IDENT)
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: handle INHERIT */
|
||||
|
||||
if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
||||
*style = PANGO_STYLE_NORMAL;
|
||||
else if (strcmp (term->content.str->stryng->str, "oblique") == 0)
|
||||
*style = PANGO_STYLE_OBLIQUE;
|
||||
else if (strcmp (term->content.str->stryng->str, "italic") == 0)
|
||||
*style = PANGO_STYLE_ITALIC;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_variant_from_term (CRTerm *term,
|
||||
PangoVariant *variant)
|
||||
{
|
||||
if (term->type != TERM_IDENT)
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: handle INHERIT */
|
||||
|
||||
if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
||||
*variant = PANGO_VARIANT_NORMAL;
|
||||
else if (strcmp (term->content.str->stryng->str, "small-caps") == 0)
|
||||
*variant = PANGO_VARIANT_SMALL_CAPS;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const PangoFontDescription *
|
||||
eek_theme_node_get_font (EekThemeNode *node)
|
||||
{
|
||||
/* Initialized despite _set flags to suppress compiler warnings */
|
||||
PangoStyle font_style = PANGO_STYLE_NORMAL;
|
||||
gboolean font_style_set = FALSE;
|
||||
PangoVariant variant = PANGO_VARIANT_NORMAL;
|
||||
gboolean variant_set = FALSE;
|
||||
PangoWeight weight = PANGO_WEIGHT_NORMAL;
|
||||
gboolean weight_absolute = TRUE;
|
||||
gboolean weight_set = FALSE;
|
||||
double size = 0.;
|
||||
gboolean size_set = FALSE;
|
||||
|
||||
char *family = NULL;
|
||||
double parent_size;
|
||||
int i;
|
||||
|
||||
if (node->font_desc)
|
||||
return node->font_desc;
|
||||
|
||||
node->font_desc = pango_font_description_copy (get_parent_font (node));
|
||||
parent_size = pango_font_description_get_size (node->font_desc);
|
||||
if (!pango_font_description_get_size_is_absolute (node->font_desc))
|
||||
{
|
||||
double resolution = eek_theme_context_get_resolution (node->context);
|
||||
parent_size *= (resolution / 72.);
|
||||
}
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
for (i = 0; i < node->n_properties; i++)
|
||||
{
|
||||
CRDeclaration *decl = node->properties[i];
|
||||
|
||||
if (strcmp (decl->property->stryng->str, "font") == 0)
|
||||
{
|
||||
PangoStyle tmp_style = PANGO_STYLE_NORMAL;
|
||||
PangoVariant tmp_variant = PANGO_VARIANT_NORMAL;
|
||||
PangoWeight tmp_weight = PANGO_WEIGHT_NORMAL;
|
||||
gboolean tmp_weight_absolute = TRUE;
|
||||
double tmp_size;
|
||||
CRTerm *term = decl->value;
|
||||
|
||||
/* A font specification starts with node/variant/weight
|
||||
* in any order. Each is allowed to be specified only once,
|
||||
* but we don't enforce that.
|
||||
*/
|
||||
for (; term; term = term->next)
|
||||
{
|
||||
if (font_style_from_term (term, &tmp_style))
|
||||
continue;
|
||||
if (font_variant_from_term (term, &tmp_variant))
|
||||
continue;
|
||||
if (font_weight_from_term (term, &tmp_weight, &tmp_weight_absolute))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* The size is mandatory */
|
||||
|
||||
if (term == NULL || term->type != TERM_NUMBER)
|
||||
{
|
||||
g_warning ("Size missing from font property");
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp_size = parent_size;
|
||||
if (!font_size_from_term (node, term, &tmp_size))
|
||||
{
|
||||
g_warning ("Couldn't parse size in font property");
|
||||
continue;
|
||||
}
|
||||
|
||||
term = term->next;
|
||||
|
||||
if (term != NULL && term->type && TERM_NUMBER && term->the_operator == DIVIDE)
|
||||
{
|
||||
/* Ignore line-height specification */
|
||||
term = term->next;
|
||||
}
|
||||
|
||||
/* the font family is mandatory - it is a comma-separated list of
|
||||
* names.
|
||||
*/
|
||||
if (!font_family_from_terms (term, &family))
|
||||
{
|
||||
g_warning ("Couldn't parse family in font property");
|
||||
continue;
|
||||
}
|
||||
|
||||
font_style = tmp_style;
|
||||
font_style_set = TRUE;
|
||||
weight = tmp_weight;
|
||||
weight_absolute = tmp_weight_absolute;
|
||||
weight_set = TRUE;
|
||||
variant = tmp_variant;
|
||||
variant_set = TRUE;
|
||||
|
||||
size = tmp_size;
|
||||
size_set = TRUE;
|
||||
|
||||
}
|
||||
else if (strcmp (decl->property->stryng->str, "font-family") == 0)
|
||||
{
|
||||
if (!font_family_from_terms (decl->value, &family))
|
||||
{
|
||||
g_warning ("Couldn't parse family in font property");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (strcmp (decl->property->stryng->str, "font-weight") == 0)
|
||||
{
|
||||
if (decl->value == NULL || decl->value->next != NULL)
|
||||
continue;
|
||||
|
||||
if (font_weight_from_term (decl->value, &weight, &weight_absolute))
|
||||
weight_set = TRUE;
|
||||
}
|
||||
else if (strcmp (decl->property->stryng->str, "font-style") == 0)
|
||||
{
|
||||
if (decl->value == NULL || decl->value->next != NULL)
|
||||
continue;
|
||||
|
||||
if (font_style_from_term (decl->value, &font_style))
|
||||
font_style_set = TRUE;
|
||||
}
|
||||
else if (strcmp (decl->property->stryng->str, "font-variant") == 0)
|
||||
{
|
||||
if (decl->value == NULL || decl->value->next != NULL)
|
||||
continue;
|
||||
|
||||
if (font_variant_from_term (decl->value, &variant))
|
||||
variant_set = TRUE;
|
||||
}
|
||||
else if (strcmp (decl->property->stryng->str, "font-size") == 0)
|
||||
{
|
||||
gdouble tmp_size;
|
||||
if (decl->value == NULL || decl->value->next != NULL)
|
||||
continue;
|
||||
|
||||
tmp_size = parent_size;
|
||||
if (font_size_from_term (node, decl->value, &tmp_size))
|
||||
{
|
||||
size = tmp_size;
|
||||
size_set = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (family)
|
||||
{
|
||||
pango_font_description_set_family (node->font_desc, family);
|
||||
g_free (family);
|
||||
}
|
||||
|
||||
if (size_set)
|
||||
pango_font_description_set_absolute_size (node->font_desc, size);
|
||||
|
||||
if (weight_set)
|
||||
{
|
||||
if (!weight_absolute)
|
||||
{
|
||||
/* bolder/lighter are supposed to switch between available styles, but with
|
||||
* font substitution, that gets to be a pretty fuzzy concept. So we use
|
||||
* a fixed step of 200. (The spec says 100, but that might not take us from
|
||||
* normal to bold.
|
||||
*/
|
||||
|
||||
PangoWeight old_weight = pango_font_description_get_weight (node->font_desc);
|
||||
if (weight == PANGO_WEIGHT_BOLD)
|
||||
weight = old_weight + 200;
|
||||
else
|
||||
weight = old_weight - 200;
|
||||
|
||||
if (weight < 100)
|
||||
weight = 100;
|
||||
if (weight > 900)
|
||||
weight = 900;
|
||||
}
|
||||
|
||||
pango_font_description_set_weight (node->font_desc, weight);
|
||||
}
|
||||
|
||||
if (font_style_set)
|
||||
pango_font_description_set_style (node->font_desc, font_style);
|
||||
if (variant_set)
|
||||
pango_font_description_set_variant (node->font_desc, variant);
|
||||
|
||||
return node->font_desc;
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#ifndef __EEK_THEME_NODE_H__
|
||||
#define __EEK_THEME_NODE_H__
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include "eek-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -70,7 +71,8 @@ typedef struct _EekThemeNodePrivate EekThemeNodePrivate;
|
||||
GType eek_theme_node_get_type
|
||||
(void) G_GNUC_CONST;
|
||||
|
||||
EekThemeNode *eek_theme_node_new (EekThemeNode *parent_node,
|
||||
EekThemeNode *eek_theme_node_new (EekThemeContext *context,
|
||||
EekThemeNode *parent_node,
|
||||
/* can be null */ EekTheme *theme,
|
||||
/* can be null */ GType element_type,
|
||||
const char *element_id,
|
||||
@ -127,6 +129,13 @@ void eek_theme_node_get_border_color
|
||||
EekSide side,
|
||||
EekColor *color);
|
||||
|
||||
/* Font rule processing is pretty complicated, so we just hardcode it
|
||||
* under the standard font/font-family/font-size/etc names. This means
|
||||
* you can't have multiple separate styled fonts for a single item,
|
||||
* but that should be OK.
|
||||
*/
|
||||
const PangoFontDescription *eek_theme_node_get_font (EekThemeNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __EEK_THEME_NODE_H__ */
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "eek-theme-node.h"
|
||||
#include "eek-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
@ -137,6 +137,7 @@ typedef struct _EekKeyboard EekKeyboard;
|
||||
typedef struct _EekSymbol EekSymbol;
|
||||
typedef struct _EekKeysym EekKeysym;
|
||||
typedef struct _EekTheme EekTheme;
|
||||
typedef struct _EekThemeContext EekThemeContext;
|
||||
typedef struct _EekThemeNode EekThemeNode;
|
||||
|
||||
typedef struct _EekSymbolMatrix EekSymbolMatrix;
|
||||
|
||||
Reference in New Issue
Block a user