Add ClutterScrollActor

ClutterScrollActor is an actor that allows showing a portion of its
contents.
This commit is contained in:
Emmanuele Bassi 2012-04-12 15:56:53 +01:00
parent 4d34a2229d
commit 999bbe20a5
9 changed files with 787 additions and 1 deletions

View File

@ -108,6 +108,7 @@ source_h = \
$(srcdir)/clutter-property-transition.h \
$(srcdir)/clutter-script.h \
$(srcdir)/clutter-scriptable.h \
$(srcdir)/clutter-scroll-actor.h \
$(srcdir)/clutter-settings.h \
$(srcdir)/clutter-shader-effect.h \
$(srcdir)/clutter-shader-types.h \
@ -186,6 +187,7 @@ source_c = \
$(srcdir)/clutter-script.c \
$(srcdir)/clutter-script-parser.c \
$(srcdir)/clutter-scriptable.c \
$(srcdir)/clutter-scroll-actor.c \
$(srcdir)/clutter-settings.c \
$(srcdir)/clutter-shader-effect.c \
$(srcdir)/clutter-shader-types.c \

View File

@ -1213,6 +1213,26 @@ typedef enum {
CLUTTER_ORIENTATION_VERTICAL
} ClutterOrientation;
/**
* ClutterScrollMode:
* @CLUTTER_SCROLL_NONE: Ignore scrolling
* @CLUTTER_SCROLL_HORIZONTALLY: Scroll only horizontally
* @CLUTTER_SCROLL_VERTICALLY: Scroll only vertically
* @CLUTTER_SCROLL_BOTH: Scroll in both directions
*
* Scroll modes.
*
* Since: 1.12
*/
typedef enum { /*< prefix=CLUTTER_SCROLL >*/
CLUTTER_SCROLL_NONE = 0,
CLUTTER_SCROLL_HORIZONTALLY = 1 << 0,
CLUTTER_SCROLL_VERTICALLY = 1 << 1,
CLUTTER_SCROLL_BOTH = CLUTTER_SCROLL_HORIZONTALLY | CLUTTER_SCROLL_VERTICALLY
} ClutterScrollMode;
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */

View File

