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