TextInput PopUp supports scrolling if buttons do not fit in visible area. 64/24164/1
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Wed, 11 Jun 2014 20:39:37 +0000 (21:39 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 8 Jul 2014 17:47:04 +0000 (18:47 +0100)
[problem]      If too many buttons in popup then part of it can be off screen
[solution]     Popup using a scroll view and allows scrolling of the buttons

Change-Id: I92b269c24a81d891ffa4ab4011dd86d0f9fc96e4
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
base/dali-toolkit/internal/controls/text-input/text-input-impl.cpp
base/dali-toolkit/internal/controls/text-input/text-input-impl.h
base/dali-toolkit/internal/controls/text-input/text-input-popup-impl.cpp
base/dali-toolkit/internal/controls/text-input/text-input-popup-impl.h

index 8b962fc..d615942 100644 (file)
@@ -44,7 +44,7 @@ const std::size_t DEFAULT_NUMBER_OF_LINES_LIMIT( std::numeric_limits<std::size_t
 const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f );  // Selection cursor image size
 const Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f );  // Selection cursor image size
 const Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
-const Vector4 LIGHTBLUE( 10.0f/255.0f, 140.0f/255.0f, 210.0f/255.0f, 1.0f );    // Used for Selection highlight
+const Vector4 LIGHTBLUE( 0.07f, 0.41f, 0.59f, 1.0f );    // Used for Selection highlight
 
 const char* DEFAULT_GRAB_HANDLE( DALI_IMAGE_DIR "insertpoint-icon.png" );
 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
 
 const char* DEFAULT_GRAB_HANDLE( DALI_IMAGE_DIR "insertpoint-icon.png" );
 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
@@ -782,6 +782,9 @@ void TextInput::SetBoundingRectangle( const Rect<float>& boundingRectangle )
                           originY + boundingRectangle.height );
 
   mBoundingRectangleWorldCoordinates = boundary;
                           originY + boundingRectangle.height );
 
   mBoundingRectangleWorldCoordinates = boundary;
+
+  // Set Boundary for Popup so it keeps the Pop-up within the area also.
+  mPopUpPanel.SetPopupBoundary( boundingRectangle );
 }
 
 const Rect<float> TextInput::GetBoundingRectangle() const
 }
 
 const Rect<float> TextInput::GetBoundingRectangle() const
@@ -1386,7 +1389,7 @@ void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap)
      SelectText( start, end );
    }
    // if no text but clipboard has content then show paste option
      SelectText( start, end );
    }
    // if no text but clipboard has content then show paste option
-   if ( mClipboard.NumberOfItems() || !mStyledText.empty() )
+   if ( ( mClipboard && mClipboard.NumberOfItems() ) || !mStyledText.empty() )
    {
      ShowPopupCutCopyPaste();
    }
    {
      ShowPopupCutCopyPaste();
    }
@@ -1576,7 +1579,7 @@ void TextInput::OnLongPress(Dali::Actor actor, Dali::LongPressGesture longPress)
     }
 
     // if no text but clipboard has content then show paste option, if no text and clipboard empty then do nothing
     }
 
     // if no text but clipboard has content then show paste option, if no text and clipboard empty then do nothing
-    if ( mClipboard.NumberOfItems() || !mStyledText.empty() )
+    if ( ( mClipboard && mClipboard.NumberOfItems() ) || !mStyledText.empty() )
     {
       ShowPopupCutCopyPaste();
     }
     {
       ShowPopupCutCopyPaste();
     }
@@ -3697,11 +3700,6 @@ void TextInput::AddPopupOptions()
   mPopUpPanel.AddPopupOptions();
 }
 
   mPopUpPanel.AddPopupOptions();
 }
 
-void TextInput::AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption)
-{
-  mPopUpPanel.AddOption(name, caption, icon, finalOption);
-}
-
 void TextInput::SetPopupPosition(const Vector3& position)
 {
   mPopUpPanel.Self().SetPosition( position );
 void TextInput::SetPopupPosition(const Vector3& position)
 {
   mPopUpPanel.Self().SetPosition( position );
@@ -3747,7 +3745,7 @@ void TextInput::ShowPopup(bool animate)
     Vector3 bottomHandle;
     bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
     bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
     Vector3 bottomHandle;
     bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
     bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
-    mPopUpPanel.SetAlternativeOffset(Vector2(0.0f, bottomHandle.y - topHandle.y));
+    mPopUpPanel.SetAlternativeOffset(Vector2( mBoundingRectangleWorldCoordinates.x, bottomHandle.y - topHandle.y));
   }
   else
   {
   }
   else
   {
@@ -3756,11 +3754,11 @@ void TextInput::ShowPopup(bool animate)
     const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition );
     position.y -= rowSize.height;
     // if can't be positioned above, then position below row.
     const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition );
     position.y -= rowSize.height;
     // if can't be positioned above, then position below row.
