TextInput PopUp supports scrolling if buttons do not fit in visible area.
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-input / text-input-popup-impl.cpp
index 7d9bf42..9df837f 100644 (file)
@@ -1,71 +1,67 @@
-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
 
 #include <dali-toolkit/internal/controls/text-input/text-input-popup-impl.h>
+
 #include <dali-toolkit/public-api/controls/buttons/push-button.h>
+#include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
+
+#include <libintl.h>
 
 using namespace std;
 using namespace Dali;
 
+#define GET_LOCALE_TEXT(string) dgettext("sys_string", string)
+
 namespace {
 
-// Popup: Background
-const char* DEFAULT_PANEL_BACKGROUND = DALI_IMAGE_DIR "cutCopyPastePopup_bg.png";
+// Default Colors
 
-// Popup: Divider
-const char* DEFAULT_PANEL_BUTTON_DIVIDER = DALI_IMAGE_DIR "copypanelLine.png";
+const Vector4 DEFAULT_POPUP_BACKGROUND( Vector4( .20f, 0.29f, 0.44f, 1.0f ) );
+const Vector4 DEFAULT_POPUP_BUTTON_PRESSED( Vector4( 0.07f, 0.10f, 0.17f, 1.0f ) );
+const Vector4 DEFAULT_BORDER_COLOR( Vector4( 0.36f, 0.45f, 0.59f, 1.0f ) );
+const Vector3 POPUP_BORDER( Vector3(1.0f, 1.0f, 0.0f) );
 
 /* Functionality in place to have the end buttons using different images to inner button.
  * Supply a centre image and then a left and right image, the centre image can have straight ends while
  * 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.
  */
 
-// Popup: Left Pressed Highlight
-const char* DEFAULT_BUTTON_HIGHLIGHT_LEFT( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
-const Vector4 DEFAULT_BUTTON_HIGHLIGHT_LEFT_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
-
-// Popup: Center Pressed Highlight
-const char* DEFAULT_BUTTON_HIGHLIGHT_CENTER( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
-const Vector4 DEFAULT_BUTTON_HIGHLIGHT_CENTER_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
-
-// Popup: Right Pressed Highlight
-const char* DEFAULT_BUTTON_HIGHLIGHT_RIGHT( DALI_IMAGE_DIR "00_popup_button_pressed.png" );
-const Vector4 DEFAULT_BUTTON_HIGHLIGHT_RIGHT_BORDER( 6.0f, 9.0f, 6.0f, 9.0f );
-
 // Popup: Tails
 const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "00_popup_bubble_tail_bottom.png" );
 
 // Popup: Vertical Constraint
 // TODO: Remove - this should come from application - it is not possible to get the
 // height of the indicator actor from Dali-Toolkit.
-const Vector2 DEFAULT_POPUP_INDICATOR_OFFSET(0.0f, 60.0f);
 
-const Vector4 BACKGROUND_IMAGE_BORDER( 22.0f, 20.0f, 29.0f, 27.0f );
-const Vector2 BACKGROUND_IMAGE_SIZE( 50.0f, 54.0f );
-const Vector3 POPUP_TEXT_OFFSET( 12.0f, 10.0f, 0.0f );
+const float POP_UP_SCREEN_EDGE_MARGIN( 4.0f );
+const Vector2 DEFAULT_POPUP_INDICATOR_OFFSET(POP_UP_SCREEN_EDGE_MARGIN, 60.0f);
+
+const Vector3 POPUP_TEXT_OFFSET( 0.0f, 0.0f, 0.0f );
 const Vector3 POPUP_TEXT_ENLARGE( 12.0f, 28.0f, 0.0f );
 const Vector3 POPUP_MINIMUM_SIZE( 128.0f, 124.0f, 0.0f );
 
 const Vector3 BUTTON_TEXT_ENLARGE( 32.0f, 0.0f, 0.0f );
 const Vector3 BUTTON_TEXT_MINIMUM_SIZE( 128.0f, 126.0f, 0.0f );
-const Vector3 BUTTON_TEXT_MAXIMUM_SIZE( 196.0f, 126.0f, 0.0f );
+const Vector3 BUTTON_TEXT_MAXIMUM_SIZE( 190.0f, 126.0f, 0.0f );
 const Vector3 TEXT_LABEL_MAX_SIZE( 160.0f, 30.0f, 0.0f );
 
 const float DIVIDER_WIDTH(2.0f);                                            ///< Width of each button divider
-const float DIVIDER_MARGIN(10.0f);                                          ///< Top/Bottom Margin between divider and edge of popup.
+const float DIVIDER_MARGIN(0.0f);                                           ///< Top/Bottom Margin between divider and edge of popup.
 
 const float DEFAULT_UI_FONT_SIZE(7.0f);                                     ///< Standard font size for Text-Input's UI
 
@@ -76,6 +72,13 @@ const Vector2 DEFAULT_ICON_SIZE( 45.0f, 45.0f );                            ///<
 const float TEXT_POSITION_OFFSET( -19.0f );                                  ///< Default offset for text label
 const float ICON_POSITION_OFFSET( 19.0f );                                  ///< Default offset for icon
 
+const char* DEFAULT_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
+const char* DEFAULT_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
+const char* DEFAULT_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
+const char* DEFAULT_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" );
+const char* DEFAULT_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
+const char* DEFAULT_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
+
 // TODO: This should be based on the content for example:
 // 1. For selection: should be above top of highlighted selection, or below bottom of highlighted selection + end handle.
 // 2. For cursor: should be above top of cursor, or below bottom of cursor + grab handle.
@@ -93,14 +96,17 @@ struct ConfinementConstraint
    * Confinement constraint constructor.
    * @param[in] topLeftMargin (optional) Top-Left margins (defaults to 0.0f, 0.0f)
    * @param[in] bottomRightMargin (optional) Bottom-Right margins (defaults to 0.0f, 0.0f)
-   * @param[in] flipVertical (optional) whether to flip Actor to the other side if near edge, and by
-   * how much (defaults to 0.0f i.e. no flip)
+   * @paran[in[ flipHorizontal (optional) whether to flip Actor to other side if near edge
+   * @param[in] flipVertical (optional) whether to flip Actor to the other side if near edge
+   * @param[in] boundingRect Rectangle to bound Popup to.
+   *
    */
-  ConfinementConstraint(Vector2 topLeftMargin = Vector2::ZERO, Vector2 bottomRightMargin = Vector2::ZERO, bool flipHorizontal = false, bool flipVertical = false)
+  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) )
   : mMinIndent(topLeftMargin),
     mMaxIndent(bottomRightMargin),
     mFlipHorizontal(flipHorizontal),
-    mFlipVertical(flipVertical)
+    mFlipVertical(flipVertical),
+    mBoundingRect( boundingRect )
   {
   }
 
@@ -123,12 +129,25 @@ struct ConfinementConstraint
     Vector3 position(constPosition + origin * referenceSize);
 
     // if top-left corner is outside of Top-Left bounds, then push back in screen.
+
     Vector3 corner(position - size * anchor - mMinIndent);
 
-    if(mFlipHorizontal && corner.x < 0.0f)
+    newPosition.x -= std::max(corner.x, 0.0f);
+
+    if ( mFlipHorizontal )
     {
-      corner.x = 0.0f;
-      newPosition.x += size.width + alternativeOffset.width;
+      if( corner.x < mBoundingRect.x + POP_UP_SCREEN_EDGE_MARGIN )
+      {
+        // Snap PopUp to left hand boundary so stays visible
+        corner.x = mBoundingRect.x + POP_UP_SCREEN_EDGE_MARGIN ;
+      }
+      else if ( ( corner.x + size.x ) > ( ( mBoundingRect.x + mBoundingRect.width ) - POP_UP_SCREEN_EDGE_MARGIN ))
+      {
+        // Calculate offset from left boundary PopUp must be placed at so it does not exceed right side boundary.
+        float requiredOffSetFromLeftBoundaryToFit = mBoundingRect.width - POP_UP_SCREEN_EDGE_MARGIN - size.x;
+        corner.x = mBoundingRect.x + requiredOffSetFromLeftBoundaryToFit - ( origin.x * referenceSize.x ) + ( size.x * anchor.x );
+       }
+      newPosition.x = corner.x;
     }
 
     if(mFlipVertical && corner.y < 0.0f)
@@ -137,27 +156,17 @@ struct ConfinementConstraint
       newPosition.y += size.height + alternativeOffset.height;
     }
 
-    newPosition.x -= std::min(corner.x, 0.0f);
     newPosition.y -= std::min(corner.y, 0.0f);
 
     // if bottom-right corner is outside of Bottom-Right bounds, then push back in screen.
     corner += size - referenceSize + mMinIndent + mMaxIndent;
 
-    if(mFlipHorizontal && corner.x > 0.0f)
-    {
-      corner.x = 0.0f;
-      newPosition.x -= size.width + alternativeOffset.width;
-    }
-
     if(mFlipVertical && corner.y > 0.0f)
     {
       corner.y = 0.0f;
       newPosition.y -= size.height + alternativeOffset.height;
     }
 
-    newPosition.x -= std::max(corner.x, 0.0f);
-    newPosition.y -= std::max(corner.y, 0.0f);
-
     return newPosition;
   }
 
