Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / contact-cards / contact-card.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
18 // CLASS HEADER
19 #include "contact-card.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
24 #include <dali/devel-api/actors/actor-devel.h>
25
26 // INTERNAL INCLUDES
27 #include "clipped-image.h"
28 #include "contact-card-layout-info.h"
29 #include "masked-image.h"
30
31 using namespace Dali;
32 using namespace Dali::Toolkit;
33
34 namespace
35 {
36 /*
37  * The constants below are used to create the following Unfold Animation.
38  *
39  * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
40  * |    |    |    |    |    |    |    |    |
41  * o-----------------------------------o   |  X Position Animation            ( 0ms To 360ms)
42  * |   o-----------------------------------o  Y Position Animation            (40ms To 400ms)
43  * o-----------------------------------o   |  Width Animation                 ( 0ms To 360ms)
44  * |   o-----------------------------------o  Height Animation                (40ms To 400ms)
45  * o-------o |    |    |    |    |    |    |  Fade out Name Text Animation    ( 0ms To  80ms)
46  * |       o-------o   |    |    |    |    |  Fade in Details Text Animation  (80ms To 160ms)
47  * o---------------o   |    |    |    |    |  Fade out other cards Animation  ( 0ms To 160ms)
48  * o---------------------------------------o  Mesh Morph Animation            ( 0ms To 400ms)
49  */
50 const TimePeriod TIME_PERIOD_UNFOLD_X(0.0f, 0.36f);               ///< Start at 0ms, duration 360ms
51 const TimePeriod TIME_PERIOD_UNFOLD_Y(0.04f, 0.36f);              ///< Start at 40ms, duration 360ms
52 const TimePeriod TIME_PERIOD_UNFOLD_WIDTH(0.0f, 0.36f);           ///< Start at 0ms, duration 360ms
53 const TimePeriod TIME_PERIOD_UNFOLD_HEIGHT(0.04f, 0.36f);         ///< Start at 40ms, duration 360ms
54 const TimePeriod TIME_PERIOD_UNFOLD_NAME_OPACITY(0.0f, 0.08f);    ///< Start at 0ms, duration 80ms
55 const TimePeriod TIME_PERIOD_UNFOLD_DETAIL_OPACITY(0.08f, 0.08f); ///< Start at 80ms, duration 80ms
56 const TimePeriod TIME_PERIOD_UNFOLD_SIBLING_OPACITY(0.0f, 0.08f); ///< Start at 0ms, duration 80ms
57 const TimePeriod TIME_PERIOD_UNFOLD_MESH_MORPH(0.0f, 0.4f);       ///< Start at 0ms, duration 400ms
58
59 /*
60  * The constants below are used to create the following Fold Animation:
61  *
62  * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
63  * |    |    |    |    |    |    |    |    |
64  * |    |o---------------------------------o  X Position Animation            ( 64ms To 400ms)
65  * o---------------------------------o|    |  Y Position Animation            (  0ms To 336ms)
66  * |    |o---------------------------------o  Width Animation                 ( 64ms To 400ms)
67  * o---------------------------------o|    |  Height Animation                (  0ms To 336ms)
68  * |       o-------o   |    |    |    |    |  Fade in Name Text animation     ( 80ms To 160ms)
69  * o-------o |    |    |    |    |    |    |  Fade out Details Text animation (  0ms To  80ms)
70  * |    |    |    |    |    |    | o-------o  Fade in other cards animation   (320ms To 400ms)
71  * o---------------------------------------o  Morph Animation                 (  0ms To 400ms)
72  */
73 const TimePeriod TIME_PERIOD_FOLD_X(0.064f, 0.336f);             ///< Start at 64ms, duration 336ms
74 const TimePeriod TIME_PERIOD_FOLD_Y(0.0f, 0.336f);               ///< Start at 0ms, duration 336ms
75 const TimePeriod TIME_PERIOD_FOLD_WIDTH(0.064f, 0.336f);         ///< Start at 64ms, duration 336ms
76 const TimePeriod TIME_PERIOD_FOLD_HEIGHT(0.0f, 0.336f);          ///< Start at 0ms, duration 336ms
77 const TimePeriod TIME_PERIOD_FOLD_NAME_OPACITY(0.08f, 0.08f);    ///< Start at 80ms, duration 80ms
78 const TimePeriod TIME_PERIOD_FOLD_DETAIL_OPACITY(0.0f, 0.08f);   ///< Start at 0ms, duration 80ms
79 const TimePeriod TIME_PERIOD_FOLD_SIBLING_OPACITY(0.32f, 0.08f); ///< Start at 320ms, duration 80ms
80 const TimePeriod TIME_PERIOD_FOLD_MESH_MORPH(0.0f, 0.4f);        ///< Start at 0ms, duration 400ms
81
82 AlphaFunction ALPHA_FUNCTION_UNFOLD(AlphaFunction::DEFAULT);   ///< Alpha function used for the Unfold Animation
83 AlphaFunction ALPHA_FUNCTION_FOLD(AlphaFunction::EASE_IN_OUT); ///< Alpha function used for the Fold Animation
84
85 const Vector4 HEADER_COLOR(231.0f / 255.0f, 231.0f / 255.0f, 231.0f / 255.0f, 1.0f); ///< The color of the header
86
87 } // unnamed namespace
88
89 ContactCard::ContactCard(
90   Dali::Window                 window,
91   const ContactCardLayoutInfo& contactCardLayoutInfo,
92   const std::string&           contactName,
93   const std::string&           contactAddress,
94   const std::string&           imagePath,
95   const Vector2&               position)
96 : mTapDetector(),
97   mContactCard(),
98   mHeader(),
99   mClippedImage(),
100   mMaskedImage(),
101   mNameText(),
102   mDetailText(),
103   mAnimation(),
104   mSlotDelegate(this),
105   mContactCardLayoutInfo(contactCardLayoutInfo),
106   foldedPosition(position),
107   mClippedImagePropertyIndex(Property::INVALID_INDEX),
108   mFolded(true)
109 {
110   // Connect to the window's key signal to allow Back and Escape to fold a contact card if it is unfolded
111   window.KeyEventSignal().Connect(mSlotDelegate, &ContactCard::OnKeyEvent);
112
113   // Create a control which will be used for the background and to clip the contents
114   mContactCard = Control::New();
115   mContactCard.SetProperty(Control::Property::BACKGROUND,
116                            Property::Map{{Toolkit::Visual::Property::TYPE, Visual::COLOR},
117                                          {ColorVisual::Property::MIX_COLOR, Color::WHITE}});
118   mContactCard.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
119   mContactCard.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
120   mContactCard.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
121   mContactCard.SetProperty(Actor::Property::POSITION, Vector2(foldedPosition.x, foldedPosition.y));
122   mContactCard.SetProperty(Actor::Property::SIZE, mContactCardLayoutInfo.foldedSize);
123   window.Add(mContactCard);
124
125   // Create the header which will be shown only when the contact is unfolded
126   mHeader = Control::New();
127   mHeader.SetProperty(Actor::Property::SIZE, mContactCardLayoutInfo.headerSize);
128   mHeader.SetProperty(Control::Property::BACKGROUND,
129                       Property::Map{{Toolkit::Visual::Property::TYPE, Visual::COLOR},
130                                     {ColorVisual::Property::MIX_COLOR, HEADER_COLOR}});
131   mHeader.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
132   mHeader.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
133   mHeader.SetProperty(Actor::Property::POSITION, Vector2(mContactCardLayoutInfo.headerFoldedPosition.x, mContactCardLayoutInfo.headerFoldedPosition.y));
134
135   // Create a clipped image (whose clipping can be animated)
136   mClippedImage = ClippedImage::Create(imagePath, mClippedImagePropertyIndex);
137   mClippedImage.SetProperty(Actor::Property::SIZE, mContactCardLayoutInfo.imageSize);
138   mClippedImage.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
139   mClippedImage.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
140   mClippedImage.SetProperty(Actor::Property::POSITION, Vector2(mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y));
141   mClippedImage.SetProperty(Actor::Property::VISIBLE, false); // Hide image as we only want to display it if we are animating or unfolded
142   mContactCard.Add(mClippedImage);
143
144   // Create an image with a mask which is to be used when the contact is folded
145   mMaskedImage = MaskedImage::Create(imagePath);
146   mMaskedImage.SetProperty(Actor::Property::SIZE, mContactCardLayoutInfo.imageSize);
147   mMaskedImage.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
148   mMaskedImage.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
149   mMaskedImage.SetProperty(Actor::Property::POSITION, Vector2(mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y));
150   mContactCard.Add(mMaskedImage);
151
152   // Add the text label for just the name
153   mNameText = TextLabel::New(contactName);
154   mNameText.SetStyleName("ContactNameTextLabel");
155   mNameText.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
156   mNameText.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
157   mNameText.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
158   mNameText.SetProperty(Actor::Property::POSITION, Vector2(mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y));
159   mContactCard.Add(mNameText);
160
161   // Create the detail text-label
162   std::string detailString(contactName);
163   detailString += "\n\n";
164   detailString += contactAddress;
165
166   mDetailText = TextLabel::New(detailString);
167   mDetailText.SetStyleName("ContactDetailTextLabel");
168   mDetailText.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
169   mDetailText.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
170   mDetailText.SetProperty(Actor::Property::POSITION, Vector2(mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y));
171   mDetailText.SetProperty(Actor::Property::SIZE, Vector2(mContactCardLayoutInfo.unfoldedSize.width - mContactCardLayoutInfo.textFoldedPosition.x * 2.0f, 0.0f));
172   mDetailText.SetProperty(Actor::Property::OPACITY, 0.0f);
173
174   // Attach tap detection to the overall clip control
175   mTapDetector = TapGestureDetector::New();
176   mTapDetector.Attach(mContactCard);
177   mTapDetector.DetectedSignal().Connect(mSlotDelegate, &ContactCard::OnTap);
178 }
179
180 ContactCard::~ContactCard()
181 {
182   if(mContactCard)
183   {
184     mContactCard.Unparent();
185   }
186 }
187
188 void ContactCard::OnTap(Actor actor, const TapGesture& /* gesture */)
189 {
190   if(actor == mContactCard)
191   {
192     Animate();
193   }
194 }
195
196 void ContactCard::Animate()
197 {
198   KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
199
200   mAnimation = Animation::New(0.0f); // Overall duration is unimportant as superseded by TimePeriods set later
201
202   if(mFolded)
203   {
204     // Set key-input-focus to our contact-card so that we can fold the contact-card if we receive a Back or Esc key
205     keyInputFocusManager.SetFocus(mContactCard);
206
207     mContactCard.Add(mHeader);
208     mContactCard.Add(mDetailText);
209
210     // Show clipped-image to animate geometry and hide the masked-image
211     mClippedImage.SetProperty(Actor::Property::VISIBLE, true);
212     mMaskedImage.SetProperty(Actor::Property::VISIBLE, false);
213
214     // Animate the size of the control (and clipping area)
215     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::POSITION_X), mContactCardLayoutInfo.unfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X);
216     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::POSITION_Y), mContactCardLayoutInfo.unfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y);
217     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::SIZE_WIDTH), mContactCardLayoutInfo.unfoldedSize.width, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_WIDTH);
218     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::SIZE_HEIGHT), mContactCardLayoutInfo.unfoldedSize.height, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_HEIGHT);
219
220     // Animate the header area into position
221     mAnimation.AnimateTo(Property(mHeader, Actor::Property::POSITION_X), mContactCardLayoutInfo.headerUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X);
222     mAnimation.AnimateTo(Property(mHeader, Actor::Property::POSITION_Y), mContactCardLayoutInfo.headerUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y);
223
224     // Animate the clipped image into the unfolded position and into a quad
225     mAnimation.AnimateTo(Property(mClippedImage, Actor::Property::POSITION_X), mContactCardLayoutInfo.imageUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X);
226     mAnimation.AnimateTo(Property(mClippedImage, Actor::Property::POSITION_Y), mContactCardLayoutInfo.imageUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y);
227     mAnimation.AnimateTo(Property(mClippedImage, mClippedImagePropertyIndex), ClippedImage::QUAD_GEOMETRY, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_MESH_MORPH);
228
229     // Fade out the opacity of the name, and animate into the unfolded position
230     mAnimation.AnimateTo(Property(mNameText, Actor::Property::COLOR_ALPHA), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_NAME_OPACITY);
231     mAnimation.AnimateTo(Property(mNameText, Actor::Property::POSITION_X), mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X);
232     mAnimation.AnimateTo(Property(mNameText, Actor::Property::POSITION_Y), mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y);
233
234     // Fade in the opacity of the detail, and animate into the unfolded position
235     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::COLOR_ALPHA), 1.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_DETAIL_OPACITY);
236     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::POSITION_X), mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X);
237     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::POSITION_Y), mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y);
238
239     // Fade out all the siblings
240     Actor parent = mContactCard.GetParent();
241     for(size_t i = 0; i < parent.GetChildCount(); ++i)
242     {
243       Actor sibling = parent.GetChildAt(i);
244       if(sibling != mContactCard)
245       {
246         mAnimation.AnimateTo(Property(sibling, Actor::Property::COLOR_ALPHA), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_SIBLING_OPACITY);
247         sibling.SetProperty(Actor::Property::SENSITIVE, false);
248       }
249     }
250
251     mAnimation.FinishedSignal().Connect(mSlotDelegate, &ContactCard::OnAnimationFinished);
252     mAnimation.Play();
253   }
254   else
255   {
256     // Remove key-input-focus from our contact-card when we are folded
257     keyInputFocusManager.RemoveFocus(mContactCard);
258
259     mContactCard.Add(mNameText);
260
261     // Animate the size of the control (and clipping area)
262     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::POSITION_X), foldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X);
263     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::POSITION_Y), foldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y);
264     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::SIZE_WIDTH), mContactCardLayoutInfo.foldedSize.width, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_WIDTH);
265     mAnimation.AnimateTo(Property(mContactCard, Actor::Property::SIZE_HEIGHT), mContactCardLayoutInfo.foldedSize.height, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_HEIGHT);
266
267     // Animate the header area out of position
268     mAnimation.AnimateTo(Property(mHeader, Actor::Property::POSITION_X), mContactCardLayoutInfo.headerFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X);
269     mAnimation.AnimateTo(Property(mHeader, Actor::Property::POSITION_Y), mContactCardLayoutInfo.headerFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y);
270
271     // Animate the clipped image into the folded position and into a circle
272     mAnimation.AnimateTo(Property(mClippedImage, Actor::Property::POSITION_X), mContactCardLayoutInfo.imageFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X);
273     mAnimation.AnimateTo(Property(mClippedImage, Actor::Property::POSITION_Y), mContactCardLayoutInfo.imageFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y);
274     mAnimation.AnimateTo(Property(mClippedImage, mClippedImagePropertyIndex), ClippedImage::CIRCLE_GEOMETRY, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_MESH_MORPH);
275
276     // Fade in the opacity of the name, and animate into the folded position
277     mAnimation.AnimateTo(Property(mNameText, Actor::Property::COLOR_ALPHA), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_NAME_OPACITY);
278     mAnimation.AnimateTo(Property(mNameText, Actor::Property::POSITION_X), mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X);
279     mAnimation.AnimateTo(Property(mNameText, Actor::Property::POSITION_Y), mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y);
280
281     // Fade out the opacity of the detail, and animate into the folded position
282     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::COLOR_ALPHA), 0.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_DETAIL_OPACITY);
283     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::POSITION_X), mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X);
284     mAnimation.AnimateTo(Property(mDetailText, Actor::Property::POSITION_Y), mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y);
285
286     // Slowly fade in all the siblings
287     Actor parent = mContactCard.GetParent();
288     for(size_t i = 0; i < parent.GetChildCount(); ++i)
289     {
290       Actor sibling = parent.GetChildAt(i);
291       if(sibling != mContactCard)
292       {
293         mAnimation.AnimateTo(Property(sibling, Actor::Property::COLOR_ALPHA), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_SIBLING_OPACITY);
294         sibling.SetProperty(Actor::Property::SENSITIVE, true);
295       }
296     }
297
298     mAnimation.FinishedSignal().Connect(mSlotDelegate, &ContactCard::OnAnimationFinished);
299     mAnimation.Play();
300   }
301
302   mFolded = !mFolded;
303 }
304
305 void ContactCard::OnAnimationFinished(Animation& animation)
306 {
307   // Ensure the finishing animation is the latest as we do not want to change state if a previous animation has finished
308   if(mAnimation == animation)
309   {
310     if(mFolded)
311     {
312       mHeader.Unparent();
313       mDetailText.Unparent();
314
315       // Hide the clipped-image as we have finished animating the geometry and show the masked-image again
316       mClippedImage.SetProperty(Actor::Property::VISIBLE, false);
317       mMaskedImage.SetProperty(Actor::Property::VISIBLE, true);
318     }
319     else
320     {
321       mNameText.Unparent();
322     }
323     mAnimation.Reset();
324   }
325 }
326
327 void ContactCard::OnKeyEvent(const KeyEvent& event)
328 {
329   if((!mFolded) && // If we're folded then there's no need to do any more checking
330      (event.GetState() == KeyEvent::DOWN))
331   {
332     if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
333     {
334       KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
335       if(keyInputFocusManager.GetCurrentFocusControl() == mContactCard)
336       {
337         // Our contact-card is set to receive focus and we're unfolded so animate back to the folded state
338         Animate();
339       }
340     }
341   }
342 }