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