[Tizen] Revert "Changes after touch consumed behaviour change"
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / decorator / text-decorator.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/decorator/text-decorator.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/public-api/adaptor-framework/timer.h>
25 #include <dali/devel-api/common/stage.h>
26 #include <dali/public-api/events/touch-event.h>
27 #include <dali/public-api/events/pan-gesture.h>
28 #include <dali/public-api/object/property-notification.h>
29 #include <dali/public-api/rendering/geometry.h>
30 #include <dali/public-api/rendering/renderer.h>
31 #include <dali/devel-api/adaptor-framework/image-loading.h>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
35 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
36 #include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
37
38 #ifdef DEBUG_ENABLED
39 #define DECORATOR_DEBUG
40
41 #endif
42
43 #define MAKE_SHADER(A)#A
44
45 namespace
46 {
47 const char* VERTEX_SHADER = MAKE_SHADER(
48 attribute mediump vec2    aPosition;
49 uniform   highp mat4      uMvpMatrix;
50
51 void main()
52 {
53   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
54   gl_Position = uMvpMatrix * position;
55 }
56 );
57
58 const char* FRAGMENT_SHADER = MAKE_SHADER(
59 uniform      lowp vec4 uColor;
60
61 void main()
62 {
63   gl_FragColor = uColor;
64 }
65 );
66 }
67
68 namespace Dali
69 {
70 namespace Internal
71 {
72 namespace
73 {
74 #ifdef DECORATOR_DEBUG
75 Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_TEXT_DECORATOR") );
76 #endif
77 }
78 }
79 }
80
81
82 // Local Data
83 namespace
84 {
85 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
86 const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
87 const Dali::Vector3 ACTIVE_LAYER_ANCHOR_POINT( 0.5f, 0.5f, 0.5f );
88
89 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color. TODO: due some problems, maybe with the blending function in the text clipping, the color is fully opaque.
90
91 const Dali::Vector4 HANDLE_COLOR( 0.0f, (183.0f / 255.0f), (229.0f / 255.0f), 1.0f  );
92
93 const unsigned int CURSOR_BLINK_INTERVAL = 500u; ///< Cursor blink interval in milliseconds.
94 const float TO_MILLISECONDS = 1000.f;            ///< Converts from seconds to milliseconds.
95 const float TO_SECONDS = 1.f / TO_MILLISECONDS;  ///< Converts from milliseconds to seconds.
96
97 const unsigned int SCROLL_TICK_INTERVAL = 50u; ///< Scroll interval in milliseconds.
98 const float SCROLL_THRESHOLD = 10.f;           ///< Threshold in pixels close to the edges of the decorator boundaries from where the scroll timer starts to emit signals.
99 const float SCROLL_SPEED = 300.f;              ///< The scroll speed in pixels/second.
100
101 const float SCROLL_DISTANCE = SCROLL_SPEED * SCROLL_TICK_INTERVAL * TO_SECONDS; ///< Distance in pixels scrolled in one second.
102
103 const float CURSOR_WIDTH = 1.f; ///< The cursor's width in pixels.
104
105 const float POPUP_PADDING = 2.f; ///< Padding space between the highlight box and the text's popup.
106
107 typedef Dali::Vector<Dali::Vector4> QuadContainer;
108
109 /**
110  * @brief Takes a bounding rectangle in the local coordinates of an actor and returns the world coordinates Bounding Box.
111  * @param[in] boundingRectangle local bounding
112  * @param[out] Vector4 World coordinate bounding Box.
113  */
114 void LocalToWorldCoordinatesBoundingBox( const Dali::Rect<int>& boundingRectangle, Dali::Vector4& boundingBox )
115 {
116   // Convert to world coordinates and store as a Vector4 to be compatible with Property Notifications.
117   Dali::Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
118
119   const float originX = boundingRectangle.x - 0.5f * stageSize.width;
120   const float originY = boundingRectangle.y - 0.5f * stageSize.height;
121
122   boundingBox = Dali::Vector4( originX,
123                                originY,
124                                originX + boundingRectangle.width,
125                                originY + boundingRectangle.height );
126 }
127
128 void WorldToLocalCoordinatesBoundingBox( const Dali::Vector4& boundingBox, Dali::Rect<int>& boundingRectangle )
129 {
130   // Convert to local coordinates and store as a Dali::Rect.
131   Dali::Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
132
133   boundingRectangle.x = boundingBox.x + 0.5f * stageSize.width;
134   boundingRectangle.y = boundingBox.y + 0.5f * stageSize.height;
135   boundingRectangle.width = boundingBox.z - boundingBox.x;
136   boundingRectangle.height = boundingBox.w - boundingBox.y;
137 }
138
139 } // end of namespace
140
141 namespace Dali
142 {
143
144 namespace Toolkit
145 {
146
147 namespace Text
148 {
149
150 struct Decorator::Impl : public ConnectionTracker
151 {
152   enum ScrollDirection
153   {
154     SCROLL_NONE,
155     SCROLL_RIGHT,
156     SCROLL_LEFT,
157     SCROLL_TOP,
158     SCROLL_BOTTOM
159   };
160
161   struct CursorImpl
162   {
163     CursorImpl()
164     : color( Dali::Color::BLACK ),
165       position(),
166       cursorHeight( 0.0f ),
167       lineHeight( 0.0f ),
168       glyphOffset( 0.0f )
169     {
170     }
171
172     Vector4 color;
173     Vector2 position;
174     float cursorHeight;
175     float lineHeight;
176     float glyphOffset;
177   };
178
179   struct HandleImpl
180   {
181     HandleImpl()
182     : position(),
183       globalPosition(),
184       size(),
185       lineHeight( 0.0f ),
186       grabDisplacementX( 0.f ),
187       grabDisplacementY( 0.f ),
188       active( false ),
189       horizontallyVisible( false ),
190       verticallyVisible( false ),
191       pressed( false ),
192       verticallyFlippedPreferred( false ),
193       horizontallyFlipped( false ),
194       verticallyFlipped( false ),
195       verticallyFlippedOnTouch( false )
196     {
197     }
198
199     ImageView actor;
200     Actor grabArea;
201     ImageView markerActor;
202
203     Vector2 position;
204     Vector2 globalPosition;
205     Size    size;
206     float   lineHeight;              ///< Not the handle height
207     float   grabDisplacementX;
208     float   grabDisplacementY;
209     bool    active                     : 1;
210     bool    horizontallyVisible        : 1;
211     bool    verticallyVisible          : 1;
212     bool    pressed                    : 1;
213     bool    verticallyFlippedPreferred : 1; ///< Whether the handle is preferred to be vertically flipped.
214     bool    horizontallyFlipped        : 1; ///< Whether the handle has been horizontally flipped.
215     bool    verticallyFlipped          : 1; ///< Whether the handle has been vertically flipped.
216     bool    verticallyFlippedOnTouch   : 1; ///< Whether the handle is vertically flipped on touch.
217   };
218
219   struct PopupImpl
220   {
221     PopupImpl()
222     : position()
223     {
224     }
225
226     TextSelectionPopup actor;
227     Vector3 position;
228   };
229
230   Impl( ControllerInterface& controller,
231         TextSelectionPopupCallbackInterface& callbackInterface )
232   : mController( controller ),
233     mEnabledPopupButtons( TextSelectionPopup::NONE ),
234     mTextSelectionPopupCallbackInterface( callbackInterface ),
235     mHandleColor( HANDLE_COLOR ),
236     mBoundingBox(),
237     mHighlightColor( LIGHT_BLUE ),
238     mHighlightPosition( Vector2::ZERO ),
239     mHighlightSize( Vector2::ZERO ),
240     mControlSize( Vector2::ZERO ),
241     mHighlightOutlineOffset( 0.f ),
242     mActiveCursor( ACTIVE_CURSOR_NONE ),
243     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
244     mCursorBlinkDuration( 0.0f ),
245     mCursorWidth( CURSOR_WIDTH ),
246     mHandleScrolling( HANDLE_TYPE_COUNT ),
247     mHandleReleased( HANDLE_TYPE_COUNT ),
248     mScrollDirection( SCROLL_NONE ),
249     mScrollThreshold( SCROLL_THRESHOLD ),
250     mScrollSpeed( SCROLL_SPEED ),
251     mScrollDistance( SCROLL_DISTANCE ),
252     mTextDepth( 0u ),
253     mActiveCopyPastePopup( false ),
254     mPopupSetNewPosition( true ),
255     mCursorBlinkStatus( true ),
256     mDelayCursorBlink( false ),
257     mPrimaryCursorVisible( false ),
258     mSecondaryCursorVisible( false ),
259     mFlipSelectionHandlesOnCross( false ),
260     mFlipLeftSelectionHandleDirection( false ),
261     mFlipRightSelectionHandleDirection( false ),
262     mIsHandlePanning( false ),
263     mIsHandleCurrentlyCrossed( false ),
264     mIsHandlePreviouslyCrossed( false ),
265     mNotifyEndOfScroll( false ),
266     mHorizontalScrollingEnabled( false ),
267     mVerticalScrollingEnabled( false ),
268     mSmoothHandlePanEnabled( false ),
269     mIsHighlightBoxActive( false ),
270     mHidePrimaryCursorAndGrabHandle( false )
271   {
272     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
273     mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
274     SetupGestures();
275   }
276
277   /**
278    * Relayout of the decorations owned by the decorator.
279    * @param[in] size The Size of the UI control the decorator is adding it's decorations to.
280    */
281   void Relayout( const Vector2& size )
282   {
283     mControlSize = size;
284
285     // TODO - Remove this if nothing is active
286     CreateActiveLayer();
287
288     // Show or hide the cursors
289     CreateCursors();
290
291     if( mPrimaryCursor )
292     {
293       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
294       mPrimaryCursorVisible = (!mHidePrimaryCursorAndGrabHandle) && ( ( mControlSize.width - ( cursor.position.x + mCursorWidth ) > -Math::MACHINE_EPSILON_1000 ) &&
295                                 ( cursor.position.x > -Math::MACHINE_EPSILON_1000 ) &&
296                                 ( mControlSize.height - ( cursor.position.y + cursor.cursorHeight ) > -Math::MACHINE_EPSILON_1000 ) &&
297                                 ( cursor.position.y > -Math::MACHINE_EPSILON_1000 ) );
298       if( mPrimaryCursorVisible )
299       {
300         mPrimaryCursor.SetProperty( Actor::Property::POSITION, Vector2( cursor.position.x,
301                                     cursor.position.y ) );
302         mPrimaryCursor.SetProperty( Actor::Property::SIZE, Size( mCursorWidth, cursor.cursorHeight ) );
303       }
304       mPrimaryCursor.SetProperty( Actor::Property::VISIBLE, mPrimaryCursorVisible && mCursorBlinkStatus );
305     }
306     if( mSecondaryCursor )
307     {
308       const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
309       mSecondaryCursorVisible = ( ( mControlSize.width - ( cursor.position.x + mCursorWidth ) > -Math::MACHINE_EPSILON_1000 ) &&
310                                   ( cursor.position.x > -Math::MACHINE_EPSILON_1000 ) &&
311                                   ( mControlSize.height - ( cursor.position.y + cursor.cursorHeight ) > -Math::MACHINE_EPSILON_1000 ) &&
312                                   ( cursor.position.y > -Math::MACHINE_EPSILON_1000 ) );
313       if( mSecondaryCursorVisible )
314       {
315         mSecondaryCursor.SetProperty( Actor::Property::POSITION, Vector2( cursor.position.x,
316                                       cursor.position.y ) );
317         mSecondaryCursor.SetProperty( Actor::Property::SIZE, Size( mCursorWidth, cursor.cursorHeight ) );
318       }
319       mSecondaryCursor.SetProperty( Actor::Property::VISIBLE, mSecondaryCursorVisible && mCursorBlinkStatus );
320     }
321
322     // Show or hide the grab handle
323     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
324     bool newGrabHandlePosition = false;
325     grabHandle.horizontallyVisible = false;
326     grabHandle.verticallyVisible = false;
327     if( grabHandle.active )
328     {
329       grabHandle.horizontallyVisible = ( ( mControlSize.width - ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) ) > -Math::MACHINE_EPSILON_1000 ) &&
330                                          ( grabHandle.position.x > -Math::MACHINE_EPSILON_1000 ) );
331       grabHandle.verticallyVisible = ( ( ( mControlSize.height - grabHandle.lineHeight ) - grabHandle.position.y > -Math::MACHINE_EPSILON_1000 ) &&
332                                        ( grabHandle.position.y > -Math::MACHINE_EPSILON_1000 ) );
333
334       const bool isVisible = grabHandle.horizontallyVisible && grabHandle.verticallyVisible && (!mHidePrimaryCursorAndGrabHandle);
335       if( isVisible )
336       {
337         CreateGrabHandle();
338
339         // Sets the grab handle position and calculate if it needs to be vertically flipped if it exceeds the boundary box.
340         SetGrabHandlePosition();
341
342         // Sets the grab handle image according if it's pressed, flipped, etc.
343         SetHandleImage( GRAB_HANDLE );
344
345         newGrabHandlePosition = true;
346       }
347
348       if( grabHandle.actor )
349       {
350         grabHandle.actor.SetProperty( Actor::Property::VISIBLE, isVisible );
351       }
352     }
353     else if( grabHandle.actor )
354     {
355       grabHandle.actor.Unparent();
356     }
357
358     // Show or hide the selection handles/highlight
359     HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
360     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
361     bool newPrimaryHandlePosition = false;
362     bool newSecondaryHandlePosition = false;
363
364     primary.horizontallyVisible = ( ( mControlSize.width - primary.position.x > -Math::MACHINE_EPSILON_1000 ) &&
365                                     ( primary.position.x > -Math::MACHINE_EPSILON_1000 ) );
366     primary.verticallyVisible = ( ( ( mControlSize.height - primary.lineHeight ) - primary.position.y > -Math::MACHINE_EPSILON_1000 ) &&
367                                   ( primary.position.y + ( primary.verticallyFlipped ? 0.f : primary.lineHeight ) > -Math::MACHINE_EPSILON_1000 ) );
368     secondary.horizontallyVisible = ( ( mControlSize.width - secondary.position.x > -Math::MACHINE_EPSILON_1000 ) &&
369                                       ( secondary.position.x > -Math::MACHINE_EPSILON_1000 ) );
370     secondary.verticallyVisible = ( ( ( mControlSize.height - secondary.lineHeight ) - secondary.position.y > -Math::MACHINE_EPSILON_1000 ) &&
371                                     ( secondary.position.y + ( secondary.verticallyFlipped ? 0.f : secondary.lineHeight ) > -Math::MACHINE_EPSILON_1000 ) );
372
373     const bool primaryVisible = primary.horizontallyVisible && primary.verticallyVisible;
374     const bool secondaryVisible = secondary.horizontallyVisible && secondary.verticallyVisible;
375
376     if( primary.active || secondary.active )
377     {
378       if( primaryVisible || secondaryVisible )
379       {
380         CreateSelectionHandles();
381
382         if( primaryVisible )
383         {
384           SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
385
386           // Sets the primary handle image according if it's pressed, flipped, etc.
387           SetHandleImage( LEFT_SELECTION_HANDLE );
388
389           SetSelectionHandleMarkerSize( primary );
390
391           newPrimaryHandlePosition = true;
392         }
393
394         if( secondaryVisible )
395         {
396           SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
397
398           // Sets the secondary handle image according if it's pressed, flipped, etc.
399           SetHandleImage( RIGHT_SELECTION_HANDLE );
400
401           SetSelectionHandleMarkerSize( secondary );
402
403           newSecondaryHandlePosition = true;
404         }
405       }
406
407       if( primary.actor )
408       {
409         primary.actor.SetProperty( Actor::Property::VISIBLE, primaryVisible );
410       }
411       if( secondary.actor )
412       {
413         secondary.actor.SetProperty( Actor::Property::VISIBLE, secondaryVisible );
414       }
415
416     }
417     else
418     {
419       if( primary.actor )
420       {
421         primary.actor.Unparent();
422       }
423       if( secondary.actor )
424       {
425         secondary.actor.Unparent();
426       }
427     }
428
429     if( mIsHighlightBoxActive )
430     {
431       CreateHighlight();
432       UpdateHighlight();
433     }
434     else
435     {
436       if( mHighlightActor )
437       {
438         mHighlightActor.Unparent();
439       }
440     }
441
442     if( newGrabHandlePosition    ||
443         newPrimaryHandlePosition ||
444         newSecondaryHandlePosition )
445     {
446       // Setup property notifications to find whether the handles leave the boundaries of the current display.
447       SetupActiveLayerPropertyNotifications();
448     }
449
450     if( mActiveCopyPastePopup &&
451         ( primaryVisible || secondaryVisible ) )
452     {
453       ShowPopup();
454       mPopupSetNewPosition = true;
455     }
456     else
457     {
458       if( mCopyPastePopup.actor )
459       {
460         mCopyPastePopup.actor.HidePopup();
461         mPopupSetNewPosition = true;
462       }
463     }
464   }
465
466   void UpdatePositions( const Vector2& scrollOffset )
467   {
468     mCursor[PRIMARY_CURSOR].position += scrollOffset;
469     mCursor[SECONDARY_CURSOR].position += scrollOffset;
470     mHandle[ GRAB_HANDLE ].position += scrollOffset;
471     mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset;
472     mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset;
473     mHighlightPosition += scrollOffset;
474   }
475
476   void ShowPopup()
477   {
478     if( !mCopyPastePopup.actor )
479     {
480       return;
481     }
482
483     if( !mCopyPastePopup.actor.GetParent() )
484     {
485       mActiveLayer.Add( mCopyPastePopup.actor );
486     }
487
488     mCopyPastePopup.actor.RaiseAbove( mActiveLayer );
489     mCopyPastePopup.actor.ShowPopup();
490   }
491
492   float CalculateVerticalPopUpPosition( float halfHeight, bool preferBelow )
493   {
494     float yPosition = 0.f;
495
496     const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
497     const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
498     const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
499
500     if( primaryHandle.active || secondaryHandle.active )
501     {
502       // The origin of the decorator's coordinate system in world coords.
503       const Vector3 originWorldCoords = mActiveLayer.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION ) - mActiveLayer.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) * ACTIVE_LAYER_ANCHOR_POINT;
504
505       if( preferBelow )
506       {
507         // Find out if there is enough space for the popup at the bottom.
508         const float primaryBelowY = primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height;
509         const float secondaryBelowY = secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height;
510
511         float maxY = std::max( primaryBelowY, secondaryBelowY );
512
513         yPosition = halfHeight + maxY;
514
515         if( originWorldCoords.y + yPosition + halfHeight > mBoundingBox.w )
516         {
517           // Does not fit below.
518
519           // Try to fit first below the non active handle. Otherwise above the active handle.
520           if( RIGHT_SELECTION_HANDLE == mHandleReleased )
521           {
522             if( primaryBelowY < secondaryBelowY )
523             {
524               yPosition = halfHeight + primaryBelowY;
525             }
526             else
527             {
528               yPosition = primaryHandle.position.y - primaryHandle.size.height - halfHeight;
529             }
530           }
531           else if( LEFT_SELECTION_HANDLE == mHandleReleased )
532           {
533             if( secondaryBelowY < primaryBelowY )
534             {
535               yPosition = halfHeight + secondaryBelowY;
536             }
537             else
538             {
539               yPosition = secondaryHandle.position.y - secondaryHandle.size.height - halfHeight;
540             }
541           }
542
543           // Check the handle is whithin the decoration box.
544           if( originWorldCoords.y + yPosition < mBoundingBox.y )
545           {
546             yPosition = mBoundingBox.y - originWorldCoords.y + halfHeight;
547           }
548
549           if( originWorldCoords.y + yPosition > mBoundingBox.w )
550           {
551             yPosition = mBoundingBox.w - originWorldCoords.y - halfHeight;
552           }
553         }
554       } // preferBelow
555       else
556       {
557         // Find out if there is enough space for the popup at the top.
558         const float primaryTopY = primaryHandle.position.y - primaryHandle.size.height;
559         const float secondaryTopY = secondaryHandle.position.y - secondaryHandle.size.height;
560
561         float minY = std::min( primaryTopY, secondaryTopY );
562
563         yPosition = -halfHeight + minY;
564       } // !preferBelow
565     } // ( primaryHandle.active || secondaryHandle.active )
566     else if( grabHandle.active )
567     {
568       if( preferBelow )
569       {
570         yPosition = halfHeight + grabHandle.lineHeight + grabHandle.size.height + grabHandle.position.y;
571       }
572       else
573       {
574         yPosition = -halfHeight + grabHandle.position.y - POPUP_PADDING;
575       }
576     }
577
578     return yPosition;
579   }
580
581   void ConstrainPopupPosition( const Vector3& popupHalfSize )
582   {
583     // Check if the popup is within the boundaries of the decoration box.
584
585     // Check first the horizontal dimension. If is not within the boundaries, it calculates the offset.
586
587     // The origin of the decorator's coordinate system in world coords.
588     const Vector3 originWorldCoords = mActiveLayer.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION ) - mActiveLayer.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) * ACTIVE_LAYER_ANCHOR_POINT;
589
590     // The popup's position in world coords.
591     Vector3 popupPositionWorldCoords = originWorldCoords + mCopyPastePopup.position;
592
593     if( popupPositionWorldCoords.x - popupHalfSize.width < mBoundingBox.x )
594     {
595        mCopyPastePopup.position.x += mBoundingBox.x - ( popupPositionWorldCoords.x - popupHalfSize.width );
596     }
597     else if( popupPositionWorldCoords.x + popupHalfSize.width > mBoundingBox.z )
598     {
599        mCopyPastePopup.position.x += mBoundingBox.z - ( popupPositionWorldCoords.x + popupHalfSize.width );
600     }
601
602     // Check the vertical dimension. If the popup doesn't fit above the handles, it looks for a valid position below.
603     if( popupPositionWorldCoords.y - popupHalfSize.height < mBoundingBox.y )
604     {
605       mCopyPastePopup.position.y = CalculateVerticalPopUpPosition( popupHalfSize.height, true ); // true -> prefer to set the popup's position below.
606     }
607   }
608
609   void SetPopupPosition( Actor actor )
610   {
611     if( !mActiveCopyPastePopup )
612     {
613       return;
614     }
615
616     // Retrieves the popup's size after relayout.
617     const Vector3 popupSize( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
618     const Vector3 popupHalfSize = popupSize * 0.5f;
619
620     if( mPopupSetNewPosition )
621     {
622       const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
623       const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
624       const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
625
626       if( primaryHandle.active || secondaryHandle.active )
627       {
628         const float minHandleXPosition = std::min( primaryHandle.position.x, secondaryHandle.position.x );
629         const float maxHandleXPosition = std::max( primaryHandle.position.x, secondaryHandle.position.x );
630
631         mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) * 0.5f );
632
633         const float primaryY = -popupHalfSize.height + primaryHandle.position.y - ( primaryHandle.verticallyFlipped ? primaryHandle.size.height : POPUP_PADDING );
634         const float secondaryY = -popupHalfSize.height + secondaryHandle.position.y - ( secondaryHandle.verticallyFlipped ? secondaryHandle.size.height : POPUP_PADDING );
635
636         mCopyPastePopup.position.y = std::min( primaryY, secondaryY );
637       }
638       else if( grabHandle.active )
639       {
640         mCopyPastePopup.position.x = grabHandle.position.x;
641
642         mCopyPastePopup.position.y = -popupHalfSize.height + grabHandle.position.y - ( grabHandle.verticallyFlipped ? grabHandle.size.height : POPUP_PADDING );
643       }
644     } // mPopupSetNewPosition
645
646     // It may change the popup's position to fit within the decoration box.
647     ConstrainPopupPosition( popupHalfSize );
648
649     SetUpPopupPositionNotifications( popupHalfSize );
650
651     // Prevent pixel mis-alignment by rounding down.
652     mCopyPastePopup.position.x = floorf( mCopyPastePopup.position.x );
653     mCopyPastePopup.position.y = floorf( mCopyPastePopup.position.y );
654
655     mCopyPastePopup.actor.SetProperty( Actor::Property::POSITION, mCopyPastePopup.position );
656     mPopupSetNewPosition = false;
657   }
658
659   void CreateCursor( Control& cursor, const Vector4& color )
660   {
661     cursor = Control::New();
662     cursor.SetBackgroundColor( color );
663     cursor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
664     cursor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
665   }
666
667   // Add or Remove cursor(s) from parent
668   void CreateCursors()
669   {
670     if( mActiveCursor == ACTIVE_CURSOR_NONE )
671     {
672       if( mPrimaryCursor )
673       {
674         mPrimaryCursor.Unparent();
675       }
676       if( mSecondaryCursor )
677       {
678         mSecondaryCursor.Unparent();
679       }
680     }
681     else
682     {
683       // Create Primary and or Secondary Cursor(s) if active and add to parent
684       if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ||
685            mActiveCursor == ACTIVE_CURSOR_BOTH )
686       {
687         if ( !mPrimaryCursor )
688         {
689           CreateCursor( mPrimaryCursor, mCursor[PRIMARY_CURSOR].color );
690 #ifdef DECORATOR_DEBUG
691           mPrimaryCursor.SetProperty( Dali::Actor::Property::NAME, "PrimaryCursorActor" );
692 #endif
693         }
694
695         if( !mPrimaryCursor.GetParent() )
696         {
697           mActiveLayer.Add( mPrimaryCursor );
698         }
699       }
700
701       if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
702       {
703         if ( !mSecondaryCursor )
704         {
705           CreateCursor( mSecondaryCursor, mCursor[SECONDARY_CURSOR].color );
706 #ifdef DECORATOR_DEBUG
707           mSecondaryCursor.SetProperty( Dali::Actor::Property::NAME, "SecondaryCursorActor" );
708 #endif
709         }
710
711         if( !mSecondaryCursor.GetParent() )
712         {
713           mActiveLayer.Add( mSecondaryCursor );
714         }
715       }
716       else
717       {
718         if( mSecondaryCursor )
719         {
720           mSecondaryCursor.Unparent();
721         }
722       }
723     }
724   }
725
726   bool OnCursorBlinkTimerTick()
727   {
728     if( !mDelayCursorBlink )
729     {
730       // Cursor blinking
731       if ( mPrimaryCursor )
732       {
733         mPrimaryCursor.SetProperty( Actor::Property::VISIBLE, mPrimaryCursorVisible && mCursorBlinkStatus );
734       }
735       if ( mSecondaryCursor )
736       {
737         mSecondaryCursor.SetProperty( Actor::Property::VISIBLE, mSecondaryCursorVisible && mCursorBlinkStatus );
738       }
739
740       mCursorBlinkStatus = !mCursorBlinkStatus;
741     }
742     else
743     {
744       // Resume blinking
745       mDelayCursorBlink = false;
746     }
747
748     return true;
749   }
750
751   void SetupGestures()
752   {
753     // Will consume tap gestures on handles.
754     mTapDetector = TapGestureDetector::New();
755
756     // Will consume double tap gestures on handles.
757     mTapDetector.SetMaximumTapsRequired( 2u );
758
759     // Will consume long press gestures on handles.
760     mLongPressDetector = LongPressGestureDetector::New();
761
762     // Detects pan gestures on handles.
763     mPanDetector = PanGestureDetector::New();
764     mPanDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
765   }
766
767   void CreateActiveLayer()
768   {
769     if( !mActiveLayer )
770     {
771       mActiveLayer = Actor::New();
772 #ifdef DECORATOR_DEBUG
773       mActiveLayer.SetProperty( Actor::Property::NAME, "ActiveLayerActor" );
774 #endif
775
776       mActiveLayer.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
777       mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
778
779       // Add the active layer telling the controller it doesn't need clipping.
780       mController.AddDecoration( mActiveLayer, false );
781     }
782
783     mActiveLayer.RaiseToTop();
784   }
785
786   void SetSelectionHandleMarkerSize( HandleImpl& handle )
787   {
788     if( handle.markerActor )
789     {
790       handle.markerActor.SetProperty( Actor::Property::SIZE, Vector2( 0, handle.lineHeight ) );
791     }
792   }
793
794   void CreateGrabHandle()
795   {
796     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
797     if( !grabHandle.actor )
798     {
799       if( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED].size() )
800       {
801         grabHandle.actor = ImageView::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
802         GetImpl( grabHandle.actor).SetDepthIndex( DepthIndex::DECORATION );
803         grabHandle.actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
804
805         // Area that Grab handle responds to, larger than actual handle so easier to move
806 #ifdef DECORATOR_DEBUG
807         grabHandle.actor.SetProperty( Dali::Actor::Property::NAME, "GrabHandleActor" );
808         if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) )
809         {
810           grabHandle.grabArea = Control::New();
811           Toolkit::Control control = Toolkit::Control::DownCast( grabHandle.grabArea );
812           control.SetBackgroundColor( Vector4( 1.0f, 1.0f, 1.0f, 0.5f ) );
813           grabHandle.grabArea.SetProperty( Dali::Actor::Property::NAME, "GrabArea" );
814         }
815         else
816         {
817           grabHandle.grabArea = Actor::New();
818           grabHandle.grabArea.SetProperty( Dali::Actor::Property::NAME, "GrabArea" );
819         }
820 #else
821         grabHandle.grabArea = Actor::New();
822 #endif
823
824         grabHandle.grabArea.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
825         grabHandle.grabArea.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
826         grabHandle.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
827         grabHandle.grabArea.SetProperty( Actor::Property::SIZE_MODE_FACTOR, DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
828         grabHandle.actor.Add( grabHandle.grabArea );
829         grabHandle.actor.SetProperty( Actor::Property::COLOR, mHandleColor );
830
831         grabHandle.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
832
833         // The grab handle's actor is attached to the tap and long press detectors in order to consume these events.
834         // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
835         mTapDetector.Attach( grabHandle.actor );
836         mLongPressDetector.Attach( grabHandle.actor );
837
838         // The grab handle's area is attached to the pan detector.
839         // The OnPan() method is connected to the signals emitted by the pan detector.
840         mPanDetector.Attach( grabHandle.grabArea );
841
842         mActiveLayer.Add( grabHandle.actor );
843       }
844     }
845
846     if( grabHandle.actor && !grabHandle.actor.GetParent() )
847     {
848       mActiveLayer.Add( grabHandle.actor );
849     }
850   }
851
852   void CreateHandleMarker( HandleImpl& handle, const std::string& image, HandleType handleType )
853   {
854     if( image.size() )
855     {
856       handle.markerActor = ImageView::New( image );
857       handle.markerActor.SetProperty( Actor::Property::COLOR, mHandleColor );
858       handle.actor.Add( handle.markerActor );
859
860       handle.markerActor.SetResizePolicy ( ResizePolicy::FIXED, Dimension::HEIGHT );
861
862       if( LEFT_SELECTION_HANDLE == handleType )
863       {
864         handle.markerActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT );
865         handle.markerActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT );
866       }
867       else if( RIGHT_SELECTION_HANDLE == handleType )
868       {
869         handle.markerActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_LEFT );
870         handle.markerActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
871       }
872     }
873   }
874
875   void CreateSelectionHandles()
876   {
877     HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
878     if( !primary.actor )
879     {
880       if( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED].size() )
881       {
882         primary.actor = ImageView::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
883 #ifdef DECORATOR_DEBUG
884         primary.actor.SetProperty( Dali::Actor::Property::NAME,"SelectionHandleOne");
885 #endif
886         primary.actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
887         GetImpl( primary.actor ).SetDepthIndex( DepthIndex::DECORATION );
888         primary.actor.SetProperty( Actor::Property::COLOR, mHandleColor );
889
890         primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
891 #ifdef DECORATOR_DEBUG
892         primary.grabArea.SetProperty( Dali::Actor::Property::NAME,"SelectionHandleOneGrabArea");
893 #endif
894         primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
895         primary.grabArea.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
896         primary.grabArea.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
897         primary.grabArea.SetProperty( Actor::Property::SIZE_MODE_FACTOR, DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
898
899         primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
900
901         // The handle's actor is attached to the tap and long press detectors in order to consume these events.
902         // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
903         mTapDetector.Attach( primary.actor );
904         mLongPressDetector.Attach( primary.actor );
905
906         // The handle's area is attached to the pan detector.
907         // The OnPan() method is connected to the signals emitted by the pan detector.
908         mPanDetector.Attach( primary.grabArea );
909
910         primary.actor.Add( primary.grabArea );
911
912         CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
913       }
914     }
915
916     if( primary.actor && !primary.actor.GetParent() )
917     {
918       mActiveLayer.Add( primary.actor );
919     }
920
921     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
922     if( !secondary.actor )
923     {
924       if( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED].size() )
925       {
926         secondary.actor = ImageView::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
927 #ifdef DECORATOR_DEBUG
928         secondary.actor.SetProperty( Dali::Actor::Property::NAME,"SelectionHandleTwo");
929 #endif
930         secondary.actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT ); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text.
931         GetImpl( secondary.actor ).SetDepthIndex( DepthIndex::DECORATION );
932         secondary.actor.SetProperty( Actor::Property::COLOR, mHandleColor );
933
934         secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
935 #ifdef DECORATOR_DEBUG
936         secondary.grabArea.SetProperty( Dali::Actor::Property::NAME,"SelectionHandleTwoGrabArea");
937 #endif
938         secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
939         secondary.grabArea.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
940         secondary.grabArea.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
941         secondary.grabArea.SetProperty( Actor::Property::SIZE_MODE_FACTOR, DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
942
943         secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
944
945         // The handle's actor is attached to the tap and long press detectors in order to consume these events.
946         // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
947         mTapDetector.Attach( secondary.actor );
948         mLongPressDetector.Attach( secondary.actor );
949
950         // The handle's area is attached to the pan detector.
951         // The OnPan() method is connected to the signals emitted by the pan detector.
952         mPanDetector.Attach( secondary.grabArea );
953
954         secondary.actor.Add( secondary.grabArea );
955
956         CreateHandleMarker( secondary, mHandleImages[RIGHT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], RIGHT_SELECTION_HANDLE  );
957       }
958     }
959
960     if( secondary.actor && !secondary.actor.GetParent() )
961     {
962       mActiveLayer.Add( secondary.actor );
963     }
964   }
965
966   void CalculateHandleWorldCoordinates( HandleImpl& handle, Vector2& position )
967   {
968     // Gets the world position of the active layer. The active layer is where the handles are added.
969     const Vector3 parentWorldPosition = mActiveLayer.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION );
970
971     // The grab handle position in world coords.
972     // The active layer's world position is the center of the active layer. The origin of the
973     // coord system of the handles is the top left of the active layer.
974     position.x = parentWorldPosition.x - 0.5f * mControlSize.width + handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f );
975     position.y = parentWorldPosition.y - 0.5f * mControlSize.height + handle.position.y + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f );
976   }
977
978   void SetGrabHandlePosition()
979   {
980     // Reference to the grab handle.
981     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
982
983     // Transforms the handle position into world coordinates.
984     // @note This is not the same value as grabHandle.actor.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION )
985     // as it's transforming the handle's position set by the text-controller and not
986     // the final position set to the actor. Another difference is the.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION )
987     // retrieves the position of the center of the actor but the handle's position set
988     // by the text controller is not the center of the actor.
989     Vector2 grabHandleWorldPosition;
990     CalculateHandleWorldCoordinates( grabHandle, grabHandleWorldPosition );
991
992     // Check if the grab handle exceeds the boundaries of the decoration box.
993     // At the moment only the height is checked for the grab handle.
994
995     grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
996                                      ( ( grabHandleWorldPosition.y - grabHandle.size.height ) > mBoundingBox.y ) ) ||
997                                    ( grabHandleWorldPosition.y + grabHandle.lineHeight + grabHandle.size.height > mBoundingBox.w );
998
999     // The grab handle 'y' position in local coords.
1000     // If the grab handle exceeds the bottom of the decoration box,
1001     // set the 'y' position to the top of the line.
1002     // The SetGrabHandleImage() method will change the orientation.
1003     const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
1004
1005     if( grabHandle.actor )
1006     {
1007       grabHandle.actor.SetProperty( Actor::Property::POSITION, Vector2( grabHandle.position.x + floor( 0.5f * mCursorWidth ) + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementX : 0.f ),
1008                                     yLocalPosition + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementY : 0.f ) ) );
1009     }
1010   }
1011
1012   void SetSelectionHandlePosition( HandleType type )
1013   {
1014     const bool isPrimaryHandle = LEFT_SELECTION_HANDLE == type;
1015
1016     // Reference to the selection handle.
1017     HandleImpl& handle = mHandle[type];
1018
1019     // Transforms the handle position into world coordinates.
1020     // @note This is not the same value as handle.actor.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION )
1021     // as it's transforming the handle's position set by the text-controller and not
1022     // the final position set to the actor. Another difference is the.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_POSITION )
1023     // retrieves the position of the center of the actor but the handle's position set
1024     // by the text controller is not the center of the actor.
1025     Vector2 handleWorldPosition;
1026     CalculateHandleWorldCoordinates( handle, handleWorldPosition );
1027
1028     // Whether to flip the handle (horizontally).
1029     bool flipHandle = isPrimaryHandle ? mFlipLeftSelectionHandleDirection : mFlipRightSelectionHandleDirection;
1030
1031     // Whether to flip the handles if they are crossed.
1032     bool crossFlip = false;
1033     if( mFlipSelectionHandlesOnCross || !mIsHandlePanning )
1034     {
1035       crossFlip = mIsHandleCurrentlyCrossed;
1036     }
1037
1038     // Whether the handle was crossed before start the panning.
1039     const bool isHandlePreviouslyCrossed = mFlipSelectionHandlesOnCross ? false : mIsHandlePreviouslyCrossed;
1040
1041     // Does not flip if both conditions are true (double flip)
1042     flipHandle = flipHandle != ( crossFlip || isHandlePreviouslyCrossed );
1043
1044     // Will flip the handles vertically if the user prefers it.
1045     bool verticallyFlippedPreferred = handle.verticallyFlippedPreferred;
1046
1047     if( crossFlip || isHandlePreviouslyCrossed )
1048     {
1049       if( isPrimaryHandle )
1050       {
1051         verticallyFlippedPreferred = mHandle[RIGHT_SELECTION_HANDLE].verticallyFlippedPreferred;
1052       }
1053       else
1054       {
1055         verticallyFlippedPreferred = mHandle[LEFT_SELECTION_HANDLE].verticallyFlippedPreferred;
1056       }
1057     }
1058
1059     // Check if the selection handle exceeds the boundaries of the decoration box.
1060     const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
1061     const bool exceedsRightEdge = ( isPrimaryHandle ? flipHandle : !flipHandle ) && ( handleWorldPosition.x + handle.size.width > mBoundingBox.z );
1062
1063     // Does not flip if both conditions are true (double flip)
1064     flipHandle = flipHandle != ( exceedsLeftEdge || exceedsRightEdge );
1065
1066     if( flipHandle )
1067     {
1068       if( handle.actor && !handle.horizontallyFlipped )
1069       {
1070         // Change the anchor point to flip the image.
1071         handle.actor.SetProperty( Actor::Property::ANCHOR_POINT, isPrimaryHandle ? AnchorPoint::TOP_LEFT : AnchorPoint::TOP_RIGHT );
1072
1073         handle.horizontallyFlipped = true;
1074       }
1075     }
1076     else
1077     {
1078       if( handle.actor && handle.horizontallyFlipped )
1079       {
1080         // Reset the anchor point.
1081         handle.actor.SetProperty( Actor::Property::ANCHOR_POINT, isPrimaryHandle ? AnchorPoint::TOP_RIGHT : AnchorPoint::TOP_LEFT );
1082
1083         handle.horizontallyFlipped = false;
1084       }
1085     }
1086
1087     // Whether to flip the handle vertically.
1088     handle.verticallyFlipped = ( verticallyFlippedPreferred &&
1089                                  ( ( handleWorldPosition.y - handle.size.height ) > mBoundingBox.y ) ) ||
1090                                ( handleWorldPosition.y + handle.lineHeight + handle.size.height > mBoundingBox.w );
1091
1092     // The primary selection handle 'y' position in local coords.
1093     // If the handle exceeds the bottom of the decoration box,
1094     // set the 'y' position to the top of the line.
1095     // The SetHandleImage() method will change the orientation.
1096     const float yLocalPosition = handle.verticallyFlipped ? handle.position.y : handle.position.y + handle.lineHeight;
1097
1098     if( handle.actor )
1099     {
1100       handle.actor.SetProperty( Actor::Property::POSITION, Vector2( handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f ),
1101                                 yLocalPosition + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f ) ) );
1102     }
1103   }
1104
1105   void SetHandleImage( HandleType type )
1106   {
1107     HandleImpl& handle = mHandle[type];
1108
1109     HandleType markerType = HANDLE_TYPE_COUNT;
1110     // If the selection handle is flipped it chooses the image of the other selection handle. Does nothing for the grab handle.
1111     if( LEFT_SELECTION_HANDLE == type )
1112     {
1113       type = handle.horizontallyFlipped ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE;
1114       markerType = handle.horizontallyFlipped ? RIGHT_SELECTION_HANDLE_MARKER : LEFT_SELECTION_HANDLE_MARKER;
1115     }
1116     else if( RIGHT_SELECTION_HANDLE == type )
1117     {
1118       type = handle.horizontallyFlipped ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE;
1119       markerType = handle.horizontallyFlipped ? LEFT_SELECTION_HANDLE_MARKER : RIGHT_SELECTION_HANDLE_MARKER;
1120     }
1121
1122     // Chooses between the released or pressed image. It checks whether the pressed image exists.
1123     if( handle.actor )
1124     {
1125       const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED].size() ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
1126
1127       handle.actor.SetImage( mHandleImages[type][imageType] );
1128     }
1129
1130     if( HANDLE_TYPE_COUNT != markerType )
1131     {
1132       if( handle.markerActor )
1133       {
1134         const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED].size() ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
1135         handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
1136       }
1137     }
1138
1139     // Whether to flip the handle vertically.
1140     if( handle.actor )
1141     {
1142       handle.actor.SetProperty( Actor::Property::ORIENTATION, Quaternion( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS ) );
1143     }
1144   }
1145
1146   void CreateHighlight()
1147   {
1148     if( !mHighlightActor )
1149     {
1150       mHighlightActor = Actor::New();
1151
1152       mHighlightActor.SetProperty( Dali::Actor::Property::NAME, "HighlightActor" );
1153       mHighlightActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
1154       mHighlightActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
1155       mHighlightActor.SetProperty( Actor::Property::COLOR, mHighlightColor );
1156       mHighlightActor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_COLOR );
1157     }
1158
1159     // Add the highlight box telling the controller it needs clipping.
1160     mController.AddDecoration( mHighlightActor, true );
1161   }
1162
1163   void UpdateHighlight()
1164   {
1165     if ( mHighlightActor )
1166     {
1167       // Sets the position of the highlight actor inside the decorator.
1168       mHighlightActor.SetProperty( Actor::Property::POSITION, Vector2( mHighlightPosition.x + mHighlightOutlineOffset,
1169                                    mHighlightPosition.y + mHighlightOutlineOffset ) );
1170
1171       const unsigned int numberOfQuads = mHighlightQuadList.Count();
1172       if( 0u != numberOfQuads )
1173       {
1174         // Set the size of the highlighted text to the actor.
1175         mHighlightActor.SetProperty( Actor::Property::SIZE, mHighlightSize );
1176
1177         // Used to translate the vertices given in decorator's coords to the mHighlightActor's local coords.
1178         const float offsetX = mHighlightPosition.x + 0.5f * mHighlightSize.width;
1179         const float offsetY = mHighlightPosition.y + 0.5f * mHighlightSize.height;
1180
1181         Vector<Vector2> vertices;
1182         Vector<unsigned short> indices;
1183
1184         vertices.Reserve( 4u * numberOfQuads );
1185         indices.Reserve( 6u * numberOfQuads );
1186
1187         // Index to the vertex.
1188         unsigned int v = 0u;
1189
1190         // Traverse all quads.
1191         for( Vector<Vector4>::ConstIterator it = mHighlightQuadList.Begin(),
1192                endIt = mHighlightQuadList.End();
1193              it != endIt;
1194              ++it, v += 4u )
1195         {
1196           const Vector4& quad = *it;
1197
1198           Vector2 vertex;
1199
1200           // top-left (v+0)
1201           vertex.x = quad.x - offsetX;
1202           vertex.y = quad.y - offsetY;
1203           vertices.PushBack( vertex );
1204
1205           // top-right (v+1)
1206           vertex.x = quad.z - offsetX;
1207           vertex.y = quad.y - offsetY;
1208           vertices.PushBack( vertex );
1209
1210           // bottom-left (v+2)
1211           vertex.x = quad.x - offsetX;
1212           vertex.y = quad.w - offsetY;
1213           vertices.PushBack( vertex );
1214
1215           // bottom-right (v+3)
1216           vertex.x = quad.z - offsetX;
1217           vertex.y = quad.w - offsetY;
1218           vertices.PushBack( vertex );
1219
1220           // triangle A (3, 1, 0)
1221           indices.PushBack( v + 3 );
1222           indices.PushBack( v + 1 );
1223           indices.PushBack( v );
1224
1225           // triangle B (0, 2, 3)
1226           indices.PushBack( v );
1227           indices.PushBack( v + 2 );
1228           indices.PushBack( v + 3 );
1229         }
1230
1231         if( ! mQuadVertices )
1232         {
1233           mQuadVertices = VertexBuffer::New( mQuadVertexFormat );
1234         }
1235
1236         mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
1237
1238         if( !mQuadGeometry )
1239         {
1240           mQuadGeometry = Geometry::New();
1241           mQuadGeometry.AddVertexBuffer( mQuadVertices );
1242         }
1243         mQuadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
1244
1245         if( !mHighlightRenderer )
1246         {
1247           mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightShader );
1248           mHighlightActor.AddRenderer( mHighlightRenderer );
1249         }
1250       }
1251
1252       mHighlightQuadList.Clear();
1253
1254       if( mHighlightRenderer )
1255       {
1256         mHighlightRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mTextDepth - 2 ); // text is rendered at mTextDepth and text's shadow at mTextDepth -1u.
1257       }
1258     }
1259   }
1260
1261   void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture )
1262   {
1263     GestureState state = gesture.GetState();
1264     if( GestureState::STARTED == state )
1265     {
1266       handle.grabDisplacementX = handle.grabDisplacementY = 0.f;
1267
1268       handle.globalPosition.x = handle.position.x;
1269       handle.globalPosition.y = handle.position.y;
1270     }
1271
1272     const Vector2& displacement = gesture.GetDisplacement();
1273     handle.grabDisplacementX += displacement.x;
1274     handle.grabDisplacementY += ( handle.verticallyFlipped ? -displacement.y : displacement.y );
1275
1276     const float x = handle.globalPosition.x + handle.grabDisplacementX;
1277     const float y = handle.globalPosition.y + handle.grabDisplacementY + 0.5f * handle.lineHeight;
1278     const float yVerticallyFlippedCorrected = y - ( handle.verticallyFlippedOnTouch ? handle.lineHeight : 0.f );
1279
1280     if( ( GestureState::STARTED    == state ) ||
1281         ( GestureState::CONTINUING == state ) )
1282     {
1283       Vector2 targetSize;
1284       mController.GetTargetSize( targetSize );
1285
1286       if( mHorizontalScrollingEnabled &&
1287           ( x < mScrollThreshold ) )
1288       {
1289         mScrollDirection = SCROLL_RIGHT;
1290         mHandleScrolling = type;
1291         StartScrollTimer();
1292       }
1293       else if( mHorizontalScrollingEnabled &&
1294                ( x > targetSize.width - mScrollThreshold ) )
1295       {
1296         mScrollDirection = SCROLL_LEFT;
1297         mHandleScrolling = type;
1298         StartScrollTimer();
1299       }
1300       else if( mVerticalScrollingEnabled &&
1301                ( yVerticallyFlippedCorrected < mScrollThreshold ) )
1302       {
1303         mScrollDirection = SCROLL_TOP;
1304         mHandleScrolling = type;
1305         StartScrollTimer();
1306       }
1307       else if( mVerticalScrollingEnabled &&
1308                ( yVerticallyFlippedCorrected + handle.lineHeight > targetSize.height - mScrollThreshold ) )
1309       {
1310         mScrollDirection = SCROLL_BOTTOM;
1311         mHandleScrolling = type;
1312         StartScrollTimer();
1313       }
1314       else
1315       {
1316         mHandleScrolling = HANDLE_TYPE_COUNT;
1317         StopScrollTimer();
1318         mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
1319       }
1320
1321       mIsHandlePanning = true;
1322     }
1323     else if( ( GestureState::FINISHED  == state ) ||
1324              ( GestureState::CANCELLED == state ) )
1325     {
1326       if( mScrollTimer &&
1327           ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
1328       {
1329         mNotifyEndOfScroll = false;
1330         mHandleScrolling = HANDLE_TYPE_COUNT;
1331         StopScrollTimer();
1332         mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
1333       }
1334       else
1335       {
1336         mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
1337       }
1338
1339       if( handle.actor )
1340       {
1341         handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
1342       }
1343       handle.pressed = false;
1344
1345       mIsHandlePanning = false;
1346     }
1347   }
1348
1349   void OnPan( Actor actor, const PanGesture& gesture )
1350   {
1351     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
1352     HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
1353     HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
1354
1355     if( actor == grabHandle.grabArea )
1356     {
1357       DoPan( grabHandle, GRAB_HANDLE, gesture );
1358     }
1359     else if( actor == primarySelectionHandle.grabArea )
1360     {
1361       DoPan( primarySelectionHandle, LEFT_SELECTION_HANDLE, gesture );
1362     }
1363     else if( actor == secondarySelectionHandle.grabArea )
1364     {
1365       DoPan( secondarySelectionHandle, RIGHT_SELECTION_HANDLE, gesture );
1366     }
1367   }
1368
1369   bool OnGrabHandleTouched( Actor actor, const TouchEvent& touch )
1370   {
1371     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
1372
1373     // Switch between pressed/release grab-handle images
1374     if( touch.GetPointCount() > 0 &&
1375         grabHandle.actor )
1376     {
1377       const PointState::Type state = touch.GetState( 0 );
1378
1379       if( PointState::DOWN == state )
1380       {
1381         grabHandle.pressed = true;
1382       }
1383       else if( ( PointState::UP == state ) ||
1384                ( PointState::INTERRUPTED == state ) )
1385       {
1386         grabHandle.pressed = false;
1387       }
1388
1389       SetHandleImage( GRAB_HANDLE );
1390     }
1391
1392     // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
1393     return true;
1394   }
1395
1396   bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
1397   {
1398     HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
1399
1400     // Switch between pressed/release selection handle images
1401     if( touch.GetPointCount() > 0 &&
1402         primarySelectionHandle.actor )
1403     {
1404       const PointState::Type state = touch.GetState( 0 );
1405
1406       if( PointState::DOWN == state )
1407       {
1408         primarySelectionHandle.pressed = true;
1409         primarySelectionHandle.verticallyFlippedOnTouch = primarySelectionHandle.verticallyFlipped;
1410       }
1411       else if( ( PointState::UP == state ) ||
1412                ( PointState::INTERRUPTED == state ) )
1413       {
1414         primarySelectionHandle.pressed = false;
1415         mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
1416         mIsHandlePanning = false;
1417         mHandleReleased = LEFT_SELECTION_HANDLE;
1418       }
1419
1420       SetHandleImage( LEFT_SELECTION_HANDLE );
1421     }
1422
1423     // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
1424     return true;
1425   }
1426
1427   bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
1428   {
1429     HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
1430
1431     // Switch between pressed/release selection handle images
1432     if( touch.GetPointCount() > 0 &&
1433         secondarySelectionHandle.actor )
1434     {
1435       const PointState::Type state = touch.GetState( 0 );
1436
1437       if( PointState::DOWN == state )
1438       {
1439         secondarySelectionHandle.pressed = true;
1440         secondarySelectionHandle.verticallyFlippedOnTouch = secondarySelectionHandle.verticallyFlipped;
1441       }
1442       else if( ( PointState::UP == state ) ||
1443                ( PointState::INTERRUPTED == state ) )
1444       {
1445         secondarySelectionHandle.pressed = false;
1446         mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
1447         mIsHandlePanning = false;
1448         mHandleReleased = RIGHT_SELECTION_HANDLE;
1449       }
1450
1451       SetHandleImage( RIGHT_SELECTION_HANDLE );
1452     }
1453
1454     // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
1455     return true;
1456   }
1457
1458   void HandleResetPosition( PropertyNotification& source )
1459   {
1460     const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
1461
1462     if( grabHandle.active )
1463     {
1464       // Sets the grab handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
1465       SetGrabHandlePosition();
1466
1467       // Sets the grab handle image according if it's pressed, flipped, etc.
1468       SetHandleImage( GRAB_HANDLE );
1469     }
1470     else
1471     {
1472       // Sets the primary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
1473       SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
1474
1475       // Sets the primary handle image according if it's pressed, flipped, etc.
1476       SetHandleImage( LEFT_SELECTION_HANDLE );
1477
1478       // Sets the secondary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
1479       SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
1480
1481       // Sets the secondary handle image according if it's pressed, flipped, etc.
1482       SetHandleImage( RIGHT_SELECTION_HANDLE );
1483     }
1484   }
1485
1486   void SetupActiveLayerPropertyNotifications()
1487   {
1488     if( !mActiveLayer )
1489     {
1490       return;
1491     }
1492
1493     // Vertical notifications.
1494
1495     // Disconnect any previous connected callback.
1496     if( mHandleVerticalLessThanNotification )
1497     {
1498       mHandleVerticalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
1499       mActiveLayer.RemovePropertyNotification( mHandleVerticalLessThanNotification );
1500     }
1501
1502     if( mHandleVerticalGreaterThanNotification )
1503     {
1504       mHandleVerticalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
1505       mActiveLayer.RemovePropertyNotification( mHandleVerticalGreaterThanNotification );
1506     }
1507
1508     const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
1509     const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
1510     const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
1511
1512     if( grabHandle.active )
1513     {
1514       if( grabHandle.verticallyFlipped )
1515       {
1516         // The grab handle is vertically flipped. Never is going to exceed the bottom edje of the display.
1517         mHandleVerticalGreaterThanNotification.Reset();
1518
1519         // The vertical distance from the center of the active layer to the top edje of the display.
1520         const float topHeight = 0.5f * mControlSize.height - grabHandle.position.y + grabHandle.size.height;
1521
1522         mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1523                                                                                     LessThanCondition( mBoundingBox.y + topHeight ) );
1524
1525         // Notifies the change from false to true and from true to false.
1526         mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1527
1528         // Connects the signals with the callbacks.
1529         mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1530       }
1531       else
1532       {
1533         // The grab handle is not vertically flipped. Never is going to exceed the top edje of the display.
1534         mHandleVerticalLessThanNotification.Reset();
1535
1536         // The vertical distance from the center of the active layer to the bottom edje of the display.
1537         const float bottomHeight = -0.5f * mControlSize.height + grabHandle.position.y + grabHandle.lineHeight + grabHandle.size.height;
1538
1539         mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1540                                                                                        GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
1541
1542         // Notifies the change from false to true and from true to false.
1543         mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1544
1545         // Connects the signals with the callbacks.
1546         mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1547       }
1548     }
1549     else // The selection handles are active
1550     {
1551       if( primaryHandle.verticallyFlipped && secondaryHandle.verticallyFlipped )
1552       {
1553         // Both selection handles are vertically flipped. Never are going to exceed the bottom edje of the display.
1554         mHandleVerticalGreaterThanNotification.Reset();
1555
1556         // The vertical distance from the center of the active layer to the top edje of the display.
1557         const float topHeight = 0.5f * mControlSize.height + std::max( -primaryHandle.position.y + primaryHandle.size.height, -secondaryHandle.position.y + secondaryHandle.size.height );
1558
1559         mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1560                                                                                     LessThanCondition( mBoundingBox.y + topHeight ) );
1561
1562         // Notifies the change from false to true and from true to false.
1563         mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1564
1565         // Connects the signals with the callbacks.
1566         mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1567       }
1568       else if( !primaryHandle.verticallyFlipped && !secondaryHandle.verticallyFlipped )
1569       {
1570         // Both selection handles aren't vertically flipped. Never are going to exceed the top edje of the display.
1571         mHandleVerticalLessThanNotification.Reset();
1572
1573         // The vertical distance from the center of the active layer to the bottom edje of the display.
1574         const float bottomHeight = -0.5f * mControlSize.height + std::max( primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height,
1575                                                                            secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height );
1576
1577         mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1578                                                                                        GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
1579
1580         // Notifies the change from false to true and from true to false.
1581         mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1582
1583         // Connects the signals with the callbacks.
1584         mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1585       }
1586       else
1587       {
1588         // Only one of the selection handles is vertically flipped. Both vertical notifications are needed.
1589
1590         // The vertical distance from the center of the active layer to the top edje of the display.
1591         const float topHeight = 0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                              ?
1592                                                                -primaryHandle.position.y + primaryHandle.size.height        :
1593                                                                -secondaryHandle.position.y + secondaryHandle.size.height );
1594
1595         mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1596                                                                                     LessThanCondition( mBoundingBox.y + topHeight ) );
1597
1598         // Notifies the change from false to true and from true to false.
1599         mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1600
1601         // Connects the signals with the callbacks.
1602         mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1603
1604         // The vertical distance from the center of the active layer to the bottom edje of the display.
1605         const float bottomHeight = -0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                                                       ?
1606                                                                    secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height :
1607                                                                    primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height );
1608
1609         mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1610                                                                                        GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
1611
1612         // Notifies the change from false to true and from true to false.
1613         mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1614
1615         // Connects the signals with the callbacks.
1616         mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1617       }
1618     }
1619
1620     // Horizontal notifications.
1621
1622     // Disconnect any previous connected callback.
1623     if( mHandleHorizontalLessThanNotification )
1624     {
1625       mHandleHorizontalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
1626       mActiveLayer.RemovePropertyNotification( mHandleHorizontalLessThanNotification );
1627     }
1628
1629     if( mHandleHorizontalGreaterThanNotification )
1630     {
1631       mHandleHorizontalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
1632       mActiveLayer.RemovePropertyNotification( mHandleHorizontalGreaterThanNotification );
1633     }
1634
1635     if( primaryHandle.active || secondaryHandle.active )
1636     {
1637       // The horizontal distance from the center of the active layer to the left edje of the display.
1638       const float leftWidth = 0.5f * mControlSize.width + std::max( -primaryHandle.position.x + primaryHandle.size.width,
1639                                                                     -secondaryHandle.position.x + secondaryHandle.size.width );
1640
1641       mHandleHorizontalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
1642                                                                                     LessThanCondition( mBoundingBox.x + leftWidth ) );
1643
1644       // Notifies the change from false to true and from true to false.
1645       mHandleHorizontalLessThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1646
1647       // Connects the signals with the callbacks.
1648       mHandleHorizontalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1649
1650       // The horizontal distance from the center of the active layer to the right edje of the display.
1651       const float rightWidth = -0.5f * mControlSize.width + std::max( primaryHandle.position.x + primaryHandle.size.width,
1652                                                                       secondaryHandle.position.x + secondaryHandle.size.width );
1653
1654       mHandleHorizontalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
1655                                                                                        GreaterThanCondition( mBoundingBox.z - rightWidth ) );
1656
1657       // Notifies the change from false to true and from true to false.
1658       mHandleHorizontalGreaterThanNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1659
1660       // Connects the signals with the callbacks.
1661       mHandleHorizontalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
1662     }
1663   }
1664
1665   // Popup
1666
1667   float AlternatePopUpPositionRelativeToCursor( bool topBottom )
1668   {
1669     float alternativePosition = 0.0f;
1670
1671     const float halfPopupHeight = 0.5f * mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
1672
1673     const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
1674     const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
1675     const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
1676     const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
1677
1678     if( primaryHandle.active || secondaryHandle.active )
1679     {
1680       float handleY = 0.f;
1681       float maxHandleHeight = 0.f;
1682
1683       const bool primaryVisible = primaryHandle.horizontallyVisible && primaryHandle.verticallyVisible;
1684       const bool secondaryVisible = secondaryHandle.horizontallyVisible && secondaryHandle.verticallyVisible;
1685
1686       if( primaryVisible && secondaryVisible )
1687       {
1688         handleY = std::max( primaryHandle.position.y, secondaryHandle.position.y );
1689         maxHandleHeight = std::max( primaryHandle.size.height, secondaryHandle.size.height );
1690       }
1691       else if( primaryVisible && !secondaryVisible )
1692       {
1693         handleY = primaryHandle.position.y;
1694         maxHandleHeight = primaryHandle.size.height;
1695       }
1696       else if( !primaryVisible && secondaryVisible )
1697       {
1698         handleY = secondaryHandle.position.y;
1699         maxHandleHeight = secondaryHandle.size.height;
1700       }
1701
1702       alternativePosition = handleY + ( topBottom ? halfPopupHeight + maxHandleHeight + cursor.lineHeight : -halfPopupHeight - maxHandleHeight );
1703     }
1704     else
1705     {
1706       alternativePosition = cursor.position.y + ( topBottom ? halfPopupHeight + grabHandle.size.height + cursor.lineHeight : -halfPopupHeight - grabHandle.size.height );
1707     }
1708
1709     return alternativePosition;
1710   }
1711
1712   void PopUpLeavesTopBoundary( PropertyNotification& source )
1713   {
1714     const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
1715
1716     // Sets the position of the popup below.
1717     mCopyPastePopup.actor.SetProperty( Actor::Property::POSITION_Y,  floorf( CalculateVerticalPopUpPosition( 0.5f * popupHeight, true ) ) );
1718   }
1719
1720   void PopUpLeavesBottomBoundary( PropertyNotification& source )
1721   {
1722     const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
1723
1724     // Sets the position of the popup above.
1725     mCopyPastePopup.actor.SetProperty( Actor::Property::POSITION_Y,  floorf( CalculateVerticalPopUpPosition( 0.5f * popupHeight, false ) ) );
1726   }
1727
1728   void SetUpPopupPositionNotifications( const Vector3& popupHalfSize )
1729   {
1730     // Disconnect any previous connected callback.
1731     if( mPopupTopExceedNotification )
1732     {
1733       mPopupTopExceedNotification.NotifySignal().Disconnect( this, &Decorator::Impl::PopUpLeavesTopBoundary );
1734       mCopyPastePopup.actor.RemovePropertyNotification( mPopupTopExceedNotification );
1735     }
1736
1737     if( mPopupBottomExceedNotification )
1738     {
1739       mPopupBottomExceedNotification.NotifySignal().Disconnect( this, &Decorator::Impl::PopUpLeavesBottomBoundary );
1740       mCopyPastePopup.actor.RemovePropertyNotification( mPopupBottomExceedNotification );
1741     }
1742
1743     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
1744
1745     // Exceeding vertical boundary
1746
1747     mPopupTopExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1748                                                                                  LessThanCondition( mBoundingBox.y + popupHalfSize.height ) );
1749
1750     mPopupBottomExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
1751                                                                                     GreaterThanCondition( mBoundingBox.w - popupHalfSize.height ) );
1752
1753     // Notifies the change from false to true and from true to false.
1754     mPopupTopExceedNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1755     mPopupBottomExceedNotification.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED );
1756
1757     mPopupTopExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesTopBoundary );
1758     mPopupBottomExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesBottomBoundary );
1759   }
1760
1761   void SetHandleImage( HandleType handleType, HandleImageType handleImageType, const std::string& imageFileName )
1762   {
1763     ImageDimensions dimensions = Dali::GetOriginalImageSize( imageFileName );
1764
1765     HandleImpl& handle = mHandle[handleType];
1766     handle.size = Size( dimensions.GetWidth(), dimensions.GetHeight() );
1767
1768     mHandleImages[handleType][handleImageType] = imageFileName;
1769   }
1770
1771   void SetScrollThreshold( float threshold )
1772   {
1773     mScrollThreshold = threshold;
1774   }
1775
1776   float GetScrollThreshold() const
1777   {
1778     return mScrollThreshold;
1779   }
1780
1781   void SetScrollSpeed( float speed )
1782   {
1783     mScrollSpeed = speed;
1784     mScrollDistance = speed * SCROLL_TICK_INTERVAL * TO_SECONDS;
1785   }
1786
1787   float GetScrollSpeed() const
1788   {
1789     return mScrollSpeed;
1790   }
1791
1792   void NotifyEndOfScroll()
1793   {
1794     StopScrollTimer();
1795
1796     if( mScrollTimer )
1797     {
1798       mNotifyEndOfScroll = true;
1799     }
1800   }
1801
1802   /**
1803    * Creates and starts a timer to scroll the text when handles are close to the edges of the text.
1804    *
1805    * It only starts the timer if it's already created.
1806    */
1807   void StartScrollTimer()
1808   {
1809     if( !mScrollTimer )
1810     {
1811       mScrollTimer = Timer::New( SCROLL_TICK_INTERVAL );
1812       mScrollTimer.TickSignal().Connect( this, &Decorator::Impl::OnScrollTimerTick );
1813     }
1814
1815     if( !mScrollTimer.IsRunning() )
1816     {
1817       mScrollTimer.Start();
1818     }
1819   }
1820
1821   /**
1822    * Stops the timer used to scroll the text.
1823    */
1824   void StopScrollTimer()
1825   {
1826     if( mScrollTimer )
1827     {
1828       mScrollTimer.Stop();
1829     }
1830   }
1831
1832   /**
1833    * Callback called by the timer used to scroll the text.
1834    *
1835    * It calculates and sets a new scroll position.
1836    */
1837   bool OnScrollTimerTick()
1838   {
1839     if( HANDLE_TYPE_COUNT != mHandleScrolling )
1840     {
1841       float x = 0.f;
1842       float y = 0.f;
1843
1844       switch( mScrollDirection )
1845       {
1846         case SCROLL_RIGHT:
1847         {
1848           x = mScrollDistance;
1849           break;
1850         }
1851         case SCROLL_LEFT:
1852         {
1853           x = -mScrollDistance;
1854           break;
1855         }
1856         case SCROLL_TOP:
1857         {
1858           y = mScrollDistance;
1859           break;
1860         }
1861         case SCROLL_BOTTOM:
1862         {
1863           y = -mScrollDistance;
1864           break;
1865         }
1866         default:
1867           break;
1868       }
1869
1870       mController.DecorationEvent( mHandleScrolling,
1871                                    HANDLE_SCROLLING,
1872                                    x,
1873                                    y );
1874     }
1875
1876     return true;
1877   }
1878
1879   ControllerInterface& mController;
1880
1881   TapGestureDetector       mTapDetector;
1882   PanGestureDetector       mPanDetector;
1883   LongPressGestureDetector mLongPressDetector;
1884
1885   Timer               mCursorBlinkTimer;          ///< Timer to signal cursor to blink
1886   Timer               mScrollTimer;               ///< Timer used to scroll the text when the grab handle is moved close to the edges.
1887
1888   Actor                mActiveLayer;                             ///< Actor for active handles and alike that ensures they are above all else.
1889   PropertyNotification mHandleVerticalLessThanNotification;      ///< Notifies when the 'y' coord of the active layer is less than a given value.
1890   PropertyNotification mHandleVerticalGreaterThanNotification;   ///< Notifies when the 'y' coord of the active layer is grater than a given value.
1891   PropertyNotification mHandleHorizontalLessThanNotification;    ///< Notifies when the 'x' coord of the active layer is less than a given value.
1892   PropertyNotification mHandleHorizontalGreaterThanNotification; ///< Notifies when the 'x' coord of the active layer is grater than a given value.
1893   PropertyNotification mPopupTopExceedNotification;              ///< Notifies when the popup leaves the bounding box through the top.
1894   PropertyNotification mPopupBottomExceedNotification;           ///< Notifies when the popup leaves the bounding box through the bottom.
1895   Control              mPrimaryCursor;
1896   Control              mSecondaryCursor;
1897
1898   Actor               mHighlightActor;            ///< Actor to display highlight
1899   Renderer            mHighlightRenderer;
1900   Shader              mHighlightShader;           ///< Shader used for highlight
1901   Property::Map       mQuadVertexFormat;
1902   PopupImpl           mCopyPastePopup;
1903   TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
1904   TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
1905
1906   std::string         mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
1907   Vector4             mHandleColor;
1908
1909   CursorImpl          mCursor[CURSOR_COUNT];
1910   HandleImpl          mHandle[HANDLE_TYPE_COUNT];
1911
1912   VertexBuffer        mQuadVertices;
1913   Geometry            mQuadGeometry;
1914   QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight.
1915
1916   Vector4             mBoundingBox;               ///< The bounding box in world coords.
1917   Vector4             mHighlightColor;            ///< Color of the highlight
1918   Vector2             mHighlightPosition;         ///< The position of the highlight actor.
1919   Size                mHighlightSize;             ///< The size of the highlighted text.
1920   Size                mControlSize;               ///< The control's size. Set by the Relayout.
1921   float               mHighlightOutlineOffset;    ///< The outline's offset.
1922
1923   unsigned int        mActiveCursor;
1924   unsigned int        mCursorBlinkInterval;
1925   float               mCursorBlinkDuration;
1926   float               mCursorWidth;             ///< The width of the cursors in pixels.
1927   HandleType          mHandleScrolling;         ///< The handle which is scrolling.
1928   HandleType          mHandleReleased;          ///< The last handle released.
1929   ScrollDirection     mScrollDirection;         ///< The direction of the scroll.
1930   float               mScrollThreshold;         ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
1931   float               mScrollSpeed;             ///< The scroll speed in pixels per second.
1932   float               mScrollDistance;          ///< Distance the text scrolls during a scroll interval.
1933   int                 mTextDepth;               ///< The depth used to render the text.
1934
1935   bool                mActiveCopyPastePopup              : 1;
1936   bool                mPopupSetNewPosition               : 1;
1937   bool                mCursorBlinkStatus                 : 1; ///< Flag to switch between blink on and blink off.
1938   bool                mDelayCursorBlink                  : 1; ///< Used to avoid cursor blinking when entering text.
1939   bool                mPrimaryCursorVisible              : 1; ///< Whether the primary cursor is visible.
1940   bool                mSecondaryCursorVisible            : 1; ///< Whether the secondary cursor is visible.
1941   bool                mFlipSelectionHandlesOnCross       : 1; ///< Whether to flip the selection handles as soon as they cross.
1942   bool                mFlipLeftSelectionHandleDirection  : 1; ///< Whether to flip the left selection handle image because of the character's direction.
1943   bool                mFlipRightSelectionHandleDirection : 1; ///< Whether to flip the right selection handle image because of the character's direction.
1944   bool                mIsHandlePanning                   : 1; ///< Whether any of the handles is moving.
1945   bool                mIsHandleCurrentlyCrossed          : 1; ///< Whether the handles are crossed.
1946   bool                mIsHandlePreviouslyCrossed         : 1; ///< Whether the handles where crossed at the last handle touch up.
1947   bool                mNotifyEndOfScroll                 : 1; ///< Whether to notify the end of the scroll.
1948   bool                mHorizontalScrollingEnabled        : 1; ///< Whether the horizontal scrolling is enabled.
1949   bool                mVerticalScrollingEnabled          : 1; ///< Whether the vertical scrolling is enabled.
1950   bool                mSmoothHandlePanEnabled            : 1; ///< Whether to pan smoothly the handles.
1951   bool                mIsHighlightBoxActive              : 1; ///< Whether the highlight box is active.
1952   bool                mHidePrimaryCursorAndGrabHandle    : 1; ///< Whether the primary cursor and grab are hidden always.
1953 };
1954
1955 DecoratorPtr Decorator::New( ControllerInterface& controller,
1956                              TextSelectionPopupCallbackInterface& callbackInterface )
1957 {
1958   return DecoratorPtr( new Decorator( controller,
1959                                       callbackInterface ) );
1960 }
1961
1962 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
1963 {
1964   LocalToWorldCoordinatesBoundingBox( boundingBox, mImpl->mBoundingBox );
1965 }
1966
1967 void Decorator::GetBoundingBox( Rect<int>& boundingBox ) const
1968 {
1969   WorldToLocalCoordinatesBoundingBox( mImpl->mBoundingBox, boundingBox );
1970 }
1971
1972 void Decorator::Relayout( const Vector2& size )
1973 {
1974   mImpl->Relayout( size );
1975 }
1976
1977 void Decorator::UpdatePositions( const Vector2& scrollOffset )
1978 {
1979   mImpl->UpdatePositions( scrollOffset );
1980 }
1981
1982 /** Cursor **/
1983
1984 void Decorator::SetActiveCursor( ActiveCursor activeCursor )
1985 {
1986   mImpl->mActiveCursor = activeCursor;
1987 }
1988
1989 unsigned int Decorator::GetActiveCursor() const
1990 {
1991   return mImpl->mActiveCursor;
1992 }
1993
1994 void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight )
1995 {
1996   Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
1997
1998   cursorImpl.position.x = x;
1999   cursorImpl.position.y = y;
2000   cursorImpl.cursorHeight = cursorHeight;
2001   cursorImpl.lineHeight = lineHeight;
2002 }
2003
2004 void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& cursorHeight, float& lineHeight ) const
2005 {
2006   const Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
2007
2008   x = cursorImpl.position.x;
2009   y = cursorImpl.position.y;
2010   cursorHeight = cursorImpl.cursorHeight;
2011   lineHeight = cursorImpl.lineHeight;
2012 }
2013
2014 const Vector2& Decorator::GetPosition( Cursor cursor ) const
2015 {
2016   return mImpl->mCursor[cursor].position;
2017 }
2018
2019 void Decorator::SetGlyphOffset( Cursor cursor, float glyphOffset )
2020 {
2021   Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
2022
2023   cursorImpl.glyphOffset = glyphOffset;
2024 }
2025
2026 const float Decorator::GetGlyphOffset( Cursor cursor) const
2027 {
2028   return mImpl->mCursor[cursor].glyphOffset;
2029 }
2030
2031 void Decorator::SetCursorColor( Cursor cursor, const Dali::Vector4& color )
2032 {
2033   mImpl->mCursor[cursor].color = color;
2034 }
2035
2036 const Dali::Vector4& Decorator::GetColor( Cursor cursor ) const
2037 {
2038   return mImpl->mCursor[cursor].color;
2039 }
2040
2041 void Decorator::StartCursorBlink()
2042 {
2043   if ( !mImpl->mCursorBlinkTimer )
2044   {
2045     mImpl->mCursorBlinkTimer = Timer::New( mImpl->mCursorBlinkInterval );
2046     mImpl->mCursorBlinkTimer.TickSignal().Connect( mImpl, &Decorator::Impl::OnCursorBlinkTimerTick );
2047   }
2048
2049   if ( !mImpl->mCursorBlinkTimer.IsRunning() )
2050   {
2051     mImpl->mCursorBlinkTimer.Start();
2052   }
2053 }
2054
2055 void Decorator::StopCursorBlink()
2056 {
2057   if ( mImpl->mCursorBlinkTimer )
2058   {
2059     mImpl->mCursorBlinkTimer.Stop();
2060   }
2061
2062   mImpl->mCursorBlinkStatus = true; // Keep cursor permanently shown
2063 }
2064
2065 void Decorator::DelayCursorBlink()
2066 {
2067   mImpl->mCursorBlinkStatus = true; // Show cursor for a bit longer
2068   mImpl->mDelayCursorBlink = true;
2069 }
2070
2071 void Decorator::SetCursorBlinkInterval( float seconds )
2072 {
2073   mImpl->mCursorBlinkInterval = static_cast<unsigned int>( seconds * TO_MILLISECONDS ); // Convert to milliseconds
2074 }
2075
2076 float Decorator::GetCursorBlinkInterval() const
2077 {
2078   return static_cast<float>( mImpl->mCursorBlinkInterval ) * TO_SECONDS;
2079 }
2080
2081 void Decorator::SetCursorBlinkDuration( float seconds )
2082 {
2083   mImpl->mCursorBlinkDuration = seconds;
2084 }
2085
2086 float Decorator::GetCursorBlinkDuration() const
2087 {
2088   return mImpl->mCursorBlinkDuration;
2089 }
2090
2091 void Decorator::SetCursorWidth( int width )
2092 {
2093   mImpl->mCursorWidth = static_cast<float>( width );
2094 }
2095
2096 int Decorator::GetCursorWidth() const
2097 {
2098   return static_cast<int>( mImpl->mCursorWidth );
2099 }
2100
2101 void Decorator::SetEditable( bool editable )
2102 {
2103   mImpl->mHidePrimaryCursorAndGrabHandle = !editable;
2104   mImpl->Relayout( mImpl->mControlSize );
2105 }
2106 /** Handles **/
2107
2108 void Decorator::SetHandleActive( HandleType handleType, bool active )
2109 {
2110   mImpl->mHandle[handleType].active = active;
2111
2112   if( !active )
2113   {
2114     if( ( LEFT_SELECTION_HANDLE == handleType ) || ( RIGHT_SELECTION_HANDLE == handleType ) )
2115     {
2116       mImpl->mIsHandlePreviouslyCrossed = false;
2117     }
2118
2119     // TODO: this is a work-around.
2120     // The problem is the handle actor does not receive the touch event with the Interrupt
2121     // state when the power button is pressed and the application goes to background.
2122     mImpl->mHandle[handleType].pressed = false;
2123     const bool imageReleased = mImpl->mHandleImages[handleType][HANDLE_IMAGE_RELEASED].size();
2124     ImageView imageView = mImpl->mHandle[handleType].actor;
2125     if( imageReleased && imageView )
2126     {
2127       imageView.SetImage( mImpl->mHandleImages[handleType][HANDLE_IMAGE_RELEASED] );
2128     }
2129   }
2130
2131 }
2132
2133 bool Decorator::IsHandleActive( HandleType handleType ) const
2134 {
2135   return mImpl->mHandle[handleType].active ;
2136 }
2137
2138 void Decorator::SetHandleImage( HandleType handleType, HandleImageType handleImageType, const std::string& imageFileName )
2139 {
2140   mImpl->SetHandleImage( handleType, handleImageType, imageFileName );
2141 }
2142
2143 const std::string& Decorator::GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const
2144 {
2145   return mImpl->mHandleImages[handleType][handleImageType];
2146 }
2147
2148 void Decorator::SetHandleColor( const Vector4& color )
2149 {
2150   mImpl->mHandleColor = color;
2151 }
2152
2153 const Vector4& Decorator::GetHandleColor() const
2154 {
2155   return mImpl->mHandleColor;
2156 }
2157
2158 void Decorator::SetPosition( HandleType handleType, float x, float y, float height )
2159 {
2160   // Adjust handle's displacement
2161   Impl::HandleImpl& handle = mImpl->mHandle[handleType];
2162
2163   handle.position.x = x;
2164   handle.position.y = y;
2165   handle.lineHeight = height;
2166
2167   if( mImpl->mSmoothHandlePanEnabled )
2168   {
2169     handle.grabDisplacementX = 0.f;
2170     handle.grabDisplacementY = 0.f;
2171   }
2172 }
2173
2174 void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& height ) const
2175 {
2176   Impl::HandleImpl& handle = mImpl->mHandle[handleType];
2177
2178   x = handle.position.x;
2179   y = handle.position.y;
2180   height = handle.lineHeight;
2181 }
2182
2183 const Vector2& Decorator::GetPosition( HandleType handleType ) const
2184 {
2185   return mImpl->mHandle[handleType].position;
2186 }
2187
2188 void Decorator::FlipHandleVertically( HandleType handleType, bool flip )
2189 {
2190   mImpl->mHandle[handleType].verticallyFlippedPreferred = flip;
2191 }
2192
2193 bool Decorator::IsHandleVerticallyFlipped( HandleType handleType ) const
2194 {
2195   return mImpl->mHandle[handleType].verticallyFlippedPreferred;
2196 }
2197
2198 void Decorator::FlipSelectionHandlesOnCrossEnabled( bool enable )
2199 {
2200   mImpl->mFlipSelectionHandlesOnCross = enable;
2201 }
2202
2203 void Decorator::SetSelectionHandleFlipState( bool indicesSwapped, bool left, bool right )
2204 {
2205   mImpl->mIsHandleCurrentlyCrossed = indicesSwapped;
2206   mImpl->mFlipLeftSelectionHandleDirection = left;
2207   mImpl->mFlipRightSelectionHandleDirection = right;
2208 }
2209
2210 void Decorator::AddHighlight( unsigned int index, const Vector4& quad )
2211 {
2212   *( mImpl->mHighlightQuadList.Begin() + index ) = quad;
2213 }
2214
2215 void Decorator::SetHighLightBox( const Vector2& position, const Size& size, float outlineOffset )
2216 {
2217   mImpl->mHighlightPosition = position;
2218   mImpl->mHighlightSize = size;
2219   mImpl->mHighlightOutlineOffset = outlineOffset;
2220 }
2221
2222 void Decorator::ClearHighlights()
2223 {
2224   mImpl->mHighlightQuadList.Clear();
2225   mImpl->mHighlightPosition = Vector2::ZERO;
2226   mImpl->mHighlightOutlineOffset = 0.f;
2227 }
2228
2229 void Decorator::ResizeHighlightQuads( unsigned int numberOfQuads )
2230 {
2231   mImpl->mHighlightQuadList.Resize( numberOfQuads );
2232 }
2233
2234 void Decorator::SetHighlightColor( const Vector4& color )
2235 {
2236   mImpl->mHighlightColor = color;
2237 }
2238
2239 const Vector4& Decorator::GetHighlightColor() const
2240 {
2241   return mImpl->mHighlightColor;
2242 }
2243
2244 void Decorator::SetHighlightActive( bool active )
2245 {
2246   mImpl->mIsHighlightBoxActive = active;
2247 }
2248
2249 bool Decorator::IsHighlightActive() const
2250 {
2251   return mImpl->mIsHighlightBoxActive;
2252 }
2253
2254 bool Decorator::IsHighlightVisible() const
2255 {
2256   return ( mImpl->mHighlightActor && mImpl->mHighlightActor.GetParent() );
2257 }
2258
2259 void Decorator::SetTextDepth( int textDepth )
2260 {
2261   mImpl->mTextDepth = textDepth;
2262 }
2263
2264 void Decorator::SetPopupActive( bool active )
2265 {
2266   mImpl->mActiveCopyPastePopup = active;
2267 }
2268
2269 bool Decorator::IsPopupActive() const
2270 {
2271   return mImpl->mActiveCopyPastePopup;
2272 }
2273
2274 void Decorator::SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask )
2275 {
2276   mImpl->mEnabledPopupButtons = enabledButtonsBitMask;
2277
2278   if ( !mImpl->mCopyPastePopup.actor )
2279   {
2280     mImpl->mCopyPastePopup.actor = TextSelectionPopup::New( &mImpl->mTextSelectionPopupCallbackInterface );
2281 #ifdef DECORATOR_DEBUG
2282     mImpl->mCopyPastePopup.actor.SetProperty( Dali::Actor::Property::NAME,"mCopyPastePopup");
2283 #endif
2284     mImpl->mCopyPastePopup.actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
2285     mImpl->mCopyPastePopup.actor.OnRelayoutSignal().Connect( mImpl, &Decorator::Impl::SetPopupPosition ); // Position popup after size negotiation
2286   }
2287
2288   mImpl->mCopyPastePopup.actor.EnableButtons( mImpl->mEnabledPopupButtons );
2289 }
2290
2291 TextSelectionPopup::Buttons& Decorator::GetEnabledPopupButtons()
2292 {
2293   return mImpl->mEnabledPopupButtons;
2294 }
2295
2296 /** Scroll **/
2297
2298 void Decorator::SetScrollThreshold( float threshold )
2299 {
2300   mImpl->SetScrollThreshold( threshold );
2301 }
2302
2303 float Decorator::GetScrollThreshold() const
2304 {
2305   return mImpl->GetScrollThreshold();
2306 }
2307
2308 void Decorator::SetScrollSpeed( float speed )
2309 {
2310   mImpl->SetScrollSpeed( speed );
2311 }
2312
2313 float Decorator::GetScrollSpeed() const
2314 {
2315   return mImpl->GetScrollSpeed();
2316 }
2317
2318 void Decorator::NotifyEndOfScroll()
2319 {
2320   mImpl->NotifyEndOfScroll();
2321 }
2322
2323 void Decorator::SetHorizontalScrollEnabled( bool enable )
2324 {
2325   mImpl->mHorizontalScrollingEnabled = enable;
2326 }
2327
2328 bool Decorator::IsHorizontalScrollEnabled() const
2329 {
2330   return mImpl->mHorizontalScrollingEnabled;
2331 }
2332
2333 void Decorator::SetVerticalScrollEnabled( bool enable )
2334 {
2335   mImpl->mVerticalScrollingEnabled = enable;
2336 }
2337
2338 bool Decorator::IsVerticalScrollEnabled() const
2339 {
2340   return mImpl->mVerticalScrollingEnabled;
2341 }
2342
2343 void Decorator::SetSmoothHandlePanEnabled( bool enable )
2344 {
2345   mImpl->mSmoothHandlePanEnabled = enable;
2346 }
2347
2348 bool Decorator::IsSmoothHandlePanEnabled() const
2349 {
2350   return mImpl->mSmoothHandlePanEnabled;
2351 }
2352
2353 Decorator::~Decorator()
2354 {
2355   delete mImpl;
2356 }
2357
2358 Decorator::Decorator( ControllerInterface& controller,
2359                       TextSelectionPopupCallbackInterface& callbackInterface )
2360 : mImpl( NULL )
2361 {
2362   mImpl = new Decorator::Impl( controller, callbackInterface );
2363 }
2364
2365 } // namespace Text
2366
2367 } // namespace Toolkit
2368
2369 } // namespace Dali