81457e69262e72913827ebd2d2249dde4da7598c
[platform/core/uifw/dali-demo.git] / examples / radial-menu / radial-sweep-view-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 #include "radial-sweep-view-impl.h"
18
19 using namespace Dali;
20
21 namespace
22 {
23
24 /**
25  * Method to project a point on a circle of radius halfSide at given
26  * angle onto a square of side 2 * halfSide
27  */
28 Vector3 CircleSquareProjection( Degree angle, float halfSide )
29 {
30   Vector3 position(0.0f, 0.0f, 0.0f);
31   Radian angleInRadians(angle);
32
33   //  135  90   45
34   //     +--+--+
35   //     | \|/ |
36   // 180 +--+--+ 0
37   //     | /|\ |
38   //     +--+--+
39   //  225  270  315
40   if( angle >= 45.0f && angle < 135.0f )
41   {
42     position.x = halfSide * cosf(angleInRadians) / sinf(angleInRadians);
43     position.y = -halfSide;
44   }
45   else if( angle >= 135.0f && angle < 225.0f )
46   {
47     position.x = -halfSide;
48     position.y = halfSide * sinf(angleInRadians) / cosf(angleInRadians);
49   }
50   else if( angle >= 225.0f && angle < 315.0f )
51   {
52     position.x = -halfSide * cosf(angleInRadians) / sinf(angleInRadians);
53     position.y =  halfSide;
54   }
55   else
56   {
57     position.x = halfSide;
58     position.y = -halfSide * sinf(angleInRadians) / cosf(angleInRadians);
59   }
60   return position;
61 }
62
63 float HoldZeroFastEaseInOutHoldOne(float progress)
64 {
65   if( progress < 0.2f)
66   {
67     return 0.0f;
68   }
69   else if(progress < 0.5f)
70   {
71     return AlphaFunctions::EaseIn((progress-0.2) / 0.3f) * 0.5f;
72   }
73   else if(progress < 0.8f)
74   {
75     return AlphaFunctions::EaseOut((progress - 0.5f) / 0.3f) * 0.5f + 0.5f;
76   }
77   else
78   {
79     return 1.0f;
80   }
81 }
82
83 struct SquareFanConstraint
84 {
85   SquareFanConstraint(int sideIndex)
86   : mSideIndex(sideIndex)
87   {
88   }
89
90   Vector3 operator()( const Vector3& current, const PropertyInput& start, const PropertyInput& rotation )
91   {
92     float degree = fmodf((start.GetFloat() + rotation.GetFloat()), 360.0f);
93     if(degree < 0.0f)
94     {
95       degree += 360.0f;
96     }
97
98     float startAngle = (90.0f*mSideIndex)-45.0f;
99     float endAngle = (90.0f*mSideIndex)+45.0f;
100     if(degree < startAngle)
101     {
102       return Vector3::ZERO;
103     }
104     else if( degree >= endAngle )
105     {
106       degree = endAngle;
107     }
108     Vector3 pos = CircleSquareProjection(Degree(degree), 0.5f);
109     pos.x = -pos.x; // Inverting X makes the animation go anti clockwise from left center
110     return pos;
111   }
112
113   int mSideIndex;
114 };
115
116 } // anonymous namespace
117
118
119 RadialSweepView RadialSweepViewImpl::New( )
120 {
121   return New( 2.0f, 100.0f, Degree(0.0f), Degree(0.0f), Degree(0.0f), Degree(359.999f) );
122 }
123
124
125 RadialSweepView RadialSweepViewImpl::New( float duration, float diameter, Degree initialAngle, Degree finalAngle, Degree initialSector, Degree finalSector )
126 {
127   RadialSweepViewImpl* impl= new RadialSweepViewImpl(duration, diameter, initialAngle, finalAngle, initialSector, finalSector);
128   RadialSweepView handle = RadialSweepView(*impl);
129   return handle;
130 }
131
132 RadialSweepViewImpl::RadialSweepViewImpl( float duration, float diameter, Degree initialAngle, Degree finalAngle, Degree initialSector, Degree finalSector )
133 : Control( false ),
134   mDuration(duration),
135   mDiameter(diameter),
136   mInitialAngle(initialAngle),
137   mFinalAngle(finalAngle),
138   mInitialSector(initialSector),
139   mFinalSector(finalSector),
140   mInitialActorAngle(0),
141   mFinalActorAngle(0),
142   mEasingFunction(HoldZeroFastEaseInOutHoldOne),
143   mRotateActorsWithStencil(false),
144   mRotateActors(false)
145 {
146 }
147
148 void RadialSweepViewImpl::SetDuration(float duration)
149 {
150   mDuration = duration;
151 }
152
153 void RadialSweepViewImpl::SetEasingFunction( Dali::AlphaFunction easingFunction )
154 {
155   mEasingFunction = easingFunction;
156 }
157
158 void RadialSweepViewImpl::SetDiameter(float diameter)
159 {
160   mDiameter = diameter;
161 }
162
163 void RadialSweepViewImpl::SetInitialAngle( Dali::Degree initialAngle)
164 {
165   mInitialAngle = initialAngle;
166 }
167
168 void RadialSweepViewImpl::SetFinalAngle( Dali::Degree finalAngle)
169 {
170   mFinalAngle = finalAngle;
171 }
172
173 void RadialSweepViewImpl::SetInitialSector( Dali::Degree initialSector)
174 {
175   mInitialSector = initialSector;
176 }
177
178 void RadialSweepViewImpl::SetFinalSector( Dali::Degree finalSector)
179 {
180   mFinalSector = finalSector;
181 }
182
183 void RadialSweepViewImpl::SetInitialActorAngle( Dali::Degree initialAngle )
184 {
185   mInitialActorAngle = initialAngle;
186   mRotateActors = true;
187 }
188
189 void RadialSweepViewImpl::SetFinalActorAngle( Dali::Degree finalAngle )
190 {
191   mFinalActorAngle = finalAngle;
192   mRotateActors = true;
193 }
194
195 float RadialSweepViewImpl::GetDuration( )
196 {
197   return mDuration;
198 }
199
200 float RadialSweepViewImpl::GetDiameter( )
201 {
202   return mDiameter;
203 }
204
205 Dali::Degree RadialSweepViewImpl::GetInitialAngle( )
206 {
207   return mInitialAngle;
208 }
209
210 Dali::Degree RadialSweepViewImpl::GetFinalAngle( )
211 {
212   return mFinalAngle;
213 }
214
215 Dali::Degree RadialSweepViewImpl::GetInitialSector( )
216 {
217   return mInitialSector;
218 }
219
220 Dali::Degree RadialSweepViewImpl::GetFinalSector( )
221 {
222   return mFinalSector;
223 }
224
225 Dali::Degree RadialSweepViewImpl::GetInitialActorAngle( )
226 {
227   return mInitialActorAngle;
228 }
229
230 Dali::Degree RadialSweepViewImpl::GetFinalActorAngle(  )
231 {
232   return mFinalActorAngle;
233 }
234
235 void RadialSweepViewImpl::RotateActorsWithStencil(bool rotate)
236 {
237   mRotateActorsWithStencil = rotate;
238 }
239
240 void RadialSweepViewImpl::Add(Actor actor)
241 {
242   if( ! mLayer )
243   {
244     mLayer = Layer::New();
245     Self().Add(mLayer);
246     mLayer.SetSize( Stage::GetCurrent().GetSize() );
247     mLayer.SetPositionInheritanceMode(USE_PARENT_POSITION);
248   }
249
250   mLayer.Add(actor);
251 }
252
253 void RadialSweepViewImpl::Activate( Animation anim, float offsetTime, float duration )
254 {
255   bool startAnimation=false;
256   if( ! anim )
257   {
258     mAnim = Animation::New( mDuration );
259     anim = mAnim;
260     startAnimation = true;
261   }
262
263   if( ! mStencilActor )
264   {
265     CreateStencil( mInitialSector );
266     mLayer.Add( mStencilActor );
267     mStencilActor.SetSize(mDiameter, mDiameter);
268   }
269
270   mStencilActor.SetRotation( Degree(mInitialAngle), Vector3::ZAXIS );
271   mStencilActor.SetProperty( mRotationAngleIndex, static_cast<float>(mInitialSector) );
272
273   if( mRotateActors )
274   {
275     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
276     {
277       Actor actor = mLayer.GetChildAt(i);
278       if( actor != mStencilActor )
279       {
280         anim.RotateTo( actor, mInitialActorAngle, Vector3::ZAXIS );
281       }
282     }
283   }
284
285   anim.AnimateTo( Property( mStencilActor, mRotationAngleIndex ), static_cast<float>(mFinalSector), mEasingFunction, TimePeriod( offsetTime, duration) );
286   anim.RotateTo( mStencilActor, mFinalAngle, Vector3::ZAXIS, mEasingFunction, offsetTime, duration );
287
288   if( mRotateActorsWithStencil )
289   {
290     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
291     {
292       Actor actor = mLayer.GetChildAt(i);
293       if( actor != mStencilActor )
294       {
295         anim.RotateTo( actor, Degree(mFinalAngle - mInitialAngle), Vector3::ZAXIS, mEasingFunction, offsetTime, duration );
296       }
297     }
298   }
299   else if( mRotateActors )
300   {
301     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
302     {
303       Actor actor = mLayer.GetChildAt(i);
304       if( actor != mStencilActor )
305       {
306         anim.RotateTo( actor, mFinalActorAngle, Vector3::ZAXIS, mEasingFunction, offsetTime, duration );
307       }
308     }
309   }
310
311
312   if( startAnimation )
313   {
314     anim.SetLooping(true);
315     anim.Play();
316   }
317 }
318
319
320 void RadialSweepViewImpl::Deactivate()
321 {
322   if( mAnim )
323   {
324     mAnim.Stop();
325   }
326   // mLayer.Remove( mStencilActor );
327   // mStencilActor.Reset();
328   // mMesh.Reset();
329   // mMaterial.Reset();
330 }
331
332 void RadialSweepViewImpl::CreateStencil( Degree initialSector )
333 {
334   mMaterial = Material::New("Material");
335   mMaterial.SetDiffuseColor(Color::WHITE);
336   mMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
337
338   // Generate a square mesh with a point at the center:
339
340   AnimatableMesh::Faces faces;
341   // Create triangles joining up the verts
342   faces.push_back(0); faces.push_back(1); faces.push_back(2);
343   faces.push_back(0); faces.push_back(2); faces.push_back(3);
344   faces.push_back(0); faces.push_back(3); faces.push_back(4);
345   faces.push_back(0); faces.push_back(4); faces.push_back(5);
346   faces.push_back(0); faces.push_back(5); faces.push_back(6);
347
348   mMesh = AnimatableMesh::New(7, faces, mMaterial);
349   mMesh[0].SetPosition( Vector3(  0.0f,  0.0f, 0.0f ) ); // Center pt
350
351   mStencilActor = MeshActor::New(mMesh);
352   mStencilActor.SetAffectedByLighting(false);
353   mStencilActor.SetCullFace(CullNone); // Allow clockwise & anticlockwise faces
354
355   mStartAngleIndex = mStencilActor.RegisterProperty("start-angle", Property::Value(0.0f));
356   mRotationAngleIndex = mStencilActor.RegisterProperty("rotation-angle", Property::Value(initialSector));
357
358   Source srcStart( mStencilActor, mStartAngleIndex );
359   Source srcRot( mStencilActor, mRotationAngleIndex );
360
361   // Constrain the vertices of the square mesh to sweep out a sector as the
362   // rotation angle is animated.
363   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(1, AnimatableVertex::POSITION),
364                                                   srcStart, srcStart, SquareFanConstraint(0)));
365   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(2, AnimatableVertex::POSITION),
366                                                   srcStart, srcRot, SquareFanConstraint(0)));
367   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(3, AnimatableVertex::POSITION),
368                                                   srcStart, srcRot, SquareFanConstraint(1)));
369   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(4, AnimatableVertex::POSITION),
370                                                   srcStart, srcRot, SquareFanConstraint(2)));
371   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(5, AnimatableVertex::POSITION),
372                                                   srcStart, srcRot, SquareFanConstraint(3)));
373   mMesh.ApplyConstraint(Constraint::New<Vector3>( mMesh.GetPropertyIndex(6, AnimatableVertex::POSITION),
374                                                   srcStart, srcRot, SquareFanConstraint(4)));
375
376   mStencilActor.SetDrawMode( DrawMode::STENCIL );
377   mStencilActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
378 }