~unity-team/nux/nux.armel-fixes

« back to all changes in this revision

Viewing changes to Nux/KineticScrolling/KineticAxisScroller.cpp

  • Committer: Tarmac
  • Author(s): Daniel d'Andrada
  • Date: 2012-10-04 15:58:52 UTC
  • mfrom: (682.1.10 flickable)
  • Revision ID: tarmac-20121004155852-h5qlr2bc4szpr8jz
New: KineticScrollView

+ InputArea::SetTrackChildMouseEvents() and EVENT_MOUSE_CANCEL. Fixes: . Approved by Jay Taoko, Eleni Maria Stea, Nick Dedekind, Michi Henning.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 - Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License, as
 
6
 * published by the  Free Software Foundation; either version 2.1 or 3.0
 
7
 * of the License.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
11
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
 
12
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 
13
 * License for more details.
 
14
 *
 
15
 * You should have received a copy of both the GNU Lesser General Public
 
16
 * License along with this program. If not, see <http://www.gnu.org/licenses/>
 
17
 *
 
18
 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
 
19
 */
 
20
 
 
21
#include <Nux/Nux.h>
 
22
#include "KineticAxisScroller.h"
 
23
#include "AxisDecelerationAnimation.h"
 
24
#include "VelocityCalculator.h"
 
25
#include <memory>
 
26
#include "KineticScrollingTickSource.h"
 
27
 
 
28
using namespace nux;
 
29
 
 
30
/*****************************************************************************
 
31
 * Private class
 
32
 *****************************************************************************/
 
33
 
 
34
class KineticAxisScroller::Private : public sigc::trackable
 
35
{
 
36
 public:
 
37
 
 
38
  Private();
 
39
 
 
40
  void CalculateContentPosLimits();
 
41
 
 
42
  void ProcessFingerDown();
 
43
 
 
44
  void ProcessFingerUp();
 
45
 
 
46
  void ProcessFingerDrag(int mov);
 
47
  void ProcessFingerDrag_Pressed(int mov);
 
48
  void ProcessFingerDrag_FollowingFinger(int mov);
 
49
 
 
50
  void UpdateAnimations(int time);
 
51
 
 
52
  int LimitOutOfBoundsMovement(int movement, int position,
 
53
                               int min_position) const;
 
54
 
 
55
  float viewport_length_;
 
56
  float content_length_;
 
57
  float content_pos_;
 
58
  float min_content_pos_;
 
59
 
 
60
  BoundsBehavior bounds_behavior_;
 
61
 
 
62
  KineticScrollerAxisState state_;
 
63
 
 
64
  VelocityCalculator velocity_calculator_;
 
65
  AxisDecelerationAnimation deceleration_animation_;
 
66
  int accumulated_movement_;
 
67
};
 
68
 
 
69
KineticAxisScroller::Private::Private()
 
70
{
 
71
  viewport_length_ = 0.0f;
 
72
  content_length_ = 0.0f;
 
73
  content_pos_ = 0.0f;
 
74
  min_content_pos_ = 0.0f;
 
75
  bounds_behavior_ = DragAndOvershootBounds;
 
76
  state_ = KineticScrollerAxisStateIdle;
 
77
}
 
78
 
 
79
void KineticAxisScroller::Private::CalculateContentPosLimits()
 
80
{
 
81
  if (content_length_ > viewport_length_)
 
82
    min_content_pos_ = -(content_length_ - viewport_length_);
 
83
  else
 
84
    min_content_pos_ = 0.0f;
 
85
}
 
86
 
 
87
void KineticAxisScroller::Private::ProcessFingerDown()
 
88
{
 
89
  switch (state_)
 
90
  {
 
91
    case KineticScrollerAxisStateIdle:
 
92
      state_ = KineticScrollerAxisStatePressed;
 
93
      accumulated_movement_ = 0;
 
94
      break;
 
95
    case KineticScrollerAxisStateMovingByInertia:
 
96
      state_ = KineticScrollerAxisStatePressed;
 
97
      accumulated_movement_ = 0;
 
98
      break;
 
99
    default:
 
100
      /* Ignore it */
 
101
      break;
 
102
  }
 
103
}
 