@@ -165,6 +174,7 @@ struct ConfinementConstraint
   Vector3 mMaxIndent;                                   ///< Bottom-Right Margin.
   bool mFlipHorizontal;                                 ///< Whether to flip actor's position if exceeds horizontal screen bounds
   bool mFlipVertical;                                   ///< Whether to flip actor's position if exceeds vertical screen bounds
+  Rect<float> mBoundingRect;                            ///< Bounding Rect Popup must stay within
 };
 
 } // unnamed namespace
@@ -182,9 +192,26 @@ const char* const TextInputPopup::SIGNAL_PRESSED = "pressed";
 const char* const TextInputPopup::SIGNAL_HIDE_FINISHED = "hide-finished";
 const char* const TextInputPopup::SIGNAL_SHOW_FINISHED = "show-finished";
 
+const char* const TextInputPopup::OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
+const char* const TextInputPopup::OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
+const char* const TextInputPopup::OPTION_CUT("option-cut");                                        // "Cut" popup option.
+const char* const TextInputPopup::OPTION_COPY("option-copy");                                      // "Copy" popup option.
+const char* const TextInputPopup::OPTION_PASTE("option-paste");                                    // "Paste" popup option.
+const char* const TextInputPopup::OPTION_CLIPBOARD("option-clipboard");                            // "Clipboard" popup option.
+
 TextInputPopup::TextInputPopup()
 : mState(StateHidden),
   mRootActor(Layer::New()),
