From ebfd783daaf2188528cabc6f747284e5ab426355 Mon Sep 17 00:00:00 2001 From: Agnelo Vaz Date: Thu, 24 Apr 2014 21:27:25 +0100 Subject: [PATCH] TextInput Decorator class and stubbed decoration classes Problem:TextInput is a huge class with many responsibilities, it's hard to maintain and decorations can not be re-used. Solution: Spilt into multiple classes. In this patch the Decorator initiates creation of decorations and positions them. Stubbed Decoration classes provided for build purposes. Change-Id: Ib880849dbc80cb1b6510a06401f5a6bfccfa55e8 Signed-off-by: Agnelo Vaz --- .../text-input/text-input-decorator-impl.cpp | 1221 ++++++++++++++++++++ .../text-input/text-input-decorator-impl.h | 635 ++++++++++ .../controls/text-input/text-input-handles-impl.h | 203 ++++ .../text-input/text-input-popup-new-impl.h | 274 +++++ .../text-input/text-input-text-highlight-impl.h | 179 +++ .../text-input/text-input-text-style-impl.h | 120 ++ .../text-input/textview-character-positions-impl.h | 340 ++++++ base/dali-toolkit/internal/file.list | 1 + 8 files changed, 2973 insertions(+) create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.cpp create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.h create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-handles-impl.h create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-popup-new-impl.h create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-text-highlight-impl.h create mode 100644 base/dali-toolkit/internal/controls/text-input/text-input-text-style-impl.h create mode 100644 base/dali-toolkit/internal/controls/text-input/textview-character-positions-impl.h diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.cpp b/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.cpp new file mode 100644 index 0000000..1e034a3 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.cpp @@ -0,0 +1,1221 @@ +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include + +// INTERNAL INCLUDES +#include + +#include + +using namespace Dali; + +namespace +{ +#if defined(DEBUG_ENABLED) + Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TEXT_INPUT_DECORATOR"); +#endif + + const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f ); + const float TOP_HANDLE_TOP_OFFSET(-1.5f); // Offset between top handle and cutCopyPaste pop-up + const float BOTTOM_HANDLE_BOTTOM_OFFSET(1.5f); // Offset between bottom handle and cutCopyPaste pop-up + const float UI_Z_OFFSET( 0.2f ); // Text Selection Handles/Cursor z-offset. + const Vector3 UI_OFFSET(0.0f, 0.0f, UI_Z_OFFSET); // Text Selection Handles/Cursor offset. + const char* DEFAULT_CURSOR( DALI_IMAGE_DIR "cursor.png" ); + const Vector4 DEFAULT_CURSOR_IMAGE_9_BORDER( 2.0f, 2.0f, 2.0f, 2.0f ); + const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval + const float CURSOR_THICKNESS(6.0f); + const Degree CURSOR_ANGLE_OFFSET(2.0f); // Offset from the angle + + const unsigned int SCROLL_TICK_INTERVAL = 50u; + const float SCROLL_THRESHOLD = 10.f; + const float SCROLL_SPEED = 15.f; + + /** + * Whether the given position plus the cursor size offset is inside the given boundary. + * + * @param[in] position The given position. + * @param[in] cursorSize The cursor size. + * @param[in] controlSize The given boundary. + * @param[in] threshold imaginary indent around boundary that will trigger the position to be outside of control. + * + * @return whether the given position is inside the given boundary. + */ + bool IsPositionWithinControl( const Vector3& position, const Size& cursorSize, const Vector3& controlSize, const Vector2 threshold = Vector2::ZERO ) + { + return ( position.x >= -Math::MACHINE_EPSILON_1000 + threshold.x ) && + ( position.x <= controlSize.width - threshold.x + Math::MACHINE_EPSILON_1000 ) && + ( position.y - cursorSize.height >= -Math::MACHINE_EPSILON_1000 + threshold.y ) && + ( position.y <= controlSize.height + Math::MACHINE_EPSILON_1000 - threshold.y); + } +} + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +Decorator::Decorator( TextViewCharacterPositioning& textViewManager, TextInputTextStyle& textStyle ): + mTextViewCharacterPositioning( textViewManager ), + mTextStyle( textStyle ), + mCursorPosition( 0 ), + mTextHighlight( textViewManager ), + mCursorBlinkStatus( true ), + mCursorVisibility( true ), + mGrabHandleEnabled( true ) +{ +} + +Decorator::~Decorator() +{ +} + +/** + * Bounding Box + */ +void Decorator::SetBoundingBox( const Rect& boundingRectangle ) +{ + // Convert to world coordinates and store as a Vector4 to be compatible with Property Notifications. + Vector2 stageSize = Dali::Stage::GetCurrent().GetSize(); + + const float originX = boundingRectangle.x - 0.5f * stageSize.width; + const float originY = boundingRectangle.y - 0.5f * stageSize.height; + + const Vector4 boundary( originX, + originY, + originX + boundingRectangle.width, + originY + boundingRectangle.height ); + + mBoundingRectangleWorldCoordinates = boundary; +} + +Vector4 Decorator::GetBoundingBox() const +{ + return mBoundingRectangleWorldCoordinates; +} + +/** + * Selection Handles + */ +void Decorator::OnHandlePan(Actor actor, PanGesture gesture) +{ + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + + switch (gesture.state) + { + case Gesture::Started: + // fall through so code not duplicated + case Gesture::Continuing: + { + if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleOne() ) + { + MoveSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition, gesture.displacement ); + HidePopUp(); + } + else if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleTwo() ) + { + MoveSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition, gesture.displacement ); + HidePopUp(); + } + else if ( actor.GetParent() == mTextInputHandles.GetGrabHandle() ) + { + SetCursorVisibility( true ); + ShowGrabHandle( mGrabHandleVisibility && mIsGrabHandleInScrollArea ); + MoveGrabHandle( gesture.displacement ); + HidePopUp(); // Do not show popup while handle is moving + } + } + break; + + case Gesture::Finished: + { + // Revert back to non-pressed selection handle images + if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleOne() ) + { + mSelectionHandleOneActualPosition = MoveSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition, gesture.displacement ); + ShowPopupCutCopyPaste(); + ShowPopUp(); + } + else if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleTwo() ) + { + mSelectionHandleTwoActualPosition = MoveSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition, gesture.displacement ); + ShowPopupCutCopyPaste(); + ShowPopUp(); + } + else if ( actor.GetParent() == mTextInputHandles.GetGrabHandle() ) + { + MoveGrabHandle( gesture.displacement ); + SetCursorVisibility( true ); + ShowPopupCutCopyPaste(); + ShowPopUp(); + } + } + break; + default: + break; + } +} + +void Decorator::CreateSelectionHandles( Actor targetParent ) +{ + if ( !mPanGestureDetector ) + { + mPanGestureDetector = PanGestureDetector::New(); + mPanGestureDetector.DetectedSignal().Connect(this, &Decorator::OnHandlePan); + } + + if ( !mTextInputHandles.GetSelectionHandleOne() ) + { + mTextInputHandles.CreateSelectionHandles(); + + mTextInputHandles.AttachSelectionHandlesToGivenPanGesture( mPanGestureDetector ); + + targetParent.Add( mTextInputHandles.GetSelectionHandleOne() ); + targetParent.Add( mTextInputHandles.GetSelectionHandleTwo() ); + + SetUpHandlePropertyNotifications(); + } +} + +void Decorator::RemoveSelectionHandles() +{ + mTextInputHandles.DestorySelectionHandles(); +} + +Vector3 Decorator::GetSelectionHandleSize() +{ + return DEFAULT_SELECTION_HANDLE_SIZE; +} + +std::size_t Decorator::GetHandleOnePosition() const +{ + return mSelectionHandleOnePosition; +} + +std::size_t Decorator::GetHandleTwoPosition() const +{ + return mSelectionHandleTwoPosition; +} + +Vector3 Decorator::PositionSelectionHandle( Actor selectionHandle, std::size_t position ) +{ + bool direction(false); + Vector3 alternatePosition; + bool alternatePositionValid(false); + + Vector3 actualPositionOfSelectionHandle = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( position, direction, alternatePosition,alternatePositionValid ); + + return PositionSelectionHandle( selectionHandle, actualPositionOfSelectionHandle, position ); + +} + +Vector3 Decorator::PositionSelectionHandle( Actor selectionHandle, Vector3& actualPosition, std::size_t position ) +{ + const Vector3 DEFAULT_HANDLE_OFFSET(0.0f, -5.0f, 0.0f); + + selectionHandle.SetPosition( actualPosition += DEFAULT_HANDLE_OFFSET ); + + if( mTextViewCharacterPositioning.IsScrollEnabled() ) + { + const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); + const Size cursorSize( GetCursorSizeAt( position ) ); + bool handleVisible = IsPositionWithinControl( actualPosition, Vector2(DEFAULT_HANDLE_OFFSET.width, DEFAULT_HANDLE_OFFSET.height), controlSize ); + + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::PositionSelectionHandle controlSize[%f,%f] cursorSize[%f,%f] actualPos[%f,%f] visible[%s] \n", + controlSize.x, controlSize.y, cursorSize.x, cursorSize.y, actualPosition.x, actualPosition.y, ( handleVisible )?"true":"false" ); + + selectionHandle.SetVisible( handleVisible ); + } + return actualPosition; +} + +void Decorator::SetSelectionHandlesVisibility(bool visible ) +{ + mTextInputHandles.SetSelectionHandleOneVisibility( visible ); + mTextInputHandles.SetSelectionHandleTwoVisibility( visible ); +} + +bool Decorator::OnHandleReleased() +{ + ShowPopUp(); + return false; +} + +void Decorator::PositionSelectionHandles( std::size_t start, std::size_t end ) +{ + mSelectionHandleOnePosition = start; + mSelectionHandleTwoPosition = end; + + mTextViewCharacterPositioning.UpdateTextLayoutInfo(); + + mSelectionHandleOneActualPosition = PositionSelectionHandle( mTextInputHandles.GetSelectionHandleOne(), mSelectionHandleOnePosition ); + mSelectionHandleTwoActualPosition = PositionSelectionHandle( mTextInputHandles.GetSelectionHandleTwo(), mSelectionHandleTwoPosition ); + + mTextInputHandles.ReleasedSignal().Connect( this, &Decorator::OnHandleReleased ); +} + +Vector3 Decorator::MoveSelectionHandle( Actor selectionHandle, + Vector3& actualSelectionHandlePosition, + std::size_t& currentSelectionHandlePosition, + const Vector2& displacement ) +{ + Vector3 actualHandlePosition; + actualSelectionHandlePosition.x += displacement.x * selectionHandle.GetCurrentScale().x; + actualSelectionHandlePosition.y += displacement.y * selectionHandle.GetCurrentScale().y;; + + // Selection handles should jump to the nearest character + std::size_t newHandlePosition = 0; + newHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( actualSelectionHandlePosition.GetVectorXY() ); + + bool direction(false); + Vector3 alternatePosition; + bool alternatePositionValid(false); + actualHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandlePosition,direction, alternatePosition, alternatePositionValid ); + + bool handleVisible = true; + + Vector2 min, max; + if( mTextViewCharacterPositioning.IsScrollEnabled() ) + { + const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); + const Size cursorSize( GetCursorSizeAt( newHandlePosition ) ); + + handleVisible = IsPositionWithinControl( actualHandlePosition, + cursorSize, + controlSize ); + + if( handleVisible ) + { + StopScrollTimer(); + mCurrentHandlePosition = actualHandlePosition; + mScrollDisplacement = Vector2::ZERO; + } + else + { + + if( ( actualHandlePosition.x < SCROLL_THRESHOLD ) && ( displacement.x <= 0.f ) ) + { + mScrollDisplacement.x = -SCROLL_SPEED; + } + else if( ( actualHandlePosition.x > controlSize.width - SCROLL_THRESHOLD ) && ( displacement.x >= 0.f ) ) + { + mScrollDisplacement.x = SCROLL_SPEED; + } + if( ( actualHandlePosition.y < SCROLL_THRESHOLD ) && ( displacement.y <= 0.f ) ) + { + mScrollDisplacement.y = -SCROLL_SPEED; + } + else if( ( actualHandlePosition.y > controlSize.height - SCROLL_THRESHOLD ) && ( displacement.y >= 0.f ) ) + { + mScrollDisplacement.y = SCROLL_SPEED; + } + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveSelectionHandle Handle not visible scroll displacement [%f]\n", mScrollDisplacement.x); + + StartScrollTimer(); + } + } + + if ( handleVisible && // Ensure the handle is visible. + ( newHandlePosition != currentSelectionHandlePosition ) && // Ensure the handle has moved. + ( newHandlePosition != mSelectionHandleTwoPosition ) && // Ensure new handle position not the same position as an existing handle. + ( newHandlePosition != mSelectionHandleOnePosition ) ) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveSelectionHandle Handle visible and moved]\n"); + + currentSelectionHandlePosition = newHandlePosition; + + PositionSelectionHandle( selectionHandle, actualHandlePosition, newHandlePosition ); + + ShowUpdatedHighlight(); + + // Set Active Style to that of first character in selection + std::size_t firstHandleInSelection = std::min( mSelectionHandleOnePosition, mSelectionHandleTwoPosition ); + + const TextStyle inputStyle = mTextViewCharacterPositioning.GetStyleAt( firstHandleInSelection ); + mTextStyle.SetInputStyle( inputStyle ); + } + return actualHandlePosition; // Returns Handle position passed in if new value not assigned. +} + +/** + * GrabHandle + */ +void Decorator::PositionGrabHandle( std::size_t positionInText ) +{ + bool direction(false); + Vector3 alternatePosition; + bool alternatePositionValid(false); + + mGrabHandlePosition = positionInText; + + mTextViewCharacterPositioning.UpdateTextLayoutInfo(); + mActualGrabHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( positionInText, direction, alternatePosition,alternatePositionValid ); + + mTextInputHandles.GetGrabHandle().SetPosition( mActualGrabHandlePosition ); +} + +void Decorator::MoveGrabHandle( const Vector2& displacement /*, std::size_t currentHandlePosition */) +{ + mActualGrabHandlePosition.x += displacement.x; + mActualGrabHandlePosition.y += displacement.y; + + // Grab handle should jump to the nearest character and take cursor with it + std::size_t newHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mActualGrabHandlePosition.GetVectorXY() ); + + Vector3 actualHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandlePosition ); + + bool handleVisible = true; + + if( mTextViewCharacterPositioning.IsScrollEnabled() ) + { + const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); + const Size cursorSize( GetCursorSizeAt( newHandlePosition ) ); + // Scrolls the text if the handle is not in a visible position + handleVisible = IsPositionWithinControl( actualHandlePosition, + cursorSize, + controlSize ); + + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveGrabHandle handleVisible[%s]\n", ( handleVisible )?"true":"false"); + + if( handleVisible ) + { + StopScrollTimer(); + mCurrentHandlePosition = actualHandlePosition; + mScrollDisplacement = Vector2::ZERO; + } + else + { + if( ( actualHandlePosition.x < SCROLL_THRESHOLD ) && ( displacement.x <= 0.f ) ) + { + mScrollDisplacement.x = -SCROLL_SPEED; + } + else if( ( actualHandlePosition.x > controlSize.width - SCROLL_THRESHOLD ) && ( displacement.x >= 0.f ) ) + { + mScrollDisplacement.x = SCROLL_SPEED; + } + if( ( actualHandlePosition.y < SCROLL_THRESHOLD ) && ( displacement.y <= 0.f ) ) + { + mScrollDisplacement.y = -SCROLL_SPEED; + } + else if( ( actualHandlePosition.y > controlSize.height - SCROLL_THRESHOLD ) && ( displacement.y >= 0.f ) ) + { + mScrollDisplacement.y = SCROLL_SPEED; + } + StartScrollTimer(); + } + } + + if( ( newHandlePosition != mGrabHandlePosition ) && // Only redraw cursor and do updates if position changed + ( handleVisible ) )// and the new position is visible (if scroll is not enabled, it's always true). + { + mActualGrabHandlePosition = actualHandlePosition; + mTextInputHandles.GetGrabHandle().SetPosition( mActualGrabHandlePosition ); + + //PositionGrabHandle( newHandlePosition ); + mGrabHandlePosition = newHandlePosition; + SetCurrentCursorPosition( mGrabHandlePosition ); + DrawCursor( mGrabHandlePosition ); + + const std::size_t cursorPosition = GetCurrentCursorPosition(); + + // Let keyboard know the new cursor position so can 're-capture' for prediction. + mCursorRePositionedSignal.Emit(); + + // Set Input Style to that of cursor position + if ( !mTextViewCharacterPositioning.IsStyledTextEmpty() && ( cursorPosition > 0 ) ) + { + DALI_ASSERT_DEBUG( ( 0 <= cursorPosition-1 ) && ( cursorPosition-1 < mTextViewCharacterPositioning.StyledTextSize() ) ); + const TextStyle inputStyle = mTextViewCharacterPositioning.GetStyleAt( cursorPosition-1 ); + mTextStyle.SetInputStyle( inputStyle ); + } + } +} + +void Decorator::ShowGrabHandle( bool visible ) +{ + mGrabHandleVisibility = visible; + mTextInputHandles.SetGrabHandleVisibility( visible ); +} + +void Decorator::CreateGrabHandle( Actor targetParent ) +{ + if ( !mPanGestureDetector ) + { + mPanGestureDetector = PanGestureDetector::New(); + mPanGestureDetector.DetectedSignal().Connect(this, &Decorator::OnHandlePan); + } + + if ( !mTextInputHandles.GetGrabHandle() ) + { + mTextInputHandles.CreateGrabHandle(); + mTextInputHandles.AttachGrabHandleToGivenPanGesture( mPanGestureDetector ); + targetParent.Add( mTextInputHandles.GetGrabHandle() ); + } +} + +void Decorator::SetGrabHandleImage( Image image ) +{ + mTextInputHandles.SetGrabHandleImage( image ); +} + +void Decorator::EnableGrabHandle( bool toggle) +{ + // enables grab handle with will in turn de-activate magnifier + mGrabHandleEnabled = toggle; +} + +bool Decorator::IsGrabHandleEnabled() +{ + // if false then magnifier will be shown instead. + return mGrabHandleEnabled; +} + +/** + * Cursor + */ +std::size_t Decorator::GetCurrentCursorPosition() const +{ + return mCursorPosition; +} + +void Decorator::SetCurrentCursorPosition( std::size_t newCursorPosition ) +{ + mCursorPosition = newCursorPosition; +} + +void Decorator::SetCursorVisibility( bool visible ) +{ + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::SetCursorVisibility[%s]\n", ( visible )?"true":"false"); + + mCursorVisibility = visible; + mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea ); + mCursorRTL.SetVisible( mCursorVisibility && mCursorRTLEnabled ); +} + +void Decorator::DrawCursor(const std::size_t nthChar) +{ + std::size_t cursorPosition = GetCurrentCursorPosition(); + + // Get height of cursor and set its size + Size size( CURSOR_THICKNESS, 0.0f ); + if ( !mTextViewCharacterPositioning.IsTextEmpty() ) + { + Vector2 min, max; // out parameters for GetRowRectFromCharacterPosition + size.height = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mTextViewCharacterPositioning.GetVisualPosition( cursorPosition ), min, max ).height; + } + else + { + // Measure Font so know how big text will be if no initial text to measure. + size.height = mTextViewCharacterPositioning.GetLineHeight( nthChar ); + } + + mCursor.SetSize(size); + + // If the character is italic then the cursor also tilts. + if ( !mTextViewCharacterPositioning.IsStyledTextEmpty() && ( cursorPosition > 0 ) ) + { + DALI_ASSERT_DEBUG( ( 0 <= cursorPosition-1 ) && ( cursorPosition-1 < mTextViewCharacterPositioning.StyledTextSize() ) ); + const TextStyle styleAtCursor = mTextViewCharacterPositioning.GetStyleAt( cursorPosition-1 ); + mCursor.SetRotation( styleAtCursor.GetItalics() ? Degree( styleAtCursor.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS ); + } + + DALI_ASSERT_DEBUG( cursorPosition <= mTextViewCharacterPositioning.GetNumberOfCharactersInText() ); + if ( ( cursorPosition <= mTextViewCharacterPositioning.GetNumberOfCharactersInText() ) ) + { + Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValid( false ); // Alternate cursor validity flag. + bool directionRTL( false ); // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 position = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition, directionRTL, altPosition, altPositionValid ); + + SetAltCursorEnabled( altPositionValid ); + + if(!altPositionValid) + { + mCursor.SetPosition( position + UI_OFFSET ); + } + else + { + size.height *= 0.5f; + mCursor.SetSize(size); + mCursor.SetPosition( position + UI_OFFSET - Vector3(0.0f, directionRTL ? 0.0f : size.height, 0.0f) ); + Vector2 min, max; // out parameters for GetRowRectFromCharacterPosition + Size rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mTextViewCharacterPositioning.GetVisualPosition( cursorPosition ), min, max ); + size.height = rowSize.height * 0.5f; + mCursorRTL.SetSize(size); + mCursorRTL.SetPosition( altPosition + UI_OFFSET - Vector3(0.0f, directionRTL ? size.height : 0.0f, 0.0f) ); + } + + if( mTextViewCharacterPositioning.IsScrollEnabled() ) + { + // Whether cursor and grab handle are inside the boundaries of the text-input when text scroll is enabled. + const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); + mIsCursorInScrollArea = mIsGrabHandleInScrollArea = IsPositionWithinControl( position, size, controlSize ); + } + } +} + +void Decorator::SetAltCursorEnabled( bool enabled ) +{ + mCursorRTLEnabled = enabled; + mCursorRTL.SetVisible( mCursorVisibility && mCursorRTLEnabled ); +} + +void Decorator::SetCursorImage(Dali::Image image, const Vector4& border ) +{ + DALI_ASSERT_DEBUG ( image && "Create cursor image invalid") + + if ( image ) + { + mCursor.SetImage( image ); + mCursor.SetNinePatchBorder( border ); + } +} + +void Decorator::SetRTLCursorImage( Image image, const Vector4& border ) +{ + DALI_ASSERT_DEBUG ( image && "Create cursor image invalid") + + if ( image ) + { + mCursorRTL.SetImage( image ); + mCursorRTL.SetNinePatchBorder( border ); + } +} + +ImageActor Decorator::CreateCursor( Image cursorImage, const Vector4& border, const std::string& cursorName ) +{ + ImageActor cursor; + + if ( cursorImage ) + { + cursor = ImageActor::New( cursorImage ); + } + else + { + cursor = ImageActor::New( Image::New( DEFAULT_CURSOR ) ); + } + + cursor.SetStyle(ImageActor::STYLE_NINE_PATCH); + cursor.SetNinePatchBorder( border ); + cursor.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER); + cursor.SetVisible(false); + cursor.SetName( cursorName ); + return cursor; +} + +void Decorator::CreateCursors( Actor targetParent ) +{ + Image mCursorImage = Image::New( DEFAULT_CURSOR ); + mCursor = CreateCursor (mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER , "mainCursor"); + mCursorRTL = CreateCursor ( mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER, "rtlCursor"); + targetParent.Add( mCursor ); + targetParent.Add( mCursorRTL ); +} + +Size Decorator::GetCursorSizeAt( std::size_t positionWithinTextToGetCursorSize ) +{ + std::size_t visualPosition = mTextViewCharacterPositioning.GetVisualPosition( positionWithinTextToGetCursorSize ); + + Vector2 min, max; + + const Size cursorSize( CURSOR_THICKNESS, + mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( visualPosition, min, max ).height ); + + return cursorSize; +} + +void Decorator::StartCursorBlinkTimer() +{ + if ( !mCursorBlinkTimer ) + { + mCursorBlinkTimer = Timer::New( CURSOR_BLINK_INTERVAL ); + mCursorBlinkTimer.TickSignal().Connect( this, &Decorator::OnCursorBlinkTimerTick ); + } + + if ( !mCursorBlinkTimer.IsRunning() ) + { + mCursorBlinkTimer.Start(); + } +} + +void Decorator::StopCursorBlinkTimer() +{ + if ( mCursorBlinkTimer ) + { + mCursorBlinkTimer.Stop(); + } +} + +bool Decorator::OnCursorBlinkTimerTick() +{ + // Cursor blinking + mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea && mCursorBlinkStatus ); + if ( mCursorRTLEnabled ) + { + mCursorRTL.SetVisible( mCursorVisibility && mIsCursorInScrollArea && mCursorBlinkStatus ); + } + mCursorBlinkStatus = !mCursorBlinkStatus; + + return true; +} + +/** + * Highlight + */ +void Decorator::ShowUpdatedHighlight() +{ + Toolkit::TextView::TextLayoutInfo textLayoutInfo = mTextViewCharacterPositioning.GetLayoutInfo(); + TextHighlight::HighlightInfo highlightInfo = mTextHighlight.CalculateHighlightInfo( mSelectionHandleOnePosition, mSelectionHandleTwoPosition, textLayoutInfo ); + + // Clamp highlightInfo so they don't exceed the boundary of the control. + const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); + highlightInfo.Clamp2D( Vector2::ZERO, Vector2(controlSize.x, controlSize.y) ); + + mTextHighlight.UpdateHighlight( highlightInfo ); +} + +void Decorator::CreateHighlight( Actor parent ) +{ + DALI_ASSERT_DEBUG( parent && "Highlight target parent does not exist" ); + + if ( !mHighlightMeshActor ) + { + mHighlightMeshActor = MeshActor::New( mTextHighlight.CreateHighLightMesh() ); + mHighlightMeshActor.SetName( "HighlightMeshActor" ); + mHighlightMeshActor.SetInheritShaderEffect( false ); + mHighlightMeshActor.SetAffectedByLighting(false); + parent.Add( mHighlightMeshActor ); + } +} + +void Decorator::RemoveHighlight() +{ + if ( mHighlightMeshActor ) + { + mHighlightMeshActor.Unparent(); + mHighlightMeshActor.Reset(); + // NOTE: We cannot dereference mHighlightMesh, due to a how the scene-graph MeshRenderer uses the Mesh data. + } +} + +void Decorator::HighlightVisibility( bool visiblility ) +{ + if ( mHighlightMeshActor ) + { + mHighlightMeshActor.SetVisible( visiblility ); + } +} + +/** + * Callbacks connected to be Property notifications for Boundary checking. + */ +// Note If PropertyNotification signal definition included Actor we would not need to duplicate functions. +void Decorator::OnHandleOneLeavesBoundary( PropertyNotification& source) +{ + mTextInputHandles.GetSelectionHandleOne().SetOpacity(0.0f); +} + +void Decorator::OnHandleOneWithinBoundary(PropertyNotification& source) +{ + mTextInputHandles.GetSelectionHandleOne().SetOpacity(1.0f); +} + +void Decorator::OnHandleTwoLeavesBoundary( PropertyNotification& source) +{ + mTextInputHandles.GetSelectionHandleTwo().SetOpacity(0.0f); +} + +void Decorator::OnHandleTwoWithinBoundary(PropertyNotification& source) +{ + mTextInputHandles.GetSelectionHandleTwo().SetOpacity(1.0f); +} + +void Decorator::OnLeftBoundaryExceeded(PropertyNotification& source) +{ + DALI_LOG_INFO(gLogFilter, Debug::General, "TextInputDecorationLayouter::OnLeftBoundaryExceeded\n"); + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + selectionHandleOne.SetScale( -1.0f, 1.0f, 1.0f ); + selectionHandleOne.SetAnchorPoint( AnchorPoint::TOP_LEFT); +} + +void Decorator::OnReturnToLeftBoundary(PropertyNotification& source) +{ + DALI_LOG_INFO(gLogFilter, Debug::General, "TextInputDecorationLayouter::OnReturnToLeftBoundary\n"); + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + selectionHandleOne.SetScale( 1.0f, 1.0f, 1.0f ); + selectionHandleOne.SetAnchorPoint( AnchorPoint::TOP_RIGHT); +} + +void Decorator::OnRightBoundaryExceeded(PropertyNotification& source) +{ + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + selectionHandleTwo.SetScale( -1.0f, 1.0f, 1.0f ); + selectionHandleTwo.SetAnchorPoint( AnchorPoint::TOP_RIGHT); +} + +void Decorator::OnReturnToRightBoundary(PropertyNotification& source) +{ + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + selectionHandleTwo.SetScale( 1.0f, 1.0f, 1.0f ); + selectionHandleTwo.SetAnchorPoint( AnchorPoint::TOP_LEFT); +} + +void Decorator::SetUpHandlePropertyNotifications() +{ + /* Property notifications for handles exceeding the boundary and returning back within boundary */ + + Vector3 handlesize = GetSelectionHandleSize(); + + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + + // Exceeding horizontal boundary + PropertyNotification leftNotification = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_X, LessThanCondition( mBoundingRectangleWorldCoordinates.x + handlesize.x) ); + leftNotification.NotifySignal().Connect( this, &Decorator::OnLeftBoundaryExceeded ); + + PropertyNotification rightNotification = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_X, GreaterThanCondition( mBoundingRectangleWorldCoordinates.z - handlesize.x ) ); + rightNotification.NotifySignal().Connect( this, &Decorator::OnRightBoundaryExceeded ); + + // Within horizontal boundary + PropertyNotification leftLeaveNotification = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_X, GreaterThanCondition( mBoundingRectangleWorldCoordinates.x + 2*handlesize.x ) ); + leftLeaveNotification.NotifySignal().Connect( this, &Decorator::OnReturnToLeftBoundary ); + + PropertyNotification rightLeaveNotification = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_X, LessThanCondition( mBoundingRectangleWorldCoordinates.z - 2*handlesize.x ) ); + rightLeaveNotification.NotifySignal().Connect( this, &Decorator::OnReturnToRightBoundary ); + + // Exceeding vertical boundary + PropertyNotification verticalExceedNotificationOne = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_Y, + OutsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y, + mBoundingRectangleWorldCoordinates.w - handlesize.y ) ); + verticalExceedNotificationOne.NotifySignal().Connect( this, &Decorator::OnHandleOneLeavesBoundary ); + + PropertyNotification verticalExceedNotificationTwo = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_Y, + OutsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y, + mBoundingRectangleWorldCoordinates.w - handlesize.y ) ); + verticalExceedNotificationTwo.NotifySignal().Connect( this, &Decorator::OnHandleTwoLeavesBoundary ); + + // Within vertical boundary + PropertyNotification verticalWithinNotificationOne = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_Y, + InsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y, + mBoundingRectangleWorldCoordinates.w - handlesize.y ) ); + verticalWithinNotificationOne.NotifySignal().Connect( this, &Decorator::OnHandleOneWithinBoundary ); + + PropertyNotification verticalWithinNotificationTwo = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_Y, + InsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y, + mBoundingRectangleWorldCoordinates.w - handlesize.y ) ); + verticalWithinNotificationTwo.NotifySignal().Connect( this, &Decorator::OnHandleTwoWithinBoundary ); +} + +/** + * PopUp + */ +Vector3 Decorator::PositionOfPopUpRelativeToSelectionHandles() +{ + Vector3 position; + Vector2 min, max; + Vector3 topHandle; + Size rowSize; + + // When text is selected, show popup above top handle (and text), or below bottom handle. + + // topHandle: referring to the top most point of the handle or the top line of selection. + if ( mSelectionHandleTwoActualPosition.y > mSelectionHandleOneActualPosition.y ) + { + topHandle = mSelectionHandleOneActualPosition; + rowSize= mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mSelectionHandleOnePosition, min, max ); + } + else + { + topHandle = mSelectionHandleTwoActualPosition; + rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mSelectionHandleTwoPosition, min, max ); + } + topHandle.y += TOP_HANDLE_TOP_OFFSET - rowSize.height; + position = Vector3(topHandle.x, topHandle.y, 0.0f); + + return position; +} + +Vector3 Decorator::AlternatePopUpPositionRelativeToSelectionHandles() +{ + // alternativePosition: referring to the bottom most point of the handle or the bottom line of selection. + Vector3 alternativePosition; + alternativePosition.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y ); + alternativePosition.y += GetSelectionHandleSize().y + mPopUpPanel.GetSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET; + + return alternativePosition; +} + +Vector3 Decorator::PositionOfPopUpRelativeToCursor() +{ + // When no text is selected, show PopUp at position of cursor + Vector3 position; + Vector2 min, max; + std::size_t cursorPosition = GetCurrentCursorPosition(); + position = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition ); + const Size rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( cursorPosition, min, max ); + position.y -= rowSize.height; + + return position; +} + +Vector3 Decorator::AlternatePopUpPositionRelativeToCursor() +{ + std::size_t cursorPosition = GetCurrentCursorPosition(); + Vector3 alternativePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition ); + + if ( mTextInputHandles.GetGrabHandle() ) + { + // If grab handle enabled then position pop-up below the grab handle. + alternativePosition.y += mTextInputHandles.GetGrabHandle().GetCurrentSize().height + mPopUpPanel.GetSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET ; + } + else + { + alternativePosition.y += mPopUpPanel.GetSize().y; + } + + return alternativePosition; + +} + +Vector3 Decorator::PositionOfPopUpRelativeToGrabHandle() +{ + return Vector3::ZERO; +} + +void Decorator::ShowPopUp() +{ + Vector3 position; + Vector3 alternativePosition; + Size rowSize; + + DALI_ASSERT_DEBUG( mPopUpTarget && "PopUp Target Actor does not exist" ); + + if( mHighlightMeshActor ) // Text Selection mode + { + position = PositionOfPopUpRelativeToSelectionHandles(); + } + else // Not in Text Selection mode so position relative to cursor. + { + position = PositionOfPopUpRelativeToCursor(); + } + + // reposition popup above the desired cursor position. + mPopUpPanel.Show( mPopUpTarget, true ); + mPopUpPanel.Self().SetPosition( position ); + mPopUpPanel.PressedSignal().Connect( this, &Decorator::OnPopupButtonPressed ); + + SetUpPopUpPositionNotifications(); + mPopUpPanel.ApplyConfinementConstraint( mBoundingRectangleWorldCoordinates ); +} + +void Decorator::ShowPopUp( Actor target ) +{ + mPopUpTarget = target; + ShowPopupCutCopyPaste(); +} + +void Decorator::ShowPopupCutCopyPaste() +{ + bool isAllTextSelectedAlready = ( mTextViewCharacterPositioning.StyledTextSize() == GetSelectedText().size() ); + bool isTextEmpty = mTextViewCharacterPositioning.IsStyledTextEmpty() ; + bool isSubsetOfTextAlreadySelected = ( !isAllTextSelectedAlready ) && mHighlightMeshActor; + + Clipboard clipboard = Clipboard::Get(); + bool hasClipboardGotContent = clipboard.NumberOfItems(); + + mPopUpPanel.CreateCutCopyPastePopUp( isAllTextSelectedAlready, isTextEmpty, hasClipboardGotContent, isSubsetOfTextAlreadySelected ); + ShowPopUp(); +} + +void Decorator::HidePopUp( bool animate, bool signalFinished ) +{ + if ( ( mPopUpPanel.GetState() == TextInputPopupNew::StateShowing ) || ( mPopUpPanel.GetState() == TextInputPopupNew::StateShown ) ) + { + mPopUpPanel.Hide( animate ); + } +} + +void Decorator::AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption) +{ + mPopUpPanel.AddButton(name, caption, icon, finalOption); +} + +void Decorator::ClearPopup() +{ + mPopUpPanel.Clear(); +} + +void Decorator::PopUpLeavesVerticalBoundary( PropertyNotification& source) +{ + Vector3 position, alternativePosition; + + if( mHighlightMeshActor ) // Text Selection mode + { + alternativePosition = AlternatePopUpPositionRelativeToSelectionHandles(); + } + else // Not in Text Selection mode + { + alternativePosition = AlternatePopUpPositionRelativeToCursor(); + // if can't be positioned above, then position below row. + } + // reposition popup above the desired cursor position. + mPopUpPanel.Self().SetPosition( alternativePosition ); +} + +void Decorator::SetUpPopUpPositionNotifications( ) +{ + // Note Property notifications ignore any set anchor point so conditions must allow for this. Default is Top Left. + + // Exceeding vertical boundary + PropertyNotification verticalExceedNotificationOne = mPopUpPanel.Self().AddPropertyNotification( Actor::WORLD_POSITION_Y, + OutsideCondition( mBoundingRectangleWorldCoordinates.y + mPopUpPanel.GetSize().y/2, + mBoundingRectangleWorldCoordinates.w - mPopUpPanel.GetSize().y/2 ) ); + verticalExceedNotificationOne.NotifySignal().Connect( this, &Decorator::PopUpLeavesVerticalBoundary ); +} + +bool Decorator::OnPopupButtonPressed( Toolkit::Button button ) +{ + mPopUpButtonPressedSignal.Emit( button ); + return false; +} + +Decorator::PressedSignal& Decorator::PopUpButtonPressedSignal() +{ + return mPopUpButtonPressedSignal; +} + +Decorator::CursorPositionedSignal& Decorator::CursorRePositionedSignal() +{ + return mCursorRePositionedSignal; +} + +/** + * Decoration Positioning during Scrolling + */ +void Decorator::TextViewScrolled( Toolkit::TextView textView, Vector2 scrollPosition ) +{ + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::TextViewScrolled\n"); + + const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); // todo Could store size and only update in Control Size change. + Size cursorSize( CURSOR_THICKNESS, 0.f ); + + // Updates the cursor and grab handle position and visibility. + if( mTextInputHandles.GetGrabHandle() || mCursor ) + { + Vector2 min, max; + size_t cursorTextPosition = GetCurrentCursorPosition(); + cursorSize.height = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( cursorTextPosition, min, max ).height; + + const Vector3 cursorPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorTextPosition ); + + bool mIsCursorInScrollArea = IsPositionWithinControl( cursorPosition, cursorSize, controlSize ); + bool mIsGrabHandleInScrollArea = mIsCursorInScrollArea; + + Vector2 actualGrabHandlePosition = cursorPosition.GetVectorXY(); + + if( mTextInputHandles.GetGrabHandle() ) + { + ShowGrabHandle( mGrabHandleVisibility && mIsGrabHandleInScrollArea ); + PositionGrabHandle( cursorTextPosition ); + } + + if( mCursor ) + { + mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea ); + DrawCursor( cursorTextPosition ); + mCursor.SetPosition( Vector3(actualGrabHandlePosition) + UI_OFFSET ); + } + } + + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + + // Updates the selection handles and highlighted text position and visibility. + if( mTextInputHandles.GetSelectionHandleOne() && mTextInputHandles.GetSelectionHandleTwo() ) + { + const Vector3 cursorPositionOne = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition ); + const Vector3 cursorPositionTwo = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition ); + + Size cursorSize( GetCursorSizeAt( mSelectionHandleOnePosition ) ); + const bool isSelectionHandleOneVisible = IsPositionWithinControl( cursorPositionOne, cursorSize, controlSize ); + + cursorSize = GetCursorSizeAt( mSelectionHandleTwoPosition ); + const bool isSelectionHandleTwoVisible = IsPositionWithinControl( cursorPositionTwo, cursorSize, controlSize ); + + mSelectionHandleOneActualPosition = cursorPositionOne.GetVectorXY(); + mSelectionHandleTwoActualPosition = cursorPositionTwo.GetVectorXY(); + + selectionHandleOne.SetVisible( isSelectionHandleOneVisible ); + selectionHandleTwo.SetVisible( isSelectionHandleTwoVisible ); + + PositionSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition ); + PositionSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition ); + + if( mHighlightMeshActor ) + { + mHighlightMeshActor.SetVisible( true ); + ShowUpdatedHighlight(); + } + } +} + +void Decorator::StartScrollTimer() +{ + if( !mScrollTimer ) + { + mScrollTimer = Timer::New( SCROLL_TICK_INTERVAL ); + mScrollTimer.TickSignal().Connect( this, &Decorator::OnScrollTimerTick ); + } + + if( !mScrollTimer.IsRunning() ) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::StartScrollTimer\n"); + mScrollTimer.Start(); + } +} + +void Decorator::StopScrollTimer() +{ + if( mScrollTimer ) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::StopScrollTimer\n"); + + mScrollTimer.Stop(); + mScrollTimer.Reset(); + } +} + +bool Decorator::OnScrollTimerTick() +{ + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::OnScrollTimerTick\n"); + + if ( mGrabHandleVisibility && mTextInputHandles.GetGrabHandle() ) + { + std::size_t newGrabHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mActualGrabHandlePosition.GetVectorXY() ); + if ( mGrabHandlePosition != newGrabHandlePosition ) + { + Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition(); + Vector2 scrollDelta = ( mActualGrabHandlePosition - mCurrentHandlePosition ).GetVectorXY(); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::OnScrollTimerTick scrollPosition(%f) scrollDelta(%f)\n", scrollPosition.x, scrollDelta.x); + scrollPosition += scrollDelta; + mTextViewCharacterPositioning.SetScrollPosition( scrollPosition ); + + // If scroll position goes too far TextView will trim it to fit. + if ( mTextViewCharacterPositioning.IsScrollPositionTrimmed() ) + { + StopScrollTimer(); + } + + mActualGrabHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newGrabHandlePosition ).GetVectorXY(); + } + } + + Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne(); + Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo(); + + if ( selectionHandleOne && selectionHandleTwo ) + { + std::size_t newHandleOnePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mSelectionHandleOneActualPosition.GetVectorXY() ); + + // todo duplicated code should be a function + + if ( mSelectionHandleOnePosition != newHandleOnePosition ) + { + const Vector3 actualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandleOnePosition ); + + Vector2 scrollDelta = ( actualPosition - mSelectionHandleOneActualPosition ).GetVectorXY(); + + Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition(); + scrollPosition += scrollDelta; + mTextViewCharacterPositioning.SetScrollPosition( scrollPosition ); + + if( mTextViewCharacterPositioning.IsScrollPositionTrimmed() ) + { + StopScrollTimer(); + } + + mSelectionHandleOnePosition = newHandleOnePosition; + mSelectionHandleOneActualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition ).GetVectorXY(); + } + else + { + mSelectionHandleOneActualPosition.x += mScrollDisplacement.x; + mSelectionHandleOneActualPosition.y += mScrollDisplacement.y; + } + + std::size_t newHandleTwoPosition = mTextViewCharacterPositioning.ReturnClosestIndex( mSelectionHandleTwoActualPosition.GetVectorXY() ); + + if ( mSelectionHandleTwoPosition != newHandleTwoPosition ) + { + const Vector3 actualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandleTwoPosition ); + + Vector2 scrollDelta = ( actualPosition - mSelectionHandleTwoActualPosition ).GetVectorXY(); + + Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition(); + scrollPosition += scrollDelta; + mTextViewCharacterPositioning.SetScrollPosition( scrollPosition ); + + if( mTextViewCharacterPositioning.IsScrollPositionTrimmed() ) + { + StopScrollTimer(); + } + + mSelectionHandleTwoPosition = newHandleTwoPosition; + mCurrentHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition ).GetVectorXY(); + + } + else + { + mSelectionHandleTwoActualPosition.x += mScrollDisplacement.x; + mSelectionHandleTwoActualPosition.y += mScrollDisplacement.y; + } + } + + return true; +} + +/** + * Text Selection + */ +MarkupProcessor::StyledTextArray Decorator::GetSelectedText() +{ + MarkupProcessor::StyledTextArray currentSelectedText; + + if ( mHighlightMeshActor ) // Text Selected + { + MarkupProcessor::StyledTextArray::iterator it = mTextViewCharacterPositioning.GetStyledTextArray().begin() + std::min(mSelectionHandleOnePosition, mSelectionHandleTwoPosition); + MarkupProcessor::StyledTextArray::iterator end = mTextViewCharacterPositioning.GetStyledTextArray().begin() + std::max(mSelectionHandleOnePosition, mSelectionHandleTwoPosition); + + for(; it != end; ++it) + { + MarkupProcessor::StyledText& styledText( *it ); + currentSelectedText.push_back( styledText ); + } + } + return currentSelectedText; +} + +} // Internal + +} // namespace Toolkit + +} // namespace Dali + diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.h b/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.h new file mode 100644 index 0000000..087cde3 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-decorator-impl.h @@ -0,0 +1,635 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_DECORATOR_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_DECORATOR_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include + +// INTERNAL INCLUDES + +#include +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class Decorator; + +typedef IntrusivePtr DecoratorPtr; + +/** + * @brief Decorator Class + * + * Decorations are Selection Handles, cursor, grab handle, magnifier the "cut copy paste" PopUp and Selection highlight. + * The Decorator triggers creation of these decorations and positions them. + * Decoration positions can be dependent on other decorations like the PopUp on the Selection handles. + * The decorator maintains a Bounding Box which the decorations have to be positioned within, decorations can be flipped or hidden to obey this Bounding Box. + * Scrolling of Text can effect positioning of decorations, the decorator repositions decorations in this case. + */ + +class Decorator : public ConnectionTracker +{ + +public: + + /** + * @brief Constructor + * + * @param[in] textviewManager TextViewManager to be used + */ + Decorator( TextViewCharacterPositioning& textviewManager, TextInputTextStyle& textStyle); + + /** + * @brief Default destructor + */ + ~Decorator(); + + /** + * @brief Set the dimensions of the bounding rectangle for decorations to obey. + * + * @param[in] boundingRectangle + */ + void SetBoundingBox( const Rect& boundingRectangle ); + + /** + * @brief Get the bounding dimensions of the bounding box + * + * @return dimensions of the bounding box from world origin. (x, y, w, z ) + * + * ----------------- + * | ^ | + * | | | + * | y | + * | | | + * | v | + * |<--x--> o <--z-->| + * | ^ | + * | | | + * | w | + * | | | + * | v | + * ----------------- + */ + Vector4 GetBoundingBox() const; + + /** + * @brief Callback when a handle is panned/moved, either selection handles or grab handle + * + * @param actor Handle of the selection or grab handle. + * @param gesture Data structure with the parameters of the gesture. + */ + void OnHandlePan(Actor actor, PanGesture gesture); + + // Selection Handles + + /** + * @brief Create a left and right selection handle and parent both to the provided actor + * @param[in] parent actor in which the handles should be added to. + */ + void CreateSelectionHandles( Actor parent ); + + /** + * @brief Remove selection handles from their parent + */ + void RemoveSelectionHandles(); + + /** + * @brief Get size of Selection handles + * + * @return size of a selection handle + */ + Vector3 GetSelectionHandleSize(); + + /** + * @brief Get position of Selection handle within text + * + * @return character position of a selection handle one + */ + std::size_t GetHandleOnePosition() const; + + /** + * @brief Get position of Selection handle within text + * + * @return character position of a selection handle two + */ + std::size_t GetHandleTwoPosition() const; + + /** + * @brief Position Selection a single handle at given positions within the text string. + * + * @param[in] selectionHandle handle to be positioned + * @param[in] position where to place handle + * @return Vector3 Position of handle as a coordinate. + */ + Vector3 PositionSelectionHandle( Actor selectionHandle, std::size_t position ); + + /** + * @brief Position Selection a single handle at given coordinates + * + * @param[in] selectionHandle handle to be positioned + * @param[in] actualPosition coordinates to position handle + * @param[in] position where to place handle + * @return Vector3 Position of handle as a coordinate. + */ + Vector3 PositionSelectionHandle( Actor selectionHandle, Vector3& actualPosition, std::size_t position ); + + /** + * @brief Make both selection handle visible or invisible + * @param[in] visible true to make visible, false to fine + */ + void SetSelectionHandlesVisibility( bool visible ); + + /** + * @brief Callback for when a handle is released + * @return bool + */ + bool OnHandleReleased(); + + /** + * @brief Position Selection handles at given positions within the text string. + * + * @param[in] start where to place first handle + * @param[in] end where to place second handle + */ + void PositionSelectionHandles( std::size_t start, std::size_t end ); + + /** + * @brief Move selection handle by the given displacement. + * + * @param[in] selectionHandle Actor to move + * @param[in] actualSelectionHandlePosition actual current position of the handle in x y z + * @param[in] currentSelectionHandlePosition current position along the string + * @param[in] displacement the x y displacement + */ + Vector3 MoveSelectionHandle( Actor selectionHandle, + Vector3& actualSelectionHandlePosition, + std::size_t& currentSelectionHandlePosition, + const Vector2& displacement ); + + /* Grab Handle */ + + /** + * @brief Position GrabHandlewith depending on the the character in the text it should be placed at + * @param[in] positonInText the character position within the text the handle should be at + */ + void PositionGrabHandle( std::size_t positionInText ); + + /** + * @brief Move grab handle to the required position within the text + * + * @param[in] displacement Displacement of the grab handle in actor coordinates. + */ + void MoveGrabHandle( const Vector2& displacement ); + + /** + * @brief Show or hide the GrabHandle is visibility is true + * + * @param[in] visible flag to show or not show the grab handle + */ + void ShowGrabHandle( bool visible ); + + /** + * @brief Create the GrabHandle used to position cursor + * @param[in] targetParent the Actor to parent the GrabHandle + */ + void CreateGrabHandle( Actor targetParent ); + + /** + * @brief Set the image to be used as the cursor grab hander + * @pre The text input actor has been initialised. + * @param[in] image The image to be used. + */ + void SetGrabHandleImage( Image image ); + + /** + * @brief Toggle to enable the grab handle, used to position cursor when magnifier not being used. + * Default behaviour is to use the magnifier to position the cursor, enabling this prevents the magnifier from being shown. + * @param[in] toggle true to enable, false to disable grab handle + */ + void EnableGrabHandle(bool toggle); + + /** + * @brief Method to check if grab handle is enabled, if false then the magnifier will be used to position cursor. + * @return bool returns true is grab handle enabled. + */ + bool IsGrabHandleEnabled(); + + /* Cursor */ + + /** + * @brief Get the current Cursor position + * @return current cursor position + */ + std::size_t GetCurrentCursorPosition() const; + + /** + * @brief Set the Cursor position + * @param[in] the position the cursor should be set to + */ + void SetCurrentCursorPosition( std::size_t newCursorPosition ); + + /** + * @brief Set if the cursors are visible or not. + * @param[in] visible flag true for visible + */ + void SetCursorVisibility( bool visible ); + + /** + * @brief Display cursor + * @param[in] nthChar position in text string to display cursor + */ + void DrawCursor( const std::size_t nthChar = 0 ); + + /** + * Sets alternate cursor enable state + * @see SetCursorVisibility + * alternate cursor will only be visible if both SetCursorVisiblity + * and cursor enabled have been set to true. + */ + void SetAltCursorEnabled( bool enabled ); + + /** + * @brief Set the image to be used for the regular left to right cursor + * @pre The text input actor has been initialised. + * @param[in] image The image to be used. + * @param[in] border The nine patch border for the image. + */ + void SetCursorImage( Image image, const Vector4& border ); + + /** + * @brief Set the image to be used for the Right to Left cursor + * @pre The text input actor has been initialised. + * @param[in] image The image to be used. + * @param[in] border The nine patch border for the image. + */ + void SetRTLCursorImage( Image image, const Vector4& border ); + + /** + * @brief Creates a cursor from the supplied image and nine patch border. + * @param[in] cursorImage the image to be used for the cursor. + * @param[in] border the nine patch border corresponding to the supplied image. + * @paran[in] cursorName actor name for cursor + * @return the image actor to be used as the cursor. + */ + ImageActor CreateCursor( Image cursorImage, const Vector4& border, const std::string& cursorName ); + + /** + * @brief Creates a regular and Right-To-Left cursor and parents them to give target Actor + * @param[in] targetParent target Actor + */ + void CreateCursors( Actor targetParent ); + + /** + * @Brief Returns the cursor size at a given position in the text. + * @return Size the size of the cursor + */ + Size GetCursorSizeAt( std::size_t positionWithinTextToGetCursorSize ); + + /** + * @brief Start a timer to signal cursor to blink. + */ + void StartCursorBlinkTimer(); + + /** + * @brief Stop the timer signalling the cursor to blink. + */ + void StopCursorBlinkTimer(); + + /** + * @brief Callback when handle timer ticks. + * + * Cursor should become visible/invisible to simulate blinking. + * + * @return True if the timer should be keep running. + */ + bool OnCursorBlinkTimerTick(); + + /* Selection Highlight */ + + /** + * @brief Updates mesh data for selection highlight depending on handle positions and displays it. + */ + void ShowUpdatedHighlight(); + + /** + * @brief Creates the Highlight used for selection + * + * @param[in] parent target actor in which the handles should be added to. + */ + void CreateHighlight( Actor parent ); + + /** + * @brief Remove Highlight actor from it's parent + */ + void RemoveHighlight(); + + /** + * @brief Set the visibility of the Highlight + * + * @param[in] visibility True to show and False to hide. + */ + void HighlightVisibility( bool visiblility ); + + /* Boundary Property Notifications when handle exceed bounding box*/ + + /** + * @brief PropertyNotification Callback when left boundary exceeded so handle can be flipped. + * + * @param[in] source PropertyNotification + */ + void OnLeftBoundaryExceeded( PropertyNotification& source ); + /** + * @brief PropertyNotification Callback when within left boundary so handle can be flipped back. + * + * @param[in] source PropertyNotification + */ + void OnReturnToLeftBoundary( PropertyNotification& source ); + /** + * @brief PropertyNotification Callback when right boundary exceeded so handle can be flipped. + * + * @param[in] source PropertyNotification + */ + void OnRightBoundaryExceeded( PropertyNotification& source ); + /** + * @brief PropertyNotification Callback when within right boundary so handle can be flipped back. + * + * @param[in] source PropertyNotification + */ + void OnReturnToRightBoundary( PropertyNotification& source ); + + /** + * @brief PropertyNotification Callbacks for hiding handle one when it exceeds boundary. + * + * @param[in] source PropertyNotification + */ + void OnHandleOneLeavesBoundary( PropertyNotification& source ); + /** + * @brief PropertyNotification Callbacks for showing hidden handle one when returns within boundary + * + * @param[in] source PropertyNotification + */ + void OnHandleOneWithinBoundary( PropertyNotification& source ); + /** + * @brief PropertyNotification Callbacks for hiding handle two it when exceeds boundary. + * + * @param[in] source PropertyNotification + */ + void OnHandleTwoLeavesBoundary( PropertyNotification& source ); + /** + * @brief PropertyNotification Callbacks for showing hidden handle two when returns within boundary + * + * @param[in] source PropertyNotification + */ + void OnHandleTwoWithinBoundary( PropertyNotification& source ); + + /** + * @brief Set up property notifications on the position of the handles to facilitate flipping and hiding when at screen boundary. + */ + void SetUpHandlePropertyNotifications(); + + // Cut & Paste Pop-up + + /** + * @brief Calculate positioning of PopUp relative to handles + * @return Actual position of PopUp + */ + Vector3 PositionOfPopUpRelativeToSelectionHandles( ); + + /** + * @brief Calculate alternative position of PopUp relative to handles when can it not be displayed in the default upper position. + * @return Actual position of PopUp + */ + Vector3 AlternatePopUpPositionRelativeToSelectionHandles(); + + /** + * @brief Calculate positioning of PopUp relative to cursor + * @return Actual position of PopUp + */ + Vector3 PositionOfPopUpRelativeToCursor(); + + /** + * @brief Calculate alternative position of PopUp relative to cursor when can not be displayed in normal upper position. + * @return Actual position of PopUp + */ + Vector3 AlternatePopUpPositionRelativeToCursor(); + + /** + * @brief Calculate positioning of PopUp relative to GrabHandle + * @return Actual position of PopUp + */ + Vector3 PositionOfPopUpRelativeToGrabHandle(); + + /** + * @brief Show the PopUp in the provided target + * @param[in] target target actor in which the PopUp should be added to. + */ + void ShowPopUp( Actor target ); + + /** + * @brief Show PopUp in previously set Target. + * @pre Must have previously called ShopPopUp( Actor target ) otherwise PopUp will not be shown. + */ + void ShowPopUp(); + + /** + * @brief Create and Show Cut Copy Paste PopUp + */ + void ShowPopupCutCopyPaste(); + + /** + * @brief Hide PopUp + * @param[in] animate Animate or just hide instantly, default is true + * @param[in] signalFinished Signal when finished, default is true + */ + void HidePopUp( bool animate=true, bool signalFinished=true ); + + /** + * @brief Adds a popup option. + * @brief Creates popup frame if not already created. + * @param[in] name The unique name for this option. + * @param[in] caption The caption (label) for this option + * @param[in] icon the image icon to be displayed for this option + * @param[in] finalOption Flag to indicate that this is the final option. + * (set to true on the last option you add) + */ + void AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption = false); + + /** + * @brief Removes popup, and its options. + */ + void ClearPopup(); + + /** + * @brief PropertyNotification Callbacks for flipping PopUp when exceeds boundary. + * @param[in] source PropertyNotification + */ + void PopUpLeavesVerticalBoundary( PropertyNotification& source ); + + /** + * @brief Setup position notifications when PopUp exceeds boundary + */ + void SetUpPopUpPositionNotifications( ); + + /** + * @brief Callback for when a button is pressed in popup panel + * @param[in] button handle to the button pressed. + * @return bool consummation + */ + bool OnPopupButtonPressed( Toolkit::Button button ); + + // Decoration positioning during scrolling + + /** + * @brief Updates the position of the decorations when Text is scrolled. + * + * @param[in] textView Handle of the text-view. + * @param[in] scrollPosition The difference with the previous scroll position. + */ + void TextViewScrolled( Toolkit::TextView textView, Vector2 scrollPosition ); + + /** + * @brief Creates and starts a timer to scroll the text when handles are close to the edges of the text-input. + * + * It only starts the timer if it's already created. + */ + void StartScrollTimer(); + + /** + * @brief Stops the timer used to scroll the text. + */ + void StopScrollTimer(); + + /** + * @brief Scroll Text according to handle position + * @param[in out] handlePosition handle position within character string + * @param[in] actual vector position of handle + * @return updated actual vector position of handle + */ + Vector3 ScrollRelativeToHandle( std::size_t& handlePosition, Vector3& actualHandlePosition ); + + /** + * @brief Callback called by the timer used to scroll the text. + * + * It calculates and sets a new scroll position. + */ + bool OnScrollTimerTick(); + + // Text Selection + + /** + * @brief Function to get Text selected between the 2 selection handles. + * @return StyledTextArray an array of + */ + MarkupProcessor::StyledTextArray GetSelectedText(); + +private: + + /** + * @brief Copy Constructor + * @param[in] decorator + * Undefined/Hidden. + */ + Decorator(const Decorator& decorator); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined/Hidden. + */ + Decorator& operator=(const Decorator& rhs); + +public: + + typedef SignalV2< bool( Toolkit::Button ) > PressedSignal; + typedef SignalV2< void () > CursorPositionedSignal; + /** + * @brief Signal emitted when the button is touched. + * This is relayed from the PopUp class. It enables the owner of the Decorator to act on the PopUp button press. + */ + PressedSignal& PopUpButtonPressedSignal(); + + /** + * @brief Signal emitted when the cursor is repositioned + * @param[in] cursor the new cursor position + */ + CursorPositionedSignal& CursorRePositionedSignal(); + +private: + + Vector4 mBoundingRectangleWorldCoordinates; + + TextViewCharacterPositioning& mTextViewCharacterPositioning; + + TextInputHandles mTextInputHandles; + + TextInputTextStyle& mTextStyle; + + Vector3 mSelectionHandleOneActualPosition; // Actual x y position of handle + Vector3 mSelectionHandleTwoActualPosition; // Actual x y position of handle + std::size_t mSelectionHandleOnePosition; // Position of handle along the string of text + std::size_t mSelectionHandleTwoPosition; // Position of handle along the string of text + + TextInputPopupNew mPopUpPanel; // PopUp used for Cut Cpoy and Paste + Actor mPopUpTarget; // Target Actor to parent PopUp + + Vector3 mActualGrabHandlePosition; // Actual position of grab handle, this might not be snapped to a character + std::size_t mGrabHandlePosition; // Position of grab handle along the string of text + Vector3 mCurrentHandlePosition; + + std::size_t mCursorPosition; // Current cursor position within the text string + ImageActor mCursor; // Cursor overlayed on Text to show where new text will be inserted + ImageActor mCursorRTL; // Right To Left Cursor overlayed on Text (where new RTL text would be inserted) + Animation mCursorAnimation; // Animation for cursor blinking. + Timer mCursorBlinkTimer; // Timer to signal cursor to blink + + Vector2 mScrollDisplacement; // How much to scroll by + Timer mScrollTimer; // Timer to scroll text over a period of time not all in one update. + + TextHighlight mTextHighlight; // Holds data required to construct the highlight + MeshActor mHighlightMeshActor; // Mesh Actor to display highlight + + PanGestureDetector mPanGestureDetector; + + PressedSignal mPopUpButtonPressedSignal; // Signal emitted when a button within the popup is pressed. + CursorPositionedSignal mCursorRePositionedSignal; // Signal emitted when a button when cursor position is changed. + + bool mCursorBlinkStatus:1; // \e true shows the cursor, \e false hides it. + bool mCursorVisibility:1; // Should cursor be visible + bool mCursorRTLEnabled:1; // Enable state of Alternate RTL Cursor (need to keep track of this as it's not always enabled) + bool mIsGrabHandleInScrollArea:1; // Whether the grab handle is inside the boundaries of the text-input. + bool mIsCursorInScrollArea:1; // Whether the cursor is inside the boundaries of the text-input. + bool mGrabHandleVisibility:1; // Should grab handle be visible + bool mGrabHandleEnabled:1; // Flag to enable the grab handle instead of the default magnifier. +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_DECORATOR_H__ + + diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-handles-impl.h b/base/dali-toolkit/internal/controls/text-input/text-input-handles-impl.h new file mode 100644 index 0000000..3686466 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-handles-impl.h @@ -0,0 +1,203 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_HANDLES_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_HANDLES_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ +/** + * Class to create handles and alter their visualisation. + * Not responsible for positioning. + */ + +class TextInputHandles : public ConnectionTracker +{ + +public: + + typedef SignalV2< bool () > HandlesReleasedSignal; + + /** + * Signal emitted when a handle is released + */ + HandlesReleasedSignal& ReleasedSignal(){ return mReleasedSignal; }; + + /** + * Default constructor + */ + TextInputHandles() {} + + /** + * Destructor + */ + ~TextInputHandles() {}; + + /** + * Create the selection handles + */ + void CreateSelectionHandles(){}; + + /** + * Un-parents the Selection Handles and resets their Image Actors + */ + void DestorySelectionHandles(){}; + + /** + * Set the Actor visibility on Selection Handle One + * @param[in] visibility visibility flag + */ + void SetSelectionHandleOneVisibility( bool visibility ){}; + + /** + * Set the Actor visibility on Selection Handle Two + * @param[in] visibility visibility flag + */ + void SetSelectionHandleTwoVisibility( bool visibility ){}; + + /** + * Attach the two selection handles to the pan gesture detector + * @param[in] panGestureDetector the PanGestureDetector to attach to + */ + void AttachSelectionHandlesToGivenPanGesture(PanGestureDetector& panGestureDetector ){}; + + /** + * Attach the two selection handles to the tap gesture detector + * @param[in] tapGestureDetector the TapGestureDetector to attach to + */ + void AttachSelectionHandlesToGivenTapDetector(TapGestureDetector& tapGestureDetector ){}; + + /** + * Attach the grab handle to the pan gesture detector + * @param[in] panGestureDetector the PanGestureDetector to attach to + */ + void AttachGrabHandleToGivenPanGesture( PanGestureDetector& panGestureDetector ){}; + + /** + * Get Selection handle one + * @return selection handle actor + */ + Actor GetSelectionHandleOne() { return Actor(); }; + + /** + * Get Selection handle two + * @return selection handle actor + */ + Actor GetSelectionHandleTwo() { return Actor(); }; + + /** + * Get the grab handle + * @return grab handle Actor + */ + Actor GetGrabHandle() { return Actor(); }; + + /** + * Create the grab handle that positions the cursor + * @param[in] image the image to be used. + */ + void CreateGrabHandle(){}; + + /** + * Removes and Resets GrabHandle + */ + void DestoryGrabHandle(){}; + + /** + * Set the image to be used as the cursor grab hander + * @pre The text input actor has been initialised. + * @param[in] image The image to be used. + */ + void SetGrabHandleImage( Dali::Image image ){}; + + /** + * Set the Actor visibility on the GrabHandle + * @param[in] visibility visibility flag + */ + void SetGrabHandleVisibility( bool visibility ){}; + + /* Touch Event Callbacks */ + + /** + * Callback on selection handle touched. + * Sets the image depending if handle in pressed or normal state + * @param[in] actor touched + * @param[in] touch touch event, used to determine if down or up event + */ + bool OnSelectionHandleTouched(Dali::Actor actor, const TouchEvent& touch){ return true; }; + +private: + + /** + * @brief Copy Constructor + * @param[in] handles + * Undefined/Hidden. + */ + TextInputHandles(const TextInputHandles& handles); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined/Hidden. + */ + TextInputHandles& operator=(const TextInputHandles& rhs); + +private: + + ImageActor mSelectionHandleOne; // First selection handle used for selecting text to cut&paste + ImageActor mSelectionHandleTwo; // Second selection handle used for selecting text to cut&paste + Actor mHandleOneGrabArea; // Invisible actor that receives pans events for the selection handle. + Actor mHandleTwoGrabArea; // Invisible actor that receives pans events for the selection handle. + + Image mSelectionHandleOneImage; // image used for selection handle one + Image mSelectionHandleOneImagePressed; // image used for selection handle one pressed state + Image mSelectionHandleTwoImage; // image used for selection handle two + Image mSelectionHandleTwoImagePressed; // image used for selection handle two pressed state + + Vector3 mSelectionHandleOneOffset; // Handle One's Offset + Vector3 mSelectionHandleTwoOffset; // Handle Two's Offset + Vector3 mSelectionHandleOneCoordinatePosition; // Actual x y z position of handle + Vector3 mSelectionHandleTwoCoordinatePosition; // Actual x y z position of handle + std::size_t mSelectionHandleOneStringPosition; // Position of handle along the string of text + std::size_t mSelectionHandleTwoStringPosition; // Position of handle along the string of text + + Image mGrabHandleImage; // Image to be used for grab handle + ImageActor mGrabHandle; // Handle used to move cursor for editing + Actor mGrabHandleGrabArea; // invisible actor that receives pans events for the grab handle. + + HandlesReleasedSignal mReleasedSignal; // Signal emitted when a handle is released + + bool mIsSelectionHandleOneFlipped:1; // Flag to know whether the handle one is flipped or not. + bool mIsSelectionHandleTwoFlipped:1; // Flag to know whether the handle two is flipped or not. +}; + + +} // namespace Internal + + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_HANDLES_H__ diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-popup-new-impl.h b/base/dali-toolkit/internal/controls/text-input/text-input-popup-new-impl.h new file mode 100644 index 0000000..a3b5d4d --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-popup-new-impl.h @@ -0,0 +1,274 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_POPUP_NEW_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_POPUP_NEW_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// INTERNAL INCLUDES +#include + +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +/** + * @brief Class to create and Popup bar made up of buttons. + * It provides signals when a button is pressed. + * The Popup must be positioned by it's owner. + * The future plan is to reuse the Toolkit Popup control to house the buttons. + */ + +class TextInputPopupNew : public ConnectionTracker +{ + +public: + + enum State + { + StateHidden, + StateHiding, + StateShowing, + StateShown + }; + + // Signal names + static const char* const SIGNAL_PRESSED; + static const char* const SIGNAL_HIDE_FINISHED; + static const char* const SIGNAL_SHOW_FINISHED; + + // Popup Button Pressed + typedef SignalV2< bool( Toolkit::Button ) > PopUpPressedSignal; + + // Popup Hide Finished + typedef SignalV2< void( TextInputPopupNew& ) > PopUpHideFinishedSignal; + + // Popup Show Finished + typedef SignalV2< void( TextInputPopupNew& ) > PopUpShowFinishedSignal; + + /** + * Signal emitted when the button is touched. + */ + PopUpPressedSignal& PressedSignal() { return mPressedSignal; } + + /** + * Signal emitted when popup is completely hidden + * @note Only occurs after a Show() call with animation enabled. + */ + PopUpHideFinishedSignal& HideFinishedSignal() {return mHideFinishedSignal;} + + /** + * Signal emitted when popup is completely shown + * @note Only occurs after a Hide() call with animation enabled. + */ + PopUpShowFinishedSignal& ShowFinishedSignal() {return mShowFinishedSignal;} + +public: + + /** + * Default constructor + * Creates an empty popup base actor (no content i.e. invisible) + */ + TextInputPopupNew(){}; + + /** + * Destructor + */ + ~TextInputPopupNew(){}; + + /** + * @return The root actor of for this popup is returned. + */ + Actor Self() { return mRootActor; }; + + /** + * Clears popup options (popup no longer exists) + */ + void Clear(){}; + + /** + * Create the label + * @param[in] styledCaption The text to be displayed + * @return the newly created label + */ + Toolkit::TextView CreateLabel( const MarkupProcessor::StyledTextArray& styledCaption ){return Toolkit::TextView();}; + + /** + * Create the label + * @param[in] iconImage the image to be used + * @return the newly created Image actor to be used as the icon + */ + ImageActor CreateIcon( Image iconImage ) {return ImageActor();}; + + /** + * Creates and sets up the popup background + */ + void CreatePopUpBackground(){}; + + /** + * Create divider if multiple options + */ + void CreateDivider(){}; + + /** + * Create a background to be used when button pressed + * @param[in] requiredSize size Image actor should be + * @param[in] finalFlag flag to be set if option is the final one. + * @return Returns an Image Actor to be used a pressed background + */ + ImageActor CreatePressedBackground( const Vector3 requiredSize, const bool finalFlag ){ return ImageActor(); }; + + /** + * Adds a popup option button. + * @note Creates popup frame if not already created. + * @param[in] name The unique name for this option. + * @param[in] caption The caption (label) for this option + * @param[in] iconImage Image to displayed with text. + * @param[in] finalOption Flag to indicate that this is the final option. + * (set to true on the last option you add) + */ + void AddButton(const std::string& name, const std::string& caption, const Image iconImage, bool finalOption ){}; + + /** + * Hides the popup + * @param[in] animate (optional) whether to animate popup to hide state over time (i.e. tween). + */ + void Hide(bool animate = true){}; + + /** + * Shows the popup + * @param[in] animate (optional) whether to animate popup to show state over time (i.e. tween). + * @param[in] target Actor to parent popup. + */ + void Show( Actor target, bool animate = true ){}; + + /** + * @brief Get the calculated size of the PopUp + * This can not be set directly as is calculated depending on the content added. + * + * @return Vector3 size of PopUp. + */ + Vector3 GetSize() const { return Vector3::ZERO;}; + + /** + * Returns the current state of the popup. + * @return The state of the popup see enum State + */ + State GetState(void) const{ return StateHidden;}; + + /** + * Get the root actor which the buttons are added to. + * @return the root actor + */ + Actor GetRootActor() const { return Actor(); }; + + /** + * @brief Creates the PopUp with the required buttons for the provided states. + * @param[in] isAllTextSelectedAlready Is all the text already selected + * @param[in] isTextEmpty Contains some text + * @param[in] hasClipboardGotContent Something to paste from clipboard + * @param[in] isSubsetOfTextAlreadySelected Some but not all text is selected + */ + void CreateCutCopyPastePopUp( bool isAllTextSelectedAlready, bool isTextEmpty, bool hasClipboardGotContent, bool isSubsetOfTextAlreadySelected ){}; + + /** + * @brief Applies constraint to keep Popup in view within the desired area. + * @param[in] bounding box in which the PopUp must remain. + * + */ + void ApplyConfinementConstraint( Vector4 boundingBox ){}; + +private: + + /** + * @brief Adds popup to the given parent + * @paran[in] parent target to add Popup to + */ + void AddToParent( Actor parent ){}; + + /** + * Removes popup from Parent. + */ + void RemoveFromStage(){}; + + /** + * Called when a button is pressed in the popup + * @param[in] button The button pressed. + */ + bool OnButtonPressed( Toolkit::Button button ){return false;}; + + /** + * Invoked upon popup Hide animation completing. + * @note Only called for animating hide, not called for instantaneous (animate = false) + * @param[in] source The animation which completed. + */ + void OnHideFinished(Animation& source){}; + + /** + * Invoked upon popup Show animation completing. + * @note Only called for animating show, not called for instantaneous (animate = false) + * @param[in] source The animation which completed. + */ + void OnShowFinished(Animation& source); + +private: + + /** + * @brief Copy Constructor + * @param[in] popup + * Undefined/Hidden. + */ + TextInputPopupNew(const TextInputPopupNew& popup ); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined/Hidden. + */ + TextInputPopupNew& operator=(const TextInputPopupNew& rhs); + +private: + + State mState; // Popup State. + Actor mRootActor; // The actor which all popup content is added to (i.e. panel and buttons) + Vector3 mPopupSize; // Size of the PopUp determined by it's content and max/min size constraints. + ImageActor mBackground; // The background popup panel + ImageActor mTail; // The tail for the popup + Vector3 mContentSize; // Size of Content (i.e. Buttons) + ActorContainer mButtonContainer; // List of buttons added to popup. + ActorContainer mDividerContainer; // List of dividers added to popup. + Animation mAnimation; // Popup Hide/Show animation. + + PopUpPressedSignal mPressedSignal; // Signal emitted when a button within the popup is pressed. + PopUpHideFinishedSignal mHideFinishedSignal; // Signal emitted when popup is completely hidden + PopUpShowFinishedSignal mShowFinishedSignal; // Signal emitted when popup is completely shown + +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_POPUP_NEW_H__ diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-text-highlight-impl.h b/base/dali-toolkit/internal/controls/text-input/text-input-text-highlight-impl.h new file mode 100644 index 0000000..ae95f7d --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-text-highlight-impl.h @@ -0,0 +1,179 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_HIGHLIGHT_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_HIGHLIGHT_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// INTERNAL INCLUDES +#include +#include + +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +/** + * @brief TextHighlight is a decoration which highlights selected text. + * + * The class creates a highlight mesh used to show selected text between handles. + * Not responsible for positioning. + */ +class TextHighlight +{ + /** + * 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) + { + } + + Vector2 min; ///< top-left (minimum) position of quad + Vector2 max; ///< bottom-right (maximum) position of quad + }; + + typedef std::vector QuadContainer; + +public: + + /** + * structure for information required to build the highlight mesh + */ + struct HighlightInfo + { + /** + * Adds a Quad (2D rectangular sub-selection) + * @param[in] x1 left co-ordinate + * @param[in] y1 top co-ordinate + * @param[in] x2 right co-ordinate + * @param[in] y2 bottom co-ordinate + */ + void AddQuad( float x1, float y1, float x2, float y2 ){}; + + /** + * Clamps all quads to fit within a min -> max 2D boundary. + */ + void Clamp2D(const Vector2& min, const Vector2& max){}; + + QuadContainer mQuadList; ///< List of quads (sub-selections that form to create complete selection) + }; + + /** + * Constructor + * @param[in] textViewCharacterPositioning TextViewCharacterPositioning to be used for positioning information. + */ + TextHighlight( TextViewCharacterPositioning& textViewCharacterPositioning ):mTextViewCharacterPositioning( textViewCharacterPositioning ){}; + + /** + * Destructor + */ + ~TextHighlight(){}; + + /** + * Gets the table of the visual text positions which has a flag + * for each Character. The flag is either true (character selected) + * or false (character de-selected) + * @note startSelection can be greater or less than endSelection + * + * @param[in,out] selectedVisualText The vector to be resized and populated with the selected flags + * @param[in] startSelection The start selection point for the text + * @param[in] endSelection The end selection point for the text + * @param[in] endSelection The end selection point for the text + * @param[in] textLayoutInfo TextView character layout information + */ + void GetVisualTextSelection(std::vector& selectedVisualText, std::size_t startSelection, std::size_t endSelection, + Toolkit::TextView::TextLayoutInfo& textLayoutInfo){}; + + /** + * Iterates between selection handles and computes the info required to build the highlight mesh + * @param[in] handlePositionStart starting handle position + * @param[in] handlePositionEnd ending handle position + * @return textHighlight target TextHighlight + */ + TextHighlight::HighlightInfo CalculateHighlightInfo( std::size_t handlePositionStart, std::size_t handlePositionEnd, Toolkit::TextView::TextLayoutInfo& textLayoutInfo ) + { return HighlightInfo();}; + + /** + * Calculates new Mesh data so highlight moves with selection handles. + * @param[in] newHighlightInfo HighlightInfo calculated by CalculateHighlightInfo + */ + void UpdateHighlight( TextHighlight::HighlightInfo& newHighlightInfo ){}; + + /** + * Creates the Mesh data needed by the Mesh Actor + */ + Mesh CreateHighLightMesh(){return Mesh();}; + +private: + + /** + * @brief Copy Constructor + * @param[in] textHight + * Undefined/Hidden. + */ + TextHighlight(const TextHighlight& textHight ); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined/Hidden. + */ + TextHighlight& operator=(const TextHighlight& rhs); + +private: + + TextViewCharacterPositioning& mTextViewCharacterPositioning; + + Mesh mHighlightMesh; ///< Mesh Data for highlight + MeshData mMeshData; ///< Container to hold meshData for highlight + Material mCustomMaterial; ///< Custom material used for highlight + HighlightInfo mNewHighlightInfo; ///< Geometry info to create highlight. + +}; + + +} // namespace Internal + + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_HIGHLIGHT_H__ diff --git a/base/dali-toolkit/internal/controls/text-input/text-input-text-style-impl.h b/base/dali-toolkit/internal/controls/text-input/text-input-text-style-impl.h new file mode 100644 index 0000000..60815cb --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/text-input-text-style-impl.h @@ -0,0 +1,120 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXT_STYLE_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXT_STYLE_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include + +// INTERNAL INCLUDES + +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class TextInputTextStyle; + +typedef IntrusivePtr TextInputTextStylePtr; + +/** + * Stores the Input Text Style and provides functions to retrieve and manipulate it. + */ + +class TextInputTextStyle : ConnectionTracker +{ + +public: + + /** + * @brief Constructor + */ + TextInputTextStyle(){}; + + /** + * @brief Destructor + */ + ~TextInputTextStyle(){}; + + /** + * @brief Returns the current Input Style, this is the style that newly inputed text will inherit. + * @return TextStyle object representing new style. + */ + TextStyle GetInputStyle() const{return mInputStyle;}; + + /** + * @brief Sets the Input style so newly inputed text will inherit this. + * @param[in] newStyle the style to now use for Input + * @return returns true if style changed. False if new style is the same as current setting. + */ + bool SetInputStyle( const TextStyle newStyle, const TextStyle::Mask mask = TextStyle::ALL ){return false;}; + + /** + * @brief Gets the Current Font used for newly inputed text + * @return the Font currently set for new text + */ + Dali::Font GetInputFont() const{return Dali::Font();}; + + /** + * Signals + */ + + /* Input style changed signal.*/ + typedef SignalV2< void( const TextStyle& style ) > StyleChangedSignalType; + + /** + * @brief Signal emitted when style changes. + * @return The signal to connect to + */ + StyleChangedSignalType& StyleChangedSignal(); + +private: + + /** + * @brief Copy Constructor + * @param[in] textStyle + * Undefined/Hidden. + */ + TextInputTextStyle(const TextInputTextStyle& textStyle ); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined/Hidden. + */ + TextInputTextStyle& operator=(const TextInputTextStyle& rhs); + +private: + + TextStyle mInputStyle; // Stores the current input style. + StyleChangedSignalType mStyleChangedSignal; // Signal emitted when style changes. +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXT_STYLE_H__ + + diff --git a/base/dali-toolkit/internal/controls/text-input/textview-character-positions-impl.h b/base/dali-toolkit/internal/controls/text-input/textview-character-positions-impl.h new file mode 100644 index 0000000..d905e22 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-input/textview-character-positions-impl.h @@ -0,0 +1,340 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXTVIEW_CHARACTER_POSITIONS_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXTVIEW_CHARACTER_POSITIONS_H__ + +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://floralicense.org/license/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// + +// INTERNAL INCLUDES +#include + +// EXTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class TextInputTextStyle; + +/** + * Class which contains functions related to the TextView. + * Functions which are needed by various parts of the TextInput to determine the position of characters. + * Functions to Set the TextView so text justification, alignment and wrapping behaviour in the desired manner for text input. + * The functionality of this class may be divided in future. + */ +class TextViewCharacterPositioning +{ + +public: + + /** + * @brief Constructor + * + * @param[in] displayedTextView TextView to be used with this class. + * @param[in] textStyle TextInputTextStyle to be used + */ + TextViewCharacterPositioning( Toolkit::TextView displayedTextView, TextInputTextStyle& textStyle ):mTextStyle( textStyle ){}; + + /** + * Destructor + */ + ~TextViewCharacterPositioning(){}; + + /** + * @brief Creates the TextView to be used within this class. + */ + void CreateTextView(){}; + + /* + * @brief Get a handle to the current text view object + * If one does not exist then it's create. + * @return TextView + */ + Toolkit::TextView GetTextView() const{return Toolkit::TextView();}; + + /** + * @brief Get the TextLayoutInfo from the TextView so know the updated positions of characters. + */ + void UpdateTextLayoutInfo(){}; + + + /** + * @brief Get the TextLayoutInfo structure for the TextView + * @return the TextLayoutInfo structure + */ + const Toolkit::TextView::TextLayoutInfo& GetLayoutInfo() const{return mTextLayoutInfo;}; + + + /** + * @brief Get the number of characters visually represented in the text + * @return the number of characters + */ + std::size_t GetNumberOfCharactersInText() const{return 0;}; + + /** + * @brief Check if any text exists in TextView's character layout table + * @return bool true if empty + */ + bool IsTextEmpty() const{return false;}; + + /** + * @brief Get the height of the line at the given cursor position + * @param[in] position + * @return float the height of the line + */ + float GetLineHeight( std::size_t position ) const{return 0.0f;}; + + /** + * @brief Sets if the inputed text can exceed the text-input boundary. + * By default is enabled. + * @param[in] enable Whether the inputed text can exceed its boundary. + */ + void SetTextExceedEnabled( bool enable ) {}; + + /** + * @brief Retrieves whether inputed text can exceed the text-input boundary. + * @return \e true if text inputed can exceed the boundary, otherwise \e false. + */ + bool IsTextExceedEnabled() const{ return false;}; + + /** + * @brief From the given x and y vector the closest character position is returned + * @param[in] source the x and y position + * @return the position in the string of the character closest to the source. + */ + std::size_t ReturnClosestIndex( const Vector2& source ){return 0;}; + + /** + * @brief If no text exists then this function uses the text alignment to position cursor. + * @param[in] cursorPosition + */ + void GetActualPositionFromCharacterPositionWhenNoText( Vector3& cursorPosition ) const{}; + + /** + * @brief Function to position cursor when a word is wrapped to another line + * @param[in] characterPosition that actual position is required for + * @return the actual position of the cursor. + */ + Vector3 PositionCursorAfterWordWrap( std::size_t characterPosition ) const{return Vector3::ZERO;}; + + /** + * @brief Returns the x-position of the current line justification + * (relative to left of text-view container) + * @return x position for line justification + */ + float GetLineJustificationPosition() const{return 0.0f;}; + + /** + * @brief Retrieve the dimensions (and min-max) of this row of text that the character resides on. + * @param[in] characterPosition the position in the 'string' of characters. + * @param[out] min the top-left position of the rectangle representing this row + * @param[out] max the bottom-right position of the rectangle representing this row + * @return The size of the rectangle representing this row (max - min) + */ + Size GetRowRectFromCharacterPosition(std::size_t characterPosition, Vector2& min, Vector2& max) const{return Vector2::ZERO;}; + + /** + * @brief Retrieve the character position of the first character on the row of text + * that this character resides on. + * @param[in] logicalPosition the position in the 'string' of characters. + * @return logical character position of start of row. + */ + std::size_t GetRowStartFromCharacterPosition(std::size_t logicalPosition) const{return 0;}; + + /** + * @brief Gets the visual position of a logical position. + * @note This is preferred over directly accessing the Map, as it resolves visual + * positions outside of the character map range. + * @param[in] logicalPosition The logical position + * @return Visual position is returned. + */ + std::size_t GetVisualPosition(std::size_t logicalPosition) const{return 0;}; + + /** + * @brief Return a vector which is the actual position for the given character position + * The character position is where a cursor would be position for that character. + * @param[in] characterPosition the logical (input) position in the 'string' of characters. + * + * @return Vector3 the actual x,y,z position + */ + Vector3 GetActualPositionFromCharacterPosition(std::size_t characterPosition ) const{return Vector3::ZERO;}; + + /** + * @brief Return a vector which is the actual position for the given character position + * The character position is where a cursor would be positioned for that character to be inserted. + * An additional alternatePosition is also set in circumstances where the possible writing + * of characters would be in the opposite direction. + * e.g. "HelloشقشلاهؤEnglish" + * | | + * * + + * [*] - Primary actual position for cursor i.e. continuing writing LTR (English) + * [+] - Alternate actual position for cursor i.e. writing RTL (Arabic) + * + * @param[in] characterPosition the logical (input) position in the 'string' of characters. + * @param[out] directionRTL Whether the actual x,y,z position is after LTR (false) or RTL (true) text. + * @param[out] alternatePosition the actual x,y,z position of the cursor if user types + * in alternate direction to current flow of text. + * @param[out] alternatePositionValid whether this alternate position is valid. + * @return Vector3 the actual x,y,z position + */ + Vector3 GetActualPositionFromCharacterPosition(std::size_t characterPosition, bool& directionRTL, Vector3& alternatePosition, bool& alternatePositionValid ) const{return Vector3::ZERO;}; + + /** + * @brief Get the currently displayed text. + * @return The currently displayed text. + */ + std::string GetText() const{return std::string();}; + + /** + * @brief Get the text currently being displayed together with mark-up tags. + * @return string, the currently displayed string with mark-up. + */ + std::string GetMarkupText() const{return std::string();}; + + /** + * @brief Sets whether markup processing should be carried out. + * + * @param[in] enable whether markup processing is carried out or not. + */ + void SetMarkupProcessingEnabled( bool enable ){}; + + /** + * @brief Returns whether markup processing is enabled or not + * + * @return true is markup processing is enabled + */ + bool IsMarkupProcessingEnabled() const{ return false;}; + + // Styled Text + + /** + * @brief Check if styled text is empty + * @return bool returns true if styled text is empty + */ + bool IsStyledTextEmpty() const{ return false;}; + + /** + * @brief The size of the style text + * @return std::size_t returns number of characters in styled text + */ + std::size_t StyledTextSize() const{return 0;}; + + /** + * @brief Get the styled text array + * @return reference to MarkupProcessor::StyledTextArray + */ + MarkupProcessor::StyledTextArray& GetStyledTextArray(){return mStyledText;}; + + /** + * @brief Get the style for the character at the given position + * @param[in] position of character style is required for + * @return a copy of the style structure for the character at the given position + */ + TextStyle GetStyleAt( std::size_t position ) const{return TextStyle();}; + +/** + * @briefApplies the given style to all text, selected or not selected. + * By default all style settings are applied but a bit mask could be used to modify only certain style settings. + * @param[in] style style to apply + * @param[in] mask mask style should be applied to + * @param[in] begin start position of range to apply style + * @param[in] end end position of range to apply style + */ + void ApplyStyleToRange( const TextStyle& style, const TextStyle::Mask mask, const std::size_t begin, const std::size_t end ){}; + + // Snapshot + /** + * @copydoc TextView::SetSnapshotModeEnabled() + */ + void SetSnapshotModeEnabled( bool enable ){}; + + /** + * @copydoc TextView::IsSnapshotModeEnabled() + */ + bool IsSnapshotModeEnabled() const{ return false;}; + + // Scrolling + /** + * @copydoc TextView::SetScrollEnabled() + */ + void SetScrollEnabled( bool enable ){}; + + /** + * @copydoc TextView::SetScrollPosition() + */ + void SetScrollPosition( const Vector2& position ){}; + + /** + * @copydoc TextView::IsScrollEnabled() + */ + bool IsScrollEnabled() const{ return false;}; + + /** + * @copydoc TextView::GetScrollPosition() + */ + Vector2 GetScrollPosition() const{return Vector2::ZERO;}; + + /** + * @copydoc TextView::GetScrollPosition() + */ + bool IsScrollPositionTrimmed() const{ return false;}; + +private: + + /** + * @brief Copy Constructor + * @param[in] characterPositioning + * Undefined. + */ + TextViewCharacterPositioning(const TextViewCharacterPositioning& characterPositioning ); + + /** + * @Assignment Constructor + * @param[in] rhs + * Undefined. + */ + TextViewCharacterPositioning& operator=(const TextViewCharacterPositioning& rhs); + +private: + + Toolkit::TextView mDisplayedTextView; // A text view object used to display the text. + TextInputTextStyle& mTextStyle; // Holds the style object related to input style + + MarkupProcessor::StyledTextArray mStyledText; // String currently displayed by TextView with style info. + + Toolkit::TextView::TextLayoutInfo mTextLayoutInfo; // It contains a table layout info per character sorted by the character's visual index (retrieved from TextView), + // a reorder map that stores each character's visual (output) index according to its logical (input) index, + // a reorder map that stores each character's logical (input) index according to its visual (output) index + + bool mExceedEnabled:1; // flag set by user to determine if text can exceed the control's size + bool mMarkUpEnabled:1; // If Markup is being passed with the text +}; + + +} // namespace Internal + + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_INPUT_TEXTVIEW_CHARACTER_POSITIONS_H__ diff --git a/base/dali-toolkit/internal/file.list b/base/dali-toolkit/internal/file.list index 3f1a9f2..0c944aa 100644 --- a/base/dali-toolkit/internal/file.list +++ b/base/dali-toolkit/internal/file.list @@ -35,6 +35,7 @@ toolkit_base_src_files = \ $(toolkit_base_src_dir)/controls/scrollable/scroll-view/scroll-view-twist-effect-impl.cpp \ $(toolkit_base_src_dir)/controls/scrollable/scroll-view/scroll-view-wobble-effect-impl.cpp \ $(toolkit_base_src_dir)/controls/table-view/table-view-impl.cpp \ + $(toolkit_base_src_dir)/controls/text-input/text-input-decorator-impl.cpp \ $(toolkit_base_src_dir)/controls/text-input/text-input-impl.cpp \ $(toolkit_base_src_dir)/controls/text-input/text-input-popup-impl.cpp \ $(toolkit_base_src_dir)/controls/text-view/relayout-utilities.cpp \ -- 2.7.4