104
 
 
105
void KineticAxisScroller::Private::ProcessFingerUp()
 
106
{
 
107
  // consider the elapsed time between the last drag update and now, that the
 
108
  // finger has been lifted (it could have been still for a while).
 
109
  velocity_calculator_.ProcessMovement(0);
 
110
  float velocity = velocity_calculator_.CalculateVelocity();
 
111
 
 
112
  if (fabs(velocity) < MINIMUM_FLICK_SPEED)
 
113
    velocity = 0.0f;
 
114
  else
 
115
    velocity *= FLICK_BOOST;
 
116
 
 
117
  /* Always run the animation, even if there's no starting speed,
 
118
     as it will pull the content back to a valid position if it
 
119
     was dragged beyond valid boundaries */
 
120
  deceleration_animation_.SetMinimumPosition(min_content_pos_);
 
121
  deceleration_animation_.SetMaximumPosition(0.0f);
 
122
  deceleration_animation_.SetStartPosition(content_pos_);
 
123
  deceleration_animation_.SetStartVelocity(velocity);
 
124
  deceleration_animation_.Start();
 
125
 
 
126
  state_ = KineticScrollerAxisStateMovingByInertia;
 
127
}
 
128
 
 
129
void KineticAxisScroller::Private::ProcessFingerDrag(int movement)
 
130
{
 
131
  movement = LimitOutOfBoundsMovement(movement, content_pos_, min_content_pos_);
 
132
 
 
133
  if (movement == 0)
 
134
    return;
 
135
 
 
136
  if (state_ == KineticScrollerAxisStatePressed)
 
137
  {
 
138
    ProcessFingerDrag_Pressed(movement);
 
139
  }
 
140
  else // KineticScrollerAxisState::FollowingFinger
 
141
  {
 
142
    ProcessFingerDrag_FollowingFinger(movement);
 
143
  }
 
144
}
 
145
 
 
146
void KineticAxisScroller::Private::ProcessFingerDrag_Pressed(int movement)
 
147
{
 
148
  accumulated_movement_ += movement;
 
149
 
 
150
  if (abs(accumulated_movement_) > KineticAxisScroller::MOVEMENT_THRESHOLD)
 
151
  {
 
152
    state_ = KineticScrollerAxisStateFollowingFinger;
 
153
    velocity_calculator_.Reset();
 
154
 
 
155
    ProcessFingerDrag_FollowingFinger(movement);
 
156
  }
 
157
}
 
158
 
 
159
void KineticAxisScroller::Private::ProcessFingerDrag_FollowingFinger(int movement)
 
160
{
 
161
  /* TODO: Filter the input for a smoother movement.
 
162
    E.g.: make the content follow the finger with a small delay instead of
 
163
    exactly following it. That will remove the inherent jitter in input coming
 
164
    from a touchscreen. */
 
165
 
 
166
  content_pos_ += movement;
 
167
 
 
168
  velocity_calculator_.ProcessMovement(movement);
 
169
}
 
170
 
 
171
void KineticAxisScroller::Private::UpdateAnimations(int delta_time)
 
172
{
 
173
  if (deceleration_animation_.IsActive())
 
174
  {
 
175
    deceleration_animation_.Update(delta_time);
 
176
    content_pos_ = deceleration_animation_.GetPosition();
 
177
 
 
178
    if (!deceleration_animation_.IsActive())
 
179
      state_ = KineticScrollerAxisStateIdle;
 
180
  }
 
181
  else
 
182
  {
 
183
    state_ = KineticScrollerAxisStateIdle;
 
184
  }
 
185
}
 
186
 
 
187
int KineticAxisScroller::Private::LimitOutOfBoundsMovement(int movement,
 
188
                                                           int position,
 
189
                                                           int min_position) const
 
