56fb7e2c58
In order to take advantage of clipped redraws (only redraw the parts that actually changed), we have to inform clutter about our paint_volume by implementing the get_paint_volume virtual method. As this feature had been added in in clutter 1.5.x we now require that. https://bugzilla.gnome.org/show_bug.cgi?id=630932
295 lines
8.8 KiB
C
295 lines
8.8 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
/*
|
|
* st-group.c: A fixed layout container based on ClutterGroup
|
|
*
|
|
* Copyright 2010 Florian Müllner
|
|
* Copyright 2010 Intel Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU Lesser General Public License,
|
|
* version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:st-group
|
|
* SECTION:clutter-group
|
|
* @short_description: A fixed layout container
|
|
*
|
|
* A #StGroup is an Actor which contains multiple child actors positioned
|
|
* relative to the #StGroup position. Other operations such as scaling,
|
|
* rotating and clipping of the group will apply to the child actors.
|
|
*
|
|
* A #StGroup's size is defined by the size and position of its children;
|
|
* it will be the smallest non-negative size that covers the right and bottom
|
|
* edges of all of its children.
|
|
*
|
|
* Setting the size on a Group using #ClutterActor methods like
|
|
* clutter_actor_set_size() will override the natural size of the Group,
|
|
* however this will not affect the size of the children and they may still
|
|
* be painted outside of the allocation of the group. One way to constrain
|
|
* the visible area of a #StGroup to a specified allocation is to
|
|
* explicitly set the size of the #StGroup and then use the
|
|
* #ClutterActor:clip-to-allocation property.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <clutter/clutter.h>
|
|
|
|
#include "st-group.h"
|
|
#include "st-enum-types.h"
|
|
#include "st-private.h"
|
|
|
|
G_DEFINE_TYPE (StGroup, st_group, ST_TYPE_CONTAINER);
|
|
|
|
static void
|
|
st_group_paint (ClutterActor *actor)
|
|
{
|
|
CLUTTER_ACTOR_CLASS (st_group_parent_class)->paint (actor);
|
|
|
|
clutter_container_foreach (CLUTTER_CONTAINER (actor),
|
|
CLUTTER_CALLBACK (clutter_actor_paint),
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
st_group_pick (ClutterActor *actor,
|
|
const ClutterColor *pick)
|
|
{
|
|
/* Chain up so we get a bounding box painted (if we are reactive) */
|
|
CLUTTER_ACTOR_CLASS (st_group_parent_class)->pick (actor, pick);
|
|
|
|
clutter_container_foreach (CLUTTER_CONTAINER (actor),
|
|
CLUTTER_CALLBACK (clutter_actor_paint),
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
st_group_get_preferred_width (ClutterActor *actor,
|
|
gfloat for_height,
|
|
gfloat *min_width_p,
|
|
gfloat *natural_width_p)
|
|
{
|
|
StThemeNode *node = st_widget_get_theme_node (ST_WIDGET (actor));
|
|
gdouble min_width, natural_width;
|
|
gint css_width, css_min_width, css_max_width;
|
|
GList *l, *children;
|
|
|
|
css_width = st_theme_node_get_width (node);
|
|
css_min_width = st_theme_node_get_min_width (node);
|
|
css_max_width = st_theme_node_get_max_width (node);
|
|
|
|
/* We will always be at least 0 sized (ie, if all of the actors are
|
|
* to the left of the origin we won't return a negative size)
|
|
*/
|
|
min_width = 0;
|
|
natural_width = 0;
|
|
|
|
children = st_container_get_children_list (ST_CONTAINER (actor));
|
|
|
|
for (l = children; l != NULL; l = l->next)
|
|
{
|
|
ClutterActor *child = l->data;
|
|
gfloat child_x, child_min, child_nat;
|
|
|
|
child_x = clutter_actor_get_x (child);
|
|
|
|
/* for_height is irrelevant to the fixed layout, so it's not used */
|
|
_st_actor_get_preferred_width (child, -1, FALSE,
|
|
&child_min, &child_nat);
|
|
|
|
/* Track the rightmost edge */
|
|
if (child_x + child_min > min_width)
|
|
min_width = child_x + child_min;
|
|
|
|
if (child_x + child_nat > natural_width)
|
|
natural_width = child_x + child_nat;
|
|
}
|
|
|
|
/* The size is defined as the distance from the origin to the right-hand
|
|
* edge of the rightmost actor, unless overridden with min-width
|
|
*/
|
|
if (min_width_p)
|
|
{
|
|
if (css_min_width != -1)
|
|
*min_width_p = css_min_width;
|
|
else
|
|
*min_width_p = min_width;
|
|
}
|
|
|
|
if (natural_width_p)
|
|
{
|
|
if (css_width != -1)
|
|
natural_width = css_width;
|
|
*natural_width_p = MIN (natural_width, css_max_width);
|
|
}
|
|
}
|
|
|
|
static void
|
|
st_group_get_preferred_height (ClutterActor *actor,
|
|
gfloat for_width,
|
|
gfloat *min_height_p,
|
|
gfloat *natural_height_p)
|
|
{
|
|
StThemeNode *node = st_widget_get_theme_node (ST_WIDGET (actor));
|
|
gdouble min_height, natural_height;
|
|
gint css_height, css_min_height, css_max_height;
|
|
GList *l, *children;
|
|
|
|
css_height = st_theme_node_get_height (node);
|
|
css_min_height = st_theme_node_get_min_height (node);
|
|
css_max_height = st_theme_node_get_max_height (node);
|
|
|
|
/* We will always be at least 0 sized (ie, if all of the actors are
|
|
* above of the origin we won't return a negative size)
|
|
*/
|
|
min_height = 0;
|
|
natural_height = 0;
|
|
|
|
children = st_container_get_children_list (ST_CONTAINER (actor));
|
|
|
|
for (l = children; l != NULL; l = l->next)
|
|
{
|
|
ClutterActor *child = l->data;
|
|
gfloat child_y, child_min, child_nat;
|
|
|
|
child_y = clutter_actor_get_y (child);
|
|
|
|
/* for_width is irrelevant to the fixed layout, so it's not used */
|
|
_st_actor_get_preferred_height (child, -1, FALSE,
|
|
&child_min, &child_nat);
|
|
|
|
/* Track the bottommost edge */
|
|
if (child_y + child_min > min_height)
|
|
min_height = child_y + child_min;
|
|
|
|
if (child_y + child_nat > natural_height)
|
|
natural_height = child_y + child_nat;
|
|
}
|
|
|
|
/* The size is defined as the distance from the origin to the right-hand
|
|
* edge of the rightmost actor, unless overridden with min-height
|
|
*/
|
|
if (min_height_p)
|
|
{
|
|
if (css_min_height != -1)
|
|
*min_height_p = css_min_height;
|
|
else
|
|
*min_height_p = min_height;
|
|
}
|
|
|
|
if (natural_height_p)
|
|
{
|
|
if (css_height != -1)
|
|
natural_height = css_height;
|
|
*natural_height_p = MIN (natural_height, css_max_height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
st_group_allocate (ClutterActor *actor,
|
|
const ClutterActorBox *box,
|
|
ClutterAllocationFlags flags)
|
|
{
|
|
GList *l, *children;
|
|
|
|
CLUTTER_ACTOR_CLASS (st_group_parent_class)->allocate (actor, box, flags);
|
|
|
|
children = st_container_get_children_list (ST_CONTAINER (actor));
|
|
for (l = children; l != NULL; l = l->next)
|
|
{
|
|
ClutterActor *child = l->data;
|
|
clutter_actor_allocate_preferred_size (child, flags);
|
|
}
|
|
}
|
|
|
|
static void
|
|
st_group_show_all (ClutterActor *actor)
|
|
{
|
|
clutter_container_foreach (CLUTTER_CONTAINER (actor),
|
|
CLUTTER_CALLBACK (clutter_actor_show),
|
|
NULL);
|
|
clutter_actor_show (actor);
|
|
}
|
|
|
|
static void
|
|
st_group_hide_all (ClutterActor *actor)
|
|
{
|
|
clutter_actor_hide (actor);
|
|
clutter_container_foreach (CLUTTER_CONTAINER (actor),
|
|
CLUTTER_CALLBACK (clutter_actor_hide),
|
|
NULL);
|
|
}
|
|
|
|
/* Based on implementation from clutter-group.c */
|
|
static gboolean
|
|
st_group_get_paint_volume (ClutterActor *actor,
|
|
ClutterPaintVolume *volume)
|
|
{
|
|
GList *l, *children;
|
|
|
|
children = st_container_get_children_list (ST_CONTAINER (actor));
|
|
|
|
CLUTTER_ACTOR_CLASS (st_group_parent_class)->get_paint_volume (actor, volume);
|
|
|
|
for (l = children; l != NULL; l = l->next)
|
|
{
|
|
ClutterActor *child = l->data;
|
|
const ClutterPaintVolume *child_volume;
|
|
|
|
/* This gets the paint volume of the child transformed into the
|
|
* group's coordinate space... */
|
|
child_volume = clutter_actor_get_transformed_paint_volume (child, actor);
|
|
if (!child_volume)
|
|
return FALSE;
|
|
|
|
clutter_paint_volume_union (volume, child_volume);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
st_group_class_init (StGroupClass *klass)
|
|
{
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
|
|
|
actor_class->get_preferred_width = st_group_get_preferred_width;
|
|
actor_class->get_preferred_height = st_group_get_preferred_height;
|
|
actor_class->allocate = st_group_allocate;
|
|
actor_class->paint = st_group_paint;
|
|
actor_class->get_paint_volume = st_group_get_paint_volume;
|
|
actor_class->pick = st_group_pick;
|
|
actor_class->show_all = st_group_show_all;
|
|
actor_class->hide_all = st_group_hide_all;
|
|
}
|
|
|
|
static void
|
|
st_group_init (StGroup *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* st_group_new:
|
|
*
|
|
* Create a new #StGroup.
|
|
*
|
|
* Return value: the newly created #StGroup actor
|
|
*/
|
|
StWidget *
|
|
st_group_new (void)
|
|
{
|
|
return g_object_new (ST_TYPE_GROUP, NULL);
|
|
}
|