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