+  mContentSize( Vector3::ZERO ),
+  mCutPasteButtonsColor( DEFAULT_POPUP_BACKGROUND ),
+  mCutPasteButtonsPressedColor( DEFAULT_POPUP_BUTTON_PRESSED ),
+  mBorderColor( DEFAULT_BORDER_COLOR ),
+  mSelectOptionPriority(1),
+  mSelectAllOptionPriority(2),
+  mCutOptionPriority(3),
+  mCopyOptionPriority(4),
+  mPasteOptionPriority(5),
+  mClipboardOptionPriority(6),
   mPressedSignal(),
   mHideFinishedSignal(),
   mShowFinishedSignal()
@@ -220,11 +247,61 @@ void TextInputPopup::ApplyConfinementConstraint()
                                                     LocalSource( mAlternativeOffsetProperty ),
                                                     ConfinementConstraint( DEFAULT_POPUP_INDICATOR_OFFSET,
                                                                            Vector2::ZERO,
-                                                                           false,
-                                                                           true) );
+                                                                           true,
+                                                                           true, mBoundingRect ) );
   mRootActor.ApplyConstraint(constraint);
 }
 
+void TextInputPopup::CreateLayer( const Vector2& size )
+{
+  mLayer = Layer::New();
+  mLayer.SetParentOrigin(ParentOrigin::CENTER);
+  mLayer.SetAnchorPoint(AnchorPoint::CENTER);
+  mLayer.SetSize( size ); // matches stencil size
+  mLayer.SetName("popup-mLayer");
+}
+
+void TextInputPopup::CreateStencil( const Vector2& size )
+{
+  mStencil = CreateSolidColorActor( Color::BLUE );
+  mStencil.SetParentOrigin( Vector3( ParentOrigin::CENTER ) );
+  mStencil.SetAnchorPoint( AnchorPoint::CENTER );
+  mStencil.SetDrawMode( DrawMode::STENCIL );
+  mStencil.SetSize( size  ); // slightly smaller than layer and stencil so over shoot always inside.
+  mStencil.SetVisible( true );
+  mStencil.SetName("popup-stencil");
+}
+
+void TextInputPopup::OnScrollStarted( const Vector3& position )
+{
+  mBackground.SetSensitive( false );
+}
+
+void TextInputPopup::OnScrollCompleted( const Vector3& position )
+{
+  mBackground.SetSensitive( true );
+}
+
+void TextInputPopup::CreateScrollView( const Vector2& domainSize, const Vector2& visibleSize )
+{
+  mScrollView = Toolkit::ScrollView::New();
+  mScrollView.SetName("popup-scroll-view");
+  mScrollView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mScrollView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  mScrollView.SetSize( visibleSize.x, visibleSize.y  );
+  mScrollView.SetScrollingDirection( PanGestureDetector::DIRECTION_HORIZONTAL, Degree( 40.0f ) );
+  mScrollView.SetAxisAutoLock( true );
+  mScrollView.ScrollStartedSignal().Connect( this, &TextInputPopup::OnScrollStarted );
+  mScrollView.ScrollCompletedSignal().Connect( this, &TextInputPopup::OnScrollCompleted );
+
+  RulerPtr rulerX = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+  RulerPtr rulerY = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+  rulerY->Disable();
+  rulerX->SetDomain( RulerDomain( 0, domainSize.width, true ) );
+  mScrollView.SetRulerX(rulerX);
+  mScrollView.SetRulerY(rulerY);
+}
+
 void TextInputPopup::RemoveFromStage()
 {
   Actor rootActor = Self();
@@ -235,8 +312,10 @@ void TextInputPopup::Clear()
 {
   if ( mBackground )
   {
-    mRootActor.Remove( mBackground );
-    mBackground.Reset();
+    UnparentAndReset( mStencil );
+    UnparentAndReset( mBackground );
+    UnparentAndReset( mScrollView );
+    UnparentAndReset( mLayer );
     mButtonContainer.clear();
     mDividerContainer.clear();
 
@@ -276,19 +355,11 @@ void TextInputPopup::CreatePopUpBackground()
   // Create background-panel if not already created (required if we have at least one option)
   if ( !mBackground )
   {
-    Image backgroundImage = Image::New( DEFAULT_PANEL_BACKGROUND );
-
-    mBackground = ImageActor::New( backgroundImage );
-    // Expand background from bottom-center of root actor.
-    mBackground.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
-    mBackground.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
-    mBackground.SetStyle( ImageActor::STYLE_NINE_PATCH );
-
-    mBackground.SetNinePatchBorder( Vector4(13.0f, 13.0f, 13.0f, 13.0f) );
-
-    Self().Add( mBackground );
+    mBackground = Toolkit::CreateSolidColorActor( GetCutPastePopUpColor(), true, mBorderColor );
+    mBackground.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    mBackground.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    mBackground.SetName("pop-up-background");
     mContentSize = POPUP_TEXT_OFFSET;
-
     Hide(false);
     AddToStage();
 
@@ -308,51 +379,124 @@ void TextInputPopup::CreateDivider()
 {
   if(mButtonContainer.size() > 0)
   {
-    Image dividerImage = Image::New( DEFAULT_PANEL_BUTTON_DIVIDER );
-    ImageActor divider = ImageActor::New( dividerImage );
+    ImageActor divider = Toolkit::CreateSolidColorActor( mBorderColor );
     divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
     divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-    divider.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y + 5.0f, 0.0f ) );
+    divider.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y, 0.0f ) );
     // Keep track of all the dividers. As their height's need to be updated to the max. of all
     // buttons currently added.
     mDividerContainer.push_back(divider);
-
     mBackground.Add( divider );
     mContentSize.width += DIVIDER_WIDTH;
   }
 }
 
