Changes after 40127, changing control background to 0.f
[platform/core/uifw/dali-demo.git] / examples / path-animation / path-animation.cpp
1 /*
2  * Copyright (c) 2014 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 /**
19  * This example shows how to use path animations in DALi
20  */
21
22 // EXTERNAL INCLUDES
23 #include <dali-toolkit/dali-toolkit.h>
24 #include <dali/devel-api/actors/mesh-actor.h>
25 #include <dali/devel-api/geometry/mesh.h>
26 #include <dali/devel-api/geometry/mesh-factory.h>
27 #include <dali-toolkit/devel-api/controls/slider/slider.h>
28
29
30
31 // INTERNAL INCLUDES
32 #include "shared/view.h"
33
34 using namespace Dali;
35 using namespace Dali::Toolkit;
36
37
38 namespace
39 {
40 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-default.png" );
41 const char* ACTOR_IMAGE( DALI_IMAGE_DIR "dali-logo.png" );
42 const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
43 const char* APPLICATION_TITLE( "Path Animation Example" );
44 }; //Unnamed namespace
45
46 /**
47  * @brief The main class of the demo.
48  */
49 class PathController : public ConnectionTracker
50 {
51 public:
52
53   PathController( Application& application )
54 : mApplication( application )
55 {
56     // Connect to the Application's Init signal
57     mApplication.InitSignal().Connect( this, &PathController::Create );
58 }
59
60   ~PathController()
61   {
62     // Nothing to do here.
63   }
64
65   /*
66    * Create a control composed of a label and an slider
67    * @param[in] label The text to be displayed ny the label
68    * @param[in] size The size of the slider
69    * @param[in] callback Pointer to the callback function to be called when user moves the slider
70   */
71   Actor CreateVectorComponentControl( const std::string& label, const Vector3& size, bool(PathController::*callback)(Dali::Toolkit::Slider,float) )
72   {
73     TextLabel text = TextLabel::New(label);
74     text.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
75     text.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
76     text.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
77
78     Slider slider = Slider::New();
79     slider.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
80     slider.SetParentOrigin( ParentOrigin::CENTER_RIGHT);
81     slider.SetProperty(Slider::Property::LOWER_BOUND, -1.0f );
82     slider.SetProperty(Slider::Property::UPPER_BOUND, 1.0f );
83
84     Property::Array marks;
85     float mark = -1.0f;
86     for(unsigned short i(0); i<21; ++i )
87     {
88       marks.PushBack( mark );
89       mark += 0.1f;
90     }
91
92     slider.SetProperty(Slider::Property::MARKS, marks);
93     slider.SetProperty(Slider::Property::SNAP_TO_MARKS, true );
94     slider.SetSize(size);
95     slider.SetScale( 0.5f );
96     slider.ValueChangedSignal().Connect(this,callback);
97     text.Add( slider );
98     return text;
99   }
100
101   /**
102    * Crate all the GUI controls
103    */
104   void CreateControls()
105   {
106     Stage stage = Stage::GetCurrent();
107
108     //TextInput
109     Dali::Layer controlsLayer = Dali::Layer::New();
110     controlsLayer.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
111     controlsLayer.SetSizeModeFactor( Vector3( 1.0f, 0.3f, 1.0f ) );
112     controlsLayer.SetPosition( 0.0f, stage.GetSize().y*0.8f, 0.0f );
113     controlsLayer.SetAnchorPoint( AnchorPoint::TOP_LEFT);
114     controlsLayer.SetParentOrigin( ParentOrigin::TOP_LEFT);
115     controlsLayer.TouchedSignal().Connect(this, &PathController::OnTouchGuiLayer);
116     stage.Add( controlsLayer );
117
118     Vector3 textInputSize( stage.GetSize().x, stage.GetSize().y*0.04f, 0.0f );
119     Actor control0 = CreateVectorComponentControl("x:", textInputSize, &PathController::OnSliderXValueChange );
120     control0.SetY( stage.GetSize().y*0.05f );
121     control0.SetAnchorPoint(AnchorPoint::TOP_LEFT);
122     controlsLayer.Add( control0 );
123
124     Actor control1 = CreateVectorComponentControl("y:", textInputSize, &PathController::OnSliderYValueChange );
125     control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
126     control1.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
127     control1.SetPosition(0.0f,stage.GetSize().y*0.01,0.0f);
128     control0.Add( control1 );
129
130     Actor control2 =CreateVectorComponentControl("z:", textInputSize, &PathController::OnSliderZValueChange );
131     control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
132     control2.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
133     control2.SetPosition(0.0f,stage.GetSize().y*0.01,0.0f);
134     control1.Add( control2 );
135   }
136
137   /**
138    * Draws the path and the control points for the path
139    * @param[in] resolution Number of segments for the path.
140    */
141   void DrawPath( unsigned int resolution )
142   {
143     //Create path mesh actor
144     Dali::MeshData meshData = MeshFactory::NewPath( mPath, resolution );
145     Dali::Material material = Material::New("LineMaterial");
146     material.SetDiffuseColor( Vector4(0.0f,0.0f,0.0f,1.0f));
147     meshData.SetMaterial(material);
148     Dali::Mesh mesh = Dali::Mesh::New( meshData );
149     if( mMeshPath )
150     {
151       mContentLayer.Remove( mMeshPath );
152     }
153     mMeshPath = Dali::MeshActor::New( mesh );
154     mMeshPath.SetAnchorPoint( AnchorPoint::TOP_LEFT );
155     mMeshPath.SetParentOrigin( ParentOrigin::TOP_LEFT );
156     mContentLayer.Add( mMeshPath );
157
158
159     ////Create mesh connecting interpolation points and control points
160     std::vector<Dali::MeshData::Vertex> vVertex;
161     std::vector<unsigned short> vIndex;
162     size_t pointCount = mPath.GetPointCount();
163     size_t controlPointIndex = 0;
164     for( size_t i(0); i<pointCount; ++i )
165     {
166       vVertex.push_back( MeshData::Vertex(mPath.GetPoint(i),Vector2::ZERO, Vector3::ZERO ) );
167       if( i<pointCount-1)
168       {
169         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex),Vector2::ZERO, Vector3::ZERO ));
170         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex+1),Vector2::ZERO, Vector3::ZERO ));
171       }
172       controlPointIndex += 2;
173     }
174
175     size_t segmentCount = 2*(pointCount-2)+2;
176     unsigned short index=0;
177     for( size_t i(0); i<segmentCount; ++i, ++index )
178     {
179       vIndex.push_back(index);
180       vIndex.push_back(index+1);
181
182       if( ~i & 1 )
183       {
184         index++;
185       }
186     }
187
188     meshData.SetLineData( vVertex, vIndex, material );
189     meshData.SetMaterial(material);
190     mesh = Dali::Mesh::New( meshData );
191     if( mMeshHandlers )
192     {
193       mContentLayer.Remove( mMeshHandlers );
194     }
195     mMeshHandlers = Dali::MeshActor::New( mesh );
196     mMeshHandlers.SetAnchorPoint( AnchorPoint::TOP_LEFT );
197     mMeshHandlers.SetParentOrigin( ParentOrigin::TOP_LEFT );
198     mContentLayer.Add( mMeshHandlers );
199
200
201     //Create actors representing interpolation points
202     index = 0;
203     for( size_t i(0); i<pointCount; ++i )
204     {
205       if( !mControlPoint[index] )
206       {
207         mControlPoint[index] = Toolkit::CreateSolidColorActor(Vector4(1.0f,1.0f,1.0f,1.0f));
208         mControlPoint[index].SetParentOrigin( ParentOrigin::TOP_LEFT);
209         mControlPoint[index].SetAnchorPoint( AnchorPoint::CENTER );
210         mControlPoint[index].SetSize( 20.0f, 20.0f );
211         mContentLayer.Add(mControlPoint[index]);
212       }
213
214       std::string name( "Knot");
215       name.push_back(i);
216       mControlPoint[index].SetName( name );
217       mControlPoint[index].SetPosition( mPath.GetPoint(i) );
218       mControlPoint[index].SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
219       ++index;
220     }
221
222     //Create actors representing control points
223     size_t controlPointCount=2*(pointCount-1);
224     for( size_t i(0); i<controlPointCount; ++i )
225     {
226       if( !mControlPoint[index])
227       {
228         mControlPoint[index] = Toolkit::CreateSolidColorActor(Vector4(1.0f,1.0f,1.0f,1.0f));
229         mControlPoint[index].SetParentOrigin( ParentOrigin::TOP_LEFT);
230         mControlPoint[index].SetAnchorPoint( AnchorPoint::CENTER );
231         mControlPoint[index].SetSize( 20.0f, 20.0f );
232         mContentLayer.Add(mControlPoint[index]);
233       }
234       std::string name( "ControlPoint");
235       name.push_back(i);
236       mControlPoint[index].SetName( name );
237       mControlPoint[index].SetPosition( mPath.GetControlPoint(i) );
238       mControlPoint[index].SetColor( Vector4(1.0f,0.0f,0.0f,1.0f));
239       ++index;
240     }
241   }
242
243   /**
244    * Create the path animation.
245    */
246   void CreateAnimation()
247   {
248     if( !mAnimation )
249     {
250       mAnimation = Animation::New( 2.0f );
251     }
252     else
253     {
254       mAnimation.Pause();
255       mAnimation.Clear();
256       mActor.SetOrientation( Quaternion() );
257     }
258
259     mAnimation.Animate( mActor, mPath, mForward );
260     mAnimation.SetLooping( true );
261     mAnimation.Play();
262   }
263
264   /**
265    * Get closest control point.void
266    * @param[in] point Point from where the distance is computed
267    * @return The closest actor if the distance is beyond 0.5cm or an uninitialized actor otherwise
268    */
269   Actor GetClosestActor(const Vector3& point)
270   {
271     size_t pointCount = mPath.GetPointCount();
272     size_t controlPointCount = 3*pointCount - 2;
273     Actor result;
274     float minDistance = 1.0/0.0;
275
276     for( size_t i(0); i<controlPointCount; ++i )
277     {
278       Vector3 v = mControlPoint[i].GetCurrentPosition() - point;
279       float distance = v.LengthSquared();
280       if( distance < minDistance )
281       {
282         result = mControlPoint[i];
283         minDistance = distance;
284       }
285     }
286
287     Vector2 dpi = Dali::Stage::GetCurrent().GetDpi();
288     float distanceTreshold = 0.2f * dpi.x * 0.2f * dpi.x;
289
290     if( minDistance < distanceTreshold )
291     {
292       return result;
293     }
294     else
295     {
296       return Actor();
297     }
298   }
299
300   /**
301    * Callback called when the background layer is touched
302    */
303   bool OnTouchLayer(Actor actor, const TouchEvent& event)
304   {
305     if(event.GetPointCount()>0)
306     {
307       const TouchPoint& point = event.GetPoint(0);
308
309       if(point.state==TouchPoint::Up)
310       {
311         //Stop dragging
312         mDragActor.Reset();
313       }
314       else if(point.state==TouchPoint::Down)
315       {
316         Vector3 touchPoint = Vector3(event.GetPoint(0).screen.x, event.GetPoint(0).screen.y, 0.0f);
317         if(!mDragActor )
318         {
319           mDragActor = GetClosestActor( touchPoint );
320           if( !mDragActor && mPath.GetPointCount() < 10 )
321           {
322             // Add new point
323             Vector3 lastPoint = mPath.GetPoint( mPath.GetPointCount()-1);
324             mPath.AddPoint( touchPoint );
325             Vector3 displacement = (touchPoint-lastPoint)/8;
326             mPath.AddControlPoint( lastPoint + displacement );
327             mPath.AddControlPoint( touchPoint - displacement);
328
329             DrawPath( 200u );
330             CreateAnimation();
331           }
332         }
333       }
334       else if( mDragActor && point.state==TouchPoint::Motion  )
335       {
336         Vector3 touchPoint = Vector3(event.GetPoint(0).screen.x, event.GetPoint(0).screen.y, 0.0f);
337         std::string actorName(mDragActor.GetName());
338         if( actorName.compare(0, 4, "Knot") == 0)
339         {
340           int index = actorName[4];
341           mPath.GetPoint(index) = touchPoint;
342         }
343         else
344         {
345           int index = actorName[12];
346           mPath.GetControlPoint(index) = touchPoint;
347         }
348
349         DrawPath( 200u );
350         CreateAnimation();
351       }
352     }
353
354     return true;
355   }
356
357   bool OnTouchGuiLayer(Actor actor, const TouchEvent& event)
358  {
359     mDragActor.Reset();
360     return false;
361  }
362   /**
363    * Callback called when user changes slider X
364    * @param[in] slider The slider that has generated the signal
365    * @param[in] value The new value
366    */
367   bool OnSliderXValueChange( Slider s, float value)
368   {
369     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
370     {
371       mForward.x = 0.0f;
372     }
373     else
374     {
375       mForward.x = value;
376     }
377
378     CreateAnimation();
379     return true;
380   }
381
382   /**
383    * Callback called when user changes slider Y
384    * @param[in] slider The slider that has generated the signal
385    * @param[in] value The new value
386    */
387   bool OnSliderYValueChange( Slider s, float value)
388   {
389     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
390     {
391       mForward.y = 0.0f;
392     }
393     else
394     {
395       mForward.y = value;
396     }
397     CreateAnimation();
398     return true;
399   }
400
401   /**
402    * Callback called when user changes slider Z
403    * @param[in] slider The slider that has generated the signal
404    * @param[in] value The new value
405    */
406   bool OnSliderZValueChange( Slider s, float value)
407   {
408     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
409     {
410       mForward.z = 0.0f;
411     }
412     else
413     {
414       mForward.z = value;
415     }
416
417     CreateAnimation();
418     return true;
419   }
420
421   /**
422    * Main key event handler.
423    * Quit on escape key.
424    */
425   void OnKeyEvent(const KeyEvent& event)
426   {
427     if( event.state == KeyEvent::Down )
428     {
429       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) ||
430           IsKey( event, Dali::DALI_KEY_BACK ) )
431       {
432         mApplication.Quit();
433       }
434     }
435   }
436
437   /**
438    * One-time setup in response to Application InitSignal.
439    */
440   void Create( Application& application )
441   {
442     // Get a handle to the stage:
443     Stage stage = Stage::GetCurrent();
444
445     // Connect to input event signals:
446     stage.KeyEventSignal().Connect(this, &PathController::OnKeyEvent);
447
448     // Create a default view with a default tool bar:
449     Toolkit::Control view;              ///< The View instance.
450     Toolkit::ToolBar toolBar;          ///< The View's Toolbar.
451     mContentLayer = DemoHelper::CreateView( mApplication,
452                                             view,
453                                             toolBar,
454                                             BACKGROUND_IMAGE,
455                                             TOOLBAR_IMAGE,
456                                             "" );
457     mContentLayer.SetDrawMode( DrawMode::OVERLAY );
458
459     mContentLayer.TouchedSignal().Connect(this, &PathController::OnTouchLayer);
460
461     //Title
462     TextLabel title = DemoHelper::CreateToolBarLabel( APPLICATION_TITLE );
463     toolBar.AddControl( title, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
464
465     //Path
466     mPath = Dali::Path::New();
467     mPath.AddPoint( Vector3( 10.0f, stage.GetSize().y*0.5f, 0.0f ));
468     mPath.AddPoint( Vector3( stage.GetSize().x*0.5f, stage.GetSize().y*0.5f, 0.0f ));
469     mPath.GenerateControlPoints(0.25f);
470     DrawPath( 200u );
471
472     //Actor
473     Image img = ResourceImage::New(ACTOR_IMAGE);
474     mActor = ImageActor::New( img );
475     mActor.SetAnchorPoint( AnchorPoint::CENTER );
476     mActor.SetSize( 100, 50, 1 );
477     mContentLayer.Add( mActor );
478
479     CreateAnimation();
480     CreateControls();
481   }
482
483 private:
484   Application&  mApplication;
485
486   Layer      mContentLayer;       ///< The content layer
487
488   Path       mPath;               ///< The path used in the animation
489   ImageActor mActor;              ///< Actor being animated
490   Vector3    mForward;            ///< Current forward vector
491   Animation  mAnimation;          ///< Path animation
492
493   MeshActor  mMeshPath;           ///< Mesh actor for the path
494   MeshActor  mMeshHandlers;       ///< Mesh actor for the handlers of the path
495
496   Actor      mControlPoint[28];   ///< ImageActors represeting control points of the path
497
498   Actor      mDragActor;          ///< Reference to the actor currently being dragged
499 };
500
501
502 void RunTest( Application& application )
503 {
504   PathController test( application );
505
506   application.MainLoop();
507 }
508
509 /** Entry point for Linux & Tizen applications */
510 int main( int argc, char **argv )
511 {
512   Application application = Application::New( &argc, &argv, DALI_DEMO_THEME_PATH );
513
514   RunTest( application );
515
516   return 0;
517 }