~gnome3-team/mutter/trunk

« back to all changes in this revision

Viewing changes to clutter/clutter/clutter-scroll-actor.c

  • Committer: Rui Matos
  • Date: 2016-04-27 16:34:03 UTC
  • mfrom: (0.1.7560)
  • Revision ID: git-v1:a7b5d790ac66477ad9e3d940527c198332a03695
Merge clutter's master branch into mutter

https://bugzilla.gnome.org/show_bug.cgi?id=760439

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Clutter.
 
3
 *
 
4
 * An OpenGL based 'interactive canvas' library.
 
5
 *
 
6
 * Copyright (C) 2012  Intel Corporation
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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/>.
 
20
 */
 
21
 
 
22
/**
 
23
 * SECTION:clutter-scroll-actor
 
24
 * @Title: ClutterScrollActor
 
25
 * @Short_Description: An actor for displaying a portion of its children
 
26
 *
 
27
 * #ClutterScrollActor is an actor that can be used to display a portion
 
28
 * of the contents of its children.
 
29
 *
 
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.
 
35
 *
 
36
 * #ClutterScrollActor does not provide pointer or keyboard event handling,
 
37
 * nor does it provide visible scroll handles.
 
38
 *
 
39
 * See [scroll-actor.c](https://git.gnome.org/browse/clutter/tree/examples/scroll-actor.c?h=clutter-1.18)
 
40
 * for an example of how to use #ClutterScrollActor.
 
41
 *
 
42
 * #ClutterScrollActor is available since Clutter 1.12.
 
43
 */
 
44
 
 
45
#ifdef HAVE_CONFIG_H
 
46
#include "config.h"
 
47
#endif
 
48
 
 
49
#include "clutter-scroll-actor.h"
 
50
 
 
51
#include "clutter-actor-private.h"
 
52
#include "clutter-animatable.h"
 
53
#include "clutter-debug.h"
 
54
#include "clutter-enum-types.h"
 
55
#include "clutter-private.h"
 
56
#include "clutter-property-transition.h"
 
57
#include "clutter-transition.h"
 
58
 
 
59
struct _ClutterScrollActorPrivate
 
60
{
 
61
  ClutterPoint scroll_to;
 
62
 
 
63
  ClutterScrollMode scroll_mode;
 
64
 
 
65
  ClutterTransition *transition;
 
66
};
 
67
 
 
68
enum
 
69
{
 
70
  PROP_0,
 
71
 
 
72
  PROP_SCROLL_MODE,
 
73
 
 
74
  PROP_LAST
 
75
};
 
76
 
 
77
enum
 
78
{
 
79
  ANIM_PROP_0,
 
80
 
 
81
  ANIM_PROP_SCROLL_TO,
 
82
 
 
83
  ANIM_PROP_LAST
 
84
};
 
85
 
 
86
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
 
87
static GParamSpec *animatable_props[ANIM_PROP_LAST] = { NULL, };
 
88
 
 
89
static ClutterAnimatableIface *parent_animatable_iface = NULL;
 
90
 
 
91
static void     clutter_animatable_iface_init   (ClutterAnimatableIface *iface);
 
92
 
 
93
G_DEFINE_TYPE_WITH_CODE (ClutterScrollActor, clutter_scroll_actor, CLUTTER_TYPE_ACTOR,
 
94
                         G_ADD_PRIVATE (ClutterScrollActor)
 
95
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
 
96
                                                clutter_animatable_iface_init))
 
97
 
 
98
static void
 
99
clutter_scroll_actor_set_scroll_to_internal (ClutterScrollActor *self,
 
100
                                             const ClutterPoint *point)
 
101
{
 
102
  ClutterScrollActorPrivate *priv = self->priv;
 
103
  ClutterActor *actor = CLUTTER_ACTOR (self);
 
104
  ClutterMatrix m = CLUTTER_MATRIX_INIT_IDENTITY;
 
105
  float dx, dy;
 
106
 
 
107
  if (clutter_point_equals (&priv->scroll_to, point))
 
108
    return;
 
109
 
 
110
  if (point == NULL)
 
111
    clutter_point_init (&priv->scroll_to, 0.f, 0.f);
 
112
  else
 
113
    priv->scroll_to = *point;
 
114
 
 
115
  if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY)
 
