2 * Copyright (c) 2018 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>
26 #include "contact-card-layout-info.h"
27 #include "clipped-image.h"
28 #include "masked-image.h"
31 using namespace Dali::Toolkit;
36 * The constants below are used to create the following Unfold Animation.
38 * 0ms 50 100 150 200 250 300 350 400 Total Animation time in Milliseconds
40 * o-----------------------------------o | X Position Animation ( 0ms To 360ms)
41 * | o-----------------------------------o Y Position Animation (40ms To 400ms)
42 * o-----------------------------------o | Width Animation ( 0ms To 360ms)
43 * | o-----------------------------------o Height Animation (40ms To 400ms)
44 * o-------o | | | | | | | Fade out Name Text Animation ( 0ms To 80ms)
45 * | o-------o | | | | | Fade in Details Text Animation (80ms To 160ms)
46 * o---------------o | | | | | Fade out other cards Animation ( 0ms To 160ms)
47 * o---------------------------------------o Mesh Morph Animation ( 0ms To 400ms)
49 const TimePeriod TIME_PERIOD_UNFOLD_X( 0.0f, 0.36f ); ///< Start at 0ms, duration 360ms
50 const TimePeriod TIME_PERIOD_UNFOLD_Y( 0.04f, 0.36f ); ///< Start at 40ms, duration 360ms
51 const TimePeriod TIME_PERIOD_UNFOLD_WIDTH( 0.0f, 0.36f ); ///< Start at 0ms, duration 360ms
52 const TimePeriod TIME_PERIOD_UNFOLD_HEIGHT( 0.04f, 0.36f ); ///< Start at 40ms, duration 360ms
53 const TimePeriod TIME_PERIOD_UNFOLD_NAME_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
54 const TimePeriod TIME_PERIOD_UNFOLD_DETAIL_OPACITY( 0.08f, 0.08f ); ///< Start at 80ms, duration 80ms
55 const TimePeriod TIME_PERIOD_UNFOLD_SIBLING_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
56 const TimePeriod TIME_PERIOD_UNFOLD_MESH_MORPH( 0.0f, 0.4f ); ///< Start at 0ms, duration 400ms
59 * The constants below are used to create the following Fold Animation:
61 * 0ms 50 100 150 200 250 300 350 400 Total Animation time in Milliseconds
63 * | |o---------------------------------o X Position Animation ( 64ms To 400ms)
64 * o---------------------------------o| | Y Position Animation ( 0ms To 336ms)
65 * | |o---------------------------------o Width Animation ( 64ms To 400ms)
66 * o---------------------------------o| | Height Animation ( 0ms To 336ms)
67 * | o-------o | | | | | Fade in Name Text animation ( 80ms To 160ms)
68 * o-------o | | | | | | | Fade out Details Text animation ( 0ms To 80ms)
69 * | | | | | | | o-------o Fade in other cards animation (320ms To 400ms)
70 * o---------------------------------------o Morph Animation ( 0ms To 400ms)
72 const TimePeriod TIME_PERIOD_FOLD_X( 0.064f, 0.336f ); ///< Start at 64ms, duration 336ms
73 const TimePeriod TIME_PERIOD_FOLD_Y( 0.0f, 0.336f ); ///< Start at 0ms, duration 336ms
74 const TimePeriod TIME_PERIOD_FOLD_WIDTH( 0.064f, 0.336f ); ///< Start at 64ms, duration 336ms
75 const TimePeriod TIME_PERIOD_FOLD_HEIGHT( 0.0f, 0.336f ); ///< Start at 0ms, duration 336ms
76 const TimePeriod TIME_PERIOD_FOLD_NAME_OPACITY( 0.08f, 0.08f ); ///< Start at 80ms, duration 80ms
77 const TimePeriod TIME_PERIOD_FOLD_DETAIL_OPACITY( 0.0f, 0.08f ); ///< Start at 0ms, duration 80ms
78 const TimePeriod TIME_PERIOD_FOLD_SIBLING_OPACITY( 0.32f, 0.08f ); ///< Start at 320ms, duration 80ms
79 const TimePeriod TIME_PERIOD_FOLD_MESH_MORPH( 0.0f, 0.4f ); ///< Start at 0ms, duration 400ms
81 AlphaFunction ALPHA_FUNCTION_UNFOLD( AlphaFunction::DEFAULT ); ///< Alpha function used for the Unfold Animation
82 AlphaFunction ALPHA_FUNCTION_FOLD( AlphaFunction::EASE_IN_OUT ); ///< Alpha function used for the Fold Animation
84 const Vector4 HEADER_COLOR( 231.0f/255.0f, 231.0f/255.0f, 231.0f/255.0f, 1.0f ); ///< The color of the header
86 } // unnamed namespace
88 ContactCard::ContactCard(
89 const ContactCardLayoutInfo& contactCardLayoutInfo,
90 const std::string& contactName,
91 const std::string& contactAddress,
92 const std::string& imagePath,
93 const Vector2& position )
102 mSlotDelegate( this ),
103 mContactCardLayoutInfo( contactCardLayoutInfo ),
104 foldedPosition( position ),
105 mClippedImagePropertyIndex( Property::INVALID_INDEX ),
108 // Connect to the stage's key signal to allow Back and Escape to fold a contact card if it is unfolded
109 Stage stage = Stage::GetCurrent();
110 stage.KeyEventSignal().Connect( mSlotDelegate, &ContactCard::OnKeyEvent );
112 // Create a control which will be used for the background and to clip the contents
113 mContactCard = Control::New();
114 mContactCard.SetProperty( Control::Property::BACKGROUND,
115 Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::COLOR )
116 .Add( ColorVisual::Property::MIX_COLOR, Color::WHITE ) );
117 mContactCard.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
118 mContactCard.SetParentOrigin( ParentOrigin::TOP_LEFT );
119 mContactCard.SetAnchorPoint( AnchorPoint::TOP_LEFT );
120 mContactCard.SetPosition( foldedPosition.x, foldedPosition.y );
121 mContactCard.SetSize( mContactCardLayoutInfo.foldedSize );
122 stage.Add( mContactCard );
124 // Create the header which will be shown only when the contact is unfolded
125 mHeader = Control::New();
126 mHeader.SetSize( mContactCardLayoutInfo.headerSize );
127 mHeader.SetProperty( Control::Property::BACKGROUND,
128 Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::COLOR )
129 .Add( ColorVisual::Property::MIX_COLOR, HEADER_COLOR ) );
130 mHeader.SetParentOrigin( ParentOrigin::TOP_LEFT );
131 mHeader.SetAnchorPoint( AnchorPoint::TOP_LEFT );
132 mHeader.SetPosition( mContactCardLayoutInfo.headerFoldedPosition.x, mContactCardLayoutInfo.headerFoldedPosition.y );
134 // Create a clipped image (whose clipping can be animated)
135 mClippedImage = ClippedImage::Create( imagePath, mClippedImagePropertyIndex );
136 mClippedImage.SetSize( mContactCardLayoutInfo.imageSize );
137 mClippedImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
138 mClippedImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
139 mClippedImage.SetPosition( mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y );
140 mClippedImage.SetVisible( false ); // Hide image as we only want to display it if we are animating or unfolded
141 mContactCard.Add( mClippedImage );
143 // Create an image with a mask which is to be used when the contact is folded
144 mMaskedImage = MaskedImage::Create( imagePath );
145 mMaskedImage.SetSize( mContactCardLayoutInfo.imageSize );
146 mMaskedImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
147 mMaskedImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
148 mMaskedImage.SetPosition( mContactCardLayoutInfo.imageFoldedPosition.x, mContactCardLayoutInfo.imageFoldedPosition.y );
149 mContactCard.Add( mMaskedImage );
151 // Add the text label for just the name
152 mNameText = TextLabel::New( contactName );
153 mNameText.SetStyleName( "ContactNameTextLabel" );
154 mNameText.SetParentOrigin( ParentOrigin::TOP_LEFT );
155 mNameText.SetAnchorPoint( AnchorPoint::TOP_LEFT );
156 mNameText.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
157 mNameText.SetPosition( mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y );
158 mContactCard.Add( mNameText );
160 // Create the detail text-label
161 std::string detailString( contactName );
162 detailString += "\n\n";
163 detailString += contactAddress;
165 mDetailText = TextLabel::New( detailString );
166 mDetailText.SetStyleName( "ContactDetailTextLabel" );
167 mDetailText.SetParentOrigin( ParentOrigin::TOP_LEFT );
168 mDetailText.SetAnchorPoint( AnchorPoint::TOP_LEFT );
169 mDetailText.SetPosition( mContactCardLayoutInfo.textFoldedPosition.x, mContactCardLayoutInfo.textFoldedPosition.y );
170 mDetailText.SetSize( Vector2( mContactCardLayoutInfo.unfoldedSize.width - mContactCardLayoutInfo.textFoldedPosition.x * 2.0f, 0.0f ) );
171 mDetailText.SetOpacity( 0.0f );
173 // Attach tap detection to the overall clip control
174 mTapDetector = TapGestureDetector::New();
175 mTapDetector.Attach( mContactCard );
176 mTapDetector.DetectedSignal().Connect( mSlotDelegate, &ContactCard::OnTap );
179 ContactCard::~ContactCard()
183 mContactCard.Unparent();
187 void ContactCard::OnTap( Actor actor, const TapGesture& /* gesture */ )
189 if( actor == mContactCard )
195 void ContactCard::Animate()
197 KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
199 mAnimation = Animation::New( 0.0f ); // Overall duration is unimportant as superseded by TimePeriods set later
203 // Set key-input-focus to our contact-card so that we can fold the contact-card if we receive a Back or Esc key
204 keyInputFocusManager.SetFocus( mContactCard );
206 mContactCard.Add( mHeader );
207 mContactCard.Add( mDetailText );
209 // Show clipped-image to animate geometry and hide the masked-image
210 mClippedImage.SetVisible( true );
211 mMaskedImage.SetVisible( false );
213 // Animate the size of the control (and clipping area)
214 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ), mContactCardLayoutInfo.unfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
215 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.unfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
216 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ), mContactCardLayoutInfo.unfoldedSize.width, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_WIDTH );
217 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_HEIGHT ), mContactCardLayoutInfo.unfoldedSize.height, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_HEIGHT );
219 // Animate the header area into position
220 mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
221 mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.headerUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
223 // Animate the clipped image into the unfolded position and into a quad
224 mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ), mContactCardLayoutInfo.imageUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
225 mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.imageUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
226 mAnimation.AnimateTo( Property( mClippedImage, mClippedImagePropertyIndex ), ClippedImage::QUAD_GEOMETRY, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_MESH_MORPH );
228 // Fade out the opacity of the name, and animate into the unfolded position
229 mAnimation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_NAME_OPACITY );
230 mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ), mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
231 mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
233 // Fade in the opacity of the detail, and animate into the unfolded position
234 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_DETAIL_OPACITY );
235 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ), mContactCardLayoutInfo.textUnfoldedPosition.x, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_X );
236 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.textUnfoldedPosition.y, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_Y );
238 // Fade out all the siblings
239 Actor parent = mContactCard.GetParent();
240 for( size_t i = 0; i < parent.GetChildCount(); ++i )
242 Actor sibling = parent.GetChildAt( i );
243 if( sibling != mContactCard )
245 mAnimation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_SIBLING_OPACITY );
246 sibling.SetSensitive( false );
250 mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
255 // Remove key-input-focus from our contact-card when we are folded
256 keyInputFocusManager.RemoveFocus( mContactCard );
258 mContactCard.Add( mNameText );
260 // Animate the size of the control (and clipping area)
261 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_X ), foldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
262 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::POSITION_Y ), foldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
263 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_WIDTH ), mContactCardLayoutInfo.foldedSize.width, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_WIDTH );
264 mAnimation.AnimateTo( Property( mContactCard, Actor::Property::SIZE_HEIGHT ), mContactCardLayoutInfo.foldedSize.height, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_HEIGHT );
266 // Animate the header area out of position
267 mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_X ), mContactCardLayoutInfo.headerFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
268 mAnimation.AnimateTo( Property( mHeader, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.headerFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
270 // Animate the clipped image into the folded position and into a circle
271 mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_X ), mContactCardLayoutInfo.imageFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
272 mAnimation.AnimateTo( Property( mClippedImage, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.imageFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
273 mAnimation.AnimateTo( Property( mClippedImage, mClippedImagePropertyIndex ), ClippedImage::CIRCLE_GEOMETRY, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_MESH_MORPH );
275 // Fade in the opacity of the name, and animate into the folded position
276 mAnimation.AnimateTo( Property( mNameText, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_NAME_OPACITY );
277 mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_X ), mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
278 mAnimation.AnimateTo( Property( mNameText, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
280 // Fade out the opacity of the detail, and animate into the folded position
281 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_DETAIL_OPACITY );
282 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_X ), mContactCardLayoutInfo.textFoldedPosition.x, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_X );
283 mAnimation.AnimateTo( Property( mDetailText, Actor::Property::POSITION_Y ), mContactCardLayoutInfo.textFoldedPosition.y, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_Y );
285 // Slowly fade in all the siblings
286 Actor parent = mContactCard.GetParent();
287 for( size_t i = 0; i < parent.GetChildCount(); ++i )
289 Actor sibling = parent.GetChildAt( i );
290 if( sibling != mContactCard )
292 mAnimation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_SIBLING_OPACITY );
293 sibling.SetSensitive( true );
297 mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
304 void ContactCard::OnAnimationFinished( Animation& animation )
306 // Ensure the finishing animation is the latest as we do not want to change state if a previous animation has finished
307 if( mAnimation == animation )
312 mDetailText.Unparent();
314 // Hide the clipped-image as we have finished animating the geometry and show the masked-image again
315 mClippedImage.SetVisible( false );
316 mMaskedImage.SetVisible( true );
320 mNameText.Unparent();
326 void ContactCard::OnKeyEvent( const KeyEvent& event )
328 if( ( ! mFolded ) && // If we're folded then there's no need to do any more checking
329 ( event.state == KeyEvent::Down ) )
331 if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
333 KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
334 if( keyInputFocusManager.GetCurrentFocusControl() == mContactCard )
336 // Our contact-card is set to receive focus and we're unfolded so animate back to the folded state