2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali/integration-api/debug.h>
21 #include <dali-toolkit/internal/controls/text-input/text-input-decorator-impl.h>
23 #include <dali-toolkit/internal/controls/text-input/text-input-handles-impl.h>
29 #if defined(DEBUG_ENABLED)
30 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TEXT_INPUT_DECORATOR");
33 const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f );
34 const float TOP_HANDLE_TOP_OFFSET(-1.5f); // Offset between top handle and cutCopyPaste pop-up
35 const float BOTTOM_HANDLE_BOTTOM_OFFSET(1.5f); // Offset between bottom handle and cutCopyPaste pop-up
36 const float UI_Z_OFFSET( 0.2f ); // Text Selection Handles/Cursor z-offset.
37 const Vector3 UI_OFFSET(0.0f, 0.0f, UI_Z_OFFSET); // Text Selection Handles/Cursor offset.
38 const char* DEFAULT_CURSOR( DALI_IMAGE_DIR "cursor.png" );
39 const Vector4 DEFAULT_CURSOR_IMAGE_9_BORDER( 2.0f, 2.0f, 2.0f, 2.0f );
40 const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval
41 const float CURSOR_THICKNESS(6.0f);
42 const Degree CURSOR_ANGLE_OFFSET(2.0f); // Offset from the angle
44 const unsigned int SCROLL_TICK_INTERVAL = 50u;
45 const float SCROLL_THRESHOLD = 10.f;
46 const float SCROLL_SPEED = 15.f;
49 * Whether the given position plus the cursor size offset is inside the given boundary.
51 * @param[in] position The given position.
52 * @param[in] cursorSize The cursor size.
53 * @param[in] controlSize The given boundary.
54 * @param[in] threshold imaginary indent around boundary that will trigger the position to be outside of control.
56 * @return whether the given position is inside the given boundary.
58 bool IsPositionWithinControl( const Vector3& position, const Size& cursorSize, const Vector3& controlSize, const Vector2 threshold = Vector2::ZERO )
60 return ( position.x >= -Math::MACHINE_EPSILON_1000 + threshold.x ) &&
61 ( position.x <= controlSize.width - threshold.x + Math::MACHINE_EPSILON_1000 ) &&
62 ( position.y - cursorSize.height >= -Math::MACHINE_EPSILON_1000 + threshold.y ) &&
63 ( position.y <= controlSize.height + Math::MACHINE_EPSILON_1000 - threshold.y);
76 Decorator::Decorator( TextViewCharacterPositioning& textViewManager, TextInputTextStyle& textStyle ):
77 mTextViewCharacterPositioning( textViewManager ),
78 mTextStyle( textStyle ),
80 mTextHighlight( textViewManager ),
81 mCursorBlinkStatus( true ),
82 mCursorVisibility( true ),
83 mGrabHandleEnabled( true )
87 Decorator::~Decorator()
94 void Decorator::SetBoundingBox( const Rect<float>& boundingRectangle )
96 // Convert to world coordinates and store as a Vector4 to be compatible with Property Notifications.
97 Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
99 const float originX = boundingRectangle.x - 0.5f * stageSize.width;
100 const float originY = boundingRectangle.y - 0.5f * stageSize.height;
102 const Vector4 boundary( originX,
104 originX + boundingRectangle.width,
105 originY + boundingRectangle.height );
107 mBoundingRectangleWorldCoordinates = boundary;
110 Vector4 Decorator::GetBoundingBox() const
112 return mBoundingRectangleWorldCoordinates;
118 void Decorator::OnHandlePan(Actor actor, PanGesture gesture)
120 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
121 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
123 switch (gesture.state)
125 case Gesture::Started:
126 // fall through so code not duplicated
127 case Gesture::Continuing:
129 if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleOne() )
131 MoveSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition, gesture.displacement );
134 else if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleTwo() )
136 MoveSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition, gesture.displacement );
139 else if ( actor.GetParent() == mTextInputHandles.GetGrabHandle() )
141 SetCursorVisibility( true );
142 ShowGrabHandle( mGrabHandleVisibility && mIsGrabHandleInScrollArea );
143 MoveGrabHandle( gesture.displacement );
144 HidePopUp(); // Do not show popup while handle is moving
149 case Gesture::Finished:
151 // Revert back to non-pressed selection handle images
152 if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleOne() )
154 mSelectionHandleOneActualPosition = MoveSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition, gesture.displacement );
155 ShowPopupCutCopyPaste();
158 else if ( actor.GetParent() == mTextInputHandles.GetSelectionHandleTwo() )
160 mSelectionHandleTwoActualPosition = MoveSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition, gesture.displacement );
161 ShowPopupCutCopyPaste();
164 else if ( actor.GetParent() == mTextInputHandles.GetGrabHandle() )
166 MoveGrabHandle( gesture.displacement );
167 SetCursorVisibility( true );
168 ShowPopupCutCopyPaste();
178 void Decorator::CreateSelectionHandles( Actor targetParent )
180 if ( !mPanGestureDetector )
182 mPanGestureDetector = PanGestureDetector::New();
183 mPanGestureDetector.DetectedSignal().Connect(this, &Decorator::OnHandlePan);
186 if ( !mTextInputHandles.GetSelectionHandleOne() )
188 mTextInputHandles.CreateSelectionHandles();
190 mTextInputHandles.AttachSelectionHandlesToGivenPanGesture( mPanGestureDetector );
192 targetParent.Add( mTextInputHandles.GetSelectionHandleOne() );
193 targetParent.Add( mTextInputHandles.GetSelectionHandleTwo() );
195 SetUpHandlePropertyNotifications();
199 void Decorator::RemoveSelectionHandles()
201 mTextInputHandles.DestorySelectionHandles();
204 Vector3 Decorator::GetSelectionHandleSize()
206 return DEFAULT_SELECTION_HANDLE_SIZE;
209 std::size_t Decorator::GetHandleOnePosition() const
211 return mSelectionHandleOnePosition;
214 std::size_t Decorator::GetHandleTwoPosition() const
216 return mSelectionHandleTwoPosition;
219 Vector3 Decorator::PositionSelectionHandle( Actor selectionHandle, std::size_t position )
221 bool direction(false);
222 Vector3 alternatePosition;
223 bool alternatePositionValid(false);
225 Vector3 actualPositionOfSelectionHandle = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( position, direction, alternatePosition,alternatePositionValid );
227 return PositionSelectionHandle( selectionHandle, actualPositionOfSelectionHandle, position );
231 Vector3 Decorator::PositionSelectionHandle( Actor selectionHandle, Vector3& actualPosition, std::size_t position )
233 const Vector3 DEFAULT_HANDLE_OFFSET(0.0f, -5.0f, 0.0f);
235 selectionHandle.SetPosition( actualPosition += DEFAULT_HANDLE_OFFSET );
237 if( mTextViewCharacterPositioning.IsScrollEnabled() )
239 const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize();
240 const Size cursorSize( GetCursorSizeAt( position ) );
241 bool handleVisible = IsPositionWithinControl( actualPosition, Vector2(DEFAULT_HANDLE_OFFSET.width, DEFAULT_HANDLE_OFFSET.height), controlSize );
243 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::PositionSelectionHandle controlSize[%f,%f] cursorSize[%f,%f] actualPos[%f,%f] visible[%s] \n",
244 controlSize.x, controlSize.y, cursorSize.x, cursorSize.y, actualPosition.x, actualPosition.y, ( handleVisible )?"true":"false" );
246 selectionHandle.SetVisible( handleVisible );
248 return actualPosition;
251 void Decorator::SetSelectionHandlesVisibility(bool visible )
253 mTextInputHandles.SetSelectionHandleOneVisibility( visible );
254 mTextInputHandles.SetSelectionHandleTwoVisibility( visible );
257 bool Decorator::OnHandleReleased()
263 void Decorator::PositionSelectionHandles( std::size_t start, std::size_t end )
265 mSelectionHandleOnePosition = start;
266 mSelectionHandleTwoPosition = end;
268 mTextViewCharacterPositioning.UpdateTextLayoutInfo();
270 mSelectionHandleOneActualPosition = PositionSelectionHandle( mTextInputHandles.GetSelectionHandleOne(), mSelectionHandleOnePosition );
271 mSelectionHandleTwoActualPosition = PositionSelectionHandle( mTextInputHandles.GetSelectionHandleTwo(), mSelectionHandleTwoPosition );
273 mTextInputHandles.ReleasedSignal().Connect( this, &Decorator::OnHandleReleased );
276 Vector3 Decorator::MoveSelectionHandle( Actor selectionHandle,
277 Vector3& actualSelectionHandlePosition,
278 std::size_t& currentSelectionHandlePosition,
279 const Vector2& displacement )
281 Vector3 actualHandlePosition;
282 actualSelectionHandlePosition.x += displacement.x * selectionHandle.GetCurrentScale().x;
283 actualSelectionHandlePosition.y += displacement.y * selectionHandle.GetCurrentScale().y;;
285 // Selection handles should jump to the nearest character
286 std::size_t newHandlePosition = 0;
287 newHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( actualSelectionHandlePosition.GetVectorXY() );
289 bool direction(false);
290 Vector3 alternatePosition;
291 bool alternatePositionValid(false);
292 actualHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandlePosition,direction, alternatePosition, alternatePositionValid );
294 bool handleVisible = true;
297 if( mTextViewCharacterPositioning.IsScrollEnabled() )
299 const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize();
300 const Size cursorSize( GetCursorSizeAt( newHandlePosition ) );
302 handleVisible = IsPositionWithinControl( actualHandlePosition,
309 mCurrentHandlePosition = actualHandlePosition;
310 mScrollDisplacement = Vector2::ZERO;
315 if( ( actualHandlePosition.x < SCROLL_THRESHOLD ) && ( displacement.x <= 0.f ) )
317 mScrollDisplacement.x = -SCROLL_SPEED;
319 else if( ( actualHandlePosition.x > controlSize.width - SCROLL_THRESHOLD ) && ( displacement.x >= 0.f ) )
321 mScrollDisplacement.x = SCROLL_SPEED;
323 if( ( actualHandlePosition.y < SCROLL_THRESHOLD ) && ( displacement.y <= 0.f ) )
325 mScrollDisplacement.y = -SCROLL_SPEED;
327 else if( ( actualHandlePosition.y > controlSize.height - SCROLL_THRESHOLD ) && ( displacement.y >= 0.f ) )
329 mScrollDisplacement.y = SCROLL_SPEED;
331 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveSelectionHandle Handle not visible scroll displacement [%f]\n", mScrollDisplacement.x);
337 if ( handleVisible && // Ensure the handle is visible.
338 ( newHandlePosition != currentSelectionHandlePosition ) && // Ensure the handle has moved.
339 ( newHandlePosition != mSelectionHandleTwoPosition ) && // Ensure new handle position not the same position as an existing handle.
340 ( newHandlePosition != mSelectionHandleOnePosition ) )
342 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveSelectionHandle Handle visible and moved]\n");
344 currentSelectionHandlePosition = newHandlePosition;
346 PositionSelectionHandle( selectionHandle, actualHandlePosition, newHandlePosition );
348 ShowUpdatedHighlight();
350 // Set Active Style to that of first character in selection
351 std::size_t firstHandleInSelection = std::min( mSelectionHandleOnePosition, mSelectionHandleTwoPosition );
353 const TextStyle inputStyle = mTextViewCharacterPositioning.GetStyleAt( firstHandleInSelection );
354 mTextStyle.SetInputStyle( inputStyle );
356 return actualHandlePosition; // Returns Handle position passed in if new value not assigned.
362 void Decorator::PositionGrabHandle( std::size_t positionInText )
364 bool direction(false);
365 Vector3 alternatePosition;
366 bool alternatePositionValid(false);
368 mGrabHandlePosition = positionInText;
370 mTextViewCharacterPositioning.UpdateTextLayoutInfo();
371 mActualGrabHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( positionInText, direction, alternatePosition,alternatePositionValid );
373 mTextInputHandles.GetGrabHandle().SetPosition( mActualGrabHandlePosition );
376 void Decorator::MoveGrabHandle( const Vector2& displacement /*, std::size_t currentHandlePosition */)
378 mActualGrabHandlePosition.x += displacement.x;
379 mActualGrabHandlePosition.y += displacement.y;
381 // Grab handle should jump to the nearest character and take cursor with it
382 std::size_t newHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mActualGrabHandlePosition.GetVectorXY() );
384 Vector3 actualHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandlePosition );
386 bool handleVisible = true;
388 if( mTextViewCharacterPositioning.IsScrollEnabled() )
390 const Vector3 controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize();
391 const Size cursorSize( GetCursorSizeAt( newHandlePosition ) );
392 // Scrolls the text if the handle is not in a visible position
393 handleVisible = IsPositionWithinControl( actualHandlePosition,
397 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::MoveGrabHandle handleVisible[%s]\n", ( handleVisible )?"true":"false");
402 mCurrentHandlePosition = actualHandlePosition;
403 mScrollDisplacement = Vector2::ZERO;
407 if( ( actualHandlePosition.x < SCROLL_THRESHOLD ) && ( displacement.x <= 0.f ) )
409 mScrollDisplacement.x = -SCROLL_SPEED;
411 else if( ( actualHandlePosition.x > controlSize.width - SCROLL_THRESHOLD ) && ( displacement.x >= 0.f ) )
413 mScrollDisplacement.x = SCROLL_SPEED;
415 if( ( actualHandlePosition.y < SCROLL_THRESHOLD ) && ( displacement.y <= 0.f ) )
417 mScrollDisplacement.y = -SCROLL_SPEED;
419 else if( ( actualHandlePosition.y > controlSize.height - SCROLL_THRESHOLD ) && ( displacement.y >= 0.f ) )
421 mScrollDisplacement.y = SCROLL_SPEED;
427 if( ( newHandlePosition != mGrabHandlePosition ) && // Only redraw cursor and do updates if position changed
428 ( handleVisible ) )// and the new position is visible (if scroll is not enabled, it's always true).
430 mActualGrabHandlePosition = actualHandlePosition;
431 mTextInputHandles.GetGrabHandle().SetPosition( mActualGrabHandlePosition );
433 //PositionGrabHandle( newHandlePosition );
434 mGrabHandlePosition = newHandlePosition;
435 SetCurrentCursorPosition( mGrabHandlePosition );
436 DrawCursor( mGrabHandlePosition );
438 const std::size_t cursorPosition = GetCurrentCursorPosition();
440 // Let keyboard know the new cursor position so can 're-capture' for prediction.
441 mCursorRePositionedSignal.Emit();
443 // Set Input Style to that of cursor position
444 if ( !mTextViewCharacterPositioning.IsStyledTextEmpty() && ( cursorPosition > 0 ) )
446 DALI_ASSERT_DEBUG( ( 0 <= cursorPosition-1 ) && ( cursorPosition-1 < mTextViewCharacterPositioning.StyledTextSize() ) );
447 const TextStyle inputStyle = mTextViewCharacterPositioning.GetStyleAt( cursorPosition-1 );
448 mTextStyle.SetInputStyle( inputStyle );
453 void Decorator::ShowGrabHandle( bool visible )
455 mGrabHandleVisibility = visible;
456 mTextInputHandles.SetGrabHandleVisibility( visible );
459 void Decorator::CreateGrabHandle( Actor targetParent )
461 if ( !mPanGestureDetector )
463 mPanGestureDetector = PanGestureDetector::New();
464 mPanGestureDetector.DetectedSignal().Connect(this, &Decorator::OnHandlePan);
467 if ( !mTextInputHandles.GetGrabHandle() )
469 mTextInputHandles.CreateGrabHandle();
470 mTextInputHandles.AttachGrabHandleToGivenPanGesture( mPanGestureDetector );
471 targetParent.Add( mTextInputHandles.GetGrabHandle() );
475 void Decorator::SetGrabHandleImage( Image image )
477 mTextInputHandles.SetGrabHandleImage( image );
480 void Decorator::EnableGrabHandle( bool toggle)
482 // enables grab handle with will in turn de-activate magnifier
483 mGrabHandleEnabled = toggle;
486 bool Decorator::IsGrabHandleEnabled()
488 // if false then magnifier will be shown instead.
489 return mGrabHandleEnabled;
495 std::size_t Decorator::GetCurrentCursorPosition() const
497 return mCursorPosition;
500 void Decorator::SetCurrentCursorPosition( std::size_t newCursorPosition )
502 mCursorPosition = newCursorPosition;
505 void Decorator::SetCursorVisibility( bool visible )
507 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::SetCursorVisibility[%s]\n", ( visible )?"true":"false");
509 mCursorVisibility = visible;
510 mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea );
511 mCursorRTL.SetVisible( mCursorVisibility && mCursorRTLEnabled );
514 void Decorator::DrawCursor(const std::size_t nthChar)
516 std::size_t cursorPosition = GetCurrentCursorPosition();
518 // Get height of cursor and set its size
519 Size size( CURSOR_THICKNESS, 0.0f );
520 if ( !mTextViewCharacterPositioning.IsTextEmpty() )
522 Vector2 min, max; // out parameters for GetRowRectFromCharacterPosition
523 size.height = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mTextViewCharacterPositioning.GetVisualPosition( cursorPosition ), min, max ).height;
527 // Measure Font so know how big text will be if no initial text to measure.
528 size.height = mTextViewCharacterPositioning.GetLineHeight( nthChar );
531 mCursor.SetSize(size);
533 // If the character is italic then the cursor also tilts.
534 if ( !mTextViewCharacterPositioning.IsStyledTextEmpty() && ( cursorPosition > 0 ) )
536 DALI_ASSERT_DEBUG( ( 0 <= cursorPosition-1 ) && ( cursorPosition-1 < mTextViewCharacterPositioning.StyledTextSize() ) );
537 const TextStyle styleAtCursor = mTextViewCharacterPositioning.GetStyleAt( cursorPosition-1 );
538 mCursor.SetRotation( styleAtCursor.GetItalics() ? Degree( styleAtCursor.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS );
541 DALI_ASSERT_DEBUG( cursorPosition <= mTextViewCharacterPositioning.GetNumberOfCharactersInText() );
542 if ( ( cursorPosition <= mTextViewCharacterPositioning.GetNumberOfCharactersInText() ) )
544 Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position.
545 bool altPositionValid( false ); // Alternate cursor validity flag.
546 bool directionRTL( false ); // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently)
547 Vector3 position = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition, directionRTL, altPosition, altPositionValid );
549 SetAltCursorEnabled( altPositionValid );
551 if(!altPositionValid)
553 mCursor.SetPosition( position + UI_OFFSET );
558 mCursor.SetSize(size);
559 mCursor.SetPosition( position + UI_OFFSET - Vector3(0.0f, directionRTL ? 0.0f : size.height, 0.0f) );
560 Vector2 min, max; // out parameters for GetRowRectFromCharacterPosition
561 Size rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mTextViewCharacterPositioning.GetVisualPosition( cursorPosition ), min, max );
562 size.height = rowSize.height * 0.5f;
563 mCursorRTL.SetSize(size);
564 mCursorRTL.SetPosition( altPosition + UI_OFFSET - Vector3(0.0f, directionRTL ? size.height : 0.0f, 0.0f) );
567 if( mTextViewCharacterPositioning.IsScrollEnabled() )
569 // Whether cursor and grab handle are inside the boundaries of the text-input when text scroll is enabled.
570 const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize();
571 mIsCursorInScrollArea = mIsGrabHandleInScrollArea = IsPositionWithinControl( position, size, controlSize );
576 void Decorator::SetAltCursorEnabled( bool enabled )
578 mCursorRTLEnabled = enabled;
579 mCursorRTL.SetVisible( mCursorVisibility && mCursorRTLEnabled );
582 void Decorator::SetCursorImage(Dali::Image image, const Vector4& border )
584 DALI_ASSERT_DEBUG ( image && "Create cursor image invalid")
588 mCursor.SetImage( image );
589 mCursor.SetNinePatchBorder( border );
593 void Decorator::SetRTLCursorImage( Image image, const Vector4& border )
595 DALI_ASSERT_DEBUG ( image && "Create cursor image invalid")
599 mCursorRTL.SetImage( image );
600 mCursorRTL.SetNinePatchBorder( border );
604 ImageActor Decorator::CreateCursor( Image cursorImage, const Vector4& border, const std::string& cursorName )
610 cursor = ImageActor::New( cursorImage );
614 cursor = ImageActor::New( Image::New( DEFAULT_CURSOR ) );
617 cursor.SetStyle(ImageActor::STYLE_NINE_PATCH);
618 cursor.SetNinePatchBorder( border );
619 cursor.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER);
620 cursor.SetVisible(false);
621 cursor.SetName( cursorName );
625 void Decorator::CreateCursors( Actor targetParent )
627 Image mCursorImage = Image::New( DEFAULT_CURSOR );
628 mCursor = CreateCursor (mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER , "mainCursor");
629 mCursorRTL = CreateCursor ( mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER, "rtlCursor");
630 targetParent.Add( mCursor );
631 targetParent.Add( mCursorRTL );
634 Size Decorator::GetCursorSizeAt( std::size_t positionWithinTextToGetCursorSize )
636 std::size_t visualPosition = mTextViewCharacterPositioning.GetVisualPosition( positionWithinTextToGetCursorSize );
640 const Size cursorSize( CURSOR_THICKNESS,
641 mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( visualPosition, min, max ).height );
646 void Decorator::StartCursorBlinkTimer()
648 if ( !mCursorBlinkTimer )
650 mCursorBlinkTimer = Timer::New( CURSOR_BLINK_INTERVAL );
651 mCursorBlinkTimer.TickSignal().Connect( this, &Decorator::OnCursorBlinkTimerTick );
654 if ( !mCursorBlinkTimer.IsRunning() )
656 mCursorBlinkTimer.Start();
660 void Decorator::StopCursorBlinkTimer()
662 if ( mCursorBlinkTimer )
664 mCursorBlinkTimer.Stop();
668 bool Decorator::OnCursorBlinkTimerTick()
671 mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea && mCursorBlinkStatus );
672 if ( mCursorRTLEnabled )
674 mCursorRTL.SetVisible( mCursorVisibility && mIsCursorInScrollArea && mCursorBlinkStatus );
676 mCursorBlinkStatus = !mCursorBlinkStatus;
684 void Decorator::ShowUpdatedHighlight()
686 Toolkit::TextView::TextLayoutInfo textLayoutInfo = mTextViewCharacterPositioning.GetLayoutInfo();
687 TextHighlight::HighlightInfo highlightInfo = mTextHighlight.CalculateHighlightInfo( mSelectionHandleOnePosition, mSelectionHandleTwoPosition, textLayoutInfo );
689 // Clamp highlightInfo so they don't exceed the boundary of the control.
690 const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize();
691 highlightInfo.Clamp2D( Vector2::ZERO, Vector2(controlSize.x, controlSize.y) );
693 mTextHighlight.UpdateHighlight( highlightInfo );
696 void Decorator::CreateHighlight( Actor parent )
698 DALI_ASSERT_DEBUG( parent && "Highlight target parent does not exist" );
700 if ( !mHighlightMeshActor )
702 mHighlightMeshActor = MeshActor::New( mTextHighlight.CreateHighLightMesh() );
703 mHighlightMeshActor.SetName( "HighlightMeshActor" );
704 mHighlightMeshActor.SetInheritShaderEffect( false );
705 mHighlightMeshActor.SetAffectedByLighting(false);
706 parent.Add( mHighlightMeshActor );
710 void Decorator::RemoveHighlight()
712 if ( mHighlightMeshActor )
714 mHighlightMeshActor.Unparent();
715 mHighlightMeshActor.Reset();
716 // NOTE: We cannot dereference mHighlightMesh, due to a how the scene-graph MeshRenderer uses the Mesh data.
720 void Decorator::HighlightVisibility( bool visiblility )
722 if ( mHighlightMeshActor )
724 mHighlightMeshActor.SetVisible( visiblility );
729 * Callbacks connected to be Property notifications for Boundary checking.
731 // Note If PropertyNotification signal definition included Actor we would not need to duplicate functions.
732 void Decorator::OnHandleOneLeavesBoundary( PropertyNotification& source)
734 mTextInputHandles.GetSelectionHandleOne().SetOpacity(0.0f);
737 void Decorator::OnHandleOneWithinBoundary(PropertyNotification& source)
739 mTextInputHandles.GetSelectionHandleOne().SetOpacity(1.0f);
742 void Decorator::OnHandleTwoLeavesBoundary( PropertyNotification& source)
744 mTextInputHandles.GetSelectionHandleTwo().SetOpacity(0.0f);
747 void Decorator::OnHandleTwoWithinBoundary(PropertyNotification& source)
749 mTextInputHandles.GetSelectionHandleTwo().SetOpacity(1.0f);
752 void Decorator::OnLeftBoundaryExceeded(PropertyNotification& source)
754 DALI_LOG_INFO(gLogFilter, Debug::General, "TextInputDecorationLayouter::OnLeftBoundaryExceeded\n");
755 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
756 selectionHandleOne.SetScale( -1.0f, 1.0f, 1.0f );
757 selectionHandleOne.SetAnchorPoint( AnchorPoint::TOP_LEFT);
760 void Decorator::OnReturnToLeftBoundary(PropertyNotification& source)
762 DALI_LOG_INFO(gLogFilter, Debug::General, "TextInputDecorationLayouter::OnReturnToLeftBoundary\n");
763 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
764 selectionHandleOne.SetScale( 1.0f, 1.0f, 1.0f );
765 selectionHandleOne.SetAnchorPoint( AnchorPoint::TOP_RIGHT);
768 void Decorator::OnRightBoundaryExceeded(PropertyNotification& source)
770 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
771 selectionHandleTwo.SetScale( -1.0f, 1.0f, 1.0f );
772 selectionHandleTwo.SetAnchorPoint( AnchorPoint::TOP_RIGHT);
775 void Decorator::OnReturnToRightBoundary(PropertyNotification& source)
777 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
778 selectionHandleTwo.SetScale( 1.0f, 1.0f, 1.0f );
779 selectionHandleTwo.SetAnchorPoint( AnchorPoint::TOP_LEFT);
782 void Decorator::SetUpHandlePropertyNotifications()
784 /* Property notifications for handles exceeding the boundary and returning back within boundary */
786 Vector3 handlesize = GetSelectionHandleSize();
788 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
789 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
791 // Exceeding horizontal boundary
792 PropertyNotification leftNotification = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_X, LessThanCondition( mBoundingRectangleWorldCoordinates.x + handlesize.x) );
793 leftNotification.NotifySignal().Connect( this, &Decorator::OnLeftBoundaryExceeded );
795 PropertyNotification rightNotification = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_X, GreaterThanCondition( mBoundingRectangleWorldCoordinates.z - handlesize.x ) );
796 rightNotification.NotifySignal().Connect( this, &Decorator::OnRightBoundaryExceeded );
798 // Within horizontal boundary
799 PropertyNotification leftLeaveNotification = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_X, GreaterThanCondition( mBoundingRectangleWorldCoordinates.x + 2*handlesize.x ) );
800 leftLeaveNotification.NotifySignal().Connect( this, &Decorator::OnReturnToLeftBoundary );
802 PropertyNotification rightLeaveNotification = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_X, LessThanCondition( mBoundingRectangleWorldCoordinates.z - 2*handlesize.x ) );
803 rightLeaveNotification.NotifySignal().Connect( this, &Decorator::OnReturnToRightBoundary );
805 // Exceeding vertical boundary
806 PropertyNotification verticalExceedNotificationOne = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_Y,
807 OutsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y,
808 mBoundingRectangleWorldCoordinates.w - handlesize.y ) );
809 verticalExceedNotificationOne.NotifySignal().Connect( this, &Decorator::OnHandleOneLeavesBoundary );
811 PropertyNotification verticalExceedNotificationTwo = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_Y,
812 OutsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y,
813 mBoundingRectangleWorldCoordinates.w - handlesize.y ) );
814 verticalExceedNotificationTwo.NotifySignal().Connect( this, &Decorator::OnHandleTwoLeavesBoundary );
816 // Within vertical boundary
817 PropertyNotification verticalWithinNotificationOne = selectionHandleOne.AddPropertyNotification( Actor::WORLD_POSITION_Y,
818 InsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y,
819 mBoundingRectangleWorldCoordinates.w - handlesize.y ) );
820 verticalWithinNotificationOne.NotifySignal().Connect( this, &Decorator::OnHandleOneWithinBoundary );
822 PropertyNotification verticalWithinNotificationTwo = selectionHandleTwo.AddPropertyNotification( Actor::WORLD_POSITION_Y,
823 InsideCondition( mBoundingRectangleWorldCoordinates.y + handlesize.y,
824 mBoundingRectangleWorldCoordinates.w - handlesize.y ) );
825 verticalWithinNotificationTwo.NotifySignal().Connect( this, &Decorator::OnHandleTwoWithinBoundary );
831 Vector3 Decorator::PositionOfPopUpRelativeToSelectionHandles()
838 // When text is selected, show popup above top handle (and text), or below bottom handle.
840 // topHandle: referring to the top most point of the handle or the top line of selection.
841 if ( mSelectionHandleTwoActualPosition.y > mSelectionHandleOneActualPosition.y )
843 topHandle = mSelectionHandleOneActualPosition;
844 rowSize= mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mSelectionHandleOnePosition, min, max );
848 topHandle = mSelectionHandleTwoActualPosition;
849 rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( mSelectionHandleTwoPosition, min, max );
851 topHandle.y += TOP_HANDLE_TOP_OFFSET - rowSize.height;
852 position = Vector3(topHandle.x, topHandle.y, 0.0f);
857 Vector3 Decorator::AlternatePopUpPositionRelativeToSelectionHandles()
859 // alternativePosition: referring to the bottom most point of the handle or the bottom line of selection.
860 Vector3 alternativePosition;
861 alternativePosition.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
862 alternativePosition.y += GetSelectionHandleSize().y + mPopUpPanel.GetSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
864 return alternativePosition;
867 Vector3 Decorator::PositionOfPopUpRelativeToCursor()
869 // When no text is selected, show PopUp at position of cursor
872 std::size_t cursorPosition = GetCurrentCursorPosition();
873 position = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition );
874 const Size rowSize = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( cursorPosition, min, max );
875 position.y -= rowSize.height;
880 Vector3 Decorator::AlternatePopUpPositionRelativeToCursor()
882 std::size_t cursorPosition = GetCurrentCursorPosition();
883 Vector3 alternativePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorPosition );
885 if ( mTextInputHandles.GetGrabHandle() )
887 // If grab handle enabled then position pop-up below the grab handle.
888 alternativePosition.y += mTextInputHandles.GetGrabHandle().GetCurrentSize().height + mPopUpPanel.GetSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET ;
892 alternativePosition.y += mPopUpPanel.GetSize().y;
895 return alternativePosition;
899 Vector3 Decorator::PositionOfPopUpRelativeToGrabHandle()
901 return Vector3::ZERO;
904 void Decorator::ShowPopUp()
907 Vector3 alternativePosition;
910 DALI_ASSERT_DEBUG( mPopUpTarget && "PopUp Target Actor does not exist" );
912 if( mHighlightMeshActor ) // Text Selection mode
914 position = PositionOfPopUpRelativeToSelectionHandles();
916 else // Not in Text Selection mode so position relative to cursor.
918 position = PositionOfPopUpRelativeToCursor();
921 // reposition popup above the desired cursor position.
922 mPopUpPanel.Show( mPopUpTarget, true );
923 mPopUpPanel.Self().SetPosition( position );
924 mPopUpPanel.PressedSignal().Connect( this, &Decorator::OnPopupButtonPressed );
926 SetUpPopUpPositionNotifications();
927 mPopUpPanel.ApplyConfinementConstraint( mBoundingRectangleWorldCoordinates );
930 void Decorator::ShowPopUp( Actor target )
932 mPopUpTarget = target;
933 ShowPopupCutCopyPaste();
936 void Decorator::ShowPopupCutCopyPaste()
938 bool isAllTextSelectedAlready = ( mTextViewCharacterPositioning.StyledTextSize() == GetSelectedText().size() );
939 bool isTextEmpty = mTextViewCharacterPositioning.IsStyledTextEmpty() ;
940 bool isSubsetOfTextAlreadySelected = ( !isAllTextSelectedAlready ) && mHighlightMeshActor;
942 Clipboard clipboard = Clipboard::Get();
943 bool hasClipboardGotContent = clipboard.NumberOfItems();
945 mPopUpPanel.CreateCutCopyPastePopUp( isAllTextSelectedAlready, isTextEmpty, hasClipboardGotContent, isSubsetOfTextAlreadySelected );
949 void Decorator::HidePopUp( bool animate, bool signalFinished )
951 if ( ( mPopUpPanel.GetState() == TextInputPopupNew::StateShowing ) || ( mPopUpPanel.GetState() == TextInputPopupNew::StateShown ) )
953 mPopUpPanel.Hide( animate );
957 void Decorator::AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption)
959 mPopUpPanel.AddButton(name, caption, icon, finalOption);
962 void Decorator::ClearPopup()
967 void Decorator::PopUpLeavesVerticalBoundary( PropertyNotification& source)
969 Vector3 position, alternativePosition;
971 if( mHighlightMeshActor ) // Text Selection mode
973 alternativePosition = AlternatePopUpPositionRelativeToSelectionHandles();
975 else // Not in Text Selection mode
977 alternativePosition = AlternatePopUpPositionRelativeToCursor();
978 // if can't be positioned above, then position below row.
980 // reposition popup above the desired cursor position.
981 mPopUpPanel.Self().SetPosition( alternativePosition );
984 void Decorator::SetUpPopUpPositionNotifications( )
986 // Note Property notifications ignore any set anchor point so conditions must allow for this. Default is Top Left.
988 // Exceeding vertical boundary
989 PropertyNotification verticalExceedNotificationOne = mPopUpPanel.Self().AddPropertyNotification( Actor::WORLD_POSITION_Y,
990 OutsideCondition( mBoundingRectangleWorldCoordinates.y + mPopUpPanel.GetSize().y/2,
991 mBoundingRectangleWorldCoordinates.w - mPopUpPanel.GetSize().y/2 ) );
992 verticalExceedNotificationOne.NotifySignal().Connect( this, &Decorator::PopUpLeavesVerticalBoundary );
995 bool Decorator::OnPopupButtonPressed( Toolkit::Button button )
997 mPopUpButtonPressedSignal.Emit( button );
1001 Decorator::PressedSignal& Decorator::PopUpButtonPressedSignal()
1003 return mPopUpButtonPressedSignal;
1006 Decorator::CursorPositionedSignal& Decorator::CursorRePositionedSignal()
1008 return mCursorRePositionedSignal;
1012 * Decoration Positioning during Scrolling
1014 void Decorator::TextViewScrolled( Toolkit::TextView textView, Vector2 scrollPosition )
1016 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::TextViewScrolled\n");
1018 const Vector3& controlSize = mTextViewCharacterPositioning.GetTextView().GetCurrentSize(); // todo Could store size and only update in Control Size change.
1019 Size cursorSize( CURSOR_THICKNESS, 0.f );
1021 // Updates the cursor and grab handle position and visibility.
1022 if( mTextInputHandles.GetGrabHandle() || mCursor )
1025 size_t cursorTextPosition = GetCurrentCursorPosition();
1026 cursorSize.height = mTextViewCharacterPositioning.GetRowRectFromCharacterPosition( cursorTextPosition, min, max ).height;
1028 const Vector3 cursorPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( cursorTextPosition );
1030 bool mIsCursorInScrollArea = IsPositionWithinControl( cursorPosition, cursorSize, controlSize );
1031 bool mIsGrabHandleInScrollArea = mIsCursorInScrollArea;
1033 Vector2 actualGrabHandlePosition = cursorPosition.GetVectorXY();
1035 if( mTextInputHandles.GetGrabHandle() )
1037 ShowGrabHandle( mGrabHandleVisibility && mIsGrabHandleInScrollArea );
1038 PositionGrabHandle( cursorTextPosition );
1043 mCursor.SetVisible( mCursorVisibility && mIsCursorInScrollArea );
1044 DrawCursor( cursorTextPosition );
1045 mCursor.SetPosition( Vector3(actualGrabHandlePosition) + UI_OFFSET );
1049 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
1050 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
1052 // Updates the selection handles and highlighted text position and visibility.
1053 if( mTextInputHandles.GetSelectionHandleOne() && mTextInputHandles.GetSelectionHandleTwo() )
1055 const Vector3 cursorPositionOne = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition );
1056 const Vector3 cursorPositionTwo = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition );
1058 Size cursorSize( GetCursorSizeAt( mSelectionHandleOnePosition ) );
1059 const bool isSelectionHandleOneVisible = IsPositionWithinControl( cursorPositionOne, cursorSize, controlSize );
1061 cursorSize = GetCursorSizeAt( mSelectionHandleTwoPosition );
1062 const bool isSelectionHandleTwoVisible = IsPositionWithinControl( cursorPositionTwo, cursorSize, controlSize );
1064 mSelectionHandleOneActualPosition = cursorPositionOne.GetVectorXY();
1065 mSelectionHandleTwoActualPosition = cursorPositionTwo.GetVectorXY();
1067 selectionHandleOne.SetVisible( isSelectionHandleOneVisible );
1068 selectionHandleTwo.SetVisible( isSelectionHandleTwoVisible );
1070 PositionSelectionHandle( selectionHandleOne, mSelectionHandleOneActualPosition, mSelectionHandleOnePosition );
1071 PositionSelectionHandle( selectionHandleTwo, mSelectionHandleTwoActualPosition, mSelectionHandleTwoPosition );
1073 if( mHighlightMeshActor )
1075 mHighlightMeshActor.SetVisible( true );
1076 ShowUpdatedHighlight();
1081 void Decorator::StartScrollTimer()
1085 mScrollTimer = Timer::New( SCROLL_TICK_INTERVAL );
1086 mScrollTimer.TickSignal().Connect( this, &Decorator::OnScrollTimerTick );
1089 if( !mScrollTimer.IsRunning() )
1091 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::StartScrollTimer\n");
1092 mScrollTimer.Start();
1096 void Decorator::StopScrollTimer()
1100 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::StopScrollTimer\n");
1102 mScrollTimer.Stop();
1103 mScrollTimer.Reset();
1107 bool Decorator::OnScrollTimerTick()
1109 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::OnScrollTimerTick\n");
1111 if ( mGrabHandleVisibility && mTextInputHandles.GetGrabHandle() )
1113 std::size_t newGrabHandlePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mActualGrabHandlePosition.GetVectorXY() );
1114 if ( mGrabHandlePosition != newGrabHandlePosition )
1116 Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition();
1117 Vector2 scrollDelta = ( mActualGrabHandlePosition - mCurrentHandlePosition ).GetVectorXY();
1118 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextInputDecorationLayouter::OnScrollTimerTick scrollPosition(%f) scrollDelta(%f)\n", scrollPosition.x, scrollDelta.x);
1119 scrollPosition += scrollDelta;
1120 mTextViewCharacterPositioning.SetScrollPosition( scrollPosition );
1122 // If scroll position goes too far TextView will trim it to fit.
1123 if ( mTextViewCharacterPositioning.IsScrollPositionTrimmed() )
1128 mActualGrabHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newGrabHandlePosition ).GetVectorXY();
1132 Actor selectionHandleOne = mTextInputHandles.GetSelectionHandleOne();
1133 Actor selectionHandleTwo = mTextInputHandles.GetSelectionHandleTwo();
1135 if ( selectionHandleOne && selectionHandleTwo )
1137 std::size_t newHandleOnePosition = mTextViewCharacterPositioning.ReturnClosestIndex( mSelectionHandleOneActualPosition.GetVectorXY() );
1139 // todo duplicated code should be a function
1141 if ( mSelectionHandleOnePosition != newHandleOnePosition )
1143 const Vector3 actualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandleOnePosition );
1145 Vector2 scrollDelta = ( actualPosition - mSelectionHandleOneActualPosition ).GetVectorXY();
1147 Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition();
1148 scrollPosition += scrollDelta;
1149 mTextViewCharacterPositioning.SetScrollPosition( scrollPosition );
1151 if( mTextViewCharacterPositioning.IsScrollPositionTrimmed() )
1156 mSelectionHandleOnePosition = newHandleOnePosition;
1157 mSelectionHandleOneActualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition ).GetVectorXY();
1161 mSelectionHandleOneActualPosition.x += mScrollDisplacement.x;
1162 mSelectionHandleOneActualPosition.y += mScrollDisplacement.y;
1165 std::size_t newHandleTwoPosition = mTextViewCharacterPositioning.ReturnClosestIndex( mSelectionHandleTwoActualPosition.GetVectorXY() );
1167 if ( mSelectionHandleTwoPosition != newHandleTwoPosition )
1169 const Vector3 actualPosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( newHandleTwoPosition );
1171 Vector2 scrollDelta = ( actualPosition - mSelectionHandleTwoActualPosition ).GetVectorXY();
1173 Vector2 scrollPosition = mTextViewCharacterPositioning.GetScrollPosition();
1174 scrollPosition += scrollDelta;
1175 mTextViewCharacterPositioning.SetScrollPosition( scrollPosition );
1177 if( mTextViewCharacterPositioning.IsScrollPositionTrimmed() )
1182 mSelectionHandleTwoPosition = newHandleTwoPosition;
1183 mCurrentHandlePosition = mTextViewCharacterPositioning.GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition ).GetVectorXY();
1188 mSelectionHandleTwoActualPosition.x += mScrollDisplacement.x;
1189 mSelectionHandleTwoActualPosition.y += mScrollDisplacement.y;
1199 MarkupProcessor::StyledTextArray Decorator::GetSelectedText()
1201 MarkupProcessor::StyledTextArray currentSelectedText;
1203 if ( mHighlightMeshActor ) // Text Selected
1205 MarkupProcessor::StyledTextArray::iterator it = mTextViewCharacterPositioning.GetStyledTextArray().begin() + std::min(mSelectionHandleOnePosition, mSelectionHandleTwoPosition);
1206 MarkupProcessor::StyledTextArray::iterator end = mTextViewCharacterPositioning.GetStyledTextArray().begin() + std::max(mSelectionHandleOnePosition, mSelectionHandleTwoPosition);
1208 for(; it != end; ++it)
1210 MarkupProcessor::StyledText& styledText( *it );
1211 currentSelectedText.push_back( styledText );
1214 return currentSelectedText;
1219 } // namespace Toolkit