TextInput uses style properties for PopUp and Highlight
[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
20 #include <dali-toolkit/public-api/controls/buttons/push-button.h>
21 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
22
23 #include <libintl.h>
24
25 using namespace std;
26 using namespace Dali;
27
28 #define GET_LOCALE_TEXT(string) dgettext("sys_string", string)
29
30 namespace {
31
32 // Default Colors
33
34 const Vector4 DEFAULT_POPUP_BACKGROUND( Vector4( 0.24f, 0.41f, 0.88f, 1.0f ) );
35 const Vector4 DEFAULT_POPUP_BUTTON_PRESSED( Vector4( 0.18f, 0.56f, 1.0f, 1.0f ) );
36 const Vector4 DEFAULT_BORDER_COLOR( Vector4( 0.2f, 0.2f, 0.2f, 1.0f ) );
37 const Vector3 POPUP_BORDER( Vector3(1.0f, 1.0f, 0.0f) );
38
39 // Popup: Divider
40 const char* DEFAULT_PANEL_BUTTON_DIVIDER = DALI_IMAGE_DIR "copypanelLine.png";
41
42 /* Functionality in place to have the end buttons using different images to inner button.
43  * Supply a centre image and then a left and right image, the centre image can have straight ends while
44  * 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.
45  */
46
47 // Popup: Tails
48 const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "00_popup_bubble_tail_bottom.png" );
49
50 // Popup: Vertical Constraint
51 // TODO: Remove - this should come from application - it is not possible to get the
52 // height of the indicator actor from Dali-Toolkit.
53 const Vector2 DEFAULT_POPUP_INDICATOR_OFFSET(0.0f, 60.0f);
54
55 const Vector3 POPUP_TEXT_OFFSET( 0.0f, 0.0f, 0.0f );
56 const Vector3 POPUP_TEXT_ENLARGE( 12.0f, 28.0f, 0.0f );
57 const Vector3 POPUP_MINIMUM_SIZE( 128.0f, 124.0f, 0.0f );
58
59 const Vector3 BUTTON_TEXT_ENLARGE( 32.0f, 0.0f, 0.0f );
60 const Vector3 BUTTON_TEXT_MINIMUM_SIZE( 128.0f, 126.0f, 0.0f );
61 const Vector3 BUTTON_TEXT_MAXIMUM_SIZE( 190.0f, 126.0f, 0.0f );
62 const Vector3 TEXT_LABEL_MAX_SIZE( 160.0f, 30.0f, 0.0f );
63
64 const float DIVIDER_WIDTH(2.0f);                                            ///< Width of each button divider
65 const float DIVIDER_MARGIN(0.0f);                                          ///< Top/Bottom Margin between divider and edge of popup.
66
67 const float DEFAULT_UI_FONT_SIZE(7.0f);                                     ///< Standard font size for Text-Input's UI
68
69 const float HIDE_POPUP_ANIMATION_DURATION(0.2f);                            ///< Duration of popup hide animation in seconds.
70 const float SHOW_POPUP_ANIMATION_DURATION(0.2f);                            ///< Duration of popup show animation in seconds.
71
72 const Vector2 DEFAULT_ICON_SIZE( 45.0f, 45.0f );                            ///< Default icon size for image in options
73 const float TEXT_POSITION_OFFSET( -19.0f );                                  ///< Default offset for text label
74 const float ICON_POSITION_OFFSET( 19.0f );                                  ///< Default offset for icon
75
76 const char* DEFAULT_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
77 const char* DEFAULT_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
78 const char* DEFAULT_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
79 const char* DEFAULT_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" );
80 const char* DEFAULT_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
81 const char* DEFAULT_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
82
83 // TODO: This should be based on the content for example:
84 // 1. For selection: should be above top of highlighted selection, or below bottom of highlighted selection + end handle.
85 // 2. For cursor: should be above top of cursor, or below bottom of cursor + grab handle.
86 const std::string POPUP_ALTERNATIVE_OFFSET("popup-alternative-offset");       ///< Alternative offset property for confinenment constraint.
87
88
89 /**
90  * Confine Actor to boundaries of reference actor (e.g. Parent)
91  * Actor bounds (top-left position + size) are confined to reference Actor's
92  * bounds.
93  */
94 struct ConfinementConstraint
95 {
96   /**
97    * Confinement constraint constructor.
98    * @param[in] topLeftMargin (optional) Top-Left margins (defaults to 0.0f, 0.0f)
99    * @param[in] bottomRightMargin (optional) Bottom-Right margins (defaults to 0.0f, 0.0f)
100    * @param[in] flipVertical (optional) whether to flip Actor to the other side if near edge, and by
101    * how much (defaults to 0.0f i.e. no flip)
102    */
103   ConfinementConstraint(Vector2 topLeftMargin = Vector2::ZERO, Vector2 bottomRightMargin = Vector2::ZERO, bool flipHorizontal = false, bool flipVertical = false)
104   : mMinIndent(topLeftMargin),
105     mMaxIndent(bottomRightMargin),
106     mFlipHorizontal(flipHorizontal),
107     mFlipVertical(flipVertical)
108   {
109   }
110
111   Vector3 operator()(const Vector3&    constPosition,
112                      const PropertyInput& sizeProperty,
113                      const PropertyInput& parentOriginProperty,
114                      const PropertyInput& anchorPointProperty,
115                      const PropertyInput& referenceSizeProperty,
116                      const PropertyInput& alternativeOffsetProperty)
117   {
118     const Vector3& size = sizeProperty.GetVector3();
119     const Vector3& origin = parentOriginProperty.GetVector3();
120     const Vector3& anchor = anchorPointProperty.GetVector3();
121     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
122     const Vector2& alternativeOffset = alternativeOffsetProperty.GetVector2();
123
124     Vector3 newPosition(constPosition);
125
126     // Get actual position of Actor relative to parent's Top-Left.
127     Vector3 position(constPosition + origin * referenceSize);
128
129     // if top-left corner is outside of Top-Left bounds, then push back in screen.
130     Vector3 corner(position - size * anchor - mMinIndent);
131
132     if(mFlipHorizontal && corner.x < 0.0f)
133     {
134       corner.x = 0.0f;
135       newPosition.x += size.width + alternativeOffset.width;
136     }
137
138     if(mFlipVertical && corner.y < 0.0f)
139     {
140       corner.y = 0.0f;
141       newPosition.y += size.height + alternativeOffset.height;
142     }
143
144     newPosition.x -= std::min(corner.x, 0.0f);
145     newPosition.y -= std::min(corner.y, 0.0f);
146
147     // if bottom-right corner is outside of Bottom-Right bounds, then push back in screen.
148     corner += size - referenceSize + mMinIndent + mMaxIndent;
149
150     if(mFlipHorizontal && corner.x > 0.0f)
151     {
152       corner.x = 0.0f;
153       newPosition.x -= size.width + alternativeOffset.width;
154     }
155
156     if(mFlipVertical && corner.y > 0.0f)
157     {
158       corner.y = 0.0f;
159       newPosition.y -= size.height + alternativeOffset.height;
160     }
161
162     newPosition.x -= std::max(corner.x, 0.0f);
163     newPosition.y -= std::max(corner.y, 0.0f);
164
165     return newPosition;
166   }
167
168   Vector3 mMinIndent;                                   ///< Top-Left Margin
169   Vector3 mMaxIndent;                                   ///< Bottom-Right Margin.
170   bool mFlipHorizontal;                                 ///< Whether to flip actor's position if exceeds horizontal screen bounds
171   bool mFlipVertical;                                   ///< Whether to flip actor's position if exceeds vertical screen bounds
172 };
173
174 } // unnamed namespace
175
176 namespace Dali
177 {
178
179 namespace Toolkit
180 {
181
182 namespace Internal
183 {
184
185 const char* const TextInputPopup::SIGNAL_PRESSED = "pressed";
186 const char* const TextInputPopup::SIGNAL_HIDE_FINISHED = "hide-finished";
187 const char* const TextInputPopup::SIGNAL_SHOW_FINISHED = "show-finished";
188
189 const char* const TextInputPopup::OPTION_SELECT_WORD = "select_word";                       // "Select Word" popup option.
190 const char* const TextInputPopup::OPTION_SELECT_ALL("select_all");                          // "Select All" popup option.
191 const char* const TextInputPopup::OPTION_CUT("cut");                                        // "Cut" popup option.
192 const char* const TextInputPopup::OPTION_COPY("copy");                                      // "Copy" popup option.
193 const char* const TextInputPopup::OPTION_PASTE("paste");                                    // "Paste" popup option.
194 const char* const TextInputPopup::OPTION_CLIPBOARD("clipboard");                            // "Clipboard" popup option.
195
196 TextInputPopup::TextInputPopup()
197 : mState(StateHidden),
198   mRootActor(Layer::New()),
199   mContentSize( Vector3::ZERO ),
200   mCutPasteButtonsColor( DEFAULT_POPUP_BACKGROUND ),
201   mCutPasteButtonsPressedColor( DEFAULT_POPUP_BUTTON_PRESSED ),
202   mBorderColor( DEFAULT_BORDER_COLOR ),
203   mSelectOptionPriority(1),
204   mSelectAllOptionPriority(2),
205   mCutOptionPriority(3),
206   mCopyOptionPriority(4),
207   mPasteOptionPriority(5),
208   mClipboardOptionPriority(6),
209   mPressedSignal(),
210   mHideFinishedSignal(),
211   mShowFinishedSignal()
212 {
213   mAlternativeOffsetProperty = mRootActor.RegisterProperty( POPUP_ALTERNATIVE_OFFSET, Vector2::ZERO );
214   mRootActor.SetParentOrigin( ParentOrigin::CENTER );
215   mRootActor.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
216   // constrain popup to size of parent.
217 }
218
219 Actor TextInputPopup::Self()
220 {
221   return mRootActor;
222 }
223
224 void TextInputPopup::AddToStage()
225 {
226   // TODO: Confinement constraint borders should be defined by the application.
227   // It should also not use the stage directly, instead it should add to parent container.
228   Stage::GetCurrent().Add(mRootActor);
229
230   ApplyConfinementConstraint();
231 }
232
233 void TextInputPopup::ApplyConfinementConstraint()
234 {
235   mRootActor.RemoveConstraints();
236   Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
237                                                     LocalSource( Actor::SIZE ),
238                                                     LocalSource( Actor::PARENT_ORIGIN ),
239                                                     LocalSource( Actor::ANCHOR_POINT ),
240                                                     ParentSource( Actor::SIZE ),
241                                                     LocalSource( mAlternativeOffsetProperty ),
242                                                     ConfinementConstraint( DEFAULT_POPUP_INDICATOR_OFFSET,
243                                                                            Vector2::ZERO,
244                                                                            false,
245                                                                            true) );
246   mRootActor.ApplyConstraint(constraint);
247 }
248
249 void TextInputPopup::RemoveFromStage()
250 {
251   Actor rootActor = Self();
252   Stage::GetCurrent().Remove( rootActor );
253 }
254
255 void TextInputPopup::Clear()
256 {
257   if ( mBackground )
258   {
259     mRootActor.Remove( mBackground );
260     mBackground.Reset();
261     mButtonContainer.clear();
262     mDividerContainer.clear();
263
264     RemoveFromStage();
265     mRootActor.RemoveConstraints();
266
267     mState = StateHidden;
268   }
269 }
270
271 Toolkit::TextView TextInputPopup::CreateOptionText( const MarkupProcessor::StyledTextArray& styledCaption )
272 {
273   Toolkit::TextView label = Toolkit::TextView::New( styledCaption );
274   label.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
275   label.SetWidthExceedPolicy( Toolkit::TextView::Fade );
276   label.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
277   label.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
278   label.SetPosition( 0.0f, TEXT_POSITION_OFFSET );
279
280   return label;
281 }
282
283 ImageActor TextInputPopup::CreateOptionIcon( Image iconImage )
284 {
285   ImageActor icon = ImageActor::New( iconImage );
286
287   icon.SetSize( DEFAULT_ICON_SIZE );
288   icon.SetParentOrigin( ParentOrigin::TOP_CENTER );
289   icon.SetAnchorPoint( AnchorPoint::TOP_CENTER );
290   icon.SetPosition( 0.0f, ICON_POSITION_OFFSET );
291
292   return icon;
293 }
294
295 void TextInputPopup::CreatePopUpBackground()
296 {
297   // Create background-panel if not already created (required if we have at least one option)
298   if ( !mBackground )
299   {
300     mBackground = Toolkit::CreateSolidColorActor( GetCutPastePopUpColor(), true, mBorderColor );
301
302     Self().Add( mBackground );
303     mContentSize = POPUP_TEXT_OFFSET;
304
305     Hide(false);
306     AddToStage();
307
308     // Add Tail too.
309     Image tailImage = Image::New( DEFAULT_POPUP_TAIL_BOTTOM );
310
311     mTail = ImageActor::New( tailImage );
312     mTail.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
313     mTail.SetAnchorPoint( AnchorPoint::TOP_CENTER );
314     mBackground.Add( mTail );
315     // TODO: Make tail visible, and positioned in relation to original intended position of popup (i.e. before constrained effects)
316     mTail.SetVisible(false);
317   }
318 }
319
320 void TextInputPopup::CreateDivider()
321 {
322   if(mButtonContainer.size() > 0)
323   {
324     Image dividerImage = Image::New( DEFAULT_PANEL_BUTTON_DIVIDER );
325     ImageActor divider = ImageActor::New( dividerImage );
326     divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
327     divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
328     divider.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y, 0.0f ) );
329     // Keep track of all the dividers. As their height's need to be updated to the max. of all
330     // buttons currently added.
331     mDividerContainer.push_back(divider);
332
333     mBackground.Add( divider );
334     mContentSize.width += DIVIDER_WIDTH;
335   }
336 }
337
338 ImageActor TextInputPopup::CreatePressedBackground( const Vector3 requiredSize )
339 {
340   std::string pressedImageFilename;
341   Vector4 pressedImageBorder;
342   Vector2 pressedImageSize;
343
344   ImageActor pressedButtonBg = Toolkit::CreateSolidColorActor( GetCutPastePopUpPressedColor() );
345
346   pressedButtonBg.SetSize ( requiredSize );
347   pressedButtonBg.SetParentOrigin( ParentOrigin::CENTER );
348   pressedButtonBg.SetAnchorPoint( AnchorPoint::CENTER );
349
350   return pressedButtonBg;
351 }
352
353 TextInputPopup::ButtonRequirement TextInputPopup::CreateRequiredButton( TextInputPopup::Buttons buttonId, std::size_t orderOfPriority,
354                                                                         const std::string& name, const std::string& caption, Image iconImage, bool enabled )
355 {
356   TextInputPopup::ButtonRequirement currentButton;
357
358   currentButton.buttonId = buttonId;
359   currentButton.orderOfPriority = orderOfPriority;
360   currentButton.name = name;
361   currentButton.caption = caption;
362   currentButton.iconImage = iconImage;
363   currentButton.enabled = enabled;
364
365   return currentButton;
366 }
367
368 void TextInputPopup::CreateOrderedListOfOptions()
369 {
370   mOrderListOfButtons.clear();
371
372   for ( std::size_t index= 0; index < ButtonsEnumEnd; index++ )
373   {
374     TextInputPopup::ButtonRequirement currentButton;
375
376     // Create button for each possible option using Option priority
377     switch ( index )
378     {
379       case ButtonsCut:
380       {
381         Image cutIcon = Image::New( DEFAULT_ICON_CUT );
382         currentButton = CreateRequiredButton( ButtonsCut, mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon, false );
383         break;
384       }
385       case ButtonsCopy:
386       {
387         Image copyIcon = Image::New( DEFAULT_ICON_COPY );
388         currentButton = CreateRequiredButton( ButtonsCopy, mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, false );
389         break;
390       }
391       case ButtonsPaste:
392       {
393         Image pasteIcon = Image::New( DEFAULT_ICON_PASTE );
394         currentButton = CreateRequiredButton( ButtonsPaste, mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, false );
395         break;
396       }
397       case ButtonsSelect:
398       {
399         Image selectIcon = Image::New( DEFAULT_ICON_SELECT );
400         currentButton = CreateRequiredButton( ButtonsSelect, mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon, false );
401         break;
402       }
403       case ButtonsSelectAll:
404       {
405         Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL );
406         currentButton = CreateRequiredButton( ButtonsSelectAll, mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon, false );
407         break;
408       }
409       case ButtonsClipboard:
410       {
411         Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD );
412         currentButton = CreateRequiredButton( ButtonsClipboard, mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, false );
413         break;
414       }
415       case ButtonsEnumEnd:
416       {
417         DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
418         currentButton.orderOfPriority = 0;
419         break;
420       }
421     }
422
423     bool match = false;
424
425     // Insert button in list of buttons in order of priority setting.
426     for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
427     {
428       const ButtonRequirement& button( *it );
429       if ( currentButton.orderOfPriority < button.orderOfPriority )
430       {
431         if ( currentButton.orderOfPriority != 0 ) // If order priority 0 then do not add button as not required.
432         {
433           mOrderListOfButtons.insert( it, currentButton );
434         }
435         match = true;
436       }
437     }
438
439     if ( !match)
440     {
441       mOrderListOfButtons.push_back( currentButton );
442     }
443   }
444 }
445
446 void TextInputPopup::AddOption(const std::string& name, const std::string& caption, const Image iconImage,  bool finalOption)
447 {
448   CreatePopUpBackground();
449
450   CreateDivider();
451
452   // Create a Button with Text, Icon and highlight when pressed
453
454   Toolkit::PushButton button = Toolkit::PushButton::New();
455   button.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
456   button.SetName( name );
457
458   // Create container for text and icon when not pressed
459   Actor iconTextContainer = Actor::New();
460   iconTextContainer.SetParentOrigin( ParentOrigin::TOP_LEFT );
461   iconTextContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
462
463   // 1. Add text.
464   TextStyle style;
465   style.SetFontPointSize( PointSize( DEFAULT_UI_FONT_SIZE ) );
466   MarkupProcessor::StyledTextArray styledCaption;
467   styledCaption.push_back( MarkupProcessor::StyledText( Text( caption ), style ) );
468   Toolkit::TextView label = CreateOptionText( styledCaption );
469   label.SetName( name );
470
471   iconTextContainer.Add( label );
472
473   // Get natural size of text and then constrain it to bounds.
474   const Vector3 textSize = label.GetNaturalSize();
475   const Vector3 constrainedTextSize = Min( textSize, TEXT_LABEL_MAX_SIZE );
476   Vector3 buttonSize( Max(constrainedTextSize + BUTTON_TEXT_ENLARGE, BUTTON_TEXT_MINIMUM_SIZE) );
477   buttonSize = ( Min(buttonSize, BUTTON_TEXT_MAXIMUM_SIZE) );
478   label.SetSize( Min( buttonSize + BUTTON_TEXT_ENLARGE, constrainedTextSize ) );
479
480   button.SetParentOrigin( ParentOrigin::TOP_LEFT );
481   button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
482   button.SetSize( buttonSize );
483   button.SetPosition( Vector3( mContentSize.width, POPUP_BORDER.y, 0.0f ) );
484
485   // 2. Add icon
486   ImageActor icon = CreateOptionIcon( iconImage );
487
488   iconTextContainer.Add( icon );
489
490   // 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.
491   ImageActor pressedImageBg = CreatePressedBackground( buttonSize );
492
493   Actor iconPressedTextContainer = Actor::New();
494   iconPressedTextContainer.SetDrawMode( DrawMode::OVERLAY );
495
496   Toolkit::TextView pressedLabel = CreateOptionText( styledCaption );
497   pressedLabel.SetSize( Min( buttonSize, TEXT_LABEL_MAX_SIZE ) );
498   ImageActor pressedIcon = CreateOptionIcon( iconImage );
499
500   iconPressedTextContainer.Add( pressedImageBg );
501   iconPressedTextContainer.Add( pressedLabel );
502   iconPressedTextContainer.Add( pressedIcon );
503
504   // Set Pressed button Image
505   iconPressedTextContainer.SetSize( buttonSize );
506   button.SetPressedImage( iconPressedTextContainer );
507
508   // Set Normal button Image
509   iconTextContainer.SetSize( buttonSize );
510   button.SetButtonImage( iconTextContainer );
511   mBackground.Add( button );
512
513   // Update content size (represents size of all content i.e. from top-left of first button, to bottom-right of last button)
514   mContentSize.width += buttonSize.width;
515   mContentSize.height = std::max(mContentSize.height + ( POPUP_BORDER.y ), buttonSize.height);
516   mButtonContainer.push_back(button);
517
518   // resize all dividers based on the height content (i.e. max of all button heights)
519   const float dividerHeight = mContentSize.height - DIVIDER_MARGIN;
520   for(ActorIter i = mDividerContainer.begin(); i != mDividerContainer.end(); ++i)
521   {
522     i->SetSize( DIVIDER_WIDTH, dividerHeight );
523   }
524
525   Vector3 popupSize( Max(mContentSize, POPUP_MINIMUM_SIZE) );
526
527   mBackground.SetSize( popupSize );
528   // Make Root Actor reflect the size of its content
529   mRootActor.SetSize( popupSize );
530   mTail.SetPosition(Vector3(0.0f, -20.0f, 0.0f));
531
532   button.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
533 }
534
535 void TextInputPopup::Hide(bool animate)
536 {
537   if(mBackground)
538   {
539     if(mAnimation)
540     {
541       mAnimation.Clear();
542       mAnimation.Reset();
543     }
544
545     if(animate)
546     {
547       mAnimation = Animation::New( HIDE_POPUP_ANIMATION_DURATION );
548       mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut );
549       mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 0.0f, AlphaFunctions::EaseOut );
550       mAnimation.Play();
551
552       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnHideFinished );
553       mState = StateHiding;
554     }
555     else
556     {
557       mBackground.SetProperty(Actor::SCALE, Vector3::ZERO);
558       mBackground.SetProperty(Actor::COLOR_ALPHA, 0.0f);
559       mState = StateHidden;
560     }
561   }
562 }
563
564 void TextInputPopup::Show(bool animate)
565 {
566   if(mBackground)
567   {
568     if(mAnimation)
569     {
570       mAnimation.Clear();
571       mAnimation.Reset();
572     }
573
574     if(animate)
575     {
576       mAnimation = Animation::New( SHOW_POPUP_ANIMATION_DURATION );
577       mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ONE, AlphaFunctions::EaseOut );
578       mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 1.0f, AlphaFunctions::EaseOut );
579       mAnimation.Play();
580
581       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnShowFinished );
582       mState = StateShowing;
583     }
584     else
585     {
586       mBackground.SetProperty(Actor::SCALE, Vector3::ONE);
587       mBackground.SetProperty(Actor::COLOR_ALPHA, 1.0f);
588       mState = StateShown;
589     }
590   }
591 }
592
593 void TextInputPopup::SetAlternativeOffset(Vector2 offset)
594 {
595   mRootActor.SetProperty( mAlternativeOffsetProperty, offset );
596   ApplyConfinementConstraint();
597 }
598
599 TextInputPopup::State TextInputPopup::GetState(void) const
600 {
601   return mState;
602 }
603
604 Actor TextInputPopup::GetRootActor() const
605 {
606   return mRootActor;
607 }
608
609 // Styling
610
611 void TextInputPopup::SetCutPastePopUpColor( const Vector4& color )
612 {
613   mCutPasteButtonsColor = color;
614 }
615
616 const Vector4& TextInputPopup::GetCutPastePopUpColor() const
617 {
618   return mCutPasteButtonsColor;
619 }
620
621 void TextInputPopup::SetCutPastePopUpPressedColor( const Vector4& color )
622 {
623   mCutPasteButtonsPressedColor = color;
624 }
625
626 const Vector4& TextInputPopup::GetCutPastePopUpPressedColor() const
627 {
628   return mCutPasteButtonsPressedColor;
629 }
630
631 void TextInputPopup::TogglePopUpButtonOnOff( TextInputPopup::Buttons requiredButton, bool enable )
632 {
633   bool match ( false );
634   for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
635    {
636      ButtonRequirement& button( *it );
637      if ( requiredButton == button.buttonId )
638      {
639        button.enabled = enable;
640        match = true;
641      }
642    }
643 }
644
645 void TextInputPopup::SetButtonPriorityPosition( TextInputPopup::Buttons button, unsigned int priority )
646 {
647   switch ( button )
648   {
649     case ButtonsCut:
650     {
651       mCutOptionPriority = priority;
652       break;
653     }
654     case ButtonsCopy:
655     {
656       mCopyOptionPriority = priority;
657       break;
658     }
659     case ButtonsPaste:
660     {
661       mPasteOptionPriority = priority;
662       break;
663     }
664     case ButtonsSelect:
665     {
666       mSelectOptionPriority = priority;
667       break;
668     }
669     case ButtonsSelectAll:
670     {
671       mSelectAllOptionPriority = priority;
672       break;
673     }
674     case ButtonsClipboard:
675     {
676       mClipboardOptionPriority = priority;
677       break;
678     }
679     case ButtonsEnumEnd:
680     {
681       DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
682       break;
683     }
684   }
685   CreateOrderedListOfOptions(); // Update list of options as priority changed.
686 }
687
688 unsigned int TextInputPopup::GetButtonPriorityPosition( TextInputPopup::Buttons button ) const
689 {
690   unsigned int priority = 0;
691
692   switch ( button )
693   {
694     case ButtonsCut:
695     {
696       priority = mCutOptionPriority;
697       break;
698     }
699     case ButtonsCopy:
700     {
701       priority = mCopyOptionPriority;
702       break;
703     }
704     case ButtonsPaste:
705     {
706       priority = mPasteOptionPriority;
707       break;
708     }
709     case ButtonsSelect:
710     {
711       priority = mSelectOptionPriority;
712       break;
713     }
714     case ButtonsSelectAll:
715     {
716       priority = mSelectAllOptionPriority;
717       break;
718     }
719     case ButtonsClipboard:
720     {
721       priority = mClipboardOptionPriority;
722       break;
723     }
724     case ButtonsEnumEnd:
725     {
726       DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
727       break;
728     }
729   }
730
731   return priority;
732 }
733
734 void TextInputPopup::AddPopupOptions()
735 {
736   for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
737   {
738     const ButtonRequirement& button( *it );
739     if (  button.enabled )
740     {
741       AddOption( button.name, button.caption, button.iconImage, false );
742     }
743   }
744 }
745
746
747 bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
748 {
749   mPressedSignal.Emit( button );
750   return false;
751 }
752
753 void TextInputPopup::OnHideFinished(Animation& source)
754 {
755   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnHideFinished );
756   Clear();
757   mState = StateHidden;
758   mHideFinishedSignal.Emit( *this );
759 }
760
761 void TextInputPopup::OnShowFinished(Animation& source)
762 {
763   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnShowFinished );
764   mState = StateShown;
765   mShowFinishedSignal.Emit( *this );
766 }
767
768 TextInputPopup::PressedSignalV2& TextInputPopup::PressedSignal()
769 {
770   return mPressedSignal;
771 }
772
773 TextInputPopup::HideFinishedSignalV2& TextInputPopup::HideFinishedSignal()
774 {
775   return mHideFinishedSignal;
776 }
777
778 TextInputPopup::ShowFinishedSignalV2& TextInputPopup::ShowFinishedSignal()
779 {
780   return mShowFinishedSignal;
781 }
782
783 } // namespace Internal
784
785 } // namespace Toolkit
786
787 } // namespace Dali