-ImageActor TextInputPopup::CreatePressedBackground( const Vector3 requiredSize, const bool finalFlag )
+ImageActor TextInputPopup::CreatePressedBackground( const Vector3 requiredSize )
 {
   std::string pressedImageFilename;
   Vector4 pressedImageBorder;
   Vector2 pressedImageSize;
 
-  if(mButtonContainer.size() == 0) // LEFT
-  {
-    pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_LEFT;
-    pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_LEFT_BORDER;
-  }
-  else if(!finalFlag) // CENTER
-  {
-    pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_CENTER;
-    pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_CENTER_BORDER;
-  }
-  else // RIGHT
+  ImageActor pressedButtonBg = Toolkit::CreateSolidColorActor( GetCutPastePopUpPressedColor() );
+
+  pressedButtonBg.SetSize ( requiredSize );
+  pressedButtonBg.SetParentOrigin( ParentOrigin::CENTER );
+  pressedButtonBg.SetAnchorPoint( AnchorPoint::CENTER );
+
+  return pressedButtonBg;
+}
+
+TextInputPopup::ButtonRequirement TextInputPopup::CreateRequiredButton( TextInputPopup::Buttons buttonId, std::size_t orderOfPriority,
+                                                                        const std::string& name, const std::string& caption, Image iconImage, bool enabled )
+{
+  TextInputPopup::ButtonRequirement currentButton;
+
+  currentButton.buttonId = buttonId;
+  currentButton.orderOfPriority = orderOfPriority;
+  currentButton.name = name;
+  currentButton.caption = caption;
+  currentButton.iconImage = iconImage;
+  currentButton.enabled = enabled;
+
+  return currentButton;
+}
+
+void TextInputPopup::CreateOrderedListOfOptions()
+{
+  mOrderListOfButtons.clear();
+
+  for ( std::size_t index= 0; index < ButtonsEnumEnd; index++ )
   {
-    pressedImageFilename = DEFAULT_BUTTON_HIGHLIGHT_RIGHT;
-    pressedImageBorder = DEFAULT_BUTTON_HIGHLIGHT_RIGHT_BORDER;
-  }
+    TextInputPopup::ButtonRequirement currentButton;
+
+    // Create button for each possible option using Option priority
+    switch ( index )
+    {
+      case ButtonsCut:
+      {
+        Image cutIcon = Image::New( DEFAULT_ICON_CUT );
+        currentButton = CreateRequiredButton( ButtonsCut, mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon, false );
+        break;
+      }
+      case ButtonsCopy:
+      {
+        Image copyIcon = Image::New( DEFAULT_ICON_COPY );
+        currentButton = CreateRequiredButton( ButtonsCopy, mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, false );
+        break;
+      }
+      case ButtonsPaste:
+      {
+        Image pasteIcon = Image::New( DEFAULT_ICON_PASTE );
+        currentButton = CreateRequiredButton( ButtonsPaste, mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, false );
+        break;
+      }
+      case ButtonsSelect:
+      {
+        Image selectIcon = Image::New( DEFAULT_ICON_SELECT );
+        currentButton = CreateRequiredButton( ButtonsSelect, mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon, false );
+        break;
+      }
+      case ButtonsSelectAll:
+      {
+        Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL );
+        currentButton = CreateRequiredButton( ButtonsSelectAll, mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon, false );
+        break;
+      }
+      case ButtonsClipboard:
+      {
+        Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD );
+        currentButton = CreateRequiredButton( ButtonsClipboard, mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, false );
+        break;
+      }
+      case ButtonsEnumEnd:
+      {
+        DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
+        currentButton.orderOfPriority = 0;
+        break;
+      }
+    }
 
