4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2012 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23 * SECTION:clutter-scroll-actor
24 * @Title: ClutterScrollActor
25 * @Short_Description: An actor for displaying a portion of its children
27 * #ClutterScrollActor is an actor that can be used to display a portion
28 * of the contents of its children.
30 * The extent of the area of a #ClutterScrollActor is defined by the size
31 * of its children; the visible region of the children of a #ClutterScrollActor
32 * is set by using clutter_scroll_actor_scroll_to_point() or by using
33 * clutter_scroll_actor_scroll_to_rect() to define a point or a rectangle
34 * acting as the origin, respectively.
36 * #ClutterScrollActor does not provide pointer or keyboard event handling,
37 * nor does it provide visible scroll handles.
41 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/scroll-actor.c">
42 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
47 * #ClutterScrollActor is available since Clutter 1.12.
54 #include "clutter-scroll-actor.h"
56 #include "clutter-actor-private.h"
57 #include "clutter-animatable.h"
58 #include "clutter-debug.h"
59 #include "clutter-enum-types.h"
60 #include "clutter-private.h"
61 #include "clutter-property-transition.h"
62 #include "clutter-transition.h"
64 struct _ClutterScrollActorPrivate
66 ClutterPoint scroll_to;
68 ClutterScrollMode scroll_mode;
70 ClutterTransition *transition;
91 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
92 static GParamSpec *animatable_props[ANIM_PROP_LAST] = { NULL, };
94 static ClutterAnimatableIface *parent_animatable_iface = NULL;
96 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
98 G_DEFINE_TYPE_WITH_CODE (ClutterScrollActor, clutter_scroll_actor, CLUTTER_TYPE_ACTOR,
99 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
100 clutter_animatable_iface_init))
103 clutter_scroll_actor_apply_transform (ClutterActor *actor,
104 CoglMatrix *transform)
106 ClutterScrollActorPrivate *priv = CLUTTER_SCROLL_ACTOR (actor)->priv;
107 float x_factor, y_factor;
109 CLUTTER_ACTOR_CLASS (clutter_scroll_actor_parent_class)->apply_transform (actor, transform);
111 if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY)
112 x_factor = -priv->scroll_to.x;
116 if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY)
117 y_factor = -priv->scroll_to.y;
121 cogl_matrix_translate (transform, x_factor, y_factor, 0.0f);
125 clutter_scroll_actor_push_clip (ClutterActor *actor)
127 ClutterScrollActorPrivate *priv = CLUTTER_SCROLL_ACTOR (actor)->priv;
128 ClutterActorBox allocation;
132 clutter_actor_get_allocation_box (actor, &allocation);
133 clutter_actor_box_get_size (&allocation, &width, &height);
135 if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY)
136 x = priv->scroll_to.x;
140 if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY)
141 y = priv->scroll_to.y;
145 /* offset the clip so that we keep it at the right place */
146 cogl_clip_push_rectangle (x,
153 clutter_scroll_actor_paint (ClutterActor *actor)
155 clutter_scroll_actor_push_clip (actor);
157 CLUTTER_ACTOR_CLASS (clutter_scroll_actor_parent_class)->paint (actor);
163 clutter_scroll_actor_pick (ClutterActor *actor,
164 const ClutterColor *pick_color)
166 ClutterActorIter iter;
169 clutter_scroll_actor_push_clip (actor);
171 CLUTTER_ACTOR_CLASS (clutter_scroll_actor_parent_class)->pick (actor, pick_color);
173 /* FIXME - this has to go away when we remove the vfunc check inside
174 * the ClutterActor::pick default implementation
176 clutter_actor_iter_init (&iter, actor);
177 while (clutter_actor_iter_next (&iter, &child))
178 clutter_actor_paint (child);
184 clutter_scroll_actor_set_scroll_to_internal (ClutterScrollActor *self,
185 const ClutterPoint *point)
187 ClutterScrollActorPrivate *priv = self->priv;
188 ClutterActor *actor = CLUTTER_ACTOR (self);
190 if (clutter_point_equals (&priv->scroll_to, point))
194 clutter_point_init (&priv->scroll_to, 0.f, 0.f);
196 priv->scroll_to = *point;
198 clutter_actor_queue_redraw (actor);
202 clutter_scroll_actor_set_property (GObject *gobject,
207 ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
211 case PROP_SCROLL_MODE:
212 clutter_scroll_actor_set_scroll_mode (actor, g_value_get_flags (value));
216 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
221 clutter_scroll_actor_get_property (GObject *gobject,
226 ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
230 case PROP_SCROLL_MODE:
231 g_value_set_flags (value, actor->priv->scroll_mode);
235 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
240 clutter_scroll_actor_class_init (ClutterScrollActorClass *klass)
242 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
243 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
245 g_type_class_add_private (klass, sizeof (ClutterScrollActorPrivate));
247 gobject_class->set_property = clutter_scroll_actor_set_property;
248 gobject_class->get_property = clutter_scroll_actor_get_property;
250 actor_class->apply_transform = clutter_scroll_actor_apply_transform;
251 actor_class->paint = clutter_scroll_actor_paint;
252 actor_class->pick = clutter_scroll_actor_pick;
255 * ClutterScrollActor:scroll-mode:
257 * The scrollin direction.
261 obj_props[PROP_SCROLL_MODE] =
262 g_param_spec_flags ("scroll-mode",
264 P_("The scrolling direction"),
265 CLUTTER_TYPE_SCROLL_MODE,
268 G_PARAM_STATIC_STRINGS);
270 g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
274 clutter_scroll_actor_init (ClutterScrollActor *self)
276 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_SCROLL_ACTOR,
277 ClutterScrollActorPrivate);
279 self->priv->scroll_mode = CLUTTER_SCROLL_BOTH;
283 clutter_scroll_actor_find_property (ClutterAnimatable *animatable,
284 const char *property_name)
286 if (strcmp (property_name, "scroll-to") == 0)
287 return animatable_props[ANIM_PROP_SCROLL_TO];
289 return parent_animatable_iface->find_property (animatable, property_name);
293 clutter_scroll_actor_set_final_state (ClutterAnimatable *animatable,
294 const char *property_name,
297 if (strcmp (property_name, "scroll-to") == 0)
299 ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
300 const ClutterPoint *point = g_value_get_boxed (value);
302 clutter_scroll_actor_set_scroll_to_internal (self, point);
305 parent_animatable_iface->set_final_state (animatable, property_name, value);
309 clutter_scroll_actor_get_initial_state (ClutterAnimatable *animatable,
310 const char *property_name,
313 if (strcmp (property_name, "scroll-to") == 0)
315 ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
317 g_value_set_boxed (value, &self->priv->scroll_to);
320 parent_animatable_iface->get_initial_state (animatable, property_name, value);
324 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
326 parent_animatable_iface = g_type_interface_peek_parent (iface);
328 animatable_props[ANIM_PROP_SCROLL_TO] =
329 g_param_spec_boxed ("scroll-to",
331 "The point to scroll the actor to",
334 G_PARAM_STATIC_STRINGS |
335 CLUTTER_PARAM_ANIMATABLE);
337 iface->find_property = clutter_scroll_actor_find_property;
338 iface->get_initial_state = clutter_scroll_actor_get_initial_state;
339 iface->set_final_state = clutter_scroll_actor_set_final_state;
343 * clutter_scroll_actor_new:
345 * Creates a new #ClutterScrollActor.
347 * Return value: (transfer full): The newly created #ClutterScrollActor
353 clutter_scroll_actor_new (void)
355 return g_object_new (CLUTTER_TYPE_SCROLL_ACTOR, NULL);
359 * clutter_scroll_actor_set_scroll_mode:
360 * @actor: a #ClutterScrollActor
361 * @mode: a #ClutterScrollMode
363 * Sets the #ClutterScrollActor:scroll-mode property.
368 clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor,
369 ClutterScrollMode mode)
371 ClutterScrollActorPrivate *priv;
373 g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
377 if (priv->scroll_mode == mode)
380 priv->scroll_mode = mode;
382 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_SCROLL_MODE]);
386 * clutter_scroll_actor_get_scroll_mode:
387 * @actor: a #ClutterScrollActor
389 * Retrieves the #ClutterScrollActor:scroll-mode property
391 * Return value: the scrolling mode
396 clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor)
398 g_return_val_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor), CLUTTER_SCROLL_NONE);
400 return actor->priv->scroll_mode;
404 * clutter_scroll_actor_scroll_to_point:
405 * @actor: a #ClutterScrollActor
406 * @point: a #ClutterPoint
408 * Scrolls the contents of @actor so that @point is the new origin
409 * of the visible area.
411 * The coordinates of @point must be relative to the @actor.
413 * This function will use the currently set easing state of the @actor
414 * to transition from the current scroll origin to the new one.
419 clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor,
420 const ClutterPoint *point)
422 ClutterScrollActorPrivate *priv;
423 const ClutterAnimationInfo *info;
425 g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
426 g_return_if_fail (point != NULL);
430 info = _clutter_actor_get_animation_info (CLUTTER_ACTOR (actor));
432 /* jump to the end if there is no easing state, or if the easing
433 * state has a duration of 0 msecs
435 if (info->cur_state == NULL ||
436 info->cur_state->easing_duration == 0)
438 /* ensure that we remove any currently running transition */
439 if (priv->transition != NULL)
441 clutter_actor_remove_transition (CLUTTER_ACTOR (actor),
443 priv->transition = NULL;
446 clutter_scroll_actor_set_scroll_to_internal (actor, point);
451 if (priv->transition == NULL)
453 priv->transition = clutter_property_transition_new ("scroll-to");
454 clutter_transition_set_animatable (priv->transition,
455 CLUTTER_ANIMATABLE (actor));
456 clutter_transition_set_remove_on_complete (priv->transition, TRUE);
458 /* delay only makes sense if the transition has just been created */
459 clutter_timeline_set_delay (CLUTTER_TIMELINE (priv->transition),
460 info->cur_state->easing_delay);
461 /* we need this to clear the priv->transition pointer */
462 g_object_add_weak_pointer (G_OBJECT (priv->transition), (gpointer *) &priv->transition);
464 clutter_actor_add_transition (CLUTTER_ACTOR (actor),
468 /* the actor now owns the transition */
469 g_object_unref (priv->transition);
472 /* if a transition already exist, update its bounds */
473 clutter_transition_set_from (priv->transition,
476 clutter_transition_set_to (priv->transition,
480 /* always use the current easing state */
481 clutter_timeline_set_duration (CLUTTER_TIMELINE (priv->transition),
482 info->cur_state->easing_duration);
483 clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (priv->transition),
484 info->cur_state->easing_mode);
486 /* ensure that we start from the beginning */
487 clutter_timeline_rewind (CLUTTER_TIMELINE (priv->transition));
488 clutter_timeline_start (CLUTTER_TIMELINE (priv->transition));
492 * clutter_scroll_actor_scroll_to_rect:
493 * @actor: a #ClutterScrollActor
494 * @rect: a #ClutterRect
496 * Scrolls @actor so that @rect is in the visible portion.
501 clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor,
502 const ClutterRect *rect)
506 g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
507 g_return_if_fail (rect != NULL);
511 /* normalize, so that we have a valid origin */
512 clutter_rect_normalize (&n_rect);
514 clutter_scroll_actor_scroll_to_point (actor, &n_rect.origin);