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