2010-05-26 14:58:15 +00:00
|
|
|
#include <stdlib.h>
|
2010-05-27 11:32:45 +00:00
|
|
|
#include <math.h>
|
2010-05-26 14:58:15 +00:00
|
|
|
#include <gmodule.h>
|
|
|
|
#include <clutter/clutter.h>
|
|
|
|
|
2010-05-27 11:32:45 +00:00
|
|
|
#define RECT_WIDTH 400
|
|
|
|
#define RECT_HEIGHT 300
|
2010-05-26 14:58:15 +00:00
|
|
|
#define N_RECTS 7
|
|
|
|
|
|
|
|
static const gchar *rect_color[N_RECTS] = {
|
|
|
|
"#edd400",
|
|
|
|
"#f57900",
|
|
|
|
"#c17d11",
|
|
|
|
"#73d216",
|
|
|
|
"#3465a4",
|
|
|
|
"#75507b",
|
|
|
|
"#cc0000"
|
|
|
|
};
|
|
|
|
|
|
|
|
static ClutterActor *rectangle[N_RECTS];
|
|
|
|
static ClutterActor *viewport = NULL;
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_drag_end (ClutterDragAction *action,
|
|
|
|
ClutterActor *actor,
|
|
|
|
gfloat event_x,
|
|
|
|
gfloat event_y,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
gfloat viewport_x = clutter_actor_get_x (viewport);
|
2010-05-27 11:32:45 +00:00
|
|
|
gfloat offset_x;
|
|
|
|
gint child_visible;
|
2010-05-26 14:58:15 +00:00
|
|
|
|
2010-05-27 11:32:45 +00:00
|
|
|
/* check if we're at the viewport edges */
|
2010-05-26 14:58:15 +00:00
|
|
|
if (viewport_x > 0)
|
|
|
|
{
|
2012-03-21 12:57:26 +00:00
|
|
|
clutter_actor_save_easing_state (viewport);
|
|
|
|
clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE);
|
|
|
|
clutter_actor_set_x (viewport, 0);
|
|
|
|
clutter_actor_restore_easing_state (viewport);
|
2010-05-26 14:58:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (viewport_x < (-1.0f * (RECT_WIDTH * (N_RECTS - 1))))
|
|
|
|
{
|
2012-03-21 12:57:26 +00:00
|
|
|
clutter_actor_save_easing_state (viewport);
|
|
|
|
clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE);
|
|
|
|
clutter_actor_set_x (viewport, -1.0f * (RECT_WIDTH * (N_RECTS - 1)));
|
|
|
|
clutter_actor_restore_easing_state (viewport);
|
2010-05-26 14:58:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-05-27 11:32:45 +00:00
|
|
|
|
|
|
|
/* animate the viewport to fully show the child once we pass
|
|
|
|
* a certain threshold with the dragging action
|
|
|
|
*/
|
|
|
|
offset_x = fabsf (viewport_x) / RECT_WIDTH + 0.5f;
|
|
|
|
if (offset_x > (RECT_WIDTH * 0.33))
|
|
|
|
child_visible = (int) offset_x + 1;
|
|
|
|
else
|
|
|
|
child_visible = (int) offset_x;
|
|
|
|
|
|
|
|
/* sanity check on the children number */
|
|
|
|
child_visible = CLAMP (child_visible, 0, N_RECTS);
|
|
|
|
|
2012-03-21 12:57:26 +00:00
|
|
|
clutter_actor_save_easing_state (viewport);
|
|
|
|
clutter_actor_set_x (viewport, -1.0f * RECT_WIDTH * child_visible);
|
|
|
|
clutter_actor_restore_easing_state (viewport);
|
2010-05-26 14:58:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
G_MODULE_EXPORT int
|
|
|
|
test_scrolling_main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
ClutterActor *stage;
|
|
|
|
ClutterActor *scroll;
|
|
|
|
ClutterAction *action;
|
|
|
|
gint i;
|
|
|
|
|
2011-02-22 00:19:35 +00:00
|
|
|
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
|
|
|
|
return 1;
|
2010-05-26 14:58:15 +00:00
|
|
|
|
|
|
|
stage = clutter_stage_new ();
|
|
|
|
clutter_stage_set_title (CLUTTER_STAGE (stage), "Scrolling");
|
|
|
|
clutter_actor_set_size (stage, 800, 600);
|
|
|
|
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
|
|
|
|
|
|
|
|
/* scroll: the group that contains the scrolling viewport; we set its
|
|
|
|
* size to be the same as one rectangle, position it in the middle of
|
2010-05-26 15:09:47 +00:00
|
|
|
* the stage and set it to clip its contents to the allocated size
|
2010-05-26 14:58:15 +00:00
|
|
|
*/
|
2012-01-17 16:20:41 +00:00
|
|
|
scroll = clutter_actor_new ();
|
|
|
|
clutter_actor_add_child (stage, scroll);
|
2010-05-26 14:58:15 +00:00
|
|
|
clutter_actor_set_size (scroll, RECT_WIDTH, RECT_HEIGHT);
|
2011-10-15 17:35:45 +00:00
|
|
|
clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
|
2010-05-26 15:09:47 +00:00
|
|
|
clutter_actor_set_clip_to_allocation (scroll, TRUE);
|
2010-05-26 14:58:15 +00:00
|
|
|
|
|
|
|
/* viewport: the actual container for the children; we scroll it using
|
|
|
|
* the Drag action constrained to the horizontal axis, and every time
|
|
|
|
* the dragging ends we check whether we're dragging past the end of
|
|
|
|
* the viewport
|
|
|
|
*/
|
2012-01-17 16:20:41 +00:00
|
|
|
viewport = clutter_actor_new ();
|
|
|
|
clutter_actor_set_layout_manager (viewport, clutter_box_layout_new ());
|
|
|
|
clutter_actor_add_child (scroll, viewport);
|
2010-05-26 14:58:15 +00:00
|
|
|
|
2010-05-27 11:32:45 +00:00
|
|
|
/* add dragging capabilities to the viewport; the heavy lifting is
|
|
|
|
* all done by the DragAction itself, plus the ::drag-end signal
|
|
|
|
* handler in our code
|
|
|
|
*/
|
2010-05-26 14:58:15 +00:00
|
|
|
action = clutter_drag_action_new ();
|
2010-05-27 11:32:45 +00:00
|
|
|
clutter_actor_add_action (viewport, action);
|
2010-05-26 14:58:15 +00:00
|
|
|
clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action),
|
|
|
|
CLUTTER_DRAG_X_AXIS);
|
|
|
|
g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);
|
|
|
|
clutter_actor_set_reactive (viewport, TRUE);
|
|
|
|
|
|
|
|
/* children of the viewport */
|
|
|
|
for (i = 0; i < N_RECTS; i++)
|
|
|
|
{
|
|
|
|
ClutterColor color;
|
|
|
|
|
|
|
|
clutter_color_from_string (&color, rect_color[i]);
|
|
|
|
|
2012-01-17 16:20:41 +00:00
|
|
|
rectangle[i] = clutter_actor_new ();
|
|
|
|
clutter_actor_set_background_color (rectangle[i], &color);
|
|
|
|
clutter_actor_add_child (viewport, rectangle[i]);
|
2010-05-26 14:58:15 +00:00
|
|
|
clutter_actor_set_size (rectangle[i], RECT_WIDTH, RECT_HEIGHT);
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_actor_show (stage);
|
|
|
|
|
|
|
|
clutter_main ();
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|