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