-  Image pressedImage = Image::New( pressedImageFilename );
-  ImageActor pressedImageBg = ImageActor::New( pressedImage );
-  pressedImageBg.SetStyle( ImageActor::STYLE_NINE_PATCH );
-  pressedImageBg.SetNinePatchBorder( pressedImageBorder );
-  pressedImageBg.SetSize ( requiredSize );
-  pressedImageBg.SetParentOrigin( ParentOrigin::CENTER );
-  pressedImageBg.SetAnchorPoint( AnchorPoint::CENTER );
+    bool match = false;
 
-  return pressedImageBg;
+    // Insert button in list of buttons in order of priority setting.
+    for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
+    {
+      const ButtonRequirement& button( *it );
+      if ( currentButton.orderOfPriority < button.orderOfPriority )
+      {
+        if ( currentButton.orderOfPriority != 0 ) // If order priority 0 then do not add button as not required.
+        {
+          mOrderListOfButtons.insert( it, currentButton );
+        }
+        match = true;
+      }
+    }
+
+    if ( !match)
+    {
+      mOrderListOfButtons.push_back( currentButton );
+    }
+  }
 }
 
 void TextInputPopup::AddOption(const std::string& name, const std::string& caption, const Image iconImage,  bool finalOption)
@@ -387,12 +531,12 @@ void TextInputPopup::AddOption(const std::string& name, const std::string& capti
   const Vector3 constrainedTextSize = Min( textSize, TEXT_LABEL_MAX_SIZE );
   Vector3 buttonSize( Max(constrainedTextSize + BUTTON_TEXT_ENLARGE, BUTTON_TEXT_MINIMUM_SIZE) );
   buttonSize = ( Min(buttonSize, BUTTON_TEXT_MAXIMUM_SIZE) );
-  label.SetSize( Min( buttonSize + BUTTON_TEXT_ENLARGE, constrainedTextSize ) );
+  label.SetSize( Min( buttonSize, constrainedTextSize ) );
 
   button.SetParentOrigin( ParentOrigin::TOP_LEFT );
   button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
   button.SetSize( buttonSize );
-  button.SetPosition( Vector3( mContentSize.width, POPUP_TEXT_OFFSET.y, 0.0f ) );
+  button.SetPosition( Vector3( mContentSize.width, POPUP_BORDER.y, 0.0f ) );
 
   // 2. Add icon
   ImageActor icon = CreateOptionIcon( iconImage );
@@ -400,7 +544,7 @@ void TextInputPopup::AddOption(const std::string& name, const std::string& capti
   iconTextContainer.Add( icon );
 
   // 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.
-  ImageActor pressedImageBg = CreatePressedBackground( buttonSize, finalOption );
+  ImageActor pressedImageBg = CreatePressedBackground( buttonSize );
 
   Actor iconPressedTextContainer = Actor::New();
   iconPressedTextContainer.SetDrawMode( DrawMode::OVERLAY );
@@ -424,7 +568,7 @@ void TextInputPopup::AddOption(const std::string& name, const std::string& capti
 
   // Update content size (represents size of all content i.e. from top-left of first button, to bottom-right of last button)
   mContentSize.width += buttonSize.width;
-  mContentSize.height = std::max(mContentSize.height, buttonSize.height);
+  mContentSize.height = std::max(mContentSize.height + ( POPUP_BORDER.y ), buttonSize.height);
   mButtonContainer.push_back(button);
 
   // resize all dividers based on the height content (i.e. max of all button heights)
@@ -434,11 +578,6 @@ void TextInputPopup::AddOption(const std::string& name, const std::string& capti
     i->SetSize( DIVIDER_WIDTH, dividerHeight );
   }
 
-  Vector3 popupSize( Max(mContentSize + POPUP_TEXT_ENLARGE, POPUP_MINIMUM_SIZE) );
-
-  mBackground.SetSize( popupSize );
-  // Make Root Actor reflect the size of its content
-  mRootActor.SetSize( popupSize );
   mTail.SetPosition(Vector3(0.0f, -20.0f, 0.0f));
 
   button.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
@@ -477,6 +616,8 @@ void TextInputPopup::Show(bool animate)
 {
   if(mBackground)
   {
+    mBackground.SetSensitive( true );
+
     if(mAnimation)
     {
       mAnimation.Clear();
@@ -518,6 +659,167 @@ Actor TextInputPopup::GetRootActor() const
   return mRootActor;
 }
 
+// Styling
+
+void TextInputPopup::SetCutPastePopUpColor( const Vector4& color )
+{
+  mCutPasteButtonsColor = color;
+}
+
+const Vector4& TextInputPopup::GetCutPastePopUpColor() const
+{
+  return mCutPasteButtonsColor;
+}
+
+void TextInputPopup::SetCutPastePopUpPressedColor( const Vector4& color )
+{
+  mCutPasteButtonsPressedColor = color;
+}
+
+const Vector4& TextInputPopup::GetCutPastePopUpPressedColor() const
+{
+  return mCutPasteButtonsPressedColor;
+}
+
+void TextInputPopup::TogglePopUpButtonOnOff( TextInputPopup::Buttons requiredButton, bool enable )
+{
+  bool match ( false );
+  for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
+   {
+     ButtonRequirement& button( *it );
+     if ( requiredButton == button.buttonId )
+     {
+       button.enabled = enable;
+       match = true;
+     }
+   }
+}
+
+void TextInputPopup::SetButtonPriorityPosition( TextInputPopup::Buttons button, unsigned int priority )
+{
+  switch ( button )
+  {
+    case ButtonsCut:
+    {
+      mCutOptionPriority = priority;
+      break;
+    }
+    case ButtonsCopy:
+    {
+      mCopyOptionPriority = priority;
+      break;
+    }
+    case ButtonsPaste:
+    {
+      mPasteOptionPriority = priority;
+      break;
+    }
+    case ButtonsSelect:
+    {
+      mSelectOptionPriority = priority;
+      break;
+    }
+    case ButtonsSelectAll:
+    {
+      mSelectAllOptionPriority = priority;
+      break;
+    }
+    case ButtonsClipboard:
+    {
+      mClipboardOptionPriority = priority;
+      break;
+    }
+    case ButtonsEnumEnd:
+    {
+      DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
+      break;
+    }
+  }
+  CreateOrderedListOfOptions(); // Update list of options as priority changed.
+}
+
+unsigned int TextInputPopup::GetButtonPriorityPosition( TextInputPopup::Buttons button ) const
+{
+  unsigned int priority = 0;
+
+  switch ( button )
+  {
+    case ButtonsCut:
+    {
+      priority = mCutOptionPriority;
+      break;
+    }
+    case ButtonsCopy:
+    {
+      priority = mCopyOptionPriority;
+      break;
+    }
+    case ButtonsPaste:
+    {
+      priority = mPasteOptionPriority;
+      break;
+    }
+    case ButtonsSelect:
+    {
+      priority = mSelectOptionPriority;
+      break;
+    }
+    case ButtonsSelectAll:
+    {
+      priority = mSelectAllOptionPriority;
+      break;
+    }
+    case ButtonsClipboard:
+    {
+      priority = mClipboardOptionPriority;
+      break;
+    }
+    case ButtonsEnumEnd:
+    {
+      DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
+      break;
+    }
+  }
+
+  return priority;
+}
+
+void TextInputPopup::AddPopupOptions()
+{
+  for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
+  {
+    const ButtonRequirement& button( *it );
+    if (  button.enabled )
+    {
+      AddOption( button.name, button.caption, button.iconImage, false );
+    }
+  }
+
+  float visiblePopUpWidth = std::min( mContentSize.width - POP_UP_SCREEN_EDGE_MARGIN*2 , mBoundingRect.width - POP_UP_SCREEN_EDGE_MARGIN *2);
+  float visbilePopUpHeight = std::max( mContentSize.height, POPUP_MINIMUM_SIZE.height );
+  Vector2 visiblePopUpSize  = Vector2( visiblePopUpWidth, visbilePopUpHeight );
+
+  visiblePopUpWidth = std::max( visiblePopUpWidth,  POPUP_MINIMUM_SIZE.width );
+
+  mBackground.SetSize( mContentSize.width, mContentSize.height );
+  mRootActor.SetSize( visiblePopUpWidth, visbilePopUpHeight );   // Make Root Actor reflect the size of its content
+
+  CreateLayer( visiblePopUpSize );
+  CreateStencil( visiblePopUpSize );
+  CreateScrollView( Vector2( mContentSize.width, mContentSize.height ), visiblePopUpSize );
+
+  mLayer.Add( mStencil );
+  mLayer.Add( mScrollView );
+  mScrollView.Add( mBackground );
+
+  Self().Add(mLayer);
+}
+
+void TextInputPopup::SetPopupBoundary( const Rect<float>& boundingRectangle )
+{
+  mBoundingRect =  boundingRectangle;
+}
+
 bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
 {
   mPressedSignal.Emit( button );