2009-09-29 19:08:01 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2009-09-10 05:42:25 +00:00
|
|
|
/*
|
|
|
|
* st-box-layout.h: box layout actor
|
|
|
|
*
|
|
|
|
* Copyright 2009 Intel Corporation.
|
2010-11-10 22:00:45 +00:00
|
|
|
* Copyright 2009 Abderrahim Kitouni
|
|
|
|
* Copyright 2009, 2010 Red Hat, Inc.
|
|
|
|
* Copyright 2010 Florian Muellner
|
2009-09-10 05:42:25 +00:00
|
|
|
*
|
|
|
|
* 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
|
2010-11-10 22:00:45 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2009-09-10 05:42:25 +00:00
|
|
|
*/
|
|
|
|
|
2009-10-23 14:18:35 +00:00
|
|
|
/* Portions copied from Clutter:
|
|
|
|
* Clutter.
|
|
|
|
*
|
|
|
|
* An OpenGL based 'interactive canvas' library.
|
|
|
|
*
|
|
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 OpenedHand
|
|
|
|
* This library 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 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
/**
|
|
|
|
* SECTION:st-box-layout
|
|
|
|
* @short_description: a layout container arranging children in a single line
|
|
|
|
*
|
|
|
|
* The #StBoxLayout arranges its children along a single line, where each
|
|
|
|
* child can be allocated either its preferred size or larger if the expand
|
|
|
|
* option is set. If the fill option is set, the actor will be allocated more
|
|
|
|
* than its requested size. If the fill option is not set, but the expand option
|
|
|
|
* is enabled, then the position of the actor within the available space can
|
|
|
|
* be determined by the alignment child property.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-09-21 22:01:17 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
#include "st-box-layout.h"
|
|
|
|
|
|
|
|
#include "st-private.h"
|
|
|
|
#include "st-scrollable.h"
|
|
|
|
#include "st-box-layout-child.h"
|
|
|
|
|
|
|
|
|
|
|
|
static void st_box_container_iface_init (ClutterContainerIface *iface);
|
|
|
|
static void st_box_scrollable_interface_init (StScrollableInterface *iface);
|
|
|
|
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_VERTICAL,
|
|
|
|
PROP_PACK_START,
|
|
|
|
|
|
|
|
PROP_HADJUST,
|
|
|
|
PROP_VADJUST
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _StBoxLayoutPrivate
|
|
|
|
{
|
|
|
|
StAdjustment *hadjustment;
|
|
|
|
StAdjustment *vadjustment;
|
|
|
|
};
|
|
|
|
|
2015-09-24 16:04:48 +00:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (StBoxLayout, st_box_layout, ST_TYPE_WIDGET,
|
|
|
|
G_ADD_PRIVATE (StBoxLayout)
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
|
|
|
|
st_box_container_iface_init)
|
|
|
|
G_IMPLEMENT_INTERFACE (ST_TYPE_SCROLLABLE,
|
|
|
|
st_box_scrollable_interface_init));
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
/*
|
|
|
|
* StScrollable Interface Implementation
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
adjustment_value_notify_cb (StAdjustment *adjustment,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
StBoxLayout *box)
|
|
|
|
{
|
|
|
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scrollable_set_adjustments (StScrollable *scrollable,
|
|
|
|
StAdjustment *hadjustment,
|
|
|
|
StAdjustment *vadjustment)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (scrollable)->priv;
|
|
|
|
|
2010-03-10 23:32:10 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (scrollable));
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
if (hadjustment != priv->hadjustment)
|
|
|
|
{
|
|
|
|
if (priv->hadjustment)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->hadjustment,
|
|
|
|
adjustment_value_notify_cb,
|
|
|
|
scrollable);
|
|
|
|
g_object_unref (priv->hadjustment);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hadjustment)
|
|
|
|
{
|
|
|
|
g_object_ref (hadjustment);
|
|
|
|
g_signal_connect (hadjustment, "notify::value",
|
|
|
|
G_CALLBACK (adjustment_value_notify_cb),
|
|
|
|
scrollable);
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->hadjustment = hadjustment;
|
2010-03-10 23:32:10 +00:00
|
|
|
g_object_notify (G_OBJECT (scrollable), "hadjustment");
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vadjustment != priv->vadjustment)
|
|
|
|
{
|
|
|
|
if (priv->vadjustment)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->vadjustment,
|
|
|
|
adjustment_value_notify_cb,
|
|
|
|
scrollable);
|
|
|
|
g_object_unref (priv->vadjustment);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vadjustment)
|
|
|
|
{
|
|
|
|
g_object_ref (vadjustment);
|
|
|
|
g_signal_connect (vadjustment, "notify::value",
|
|
|
|
G_CALLBACK (adjustment_value_notify_cb),
|
|
|
|
scrollable);
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->vadjustment = vadjustment;
|
2010-03-10 23:32:10 +00:00
|
|
|
g_object_notify (G_OBJECT (scrollable), "vadjustment");
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
2010-03-10 23:32:10 +00:00
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (scrollable));
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scrollable_get_adjustments (StScrollable *scrollable,
|
|
|
|
StAdjustment **hadjustment,
|
|
|
|
StAdjustment **vadjustment)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv;
|
|
|
|
|
|
|
|
priv = (ST_BOX_LAYOUT (scrollable))->priv;
|
|
|
|
|
2010-07-12 18:24:16 +00:00
|
|
|
if (hadjustment)
|
2010-03-10 23:32:10 +00:00
|
|
|
*hadjustment = priv->hadjustment;
|
2009-09-10 05:42:25 +00:00
|
|
|
|
|
|
|
if (vadjustment)
|
2010-03-10 23:32:10 +00:00
|
|
|
*vadjustment = priv->vadjustment;
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_scrollable_interface_init (StScrollableInterface *iface)
|
|
|
|
{
|
|
|
|
iface->set_adjustments = scrollable_set_adjustments;
|
|
|
|
iface->get_adjustments = scrollable_get_adjustments;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_container_iface_init (ClutterContainerIface *iface)
|
|
|
|
{
|
|
|
|
iface->child_meta_type = ST_TYPE_BOX_LAYOUT_CHILD;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterLayoutManager *layout;
|
2009-09-10 05:42:25 +00:00
|
|
|
StAdjustment *adjustment;
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterOrientation orientation;
|
2009-09-10 05:42:25 +00:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_VERTICAL:
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = clutter_actor_get_layout_manager (CLUTTER_ACTOR (object));
|
|
|
|
orientation = clutter_box_layout_get_orientation (CLUTTER_BOX_LAYOUT (layout));
|
|
|
|
g_value_set_boolean (value, orientation == CLUTTER_ORIENTATION_VERTICAL);
|
2009-09-10 05:42:25 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_PACK_START:
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = clutter_actor_get_layout_manager (CLUTTER_ACTOR (object));
|
|
|
|
g_value_set_boolean (value, clutter_box_layout_get_pack_start (CLUTTER_BOX_LAYOUT (layout)));
|
2009-09-10 05:42:25 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HADJUST:
|
|
|
|
scrollable_get_adjustments (ST_SCROLLABLE (object), &adjustment, NULL);
|
|
|
|
g_value_set_object (value, adjustment);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_VADJUST:
|
|
|
|
scrollable_get_adjustments (ST_SCROLLABLE (object), NULL, &adjustment);
|
|
|
|
g_value_set_object (value, adjustment);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
StBoxLayout *box = ST_BOX_LAYOUT (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_VERTICAL:
|
|
|
|
st_box_layout_set_vertical (box, g_value_get_boolean (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_PACK_START:
|
|
|
|
st_box_layout_set_pack_start (box, g_value_get_boolean (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HADJUST:
|
|
|
|
scrollable_set_adjustments (ST_SCROLLABLE (object),
|
|
|
|
g_value_get_object (value),
|
|
|
|
box->priv->vadjustment);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_VADJUST:
|
|
|
|
scrollable_set_adjustments (ST_SCROLLABLE (object),
|
|
|
|
box->priv->hadjustment,
|
|
|
|
g_value_get_object (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (object)->priv;
|
|
|
|
|
|
|
|
if (priv->hadjustment)
|
|
|
|
{
|
|
|
|
g_object_unref (priv->hadjustment);
|
|
|
|
priv->hadjustment = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->vadjustment)
|
|
|
|
{
|
|
|
|
g_object_unref (priv->vadjustment);
|
|
|
|
priv->vadjustment = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (st_box_layout_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_allocate (ClutterActor *actor,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv;
|
2009-09-20 17:41:13 +00:00
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterLayoutManager *layout = clutter_actor_get_layout_manager (actor);
|
2009-09-20 17:41:13 +00:00
|
|
|
ClutterActorBox content_box;
|
2009-09-21 22:01:17 +00:00
|
|
|
gfloat avail_width, avail_height, min_width, natural_width, min_height, natural_height;
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->allocate (actor, box, flags);
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
st_theme_node_get_content_box (theme_node, box, &content_box);
|
2013-07-02 19:47:44 +00:00
|
|
|
clutter_actor_box_get_size (&content_box, &avail_width, &avail_height);
|
2009-09-20 17:41:13 +00:00
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
clutter_layout_manager_get_preferred_width (layout, CLUTTER_CONTAINER (actor),
|
|
|
|
avail_height,
|
|
|
|
&min_width, &natural_width);
|
|
|
|
clutter_layout_manager_get_preferred_height (layout, CLUTTER_CONTAINER (actor),
|
|
|
|
MAX (avail_width, min_width),
|
|
|
|
&min_height, &natural_height);
|
2010-03-05 22:20:56 +00:00
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
|
|
|
|
/* update adjustments for scrolling */
|
|
|
|
if (priv->vadjustment)
|
|
|
|
{
|
|
|
|
gdouble prev_value;
|
|
|
|
|
|
|
|
g_object_set (G_OBJECT (priv->vadjustment),
|
|
|
|
"lower", 0.0,
|
2010-03-10 18:57:05 +00:00
|
|
|
"upper", MAX (min_height, avail_height),
|
2009-09-10 05:42:25 +00:00
|
|
|
"page-size", avail_height,
|
|
|
|
"step-increment", avail_height / 6,
|
2010-03-10 18:57:05 +00:00
|
|
|
"page-increment", avail_height - avail_height / 6,
|
2009-09-10 05:42:25 +00:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
prev_value = st_adjustment_get_value (priv->vadjustment);
|
|
|
|
st_adjustment_set_value (priv->vadjustment, prev_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->hadjustment)
|
|
|
|
{
|
|
|
|
gdouble prev_value;
|
|
|
|
|
|
|
|
g_object_set (G_OBJECT (priv->hadjustment),
|
|
|
|
"lower", 0.0,
|
2010-03-10 18:57:05 +00:00
|
|
|
"upper", MAX (min_width, avail_width),
|
2009-09-10 05:42:25 +00:00
|
|
|
"page-size", avail_width,
|
|
|
|
"step-increment", avail_width / 6,
|
2010-03-10 18:57:05 +00:00
|
|
|
"page-increment", avail_width - avail_width / 6,
|
2009-09-10 05:42:25 +00:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
prev_value = st_adjustment_get_value (priv->hadjustment);
|
|
|
|
st_adjustment_set_value (priv->hadjustment, prev_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_apply_transform (ClutterActor *a,
|
|
|
|
CoglMatrix *m)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (a)->priv;
|
|
|
|
gdouble x, y;
|
|
|
|
|
|
|
|
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->apply_transform (a, m);
|
|
|
|
|
|
|
|
if (priv->hadjustment)
|
|
|
|
x = st_adjustment_get_value (priv->hadjustment);
|
|
|
|
else
|
|
|
|
x = 0;
|
|
|
|
|
|
|
|
if (priv->vadjustment)
|
|
|
|
y = st_adjustment_get_value (priv->vadjustment);
|
|
|
|
else
|
|
|
|
y = 0;
|
|
|
|
|
|
|
|
cogl_matrix_translate (m, (int) -x, (int) -y, 0);
|
|
|
|
}
|
|
|
|
|
2010-11-13 14:08:03 +00:00
|
|
|
/* If we are translated, then we need to translate back before chaining
|
|
|
|
* up or the background and borders will be drawn in the wrong place */
|
|
|
|
static void
|
|
|
|
get_border_paint_offsets (StBoxLayout *self,
|
|
|
|
double *x,
|
|
|
|
double *y)
|
|
|
|
{
|
|
|
|
StBoxLayoutPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->hadjustment)
|
|
|
|
*x = st_adjustment_get_value (priv->hadjustment);
|
|
|
|
else
|
|
|
|
*x = 0;
|
|
|
|
|
|
|
|
if (priv->vadjustment)
|
|
|
|
*y = st_adjustment_get_value (priv->vadjustment);
|
|
|
|
else
|
|
|
|
*y = 0;
|
|
|
|
}
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_paint (ClutterActor *actor)
|
|
|
|
{
|
2010-11-13 14:08:03 +00:00
|
|
|
StBoxLayout *self = ST_BOX_LAYOUT (actor);
|
|
|
|
StBoxLayoutPrivate *priv = self->priv;
|
2009-09-21 23:11:09 +00:00
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
2009-09-10 05:42:25 +00:00
|
|
|
gdouble x, y;
|
2009-09-21 23:11:09 +00:00
|
|
|
ClutterActorBox allocation_box;
|
|
|
|
ClutterActorBox content_box;
|
2012-02-16 18:40:31 +00:00
|
|
|
ClutterActor *child;
|
2015-02-21 01:02:56 +00:00
|
|
|
CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2010-11-13 14:08:03 +00:00
|
|
|
get_border_paint_offsets (self, &x, &y);
|
2009-09-21 23:11:09 +00:00
|
|
|
if (x != 0 || y != 0)
|
|
|
|
{
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_push_matrix (fb);
|
|
|
|
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
|
2009-09-21 23:11:09 +00:00
|
|
|
}
|
|
|
|
|
2012-02-13 21:41:29 +00:00
|
|
|
st_widget_paint_background (ST_WIDGET (actor));
|
2009-09-21 23:11:09 +00:00
|
|
|
|
|
|
|
if (x != 0 || y != 0)
|
|
|
|
{
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_pop_matrix (fb);
|
2009-09-21 23:11:09 +00:00
|
|
|
}
|
|
|
|
|
2012-02-16 18:40:31 +00:00
|
|
|
if (clutter_actor_get_n_children (actor) == 0)
|
2009-09-21 23:11:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
clutter_actor_get_allocation_box (actor, &allocation_box);
|
|
|
|
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
|
|
|
|
|
|
|
|
content_box.x1 += x;
|
|
|
|
content_box.y1 += y;
|
|
|
|
content_box.x2 += x;
|
|
|
|
content_box.y2 += y;
|
|
|
|
|
|
|
|
/* The content area forms the viewport into the scrolled contents, while
|
|
|
|
* the borders and background stay in place; after drawing the borders and
|
|
|
|
* background, we clip to the content area */
|
|
|
|
if (priv->hadjustment || priv->vadjustment)
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_push_rectangle_clip (fb,
|
|
|
|
(int)content_box.x1,
|
|
|
|
(int)content_box.y1,
|
|
|
|
(int)content_box.x2,
|
|
|
|
(int)content_box.y2);
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2012-02-16 18:40:31 +00:00
|
|
|
for (child = clutter_actor_get_first_child (actor);
|
|
|
|
child != NULL;
|
|
|
|
child = clutter_actor_get_next_sibling (child))
|
|
|
|
clutter_actor_paint (child);
|
2009-09-21 23:11:09 +00:00
|
|
|
|
|
|
|
if (priv->hadjustment || priv->vadjustment)
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_pop_clip (fb);
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_pick (ClutterActor *actor,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
2010-11-13 14:08:03 +00:00
|
|
|
StBoxLayout *self = ST_BOX_LAYOUT (actor);
|
|
|
|
StBoxLayoutPrivate *priv = self->priv;
|
2009-09-21 23:11:09 +00:00
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
2009-09-10 05:42:25 +00:00
|
|
|
gdouble x, y;
|
2009-09-21 23:11:09 +00:00
|
|
|
ClutterActorBox allocation_box;
|
|
|
|
ClutterActorBox content_box;
|
2012-02-16 18:40:31 +00:00
|
|
|
ClutterActor *child;
|
2015-02-21 01:02:56 +00:00
|
|
|
CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2010-11-13 14:08:03 +00:00
|
|
|
get_border_paint_offsets (self, &x, &y);
|
2009-09-21 23:11:09 +00:00
|
|
|
if (x != 0 || y != 0)
|
|
|
|
{
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_push_matrix (fb);
|
|
|
|
cogl_framebuffer_translate (fb, (int)x, (int)y, 0);
|
2009-09-21 23:11:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color);
|
|
|
|
|
|
|
|
if (x != 0 || y != 0)
|
|
|
|
{
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_pop_matrix (fb);
|
2009-09-21 23:11:09 +00:00
|
|
|
}
|
|
|
|
|
2012-02-16 18:40:31 +00:00
|
|
|
if (clutter_actor_get_n_children (actor) == 0)
|
2009-09-21 23:11:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
clutter_actor_get_allocation_box (actor, &allocation_box);
|
|
|
|
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
|
|
|
|
|
|
|
|
content_box.x1 += x;
|
|
|
|
content_box.y1 += y;
|
|
|
|
content_box.x2 += x;
|
|
|
|
content_box.y2 += y;
|
|
|
|
|
|
|
|
if (priv->hadjustment || priv->vadjustment)
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_push_rectangle_clip (fb,
|
|
|
|
(int)content_box.x1,
|
|
|
|
(int)content_box.y1,
|
|
|
|
(int)content_box.x2,
|
|
|
|
(int)content_box.y2);
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2012-02-16 18:40:31 +00:00
|
|
|
for (child = clutter_actor_get_first_child (actor);
|
|
|
|
child != NULL;
|
|
|
|
child = clutter_actor_get_next_sibling (child))
|
|
|
|
clutter_actor_paint (child);
|
2009-09-21 23:11:09 +00:00
|
|
|
|
|
|
|
if (priv->hadjustment || priv->vadjustment)
|
2015-02-21 01:02:56 +00:00
|
|
|
cogl_framebuffer_pop_clip (fb);
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
2010-11-13 14:08:03 +00:00
|
|
|
static gboolean
|
|
|
|
st_box_layout_get_paint_volume (ClutterActor *actor,
|
|
|
|
ClutterPaintVolume *volume)
|
|
|
|
{
|
|
|
|
StBoxLayout *self = ST_BOX_LAYOUT (actor);
|
|
|
|
gdouble x, y;
|
2012-02-13 20:05:38 +00:00
|
|
|
StBoxLayoutPrivate *priv = self->priv;
|
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
|
|
|
ClutterActorBox allocation_box;
|
|
|
|
ClutterActorBox content_box;
|
|
|
|
ClutterVertex origin;
|
2010-11-13 14:08:03 +00:00
|
|
|
|
2014-09-15 15:32:33 +00:00
|
|
|
/* Setting the paint volume does not make sense when we don't have any allocation */
|
|
|
|
if (!clutter_actor_has_allocation (actor))
|
|
|
|
return FALSE;
|
|
|
|
|
2012-02-13 20:05:38 +00:00
|
|
|
/* When have an adjustment we are clipped to the content box, so base
|
|
|
|
* our paint volume on that. */
|
|
|
|
if (priv->hadjustment || priv->vadjustment)
|
|
|
|
{
|
|
|
|
clutter_actor_get_allocation_box (actor, &allocation_box);
|
|
|
|
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
|
|
|
|
origin.x = content_box.x1 - allocation_box.x1;
|
|
|
|
origin.y = content_box.y1 - allocation_box.y2;
|
|
|
|
origin.z = 0.f;
|
|
|
|
clutter_paint_volume_set_width (volume, content_box.x2 - content_box.x1);
|
|
|
|
clutter_paint_volume_set_height (volume, content_box.y2 - content_box.y1);
|
|
|
|
}
|
|
|
|
else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume))
|
2011-08-01 19:16:45 +00:00
|
|
|
return FALSE;
|
2010-11-13 14:08:03 +00:00
|
|
|
|
|
|
|
/* When scrolled, st_box_layout_apply_transform() includes the scroll offset
|
|
|
|
* and affects paint volumes. This is right for our children, but our paint volume
|
|
|
|
* is determined by our allocation and borders and doesn't scroll, so we need
|
|
|
|
* to reverse-compensate here, the same as we do when painting.
|
|
|
|
*/
|
|
|
|
get_border_paint_offsets (self, &x, &y);
|
|
|
|
if (x != 0 || y != 0)
|
|
|
|
{
|
|
|
|
clutter_paint_volume_get_origin (volume, &origin);
|
|
|
|
origin.x += x;
|
|
|
|
origin.y += y;
|
|
|
|
clutter_paint_volume_set_origin (volume, &origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-09-30 03:03:41 +00:00
|
|
|
static void
|
|
|
|
st_box_layout_style_changed (StWidget *self)
|
|
|
|
{
|
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (self);
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterBoxLayout *layout;
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
double spacing;
|
2009-09-30 03:03:41 +00:00
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = CLUTTER_BOX_LAYOUT (clutter_actor_get_layout_manager (CLUTTER_ACTOR (self)));
|
|
|
|
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
spacing = st_theme_node_get_length (theme_node, "spacing");
|
2013-07-02 19:47:44 +00:00
|
|
|
clutter_box_layout_set_spacing (layout, (int)(spacing + 0.5));
|
2009-09-30 03:03:41 +00:00
|
|
|
|
|
|
|
ST_WIDGET_CLASS (st_box_layout_parent_class)->style_changed (self);
|
|
|
|
}
|
|
|
|
|
2013-07-06 22:11:02 +00:00
|
|
|
static void
|
|
|
|
layout_notify (GObject *object,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GObject *self = user_data;
|
|
|
|
const char *prop_name = g_param_spec_get_name (pspec);
|
|
|
|
|
|
|
|
if (g_object_class_find_property (G_OBJECT_GET_CLASS (self), prop_name))
|
|
|
|
g_object_notify (self, prop_name);
|
|
|
|
}
|
|
|
|
|
2015-10-04 01:06:34 +00:00
|
|
|
static void
|
|
|
|
on_layout_manager_notify (GObject *object,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ClutterActor *actor = CLUTTER_ACTOR (object);
|
|
|
|
ClutterLayoutManager *layout = clutter_actor_get_layout_manager (actor);
|
|
|
|
|
|
|
|
g_warn_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
|
|
|
|
|
|
|
|
if (layout == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_signal_connect_swapped (layout, "layout-changed",
|
|
|
|
G_CALLBACK (clutter_actor_queue_relayout), actor);
|
|
|
|
g_signal_connect (layout, "notify", G_CALLBACK (layout_notify), object);
|
|
|
|
}
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
static void
|
|
|
|
st_box_layout_class_init (StBoxLayoutClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
2009-09-30 03:03:41 +00:00
|
|
|
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
|
2009-09-10 05:42:25 +00:00
|
|
|
GParamSpec *pspec;
|
|
|
|
|
|
|
|
object_class->get_property = st_box_layout_get_property;
|
|
|
|
object_class->set_property = st_box_layout_set_property;
|
|
|
|
object_class->dispose = st_box_layout_dispose;
|
|
|
|
|
|
|
|
actor_class->allocate = st_box_layout_allocate;
|
|
|
|
actor_class->apply_transform = st_box_layout_apply_transform;
|
|
|
|
|
|
|
|
actor_class->paint = st_box_layout_paint;
|
2010-11-13 14:08:03 +00:00
|
|
|
actor_class->get_paint_volume = st_box_layout_get_paint_volume;
|
2009-09-10 05:42:25 +00:00
|
|
|
actor_class->pick = st_box_layout_pick;
|
|
|
|
|
2009-09-30 03:03:41 +00:00
|
|
|
widget_class->style_changed = st_box_layout_style_changed;
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
pspec = g_param_spec_boolean ("vertical",
|
|
|
|
"Vertical",
|
|
|
|
"Whether the layout should be vertical, rather"
|
|
|
|
"than horizontal",
|
|
|
|
FALSE,
|
|
|
|
ST_PARAM_READWRITE);
|
|
|
|
g_object_class_install_property (object_class, PROP_VERTICAL, pspec);
|
|
|
|
|
|
|
|
pspec = g_param_spec_boolean ("pack-start",
|
|
|
|
"Pack Start",
|
|
|
|
"Whether to pack items at the start of the box",
|
|
|
|
FALSE,
|
|
|
|
ST_PARAM_READWRITE);
|
|
|
|
g_object_class_install_property (object_class, PROP_PACK_START, pspec);
|
|
|
|
|
|
|
|
/* StScrollable properties */
|
|
|
|
g_object_class_override_property (object_class,
|
|
|
|
PROP_HADJUST,
|
|
|
|
"hadjustment");
|
|
|
|
|
|
|
|
g_object_class_override_property (object_class,
|
|
|
|
PROP_VADJUST,
|
|
|
|
"vadjustment");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_box_layout_init (StBoxLayout *self)
|
|
|
|
{
|
2015-09-24 16:04:48 +00:00
|
|
|
self->priv = st_box_layout_get_instance_private (self);
|
2015-10-04 01:06:34 +00:00
|
|
|
|
|
|
|
g_signal_connect (self, "notify::layout-manager",
|
|
|
|
G_CALLBACK (on_layout_manager_notify), NULL);
|
|
|
|
clutter_actor_set_layout_manager (CLUTTER_ACTOR (self), clutter_box_layout_new ());
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_box_layout_new:
|
|
|
|
*
|
|
|
|
* Create a new #StBoxLayout.
|
|
|
|
*
|
|
|
|
* Returns: a newly allocated #StBoxLayout
|
|
|
|
*/
|
|
|
|
StWidget *
|
|
|
|
st_box_layout_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (ST_TYPE_BOX_LAYOUT, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_box_layout_set_vertical:
|
|
|
|
* @box: A #StBoxLayout
|
2010-03-23 23:56:10 +00:00
|
|
|
* @vertical: %TRUE if the layout should be vertical
|
2009-09-10 05:42:25 +00:00
|
|
|
*
|
|
|
|
* Set the value of the #StBoxLayout::vertical property
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_box_layout_set_vertical (StBoxLayout *box,
|
|
|
|
gboolean vertical)
|
|
|
|
{
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterLayoutManager *layout;
|
|
|
|
ClutterOrientation orientation;
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
g_return_if_fail (ST_IS_BOX_LAYOUT (box));
|
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box));
|
|
|
|
orientation = vertical ? CLUTTER_ORIENTATION_VERTICAL
|
|
|
|
: CLUTTER_ORIENTATION_HORIZONTAL;
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
if (clutter_box_layout_get_orientation (CLUTTER_BOX_LAYOUT (layout)) != orientation)
|
|
|
|
{
|
|
|
|
clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), orientation);
|
2009-09-10 05:42:25 +00:00
|
|
|
g_object_notify (G_OBJECT (box), "vertical");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_box_layout_get_vertical:
|
|
|
|
* @box: A #StBoxLayout
|
|
|
|
*
|
|
|
|
* Get the value of the #StBoxLayout::vertical property.
|
|
|
|
*
|
2010-03-23 23:56:10 +00:00
|
|
|
* Returns: %TRUE if the layout is vertical
|
2009-09-10 05:42:25 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_box_layout_get_vertical (StBoxLayout *box)
|
|
|
|
{
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterLayoutManager *layout;
|
|
|
|
ClutterOrientation orientation;
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
g_return_val_if_fail (ST_IS_BOX_LAYOUT (box), FALSE);
|
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box));
|
|
|
|
orientation = clutter_box_layout_get_orientation (CLUTTER_BOX_LAYOUT (layout));
|
|
|
|
return orientation == CLUTTER_ORIENTATION_VERTICAL;
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_box_layout_set_pack_start:
|
|
|
|
* @box: A #StBoxLayout
|
2010-03-23 23:56:10 +00:00
|
|
|
* @pack_start: %TRUE if the layout should use pack-start
|
2009-09-10 05:42:25 +00:00
|
|
|
*
|
|
|
|
* Set the value of the #StBoxLayout::pack-start property.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_box_layout_set_pack_start (StBoxLayout *box,
|
|
|
|
gboolean pack_start)
|
|
|
|
{
|
2013-07-02 19:47:44 +00:00
|
|
|
ClutterBoxLayout *layout;
|
|
|
|
|
2009-09-10 05:42:25 +00:00
|
|
|
g_return_if_fail (ST_IS_BOX_LAYOUT (box));
|
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
layout = CLUTTER_BOX_LAYOUT (clutter_actor_get_layout_manager (CLUTTER_ACTOR (box)));
|
2009-09-10 05:42:25 +00:00
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
if (clutter_box_layout_get_pack_start (layout) != pack_start)
|
|
|
|
{
|
|
|
|
clutter_box_layout_set_pack_start (layout, pack_start);
|
2009-09-10 05:42:25 +00:00
|
|
|
g_object_notify (G_OBJECT (box), "pack-start");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_box_layout_get_pack_start:
|
|
|
|
* @box: A #StBoxLayout
|
|
|
|
*
|
|
|
|
* Get the value of the #StBoxLayout::pack-start property.
|
|
|
|
*
|
2010-03-23 23:56:10 +00:00
|
|
|
* Returns: %TRUE if pack-start is enabled
|
2009-09-10 05:42:25 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_box_layout_get_pack_start (StBoxLayout *box)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_BOX_LAYOUT (box), FALSE);
|
|
|
|
|
2013-07-02 19:47:44 +00:00
|
|
|
return clutter_box_layout_get_pack_start (CLUTTER_BOX_LAYOUT (clutter_actor_get_layout_manager (CLUTTER_ACTOR (box))));
|
2009-09-10 05:42:25 +00:00
|
|
|
}
|