116
    dx = -priv->scroll_to.x;
 
117
  else
 
118
    dx = 0.f;
 
119
 
 
120
  if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY)
 
121
    dy = -priv->scroll_to.y;
 
122
  else
 
123
    dy = 0.f;
 
124
 
 
125
  cogl_matrix_translate (&m, dx, dy, 0.f);
 
126
  clutter_actor_set_child_transform (actor, &m);
 
127
}
 
128
 
 
129
static void
 
130
clutter_scroll_actor_set_property (GObject      *gobject,
 
131
                                   guint         prop_id,
 
132
                                   const GValue *value,
 
133
                                   GParamSpec   *pspec)
 
134
{
 
135
  ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
 
136
 
 
137
  switch (prop_id)
 
138
    {
 
139
    case PROP_SCROLL_MODE:
 
140
      clutter_scroll_actor_set_scroll_mode (actor, g_value_get_flags (value));
 
141
      break;
 
142
 
 
143
    default:
 
144
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
145
    }
 
146
}
 
147
 
 
148
static void
 
149
clutter_scroll_actor_get_property (GObject    *gobject,
 
150
                                   guint       prop_id,
 
151
                                   GValue     *value,
 
152
                                   GParamSpec *pspec)
 
153
{
 
154
  ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject);
 
155
 
 
156
  switch (prop_id)
 
157
    {
 
158
    case PROP_SCROLL_MODE:
 
159
      g_value_set_flags (value, actor->priv->scroll_mode);
 
160
      break;
 
161
 
 
162
    default:
 
163
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
164
    }
 
165
}
 
166
 
 
167
static void
 
168
clutter_scroll_actor_class_init (ClutterScrollActorClass *klass)
 
169
{
 
170
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
171
 
 
172
  gobject_class->set_property = clutter_scroll_actor_set_property;
 
173
  gobject_class->get_property = clutter_scroll_actor_get_property;
 
174
 
 
175
  /**
 
176
   * ClutterScrollActor:scroll-mode:
 
177
   *
 
178
   * The scrollin direction.
 
179
   *
 
180
   * Since: 1.12
 
181
   */
 
182
  obj_props[PROP_SCROLL_MODE] =
 
183
    g_param_spec_flags ("scroll-mode",
 
184
                        P_("Scroll Mode"),
 
185
                        P_("The scrolling direction"),
 
186
                        CLUTTER_TYPE_SCROLL_MODE,
 
187
                        CLUTTER_SCROLL_BOTH,
 
188
                        G_PARAM_READWRITE |
 
189
                        G_PARAM_STATIC_STRINGS);
 
190
 
 
191
  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
 
192
}
 
193
 
 
194
static void
 
195
clutter_scroll_actor_init (ClutterScrollActor *self)
 
196
{
 
197
  self->priv = clutter_scroll_actor_get_instance_private (self);
 
198
  self->priv->scroll_mode = CLUTTER_SCROLL_BOTH;
 
199
 
 
200
  clutter_actor_set_clip_to_allocation (CLUTTER_ACTOR (self), TRUE);
 
201
}
 
202
 
 
203
static GParamSpec *
 
204
clutter_scroll_actor_find_property (ClutterAnimatable *animatable,
 
205
                                    const char        *property_name)
 
206
{
 
207
  if (strcmp (property_name, "scroll-to") == 0)
 
208
    return animatable_props[ANIM_PROP_SCROLL_TO];
 
209
 
 
210
  return parent_animatable_iface->find_property (animatable, property_name);
 
211
}
 
212
 
 
213
static void
 
214
clutter_scroll_actor_set_final_state (ClutterAnimatable *animatable,
 
215
                                      const char        *property_name,
 
216
                                      const GValue      *value)
 
217
{
 
218
  if (strcmp (property_name, "scroll-to") == 0)
 
219
    {
 
220
      ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
 
221
      const ClutterPoint *point = g_value_get_boxed (value);
 
222
 
 
223
      clutter_scroll_actor_set_scroll_to_internal (self, point);
 
224
    }
 
225
  else
 
226
    parent_animatable_iface->set_final_state (animatable, property_name, value);
 
227
}
 
