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