-    Vector2 alternativePopUpPosition( 0.0f, position.y ); // default if no grab handle
+    Vector2 alternativePopUpPosition( mBoundingRectangleWorldCoordinates.x, position.y ); // default if no grab handle
     if ( mGrabHandle )
     {
     if ( mGrabHandle )
     {
-      alternativePopUpPosition.y = rowSize.height + ( mGrabHandle.GetCurrentSize().height * DEFAULT_GRAB_HANDLE_RELATIVE_SIZE.y ) ;
       // If grab handle enabled then position pop-up below the grab handle.
       // If grab handle enabled then position pop-up below the grab handle.
+      alternativePopUpPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + BOTTOM_HANDLE_BOTTOM_OFFSET ;
     }
     mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
   }
     }
     mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
   }
@@ -3768,7 +3766,7 @@ void TextInput::ShowPopup(bool animate)
   // reposition popup above the desired cursor posiiton.
   Vector3 textViewSize = mDisplayedTextView.GetCurrentSize();
   textViewSize.z = 0.0f;
   // reposition popup above the desired cursor posiiton.
   Vector3 textViewSize = mDisplayedTextView.GetCurrentSize();
   textViewSize.z = 0.0f;
-  // World position = world position of ParentOrigin of cursor (i.e. top-left corner of TextView) + cursor position;
+  // World position = world position of local position i.e. top-left corner of TextView
   Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position;
 
   SetPopupPosition( worldPosition );
   Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position;
 
   SetPopupPosition( worldPosition );
@@ -3798,7 +3796,7 @@ void TextInput::ShowPopupCutCopyPaste()
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
 
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
 
