Add 'ExclusiveArch: armv7l' limit build to arm architecture
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-input / text-input-popup-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 #include <dali-toolkit/internal/controls/text-input/text-input-popup-impl.h>
18 #include <dali-toolkit/public-api/controls/buttons/push-button.h>
19
20 using namespace std;
21 using namespace Dali;
22
23 namespace {
24
25 // Popup: Background
26 const char* DEFAULT_PANEL_BACKGROUND = DALI_IMAGE_DIR "cutCopyPastePopup_bg.png";
27
28 // Popup: Divider
29 const char* DEFAULT_PANEL_BUTTON_DIVIDER = DALI_IMAGE_DIR "copypanelLine.png";
30
31 /* Functionality in place to have the end buttons using different images to inner button.
32  * Supply a centre image and then a left and right image, the centre image can have straight ends while
33  * the left image can be rounded on the left and straight on the right, the right image can be straight on the left and rounded on the right.
34  */
35
36 // Popup: Left Pressed Highlight
37 const char* DEFAULT_BUTTON_HIGHLIGHT_LEFT( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
38 const Vector4 DEFAULT_BUTTON_HIGHLIGHT_LEFT_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
39
40 // Popup: Center Pressed Highlight
41 const char* DEFAULT_BUTTON_HIGHLIGHT_CENTER( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
42 const Vector4 DEFAULT_BUTTON_HIGHLIGHT_CENTER_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
43
44 // Popup: Right Pressed Highlight
45 const char* DEFAULT_BUTTON_HIGHLIGHT_RIGHT( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
46 const Vector4 DEFAULT_BUTTON_HIGHLIGHT_RIGHT_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
47
48 // Popup: Tails
49 const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "00_popup_bubble_tail_bottom.png" );
50
51 // Popup: Vertical Constraint
52 // TODO: Remove - this should come from application - it is not possible to get the
53 // height of the indicator actor from Dali-Toolkit.
54 const Vector2 DEFAULT_POPUP_INDICATOR_OFFSET(0.0f, 60.0f);
55
56 const Vector4 BACKGROUND_IMAGE_BORDER( 22.0f, 20.0f, 29.0f, 27.0f );
57 const Vector2 BACKGROUND_IMAGE_SIZE( 50.0f, 54.0f );
58 const Vector3 POPUP_TEXT_OFFSET( 12.0f, 10.0f, 0.0f );
59 const Vector3 POPUP_TEXT_ENLARGE( 12.0f, 28.0f, 0.0f );
60 const Vector3 POPUP_MINIMUM_SIZE( 128.0f, 124.0f, 0.0f );
61
62 const Vector3 BUTTON_TEXT_ENLARGE( 32.0f, 0.0f, 0.0f );
63 const Vector3 BUTTON_TEXT_MINIMUM_SIZE( 128.0f, 126.0f, 0.0f );
64 const Vector3 BUTTON_TEXT_MAXIMUM_SIZE( 196.0f, 126.0f, 0.0f );
65 const Vector3 TEXT_LABEL_MAX_SIZE( 160.0f, 30.0f, 0.0f );
66
67 const float DIVIDER_WIDTH(2.0f);                                            ///< Width of each button divider
68 const float DIVIDER_MARGIN(10.0f);                                          ///< Top/Bottom Margin between divider and edge of popup.
69
70 const float DEFAULT_UI_FONT_SIZE(7.0f);                                     ///< Standard font size for Text-Input's UI
71
72 const float HIDE_POPUP_ANIMATION_DURATION(0.2f);                            ///< Duration of popup hide animation in seconds.
73 const float SHOW_POPUP_ANIMATION_DURATION(0.2f);                            ///< Duration of popup show animation in seconds.
74
75 const Vector2 DEFAULT_ICON_SIZE( 45.0f, 45.0f );                            ///< Default icon size for image in options
76 const float TEXT_POSITION_OFFSET( -19.0f );                                  ///< Default offset for text label
77 const float ICON_POSITION_OFFSET( 19.0f );                                  ///< Default offset for icon
78
79 // TODO: This should be based on the content for example:
80 // 1. For selection: should be above top of highlighted selection, or below bottom of highlighted selection + end handle.
81 // 2. For cursor: should be above top of cursor, or below bottom of cursor + grab handle.
82 const std::string POPUP_ALTERNATIVE_OFFSET("popup-alternative-offset");       ///< Alternative offset property for confinenment constraint.
83
84
85 /**
86  * Confine Actor to boundaries of reference actor (e.g. Parent)
87  * Actor bounds (top-left position + size) are confined to reference Actor's
88  * bounds.
89  */
90 struct ConfinementConstraint
91 {
92   /**
93    * Confinement constraint constructor.
94    * @param[in] topLeftMargin (optional) Top-Left margins (defaults to 0.0f, 0.0f)
95    * @param[in] bottomRightMargin (optional) Bottom-Right margins (defaults to 0.0f, 0.0f)
96    * @param[in] flipVertical (optional) whether to flip Actor to the other side if near edge, and by
97    * how much (defaults to 0.0f i.e. no flip)
98    */
99   ConfinementConstraint(Vector2 topLeftMargin = Vector2::ZERO, Vector2 bottomRightMargin = Vector2::ZERO, bool flipHorizontal = false, bool flipVertical = false)
100   : mMinIndent(topLeftMargin),
101     mMaxIndent(bottomRightMargin),
102     mFlipHorizontal(flipHorizontal),
103     mFlipVertical(flipVertical)
104   {
105   }
106
107   Vector3 operator()(const Vector3&    constPosition,
108                      const PropertyInput& sizeProperty,
109                      const PropertyInput& parentOriginProperty,
110                      const PropertyInput& anchorPointProperty,
111                      const PropertyInput& referenceSizeProperty,
112                      const PropertyInput& alternativeOffsetProperty)
113   {
114     const Vector3& size = sizeProperty.GetVector3();
115     const Vector3& origin = parentOriginProperty.GetVector3();
116     const Vector3& anchor = anchorPointProperty.GetVector3();
117     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
118     const Vector2& alternativeOffset = alternativeOffsetProperty.GetVector2();
119
120     Vector3 newPosition(constPosition);
121
122     // Get actual position of Actor relative to parent's Top-Left.
123     Vector3 position(constPosition + origin * referenceSize);
124
125     // if top-left corner is outside of Top-Left bounds, then push back in screen.
126     Vector3 corner(position - size * anchor - mMinIndent);
127
128     if(mFlipHorizontal && corner.x < 0.0f)
129     {
130       corner.x = 0.0f;
131       newPosition.x += size.width + alternativeOffset.width;
132     }
133
134     if(mFlipVertical && corner.y < 0.0f)
135     {
136       corner.y = 0.0f;
137       newPosition.y += size.height + alternativeOffset.height;
138     }
139
140     newPosition.x -= std::min(corner.x, 0.0f);
141     newPosition.y -= std::min(corner.y, 0.0f);
142
143     // if bottom-right corner is outside of Bottom-Right bounds, then push back in screen.
144     corner += size - referenceSize + mMinIndent + mMaxIndent;
145
146     if(mFlipHorizontal && corner.x > 0.0f)
147     {
148       corner.x = 0.0f;
149       newPosition.x -= size.width + alternativeOffset.width;
150     }
151
152     if(mFlipVertical && corner.y > 0.0f)
153     {
154       corner.y = 0.0f;
155       newPosition.y -= size.height + alternativeOffset.height;
156     }
157
158     newPosition.x -= std::max(corner.x, 0.0f);
159     newPosition.y -= std::max(corner.y, 0.0f);
160
161     return newPosition;
162   }
163
164   Vector3 mMinIndent;                                   ///< Top-Left Margin
165   Vector3 mMaxIndent;                                   ///< Bottom-Right Margin.
166   bool mFlipHorizontal;                                 ///< Whether to flip actor's position if exceeds horizontal screen bounds
167   bool mFlipVertical;                                   ///< Whether to flip actor's position if exceeds vertical screen bounds
168 };
169
170 } // unnamed namespace
171
172 namespace Dali
173 {
174
175 namespace Toolkit
176 {
177
178 namespace Internal
179 {
180
181 const char* const TextInputPopup::SIGNAL_PRESSED = "pressed";
182 const char* const TextInputPopup::SIGNAL_HIDE_FINISHED = "hide-finished";
183 const char* const TextInputPopup::SIGNAL_SHOW_FINISHED = "show-finished";
184
185 TextInputPopup::TextInputPopup()
186 : mState(StateHidden),
187   mRootActor(Layer::New()),
188   mPressedSignal(),
189   mHideFinishedSignal(),
190   mShowFinishedSignal()
191 {
192   mAlternativeOffsetProperty = mRootActor.RegisterProperty( POPUP_ALTERNATIVE_OFFSET, Vector2::ZERO );
193   mRootActor.SetParentOrigin( ParentOrigin::CENTER );
194   mRootActor.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
195   // constrain popup to size of parent.
196 }
197
198 Actor TextInputPopup::Self()
199 {
200   return mRootActor;
201 }
202
203 void TextInputPopup::AddToStage()
204 {
205   // TODO: Confinement constraint borders should be defined by the application.
206   // It should also not use the stage directly, instead it should add to parent container.
207   Stage::GetCurrent().Add(mRootActor);
208
209   ApplyConfinementConstraint();
210 }
211
212 void TextInputPopup::ApplyConfinementConstraint()
213 {
214   mRootActor.RemoveConstraints();
215   Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
216                                                     LocalSource( Actor::SIZE ),
217                                                     LocalSource( Actor::PARENT_ORIGIN ),
218                                                     LocalSource( Actor::ANCHOR_POINT ),
219                                                     ParentSource( Actor::SIZE ),
220                                                     LocalSource( mAlternativeOffsetProperty ),
221                                                     ConfinementConstraint( DEFAULT_POPUP_INDICATOR_OFFSET,
222                                                                            Vector2::ZERO,
223                                                                            false,
224                                                                            true) );
225   mRootActor.ApplyConstraint(constraint);
226 }
227
228 void TextInputPopup::RemoveFromStage()
229 {
230   Actor rootActor = Self();
231   Stage::GetCurrent().Remove( rootActor );
232 }
233
234 void TextInputPopup::Clear()
235 {
236   if ( mBackground )
237   {
238     mRootActor.Remove( mBackground );
239     mBackground.Reset();
240     mButtonContainer.clear();
241     mDividerContainer.clear();
242
243     RemoveFromStage();
244     mRootActor.RemoveConstraints();
245
246     mState = StateHidden;
247   }
248 }
249
250 Toolkit::TextView TextInputPopup::CreateOptionText( const MarkupProcessor::StyledTextArray& styledCaption )
251 {
252   Toolkit::TextView label = Toolkit::TextView::New( styledCaption );
253   label.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
254   label.SetWidthExceedPolicy( Toolkit::TextView::Fade );
255   label.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
256   label.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
257   label.SetPosition( 0.0f, TEXT_POSITION_OFFSET );
258
259   return label;
260 }
261
262 ImageActor TextInputPopup::CreateOptionIcon( Image iconImage )
263 {
264   ImageActor icon = ImageActor::New( iconImage );
265
266   icon.SetSize( DEFAULT_ICON_SIZE );
267   icon.SetParentOrigin( ParentOrigin::TOP_CENTER );
268   icon.SetAnchorPoint( AnchorPoint::TOP_CENTER );
269   icon.SetPosition( 0.0f, ICON_POSITION_OFFSET );
270
271   return icon;
272 }
273
274 void TextInputPopup::CreatePopUpBackground()
275 {
276   // Create background-panel if not already created (required if we have at least one option)
277   if ( !mBackground )
278   {
279     Image backgroundImage = Image::New( DEFAULT_PANEL_BACKGROUND );
280
281     mBackground = ImageActor::New( backgroundImage );
282     // Expand background from bottom-center of root actor.
283     mBackground.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
284     mBackground.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
285     mBackground.SetStyle( ImageActor::STYLE_NINE_PATCH );
286
287     mBackground.SetNinePatchBorder( Vector4(13.0f, 13.0f, 13.0f, 13.0f) );
288
289     Self().Add( mBackground );
290     mContentSize = POPUP_TEXT_OFFSET;
291
292     Hide(false);
293     AddToStage();
294
295     // Add Tail too.
296     Image tailImage = Image::New( DEFAULT_POPUP_TAIL_BOTTOM );
297
298     mTail = ImageActor::New( tailImage );
299     mTail.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
300     mTail.SetAnchorPoint( AnchorPoint::TOP_CENTER );
301     mBackground.Add( mTail );
302     // TODO: Make tail visible, and positioned in relation to original intended position of popup (i.e. before constrained effects)
303     mTail.SetVisible(false);
304   }
305 }
306
307 void TextInputPopup::CreateDivider()
308 {
309   if(mButtonContainer.size() > 0)
310   {
311     Image dividerImage = Image::New( DEFAULT_PANEL_BUTTON_DIVIDER );
312     ImageActor divider = ImageActor::New( dividerImage );
313     divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
314     divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
315     divider.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y + 5.0f, 0.0f ) );
316     // Keep track of all the dividers. As their height's need to be updated to the max. of all
317     // buttons currently added.
318     mDividerContainer.push_back(divider);
319
320     mBackground.Add( divider );
321     mContentSize.width += DIVIDER_WIDTH;
322   }
323 }
324
325 ImageActor TextInputPopup::CreatePressedBackground( const Vector3 requiredSize, const bool finalFlag )
326 {
327   std::string pressedImageFilename;
328   Vector4 pressedImageBorder;
329   Vector2 pressedImageSize;
330
331   if(mButtonContainer.size() == 0) // LEFT
332   {
333     pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_LEFT;
334     pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_LEFT_BORDER;
335   }
336   else if(!finalFlag) // CENTER
337   {
338     pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_CENTER;
339     pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_CENTER_BORDER;
340   }
341   else // RIGHT
342   {
343     pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_RIGHT;
344     pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_RIGHT_BORDER;
345   }
346
347   Image pressedImage = Image::New( pressedImageFilename );
348   ImageActor pressedImageBg = ImageActor::New( pressedImage );
349   pressedImageBg.SetStyle( ImageActor::STYLE_NINE_PATCH );
350   pressedImageBg.SetNinePatchBorder( pressedImageBorder );
351   pressedImageBg.SetSize ( requiredSize );
352   pressedImageBg.SetParentOrigin( ParentOrigin::CENTER );
353   pressedImageBg.SetAnchorPoint( AnchorPoint::CENTER );
354
355   return pressedImageBg;
356 }
357
358 void TextInputPopup::AddOption(const std::string& name, const std::string& caption, const Image iconImage,  bool finalOption)
359 {
360   CreatePopUpBackground();
361
362   CreateDivider();
363
364   // Create a Button with Text, Icon and highlight when pressed
365
366   Toolkit::PushButton button = Toolkit::PushButton::New();
367   button.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
368   button.SetName( name );
369
370   // Create container for text and icon when not pressed
371   Actor iconTextContainer = Actor::New();
372   iconTextContainer.SetParentOrigin( ParentOrigin::TOP_LEFT );
373   iconTextContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
374
375   // 1. Add text.
376   TextStyle style;
377   style.SetFontPointSize( PointSize( DEFAULT_UI_FONT_SIZE ) );
378   MarkupProcessor::StyledTextArray styledCaption;
379   styledCaption.push_back( MarkupProcessor::StyledText( Text( caption ), style ) );
380   Toolkit::TextView label = CreateOptionText( styledCaption );
381   label.SetName( name );
382
383   iconTextContainer.Add( label );
384
385   // Get natural size of text and then constrain it to bounds.
386   const Vector3 textSize = label.GetNaturalSize();
387   const Vector3 constrainedTextSize = Min( textSize, TEXT_LABEL_MAX_SIZE );
388   Vector3 buttonSize( Max(constrainedTextSize + BUTTON_TEXT_ENLARGE, BUTTON_TEXT_MINIMUM_SIZE) );
389   buttonSize = ( Min(buttonSize, BUTTON_TEXT_MAXIMUM_SIZE) );
390   label.SetSize( Min( buttonSize + BUTTON_TEXT_ENLARGE, constrainedTextSize ) );
391
392   button.SetParentOrigin( ParentOrigin::TOP_LEFT );
393   button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
394   button.SetSize( buttonSize );
395   button.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y, 0.0f ) );
396
397   // 2. Add icon
398   ImageActor icon = CreateOptionIcon( iconImage );
399
400   iconTextContainer.Add( icon );
401
402   // 3. Add highlight - Pressed state in Pushbutton needs a new image which means creating the text and icon again but including a highlight this time.
403   ImageActor pressedImageBg = CreatePressedBackground( buttonSize, finalOption );
404
405   Actor iconPressedTextContainer = Actor::New();
406   iconPressedTextContainer.SetDrawMode( DrawMode::OVERLAY );
407
408   Toolkit::TextView pressedLabel = CreateOptionText( styledCaption );
409   pressedLabel.SetSize( Min( buttonSize, TEXT_LABEL_MAX_SIZE ) );
410   ImageActor pressedIcon = CreateOptionIcon( iconImage );
411
412   iconPressedTextContainer.Add( pressedImageBg );
413   iconPressedTextContainer.Add( pressedLabel );
414   iconPressedTextContainer.Add( pressedIcon );
415
416   // Set Pressed button Image
417   iconPressedTextContainer.SetSize( buttonSize );
418   button.SetPressedImage( iconPressedTextContainer );
419
420   // Set Normal button Image
421   iconTextContainer.SetSize( buttonSize );
422   button.SetButtonImage( iconTextContainer );
423   mBackground.Add( button );
424
425   // Update content size (represents size of all content i.e. from top-left of first button, to bottom-right of last button)
426   mContentSize.width += buttonSize.width;
427   mContentSize.height = std::max(mContentSize.height, buttonSize.height);
428   mButtonContainer.push_back(button);
429
430   // resize all dividers based on the height content (i.e. max of all button heights)
431   const float dividerHeight = mContentSize.height - DIVIDER_MARGIN;
432   for(ActorIter i = mDividerContainer.begin(); i != mDividerContainer.end(); ++i)
433   {
434     i->SetSize( DIVIDER_WIDTH, dividerHeight );
435   }
436
437   Vector3 popupSize( Max(mContentSize + POPUP_TEXT_ENLARGE, POPUP_MINIMUM_SIZE) );
438
439   mBackground.SetSize( popupSize );
440   // Make Root Actor reflect the size of its content
441   mRootActor.SetSize( popupSize );
442   mTail.SetPosition(Vector3(0.0f, -20.0f, 0.0f));
443
444   button.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
445 }
446
447 void TextInputPopup::Hide(bool animate)
448 {
449   if(mBackground)
450   {
451     if(mAnimation)
452     {
453       mAnimation.Clear();
454       mAnimation.Reset();
455     }
456
457     if(animate)
458     {
459       mAnimation = Animation::New( HIDE_POPUP_ANIMATION_DURATION );
460       mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut );
461       mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 0.0f, AlphaFunctions::EaseOut );
462       mAnimation.Play();
463
464       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnHideFinished );
465       mState = StateHiding;
466     }
467     else
468     {
469       mBackground.SetProperty(Actor::SCALE, Vector3::ZERO);
470       mBackground.SetProperty(Actor::COLOR_ALPHA, 0.0f);
471       mState = StateHidden;
472     }
473   }
474 }
475
476 void TextInputPopup::Show(bool animate)
477 {
478   if(mBackground)
479   {
480     if(mAnimation)
481     {
482       mAnimation.Clear();
483       mAnimation.Reset();
484     }
485
486     if(animate)
487     {
488       mAnimation = Animation::New( SHOW_POPUP_ANIMATION_DURATION );
489       mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ONE, AlphaFunctions::EaseOut );
490       mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 1.0f, AlphaFunctions::EaseOut );
491       mAnimation.Play();
492
493       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnShowFinished );
494       mState = StateShowing;
495     }
496     else
497     {
498       mBackground.SetProperty(Actor::SCALE, Vector3::ONE);
499       mBackground.SetProperty(Actor::COLOR_ALPHA, 1.0f);
500       mState = StateShown;
501     }
502   }
503 }
504
505 void TextInputPopup::SetAlternativeOffset(Vector2 offset)
506 {
507   mRootActor.SetProperty( mAlternativeOffsetProperty, offset );
508   ApplyConfinementConstraint();
509 }
510
511 TextInputPopup::State TextInputPopup::GetState(void) const
512 {
513   return mState;
514 }
515
516 Actor TextInputPopup::GetRootActor() const
517 {
518   return mRootActor;
519 }
520
521 bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
522 {
523   mPressedSignal.Emit( button );
524   return false;
525 }
526
527 void TextInputPopup::OnHideFinished(Animation& source)
528 {
529   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnHideFinished );
530   Clear();
531   mState = StateHidden;
532   mHideFinishedSignal.Emit( *this );
533 }
534
535 void TextInputPopup::OnShowFinished(Animation& source)
536 {
537   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnShowFinished );
538   mState = StateShown;
539   mShowFinishedSignal.Emit( *this );
540 }
541
542 TextInputPopup::PressedSignalV2& TextInputPopup::PressedSignal()
543 {
544   return mPressedSignal;
545 }
546
547 TextInputPopup::HideFinishedSignalV2& TextInputPopup::HideFinishedSignal()
548 {
549   return mHideFinishedSignal;
550 }
551
552 TextInputPopup::ShowFinishedSignalV2& TextInputPopup::ShowFinishedSignal()
553 {
554   return mShowFinishedSignal;
555 }
556
557 } // namespace Internal
558
559 } // namespace Toolkit
560
561 } // namespace Dali