@ -0,0 +1,478 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2012 Intel Corporation
*
* 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.
*
* This library is distributed in the hope that 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:clutter-scroll-actor
* @Title: ClutterScrollActor
* @Short_Description: An actor for displaying a portion of its children
*
* #ClutterScrollActor is an actor that can be used to display a portion
* of the contents of its children.
*
* The extent of the area of a #ClutterScrollActor is defined by the size
* of its children; the visible region of the children of a #ClutterScrollActor
* is set by using clutter_scroll_actor_scroll_to_point() or by using
* clutter_scroll_actor_scroll_to_rect() to define a point or a rectangle
* acting as the origin, respectively.
*
* #ClutterScrollActor does not provide pointer or keyboard event handling,
* nor does it provide visible scroll handles.
*
* #ClutterScrollActor is available since Clutter 1.12.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-scroll-actor.h"
#include "clutter-actor-private.h"
#include "clutter-animatable.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-property-transition.h"
#include "clutter-transition.h"
struct _ClutterScrollActorPrivate
{
ClutterPoint scroll_to;
ClutterScrollMode scroll_mode;
ClutterTransition *transition;
};
enum
{
PROP_0,
PROP_SCROLL_MODE,
PROP_LAST
};
enum
{
ANIM_PROP_0,
ANIM_PROP_SCROLL_TO,
ANIM_PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
static GParamSpec *animatable_props[ANIM_PROP_LAST] = { NULL, };
static ClutterAnimatableIface *parent_animatable_iface = NULL;
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterScrollActor, clutter_scroll_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
clutter_animatable_iface_init))
static void
clutter_scroll_actor_apply_transform (ClutterActor *actor,
CoglMatrix *transform)
{
ClutterScrollActorPrivate *priv = CLUTTER_SCROLL_ACTOR (actor)->priv;
float x_factor, y_factor;
CLUTTER_ACTOR_CLASS (clutter_scroll_actor_parent_class)->apply_transform (actor, transform);
if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY)
x_factor = -priv->scroll_to.x;
else
x_factor = 0.f;
if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY)
y_factor = -priv->scroll_to.y;
else
y_factor = 0.f;
cogl_matrix_translate (transform, x_factor, y_factor, 0.0f);
}
static void
clutter_scroll_actor_paint (ClutterActor *actor)
{
ClutterScrollActorPrivate *priv = CLUTTER_SCROLL_ACTOR (actor)->priv;
ClutterActorBox allocation;
float width, height;
float x, y;
clutter_actor_get_allocation_box (actor, &allocation);
clutter_actor_box_get_size (&allocation, &width, &height);
if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY)
x = priv->scroll_to.x;
else
x = 0.f;
if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY)
y = priv->scroll_to.y;
else
y = 0.f;
/* offset the clip so that we keep it at the right place */
cogl_clip_push_rectangle (x,
y,
x + width,
y + height);
CLUTTER_ACTOR_CLASS (clutter_scroll_actor_parent_class)->paint (actor);
cogl_clip_pop ();
}
static void
clutter_scroll_actor_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
switch (prop_id)
{
case PROP_SCROLL_MODE:
clutter_scroll_actor_set_scroll_mode (actor, g_value_get_flags (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
clutter_scroll_actor_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
switch (prop_id)
{
case PROP_SCROLL_MODE:
g_value_set_flags (value, actor->priv->scroll_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
clutter_scroll_actor_class_init (ClutterScrollActorClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
g_type_class_add_private (klass, sizeof (ClutterScrollActorPrivate));
gobject_class->set_property = clutter_scroll_actor_set_property;
gobject_class->get_property = clutter_scroll_actor_get_property;
actor_class->apply_transform = clutter_scroll_actor_apply_transform;
actor_class->paint = clutter_scroll_actor_paint;
/**
* ClutterScrollActor:scroll-mode:
*
* The scrollin direction.
*
* Since: 1.12
*/
obj_props[PROP_SCROLL_MODE] =
g_param_spec_flags ("scroll-mode",
P_("Scroll Mode"),
P_("The scrolling direction"),
CLUTTER_TYPE_SCROLL_MODE,
CLUTTER_SCROLL_BOTH,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
}
static void
clutter_scroll_actor_init (ClutterScrollActor *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_SCROLL_ACTOR,
ClutterScrollActorPrivate);
self->priv->scroll_mode = CLUTTER_SCROLL_BOTH;
}
static GParamSpec *
clutter_scroll_actor_find_property (ClutterAnimatable *animatable,
const char *property_name)
{
if (strcmp (property_name, "scroll-to") == 0)
return animatable_props[ANIM_PROP_SCROLL_TO];
return parent_animatable_iface->find_property (animatable, property_name);
}
static void
clutter_scroll_actor_set_final_state (ClutterAnimatable *animatable,
const char *property_name,
const GValue *value)
{
if (strcmp (property_name, "scroll-to") == 0)
{
ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
const ClutterPoint *point = g_value_get_boxed (value);
if (point == NULL)
clutter_point_init (&self->priv->scroll_to, 0.f, 0.f);
else
self->priv->scroll_to = *point;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
else
parent_animatable_iface->set_final_state (animatable, property_name, value);
}
static void
clutter_scroll_actor_get_initial_state (ClutterAnimatable *animatable,
const char *property_name,
GValue *value)
{
if (strcmp (property_name, "scroll-to") == 0)
{
ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
g_value_set_boxed (value, &self->priv->scroll_to);
}
else
parent_animatable_iface->get_initial_state (animatable, property_name, value);
}
static void
clutter_animatable_iface_init (ClutterAnimatableIface *iface)
{
parent_animatable_iface = g_type_interface_peek_parent (iface);
animatable_props[ANIM_PROP_SCROLL_TO] =
g_param_spec_boxed ("scroll-to",
"Scroll To",
"The point to scroll the actor to",
CLUTTER_TYPE_POINT,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
CLUTTER_PARAM_ANIMATABLE);
iface->find_property = clutter_scroll_actor_find_property;
iface->get_initial_state = clutter_scroll_actor_get_initial_state;
iface->set_final_state = clutter_scroll_actor_set_final_state;
}
/**
* clutter_scroll_actor_new:
*
* Creates a new #ClutterScrollActor.
*
* Return value: (transfer full): The newly created #ClutterScrollActor
* instance.
*
* Since: 1.12
*/
ClutterActor *
clutter_scroll_actor_new (void)
{
return g_object_new (CLUTTER_TYPE_SCROLL_ACTOR, NULL);
}
/**
* clutter_scroll_actor_set_scroll_mode:
* @actor: a #ClutterScrollActor
* @mode: a #ClutterScrollMode
*
* Sets the #ClutterScrollActor:scroll-mode property.
*
* Since: 1.12
*/
void
clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor,
ClutterScrollMode mode)
{
ClutterScrollActorPrivate *priv;
g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
priv = actor->priv;
if (priv->scroll_mode == mode)
return;
priv->scroll_mode = mode;
g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_SCROLL_MODE]);
}
/**
* clutter_scroll_actor_get_scroll_mode:
* @actor: a #ClutterScrollActor
*
* Retrieves the #ClutterScrollActor:scroll-mode property
*
* Return value: the scrolling mode
*
* Since: 1.12
*/
ClutterScrollMode
clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor)
{
g_return_val_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor), CLUTTER_SCROLL_NONE);
return actor->priv->scroll_mode;
}
static void
on_transition_completed (ClutterTimeline *timeline,
ClutterScrollActor *actor)
{
actor->priv->transition = NULL;
}
/**
* clutter_scroll_actor_scroll_to_point:
* @actor: a #ClutterScrollActor
* @point: a #ClutterPoint
*
* Scrolls the contents of @actor so that @point is the new origin
* of the visible area.
*
* This function will use the currently set easing state of the @actor
* to transition from the current scroll origin to the new one.
*
* Since: 1.12
*/
void
clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor,
const ClutterPoint *point)
{
ClutterScrollActorPrivate *priv;
const ClutterAnimationInfo *info;
g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
g_return_if_fail (point != NULL);
priv = actor->priv;
if (clutter_point_equals (&priv->scroll_to, point))
return;
info = _clutter_actor_get_animation_info (CLUTTER_ACTOR (actor));
/* jump to the end if there is no easing state, or if the easing
* state has a duration of 0 msecs
*/
if (info->cur_state == NULL ||
info->cur_state->easing_duration == 0)
{
/* ensure that we remove any currently running transition */
if (priv->transition != NULL)
{
clutter_actor_remove_transition (CLUTTER_ACTOR (actor),
"scroll-to");
priv->transition = NULL;
}
priv->scroll_to = *point;
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
return;
}
if (priv->transition == NULL)
{
priv->transition = clutter_property_transition_new ("scroll-to");
clutter_transition_set_animatable (priv->transition,
CLUTTER_ANIMATABLE (actor));
clutter_transition_set_remove_on_complete (priv->transition, TRUE);
/* delay only makes sense if the transition has just been created */
clutter_timeline_set_delay (CLUTTER_TIMELINE (priv->transition),
info->cur_state->easing_delay);
/* we need this to clear the priv->transition pointer */
g_signal_connect (priv->transition, "completed",
G_CALLBACK (on_transition_completed),
actor);
clutter_actor_add_transition (CLUTTER_ACTOR (actor),
"scroll-to",
priv->transition);
/* the actor now owns the transition */
g_object_unref (priv->transition);
}
/* if a transition already exist, update its bounds */
clutter_transition_set_from (priv->transition,
CLUTTER_TYPE_POINT,
&priv->scroll_to);
clutter_transition_set_to (priv->transition,
CLUTTER_TYPE_POINT,
point);
/* always use the current easing state */
clutter_timeline_set_duration (CLUTTER_TIMELINE (priv->transition),
info->cur_state->easing_duration);
clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (priv->transition),
info->cur_state->easing_mode);
/* ensure that we start from the beginning */
clutter_timeline_rewind (CLUTTER_TIMELINE (priv->transition));
clutter_timeline_start (CLUTTER_TIMELINE (priv->transition));
}
/**
* clutter_scroll_actor_scroll_to_rect:
* @actor: a #ClutterScrollActor
* @rect: a #ClutterRect
*
* Scrolls @actor so that @rect is in the visible portion.
*
* Since: 1.12
*/
void
clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor,
const ClutterRect *rect)
{
ClutterRect n_rect;
g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
g_return_if_fail (rect != NULL);
n_rect = *rect;
/* normalize, so that we have a valid origin */
clutter_rect_normalize (&n_rect);
clutter_scroll_actor_scroll_to_point (actor, &n_rect.origin);
}

