#include <dali/public-api/common/stage.h>
#include <dali/public-api/events/tap-gesture.h>
#include <dali/public-api/events/tap-gesture-detector.h>
+#include <dali/public-api/events/touch-event.h>
#include <dali/public-api/events/pan-gesture.h>
#include <dali/public-api/events/pan-gesture-detector.h>
#include <dali/devel-api/geometry/mesh.h>
const char* DEFAULT_GRAB_HANDLE_IMAGE_RELEASED( DALI_IMAGE_DIR "insertpoint-icon.png" );
const char* DEFAULT_GRAB_HANDLE_IMAGE_PRESSED( DALI_IMAGE_DIR "insertpoint-icon-pressed.png" );
-const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
-const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
+const char* DEFAULT_SELECTION_HANDLE_ONE_RELEASED( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
+const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" );
+const char* DEFAULT_SELECTION_HANDLE_TWO_RELEASED( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
+const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
-const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
-const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
+const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
-const Dali::Vector4 LIGHT_BLUE( 0.07f, 0.41f, 0.59f, 1.0f ); // The text highlight color.
+const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+
+const Dali::Vector4 LIGHT_BLUE( (0xb2 / 255.0f), (0xeb / 255.0f), (0xf2 / 255.0f), 0.5f ); // The text highlight color.
const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
const float TO_MILLISECONDS = 1000.f;
grabDisplacementY( 0.f ),
active( false ),
visible( false ),
+ pressed( false ),
flipped( false )
{
}
float grabDisplacementY;
bool active : 1;
bool visible : 1;
+ bool pressed : 1;
bool flipped : 1;
};
- Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
- : mTextControlParent( parent ),
- mObserver( observer ),
+ struct PopupImpl
+ {
+ PopupImpl()
+ : position(),
+ offset( DEFAULT_POPUP_OFFSET )
+ {
+ }
+
+ TextSelectionPopup actor;
+ Vector3 position;
+ int offset;
+ };
+
+ Impl( ControllerInterface& controller,
+ TextSelectionPopupCallbackInterface& callbackInterface )
+ : mController( controller ),
+ mEnabledPopupButtons( TextSelectionPopup::NONE ),
+ mTextSelectionPopupCallbackInterface( callbackInterface ),
mBoundingBox( Rect<int>() ),
mHighlightColor( LIGHT_BLUE ),
+ mHighlightPosition( Vector2::ZERO ),
mActiveCursor( ACTIVE_CURSOR_NONE ),
mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
mCursorBlinkDuration( 0.0f ),
mActiveCopyPastePopup( false ),
mCursorBlinkStatus( true ),
mPrimaryCursorVisible( false ),
- mSecondaryCursorVisible( false )
+ mSecondaryCursorVisible( false ),
+ mSwapSelectionHandles( false ),
+ mNotifyEndOfScroll( false )
{
}
if( mPrimaryCursorVisible )
{
Vector2 position = cursor.position;
- if( GRAB_HANDLE == mHandleScrolling )
- {
- if( mScrollDirection == SCROLL_RIGHT )
- {
- position.x = 0.f;
- }
- else
- {
- position.x = size.width;
- }
- }
mPrimaryCursor.SetPosition( position.x,
position.y );
{
Vector2 position = grabHandle.position;
- if( GRAB_HANDLE == mHandleScrolling )
- {
- if( mScrollDirection == SCROLL_RIGHT )
- {
- position.x = 0.f;
- }
- else
- {
- position.x = size.width;
- }
- }
-
const bool isVisible = ( position.x <= size.width ) && ( position.x >= 0.f );
if( isVisible )
HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
if( primary.active || secondary.active )
{
- SetupTouchEvents();
+ Vector2 primaryPosition = primary.position;
+ Vector2 secondaryPosition = secondary.position;
- CreateSelectionHandles();
+ const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
+ const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
- primary.actor.SetPosition( primary.position.x,
- primary.position.y + primary.lineHeight );
+ if( isPrimaryVisible || isSecondaryVisible )
+ {
+ SetupTouchEvents();
- secondary.actor.SetPosition( secondary.position.x,
- secondary.position.y + secondary.lineHeight );
+ CreateSelectionHandles();
+
+ if( isPrimaryVisible )
+ {
+ primary.actor.SetPosition( primaryPosition.x,
+ primaryPosition.y + primary.lineHeight );
+ }
+
+ if( isSecondaryVisible )
+ {
+ secondary.actor.SetPosition( secondaryPosition.x,
+ secondaryPosition.y + secondary.lineHeight );
+ }
+ }
+ primary.actor.SetVisible( isPrimaryVisible );
+ secondary.actor.SetVisible( isSecondaryVisible );
CreateHighlight();
UpdateHighlight();
if ( mActiveCopyPastePopup )
{
- if ( !mCopyPastePopup )
+ // todo Swap UnparentAndReset for DeterminePositionPopup() if mCopyPastePopup.actor valid Once the issue with the labels disappearing is fixed.
+ UnparentAndReset( mCopyPastePopup.actor );
+ if ( !mCopyPastePopup.actor )
{
- mCopyPastePopup = TextSelectionPopup::New();
+ mCopyPastePopup.actor = TextSelectionPopup::New( mEnabledPopupButtons, &mTextSelectionPopupCallbackInterface );
#ifdef DECORATOR_DEBUG
- mCopyPastePopup.SetName("mCopyPastePopup");
+ mCopyPastePopup.actor.SetName("mCopyPastePopup");
#endif
- mCopyPastePopup.SetAnchorPoint( AnchorPoint::CENTER );
- mCopyPastePopup.OnRelayoutSignal().Connect( this, &Decorator::Impl::PopUpRelayoutComplete ); // Position popup after size negotiation
- mActiveLayer.Add ( mCopyPastePopup );
+ mCopyPastePopup.actor.SetAnchorPoint( AnchorPoint::CENTER );
+ mCopyPastePopup.actor.OnRelayoutSignal().Connect( this, &Decorator::Impl::PopupRelayoutComplete ); // Position popup after size negotiation
+ mActiveLayer.Add ( mCopyPastePopup.actor );
}
}
else
{
- if ( mCopyPastePopup )
+ if ( mCopyPastePopup.actor )
{
- UnparentAndReset( mCopyPastePopup );
+ UnparentAndReset( mCopyPastePopup.actor );
}
}
}
mHandle[ GRAB_HANDLE ].position += scrollOffset;
mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset;
mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset;
-
- // TODO Highlight box??
+ mHighlightPosition += scrollOffset;
}
- void PopUpRelayoutComplete( Actor actor )
+ void DeterminePositionPopup()
{
- // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+ if ( !mActiveCopyPastePopup )
+ {
+ return;
+ }
- mCopyPastePopup.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopUpRelayoutComplete );
+ if ( mHandle[LEFT_SELECTION_HANDLE].active || mHandle[RIGHT_SELECTION_HANDLE].active )
+ {
+ float minHandleXPosition = std::min ( mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
+ float maxHandleXPosition = std::max ( mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
- Vector3 popupPosition( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f); //todo 100 to be an offset Property
+ float minHandleYPosition = std::min ( mHandle[LEFT_SELECTION_HANDLE].position.y, mHandle[RIGHT_SELECTION_HANDLE].position.y );
- Vector3 popupSize = Vector3( mCopyPastePopup.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+ mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) *0.5f );
+ mCopyPastePopup.position.y = minHandleYPosition + mCopyPastePopup.offset;
+ }
+ else
+ {
+ mCopyPastePopup.position = Vector3( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f ); //todo 100 to be an offset Property
+ }
- GetConstrainedPopupPosition( popupPosition, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
+ Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
- SetUpPopUpPositionNotifications();
+ GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
- mCopyPastePopup.SetPosition( popupPosition ); //todo grabhandle(cursor) or selection handle positions to be used
+ SetUpPopupPositionNotifications();
+
+ mCopyPastePopup.actor.SetPosition( mCopyPastePopup.position );
+ }
+
+ void PopupRelayoutComplete( Actor actor )
+ {
+ // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+ mCopyPastePopup.actor.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopupRelayoutComplete );
+
+ DeterminePositionPopup();
}
void CreateCursor( ImageActor& cursor, const Vector4& color )
{
if( !mActiveLayer )
{
- Actor parent = mTextControlParent.Self();
-
mActiveLayer = Layer::New();
#ifdef DECORATOR_DEBUG
mActiveLayer.SetName ( "ActiveLayerActor" );
mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
- parent.Add( mActiveLayer );
+ // Add the active layer telling the controller it doesn't need clipping.
+ mController.AddDecoration( mActiveLayer, false );
}
mActiveLayer.RaiseToTop();
grabHandle.grabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
grabHandle.actor.Add( grabHandle.grabArea );
+ grabHandle.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
mTapDetector.Attach( grabHandle.grabArea );
mPanGestureDetector.Attach( grabHandle.grabArea );
{
if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
{
- mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
+ mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_RELEASED );
+ }
+ if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] )
+ {
+ mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_PRESSED );
}
primary.actor = ImageActor::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
primary.grabArea.SetName("SelectionHandleOneGrabArea");
#endif
primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+ primary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+ primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
- primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
mTapDetector.Attach( primary.grabArea );
mPanGestureDetector.Attach( primary.grabArea );
{
if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
{
- mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
+ mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO_RELEASED );
+ }
+ if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] )
+ {
+ mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO_PRESSED );
}
secondary.actor = ImageActor::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
#endif
secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+ secondary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+ secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
- secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
mTapDetector.Attach( secondary.grabArea );
mPanGestureDetector.Attach( secondary.grabArea );
mHighlightMeshActor.SetName( "HighlightMeshActor" );
#endif
mHighlightMeshActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
- mHighlightMeshActor.SetPosition( 0.0f, 0.0f, DISPLAYED_HIGHLIGHT_Z_OFFSET );
- Actor parent = mTextControlParent.Self();
- parent.Add( mHighlightMeshActor );
+ // Add the highlight box telling the controller it needs clipping.
+ mController.AddDecoration( mHighlightMeshActor, true );
}
+
+ mHighlightMeshActor.SetPosition( mHighlightPosition.x, mHighlightPosition.y, DISPLAYED_HIGHLIGHT_Z_OFFSET );
}
void UpdateHighlight()
if( Gesture::Started == gesture.state )
{
handle.grabDisplacementX = handle.grabDisplacementY = 0;
- if( mHandleImages[type][HANDLE_IMAGE_PRESSED] )
- {
- handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_PRESSED] );
- }
}
handle.grabDisplacementX += gesture.displacement.x;
if( Gesture::Started == gesture.state ||
Gesture::Continuing == gesture.state )
{
+ Vector2 targetSize;
+ mController.GetTargetSize( targetSize );
+
if( x < mScrollThreshold )
{
mScrollDirection = SCROLL_RIGHT;
mHandleScrolling = type;
StartScrollTimer();
}
- else if( x > mTextControlParent.Self().GetTargetSize().width - mScrollThreshold )
+ else if( x > targetSize.width - mScrollThreshold )
{
mScrollDirection = SCROLL_LEFT;
mHandleScrolling = type;
{
mHandleScrolling = HANDLE_TYPE_COUNT;
StopScrollTimer();
- mObserver.HandleEvent( type, HANDLE_PRESSED, x, y );
+ mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
}
}
else if( Gesture::Finished == gesture.state ||
Gesture::Cancelled == gesture.state )
{
- if( mScrollTimer && mScrollTimer.IsRunning() )
+ if( mScrollTimer &&
+ ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
{
+ mNotifyEndOfScroll = false;
mHandleScrolling = HANDLE_TYPE_COUNT;
StopScrollTimer();
- mObserver.HandleEvent( type, HANDLE_STOP_SCROLLING, x, y );
+ mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
+ }
+ else
+ {
+ mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
+ }
+
+ if( GRAB_HANDLE == type )
+ {
+ handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
}
else
{
- mObserver.HandleEvent( type, HANDLE_RELEASED, x, y );
+ HandleType selectionHandleType = type;
+
+ if( mSwapSelectionHandles != handle.flipped )
+ {
+ selectionHandleType = ( LEFT_SELECTION_HANDLE == type ) ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE;
+ }
+
+ handle.actor.SetImage( mHandleImages[selectionHandleType][HANDLE_IMAGE_RELEASED] );
}
- handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+ handle.pressed = false;
}
}
}
}
- bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
+ bool OnGrabHandleTouched( Actor actor, const TouchEvent& event )
+ {
+ // Switch between pressed/release grab-handle images
+ if( event.GetPointCount() > 0 &&
+ mHandle[GRAB_HANDLE].actor )
+ {
+ const TouchPoint& point = event.GetPoint(0);
+
+ if( TouchPoint::Down == point.state )
+ {
+ mHandle[GRAB_HANDLE].pressed = true;
+ Image imagePressed = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED];
+ if( imagePressed )
+ {
+ mHandle[GRAB_HANDLE].actor.SetImage( imagePressed );
+ }
+ }
+ else if( TouchPoint::Up == point.state )
+ {
+ mHandle[GRAB_HANDLE].pressed = false;
+ Image imageReleased = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED];
+ if( imageReleased )
+ {
+ mHandle[GRAB_HANDLE].actor.SetImage( imageReleased );
+ }
+ }
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
+ }
+
+ bool OnHandleOneTouched( Actor actor, const TouchEvent& event )
{
- // TODO
- return false;
+ // Switch between pressed/release selection handle images
+ if( event.GetPointCount() > 0 &&
+ mHandle[LEFT_SELECTION_HANDLE].actor )
+ {
+ const TouchPoint& point = event.GetPoint(0);
+
+ const bool flip = mSwapSelectionHandles != mHandle[LEFT_SELECTION_HANDLE].flipped;
+ if( TouchPoint::Down == point.state )
+ {
+ mHandle[LEFT_SELECTION_HANDLE].pressed = true;
+ Image imagePressed = mHandleImages[flip ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED];
+ if( imagePressed )
+ {
+ mHandle[LEFT_SELECTION_HANDLE].actor.SetImage( imagePressed );
+ }
+ }
+ else if( TouchPoint::Up == point.state )
+ {
+ mHandle[LEFT_SELECTION_HANDLE].pressed = false;
+ Image imageReleased = mHandleImages[flip ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED];
+ if( imageReleased )
+ {
+ mHandle[LEFT_SELECTION_HANDLE].actor.SetImage( imageReleased );
+ }
+ }
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
}
- bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
+ bool OnHandleTwoTouched( Actor actor, const TouchEvent& event )
{
- // TODO
- return false;
+ // Switch between pressed/release selection handle images
+ if( event.GetPointCount() > 0 &&
+ mHandle[RIGHT_SELECTION_HANDLE].actor )
+ {
+ const TouchPoint& point = event.GetPoint(0);
+
+ const bool flip = mSwapSelectionHandles != mHandle[RIGHT_SELECTION_HANDLE].flipped;
+ if( TouchPoint::Down == point.state )
+ {
+ Image imagePressed = mHandleImages[flip ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED];
+ mHandle[RIGHT_SELECTION_HANDLE].pressed = true;
+ if( imagePressed )
+ {
+ mHandle[RIGHT_SELECTION_HANDLE].actor.SetImage( imagePressed );
+ }
+ }
+ else if( TouchPoint::Up == point.state )
+ {
+ Image imageReleased = mHandleImages[flip ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED];
+ mHandle[RIGHT_SELECTION_HANDLE].pressed = false;
+ if( imageReleased )
+ {
+ mHandle[RIGHT_SELECTION_HANDLE].actor.SetImage( imageReleased );
+ }
+ }
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
}
// Popup
// if can't be positioned above, then position below row.
alternativeYPosition = AlternatePopUpPositionRelativeToCursor();
- mCopyPastePopup.SetY( alternativeYPosition );
+ mCopyPastePopup.actor.SetY( alternativeYPosition );
}
- void SetUpPopUpPositionNotifications( )
+ void SetUpPopupPositionNotifications( )
{
// Note Property notifications ignore any set anchor point so conditions must allow for this. Default is Top Left.
Vector4 worldCoordinatesBoundingBox;
LocalToWorldCoordinatesBoundingBox( mBoundingBox, worldCoordinatesBoundingBox );
- float popupHeight = mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT);
+ float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT);
- PropertyNotification verticalExceedNotification = mCopyPastePopup.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
- OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight/2,
- worldCoordinatesBoundingBox.w - popupHeight/2 ) );
+ PropertyNotification verticalExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+ OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight * 0.5f,
+ worldCoordinatesBoundingBox.w - popupHeight * 0.5f ) );
verticalExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesVerticalBoundary );
}
}
requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
+
+ // Prevent pixel mis-alignment by rounding down.
+ requiredPopupPosition.x = static_cast<int>( requiredPopupPosition.x );
+ requiredPopupPosition.y = static_cast<int>( requiredPopupPosition.y );
+
+ }
+
+ void FlipSelectionHandleImages()
+ {
+ SetupTouchEvents();
+
+ CreateSelectionHandles();
+
+ HandleImpl& leftHandle = mHandle[LEFT_SELECTION_HANDLE];
+ HandleImpl& rightHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+ const HandleImageType leftImageType = leftHandle.pressed ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED;
+ const HandleImageType rightImageType = rightHandle.pressed ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED;
+ const bool leftFlipped = mSwapSelectionHandles != leftHandle.flipped;
+ const bool rightFlipped = mSwapSelectionHandles != rightHandle.flipped;
+
+ leftHandle.actor.SetImage( leftFlipped ? mHandleImages[RIGHT_SELECTION_HANDLE][leftImageType] : mHandleImages[LEFT_SELECTION_HANDLE][leftImageType] );
+
+ leftHandle.actor.SetAnchorPoint( leftFlipped ? AnchorPoint::TOP_LEFT : AnchorPoint::TOP_RIGHT );
+
+ rightHandle.actor.SetImage( rightFlipped ? mHandleImages[LEFT_SELECTION_HANDLE][rightImageType] : mHandleImages[RIGHT_SELECTION_HANDLE][rightImageType] );
+
+ rightHandle.actor.SetAnchorPoint( rightFlipped ? AnchorPoint::TOP_RIGHT : AnchorPoint::TOP_LEFT );
}
void SetScrollThreshold( float threshold )
return mScrollSpeed;
}
+ void NotifyEndOfScroll()
+ {
+ StopScrollTimer();
+
+ if( mScrollTimer )
+ {
+ mNotifyEndOfScroll = true;
+ }
+ }
+
/**
* Creates and starts a timer to scroll the text when handles are close to the edges of the text.
*
{
if( HANDLE_TYPE_COUNT != mHandleScrolling )
{
- mObserver.HandleEvent( mHandleScrolling,
- HANDLE_SCROLLING,
- mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
- 0.f );
+ mController.DecorationEvent( mHandleScrolling,
+ HANDLE_SCROLLING,
+ mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
+ 0.f );
}
return true;
}
- Internal::Control& mTextControlParent;
- Observer& mObserver;
+ ControllerInterface& mController;
TapGestureDetector mTapDetector;
PanGestureDetector mPanGestureDetector;
ImageActor mPrimaryCursor;
ImageActor mSecondaryCursor;
MeshActor mHighlightMeshActor; ///< Mesh Actor to display highlight
- TextSelectionPopup mCopyPastePopup;
+
+ PopupImpl mCopyPastePopup;
+ TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
+ TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
Image mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
Image mCursorImage;
Rect<int> mBoundingBox;
Vector4 mHighlightColor; ///< Color of the highlight
+ Vector2 mHighlightPosition; ///< The position of the highlight actor.
unsigned int mActiveCursor;
unsigned int mCursorBlinkInterval;
float mScrollThreshold; ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
float mScrollSpeed; ///< The scroll speed in pixels per second.
float mScrollDistance; ///< Distance the text scrolls during a scroll interval.
- unsigned int mScrollInterval; ///< Time in milliseconds of a scroll interval.
bool mActiveCopyPastePopup : 1;
bool mCursorBlinkStatus : 1; ///< Flag to switch between blink on and blink off.
bool mPrimaryCursorVisible : 1; ///< Whether the primary cursor is visible.
bool mSecondaryCursorVisible : 1; ///< Whether the secondary cursor is visible.
+ bool mSwapSelectionHandles : 1; ///< Whether to swap the selection handle images.
+ bool mNotifyEndOfScroll : 1; ///< Whether to notify the end of the scroll.
};
-DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
+DecoratorPtr Decorator::New( ControllerInterface& controller,
+ TextSelectionPopupCallbackInterface& callbackInterface )
{
- return DecoratorPtr( new Decorator(parent, observer) );
+ return DecoratorPtr( new Decorator( controller,
+ callbackInterface ) );
}
void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
height = handle.lineHeight;
}
+const Vector2& Decorator::GetPosition( HandleType handleType ) const
+{
+ return mImpl->mHandle[handleType].position;
+}
+
+void Decorator::SwapSelectionHandlesEnabled( bool enable )
+{
+ mImpl->mSwapSelectionHandles = enable;
+
+ mImpl->FlipSelectionHandleImages();
+}
+
void Decorator::AddHighlight( float x1, float y1, float x2, float y2 )
{
mImpl->mHighlightQuadList.push_back( QuadCoordinates(x1, y1, x2, y2) );
void Decorator::ClearHighlights()
{
mImpl->mHighlightQuadList.clear();
+ mImpl->mHighlightPosition = Vector2::ZERO;
}
void Decorator::SetHighlightColor( const Vector4& color )
return mImpl->mActiveCopyPastePopup ;
}
+void Decorator::SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask )
+{
+ mImpl->mEnabledPopupButtons = enabledButtonsBitMask;
+}
+
+TextSelectionPopup::Buttons& Decorator::GetEnabledPopupButtons()
+{
+ return mImpl->mEnabledPopupButtons;
+}
+
/** Scroll **/
void Decorator::SetScrollThreshold( float threshold )
return mImpl->GetScrollSpeed();
}
+void Decorator::NotifyEndOfScroll()
+{
+ mImpl->NotifyEndOfScroll();
+}
+
Decorator::~Decorator()
{
delete mImpl;
}
-Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
+Decorator::Decorator( ControllerInterface& controller,
+ TextSelectionPopupCallbackInterface& callbackInterface )
: mImpl( NULL )
{
- mImpl = new Decorator::Impl( parent, observer );
+ mImpl = new Decorator::Impl( controller, callbackInterface );
}
} // namespace Text