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