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 Dali::Vector4 LIGHT_BLUE( 0.07f, 0.41f, 0.59f, 1.0f ); // The text highlight color.
+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 ),
+ Impl( ControllerInterface& controller )
+ : mController( controller ),
+ mEnabledPopupButtons( TextSelectionPopup::NONE ),
mBoundingBox( Rect<int>() ),
mHighlightColor( LIGHT_BLUE ),
mActiveCursor( ACTIVE_CURSOR_NONE ),
mActiveCopyPastePopup( false ),
mCursorBlinkStatus( true ),
mPrimaryCursorVisible( false ),
- mSecondaryCursorVisible( false )
+ mSecondaryCursorVisible( false ),
+ mSwapSelectionHandles( false )
{
}
HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
if( primary.active || secondary.active )
{
- SetupTouchEvents();
+ Vector2 primaryPosition = primary.position;
+ Vector2 secondaryPosition = secondary.position;
- CreateSelectionHandles();
+ if( LEFT_SELECTION_HANDLE == mHandleScrolling )
+ {
+ if( mScrollDirection == SCROLL_RIGHT )
+ {
+ primaryPosition.x = 0.f;
+ }
+ else
+ {
+ primaryPosition.x = size.width;
+ }
+ }
+ else if( RIGHT_SELECTION_HANDLE == mHandleScrolling )
+ {
+ if( mScrollDirection == SCROLL_RIGHT )
+ {
+ secondaryPosition.x = 0.f;
+ }
+ else
+ {
+ secondaryPosition.x = size.width;
+ }
+ }
+
+ const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
+ const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
+
+ if( isPrimaryVisible || isSecondaryVisible )
+ {
+ SetupTouchEvents();
+
+ CreateSelectionHandles();
- primary.actor.SetPosition( primary.position.x,
- primary.position.y + primary.lineHeight );
+ if( isPrimaryVisible )
+ {
+ primary.actor.SetPosition( primaryPosition.x,
+ primaryPosition.y + primary.lineHeight );
+ }
- secondary.actor.SetPosition( secondary.position.x,
- secondary.position.y + secondary.lineHeight );
+ if( isSecondaryVisible )
+ {
+ secondary.actor.SetPosition( secondaryPosition.x,
+ secondaryPosition.y + secondary.lineHeight );
+ }
+ }
+ primary.actor.SetVisible( isPrimaryVisible );
+ secondary.actor.SetVisible( isSecondaryVisible );
CreateHighlight();
UpdateHighlight();
{
if ( !mCopyPastePopup )
{
- mCopyPastePopup = TextSelectionPopup::New();
+ mCopyPastePopup = TextSelectionPopup::New( mEnabledPopupButtons );
#ifdef DECORATOR_DEBUG
mCopyPastePopup.SetName("mCopyPastePopup");
#endif
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 )
{
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();
{
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] );
{
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] );
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 ||
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 ||
{
mHandleScrolling = HANDLE_TYPE_COUNT;
StopScrollTimer();
- mObserver.HandleEvent( type, HANDLE_STOP_SCROLLING, x, y );
+ mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
}
else
{
- mObserver.HandleEvent( type, HANDLE_RELEASED, x, y );
+ mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
+ }
+
+ if( GRAB_HANDLE == type )
+ {
+ handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
}
- handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+ else
+ {
+ 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.pressed = false;
}
}
{
const TouchPoint& point = event.GetPoint(0);
- if( TouchPoint::Down == point.state &&
- mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] )
+ if( TouchPoint::Down == point.state )
{
- mHandle[GRAB_HANDLE].actor.SetImage( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] );
+ 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 &&
- mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
+ else if( TouchPoint::Up == point.state )
{
- mHandle[GRAB_HANDLE].actor.SetImage( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
+ mHandle[GRAB_HANDLE].pressed = false;
+ Image imageReleased = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED];
+ if( imageReleased )
+ {
+ mHandle[GRAB_HANDLE].actor.SetImage( imageReleased );
+ }
}
}
return true;
}
- bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
+ bool OnHandleOneTouched( Actor actor, const TouchEvent& event )
{
- // TODO
+ // 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
+ // 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;
}
requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
}
+ 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 )
{
mScrollThreshold = threshold;
{
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 mSecondaryCursor;
MeshActor mHighlightMeshActor; ///< Mesh Actor to display highlight
TextSelectionPopup mCopyPastePopup;
+ TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
Image mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
Image mCursorImage;
CursorImpl mCursor[CURSOR_COUNT];
HandleImpl mHandle[HANDLE_TYPE_COUNT];
QuadContainer mHighlightQuadList; ///< Sub-selections that combine to create the complete selection highlight
+ Vector2 mHighlightPosition; ///< The position of the highlight actor.
Rect<int> mBoundingBox;
Vector4 mHighlightColor; ///< Color of the highlight
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.
};
-DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
+DecoratorPtr Decorator::New( ControllerInterface& controller )
{
- return DecoratorPtr( new Decorator(parent, observer) );
+ return DecoratorPtr( new Decorator(controller) );
}
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 )
delete mImpl;
}
-Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
+Decorator::Decorator( ControllerInterface& controller )
: mImpl( NULL )
{
- mImpl = new Decorator::Impl( parent, observer );
+ mImpl = new Decorator::Impl( controller );
}
} // namespace Text