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