X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fdecorator%2Ftext-decorator.cpp;h=02de592f9fda06113e063a76f9c3553817ce0641;hb=refs%2Fchanges%2F74%2F42074%2F1;hp=32e3becd14020deb9c8b53dceee3550f510d3ba2;hpb=caa46059c4cd1c18f380b81487f83a395846e5df;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp index 32e3bec..02de592 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.cpp +++ b/dali-toolkit/internal/text/decorator/text-decorator.cpp @@ -24,16 +24,17 @@ #include #include #include -#include +#include #include #include #include #include #include +#include #include #include -#include -#include +#include +#include #include #include #include @@ -47,7 +48,7 @@ #include #include #include -#include +#include #ifdef DEBUG_ENABLED #define DECORATOR_DEBUG @@ -72,21 +73,32 @@ Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLog namespace { -const char* DEFAULT_GRAB_HANDLE_IMAGE( DALI_IMAGE_DIR "insertpoint-icon.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_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" ); -//const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" ); +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_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::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; -const float TO_SECONDS = 1.f / 1000.f; +const float TO_SECONDS = 1.f / TO_MILLISECONDS; const float DISPLAYED_HIGHLIGHT_Z_OFFSET( -0.05f ); +const unsigned int SCROLL_TICK_INTERVAL = 50u; + +const float SCROLL_THRESHOLD = 10.f; +const float SCROLL_SPEED = 300.f; +const float SCROLL_DISTANCE = SCROLL_SPEED * SCROLL_TICK_INTERVAL * TO_SECONDS; + /** * structure to hold coordinates of each quad, which will make up the mesh. */ @@ -151,10 +163,19 @@ namespace Text struct Decorator::Impl : public ConnectionTracker { + enum ScrollDirection + { + SCROLL_NONE, + SCROLL_RIGHT, + SCROLL_LEFT, + SCROLL_TOP, + SCROLL_BOTTOM + }; + struct CursorImpl { CursorImpl() - : color( Dali::Color::WHITE ), + : color( Dali::Color::BLACK ), position(), cursorHeight( 0.0f ), lineHeight( 0.0f ) @@ -167,11 +188,16 @@ struct Decorator::Impl : public ConnectionTracker float lineHeight; }; - struct SelectionHandleImpl + struct HandleImpl { - SelectionHandleImpl() + HandleImpl() : position(), lineHeight( 0.0f ), + grabDisplacementX( 0.f ), + grabDisplacementY( 0.f ), + active( false ), + visible( false ), + pressed( false ), flipped( false ) { } @@ -179,30 +205,49 @@ struct Decorator::Impl : public ConnectionTracker ImageActor actor; Actor grabArea; - Image pressedImage; - Image releasedImage; - Vector2 position; float lineHeight; ///< Not the handle height - bool flipped; + float grabDisplacementX; + 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() ), - mHighlightColor( 0.07f, 0.41f, 0.59f, 1.0f ), // light blue + mHighlightColor( LIGHT_BLUE ), mActiveCursor( ACTIVE_CURSOR_NONE ), mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ), mCursorBlinkDuration( 0.0f ), - mGrabDisplacementX( 0.0f ), - mGrabDisplacementY( 0.0f ), - mActiveGrabHandle( false ), - mActiveSelection( false ), + mHandleScrolling( HANDLE_TYPE_COUNT ), + mScrollDirection( SCROLL_NONE ), + mScrollThreshold( SCROLL_THRESHOLD ), + mScrollSpeed( SCROLL_SPEED ), + mScrollDistance( SCROLL_DISTANCE ), mActiveCopyPastePopup( false ), mCursorBlinkStatus( true ), mPrimaryCursorVisible( false ), - mSecondaryCursorVisible( false ) + mSecondaryCursorVisible( false ), + mSwapSelectionHandles( false ) { } @@ -219,31 +264,61 @@ struct Decorator::Impl : public ConnectionTracker CreateCursors(); if( mPrimaryCursor ) { - mPrimaryCursorVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f ); + const CursorImpl& cursor = mCursor[PRIMARY_CURSOR]; + mPrimaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f ); if( mPrimaryCursorVisible ) { - mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].position.x, - mCursor[PRIMARY_CURSOR].position.y ); - mPrimaryCursor.SetSize( Size( 1.0f, mCursor[PRIMARY_CURSOR].cursorHeight ) ); + 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 ); + mPrimaryCursor.SetSize( Size( 1.0f, cursor.cursorHeight ) ); } mPrimaryCursor.SetVisible( mPrimaryCursorVisible ); } if( mSecondaryCursor ) { - mSecondaryCursorVisible = ( mCursor[SECONDARY_CURSOR].position.x <= size.width ) && ( mCursor[SECONDARY_CURSOR].position.x >= 0.f ); + const CursorImpl& cursor = mCursor[SECONDARY_CURSOR]; + mSecondaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f ); if( mSecondaryCursorVisible ) { - mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].position.x, - mCursor[SECONDARY_CURSOR].position.y ); - mSecondaryCursor.SetSize( Size( 1.0f, mCursor[SECONDARY_CURSOR].cursorHeight ) ); + mSecondaryCursor.SetPosition( cursor.position.x, + cursor.position.y ); + mSecondaryCursor.SetSize( Size( 1.0f, cursor.cursorHeight ) ); } mSecondaryCursor.SetVisible( mSecondaryCursorVisible ); } // Show or hide the grab handle - if( mActiveGrabHandle ) + HandleImpl& grabHandle = mHandle[GRAB_HANDLE]; + if( grabHandle.active ) { - const bool isVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f ); + 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 ) { @@ -251,59 +326,101 @@ struct Decorator::Impl : public ConnectionTracker CreateGrabHandle(); - mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].position.x, - mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight ); + grabHandle.actor.SetPosition( position.x, + position.y + grabHandle.lineHeight ); } - mGrabHandle.SetVisible( isVisible ); + grabHandle.actor.SetVisible( isVisible ); } - else if( mGrabHandle ) + else if( grabHandle.actor ) { - UnparentAndReset( mGrabHandle ); + UnparentAndReset( grabHandle.actor ); } // Show or hide the selection handles/highlight - if( mActiveSelection ) + HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ]; + 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; + } + } - SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ]; - primary.actor.SetPosition( primary.position.x, - primary.position.y + primary.lineHeight ); + const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f ); + const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f ); - SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ]; - secondary.actor.SetPosition( secondary.position.x, - secondary.position.y + secondary.lineHeight ); + if( isPrimaryVisible || isSecondaryVisible ) + { + SetupTouchEvents(); + + 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(); } else { - UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor ); - UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor ); + UnparentAndReset( primary.actor ); + UnparentAndReset( secondary.actor ); UnparentAndReset( mHighlightMeshActor ); } 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 ); } } } @@ -312,32 +429,54 @@ struct Decorator::Impl : public ConnectionTracker { mCursor[PRIMARY_CURSOR].position += scrollOffset; mCursor[SECONDARY_CURSOR].position += scrollOffset; - mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].position += scrollOffset; - mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].position += scrollOffset; - - // TODO Highlight box?? + mHandle[ GRAB_HANDLE ].position += scrollOffset; + mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset; + mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset; + 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 + } + + Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f ); - GetConstrainedPopupPosition( popupPosition, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox ); + GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox ); - SetUpPopUpPositionNotifications(); + SetUpPopupPositionNotifications(); - mCopyPastePopup.SetPosition( popupPosition ); //todo grabhandle(cursor) or selection handle positions to be used + mCopyPastePopup.actor.SetPosition( mCopyPastePopup.position ); } - void CreateCursor( ImageActor& cursor ) + void PopupRelayoutComplete( Actor actor ) { - cursor = CreateSolidColorActor( Color::WHITE ); + // 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 ) + { + cursor = CreateSolidColorActor( color ); cursor.SetParentOrigin( ParentOrigin::TOP_LEFT ); // Need to set the default parent origin as CreateSolidColorActor() sets a different one. cursor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); } @@ -358,7 +497,7 @@ struct Decorator::Impl : public ConnectionTracker { if ( !mPrimaryCursor ) { - CreateCursor( mPrimaryCursor ); + CreateCursor( mPrimaryCursor, mCursor[PRIMARY_CURSOR].color ); #ifdef DECORATOR_DEBUG mPrimaryCursor.SetName( "PrimaryCursorActor" ); #endif @@ -370,7 +509,7 @@ struct Decorator::Impl : public ConnectionTracker { if ( !mSecondaryCursor ) { - CreateCursor( mSecondaryCursor ); + CreateCursor( mSecondaryCursor, mCursor[SECONDARY_CURSOR].color ); #ifdef DECORATOR_DEBUG mSecondaryCursor.SetName( "SecondaryCursorActor" ); #endif @@ -420,8 +559,6 @@ struct Decorator::Impl : public ConnectionTracker { if( !mActiveLayer ) { - Actor parent = mTextControlParent.Self(); - mActiveLayer = Layer::New(); #ifdef DECORATOR_DEBUG mActiveLayer.SetName ( "ActiveLayerActor" ); @@ -431,7 +568,8 @@ struct Decorator::Impl : public ConnectionTracker 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(); @@ -439,57 +577,67 @@ struct Decorator::Impl : public ConnectionTracker void CreateGrabHandle() { - if( !mGrabHandle ) + HandleImpl& grabHandle = mHandle[GRAB_HANDLE]; + if( !grabHandle.actor ) { - if ( !mGrabHandleImage ) + if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] ) + { + mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_RELEASED ); + } + if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] ) { - mGrabHandleImage = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE ); + mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_PRESSED ); } - mGrabHandle = ImageActor::New( mGrabHandleImage ); - mGrabHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER ); - mGrabHandle.SetDrawMode( DrawMode::OVERLAY ); + grabHandle.actor = ImageActor::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] ); + grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + grabHandle.actor.SetDrawMode( DrawMode::OVERLAY ); // Area that Grab handle responds to, larger than actual handle so easier to move #ifdef DECORATOR_DEBUG - mGrabHandle.SetName( "GrabHandleActor" ); + grabHandle.actor.SetName( "GrabHandleActor" ); if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) ) { - mGrabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 ); - mGrabArea.SetName( "GrabArea" ); + grabHandle.grabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 ); + grabHandle.grabArea.SetName( "GrabArea" ); } else { - mGrabArea = Actor::New(); - mGrabArea.SetName( "GrabArea" ); + grabHandle.grabArea = Actor::New(); + grabHandle.grabArea.SetName( "GrabArea" ); } #else - mGrabArea = Actor::New(); + grabHandle.grabArea = Actor::New(); #endif - mGrabArea.SetParentOrigin( ParentOrigin::TOP_CENTER ); - mGrabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER ); - mGrabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS ); - mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE ); - mGrabHandle.Add( mGrabArea ); + grabHandle.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER ); + grabHandle.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + grabHandle.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS ); + grabHandle.grabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE ); + grabHandle.actor.Add( grabHandle.grabArea ); - mTapDetector.Attach( mGrabArea ); - mPanGestureDetector.Attach( mGrabArea ); + grabHandle.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched ); + mTapDetector.Attach( grabHandle.grabArea ); + mPanGestureDetector.Attach( grabHandle.grabArea ); - mActiveLayer.Add( mGrabHandle ); + mActiveLayer.Add( grabHandle.actor ); } } void CreateSelectionHandles() { - SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ]; - if ( !primary.actor ) + HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ]; + if( !primary.actor ) { - if ( !primary.releasedImage ) + if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] ) + { + mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_RELEASED ); + } + if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] ) { - primary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE ); + mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_PRESSED ); } - primary.actor = ImageActor::New( primary.releasedImage ); + primary.actor = ImageActor::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] ); #ifdef DECORATOR_DEBUG primary.actor.SetName("SelectionHandleOne"); #endif @@ -502,8 +650,9 @@ struct Decorator::Impl : public ConnectionTracker 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 ); @@ -513,15 +662,19 @@ struct Decorator::Impl : public ConnectionTracker mActiveLayer.Add( primary.actor ); } - SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ]; - if ( !secondary.actor ) + HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ]; + if( !secondary.actor ) { - if ( !secondary.releasedImage ) + if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] ) { - secondary.releasedImage = 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( secondary.releasedImage ); + secondary.actor = ImageActor::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] ); #ifdef DECORATOR_DEBUG secondary.actor.SetName("SelectionHandleTwo"); #endif @@ -534,8 +687,9 @@ struct Decorator::Impl : public ConnectionTracker 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 ); @@ -544,8 +698,6 @@ struct Decorator::Impl : public ConnectionTracker secondary.actor.Add( secondary.grabArea ); mActiveLayer.Add( secondary.actor ); } - - //SetUpHandlePropertyNotifications(); TODO } void CreateHighlight() @@ -565,11 +717,12 @@ struct Decorator::Impl : public ConnectionTracker 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() @@ -666,50 +819,199 @@ struct Decorator::Impl : public ConnectionTracker void OnTap( Actor actor, const TapGesture& tap ) { - if( actor == mGrabHandle ) + if( actor == mHandle[GRAB_HANDLE].actor ) { // TODO } } - void OnPan( Actor actor, const PanGesture& gesture ) + void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture ) { - if( actor == mGrabArea ) + if( Gesture::Started == gesture.state ) + { + handle.grabDisplacementX = handle.grabDisplacementY = 0; + } + + handle.grabDisplacementX += gesture.displacement.x; + handle.grabDisplacementY += gesture.displacement.y; + + const float x = handle.position.x + handle.grabDisplacementX; + const float y = handle.position.y + handle.lineHeight*0.5f + handle.grabDisplacementY; + + if( Gesture::Started == gesture.state || + Gesture::Continuing == gesture.state ) { - if( Gesture::Started == gesture.state ) + Vector2 targetSize; + mController.GetTargetSize( targetSize ); + + if( x < mScrollThreshold ) + { + mScrollDirection = SCROLL_RIGHT; + mHandleScrolling = type; + StartScrollTimer(); + } + else if( x > targetSize.width - mScrollThreshold ) + { + mScrollDirection = SCROLL_LEFT; + mHandleScrolling = type; + StartScrollTimer(); + } + else + { + mHandleScrolling = HANDLE_TYPE_COUNT; + StopScrollTimer(); + mController.DecorationEvent( type, HANDLE_PRESSED, x, y ); + } + } + else if( Gesture::Finished == gesture.state || + Gesture::Cancelled == gesture.state ) + { + if( mScrollTimer && mScrollTimer.IsRunning() ) + { + mHandleScrolling = HANDLE_TYPE_COUNT; + StopScrollTimer(); + mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y ); + } + else { - mGrabDisplacementX = mGrabDisplacementY = 0; + mController.DecorationEvent( type, HANDLE_RELEASED, x, y ); } - mGrabDisplacementX += gesture.displacement.x; - mGrabDisplacementY += gesture.displacement.y; + if( GRAB_HANDLE == type ) + { + 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; + } + } + + void OnPan( Actor actor, const PanGesture& gesture ) + { + HandleImpl& grabHandle = mHandle[GRAB_HANDLE]; + HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE]; + HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE]; + + if( actor == grabHandle.grabArea ) + { + DoPan( grabHandle, GRAB_HANDLE, gesture ); + } + else if( actor == primarySelectionHandle.grabArea ) + { + DoPan( primarySelectionHandle, LEFT_SELECTION_HANDLE, gesture ); + } + else if( actor == secondarySelectionHandle.grabArea ) + { + DoPan( secondarySelectionHandle, RIGHT_SELECTION_HANDLE, gesture ); + } + } - const float x = mCursor[PRIMARY_CURSOR].position.x + mGrabDisplacementX; - const float y = mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight*0.5f + mGrabDisplacementY; + 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( Gesture::Started == gesture.state || - Gesture::Continuing == gesture.state ) + if( TouchPoint::Down == point.state ) { - mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y ); + mHandle[GRAB_HANDLE].pressed = true; + Image imagePressed = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED]; + if( imagePressed ) + { + mHandle[GRAB_HANDLE].actor.SetImage( imagePressed ); + } } - else if( Gesture::Finished == gesture.state || - Gesture::Cancelled == gesture.state ) + else if( TouchPoint::Up == point.state ) { - mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y ); + 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& touch ) + 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 @@ -726,7 +1028,7 @@ struct Decorator::Impl : public ConnectionTracker const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class. - if( mActiveGrabHandle ) + if( mHandle[GRAB_HANDLE].active ) { // If grab handle enabled then position pop-up below the grab handle. const Vector2 grabHandleSize( 59.0f, 56.0f ); // todo @@ -744,21 +1046,15 @@ struct Decorator::Impl : public ConnectionTracker void PopUpLeavesVerticalBoundary( PropertyNotification& source ) { float alternativeYPosition=0.0f; - // todo - // if( mHighlightMeshActor ) // Text Selection mode - // { - // alternativePosition = AlternatePopUpPositionRelativeToSelectionHandles(); - // } - // else // Not in Text Selection mode - // { + // todo use AlternatePopUpPositionRelativeToSelectionHandles() if text is highlighted // 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. @@ -767,11 +1063,11 @@ struct Decorator::Impl : public ConnectionTracker 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 ); } @@ -808,32 +1104,131 @@ struct Decorator::Impl : public ConnectionTracker } requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds; + + // Prevent pixel mis-alignment by rounding down. + requiredPopupPosition.x = static_cast( requiredPopupPosition.x ); + requiredPopupPosition.y = static_cast( 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 ) + { + mScrollThreshold = threshold; + } + + float GetScrollThreshold() const + { + return mScrollThreshold; + } + + void SetScrollSpeed( float speed ) + { + mScrollSpeed = speed; + mScrollDistance = speed * SCROLL_TICK_INTERVAL * TO_SECONDS; + } + + float GetScrollSpeed() const + { + return mScrollSpeed; + } + + /** + * Creates and starts a timer to scroll the text when handles are close to the edges of the text. + * + * It only starts the timer if it's already created. + */ + void StartScrollTimer() + { + if( !mScrollTimer ) + { + mScrollTimer = Timer::New( SCROLL_TICK_INTERVAL ); + mScrollTimer.TickSignal().Connect( this, &Decorator::Impl::OnScrollTimerTick ); + } + + if( !mScrollTimer.IsRunning() ) + { + mScrollTimer.Start(); + } + } + + /** + * Stops the timer used to scroll the text. + */ + void StopScrollTimer() + { + if( mScrollTimer ) + { + mScrollTimer.Stop(); + } + } + + /** + * Callback called by the timer used to scroll the text. + * + * It calculates and sets a new scroll position. + */ + bool OnScrollTimerTick() + { + if( HANDLE_TYPE_COUNT != mHandleScrolling ) + { + 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; Timer mCursorBlinkTimer; ///< Timer to signal cursor to blink + Timer mScrollTimer; ///< Timer used to scroll the text when the grab handle is moved close to the edges. Layer mActiveLayer; ///< Layer for active handles and alike that ensures they are above all else. ImageActor mPrimaryCursor; ImageActor mSecondaryCursor; - ImageActor mGrabHandle; - Actor mGrabArea; 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; - Image mGrabHandleImage; Mesh mHighlightMesh; ///< Mesh for highlight MeshData mHighlightMeshData; ///< Mesh Data for highlight Material mHighlightMaterial; ///< Material used for highlight CursorImpl mCursor[CURSOR_COUNT]; - SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_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 mBoundingBox; Vector4 mHighlightColor; ///< Color of the highlight @@ -841,20 +1236,25 @@ struct Decorator::Impl : public ConnectionTracker unsigned int mActiveCursor; unsigned int mCursorBlinkInterval; float mCursorBlinkDuration; - float mGrabDisplacementX; - float mGrabDisplacementY; + HandleType mHandleScrolling; ///< The handle which is scrolling. + ScrollDirection mScrollDirection; ///< The direction of the scroll. + 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 mActiveGrabHandle : 1; - bool mActiveSelection : 1; 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. }; -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& boundingBox ) @@ -891,13 +1291,6 @@ unsigned int Decorator::GetActiveCursor() const void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight ) { - // Adjust grab handle displacement - if( PRIMARY_CURSOR == cursor ) - { - mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].position.x; - mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].position.y; - } - mImpl->mCursor[cursor].position.x = x; mImpl->mCursor[cursor].position.y = y; mImpl->mCursor[cursor].cursorHeight = cursorHeight; @@ -969,74 +1362,60 @@ float Decorator::GetCursorBlinkDuration() const return mImpl->mCursorBlinkDuration; } -/** GrabHandle **/ +/** Handles **/ -void Decorator::SetGrabHandleActive( bool active ) +void Decorator::SetHandleActive( HandleType handleType, bool active ) { - mImpl->mActiveGrabHandle = active; + mImpl->mHandle[handleType].active = active; } -bool Decorator::IsGrabHandleActive() const +bool Decorator::IsHandleActive( HandleType handleType ) const { - return mImpl->mActiveGrabHandle; + return mImpl->mHandle[handleType].active ; } -void Decorator::SetGrabHandleImage( Dali::Image image ) +void Decorator::SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image ) { - mImpl->mGrabHandleImage = image; + mImpl->mHandleImages[handleType][handleImageType] = image; } -Dali::Image Decorator::GetGrabHandleImage() const +Dali::Image Decorator::GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const { - return mImpl->mGrabHandleImage; + return mImpl->mHandleImages[handleType][handleImageType]; } -/** Selection **/ - -void Decorator::SetSelectionActive( bool active ) +void Decorator::SetPosition( HandleType handleType, float x, float y, float height ) { - mImpl->mActiveSelection = active; -} + // Adjust grab handle displacement + Impl::HandleImpl& handle = mImpl->mHandle[handleType]; -bool Decorator::IsSelectionActive() const -{ - return mImpl->mActiveSelection; -} + handle.grabDisplacementX -= x - handle.position.x; + handle.grabDisplacementY -= y - handle.position.y; -void Decorator::SetPosition( SelectionHandle handle, float x, float y, float height ) -{ - mImpl->mSelectionHandle[handle].position.x = x; - mImpl->mSelectionHandle[handle].position.y = y; - mImpl->mSelectionHandle[handle].lineHeight = height; + handle.position.x = x; + handle.position.y = y; + handle.lineHeight = height; } -void Decorator::GetPosition( SelectionHandle handle, float& x, float& y, float& height ) const +void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& height ) const { - x = mImpl->mSelectionHandle[handle].position.x; - y = mImpl->mSelectionHandle[handle].position.y; - height = mImpl->mSelectionHandle[handle].lineHeight; + Impl::HandleImpl& handle = mImpl->mHandle[handleType]; + + x = handle.position.x; + y = handle.position.y; + height = handle.lineHeight; } -void Decorator::SetImage( SelectionHandle handle, SelectionHandleState state, Dali::Image image ) +const Vector2& Decorator::GetPosition( HandleType handleType ) const { - if( SELECTION_HANDLE_PRESSED == state ) - { - mImpl->mSelectionHandle[handle].pressedImage = image; - } - else - { - mImpl->mSelectionHandle[handle].releasedImage = image; - } + return mImpl->mHandle[handleType].position; } -Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState state ) const +void Decorator::SwapSelectionHandlesEnabled( bool enable ) { - if( SELECTION_HANDLE_PRESSED == state ) - { - return mImpl->mSelectionHandle[handle].pressedImage; - } + mImpl->mSwapSelectionHandles = enable; - return mImpl->mSelectionHandle[handle].releasedImage; + mImpl->FlipSelectionHandleImages(); } void Decorator::AddHighlight( float x1, float y1, float x2, float y2 ) @@ -1047,6 +1426,17 @@ void Decorator::AddHighlight( float x1, float y1, float x2, float y2 ) void Decorator::ClearHighlights() { mImpl->mHighlightQuadList.clear(); + mImpl->mHighlightPosition = Vector2::ZERO; +} + +void Decorator::SetHighlightColor( const Vector4& color ) +{ + mImpl->mHighlightColor = color; +} + +const Vector4& Decorator::GetHighlightColor() const +{ + return mImpl->mHighlightColor; } void Decorator::SetPopupActive( bool active ) @@ -1059,15 +1449,48 @@ bool Decorator::IsPopupActive() const 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 ) +{ + mImpl->SetScrollThreshold( threshold ); +} + +float Decorator::GetScrollThreshold() const +{ + return mImpl->GetScrollThreshold(); +} + +void Decorator::SetScrollSpeed( float speed ) +{ + mImpl->SetScrollSpeed( speed ); +} + +float Decorator::GetScrollSpeed() const +{ + return mImpl->GetScrollSpeed(); +} + 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