Added application to test visual transition framework
[platform/core/uifw/dali-demo.git] / examples / transitions / shadow-button-impl.cpp
1 /*
2  * Copyright (c) 2017 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 #include "shadow-button-impl.h"
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali/public-api/object/type-registry-helper.h>
20 #include <dali/devel-api/scripting/enum-helper.h>
21 #include <dali-toolkit/devel-api/align-enums.h>
22 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
23 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
24
25 #include <cstdio>
26
27 using namespace Dali; // Needed for macros
28 using namespace Dali::Toolkit;
29
30 namespace Demo
31 {
32 namespace Internal
33 {
34
35 namespace
36 {
37
38
39 Dali::BaseHandle Create()
40 {
41   return Demo::ShadowButton::New();
42 }
43
44 DALI_TYPE_REGISTRATION_BEGIN( ShadowButton, Dali::Toolkit::Button, Create );
45
46 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "activeTransition", ARRAY, ACTIVE_TRANSITION );
47 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "inactiveTransition", ARRAY, INACTIVE_TRANSITION );
48 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "clickTransition", ARRAY, CLICK_TRANSITION );
49 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "backgroundVisual", MAP, BACKGROUND_VISUAL );
50 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "checkboxBgVisual", MAP, CHECKBOX_BG_VISUAL );
51 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "checkboxFgVisual", MAP, CHECKBOX_FG_VISUAL );
52 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "labelVisual", MAP, LABEL_VISUAL );
53 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "checkState", BOOLEAN, ACTIVE_STATE );
54 DALI_PROPERTY_REGISTRATION( Demo, ShadowButton, "checkState", BOOLEAN, CHECK_STATE );
55
56 DALI_TYPE_REGISTRATION_END();
57
58 DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_PROPERTIES )
59 { "backgroundVisual", Demo::ShadowButton::Property::BACKGROUND_VISUAL },
60 { "checkboxBgVisual", Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL},
61 { "checkboxFgVisual", Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL},
62 { "labelVisual",      Demo::ShadowButton::Property::LABEL_VISUAL}
63 DALI_ENUM_TO_STRING_TABLE_END( VISUAL_PROPERTIES )
64
65 Toolkit::TransitionData ConvertPropertyToTransition( const Property::Value& value )
66 {
67   Toolkit::TransitionData transitionData;
68
69   if( value.GetType() == Property::ARRAY )
70   {
71     transitionData = Toolkit::TransitionData::New( *value.GetArray());
72   }
73   else if( value.GetType() == Property::MAP )
74   {
75     transitionData = Toolkit::TransitionData::New( *value.GetMap() );
76   }
77   return transitionData;
78 }
79
80 } // anonymous namespace
81
82
83 Internal::ShadowButton::ShadowButton()
84 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
85   mCheckState(false),
86   mActiveState(false)
87 {
88 }
89
90 Internal::ShadowButton::~ShadowButton()
91 {
92 }
93
94 Demo::ShadowButton Internal::ShadowButton::New()
95 {
96   IntrusivePtr<Internal::ShadowButton> impl = new Internal::ShadowButton();
97   Demo::ShadowButton handle = Demo::ShadowButton( *impl );
98   impl->Initialize();
99   return handle;
100 }
101
102 void ShadowButton::SetActiveState( bool active )
103 {
104   if( active != mActiveState )
105   {
106     mActiveState = active;
107     if( active )
108     {
109       StartTransition( Demo::ShadowButton::Property::ACTIVE_TRANSITION );
110     }
111     else
112     {
113       StartTransition( Demo::ShadowButton::Property::INACTIVE_TRANSITION );
114     }
115   }
116 }
117
118 bool ShadowButton::GetActiveState()
119 {
120   return mActiveState;
121 }
122
123 void ShadowButton::SetCheckState( bool checkState )
124 {
125   mCheckState = checkState;
126   EnableVisual( Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL, mCheckState );
127   RelayoutRequest();
128 }
129
130 bool ShadowButton::GetCheckState()
131 {
132   return mCheckState;
133 }
134
135 void ShadowButton::StartTransition( Property::Index transitionId )
136 {
137   Transitions::iterator iter = FindTransition( transitionId );
138   if( iter != mTransitions.end() )
139   {
140     if( iter->mAnimation )
141     {
142       iter->mAnimation.Stop();
143       iter->mPlaying = false;
144
145       iter->mAnimation.FinishedSignal().Disconnect( this, &ShadowButton::OnTransitionFinished );
146     }
147
148     iter->mAnimation = CreateTransition( iter->mTransitionData );
149     StoreTargetLayouts( iter->mTransitionData );
150
151     iter->mAnimation.FinishedSignal().Connect( this, &ShadowButton::OnTransitionFinished );
152     iter->mAnimation.Play();
153     iter->mPlaying = true;
154   }
155 }
156
157 void ShadowButton::OnTransitionFinished( Animation& src )
158 {
159   ShadowButton::Transitions::iterator iter = mTransitions.begin();
160   for( ; iter != mTransitions.end(); ++iter )
161   {
162     if( iter->mAnimation == src )
163     {
164       iter->mPlaying = false;
165       iter->mAnimation.Reset(); // Remove the animation when it's finished.
166       switch( iter->mTransitionId )
167       {
168         case Demo::ShadowButton::Property::ACTIVE_TRANSITION:
169         {
170           // Consider relayouting the text.
171           break;
172         }
173         case Demo::ShadowButton::Property::INACTIVE_TRANSITION:
174         {
175           // Consider relayouting the text.
176           break;
177         }
178       }
179       break;
180     }
181   }
182 }
183
184 void ShadowButton::OnInitialize()
185 {
186   Actor self = Self();
187 }
188
189 void ShadowButton::OnStageConnection( int depth )
190 {
191   Control::OnStageConnection( depth );
192 }
193
194 void ShadowButton::OnStageDisconnection()
195 {
196   Control::OnStageDisconnection();
197 }
198
199 void ShadowButton::OnSizeSet( const Vector3& targetSize )
200 {
201   Control::OnSizeSet( targetSize );
202   RelayoutVisuals( Vector2( targetSize ) );
203 }
204
205 void ShadowButton::OnRelayout( const Vector2& targetSize, RelayoutContainer& container )
206 {
207   RelayoutVisuals( targetSize );
208 }
209
210 void ShadowButton::RelayoutVisuals( const Vector2& targetSize )
211 {
212   bool transitioning = false;
213   ShadowButton::Transitions::iterator iter = mTransitions.begin();
214   for( ; iter != mTransitions.end(); ++iter )
215   {
216     if( iter->mPlaying == true )
217     {
218       transitioning = true;
219       break;
220     }
221   }
222
223   if( ! transitioning )
224   {
225     for( ShadowButton::Transforms::iterator iter = mTransforms.begin();
226          iter != mTransforms.end(); ++iter )
227     {
228       switch( iter->mTransformId )
229       {
230         case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
231         {
232           mBackgroundVisual.SetTransformAndSize( iter->mTransform, targetSize );
233           break;
234         }
235         case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
236         {
237           mCheckboxBgVisual.SetTransformAndSize( iter->mTransform, targetSize );
238           break;
239         }
240         case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
241         {
242           mCheckboxFgVisual.SetTransformAndSize( iter->mTransform, targetSize );
243           break;
244         }
245         case Demo::ShadowButton::Property::LABEL_VISUAL:
246         {
247           mLabelVisual.SetTransformAndSize( iter->mTransform, targetSize );
248           break;
249         }
250       }
251     }
252   }
253 }
254
255 Vector3 ShadowButton::GetNaturalSize()
256 {
257   int width;
258   int height;
259
260   Vector2 checkboxBgSize;
261   Vector2 checkboxFgSize;
262   Vector2 labelSize;
263   mCheckboxBgVisual.GetNaturalSize( checkboxBgSize );
264   mCheckboxFgVisual.GetNaturalSize( checkboxFgSize );
265   mLabelVisual.GetNaturalSize( labelSize );
266
267   width = std::max( checkboxBgSize.x, checkboxFgSize.x ) + labelSize.x;
268   height = std::max( std::max( checkboxFgSize.y, checkboxBgSize.y ), labelSize.y );
269
270   return Vector3( width, height, height );
271 }
272
273 void ShadowButton::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
274 {
275   // Chain up.
276   Control::OnStyleChange( styleManager, change );
277 }
278
279 ShadowButton::Transitions::iterator ShadowButton::FindTransition( Property::Index index )
280 {
281   bool found = false;
282   ShadowButton::Transitions::iterator iter = mTransitions.begin();
283   for( ; iter != mTransitions.end(); ++iter )
284   {
285     if( iter->mTransitionId == index )
286     {
287       found = true;
288       break;
289     }
290   }
291   if( ! found )
292   {
293     iter = mTransitions.end();
294   }
295   return iter;
296 }
297
298 ShadowButton::Transforms::iterator ShadowButton::FindTransform( Property::Index index )
299 {
300   bool found = false;
301   ShadowButton::Transforms::iterator iter = mTransforms.begin();
302   for( ; iter != mTransforms.end(); ++iter )
303   {
304     if( iter->mTransformId == index )
305     {
306       found = true;
307       break;
308     }
309   }
310   if( ! found )
311   {
312     iter = mTransforms.end();
313   }
314   return iter;
315 }
316
317 void ShadowButton::ResetVisual(
318   Property::Index        index,
319   Visual::Base&          visual,
320   const Property::Value& value )
321 {
322   if( visual )
323   {
324     // we are replacing an existing visual, so force relayout
325     RelayoutRequest();
326   }
327   Property::Map* map = value.GetMap();
328   if( map )
329   {
330     visual = Toolkit::VisualFactory::Get().CreateVisual( *map );
331     RegisterVisual( index, visual );
332
333     // Set the appropriate depth index.
334     // @todo Should be able to set this from the style sheet
335     switch( index )
336     {
337       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
338       {
339         visual.SetDepthIndex(0.0f);
340         break;
341       }
342       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
343       {
344         visual.SetDepthIndex(1.0f);
345         break;
346       }
347       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
348       {
349         visual.SetDepthIndex(2.0f);
350         break;
351       }
352       case Demo::ShadowButton::Property::LABEL_VISUAL:
353       {
354         visual.SetDepthIndex(1.0f);
355         break;
356       }
357     }
358
359     // Extract transform maps out of the visual definition and store them
360     Property::Value* value = map->Find( DevelVisual::Property::TRANSFORM, "transform");
361     if( value )
362     {
363       Property::Map* transformMap = value->GetMap();
364       if( transformMap )
365       {
366         ShadowButton::Transforms::iterator iter = FindTransform( index );
367         if( iter != mTransforms.end() )
368         {
369           iter->mTransform = *transformMap;
370         }
371         else
372         {
373           mTransforms.push_back( Transform( index, *transformMap ) );
374         }
375       }
376     }
377   }
378 }
379
380 bool IsTransformProperty( const std::string& property )
381 {
382   const char* transformProperties[]= { "size", "offset", "origin", "anchorPoint", "offsetSizeMode" };
383   const int NUM_TRANSFORM_PROPERTIES = sizeof( transformProperties ) / sizeof( const char * );
384
385   bool found=false;
386   for( int i=0; i<NUM_TRANSFORM_PROPERTIES; ++i )
387   {
388     if( property == transformProperties[i] )
389     {
390       found = true;
391       break;
392     }
393   }
394   return found;
395 }
396
397 void ShadowButton::StoreTargetLayouts( TransitionData transitionData )
398 {
399   // Pseudo code
400   // foreach animator in transitionData
401   //   if animator{"property"} in [ "size", "offset", "origin", "anchorPoint", "offsetSizeMode" ]
402   //     transforms{ animator{"target"} }->{animator{"property"}} = animator{"targetValue"}
403
404
405   for( unsigned int i=0; i < transitionData.Count(); ++i )
406   {
407     Property::Map animator = transitionData.GetAnimatorAt(i);
408     Property::Value* target = animator.Find( "target" );
409     if( target )
410     {
411       // Convert to index
412       Property::Index index;
413       if( Scripting::GetEnumerationProperty( *target, VISUAL_PROPERTIES_TABLE, VISUAL_PROPERTIES_TABLE_COUNT, index ) )
414       {
415         ShadowButton::Transforms::iterator iter = FindTransform( index );
416         if( iter != mTransforms.end() )
417         {
418           Property::Value* property = animator.Find( "property" );
419           if( property )
420           {
421             std::string propertyString;
422             property->Get(propertyString);
423             if( IsTransformProperty( propertyString ) )
424             {
425               Property::Value* targetValue = animator.Find( "targetValue" );
426               if( targetValue )
427               {
428                 iter->mTransform[ propertyString ] = *targetValue;
429               }
430             }
431           }
432         }
433       }
434     }
435   }
436 }
437
438 void ShadowButton::ResetTransition(
439   Property::Index        index,
440   const Property::Value& value)
441 {
442   ShadowButton::Transitions::iterator iter = FindTransition( index );
443   if( iter != mTransitions.end() )
444   {
445     // Already exists
446     iter->mTransitionData = ConvertPropertyToTransition( value );
447     iter->mAnimation.Stop();
448     iter->mAnimation.Clear();
449   }
450   else
451   {
452     mTransitions.push_back( Transition( index, ConvertPropertyToTransition( value ) ) );
453   }
454 }
455
456
457 void ShadowButton::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
458 {
459   Demo::ShadowButton shadowButton = Demo::ShadowButton::DownCast( Dali::BaseHandle( object ) );
460
461   if( shadowButton )
462   {
463     ShadowButton& impl = GetImpl( shadowButton );
464     switch ( index )
465     {
466       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
467       {
468         impl.ResetVisual( index, impl.mBackgroundVisual, value );
469         break;
470       }
471       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
472       {
473         impl.ResetVisual( index, impl.mCheckboxBgVisual, value );
474         break;
475       }
476       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
477       {
478         impl.ResetVisual( index, impl.mCheckboxFgVisual, value );
479         impl.EnableVisual( Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL, impl.mCheckState );
480         break;
481       }
482       case Demo::ShadowButton::Property::LABEL_VISUAL:
483       {
484         impl.ResetVisual( index, impl.mLabelVisual, value );
485         break;
486       }
487       case Demo::ShadowButton::Property::ACTIVE_TRANSITION:
488       case Demo::ShadowButton::Property::INACTIVE_TRANSITION:
489       case Demo::ShadowButton::Property::CLICK_TRANSITION:
490       {
491         impl.ResetTransition( index, value );
492         break;
493       }
494     }
495   }
496 }
497
498 Property::Value ShadowButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
499 {
500   Property::Value value;
501
502   Demo::ShadowButton shadowButton = Demo::ShadowButton::DownCast( Dali::BaseHandle( object ) );
503
504   if ( shadowButton )
505   {
506     ShadowButton& impl = GetImpl( shadowButton );
507     switch ( propertyIndex )
508     {
509       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
510       {
511         Property::Map map;
512         impl.mBackgroundVisual.CreatePropertyMap(map);
513         value = map;
514         break;
515       }
516       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
517       {
518         Property::Map map;
519         impl.mCheckboxBgVisual.CreatePropertyMap(map);
520         value = map;
521         break;
522       }
523       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
524       {
525         Property::Map map;
526         impl.mCheckboxFgVisual.CreatePropertyMap(map);
527         value = map;
528         break;
529       }
530       case Demo::ShadowButton::Property::LABEL_VISUAL:
531       {
532         Property::Map map;
533         impl.mLabelVisual.CreatePropertyMap(map);
534         value = map;
535         break;
536       }
537
538       default:
539         break;
540     }
541   }
542
543   return value;
544 }
545
546
547 } // Internal
548 } // Demo