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