190
{
 
191
  int new_position = position + movement;
 
192
 
 
193
  if (new_position > 0)
 
194
  {
 
195
    if (bounds_behavior_ == StopAtBounds)
 
196
    {
 
197
      return 0 - position;
 
198
    }
 
199
    else
 
200
    {
 
201
      /* hinder movement to hint user that he's dragging content beyound its
 
202
         boundaries*/
 
203
      return movement / 2;
 
204
    }
 
205
  }
 
206
  else if (new_position < min_position)
 
207
  {
 
208
    if (bounds_behavior_ == StopAtBounds)
 
209
    {
 
210
      return min_position - position;
 
211
    }
 
212
    else
 
213
    {
 
214
      return movement / 2;
 
215
    }
 
216
  }
 
217
  else
 
218
  {
 
219
    /* new_position is still within bounds */
 
220
    return movement;
 
221
  }
 
222
}
 
223
 
 
224
/*****************************************************************************
 
225
 * Public class
 
226
 *****************************************************************************/
 
227
 
 
228
const float KineticAxisScroller::MINIMUM_FLICK_SPEED = 0.003f;
 
229
const float KineticAxisScroller::FLICK_BOOST = 2.0f;
 
230
 
 
231
KineticAxisScroller::KineticAxisScroller()
 
232
  : p(new Private)
 
233
{
 
234
}
 
235
 
 
236
KineticAxisScroller::~KineticAxisScroller()
 
237
{
 
238
  delete p;
 
239
}
 
240
 
 
241
void KineticAxisScroller::SetViewportLength(int length)
 
242
{
 
243
  p->viewport_length_ = length;
 
244
  p->CalculateContentPosLimits();
 
245
}
 
246
 
 
247
int KineticAxisScroller::GetViewportLength() const
 
248
{
 
249
  return p->viewport_length_;
 
250
}
 
251
 
 
252
void KineticAxisScroller::SetContentLength(int length)
 
253
{
 
254
  p->content_length_ = length;
 
255
  p->CalculateContentPosLimits();
 
256
}
 
257
 
 
258
int KineticAxisScroller::GetContentLength() const
 
259
{
 
260
  return p->content_length_;
 
261
}
 
262
 
 
263
void KineticAxisScroller::SetContentPosition(int pos)
 
264
{
 
265
  p->content_pos_ = pos;
 
266
}
 
267
 
 
268
void KineticAxisScroller::SetBoundsBehavior(BoundsBehavior bounds_behavior)
 
269
{
 
270
  p->bounds_behavior_ = bounds_behavior;
 
271
 
 
272
  p->deceleration_animation_.SetOvershootBoundsEnabled(
 
273
      bounds_behavior != BoundsBehavior::StopAtBounds);
 
274
}
 
275
 
 
276
void KineticAxisScroller::ProcessFingerDown()
 
277
{
 
278
  p->ProcessFingerDown();
 
279
}
 
280
 
 
281
void KineticAxisScroller::ProcessFingerUp()
 
282
{
 
283
  p->ProcessFingerUp();
 
284
}
 
285
 
 
286
void KineticAxisScroller::ProcessFingerDrag(int movement)
 
287
{
 
288
  p->ProcessFingerDrag(movement);
 
289
}
 
290
 
 
291
void KineticAxisScroller::UpdateTime(int delta_time)
 
292
{
 
293
  p->UpdateAnimations(delta_time);
 
294
}
 
295
 
 
296
bool KineticAxisScroller::NeedTimeUpdates() const
 
297
{
 
298
  return p->state_ == KineticScrollerAxisStateMovingByInertia
 
299
    && p->deceleration_animation_.IsActive();
 
300
}
 
301
 
 
302
KineticScrollerAxisState KineticAxisScroller::GetState() const
 
303
{
 
304
  return p->state_;
 
305
}
 
306
 
 
307
int KineticAxisScroller::GetContentPosition() const
 
308
{
 
309
  return p->content_pos_;
 
310
}