View File

@ -0,0 +1,97 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2012 Intel Corporation
*
* 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.
*
* This library is distributed in the hope that 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_SCROLL_ACTOR_H__
#define __CLUTTER_SCROLL_ACTOR_H__
#include <clutter/clutter-types.h>
#include <clutter/clutter-actor.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_SCROLL_ACTOR (clutter_scroll_actor_get_type ())
#define CLUTTER_SCROLL_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActor))
#define CLUTTER_IS_SCROLL_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCROLL_ACTOR))
#define CLUTTER_SCROLL_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActorClass))
#define CLUTTER_IS_SCROLL_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SCROLL_ACTOR))
#define CLUTTER_SCROLL_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActorClass))
typedef struct _ClutterScrollActorPrivate ClutterScrollActorPrivate;
typedef struct _ClutterScrollActorClass ClutterScrollActorClass;
/**
* ClutterScrollActor:
*
* The <structname>ClutterScrollActor</structname> structure contains only
* private data, and should be accessed using the provided API.
*
* Since: 1.12
*/
struct _ClutterScrollActor
{
/*< private >*/
ClutterActor parent_instance;
ClutterScrollActorPrivate *priv;
};
/**
* ClutterScrollActorClass:
*
* The <structname>ClutterScrollActor</structname> structure contains only
* private data.
*
* Since: 1.12
*/
struct _ClutterScrollActorClass
{
/*< private >*/
ClutterActorClass parent_instance;
gpointer _padding[8];
};
CLUTTER_AVAILABLE_IN_1_12
GType clutter_scroll_actor_get_type (void) G_GNUC_CONST;
CLUTTER_AVAILABLE_IN_1_12
ClutterActor * clutter_scroll_actor_new (void);
CLUTTER_AVAILABLE_IN_1_12
void clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor,
ClutterScrollMode mode);
CLUTTER_AVAILABLE_IN_1_12
ClutterScrollMode clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor);
CLUTTER_AVAILABLE_IN_1_12
void clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor,
const ClutterPoint *point);
CLUTTER_AVAILABLE_IN_1_12
void clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor,
const ClutterRect *rect);
G_END_DECLS
#endif /* __CLUTTER_SCROLL_ACTOR_H__ */

