2009-09-29 19:08:01 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2009-09-08 19:47:30 +00:00
|
|
|
#include "st-private.h"
|
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
/**
|
|
|
|
* _st_actor_get_preferred_width:
|
|
|
|
* @actor: a #ClutterActor
|
|
|
|
* @for_height: as with clutter_actor_get_preferred_width()
|
|
|
|
* @y_fill: %TRUE if @actor will fill its allocation vertically
|
|
|
|
* @min_width_p: as with clutter_actor_get_preferred_width()
|
|
|
|
* @natural_width_p: as with clutter_actor_get_preferred_width()
|
|
|
|
*
|
|
|
|
* Like clutter_actor_get_preferred_width(), but if @y_fill is %FALSE,
|
|
|
|
* then it will compute a width request based on the assumption that
|
|
|
|
* @actor will be given an allocation no taller than its natural
|
|
|
|
* height.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_st_actor_get_preferred_width (ClutterActor *actor,
|
|
|
|
gfloat for_height,
|
|
|
|
gboolean y_fill,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
|
|
|
{
|
|
|
|
if (!y_fill && for_height != -1)
|
|
|
|
{
|
|
|
|
ClutterRequestMode mode;
|
|
|
|
gfloat natural_height;
|
|
|
|
|
|
|
|
g_object_get (G_OBJECT (actor), "request-mode", &mode, NULL);
|
|
|
|
if (mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
|
|
|
|
{
|
|
|
|
clutter_actor_get_preferred_height (actor, -1, NULL, &natural_height);
|
|
|
|
if (for_height > natural_height)
|
|
|
|
for_height = natural_height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_width (actor, for_height, min_width_p, natural_width_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* _st_actor_get_preferred_height:
|
|
|
|
* @actor: a #ClutterActor
|
|
|
|
* @for_width: as with clutter_actor_get_preferred_height()
|
|
|
|
* @x_fill: %TRUE if @actor will fill its allocation horizontally
|
|
|
|
* @min_height_p: as with clutter_actor_get_preferred_height()
|
|
|
|
* @natural_height_p: as with clutter_actor_get_preferred_height()
|
|
|
|
*
|
|
|
|
* Like clutter_actor_get_preferred_height(), but if @x_fill is
|
|
|
|
* %FALSE, then it will compute a height request based on the
|
|
|
|
* assumption that @actor will be given an allocation no wider than
|
|
|
|
* its natural width.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_st_actor_get_preferred_height (ClutterActor *actor,
|
|
|
|
gfloat for_width,
|
|
|
|
gboolean x_fill,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
|
|
|
{
|
|
|
|
if (!x_fill && for_width != -1)
|
|
|
|
{
|
|
|
|
ClutterRequestMode mode;
|
|
|
|
gfloat natural_width;
|
|
|
|
|
|
|
|
g_object_get (G_OBJECT (actor), "request-mode", &mode, NULL);
|
|
|
|
if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
|
|
|
{
|
|
|
|
clutter_actor_get_preferred_width (actor, -1, NULL, &natural_width);
|
|
|
|
if (for_width > natural_width)
|
|
|
|
for_width = natural_width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_height (actor, for_width, min_height_p, natural_height_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* _st_allocate_fill:
|
|
|
|
* @parent: the parent #StWidget
|
|
|
|
* @child: the child (not necessarily an #StWidget)
|
|
|
|
* @childbox: total space that could be allocated to @child
|
|
|
|
* @x_alignment: horizontal alignment within @childbox
|
|
|
|
* @y_alignment: vertical alignment within @childbox
|
|
|
|
* @x_fill: whether or not to fill @childbox horizontally
|
|
|
|
* @y_fill: whether or not to fill @childbox vertically
|
|
|
|
*
|
|
|
|
* Given @childbox, containing the initial allocation of @child, this
|
|
|
|
* adjusts the horizontal allocation if @x_fill is %FALSE, and the
|
|
|
|
* vertical allocation if @y_fill is %FALSE, by:
|
|
|
|
*
|
|
|
|
* - reducing the allocation if it is larger than @child's natural
|
|
|
|
* size.
|
|
|
|
*
|
|
|
|
* - adjusting the position of the child within the allocation
|
|
|
|
* according to @x_alignment/@y_alignment (and flipping
|
|
|
|
* @x_alignment if @parent has %ST_TEXT_DIRECTION_RTL)
|
|
|
|
*
|
|
|
|
* If @x_fill and @y_fill are both %TRUE, or if @child's natural size
|
|
|
|
* is larger than the initial allocation in @childbox, then @childbox
|
|
|
|
* will be unchanged.
|
|
|
|
*
|
|
|
|
* If you are allocating children with _st_allocate_fill(), you should
|
|
|
|
* determine their preferred sizes using
|
|
|
|
* _st_actor_get_preferred_width() and
|
|
|
|
* _st_actor_get_preferred_height(), not with the corresponding
|
|
|
|
* Clutter methods.
|
2009-09-08 19:47:30 +00:00
|
|
|
*/
|
|
|
|
void
|
2010-02-13 16:24:25 +00:00
|
|
|
_st_allocate_fill (StWidget *parent,
|
|
|
|
ClutterActor *child,
|
2009-09-08 19:47:30 +00:00
|
|
|
ClutterActorBox *childbox,
|
|
|
|
StAlign x_alignment,
|
|
|
|
StAlign y_alignment,
|
|
|
|
gboolean x_fill,
|
|
|
|
gboolean y_fill)
|
|
|
|
{
|
|
|
|
gfloat natural_width, natural_height;
|
|
|
|
gfloat min_width, min_height;
|
|
|
|
gfloat child_width, child_height;
|
|
|
|
gfloat available_width, available_height;
|
|
|
|
ClutterRequestMode request;
|
|
|
|
gdouble x_align, y_align;
|
|
|
|
|
|
|
|
available_width = childbox->x2 - childbox->x1;
|
|
|
|
available_height = childbox->y2 - childbox->y1;
|
|
|
|
|
|
|
|
if (available_width < 0)
|
|
|
|
{
|
2010-02-13 16:24:25 +00:00
|
|
|
available_width = 0;
|
|
|
|
childbox->x2 = childbox->x1;
|
2009-09-08 19:47:30 +00:00
|
|
|
}
|
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
if (available_height < 0)
|
2009-09-08 19:47:30 +00:00
|
|
|
{
|
2010-02-13 16:24:25 +00:00
|
|
|
available_height = 0;
|
|
|
|
childbox->y2 = childbox->y1;
|
2009-09-08 19:47:30 +00:00
|
|
|
}
|
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
/* If we are filling both horizontally and vertically then we don't
|
|
|
|
* need to do anything else.
|
|
|
|
*/
|
2009-09-08 19:47:30 +00:00
|
|
|
if (x_fill && y_fill)
|
2010-02-13 16:24:25 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
_st_get_align_factors (parent, x_alignment, y_alignment,
|
|
|
|
&x_align, &y_align);
|
2009-09-08 19:47:30 +00:00
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
/* The following is based on clutter_actor_get_preferred_size(), but
|
|
|
|
* modified to cope with the fact that the available size may be
|
|
|
|
* less than the preferred size.
|
|
|
|
*/
|
2009-09-08 19:47:30 +00:00
|
|
|
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
|
|
|
|
g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
|
|
|
|
|
|
|
|
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
|
|
|
{
|
|
|
|
clutter_actor_get_preferred_width (child, available_height,
|
|
|
|
&min_width,
|
|
|
|
&natural_width);
|
|
|
|
|
|
|
|
child_width = CLAMP (natural_width, min_width, available_width);
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_height (child, child_width,
|
|
|
|
&min_height,
|
|
|
|
&natural_height);
|
|
|
|
|
|
|
|
child_height = CLAMP (natural_height, min_height, available_height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
clutter_actor_get_preferred_height (child, available_width,
|
|
|
|
&min_height,
|
|
|
|
&natural_height);
|
|
|
|
|
|
|
|
child_height = CLAMP (natural_height, min_height, available_height);
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_width (child, child_height,
|
|
|
|
&min_width,
|
|
|
|
&natural_width);
|
|
|
|
|
|
|
|
child_width = CLAMP (natural_width, min_width, available_width);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!x_fill)
|
|
|
|
{
|
2010-02-13 16:24:25 +00:00
|
|
|
childbox->x1 += (int)((available_width - child_width) * x_align);
|
|
|
|
childbox->x2 = childbox->x1 + (int) child_width;
|
2009-09-08 19:47:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!y_fill)
|
|
|
|
{
|
2010-02-13 16:24:25 +00:00
|
|
|
childbox->y1 += (int)((available_height - child_height) * y_align);
|
|
|
|
childbox->y2 = childbox->y1 + (int) child_height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* _st_get_align_factors:
|
|
|
|
* @widget: an #StWidget
|
|
|
|
* @x_align: an #StAlign
|
|
|
|
* @y_align: an #StAlign
|
|
|
|
* @x_align_out: (out) (allow-none): @x_align as a #gdouble
|
|
|
|
* @y_align_out: (out) (allow-none): @y_align as a #gdouble
|
|
|
|
*
|
|
|
|
* Converts @x_align and @y_align to #gdouble values. If @widget has
|
|
|
|
* %ST_TEXT_DIRECTION_RTL, the @x_align_out value will be flipped
|
|
|
|
* relative to @x_align.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_st_get_align_factors (StWidget *widget,
|
|
|
|
StAlign x_align,
|
|
|
|
StAlign y_align,
|
|
|
|
gdouble *x_align_out,
|
|
|
|
gdouble *y_align_out)
|
|
|
|
{
|
|
|
|
if (x_align_out)
|
|
|
|
{
|
|
|
|
switch (x_align)
|
|
|
|
{
|
|
|
|
case ST_ALIGN_START:
|
|
|
|
*x_align_out = 0.0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_ALIGN_MIDDLE:
|
|
|
|
*x_align_out = 0.5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_ALIGN_END:
|
|
|
|
*x_align_out = 1.0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_warn_if_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (st_widget_get_direction (widget) == ST_TEXT_DIRECTION_RTL)
|
|
|
|
*x_align_out = 1.0 - *x_align_out;
|
2009-09-08 19:47:30 +00:00
|
|
|
}
|
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
if (y_align_out)
|
|
|
|
{
|
|
|
|
switch (y_align)
|
|
|
|
{
|
|
|
|
case ST_ALIGN_START:
|
|
|
|
*y_align_out = 0.0;
|
|
|
|
break;
|
2009-09-08 19:47:30 +00:00
|
|
|
|
2010-02-13 16:24:25 +00:00
|
|
|
case ST_ALIGN_MIDDLE:
|
|
|
|
*y_align_out = 0.5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_ALIGN_END:
|
|
|
|
*y_align_out = 1.0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_warn_if_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-09-08 19:47:30 +00:00
|
|
|
}
|
2009-12-02 19:42:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* _st_set_text_from_style:
|
|
|
|
* @text: Target #ClutterText
|
|
|
|
* @theme_node: Source #StThemeNode
|
|
|
|
*
|
|
|
|
* Set various GObject properties of the @text object using
|
|
|
|
* CSS information from @theme_node.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_st_set_text_from_style (ClutterText *text,
|
|
|
|
StThemeNode *theme_node)
|
|
|
|
{
|
|
|
|
|
|
|
|
ClutterColor color;
|
|
|
|
StTextDecoration decoration;
|
|
|
|
PangoAttrList *attribs;
|
|
|
|
const PangoFontDescription *font;
|
|
|
|
gchar *font_string;
|
|
|
|
|
|
|
|
st_theme_node_get_foreground_color (theme_node, &color);
|
|
|
|
clutter_text_set_color (text, &color);
|
|
|
|
|
|
|
|
font = st_theme_node_get_font (theme_node);
|
|
|
|
font_string = pango_font_description_to_string (font);
|
|
|
|
clutter_text_set_font_name (text, font_string);
|
|
|
|
g_free (font_string);
|
|
|
|
|
|
|
|
attribs = pango_attr_list_new ();
|
|
|
|
|
|
|
|
decoration = st_theme_node_get_text_decoration (theme_node);
|
|
|
|
if (decoration & ST_TEXT_DECORATION_UNDERLINE)
|
|
|
|
{
|
|
|
|
PangoAttribute *underline = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
|
|
|
|
pango_attr_list_insert (attribs, underline);
|
|
|
|
}
|
|
|
|
if (decoration & ST_TEXT_DECORATION_LINE_THROUGH)
|
|
|
|
{
|
|
|
|
PangoAttribute *strikethrough = pango_attr_strikethrough_new (TRUE);
|
|
|
|
pango_attr_list_insert (attribs, strikethrough);
|
|
|
|
}
|
|
|
|
/* Pango doesn't have an equivalent attribute for _OVERLINE, and we deliberately
|
|
|
|
* skip BLINK (for now...)
|
|
|
|
*/
|
|
|
|
|
|
|
|
clutter_text_set_attributes (text, attribs);
|
|
|
|
|
|
|
|
pango_attr_list_unref (attribs);
|
|
|
|
}
|