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