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