[problem] User may not know the cut and paste popup applies to the current TextInput
[solution] Display a tail which points to the TextInput.
Change-Id: I712eb34ce00fbf3a02e7fe4bd975fc556b5c97e6
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
const std::size_t CURSOR_BLINK_INTERVAL = 500; ///< Cursor blink interval
const float CHARACTER_THRESHOLD( 2.5f ); ///< the threshold of a line.
-const float DISPLAYED_HIGHLIGHT_Z_OFFSET( 0.0f ); ///< 1. Highlight rendered (z-offset).
-const float DISPLAYED_TEXT_VIEW_Z_OFFSET( 0.1f ); ///< 2. Text rendered (z-offset).
+const float DISPLAYED_HIGHLIGHT_Z_OFFSET( 0.1f ); ///< 1. Highlight rendered (z-offset).
+const float DISPLAYED_TEXT_VIEW_Z_OFFSET( 0.2f ); ///< 2. Text rendered (z-offset).
const float UI_Z_OFFSET( 0.2f ); ///< 3. Text Selection Handles/Cursor z-offset.
const Vector3 UI_OFFSET(0.0f, 0.0f, UI_Z_OFFSET); ///< Text Selection Handles/Cursor offset.
const Vector3 DEFAULT_HANDLE_ONE_OFFSET(0.0f, -5.0f, 0.0f); ///< Handle One's Offset
const Vector3 DEFAULT_HANDLE_TWO_OFFSET(0.0f, -5.0f, 0.0f); ///< Handle Two's Offset
-const float TOP_HANDLE_TOP_OFFSET(-1.5f); ///< Offset between top handle and cutCopyPaste pop-up
-const float BOTTOM_HANDLE_BOTTOM_OFFSET(1.5f); ///< Offset between bottom handle and cutCopyPaste pop-up
+const float TOP_HANDLE_TOP_OFFSET( 34.0f); ///< Offset between top handle and cutCopyPaste pop-up
+const float BOTTOM_HANDLE_BOTTOM_OFFSET(34.0f); ///< Offset between bottom handle and cutCopyPaste pop-up
const float CURSOR_THICKNESS(6.0f);
const Degree CURSOR_ANGLE_OFFSET(2.0f); ///< Offset from the angle of italic angle.
const Property::Index TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+7;
const Property::Index TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+8;
+const Property::Index TextInput::POP_UP_OFFSET_FROM_TEXT_PROPERTY = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+9;
+
namespace Internal
{
mBoundingRectangleWorldCoordinates( 0.0f, 0.0f, 0.0f, 0.0f ),
mClipboard(),
mMaterialColor( LIGHTBLUE ),
+ mPopupOffsetFromText ( Vector4( 0.0f, TOP_HANDLE_TOP_OFFSET, 0.0f, BOTTOM_HANDLE_BOTTOM_OFFSET ) ),
mOverrideAutomaticAlignment( false ),
mCursorRTLEnabled( false ),
mClosestCursorPositionEOL ( false ),
void TextInput::SetPopupPosition(const Vector3& position)
{
mPopUpPanel.Self().SetPosition( position );
+ mPopUpPanel.SetTailPosition( position );
}
void TextInput::HidePopup(bool animate, bool signalFinished )
topHandle = mSelectionHandleTwoActualPosition;
rowSize = GetRowRectFromCharacterPosition( mSelectionHandleTwoPosition );
}
- topHandle.y += TOP_HANDLE_TOP_OFFSET - rowSize.height;
+ topHandle.y += -mPopupOffsetFromText.y - rowSize.height;
position = Vector3(topHandle.x, topHandle.y, 0.0f);
// bottomHandle: referring to the bottom most point of the handle or the bottom line of selection.
Vector3 bottomHandle;
bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
- bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
+ bottomHandle.y += GetSelectionHandleSize().y + mPopupOffsetFromText.w;
mPopUpPanel.SetAlternativeOffset(Vector2( mBoundingRectangleWorldCoordinates.x, bottomHandle.y - topHandle.y));
+
+ float xPosition = ( fabsf( topHandle.x - bottomHandle.x ) )*0.5f + std::min( topHandle.x , bottomHandle.x );
+
+ position.x = xPosition;
}
else
{
// When no text is selected, show popup at world position of grab handle or cursor
position = GetActualPositionFromCharacterPosition( mCursorPosition );
const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition );
- position.y -= rowSize.height;
+ position.y -= ( mPopupOffsetFromText.y + rowSize.height );
// if can't be positioned above, then position below row.
Vector2 alternativePopUpPosition( mBoundingRectangleWorldCoordinates.x, position.y ); // default if no grab handle
if ( mGrabHandle )
{
// If grab handle enabled then position pop-up below the grab handle.
- alternativePopUpPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + BOTTOM_HANDLE_BOTTOM_OFFSET ;
+ alternativePopUpPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + mPopupOffsetFromText.w +50.0f;
}
mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
}
Vector3 textViewSize = mDisplayedTextView.GetCurrentSize();
textViewSize.z = 0.0f;
// World position = world position of local position i.e. top-left corner of TextView
- Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position;
+ Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - ( textViewSize * 0.5f ) + position;
SetPopupPosition( worldPosition );
}
}
+void TextInput::SetOffsetFromText( const Vector4& offset )
+{
+ mPopupOffsetFromText = offset;
+}
+
+const Vector4& TextInput::GetOffsetFromText() const
+{
+ return mPopupOffsetFromText;
+}
+
void TextInput::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
{
Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( Dali::BaseHandle( object ) );
textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsClipboard, value.Get<unsigned int>() );
break;
}
+ case Toolkit::TextInput::POP_UP_OFFSET_FROM_TEXT_PROPERTY:
+ {
+ textInputImpl.SetOffsetFromText( value.Get< Vector4 >() );
+ break;
+ }
}
}
}
value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsClipboard );
break;
}
+ case Toolkit::TextInput::POP_UP_OFFSET_FROM_TEXT_PROPERTY:
+ {
+ value = textInputImpl.GetOffsetFromText();
+ break;
+ }
}
}
return value;
*/
void GetTextLayoutInfo();
+ /**
+ * Set the offset for positioning Popup from the TextInput
+ * @param[in] offset in the order, left, top, right, bottom
+ */
+ void SetOffsetFromText( const Vector4& offset );
+
+ /**
+ * Get the offset of the Popup from the TextInput
+ * @return Vector4 with the offset in the order, left, top, right, bottom
+ */
+ const Vector4& GetOffsetFromText() const;
+
// Properties
/**
Vector4 mSelectionHandleFlipMargin;
Vector4 mBoundingRectangleWorldCoordinates;
- Clipboard mClipboard; ///< Handle to clipboard
+ Clipboard mClipboard; ///< Handle to clipboard
// Styling
- Vector4 mMaterialColor; // Color of the highlight
+ Vector4 mMaterialColor; // Color of the highlight
+ Vector4 mPopupOffsetFromText; // Offset of Popup from the TextInput.
bool mOverrideAutomaticAlignment:1; ///< Whether to override the alignment automatically set by the text content (e.g. european LTR or arabic RTL)
bool mCursorRTLEnabled:1; ///< Enable state of Alternate RTL Cursor (need to keep track of this as it's not always enabled)
*/
// Popup: Tails
-const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "00_popup_bubble_tail_bottom.png" );
+const char* DEFAULT_POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "popup_bubble_tail_bottom.png" );
+const char* DEFAULT_POPUP_TAIL_BOTTOM_OUTLINE( DALI_IMAGE_DIR "popup_bubble_tail_bottom_line.png" );
// Popup: Vertical Constraint
// TODO: Remove - this should come from application - it is not possible to get the
const float SHOW_POPUP_ANIMATION_DURATION(0.2f); ///< Duration of popup show animation in seconds.
const Vector2 DEFAULT_ICON_SIZE( 45.0f, 45.0f ); ///< Default icon size for image in options
-const float TEXT_POSITION_OFFSET( -19.0f ); ///< Default offset for text label
+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" );
Rect<float> mBoundingRect; ///< Bounding Rect Popup must stay within
};
+/**
+ * Confine actor to the x axis boundaries of reference actor (e.g. Parent)
+ */
+struct ParentXAxisConstraint
+{
+ /**
+ * Confinement constraint constructor.
+ */
+ ParentXAxisConstraint( float handlesMidPoint = 0.0f )
+ : mHandlesMidPoint( handlesMidPoint )
+ {
+ }
+
+ float operator()( const float constXPosition,
+ const PropertyInput& localWidthProperty,
+ const PropertyInput& anchorPointXProperty )
+ {
+ const float size = localWidthProperty.GetFloat();
+ const float anchor = anchorPointXProperty.GetFloat();
+
+ float newPosition = Clamp( mHandlesMidPoint, constXPosition - size * anchor , constXPosition + size * anchor);
+
+ return newPosition;
+ }
+
+ float mHandlesMidPoint;
+};
+
+
} // unnamed namespace
namespace Dali
TextInputPopup::TextInputPopup()
: mState(StateHidden),
mRootActor(Layer::New()),
+ mPopupTailXPosition( 0.0f ),
mContentSize( Vector3::ZERO ),
mCutPasteButtonsColor( DEFAULT_POPUP_BACKGROUND ),
mCutPasteButtonsPressedColor( DEFAULT_POPUP_BUTTON_PRESSED ),
mRootActor.ApplyConstraint(constraint);
}
+void TextInputPopup::ApplyTailConstraint()
+{
+ mTail.RemoveConstraints();
+ Constraint constraint = Constraint::New<float>( Actor::POSITION_X,
+ LocalSource( Actor::SIZE_WIDTH ),
+ LocalSource( Actor::ANCHOR_POINT_X ),
+ ParentXAxisConstraint());
+}
+
void TextInputPopup::CreateLayer( const Vector2& size )
{
mLayer = Layer::New();
{
if ( mBackground )
{
+ UnparentAndReset( mTail );
UnparentAndReset( mStencil );
UnparentAndReset( mBackground );
UnparentAndReset( mScrollView );
// Add Tail too.
Image tailImage = Image::New( DEFAULT_POPUP_TAIL_BOTTOM );
+ Image tailImageOutline = Image::New( DEFAULT_POPUP_TAIL_BOTTOM_OUTLINE );
+
+ mTailOutline = ImageActor::New ( tailImageOutline );
+ mTailOutline.SetParentOrigin( ParentOrigin::CENTER );
+ mTailOutline.SetAnchorPoint( AnchorPoint::CENTER );
+ mTailOutline.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
mTail = ImageActor::New( tailImage );
mTail.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
mTail.SetAnchorPoint( AnchorPoint::TOP_CENTER );
- mBackground.Add( mTail );
// TODO: Make tail visible, and positioned in relation to original intended position of popup (i.e. before constrained effects)
- mTail.SetVisible(false);
+ mTail.SetVisible(true);
+ mTail.SetColor( mCutPasteButtonsColor );
+ mTailOutline.SetColor( mBorderColor );
+ mTail.Add( mTailOutline);
}
}
{
i->SetSize( DIVIDER_WIDTH, dividerHeight );
}
-
- mTail.SetPosition(Vector3(0.0f, -20.0f, 0.0f));
-
button.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
}
void TextInputPopup::Hide(bool animate)
{
- if(mBackground)
+ if( mRootActor )
{
if(mAnimation)
{
if(animate)
{
mAnimation = Animation::New( HIDE_POPUP_ANIMATION_DURATION );
- mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut );
- mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 0.0f, AlphaFunctions::EaseOut );
+ mAnimation.AnimateTo( Property(mRootActor, Actor::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut );
+ mAnimation.AnimateTo( Property(mRootActor, Actor::COLOR_ALPHA), 0.0f, AlphaFunctions::EaseOut );
mAnimation.Play();
mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnHideFinished );
}
else
{
- mBackground.SetProperty(Actor::SCALE, Vector3::ZERO);
- mBackground.SetProperty(Actor::COLOR_ALPHA, 0.0f);
+ mRootActor.SetProperty(Actor::SCALE, Vector3::ZERO);
+ mRootActor.SetProperty(Actor::COLOR_ALPHA, 0.0f);
mState = StateHidden;
}
}
void TextInputPopup::Show(bool animate)
{
- if(mBackground)
+ if( mRootActor )
{
- mBackground.SetSensitive( true );
+ mRootActor.SetSensitive( true );
+
+ mTail.SetPosition(Vector3( mPopupTailXPosition, 0.0f, 0.0f));
if(mAnimation)
{
if(animate)
{
mAnimation = Animation::New( SHOW_POPUP_ANIMATION_DURATION );
- mAnimation.AnimateTo( Property(mBackground, Actor::SCALE), Vector3::ONE, AlphaFunctions::EaseOut );
- mAnimation.AnimateTo( Property(mBackground, Actor::COLOR_ALPHA), 1.0f, AlphaFunctions::EaseOut );
+ mAnimation.AnimateTo( Property(mRootActor, Actor::SCALE), Vector3::ONE, AlphaFunctions::EaseOut );
+ mAnimation.AnimateTo( Property(mRootActor, Actor::COLOR_ALPHA), 1.0f, AlphaFunctions::EaseOut );
mAnimation.Play();
mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnShowFinished );
}
else
{
- mBackground.SetProperty(Actor::SCALE, Vector3::ONE);
- mBackground.SetProperty(Actor::COLOR_ALPHA, 1.0f);
+ mRootActor.SetProperty(Actor::SCALE, Vector3::ONE);
+ mRootActor.SetProperty(Actor::COLOR_ALPHA, 1.0f);
mState = StateShown;
}
}
mLayer.Add( mStencil );
mLayer.Add( mScrollView );
mScrollView.Add( mBackground );
+ mRootActor.Add( mTail );
Self().Add(mLayer);
}
mBoundingRect = boundingRectangle;
}
+void TextInputPopup::SetTailPosition( const Vector3& position )
+{
+ mPopupTailXPosition = position.x;
+ ApplyTailConstraint();
+}
+
bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
{
mPressedSignal.Emit( button );
} // namespace Toolkit
} // namespace Dali
+
*/
void SetPopupBoundary( const Rect<float>& boundingRectangle );
+ /**
+ * Sets the positon of the PopUp tail relative to TextInput
+ * @param position Position to set
+ */
+ void SetTailPosition( const Vector3& position );
+
private:
/**
void ApplyConfinementConstraint();
/**
+ * Applies constraint to keep the Tail attached to Popup
+ */
+ void ApplyTailConstraint();
+
+ /**
* Create a layer to hold the stencil
* @param[in] size Size to of layer
*/
Property::Index mAlternativeOffsetProperty; ///< Property [Vector3] how much to offset the popup if it goes out of the screen
ImageActor mBackground; ///< The background popup panel
ImageActor mTail; ///< The tail for the popup
+ ImageActor mTailOutline; ///< The border/outline around the tail
+
+ float mPopupTailXPosition; ///< X position of PopUp tail.
+
Vector3 mContentSize; ///< Size of Content (i.e. Buttons)
ActorContainer mButtonContainer; ///< List of buttons added to popup.
ActorContainer mDividerContainer; ///< List of dividers added to popup.
static const Property::Index SELECT_BUTTON_POSITION_PRIORITY_PROPERTY; // Property, name "select-button-position-priority", type unsigned int
static const Property::Index SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY; // Property, name "select-all-button-position-priority", type unsigned int
static const Property::Index CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY; // Property, name "clipboard-button-position-priority", type unsigned int
+
+ static const Property::Index POP_UP_OFFSET_FROM_TEXT_PROPERTY; // Property, name "popup-offset-from-text", type VECTOR4
+
/** @} */
/// @name Signals