View File

@ -58,6 +58,7 @@ typedef struct _ClutterLayoutManager ClutterLayoutManager;
typedef struct _ClutterActorIter ClutterActorIter;
typedef struct _ClutterPaintNode ClutterPaintNode;
typedef struct _ClutterContent ClutterContent; /* dummy */
typedef struct _ClutterScrollActor ClutterScrollActor;
typedef struct _ClutterInterval ClutterInterval;
typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */

View File

@ -88,6 +88,7 @@
#include "clutter-property-transition.h"
#include "clutter-scriptable.h"
#include "clutter-script.h"
#include "clutter-scroll-actor.h"
#include "clutter-settings.h"
#include "clutter-shader-effect.h"
#include "clutter-shader-types.h"

View File

@ -1085,7 +1085,14 @@ clutter_script_lookup_filename
clutter_script_new
clutter_script_set_translation_domain
clutter_script_unmerge_objects
clutter_scroll_actor_get_scroll_mode
clutter_scroll_actor_get_type
clutter_scroll_actor_new
clutter_scroll_actor_scroll_to_point
clutter_scroll_actor_scroll_to_rect
clutter_scroll_actor_set_scroll_mode
clutter_scroll_direction_get_type
clutter_scroll_mode_get_type
clutter_settings_get_default
clutter_settings_get_type
clutter_set_default_frame_rate

View File

@ -58,7 +58,8 @@ UNIT_TESTS = \
test-transitions.c \
test-content.c \
test-canvas.c \
test-keyframe-transition.c
test-keyframe-transition.c \
test-scroll-actor.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c

View File

