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