Changed some examples to use initializer list for Maps & Arrays
[platform/core/uifw/dali-demo.git] / examples / contact-cards / contact-card.cpp
1 /*
2  * Copyright (c) 2019 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
25 // INTERNAL INCLUDES
26 #include "contact-card-layout-info.h"
27 #include "clipped-image.h"
28 #include "masked-image.h"
29
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32
33 namespace
34 {
35 /*
36  * The constants below are used to create the following Unfold Animation.
37  *
38  * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
39  * |    |    |    |    |    |    |    |    |
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)
48  */
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
57
58 /*
59  * The constants below are used to create the following Fold Animation:
60  *
61  * 0ms  50  100  150  200  250  300  350  400 Total Animation time in Milliseconds
62  * |    |    |    |    |    |    |    |    |
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)
71  */
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
80
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
83
84 const Vector4 HEADER_COLOR( 231.0f/255.0f, 231.0f/255.0f, 231.0f/255.0f, 1.0f ); ///< The color of the header
85
86 } // unnamed namespace
87
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 )
94 : mTapDetector(),
95   mContactCard(),
96   mHeader(),
97   mClippedImage(),
98   mMaskedImage(),
99   mNameText(),
100   mDetailText(),
101   mAnimation(),
102   mSlotDelegate( this ),
103   mContactCardLayoutInfo( contactCardLayoutInfo ),
104   foldedPosition( position ),
105   mClippedImagePropertyIndex( Property::INVALID_INDEX ),
106   mFolded( true )
107 {
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 );
111
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{ { Toolkit::Visual::Property::TYPE, Visual::COLOR },
116                                            { 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 );
123
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{ { Toolkit::Visual::Property::TYPE, Visual::COLOR },
129                                       { 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 );
133
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 );
142
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 );
150
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 );
159
160   // Create the detail text-label
161   std::string detailString( contactName );
162   detailString += "\n\n";
163   detailString += contactAddress;
164
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 );
172
173   // Attach tap detection to the overall clip control
174   mTapDetector = TapGestureDetector::New();
175   mTapDetector.Attach( mContactCard );
176   mTapDetector.DetectedSignal().Connect( mSlotDelegate, &ContactCard::OnTap );
177 }
178
179 ContactCard::~ContactCard()
180 {
181   if( mContactCard )
182   {
183     mContactCard.Unparent();
184   }
185 }
186
187 void ContactCard::OnTap( Actor actor, const TapGesture& /* gesture */ )
188 {
189   if( actor == mContactCard )
190   {
191     Animate();
192   }
193 }
194
195 void ContactCard::Animate()
196 {
197   KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
198
199   mAnimation = Animation::New( 0.0f ); // Overall duration is unimportant as superseded by TimePeriods set later
200
201   if( mFolded )
202   {
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 );
205
206     mContactCard.Add( mHeader );
207     mContactCard.Add( mDetailText );
208
209     // Show clipped-image to animate geometry and hide the masked-image
210     mClippedImage.SetVisible( true );
211     mMaskedImage.SetVisible( false );
212
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 );
218
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 );
222
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 );
227
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 );
232
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 );
237
238     // Fade out all the siblings
239     Actor parent = mContactCard.GetParent();
240     for( size_t i = 0; i < parent.GetChildCount(); ++i )
241     {
242       Actor sibling = parent.GetChildAt( i );
243       if( sibling != mContactCard )
244       {
245         mAnimation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 0.0f, ALPHA_FUNCTION_UNFOLD, TIME_PERIOD_UNFOLD_SIBLING_OPACITY );
246         sibling.SetSensitive( false );
247       }
248     }
249
250     mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
251     mAnimation.Play();
252   }
253   else
254   {
255     // Remove key-input-focus from our contact-card when we are folded
256     keyInputFocusManager.RemoveFocus( mContactCard );
257
258     mContactCard.Add( mNameText );
259
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 );
265
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 );
269
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 );
274
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 );
279
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 );
284
285     // Slowly fade in all the siblings
286     Actor parent = mContactCard.GetParent();
287     for( size_t i = 0; i < parent.GetChildCount(); ++i )
288     {
289       Actor sibling = parent.GetChildAt( i );
290       if( sibling != mContactCard )
291       {
292         mAnimation.AnimateTo( Property( sibling, Actor::Property::COLOR_ALPHA ), 1.0f, ALPHA_FUNCTION_FOLD, TIME_PERIOD_FOLD_SIBLING_OPACITY );
293         sibling.SetSensitive( true );
294       }
295     }
296
297     mAnimation.FinishedSignal().Connect( mSlotDelegate, &ContactCard::OnAnimationFinished );
298     mAnimation.Play();
299   }
300
301   mFolded = !mFolded;
302 }
303
304 void ContactCard::OnAnimationFinished( Animation& animation )
305 {
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 )
308   {
309     if( mFolded )
310     {
311       mHeader.Unparent();
312       mDetailText.Unparent();
313
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 );
317     }
318     else
319     {
320       mNameText.Unparent();
321     }
322     mAnimation.Reset();
323   }
324 }
325
326 void ContactCard::OnKeyEvent( const KeyEvent& event )
327 {
328   if( ( ! mFolded ) && // If we're folded then there's no need to do any more checking
329       ( event.state == KeyEvent::Down ) )
330   {
331     if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
332     {
333       KeyInputFocusManager keyInputFocusManager = KeyInputFocusManager::Get();
334       if( keyInputFocusManager.GetCurrentFocusControl() == mContactCard )
335       {
336         // Our contact-card is set to receive focus and we're unfolded so animate back to the folded state
337         Animate();
338       }
339     }
340   }
341 }