@ -0,0 +1,179 @@
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static const char *menu_items_name[] = {
"Option 1",
"Option 2",
"Option 3",
"Option 4",
"Option 5",
"Option 6",
"Option 7",
"Option 8",
"Option 9",
"Option 10",
"Option 11",
};
static const guint menu_items_len = G_N_ELEMENTS (menu_items_name);
static void
select_item_at_index (ClutterActor *scroll,
int index_)
{
ClutterPoint point;
ClutterActor *menu, *item;
gpointer old_selected;
menu = clutter_actor_get_first_child (scroll);
old_selected = g_object_get_data (G_OBJECT (scroll), "selected-item");
if (old_selected != NULL)
{
item = clutter_actor_get_child_at_index (menu, GPOINTER_TO_INT (old_selected));
clutter_text_set_color (CLUTTER_TEXT (item), CLUTTER_COLOR_White);
}
if (index_ < 0)
index_ = clutter_actor_get_n_children (menu) - 1;
else if (index_ >= clutter_actor_get_n_children (menu))
index_ = 0;
item = clutter_actor_get_child_at_index (menu, index_);
clutter_actor_get_position (item, &point.x, &point.y);
clutter_actor_save_easing_state (scroll);
clutter_scroll_actor_scroll_to_point (CLUTTER_SCROLL_ACTOR (scroll), &point);
clutter_actor_restore_easing_state (scroll);
clutter_text_set_color (CLUTTER_TEXT (item), CLUTTER_COLOR_LightSkyBlue);
g_object_set_data (G_OBJECT (scroll), "selected-item",
GINT_TO_POINTER (index_));
}
static void
select_next_item (ClutterActor *scroll)
{
gpointer selected_ = g_object_get_data (G_OBJECT (scroll), "selected-item");
select_item_at_index (scroll, GPOINTER_TO_INT (selected_) + 1);
}
static void
select_prev_item (ClutterActor *scroll)
{
gpointer selected_ = g_object_get_data (G_OBJECT (scroll), "selected-item");
select_item_at_index (scroll, GPOINTER_TO_INT (selected_) - 1);
}
static ClutterActor *
create_menu_item (const char *name)
{
ClutterActor *text;
text = clutter_text_new ();
clutter_text_set_font_name (CLUTTER_TEXT (text), "Sans Bold 24");
clutter_text_set_text (CLUTTER_TEXT (text), name);
clutter_text_set_color (CLUTTER_TEXT (text), CLUTTER_COLOR_White);
clutter_actor_set_margin_left (text, 12.f);
clutter_actor_set_margin_right (text, 12.f);
return text;
}
static ClutterActor *
create_menu_actor (ClutterActor *scroll)
{
ClutterActor *menu;
ClutterLayoutManager *layout_manager;
guint i;
layout_manager = clutter_box_layout_new ();
clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout_manager),
CLUTTER_ORIENTATION_VERTICAL);
clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout_manager), 12.f);
menu = clutter_actor_new ();
clutter_actor_set_layout_manager (menu, layout_manager);
clutter_actor_set_background_color (menu, CLUTTER_COLOR_Black);
for (i = 0; i < menu_items_len; i++)
clutter_actor_add_child (menu, create_menu_item (menu_items_name[i]));
return menu;
}
static ClutterActor *
create_scroll_actor (ClutterActor *stage)
{
ClutterActor *scroll;
scroll = clutter_scroll_actor_new ();
clutter_actor_set_name (scroll, "scroll");
clutter_actor_set_position (scroll, 0.f, 18.f);
clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
clutter_actor_add_constraint (scroll, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -36.f));
clutter_scroll_actor_set_scroll_mode (CLUTTER_SCROLL_ACTOR (scroll),
CLUTTER_SCROLL_VERTICALLY);
clutter_actor_add_child (scroll, create_menu_actor (scroll));
select_item_at_index (scroll, 0);
return scroll;
}
static gboolean
on_key_press (ClutterActor *stage,
ClutterEvent *event,
gpointer unused)
{
ClutterActor *scroll;
guint key_symbol;
scroll = clutter_actor_get_first_child (stage);
key_symbol = clutter_event_get_key_symbol (event);
if (key_symbol == CLUTTER_KEY_Up)
select_prev_item (scroll);
else if (key_symbol == CLUTTER_KEY_Down)
select_next_item (scroll);
return CLUTTER_EVENT_STOP;
}
G_MODULE_EXPORT const char *
test_scroll_actor_describe (void)
{
return "Scrolling actor example.";
}
G_MODULE_EXPORT int
test_scroll_actor_main (int argc, char *argv[])
{
ClutterActor *stage;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Scroll Actor");
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), NULL);
clutter_actor_add_child (stage, create_scroll_actor (stage));
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}