Remove variable shadowing
[platform/core/uifw/dali-demo.git] / examples / bezier-curve / bezier-curve-example.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali-toolkit/devel-api/controls/table-view/table-view.h>
20 #include <dali/dali.h>
21 #include "generated/bezier-curve-frag.h"
22 #include "generated/bezier-curve-vert.h"
23 #include "shared/view.h"
24
25 #include <sstream>
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29 using namespace std;
30
31 namespace
32 {
33 const Vector4     GRID_BACKGROUND_COLOR(0.85f, 0.85f, 0.85f, 1.0f);
34 const Vector4     CONTROL_POINT1_COLOR(Color::MAGENTA);
35 const Vector4     CONTROL_POINT2_COLOR(0.0, 0.9, 0.9, 1.0);
36 const Vector3     CONTROL_POINT1_ORIGIN(-100, 200, 0);
37 const Vector3     CONTROL_POINT2_ORIGIN(100, -200, 0);
38 const char* const CIRCLE1_IMAGE(DEMO_IMAGE_DIR "circle1.png");
39 const char* const CIRCLE2_IMAGE(DEMO_IMAGE_DIR "circle2.png");
40 const char* const ANIMATION_BACKGROUND(DEMO_IMAGE_DIR "slider-skin.9.png");
41 const char*       APPLICATION_TITLE("Bezier curve animation");
42 const float       ANIM_LEFT_FACTOR(0.2f);
43 const float       ANIM_RIGHT_FACTOR(0.8f);
44 const int         AXIS_LABEL_POINT_SIZE(7);
45 const float       AXIS_LINE_SIZE(1.0f);
46
47 inline float Clamp(float v, float min, float max)
48 {
49   if(v < min) return min;
50   if(v > max) return max;
51   return v;
52 }
53
54 struct HandlePositionConstraint
55 {
56   void operator()(Vector3& current, const PropertyInputContainer& inputs)
57   {
58     Vector3 size(inputs[0]->GetVector3());
59     current.x = Clamp(current.x, minRelX * size.x, maxRelX * size.x);
60     current.y = Clamp(current.y, minRelY * size.y, maxRelY * size.y);
61   }
62
63   float minRelX{0.0f};
64   float maxRelX{0.0f};
65   float minRelY{0.0f};
66   float maxRelY{0.0f};
67 };
68
69 void AnimatingPositionConstraint(Vector3& current, const PropertyInputContainer& inputs)
70 {
71   float   positionFactor(inputs[0]->GetFloat()); // -1 - 2
72   Vector3 size(inputs[1]->GetVector3());
73
74   current.x = size.x * (positionFactor - 0.5f); // size * (-1.5 - 1.5)
75 }
76
77 } //unnamed namespace
78
79 class BezierCurveExample : public ConnectionTracker
80 {
81 public:
82   BezierCurveExample(Application& application)
83   : mApplication(application),
84     mControlPoint1(),
85     mControlPoint2(),
86     mControlLine1(),
87     mControlLine2(),
88     mAnimIcon1(),
89     mAnimIcon2(),
90     mDragActor(),
91     mCurve(),
92     mCoefficientLabel(),
93     mContentLayer(),
94     mGrid(),
95     mTimer(),
96     mDragAnimation(),
97     mBezierAnimation(),
98     mCurveVertices(),
99     mLine1Vertices(),
100     mLine2Vertices(),
101     mRelativeDragPoint(),
102     mLastControlPointPosition1(),
103     mLastControlPointPosition2(),
104     mPositionFactorIndex(),
105     mDuration(2.0f),
106     mControlPoint1Id(0.0f),
107     mControlPoint2Id(0.0f),
108     mControlPointScale(0.5f),
109     mControlPointZoomScale(mControlPointScale * 2.0),
110     mGoingRight(true)
111   {
112     // Connect to the Application's Init signal
113     mApplication.InitSignal().Connect(this, &BezierCurveExample::Create);
114   }
115
116   ~BezierCurveExample()
117   {
118     // Nothing to do here;
119   }
120
121   // The Init signal is received once (only) during the Application lifetime
122   void Create(Application& application)
123   {
124     Window window = mApplication.GetWindow();
125     window.KeyEventSignal().Connect(this, &BezierCurveExample::OnKeyEvent);
126
127     CreateBackground(window);
128
129     mControlPointScale     = 0.5f;
130     mControlPointZoomScale = mControlPointScale * 2.0f;
131
132     mContentLayer = Layer::New();
133     mContentLayer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
134     mContentLayer.TouchedSignal().Connect(this, &BezierCurveExample::OnTouchLayer);
135     mContentLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
136     window.Add(mContentLayer);
137
138     // 6 rows: title, grid, coords, play, anim1, anim2
139     TableView contentLayout = TableView::New(5, 1);
140     contentLayout.SetProperty(Dali::Actor::Property::NAME, "contentLayout");
141     contentLayout.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
142     contentLayout.SetCellPadding(Size(30, 30));
143     contentLayout.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
144     contentLayout.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
145     mContentLayer.Add(contentLayout);
146
147     // Create a TextLabel for the application title.
148     Toolkit::TextLabel label = Toolkit::TextLabel::New(APPLICATION_TITLE);
149     label.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
150     label.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
151     label.SetProperty(Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLACK);
152     contentLayout.Add(label);
153     contentLayout.SetFitHeight(0);
154
155     mGrid = Control::New();
156
157     mGrid.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH);
158     mGrid.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT);
159
160     mGrid.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
161     mGrid.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
162     mGrid.SetBackgroundColor(GRID_BACKGROUND_COLOR);
163
164     contentLayout.Add(mGrid);
165     contentLayout.SetCellAlignment(1, HorizontalAlignment::CENTER, VerticalAlignment::CENTER);
166     CreateCubic(mGrid);
167     CreateControlPoints(mGrid); // Control points constrained to double height of grid
168     CreateAxisLabels(mGrid);
169
170     mCoefficientLabel = TextLabel::New();
171     mCoefficientLabel.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
172     mCoefficientLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
173     mCoefficientLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
174     mCoefficientLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
175
176     contentLayout.Add(mCoefficientLabel);
177     SetLabel(Vector2(0, 0), Vector2(1, 1));
178     contentLayout.SetCellAlignment(2, HorizontalAlignment::CENTER, VerticalAlignment::CENTER);
179     contentLayout.SetFitHeight(2);
180
181     // Setup Play button and 2 icons to show off current anim and linear anim
182
183     PushButton play = PushButton::New();
184     play.SetProperty(Dali::Actor::Property::NAME, "Play");
185     play.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
186     play.SetProperty(Button::Property::LABEL, "Play");
187     play.ClickedSignal().Connect(this, &BezierCurveExample::OnPlayClicked);
188
189     contentLayout.Add(play);
190     contentLayout.SetCellAlignment(3, HorizontalAlignment::CENTER, VerticalAlignment::CENTER);
191     contentLayout.SetFitHeight(3);
192
193     auto animContainer = Control::New();
194     animContainer.SetProperty(Dali::Actor::Property::NAME, "AnimationContainer");
195     animContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
196     animContainer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
197
198     auto animRail = Control::New();
199     animRail.SetProperty(Control::Property::BACKGROUND, Property::Map().Add(Visual::Property::TYPE, Visual::IMAGE).Add(ImageVisual::Property::URL, ANIMATION_BACKGROUND));
200     animRail.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
201     animRail.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(0.666f, 0.2f, 1.0f));
202     animRail.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
203     animContainer.Add(animRail);
204
205     contentLayout.Add(animContainer);
206     contentLayout.SetFixedHeight(4, 150);
207
208     mAnimIcon1 = ImageView::New(CIRCLE1_IMAGE);
209     mAnimIcon1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
210     mAnimIcon1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
211
212     // Would like some means of setting and animating position as a percentage of
213     // parent size without using constraints, but this will have to suffice for the moment.
214     mPositionFactorIndex  = mAnimIcon1.RegisterProperty("positionFactor", ANIM_LEFT_FACTOR); // range: 0-1 (+/- 1)
215     Constraint constraint = Constraint::New<Vector3>(mAnimIcon1, Actor::Property::POSITION, AnimatingPositionConstraint);
216     constraint.AddSource(Source(mAnimIcon1, mPositionFactorIndex));
217     constraint.AddSource(Source(animContainer, Actor::Property::SIZE));
218     constraint.Apply();
219
220     animContainer.Add(mAnimIcon1);
221
222     // First UpdateCurve needs to run after size negotiation and after images have loaded
223     mGrid.OnRelayoutSignal().Connect(this, &BezierCurveExample::InitialUpdateCurve);
224
225     auto controlPoint1 = Control::DownCast(mControlPoint1);
226     if(controlPoint1)
227     {
228       controlPoint1.ResourceReadySignal().Connect(this, &BezierCurveExample::ControlPointReady);
229     }
230
231     auto controlPoint2 = Control::DownCast(mControlPoint2);
232     if(controlPoint2)
233     {
234       controlPoint2.ResourceReadySignal().Connect(this, &BezierCurveExample::ControlPointReady);
235     }
236   }
237
238   void ControlPointReady(Control control)
239   {
240     UpdateCurve();
241   }
242
243   void InitialUpdateCurve(Actor actor)
244   {
245     UpdateCurve();
246   }
247
248   void CreateBackground(Window window)
249   {
250     Toolkit::Control background = Dali::Toolkit::Control::New();
251     background.SetProperty(Actor::Property::ANCHOR_POINT, Dali::AnchorPoint::CENTER);
252     background.SetProperty(Actor::Property::PARENT_ORIGIN, Dali::ParentOrigin::CENTER);
253     background.SetResizePolicy(Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS);
254
255     Property::Map map;
256     map.Insert(Visual::Property::TYPE, Visual::COLOR);
257     map.Insert(ColorVisual::Property::MIX_COLOR, Vector4(253 / 255.0f, 245 / 255.0f, 230 / 255.0f, 1.0f));
258     background.SetProperty(Dali::Toolkit::Control::Property::BACKGROUND, map);
259     window.Add(background);
260   }
261
262   void CreateCubic(Actor parent)
263   {
264     // Create a mesh to draw the cubic as a single line
265     mCurve = Actor::New();
266     mCurve.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
267     mCurve.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
268
269     Shader shader = Shader::New(SHADER_BEZIER_CURVE_VERT, SHADER_BEZIER_CURVE_FRAG);
270
271     Property::Map curveVertexFormat;
272     curveVertexFormat["aPosition"] = Property::VECTOR2;
273     mCurveVertices                 = VertexBuffer::New(curveVertexFormat);
274     Vector2 vertexData[2]          = {Vector2(-0.5f, 0.5f), Vector2(0.5f, -0.5f)};
275     mCurveVertices.SetData(vertexData, 2);
276
277     Geometry geometry = Geometry::New();
278     geometry.AddVertexBuffer(mCurveVertices);
279     geometry.SetType(Geometry::LINE_STRIP);
280
281     Renderer renderer = Renderer::New(geometry, shader);
282     mCurve.AddRenderer(renderer);
283     parent.Add(mCurve);
284   }
285
286   Actor CreateControlPoint(Actor parent, const char* url, Vector3 position)
287   {
288     Actor actor = ImageView::New(url);
289     actor.SetProperty(Actor::Property::SCALE, mControlPointScale);
290     actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
291     // Curve and line drawing works off current value (i.e. last update frame's value). Need to animate to ensure
292     // initial position is baked to both frames before initially drawing the curve.
293     auto positionAnimation = Animation::New(0.01f);
294     positionAnimation.AnimateTo(Property(actor, Actor::Property::POSITION), position, AlphaFunction::EASE_IN_OUT);
295     positionAnimation.Play();
296     positionAnimation.FinishedSignal().Connect(this, &BezierCurveExample::OnAnimationFinished);
297
298     // Set up constraints for drag/drop
299     Constraint constraint = Constraint::New<Vector3>(actor, Actor::Property::POSITION, HandlePositionConstraint{-0.5, 0.5, -1, 1});
300     constraint.AddSource(Source(parent, Actor::Property::SIZE));
301     constraint.Apply();
302
303     actor.TouchedSignal().Connect(this, &BezierCurveExample::OnTouchControlPoint);
304     return actor;
305   }
306
307   Actor CreateControlLine(VertexBuffer vertexBuffer)
308   {
309     Actor line = Actor::New();
310     line.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
311     line.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
312
313     Shader   shader   = Shader::New(SHADER_BEZIER_CURVE_VERT, SHADER_BEZIER_CURVE_FRAG);
314     Geometry geometry = Geometry::New();
315     geometry.AddVertexBuffer(vertexBuffer);
316     geometry.SetType(Geometry::LINE_STRIP);
317
318     Renderer renderer = Renderer::New(geometry, shader);
319     line.AddRenderer(renderer);
320     return line;
321   }
322
323   void CreateControlPoints(Actor parent)
324   {
325     mControlPoint1   = CreateControlPoint(parent,
326                                         CIRCLE1_IMAGE,
327                                         CONTROL_POINT1_ORIGIN);
328     mControlPoint1Id = mControlPoint1.GetProperty<int>(Actor::Property::ID);
329
330     mControlPoint2   = CreateControlPoint(parent,
331                                         CIRCLE2_IMAGE,
332                                         CONTROL_POINT2_ORIGIN);
333     mControlPoint2Id = mControlPoint2.GetProperty<int>(Actor::Property::ID);
334
335     Property::Map lineVertexFormat;
336     lineVertexFormat["aPosition"] = Property::VECTOR2;
337     mLine1Vertices                = VertexBuffer::New(lineVertexFormat);
338     mLine2Vertices                = VertexBuffer::New(lineVertexFormat);
339
340     mControlLine1 = CreateControlLine(mLine1Vertices);
341     mControlLine2 = CreateControlLine(mLine2Vertices);
342
343     parent.Add(mControlLine1);
344     parent.Add(mControlLine2);
345     parent.Add(mControlPoint1);
346     parent.Add(mControlPoint2);
347   }
348
349   void CreateAxisLabels(Actor parent)
350   {
351     TextLabel progressionLabel = TextLabel::New("Progression");
352     progressionLabel.SetProperty(TextLabel::Property::POINT_SIZE, AXIS_LABEL_POINT_SIZE);
353     progressionLabel.SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(Degree(-90.0f)), Vector3::ZAXIS));
354     progressionLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_LEFT);
355     progressionLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_LEFT);
356     CreateLine(progressionLabel, ParentOrigin::BOTTOM_LEFT);
357
358     TextLabel timeLabel = TextLabel::New("Time");
359     timeLabel.SetProperty(TextLabel::Property::POINT_SIZE, AXIS_LABEL_POINT_SIZE);
360     timeLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
361     timeLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_LEFT);
362     CreateLine(timeLabel, ParentOrigin::TOP_LEFT);
363
364     parent.Add(progressionLabel);
365     parent.Add(timeLabel);
366   }
367
368   void CreateLine(Actor parent, const Vector3& parentOrigin)
369   {
370     Control control = Control::New();
371     control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
372     control.SetProperty(Actor::Property::PARENT_ORIGIN, parentOrigin);
373     control.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
374     control.SetProperty(Actor::Property::SIZE_HEIGHT, AXIS_LINE_SIZE);
375     control.SetBackgroundColor(Color::BLACK);
376     parent.Add(control);
377   }
378
379   void SetLabel(Vector2 pos1, Vector2 pos2)
380   {
381     std::ostringstream oss;
382     oss.setf(std::ios::fixed, std::ios::floatfield);
383     oss.precision(2);
384     oss << "( <color value='#971586'>" << pos1.x << ", " << pos1.y << ", </color>";
385     oss << "<color value='#e7640d'>" << pos2.x << ", " << pos2.y << "</color>";
386     oss << "<color value='black'> )</color>";
387
388     mCoefficientLabel.SetProperty(TextLabel::Property::TEXT, oss.str());
389   }
390
391   Vector2 AlignToGrid(Vector3 actorPos, Vector3 gridSize)
392   {
393     actorPos /= gridSize; // => -0.5 - 0.5
394     actorPos.x = Clamp(actorPos.x, -0.5f, 0.5f);
395     return Vector2(actorPos.x + 0.5f, 0.5f - actorPos.y);
396   }
397
398   void GetControlPoints(Vector2& pt1, Vector2& pt2)
399   {
400     Vector3 gridSize = mGrid.GetProperty<Vector3>(Actor::Property::SIZE); // Get target value
401
402     pt1 = AlignToGrid(mControlPoint1.GetCurrentProperty<Vector3>(Actor::Property::POSITION), gridSize);
403     pt2 = AlignToGrid(mControlPoint2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), gridSize);
404   }
405
406   /**
407    * @param[in] actor The actor to get the position from
408    * @param[out] point The point in the grid in the range -0.5 -> 0.5 in x and y, with y up.
409    * @param[out] position The actor position, floored to the nearest pixel
410    */
411   void GetPoint(Actor actor, Vector2& point, Vector2& position)
412   {
413     auto gridSize        = mGrid.GetProperty<Vector3>(Actor::Property::SIZE);            // Get target value
414     auto currentPosition = actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION); // Get constrained current value
415
416     position = Vector2(floor(currentPosition.x), floor(currentPosition.y));
417
418     point.x = Clamp(position.x / gridSize.x, -0.5f, 0.5f) + 0.5f;
419     point.y = 0.5f - position.y / gridSize.y;
420   }
421
422   void UpdateCurve()
423   {
424     Vector2   point1, point2;
425     Vector2   position1, position2;
426     const int NUMBER_OF_SEGMENTS(40);
427
428     GetPoint(mControlPoint1, point1, position1);
429     GetPoint(mControlPoint2, point2, position2);
430
431     if(position1 != mLastControlPointPosition1 ||
432        position2 != mLastControlPointPosition2)
433     {
434       mLastControlPointPosition1 = position1;
435       mLastControlPointPosition2 = position2;
436
437       SetLabel(point1, point2);
438
439       Path path = Path::New();
440       path.AddPoint(Vector3::ZERO);
441       path.AddPoint(Vector3(1.0f, 1.0f, 1.0f));
442       path.AddControlPoint(Vector3(point1.x, point1.y, 0));
443       path.AddControlPoint(Vector3(point2.x, point2.y, 0));
444
445       Dali::Vector<float> verts;
446
447       verts.Resize(2 * (NUMBER_OF_SEGMENTS + 1)); // 1 more point than segment
448       for(int i = 0; i <= NUMBER_OF_SEGMENTS; ++i)
449       {
450         Vector3 position, tangent;
451         path.Sample(i / float(NUMBER_OF_SEGMENTS), position, tangent);
452         verts[i * 2]     = position.x - 0.5;
453         verts[i * 2 + 1] = 0.5 - position.y;
454       }
455       mCurveVertices.SetData(&verts[0], NUMBER_OF_SEGMENTS + 1);
456
457       Vector4 line1(-0.5f, 0.5f, point1.x - 0.5f, 0.5f - point1.y);
458       mLine1Vertices.SetData(line1.AsFloat(), 2);
459
460       Vector4 line2(0.5f, -0.5f, point2.x - 0.5f, 0.5f - point2.y);
461       mLine2Vertices.SetData(line2.AsFloat(), 2);
462     }
463   }
464
465   bool OnTouchControlPoint(Actor controlPoint, const TouchEvent& event)
466   {
467     if(event.GetPointCount() > 0)
468     {
469       if(event.GetState(0) == PointState::DOWN)
470       {
471         Vector2 screenPoint = event.GetScreenPosition(0);
472         mRelativeDragPoint  = screenPoint;
473         mRelativeDragPoint -= Vector2(controlPoint.GetCurrentProperty<Vector3>(Actor::Property::POSITION));
474         mDragActor     = controlPoint;
475         mDragAnimation = Animation::New(0.25f);
476         mDragAnimation.AnimateTo(Property(mDragActor, Actor::Property::SCALE), Vector3(mControlPointZoomScale, mControlPointZoomScale, 1.0f), AlphaFunction::EASE_OUT);
477         mDragAnimation.Play();
478       }
479     }
480     return false; // Don't mark this as consumed - let the layer get the touch
481   }
482
483   bool OnTouchLayer(Actor actor, const TouchEvent& event)
484   {
485     if(event.GetPointCount() > 0)
486     {
487       if(mDragActor)
488       {
489         Vector3 position(event.GetScreenPosition(0));
490
491         mDragActor.SetProperty(Actor::Property::POSITION, position - Vector3(mRelativeDragPoint));
492
493         if(event.GetState(0) == PointState::UP) // Stop dragging
494         {
495           mDragAnimation = Animation::New(0.25f);
496           mDragAnimation.AnimateTo(Property(mDragActor, Actor::Property::SCALE), Vector3(mControlPointScale, mControlPointScale, 1.0f), AlphaFunction::EASE_IN);
497           mDragAnimation.FinishedSignal().Connect(this, &BezierCurveExample::OnAnimationFinished);
498           mDragAnimation.Play();
499           mDragActor.Reset();
500         }
501       }
502       UpdateCurve();
503     }
504     return false;
505   }
506
507   void OnAnimationFinished(Animation& animation)
508   {
509     UpdateCurve();
510   }
511
512   bool OnPlayClicked(Button button)
513   {
514     if(!mBezierAnimation)
515     {
516       mBezierAnimation = Animation::New(mDuration);
517     }
518     mBezierAnimation.Stop();
519     mBezierAnimation.Clear();
520
521     float positionFactor = ANIM_LEFT_FACTOR;
522     if(mGoingRight)
523     {
524       positionFactor = ANIM_RIGHT_FACTOR;
525       mGoingRight    = false;
526     }
527     else
528     {
529       mGoingRight = true;
530     }
531
532     Vector2 pt1, pt2;
533     GetControlPoints(pt1, pt2);
534
535     mBezierAnimation.AnimateTo(Property(mAnimIcon1, mPositionFactorIndex), positionFactor, AlphaFunction(pt1, pt2));
536     mBezierAnimation.Play();
537     return true;
538   }
539
540   /**
541    * Main key event handler
542    */
543   void OnKeyEvent(const KeyEvent& event)
544   {
545     if(event.GetState() == KeyEvent::DOWN && (IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK)))
546     {
547       mApplication.Quit();
548     }
549   }
550
551 private:
552   Application&    mApplication;
553   Actor           mControlPoint1;
554   Actor           mControlPoint2;
555   Actor           mControlLine1;
556   Actor           mControlLine2;
557   ImageView       mAnimIcon1;
558   ImageView       mAnimIcon2;
559   Actor           mDragActor;
560   Actor           mCurve;
561   TextLabel       mCoefficientLabel;
562   Layer           mContentLayer;
563   Control         mGrid;
564   Timer           mTimer;
565   Animation       mDragAnimation;
566   Animation       mBezierAnimation;
567   VertexBuffer    mCurveVertices;
568   VertexBuffer    mLine1Vertices;
569   VertexBuffer    mLine2Vertices;
570   Vector2         mRelativeDragPoint;
571   Vector2         mLastControlPointPosition1;
572   Vector2         mLastControlPointPosition2;
573   Property::Index mPositionFactorIndex;
574   float           mDuration;
575   unsigned int    mControlPoint1Id;
576   unsigned int    mControlPoint2Id;
577   float           mControlPointScale;
578   float           mControlPointZoomScale;
579   bool            mGoingRight;
580 };
581
582 int DALI_EXPORT_API main(int argc, char** argv)
583 {
584   Application application = Application::New(&argc, &argv);
585
586   BezierCurveExample test(application);
587   application.MainLoop();
588   return 0;
589 }