-  if( mClipboard.NumberOfItems() )
+  if( mClipboard && mClipboard.NumberOfItems() )
   {
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
   {
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
@@ -3822,7 +3820,7 @@ void TextInput::SetUpPopUpSelection()
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
   // if clipboard has valid contents then offer paste option
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
   // if clipboard has valid contents then offer paste option
-  if( mClipboard.NumberOfItems() )
+  if( mClipboard && mClipboard.NumberOfItems() )
   {
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
   {
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
     mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
index b9f3233..9eb5ee6 100644 (file)
@@ -1060,17 +1060,6 @@ public:  // Public to allow internal testing.
   void AddPopupOptions();
 
   /**
   void AddPopupOptions();
 
   /**
-   * Adds a popup option.
-   * @note Creates popup frame if not already created.
-   * @param[in] name The unique name for this option.
-   * @param[in] caption The caption (label) for this option
-   * @param[in] icon the image icon to be displayed for this option
-   * @param[in] finalOption Flag to indicate that this is the final option.
-   * (set to true on the last option you add)
-   */
-  void AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption = false);
-
-  /**
    * Sets popup position
    * @param[in] position The actual position for this popup.
    */
    * Sets popup position
    * @param[in] position The actual position for this popup.
    */
index ca1c16a..9df837f 100644 (file)
@@ -31,14 +31,11 @@ namespace {
 
 // Default Colors
 
 
 // Default Colors
 
-const Vector4 DEFAULT_POPUP_BACKGROUND( Vector4( 0.24f, 0.41f, 0.88f, 1.0f ) );
-const Vector4 DEFAULT_POPUP_BUTTON_PRESSED( Vector4( 0.18f, 0.56f, 1.0f, 1.0f ) );
-const Vector4 DEFAULT_BORDER_COLOR( Vector4( 0.2f, 0.2f, 0.2f, 1.0f ) );
+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) );
 
 const Vector3 POPUP_BORDER( Vector3(1.0f, 1.0f, 0.0f) );
 
-// Popup: Divider
-const char* DEFAULT_PANEL_BUTTON_DIVIDER = DALI_IMAGE_DIR "copypanelLine.png";
-
 /* 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.
 /* 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.
@@ -50,7 +47,9 @@ const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "00_popup_bubble_tail_bott
 // 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.
 // 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 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_TEXT_OFFSET( 0.0f, 0.0f, 0.0f );
 const Vector3 POPUP_TEXT_ENLARGE( 12.0f, 28.0f, 0.0f );
@@ -62,7 +61,7 @@ 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 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(0.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
 
 
 const float DEFAULT_UI_FONT_SIZE(7.0f);                                     ///< Standard font size for Text-Input's UI
 
@@ -97,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)
    * 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),
   : mMinIndent(topLeftMargin),
     mMaxIndent(bottomRightMargin),
     mFlipHorizontal(flipHorizontal),
-    mFlipVertical(flipVertical)
+    mFlipVertical(flipVertical),
+    mBoundingRect( boundingRect )
   {
   }
 
   {
   }
 
@@ -127,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 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);
 
     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)
     }
 
     if(mFlipVertical && corner.y < 0.0f)
@@ -141,27 +156,17 @@ struct ConfinementConstraint
       newPosition.y += size.height + alternativeOffset.height;
     }
 
       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;
 
     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;
     }
 
     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;
   }
 
     return newPosition;
   }
 
@@ -169,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
   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
 };
 
 } // unnamed namespace
@@ -186,12 +192,12 @@ 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::SIGNAL_HIDE_FINISHED = "hide-finished";
 const char* const TextInputPopup::SIGNAL_SHOW_FINISHED = "show-finished";
 
-const char* const TextInputPopup::OPTION_SELECT_WORD = "select_word";                       // "Select Word" popup option.
-const char* const TextInputPopup::OPTION_SELECT_ALL("select_all");                          // "Select All" popup option.
-const char* const TextInputPopup::OPTION_CUT("cut");                                        // "Cut" popup option.
-const char* const TextInputPopup::OPTION_COPY("copy");                                      // "Copy" popup option.
-const char* const TextInputPopup::OPTION_PASTE("paste");                                    // "Paste" popup option.
-const char* const TextInputPopup::OPTION_CLIPBOARD("clipboard");                            // "Clipboard" popup option.
+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),
 
 TextInputPopup::TextInputPopup()
 : mState(StateHidden),
@@ -241,11 +247,61 @@ void TextInputPopup::ApplyConfinementConstraint()
                                                     LocalSource( mAlternativeOffsetProperty ),
                                                     ConfinementConstraint( DEFAULT_POPUP_INDICATOR_OFFSET,
                                                                            Vector2::ZERO,
                                                     LocalSource( mAlternativeOffsetProperty ),
                                                     ConfinementConstraint( DEFAULT_POPUP_INDICATOR_OFFSET,
                                                                            Vector2::ZERO,
-                                                                           false,
-                                                                           true) );
+                                                                           true,
+                                                                           true, mBoundingRect ) );
   mRootActor.ApplyConstraint(constraint);
 }
 
   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();
 void TextInputPopup::RemoveFromStage()
 {
   Actor rootActor = Self();
@@ -256,8 +312,10 @@ void TextInputPopup::Clear()
 {
   if ( mBackground )
   {
 {
   if ( mBackground )
   {
-    mRootActor.Remove( mBackground );
-    mBackground.Reset();
+    UnparentAndReset( mStencil );
+    UnparentAndReset( mBackground );
+    UnparentAndReset( mScrollView );
+    UnparentAndReset( mLayer );
     mButtonContainer.clear();
     mDividerContainer.clear();
 
     mButtonContainer.clear();
     mDividerContainer.clear();
 
@@ -298,10 +356,10 @@ void TextInputPopup::CreatePopUpBackground()
   if ( !mBackground )
   {
     mBackground = Toolkit::CreateSolidColorActor( GetCutPastePopUpColor(), true, mBorderColor );
   if ( !mBackground )
   {
     mBackground = Toolkit::CreateSolidColorActor( GetCutPastePopUpColor(), true, mBorderColor );
-
-    Self().Add( mBackground );
+    mBackground.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    mBackground.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    mBackground.SetName("pop-up-background");
     mContentSize = POPUP_TEXT_OFFSET;
     mContentSize = POPUP_TEXT_OFFSET;
-
     Hide(false);
     AddToStage();
 
     Hide(false);
     AddToStage();
 
@@ -321,15 +379,13 @@ void TextInputPopup::CreateDivider()
 {
   if(mButtonContainer.size() > 0)
   {
 {
   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, 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);
     divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
     divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
     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;
   }
     mBackground.Add( divider );
     mContentSize.width += DIVIDER_WIDTH;
   }
@@ -475,7 +531,7 @@ 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) );
   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.SetParentOrigin( ParentOrigin::TOP_LEFT );
   button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
@@ -522,11 +578,6 @@ void TextInputPopup::AddOption(const std::string& name, const std::string& capti
     i->SetSize( DIVIDER_WIDTH, dividerHeight );
   }
 
     i->SetSize( DIVIDER_WIDTH, dividerHeight );
   }
 
-  Vector3 popupSize( Max(mContentSize, 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 );
   mTail.SetPosition(Vector3(0.0f, -20.0f, 0.0f));
 
   button.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
@@ -565,6 +616,8 @@ void TextInputPopup::Show(bool animate)
 {
   if(mBackground)
   {
 {
   if(mBackground)
   {
+    mBackground.SetSensitive( true );
+
     if(mAnimation)
     {
       mAnimation.Clear();
     if(mAnimation)
     {
       mAnimation.Clear();
@@ -741,8 +794,31 @@ void TextInputPopup::AddPopupOptions()
       AddOption( button.name, button.caption, button.iconImage, false );
     }
   }
       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 )
 {
 
 bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
 {
index 81186df..cd5b2be 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/dali.h>
 
 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
 #include <dali/dali.h>
 
 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
 
 namespace Dali
 {
 
 namespace Dali
 {
@@ -253,6 +254,12 @@ public:
    */
   void AddPopupOptions();
 
    */
   void AddPopupOptions();
 
+  /**
+   * Set Boundary that PopUp should stay within
+   * @param[in] boundingRectangle coordinates of bounding box from Top Left
+   */
+  void SetPopupBoundary( const Rect<float>& boundingRectangle );
+
 private:
 
   /**
 private:
 
   /**
@@ -278,6 +285,37 @@ private:
   void ApplyConfinementConstraint();
 
   /**
   void ApplyConfinementConstraint();
 
   /**
+   * Create a layer to hold the stencil
+   * @param[in] size Size to of layer
+   */
+  void CreateLayer(  const Vector2& size );
+
+  /**
+   * Create a stencil to clip the scroll view content
+   * @param[in] size Size to of stencil
+   */
+  void CreateStencil( const Vector2& size );
+
+  /**
+   * Popup has started to scroll
+   * @param[in] position current scroll view position
+   */
+  void OnScrollStarted( const Vector3& position );
+
+  /**
+   * Popup has stopped scrolling
+   * @param[in] position current scroll view position
+   */
+  void OnScrollCompleted( const Vector3& position );
+
+  /**
+   * Create a scroll view to hold the popup buttons and allow scrolling if too many buttons to fit within the visible boundary
+   * @param[in] scrollViewSize size of content of the scroll view which can exceed its visible size
+   * @param[in] visibleSize size of the visible scroll view
+   */
+  void CreateScrollView( const Vector2& scrollViewSize, const Vector2& visibleSize );
+
+  /**
    * Removes Popup from the stage.
    */
   void RemoveFromStage();
    * Removes Popup from the stage.
    */
   void RemoveFromStage();
@@ -314,12 +352,18 @@ private:
   ActorContainer mDividerContainer;                   ///< List of dividers added to popup.
   Animation mAnimation;                               ///< Popup Hide/Show animation.
 
   ActorContainer mDividerContainer;                   ///< List of dividers added to popup.
   Animation mAnimation;                               ///< Popup Hide/Show animation.
 
+  Actor mStencil;                                     ///< Stencil to clip scrollview
+  Toolkit::ScrollView mScrollView;                    ///< Scrollview to house the popup
+  Layer mLayer;                                       ///< Layer to house the scroll view and stencil
+
   std::vector<ButtonRequirement> mOrderListOfButtons;        // List of buttons in the order to be displayed and a flag to indicate if needed.
 
   Vector4           mCutPasteButtonsColor;  // Color of the cut and paste popup
   Vector4           mCutPasteButtonsPressedColor;  // Color of the cut and paste buttons when pressed.
   Vector4           mBorderColor; // Color of the border around the Cut and Paste Popup
 
   std::vector<ButtonRequirement> mOrderListOfButtons;        // List of buttons in the order to be displayed and a flag to indicate if needed.
 
   Vector4           mCutPasteButtonsColor;  // Color of the cut and paste popup
   Vector4           mCutPasteButtonsPressedColor;  // Color of the cut and paste buttons when pressed.
   Vector4           mBorderColor; // Color of the border around the Cut and Paste Popup
 
+  Rect<float> mBoundingRect; // Boundary that Popup must stay within.
+
   // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right.
   std::size_t mSelectOptionPriority;  // Position of Select Button
   std::size_t mSelectAllOptionPriority; // Position of Select All button
   // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right.
   std::size_t mSelectOptionPriority;  // Position of Select Button
   std::size_t mSelectAllOptionPriority; // Position of Select All button