Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / transitions / shadow-button-impl.cpp
1 /*
2  * Copyright (c) 2020 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   ShadowButton::Transitions::iterator iter          = mTransitions.begin();
225   for(; iter != mTransitions.end(); ++iter)
226   {
227     if(iter->mPlaying == true)
228     {
229       transitioning = true;
230       break;
231     }
232   }
233
234   if(!transitioning)
235   {
236     for(ShadowButton::Transforms::iterator iter = mTransforms.begin();
237         iter != mTransforms.end();
238         ++iter)
239     {
240       switch(iter->mTransformId)
241       {
242         case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
243         {
244           mBackgroundVisual.SetTransformAndSize(iter->mTransform, targetSize);
245           break;
246         }
247         case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
248         {
249           mCheckboxBgVisual.SetTransformAndSize(iter->mTransform, targetSize);
250           break;
251         }
252         case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
253         {
254           mCheckboxFgVisual.SetTransformAndSize(iter->mTransform, targetSize);
255           break;
256         }
257         case Demo::ShadowButton::Property::LABEL_VISUAL:
258         {
259           mLabelVisual.SetTransformAndSize(iter->mTransform, targetSize);
260           break;
261         }
262       }
263     }
264   }
265 }
266
267 Vector3 ShadowButton::GetNaturalSize()
268 {
269   int width;
270   int height;
271
272   Vector2 checkboxBgSize;
273   Vector2 checkboxFgSize;
274   Vector2 labelSize;
275   mCheckboxBgVisual.GetNaturalSize(checkboxBgSize);
276   mCheckboxFgVisual.GetNaturalSize(checkboxFgSize);
277   mLabelVisual.GetNaturalSize(labelSize);
278
279   width  = std::max(checkboxBgSize.x, checkboxFgSize.x) + labelSize.x;
280   height = std::max(std::max(checkboxFgSize.y, checkboxBgSize.y), labelSize.y);
281
282   return Vector3(width, height, height);
283 }
284
285 void ShadowButton::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
286 {
287   // Chain up.
288   Control::OnStyleChange(styleManager, change);
289 }
290
291 ShadowButton::Transitions::iterator ShadowButton::FindTransition(Property::Index index)
292 {
293   bool                                found = false;
294   ShadowButton::Transitions::iterator iter  = mTransitions.begin();
295   for(; iter != mTransitions.end(); ++iter)
296   {
297     if(iter->mTransitionId == index)
298     {
299       found = true;
300       break;
301     }
302   }
303   if(!found)
304   {
305     iter = mTransitions.end();
306   }
307   return iter;
308 }
309
310 ShadowButton::Transforms::iterator ShadowButton::FindTransform(Property::Index index)
311 {
312   bool                               found = false;
313   ShadowButton::Transforms::iterator iter  = mTransforms.begin();
314   for(; iter != mTransforms.end(); ++iter)
315   {
316     if(iter->mTransformId == index)
317     {
318       found = true;
319       break;
320     }
321   }
322   if(!found)
323   {
324     iter = mTransforms.end();
325   }
326   return iter;
327 }
328
329 void ShadowButton::ResetVisual(
330   Property::Index        index,
331   Visual::Base&          visual,
332   const Property::Value& value)
333 {
334   if(visual)
335   {
336     // we are replacing an existing visual, so force relayout
337     RelayoutRequest();
338   }
339   Property::Map* map = value.GetMap();
340   if(map)
341   {
342     visual = Toolkit::VisualFactory::Get().CreateVisual(*map);
343
344     // Set the appropriate depth index.
345     // @todo Should be able to set this from the style sheet
346     switch(index)
347     {
348       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
349       {
350         DevelControl::RegisterVisual(*this, index, visual, 0);
351         break;
352       }
353       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
354       {
355         DevelControl::RegisterVisual(*this, index, visual, 1);
356         break;
357       }
358       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
359       {
360         DevelControl::RegisterVisual(*this, index, visual, mCheckState, 2);
361         break;
362       }
363       case Demo::ShadowButton::Property::LABEL_VISUAL:
364       {
365         DevelControl::RegisterVisual(*this, index, visual, 1);
366         break;
367       }
368     }
369
370     // Extract transform maps out of the visual definition and store them
371     Property::Value* value = map->Find(Visual::Property::TRANSFORM, "transform");
372     if(value)
373     {
374       Property::Map* transformMap = value->GetMap();
375       if(transformMap)
376       {
377         ShadowButton::Transforms::iterator iter = FindTransform(index);
378         if(iter != mTransforms.end())
379         {
380           iter->mTransform = *transformMap;
381         }
382         else
383         {
384           mTransforms.push_back(Transform(index, *transformMap));
385         }
386       }
387     }
388   }
389 }
390
391 bool IsTransformProperty(const std::string& property)
392 {
393   const char* transformProperties[]    = {"size", "offset", "origin", "anchorPoint", "offsetPolicy", "sizePolicy"};
394   const int   NUM_TRANSFORM_PROPERTIES = sizeof(transformProperties) / sizeof(const char*);
395
396   bool found = false;
397   for(int i = 0; i < NUM_TRANSFORM_PROPERTIES; ++i)
398   {
399     if(property == transformProperties[i])
400     {
401       found = true;
402       break;
403     }
404   }
405   return found;
406 }
407
408 void ShadowButton::StoreTargetLayouts(TransitionData transitionData)
409 {
410   // Pseudo code
411   // foreach animator in transitionData
412   //   if animator{"property"} in [ "size", "offset", "origin", "anchorPoint", "offsetPolicy", "sizePolicy" ]
413   //     transforms{ animator{"target"} }->{animator{"property"}} = animator{"targetValue"}
414
415   for(unsigned int i = 0; i < transitionData.Count(); ++i)
416   {
417     Property::Map    animator = transitionData.GetAnimatorAt(i);
418     Property::Value* target   = animator.Find("target");
419     if(target)
420     {
421       // Convert to index
422       Property::Index index = Property::INVALID_INDEX;
423       if(Scripting::GetEnumerationProperty(*target, VISUAL_PROPERTIES_TABLE, VISUAL_PROPERTIES_TABLE_COUNT, index))
424       {
425         ShadowButton::Transforms::iterator iter = FindTransform(index);
426         if(iter != mTransforms.end())
427         {
428           Property::Value* property = animator.Find("property");
429           if(property)
430           {
431             std::string propertyString;
432             property->Get(propertyString);
433             if(IsTransformProperty(propertyString))
434             {
435               Property::Value* targetValue = animator.Find("targetValue");
436               if(targetValue)
437               {
438                 iter->mTransform[propertyString] = *targetValue;
439               }
440             }
441           }
442         }
443       }
444     }
445   }
446 }
447
448 void ShadowButton::ResetTransition(
449   Property::Index        index,
450   const Property::Value& value)
451 {
452   ShadowButton::Transitions::iterator iter = FindTransition(index);
453   if(iter != mTransitions.end())
454   {
455     // Already exists
456     iter->mTransitionData = ConvertPropertyToTransition(value);
457     iter->mAnimation.Stop();
458     iter->mAnimation.Clear();
459   }
460   else
461   {
462     mTransitions.push_back(Transition(index, ConvertPropertyToTransition(value)));
463   }
464 }
465
466 void ShadowButton::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
467 {
468   Demo::ShadowButton shadowButton = Demo::ShadowButton::DownCast(Dali::BaseHandle(object));
469
470   if(shadowButton)
471   {
472     ShadowButton& impl = GetImpl(shadowButton);
473     switch(index)
474     {
475       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
476       {
477         impl.ResetVisual(index, impl.mBackgroundVisual, value);
478         break;
479       }
480       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
481       {
482         impl.ResetVisual(index, impl.mCheckboxBgVisual, value);
483         break;
484       }
485       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
486       {
487         impl.ResetVisual(index, impl.mCheckboxFgVisual, value);
488         DevelControl::EnableVisual(impl, Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL, impl.mCheckState);
489         break;
490       }
491       case Demo::ShadowButton::Property::LABEL_VISUAL:
492       {
493         impl.ResetVisual(index, impl.mLabelVisual, value);
494         break;
495       }
496       case Demo::ShadowButton::Property::ACTIVE_TRANSITION:
497       case Demo::ShadowButton::Property::INACTIVE_TRANSITION:
498       case Demo::ShadowButton::Property::CHECK_TRANSITION:
499       case Demo::ShadowButton::Property::UNCHECK_TRANSITION:
500       {
501         impl.ResetTransition(index, value);
502         break;
503       }
504     }
505   }
506 }
507
508 Property::Value ShadowButton::GetProperty(BaseObject* object, Property::Index propertyIndex)
509 {
510   Property::Value value;
511
512   Demo::ShadowButton shadowButton = Demo::ShadowButton::DownCast(Dali::BaseHandle(object));
513
514   if(shadowButton)
515   {
516     ShadowButton& impl = GetImpl(shadowButton);
517     switch(propertyIndex)
518     {
519       case Demo::ShadowButton::Property::BACKGROUND_VISUAL:
520       {
521         Property::Map map;
522         impl.mBackgroundVisual.CreatePropertyMap(map);
523         value = map;
524         break;
525       }
526       case Demo::ShadowButton::Property::CHECKBOX_BG_VISUAL:
527       {
528         Property::Map map;
529         impl.mCheckboxBgVisual.CreatePropertyMap(map);
530         value = map;
531         break;
532       }
533       case Demo::ShadowButton::Property::CHECKBOX_FG_VISUAL:
534       {
535         Property::Map map;
536         impl.mCheckboxFgVisual.CreatePropertyMap(map);
537         value = map;
538         break;
539       }
540       case Demo::ShadowButton::Property::LABEL_VISUAL:
541       {
542         Property::Map map;
543         impl.mLabelVisual.CreatePropertyMap(map);
544         value = map;
545         break;
546       }
547
548       default:
549         break;
550     }
551   }
552
553   return value;
554 }
555
556 } // namespace Internal
557 } // namespace Demo