228
 
 
229
static void
 
230
clutter_scroll_actor_get_initial_state (ClutterAnimatable *animatable,
 
231
                                        const char        *property_name,
 
232
                                        GValue            *value)
 
233
{
 
234
  if (strcmp (property_name, "scroll-to") == 0)
 
235
    {
 
236
      ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable);
 
237
 
 
238
      g_value_set_boxed (value, &self->priv->scroll_to);
 
239
    }
 
240
  else
 
241
    parent_animatable_iface->get_initial_state (animatable, property_name, value);
 
242
}
 
243
 
 
244
static void
 
245
clutter_animatable_iface_init (ClutterAnimatableIface *iface)
 
246
{
 
247
  parent_animatable_iface = g_type_interface_peek_parent (iface);
 
248
 
 
249
  animatable_props[ANIM_PROP_SCROLL_TO] =
 
250
    g_param_spec_boxed ("scroll-to",
 
251
                        "Scroll To",
 
252
                        "The point to scroll the actor to",
 
253
                        CLUTTER_TYPE_POINT,
 
254
                        G_PARAM_READWRITE |
 
255
                        G_PARAM_STATIC_STRINGS |
 
256
                        CLUTTER_PARAM_ANIMATABLE);
 
257
 
 
258
  iface->find_property = clutter_scroll_actor_find_property;
 
259
  iface->get_initial_state = clutter_scroll_actor_get_initial_state;
 
260
  iface->set_final_state = clutter_scroll_actor_set_final_state;
 
261
}
 
262
 
 
263
/**
 
264
 * clutter_scroll_actor_new:
 
265
 *
 
266
 * Creates a new #ClutterScrollActor.
 
267
 *
 
268
 * Return value: The newly created #ClutterScrollActor
 
269
 *   instance.
 
270
 *
 
271
 * Since: 1.12
 
272
 */
 
273
ClutterActor *
 
274
clutter_scroll_actor_new (void)
 
275
{
 
276
  return g_object_new (CLUTTER_TYPE_SCROLL_ACTOR, NULL);
 
277
}
 
278
 
 
279
/**
 
280
 * clutter_scroll_actor_set_scroll_mode:
 
281
 * @actor: a #ClutterScrollActor
 
282
 * @mode: a #ClutterScrollMode
 
283
 *
 
284
 * Sets the #ClutterScrollActor:scroll-mode property.
 
285
 *
 
286
 * Since: 1.12
 
287
 */
 
288
void
 
289
clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor,
 
290
                                      ClutterScrollMode   mode)
 
291
{
 
292
  ClutterScrollActorPrivate *priv;
 
293
 
 
294
  g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
 
295
 
 
296
  priv = actor->priv;
 
297
 
 
298
  if (priv->scroll_mode == mode)
 
299
    return;
 
300
 
 
301
  priv->scroll_mode = mode;
 
302
 
 
303
  g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_SCROLL_MODE]);
 
304
}
 
305
 
 
306
/**
 
307
 * clutter_scroll_actor_get_scroll_mode:
 
308
 * @actor: a #ClutterScrollActor
 
309
 *
 
310
 * Retrieves the #ClutterScrollActor:scroll-mode property
 
311
 *
 
312
 * Return value: the scrolling mode
 
313
 *
 
314
 * Since: 1.12
 
315
 */
 
316
ClutterScrollMode
 
317
clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor)
 
318
{
 
319
  g_return_val_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor), CLUTTER_SCROLL_NONE);
 
320
 
 
321
  return actor->priv->scroll_mode;
 
322
}
 
323
 
 
324
/**
 
325
 * clutter_scroll_actor_scroll_to_point:
 
326
 * @actor: a #ClutterScrollActor
 
327
 * @point: a #ClutterPoint
 
328
 *
 
329
 * Scrolls the contents of @actor so that @point is the new origin
 
330
 * of the visible area.
 
331
 *
 
332
 * The coordinates of @point must be relative to the @actor.
 
333
 *
 
334
 * This function will use the currently set easing state of the @actor
 
335
 * to transition from the current scroll origin to the new one.
 
336
 *
 
337
 * Since: 1.12
 
338
 */
 
