2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "contact-card.h"
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>
27 #include "clipped-image.h"
28 #include "contact-card-layout-info.h"
29 #include "masked-image.h"
32 using namespace Dali::Toolkit;
37 * The constants below are used to create the following Unfold Animation.
39 * 0ms 50 100 150 200 250 300 350 400 Total Animation time in Milliseconds
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)
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
60 * The constants below are used to create the following Fold Animation:
62 * 0ms 50 100 150 200 250 300 350 400 Total Animation time in Milliseconds
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)
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
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
85 const Vector4 HEADER_COLOR(231.0f / 255.0f, 231.0f / 255.0f, 231.0f / 255.0f, 1.0f); ///< The color of the header
87 } // unnamed namespace
89 ContactCard::ContactCard(
91 const ContactCardLayoutInfo& contactCardLayoutInfo,
92 const std::string& contactName,
93 const std::string& contactAddress,
94 const std::string& imagePath,
95 const Vector2& position)
105 mContactCardLayoutInfo(contactCardLayoutInfo),
106 foldedPosition(position),
107 mClippedImagePropertyIndex(Property::INVALID_INDEX),
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);
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);
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));
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);
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);
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);
161 // Create the detail text-label
162 std::string detailString(contactName);
163 detailString += "\n\n";
164 detailString += contactAddress;
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);
174 // Attach tap detection to the overall clip control
175 mTapDetector = TapGestureDetector::New();
176 mTapDetector.Attach(mContactCard);
177 mTapDetector.DetectedSignal().Connect(mSlotDelegate, &ContactCard::OnTap);
180 ContactCard::~ContactCard()
184 mContactCard.Unparent();
188 void ContactCard::OnTap(Actor actor, const TapGesture& /* gesture */)
190 if(actor == mContactCard)
196 void ContactCard::Animate()
198 KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
200 mAnimation = Animation::New(0.0f); // Overall duration is unimportant as superseded by TimePeriods set later
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);
207 mContactCard.Add(mHeader);
208 mContactCard.Add(mDetailText);
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);
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);
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);
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);
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);
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);
239 // Fade out all the siblings
240 Actor parent = mContactCard.GetParent();
241 for(size_t i = 0; i < parent.GetChildCount(); ++i)
243 Actor sibling = parent.GetChildAt(i);
244 if(sibling != mContactCard)
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);
251 mAnimation.FinishedSignal().Connect(mSlotDelegate, &ContactCard::OnAnimationFinished);
256 // Remove key-input-focus from our contact-card when we are folded
257 keyInputFocusManager.RemoveFocus(mContactCard);
259 mContactCard.Add(mNameText);
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);
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);
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);
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);
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);
286 // Slowly fade in all the siblings
287 Actor parent = mContactCard.GetParent();
288 for(size_t i = 0; i < parent.GetChildCount(); ++i)
290 Actor sibling = parent.GetChildAt(i);
291 if(sibling != mContactCard)
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);
298 mAnimation.FinishedSignal().Connect(mSlotDelegate, &ContactCard::OnAnimationFinished);
305 void ContactCard::OnAnimationFinished(Animation& animation)
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)
313 mDetailText.Unparent();
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);
321 mNameText.Unparent();
327 void ContactCard::OnKeyEvent(const KeyEvent& event)
329 if((!mFolded) && // If we're folded then there's no need to do any more checking
330 (event.GetState() == KeyEvent::DOWN))
332 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
334 KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
335 if(keyInputFocusManager.GetCurrentFocusControl() == mContactCard)
337 // Our contact-card is set to receive focus and we're unfolded so animate back to the folded state