X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fdecorator%2Ftext-decorator.cpp;h=b4a0705737e2b4298ee94375f8529f7476c17910;hp=5b5ba836448e85aaed020e6d8de732e06bc8bdc1;hb=56d412791a44c2a79135d2293c13fddb135c9d54;hpb=830f03638ec6ecd3b12ba3d9eb6419fdb3a3db09 diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp index 5b5ba83..b4a0705 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.cpp +++ b/dali-toolkit/internal/text/decorator/text-decorator.cpp @@ -23,20 +23,27 @@ #include #include #include +#include #include -#include #include #include #include #include +#include +#include #include #include #include +//#include #include // INTERNAL INCLUDES #include #include +#include +#include +#include +#include #ifdef DEBUG_ENABLED #define DECORATOR_DEBUG @@ -51,7 +58,6 @@ const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-h 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_CURSOR_IMAGE( DALI_IMAGE_DIR "decorator-cursor.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 ); @@ -59,6 +65,39 @@ const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f ); const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval const std::size_t MILLISECONDS = 1000; +const float DISPLAYED_HIGHLIGHT_Z_OFFSET( -0.05f ); + +/** + * structure to hold coordinates of each quad, which will make up the mesh. + */ +struct QuadCoordinates +{ + /** + * Default constructor + */ + QuadCoordinates() + { + } + + /** + * Constructor + * @param[in] x1 left co-ordinate + * @param[in] y1 top co-ordinate + * @param[in] x2 right co-ordinate + * @param[in] y2 bottom co-ordinate + */ + QuadCoordinates(float x1, float y1, float x2, float y2) + : min(x1, y1), + max(x2, y2) + { + } + + Dali::Vector2 min; ///< top-left (minimum) position of quad + Dali::Vector2 max; ///< bottom-right (maximum) position of quad +}; + +typedef std::vector QuadContainer; + } // end of namespace namespace Dali @@ -112,16 +151,18 @@ struct Decorator::Impl : public ConnectionTracker }; Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer ) - : mParent(parent), + : mTextControlParent(parent), mObserver(observer), mActiveCursor(ACTIVE_CURSOR_NONE), mActiveGrabHandle(false), mActiveSelection( false ), + mActiveCopyPastePopup( false ), mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ), mCursorBlinkDuration( 0.0f ), mCursorBlinkStatus( true ), mGrabDisplacementX( 0.0f ), mGrabDisplacementY( 0.0f ), + mHighlightColor( 0.07f, 0.41f, 0.59f, 1.0f ), // light blue mBoundingBox( Rect() ) { } @@ -130,19 +171,35 @@ struct Decorator::Impl : public ConnectionTracker * Relayout of the decorations owned by the decorator. * @param[in] size The Size of the UI control the decorater is adding it's decorations to. */ - void Relayout( const Vector2& size ) + void Relayout( const Vector2& size, const Vector2& scrollPosition ) { - SetCursors(); + // TODO - Remove this if nothing is active + CreateActiveLayer(); + + // Show or hide the cursors + CreateCursors(); + if( mPrimaryCursor ) + { + mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x, + mCursor[PRIMARY_CURSOR].y + scrollPosition.y ); + mPrimaryCursor.SetSize( Vector2( 1.0f, mCursor[PRIMARY_CURSOR].height ) ); + } + if( mSecondaryCursor ) + { + mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].x + scrollPosition.x, + mCursor[SECONDARY_CURSOR].y + scrollPosition.y ); + mSecondaryCursor.SetSize( Vector2( 1.0f, mCursor[SECONDARY_CURSOR].height ) ); + } // Show or hide the grab handle if( mActiveGrabHandle ) { SetupTouchEvents(); - CreateActiveLayer(); CreateGrabHandle(); - mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height ); + mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x, + mCursor[PRIMARY_CURSOR].y + scrollPosition.y + mCursor[PRIMARY_CURSOR].height ); } else if( mGrabHandle ) { @@ -154,79 +211,86 @@ struct Decorator::Impl : public ConnectionTracker { SetupTouchEvents(); - CreateActiveLayer(); CreateSelectionHandles(); SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ]; - primary.actor.SetPosition( primary.x, primary.y + primary.cursorHeight ); + primary.actor.SetPosition( primary.x + scrollPosition.x, + primary.y + scrollPosition.y + primary.cursorHeight ); SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ]; - secondary.actor.SetPosition( secondary.x, secondary.y + secondary.cursorHeight ); + secondary.actor.SetPosition( secondary.x + scrollPosition.x, + secondary.y + scrollPosition.y + secondary.cursorHeight ); - //CreateHighlight(); TODO + CreateHighlight(); + UpdateHighlight(); } else { UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor ); UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor ); + UnparentAndReset( mHighlightMeshActor ); + } + + if ( mActiveCopyPastePopup ) + { + if ( !mCopyPastePopup ) + { + mCopyPastePopup = TextSelectionPopup::New(); + mActiveLayer.Add ( mCopyPastePopup ); + } + mCopyPastePopup.SetPosition( Vector3( 200.0f, -100.0f, 0.0f ) ); //todo grabhandle or selection handle positions to be used + } + else + { + if ( mCopyPastePopup ) + { + UnparentAndReset( mCopyPastePopup ); + } } } - /** - * Creates a cursor - */ void CreateCursor( ImageActor& cursor ) { - if ( !mCursorImage ) - { - mCursorImage = ResourceImage::New( DEFAULT_CURSOR_IMAGE ); - } - cursor = ImageActor::New( mCursorImage ); + cursor = CreateSolidColorActor( Color::WHITE ); + cursor.SetParentOrigin( ParentOrigin::TOP_LEFT ); // Need to set the default parent origin as CreateSolidColorActor() sets a different one. cursor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + cursor.SetRelayoutEnabled( false ); } - /** - * Add / Remove cursor(s) from parent - */ - void SetCursors() + // Add or Remove cursor(s) from parent + void CreateCursors() { - Actor parent = mParent.Self(); - /* Create Primary and or Secondary Cursor(s) if active and add to parent */ - if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ) + if( mActiveCursor == ACTIVE_CURSOR_NONE ) { - if ( !mPrimaryCursor ) - { - CreateCursor( mPrimaryCursor ); -#ifdef DECORATOR_DEBUG - mPrimaryCursor.SetName( "PrimaryCursorActor" ); -#endif - parent.Add( mPrimaryCursor); - } - - mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y ); + UnparentAndReset( mPrimaryCursor ); + UnparentAndReset( mSecondaryCursor ); } - else if ( mActiveCursor == ACTIVE_CURSOR_BOTH ) + else { - if ( !mSecondaryCursor ) + /* Create Primary and or Secondary Cursor(s) if active and add to parent */ + if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY || + mActiveCursor == ACTIVE_CURSOR_BOTH ) { - CreateCursor( mSecondaryCursor ); + if ( !mPrimaryCursor ) + { + CreateCursor( mPrimaryCursor ); #ifdef DECORATOR_DEBUG - mSecondaryCursor.SetName( "SecondaryCursorActor" ); + mPrimaryCursor.SetName( "PrimaryCursorActor" ); #endif - parent.Add( mSecondaryCursor); - } - } - else - { - /* ACTIVE_CURSOR_NONE so unparent cursors*/ - if ( mPrimaryCursor ) - { - UnparentAndReset( mPrimaryCursor ); + mActiveLayer.Add( mPrimaryCursor); + } } - if ( mSecondaryCursor ) + if ( mActiveCursor == ACTIVE_CURSOR_BOTH ) { - UnparentAndReset( mSecondaryCursor ); + if ( !mSecondaryCursor ) + { + CreateCursor( mSecondaryCursor ); +#ifdef DECORATOR_DEBUG + mSecondaryCursor.SetName( "SecondaryCursorActor" ); +#endif + mActiveLayer.Add( mSecondaryCursor); + } } } } @@ -234,13 +298,12 @@ struct Decorator::Impl : public ConnectionTracker bool OnCursorBlinkTimerTick() { // Cursor blinking - if ( ACTIVE_CURSOR_PRIMARY ) + if ( mPrimaryCursor ) { mPrimaryCursor.SetVisible( mCursorBlinkStatus ); } - else if ( ACTIVE_CURSOR_BOTH ) + if ( mSecondaryCursor ) { - mPrimaryCursor.SetVisible( mCursorBlinkStatus ); mSecondaryCursor.SetVisible( mCursorBlinkStatus ); } @@ -268,16 +331,15 @@ struct Decorator::Impl : public ConnectionTracker { if( !mActiveLayer ) { - Actor parent = mParent.Self(); + Actor parent = mTextControlParent.Self(); mActiveLayer = Layer::New(); #ifdef DECORATOR_DEBUG mActiveLayer.SetName ( "ActiveLayerActor" ); #endif - mActiveLayer.SetAnchorPoint( AnchorPoint::CENTER); - mActiveLayer.SetParentOrigin( ParentOrigin::CENTER); - mActiveLayer.SetSizeMode( SIZE_EQUAL_TO_PARENT ); + mActiveLayer.SetParentOrigin( ParentOrigin::CENTER ); + mActiveLayer.SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS ); mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION ); parent.Add( mActiveLayer ); @@ -299,18 +361,21 @@ struct Decorator::Impl : public ConnectionTracker #ifdef DECORATOR_DEBUG mGrabHandle.SetName( "GrabHandleActor" ); #endif - mGrabHandle.SetParentOrigin( ParentOrigin::TOP_LEFT ); mGrabHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER ); mGrabHandle.SetDrawMode( DrawMode::OVERLAY ); - - mGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move + // Area that Grab handle responds to, larger than actual handle so easier to move #ifdef DECORATOR_DEBUG - mGrabArea.SetName( "GrabArea" ); + mGrabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 ); + mGrabArea.SetName( "GrabArea" ); +#else + mGrabArea = Actor::New(); + mGrabArea.SetRelayoutEnabled( true ); #endif - mGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); - mGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + mGrabArea.SetParentOrigin( ParentOrigin::TOP_CENTER ); + mGrabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + mGrabArea.SetResizePolicy( SIZE_RELATIVE_TO_PARENT, ALL_DIMENSIONS ); mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE ); - mGrabHandle.Add(mGrabArea); + mGrabHandle.Add( mGrabArea ); mTapDetector.Attach( mGrabArea ); mPanGestureDetector.Attach( mGrabArea ); @@ -333,16 +398,16 @@ struct Decorator::Impl : public ConnectionTracker #ifdef DECORATOR_DEBUG primary.actor.SetName("SelectionHandleOne"); #endif - primary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text. primary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text primary.flipped = false; primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move + primary.grabArea.SetRelayoutEnabled( true ); #ifdef DECORATOR_DEBUG primary.grabArea.SetName("SelectionHandleOneGrabArea"); #endif - primary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + primary.grabArea.SetResizePolicy( SIZE_RELATIVE_TO_PARENT, ALL_DIMENSIONS ); primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ); primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); @@ -366,16 +431,16 @@ struct Decorator::Impl : public ConnectionTracker #ifdef DECORATOR_DEBUG secondary.actor.SetName("SelectionHandleTwo"); #endif - secondary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); - secondary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text. + secondary.actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text. secondary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text secondary.flipped = false; secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move + secondary.grabArea.SetRelayoutEnabled( true ); #ifdef DECORATOR_DEBUG secondary.grabArea.SetName("SelectionHandleTwoGrabArea"); #endif - secondary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + secondary.grabArea.SetResizePolicy( SIZE_RELATIVE_TO_PARENT, ALL_DIMENSIONS ); secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ); secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); @@ -390,6 +455,122 @@ struct Decorator::Impl : public ConnectionTracker //SetUpHandlePropertyNotifications(); TODO } + void CreateHighlight() + { + if ( !mHighlightMeshActor ) + { + mHighlightMaterial = Material::New( "HighlightMaterial" ); + mHighlightMaterial.SetDiffuseColor( mHighlightColor ); + + mHighlightMeshData.SetMaterial( mHighlightMaterial ); + mHighlightMeshData.SetHasNormals( true ); + + mHighlightMesh = Mesh::New( mHighlightMeshData ); + + mHighlightMeshActor = MeshActor::New( mHighlightMesh ); +#ifdef DECORATOR_DEBUG + 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 ); + } + } + + void UpdateHighlight() + { + // Construct a Mesh with a texture to be used as the highlight 'box' for selected text + // + // Example scenarios where mesh is made from 3, 1, 2, 2 ,3 or 3 quads. + // + // [ TOP ] [ TOP ] [TOP ] [ TOP ] [ TOP ] [ TOP ] + // [ MIDDLE ] [BOTTOM] [BOTTOM] [ MIDDLE ] [ MIDDLE ] + // [ BOTTOM] [ MIDDLE ] [ MIDDLE ] + // [BOTTOM] [ MIDDLE ] + // [BOTTOM] + // + // Each quad is created as 2 triangles. + // Middle is just 1 quad regardless of its size. + // + // (0,0) (0,0) + // 0* *2 0* *2 + // TOP TOP + // 3* *1 3* *1 + // 4* *1 4* *6 + // MIDDLE BOTTOM + // 6* *5 7* *5 + // 6* *8 + // BOTTOM + // 9* *7 + // + + if ( mHighlightMesh && mHighlightMaterial && !mHighlightQuadList.empty() ) + { + MeshData::VertexContainer vertices; + Dali::MeshData::FaceIndices faceIndices; + + std::vector::iterator iter = mHighlightQuadList.begin(); + std::vector::iterator endIter = mHighlightQuadList.end(); + + // vertex position defaults to (0 0 0) + MeshData::Vertex vertex; + // set normal for all vertices as (0 0 1) pointing outward from TextInput Actor. + vertex.nZ = 1.0f; + + for(std::size_t v = 0; iter != endIter; ++iter,v+=4 ) + { + // Add each quad geometry (a sub-selection) to the mesh data. + + // 0-----1 + // |\ | + // | \ A | + // | \ | + // | B \ | + // | \| + // 2-----3 + + QuadCoordinates& quad = *iter; + // top-left (v+0) + vertex.x = quad.min.x; + vertex.y = quad.min.y; + vertices.push_back( vertex ); + + // top-right (v+1) + vertex.x = quad.max.x; + vertex.y = quad.min.y; + vertices.push_back( vertex ); + + // bottom-left (v+2) + vertex.x = quad.min.x; + vertex.y = quad.max.y; + vertices.push_back( vertex ); + + // bottom-right (v+3) + vertex.x = quad.max.x; + vertex.y = quad.max.y; + vertices.push_back( vertex ); + + // triangle A (3, 1, 0) + faceIndices.push_back( v + 3 ); + faceIndices.push_back( v + 1 ); + faceIndices.push_back( v ); + + // triangle B (0, 2, 3) + faceIndices.push_back( v ); + faceIndices.push_back( v + 2 ); + faceIndices.push_back( v + 3 ); + + mHighlightMeshData.SetFaceIndices( faceIndices ); + } + + BoneContainer bones(0); // passed empty as bones not required + mHighlightMeshData.SetData( vertices, faceIndices, bones, mHighlightMaterial ); + mHighlightMesh.UpdateMeshData( mHighlightMeshData ); + } + } + void OnTap( Actor actor, const TapGesture& tap ) { if( actor == mGrabHandle ) @@ -438,7 +619,8 @@ struct Decorator::Impl : public ConnectionTracker return false; } - Internal::Control& mParent; + + Internal::Control& mTextControlParent; Observer& mObserver; Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else. @@ -446,6 +628,7 @@ struct Decorator::Impl : public ConnectionTracker unsigned int mActiveCursor; bool mActiveGrabHandle; bool mActiveSelection; + bool mActiveCopyPastePopup; CursorImpl mCursor[CURSOR_COUNT]; @@ -464,6 +647,15 @@ struct Decorator::Impl : public ConnectionTracker SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT]; + MeshActor mHighlightMeshActor; ///< Mesh Actor to display highlight + Mesh mHighlightMesh; ///< Mesh for highlight + MeshData mHighlightMeshData; ///< Mesh Data for highlight + Material mHighlightMaterial; ///< Material used for highlight + Vector4 mHighlightColor; ///< Color of the highlight + QuadContainer mHighlightQuadList; ///< Sub-selections that combine to create the complete selection highlight + + TextSelectionPopup mCopyPastePopup; + Image mCursorImage; Image mGrabHandleImage; @@ -488,9 +680,9 @@ const Rect& Decorator::GetBoundingBox() const return mImpl->mBoundingBox; } -void Decorator::Relayout( const Vector2& size ) +void Decorator::Relayout( const Vector2& size, const Vector2& scrollPosition ) { - mImpl->Relayout( size ); + mImpl->Relayout( size, scrollPosition ); } /** Cursor **/ @@ -523,16 +715,6 @@ void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& height ) height = mImpl->mCursor[cursor].height; } -void Decorator::SetCursorImage( Dali::Image image ) -{ - mImpl->mCursorImage = image; -} - -Dali::Image Decorator::GetCursorImage() const -{ - return mImpl->mCursorImage; -} - void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color ) { mImpl->mCursor[cursor].color = color; @@ -655,6 +837,26 @@ Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState st return mImpl->mSelectionHandle[handle].releasedImage; } +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(); +} + +void Decorator::SetPopupActive( bool active ) +{ + mImpl->mActiveCopyPastePopup = active; +} + +bool Decorator::IsPopupActive() const +{ + return mImpl->mActiveCopyPastePopup ; +} + Decorator::~Decorator() { delete mImpl;