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" );
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
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();
}
}
// 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();
}
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 );
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
{
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 )
{
- 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.
+ alternativePopUpPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + BOTTOM_HANDLE_BOTTOM_OFFSET ;
}
mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
}
// 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 );
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::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 );
// 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) );
-// 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.
// 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 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
* 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 )
{
}
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)
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;
}
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
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),
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();
{
if ( mBackground )
{
- mRootActor.Remove( mBackground );
- mBackground.Reset();
+ UnparentAndReset( mStencil );
+ UnparentAndReset( mBackground );
+ UnparentAndReset( mScrollView );
+ UnparentAndReset( mLayer );
mButtonContainer.clear();
mDividerContainer.clear();
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;
-
Hide(false);
AddToStage();
{
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);
-
mBackground.Add( divider );
mContentSize.width += DIVIDER_WIDTH;
}
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 );
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 );
{
if(mBackground)
{
+ mBackground.SetSensitive( true );
+
if(mAnimation)
{
mAnimation.Clear();
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 )
{