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