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