339
void
 
340
clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor,
 
341
                                      const ClutterPoint *point)
 
342
{
 
343
  ClutterScrollActorPrivate *priv;
 
344
  const ClutterAnimationInfo *info;
 
345
 
 
346
  g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
 
347
  g_return_if_fail (point != NULL);
 
348
 
 
349
  priv = actor->priv;
 
350
 
 
351
  info = _clutter_actor_get_animation_info (CLUTTER_ACTOR (actor));
 
352
 
 
353
  /* jump to the end if there is no easing state, or if the easing
 
354
   * state has a duration of 0 msecs
 
355
   */
 
356
  if (info->cur_state == NULL ||
 
357
      info->cur_state->easing_duration == 0)
 
358
    {
 
359
      /* ensure that we remove any currently running transition */
 
360
      if (priv->transition != NULL)
 
361
        {
 
362
          clutter_actor_remove_transition (CLUTTER_ACTOR (actor),
 
363
                                           "scroll-to");
 
364
          priv->transition = NULL;
 
365
        }
 
366
 
 
367
      clutter_scroll_actor_set_scroll_to_internal (actor, point);
 
368
 
 
369
      return;
 
370
    }
 
371
 
 
372
  if (priv->transition == NULL)
 
373
    {
 
374
      priv->transition = clutter_property_transition_new ("scroll-to");
 
375
      clutter_transition_set_animatable (priv->transition,
 
376
                                         CLUTTER_ANIMATABLE (actor));
 
377
      clutter_transition_set_remove_on_complete (priv->transition, TRUE);
 
378
 
 
379
      /* delay only makes sense if the transition has just been created */
 
380
      clutter_timeline_set_delay (CLUTTER_TIMELINE (priv->transition),
 
381
                                  info->cur_state->easing_delay);
 
382
      /* we need this to clear the priv->transition pointer */
 
383
      g_object_add_weak_pointer (G_OBJECT (priv->transition), (gpointer *) &priv->transition);
 
384
 
 
385
      clutter_actor_add_transition (CLUTTER_ACTOR (actor),
 
386
                                    "scroll-to",
 
387
                                    priv->transition);
 
388
 
 
389
      /* the actor now owns the transition */
 
390
      g_object_unref (priv->transition);
 
391
    }
 
392
 
 
393
  /* if a transition already exist, update its bounds */
 
394
  clutter_transition_set_from (priv->transition,
 
395
                               CLUTTER_TYPE_POINT,
 
396
                               &priv->scroll_to);
 
397
  clutter_transition_set_to (priv->transition,
 
398
                             CLUTTER_TYPE_POINT,
 
399
                             point);
 
400
 
 
401
  /* always use the current easing state */
 
402
  clutter_timeline_set_duration (CLUTTER_TIMELINE (priv->transition),
 
403
                                 info->cur_state->easing_duration);
 
404
  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (priv->transition),
 
405
                                      info->cur_state->easing_mode);
 
406
 
 
407
  /* ensure that we start from the beginning */
 
408
  clutter_timeline_rewind (CLUTTER_TIMELINE (priv->transition));
 
409
  clutter_timeline_start (CLUTTER_TIMELINE (priv->transition));
 
410
}
 
411
 
 
412
/**
 
413
 * clutter_scroll_actor_scroll_to_rect:
 
414
 * @actor: a #ClutterScrollActor
 
415
 * @rect: a #ClutterRect
 
416
 *
 
417
 * Scrolls @actor so that @rect is in the visible portion.
 
418
 *
 
419
 * Since: 1.12
 
420
 */
 
421
void
 
422
clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor,
 
423
                                     const ClutterRect  *rect)
 
424
{
 
425
  ClutterRect n_rect;
 
426
 
 
427
  g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor));
 
428
  g_return_if_fail (rect != NULL);
 
429
 
 
430
  n_rect = *rect;
 
431
 
 
432
  /* normalize, so that we have a valid origin */
 
433
  clutter_rect_normalize (&n_rect);
 
434
 
 
435
  clutter_scroll_actor_scroll_to_point (actor, &n_rect.origin);
 
436
}