4cff45440da2f31d1ff000461d67b9188dceb8e3
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / decorator / text-decorator.cpp
1 /*
2  * Copyright (c) 2015 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/public-api/actors/actor.h>
23 #include <dali/public-api/adaptor-framework/timer.h>
24 #include <dali/public-api/actors/image-actor.h>
25 #include <dali/public-api/actors/layer.h>
26 #include <dali/public-api/common/constants.h>
27 #include <dali/public-api/events/tap-gesture.h>
28 #include <dali/public-api/events/tap-gesture-detector.h>
29 #include <dali/public-api/events/pan-gesture.h>
30 #include <dali/public-api/events/pan-gesture-detector.h>
31 #include <dali/public-api/images/resource-image.h>
32 #include <dali/public-api/math/vector2.h>
33 #include <dali/public-api/math/vector4.h>
34 #include <dali/public-api/images/nine-patch-image.h>
35 #include <dali/public-api/signals/connection-tracker.h>
36 #include <libintl.h>
37
38 // INTERNAL INCLUDES
39 #include <dali-toolkit/public-api/controls/control.h>
40 #include <dali-toolkit/public-api/controls/control-impl.h>
41 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
42 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
43 #include <dali-toolkit/public-api/controls/buttons/push-button.h>
44 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
45
46 #ifdef DEBUG_ENABLED
47 #define DECORATOR_DEBUG
48 #endif
49
50 // todo Move this to adaptor??
51 #define GET_LOCALE_TEXT(string) dgettext("elementary", string)
52
53 // Local Data
54 namespace
55 {
56
57 const char* DEFAULT_GRAB_HANDLE_IMAGE( DALI_IMAGE_DIR "insertpoint-icon.png" );
58 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
59 const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
60 //const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" );
61 //const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
62
63 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
64 const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
65
66 const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval
67 const std::size_t MILLISECONDS = 1000;
68
69 const std::string POPUP_BACKGROUND( DALI_IMAGE_DIR "popup_bubble_bg.#.png" );
70 const std::string POPUP_BACKGROUND_EFFECT( DALI_IMAGE_DIR "popup_bubble_bg_ef.#.png" );
71 const std::string POPUP_BACKGROUND_LINE( DALI_IMAGE_DIR "popup_bubble_bg_line.#.png" );
72
73 const Dali::Vector4 DEFAULT_POPUP_BACKGROUND( Dali::Vector4( .20f, 0.29f, 0.44f, 1.0f ) );
74 const Dali::Vector4 DEFAULT_POPUP_BACKGROUND_PRESSED( Dali::Vector4( 0.07f, 0.10f, 0.17f, 1.0f ) );
75 const Dali::Vector4 DEFAULT_POPUP_LINE_COLOR( Dali::Vector4( 0.36f, 0.45f, 0.59f, 1.0f ) );
76 const Dali::Vector4 DEFAULT_OPTION_ICON( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
77 const Dali::Vector4 DEFAULT_OPTION_ICON_PRESSED( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
78 const Dali::Vector4 DEFAULT_OPTION_TEXT( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
79 const Dali::Vector4 DEFAULT_OPTION_TEXT_PRESSED( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
80
81 const std::string OPTION_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
82 const std::string OPTION_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
83 const std::string OPTION_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
84 const std::string OPTION_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" );
85 const std::string OPTION_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
86 const std::string OPTION_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
87
88 const Dali::Vector2 DEFAULT_POPUP_MAX_SIZE( 470.0f, 120.0f ); ///< The maximum size of the popup.
89
90 const float OPTION_TEXT_LINE_HEIGHT( 32.0f );     ///< The line height of the text.
91 const Dali::Vector2 OPTION_ICON_SIZE( 0.f, 0.f );       ///< The size of the icon.
92 const float OPTION_GAP_ICON_TEXT( 6.f );          ///< The gap between the icon and the text
93 const float OPTION_MARGIN_WIDTH( 10.f );          ///< The margin between the right or lefts edge and the text or icon.
94 const float OPTION_MAX_WIDTH( DEFAULT_POPUP_MAX_SIZE.width / 6 ); ///< The maximum width of the option (currently set to the max)
95 const float OPTION_MIN_WIDTH( 86.0f );           ///< The minimum width of the option.
96
97 const float POPUP_DIVIDER_WIDTH( 1.f );        ///< The size of the divider.
98
99 const Dali::Vector2 POPUP_TAIL_SIZE( 20.0f, 16.0f ); ///< The size of the tail.
100 const float POPUP_TAIL_Y_OFFSET( 5.f );        ///< The y offset of the tail (when its position is on the bottom).
101 const float POPUP_TAIL_TOP_Y_OFFSET( 3.f );    ///< The y offset of the tail (when its position is on the top).
102
103 const float HIDE_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup hide animation in seconds.
104 const float SHOW_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup show animation in seconds.
105
106 const char* const OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
107 const char* const OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
108 const char* const OPTION_CUT("option-cut");                                        // "Cut" popup option.
109 const char* const OPTION_COPY("option-copy");                                      // "Copy" popup option.
110 const char* const OPTION_PASTE("option-paste");                                    // "Paste" popup option.
111 const char* const OPTION_CLIPBOARD("option-clipboard");                            // "Clipboard" popup option.
112
113 enum Buttons
114 {
115   ButtonsCut,
116   ButtonsCopy,
117   ButtonsPaste,
118   ButtonsSelect,
119   ButtonsSelectAll,
120   ButtonsClipboard,
121   ButtonsEnumEnd
122 };
123
124 struct ButtonRequirement
125 {
126   ButtonRequirement()
127   : id( ButtonsEnumEnd ),
128     priority( 0u ),
129     name(),
130     caption(),
131     icon(),
132     enabled( false )
133   {}
134
135   ButtonRequirement( Buttons buttonId,
136                      std::size_t buttonPriority,
137                      const std::string& buttonName,
138                      const std::string& buttonCaption,
139                      Dali::ResourceImage buttonIcon,
140                      bool buttonEnabled )
141   : id( buttonId ),
142     priority( buttonPriority ),
143     name( buttonName ),
144     caption( buttonCaption ),
145     icon( buttonIcon ),
146     enabled( buttonEnabled )
147   {}
148
149   Buttons id;
150   std::size_t priority;
151   std::string name;
152   std::string caption;
153   Dali::ResourceImage icon;
154   bool enabled;
155 };
156
157 // Comparison function for ButtonRequirement Priority
158 bool PriorityCompare( ButtonRequirement const& a, ButtonRequirement const& b)
159 {
160   return a.priority < b.priority;
161 }
162
163 } // end of namespace
164
165 namespace Dali
166 {
167
168 namespace Toolkit
169 {
170
171 namespace Text
172 {
173
174 struct Decorator::Impl : public ConnectionTracker
175 {
176   struct CursorImpl
177   {
178     CursorImpl()
179     : x(0.0f),
180       y(0.0f),
181       height(0.0f),
182       color(Dali::Color::WHITE)
183     {
184     }
185
186     float x;
187     float y;
188     float height;
189
190     Vector4 color;
191   };
192
193   struct SelectionHandleImpl
194   {
195     SelectionHandleImpl()
196     : x(0.0f),
197       y(0.0f),
198       cursorHeight(0.0f),
199       flipped(false)
200     {
201     }
202
203     float x;
204     float y;
205     float cursorHeight; ///< Not the handle height
206     bool flipped;
207
208     ImageActor actor;
209     Actor grabArea;
210
211     Image pressedImage;
212     Image releasedImage;
213   };
214
215   struct PopupImpl
216   {
217     PopupImpl()
218     : mVisiblePopUpSize( Vector2( 100.0f, 100.0f ) ),
219       mRequiredPopUpSize( Vector2( 100.0f, 100.0f ) ),
220       mMaxWidth( DEFAULT_POPUP_MAX_SIZE.width ),
221       mBackgroundColor( DEFAULT_POPUP_BACKGROUND ),
222       mBackgroundPressedColor( DEFAULT_POPUP_BACKGROUND_PRESSED ),
223       mLineColor( DEFAULT_POPUP_LINE_COLOR ),
224       mIconColor( DEFAULT_OPTION_ICON ),
225       mIconPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
226       mTextColor( DEFAULT_OPTION_TEXT ),
227       mTextPressedColor( DEFAULT_OPTION_TEXT_PRESSED )
228       {
229       }
230
231       Actor mRoot;                                        // The actor which all popup content is added to (i.e. panel and buttons)
232       Actor mButtons;                                     // Actor which holds all the buttons, sensitivity can be set oActor buttons via this actor
233       Layer mStencilLayer;                                // Layer to enable clipping when buttons exceed popup
234       ImageActor mBackground;                             // The background popup panel
235       ImageActor mTail;                                   // The tail for the popup
236       ImageActor mTailEffect;                             // the tail effect
237       ImageActor mTailLine;                               // The border/outline around the tail
238
239       Size mVisiblePopUpSize;                             // Visible Size of popup excluding content that needs scrolling.
240       Size mRequiredPopUpSize;                            // Total size of popup including any invisible margin
241       float mMaxWidth;                                    // Max width of the Popup
242
243       Vector4 mNinePatchMargins;                          // Margins between the edge of the cropped image and the nine patch rect (left, right, top, bottom).
244
245       Size mContentSize;                                  // Size of Content (i.e. Buttons)
246       //Animation mAnimation;                               // Popup Hide/Show animation.
247
248       std::vector<ButtonRequirement> mOrderListOfButtons; // List of buttons in the order to be displayed and a flag to indicate if needed.
249
250       Vector4 mBackgroundColor;             // Color of the background of the text input popup
251       Vector4 mBackgroundPressedColor;      // Color of the option background.
252       Vector4 mLineColor;                   // Color of the line around the text input popup
253       Vector4 mIconColor;                   // Color of the popup icon.
254       Vector4 mIconPressedColor;            // Color of the popup icon when pressed.
255       Vector4 mTextColor;                   // Color of the popup text.
256       Vector4 mTextPressedColor;            // Color of the popup text when pressed.
257
258       // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right.
259       std::size_t mSelectOptionPriority;    // Position of Select Button
260       std::size_t mSelectAllOptionPriority; // Position of Select All button
261       std::size_t mCutOptionPriority;       // Position of Cut button
262       std::size_t mCopyOptionPriority;      // Position of Copy button
263       std::size_t mPasteOptionPriority;     // Position of Paste button
264       std::size_t mClipboardOptionPriority; // Position of Clipboard button
265
266       bool mShowIcons; // Flag to show icons
267   };
268
269
270   Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
271   : mTextControlParent(parent),
272     mObserver(observer),
273     mActiveCursor(ACTIVE_CURSOR_NONE),
274     mActiveGrabHandle(false),
275     mActiveSelection( false ),
276     mActiveCopyPastePopup( false ),
277     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
278     mCursorBlinkDuration( 0.0f ),
279     mCursorBlinkStatus( true ),
280     mGrabDisplacementX( 0.0f ),
281     mGrabDisplacementY( 0.0f ),
282     mBoundingBox( Rect<int>() )
283   {
284   }
285
286   /**
287    * Relayout of the decorations owned by the decorator.
288    * @param[in] size The Size of the UI control the decorater is adding it's decorations to.
289    */
290   void Relayout( const Vector2& size, const Vector2& scrollPosition )
291   {
292     // TODO - Remove this if nothing is active
293     CreateActiveLayer();
294
295     // Show or hide the cursors
296     CreateCursors();
297     if( mPrimaryCursor )
298     {
299       mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x,
300                                   mCursor[PRIMARY_CURSOR].y + scrollPosition.y );
301       mPrimaryCursor.SetSize( 1.0f, mCursor[PRIMARY_CURSOR].height );
302     }
303     if( mSecondaryCursor )
304     {
305       mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].x + scrollPosition.x,
306                                     mCursor[SECONDARY_CURSOR].y + scrollPosition.y );
307       mSecondaryCursor.SetSize( 1.0f, mCursor[SECONDARY_CURSOR].height );
308     }
309
310     // Show or hide the grab handle
311     if( mActiveGrabHandle )
312     {
313       SetupTouchEvents();
314
315       CreateGrabHandle();
316
317       mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x,
318                                mCursor[PRIMARY_CURSOR].y + scrollPosition.y + mCursor[PRIMARY_CURSOR].height );
319     }
320     else if( mGrabHandle )
321     {
322       UnparentAndReset( mGrabHandle );
323     }
324
325     // Show or hide the selection handles/highlight
326     if( mActiveSelection )
327     {
328       SetupTouchEvents();
329
330       CreateSelectionHandles();
331
332       SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
333       primary.actor.SetPosition( primary.x + scrollPosition.x,
334                                  primary.y + scrollPosition.y + primary.cursorHeight );
335
336       SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
337       secondary.actor.SetPosition( secondary.x + scrollPosition.x,
338                                    secondary.y + scrollPosition.y + secondary.cursorHeight );
339
340       //CreateHighlight(); TODO
341     }
342     else
343     {
344       UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor );
345       UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor );
346     }
347
348     if ( mActiveCopyPastePopup )
349     {
350       CreatePopup();
351       mCopyPastePopup.mRoot.SetPosition( Vector3( 180.0f, -100.0f, 0.0f ) ); //todo grabhandle or selection handle postions to be used
352     }
353     else
354     {
355       DestroyPopup();
356     }
357   }
358
359   void CreateCursor( ImageActor& cursor )
360   {
361     cursor = CreateSolidColorActor( Color::WHITE );
362     cursor.SetParentOrigin( ParentOrigin::TOP_LEFT );
363     cursor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
364   }
365
366   // Add or Remove cursor(s) from parent
367   void CreateCursors()
368   {
369     if( mActiveCursor == ACTIVE_CURSOR_NONE )
370     {
371       UnparentAndReset( mPrimaryCursor );
372       UnparentAndReset( mSecondaryCursor );
373     }
374     else
375     {
376       /* Create Primary and or Secondary Cursor(s) if active and add to parent */
377       if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ||
378            mActiveCursor == ACTIVE_CURSOR_BOTH )
379       {
380         if ( !mPrimaryCursor )
381         {
382           CreateCursor( mPrimaryCursor );
383 #ifdef DECORATOR_DEBUG
384           mPrimaryCursor.SetName( "PrimaryCursorActor" );
385 #endif
386           mActiveLayer.Add( mPrimaryCursor);
387         }
388       }
389
390       if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
391       {
392         if ( !mSecondaryCursor )
393         {
394           CreateCursor( mSecondaryCursor );
395 #ifdef DECORATOR_DEBUG
396           mSecondaryCursor.SetName( "SecondaryCursorActor" );
397 #endif
398           mActiveLayer.Add( mSecondaryCursor);
399         }
400       }
401     }
402   }
403
404   bool OnCursorBlinkTimerTick()
405   {
406     // Cursor blinking
407     if ( mPrimaryCursor )
408     {
409       mPrimaryCursor.SetVisible( mCursorBlinkStatus );
410     }
411     if ( mSecondaryCursor )
412     {
413       mSecondaryCursor.SetVisible( mCursorBlinkStatus );
414     }
415
416     mCursorBlinkStatus = !mCursorBlinkStatus;
417
418     return true;
419   }
420
421   void SetupTouchEvents()
422   {
423     if ( !mTapDetector )
424     {
425       mTapDetector = TapGestureDetector::New();
426       mTapDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnTap );
427     }
428
429     if ( !mPanGestureDetector )
430     {
431       mPanGestureDetector = PanGestureDetector::New();
432       mPanGestureDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
433     }
434   }
435
436   void CreateActiveLayer()
437   {
438     if( !mActiveLayer )
439     {
440       Actor parent = mTextControlParent.Self();
441
442       mActiveLayer = Layer::New();
443 #ifdef DECORATOR_DEBUG
444       mActiveLayer.SetName ( "ActiveLayerActor" );
445 #endif
446
447       mActiveLayer.SetAnchorPoint( AnchorPoint::CENTER);
448       mActiveLayer.SetParentOrigin( ParentOrigin::CENTER);
449       mActiveLayer.SetSizeMode( SIZE_EQUAL_TO_PARENT );
450       mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
451
452       parent.Add( mActiveLayer );
453     }
454
455     mActiveLayer.RaiseToTop();
456   }
457
458   void CreateGrabHandle()
459   {
460     if( !mGrabHandle )
461     {
462       if ( !mGrabHandleImage )
463       {
464         mGrabHandleImage = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE );
465       }
466
467       mGrabHandle = ImageActor::New( mGrabHandleImage );
468 #ifdef DECORATOR_DEBUG
469       mGrabHandle.SetName( "GrabHandleActor" );
470 #endif
471       mGrabHandle.SetParentOrigin( ParentOrigin::TOP_LEFT );
472       mGrabHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER );
473       mGrabHandle.SetDrawMode( DrawMode::OVERLAY );
474
475       mGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
476 #ifdef DECORATOR_DEBUG
477       mGrabArea.SetName( "GrabArea" );
478 #endif
479       mGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
480       mGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
481       mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
482       mGrabHandle.Add(mGrabArea);
483
484       mTapDetector.Attach( mGrabArea );
485       mPanGestureDetector.Attach( mGrabArea );
486
487       mActiveLayer.Add(mGrabHandle);
488     }
489   }
490
491   void CreateSelectionHandles()
492   {
493     SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
494     if ( !primary.actor )
495     {
496       if ( !primary.releasedImage )
497       {
498         primary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
499       }
500
501       primary.actor = ImageActor::New( primary.releasedImage );
502 #ifdef DECORATOR_DEBUG
503       primary.actor.SetName("SelectionHandleOne");
504 #endif
505       primary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
506       primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
507       primary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
508       primary.flipped = false;
509
510       primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
511 #ifdef DECORATOR_DEBUG
512       primary.grabArea.SetName("SelectionHandleOneGrabArea");
513 #endif
514       primary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
515       primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
516       primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
517
518       mTapDetector.Attach( primary.grabArea );
519       mPanGestureDetector.Attach( primary.grabArea );
520       primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
521
522       primary.actor.Add( primary.grabArea );
523       mActiveLayer.Add( primary.actor );
524     }
525
526     SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
527     if ( !secondary.actor )
528     {
529       if ( !secondary.releasedImage )
530       {
531         secondary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
532       }
533
534       secondary.actor = ImageActor::New( secondary.releasedImage );
535 #ifdef DECORATOR_DEBUG
536       secondary.actor.SetName("SelectionHandleTwo");
537 #endif
538       secondary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
539       secondary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
540       secondary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
541       secondary.flipped = false;
542
543       secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
544 #ifdef DECORATOR_DEBUG
545       secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
546 #endif
547       secondary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
548       secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
549       secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
550
551       mTapDetector.Attach( secondary.grabArea );
552       mPanGestureDetector.Attach( secondary.grabArea );
553       secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
554
555       secondary.actor.Add( secondary.grabArea );
556       mActiveLayer.Add( secondary.actor );
557     }
558
559     //SetUpHandlePropertyNotifications(); TODO
560   }
561
562   void OnTap( Actor actor, const TapGesture& tap )
563   {
564     if( actor == mGrabHandle )
565     {
566       // TODO
567     }
568   }
569
570   void OnPan( Actor actor, const PanGesture& gesture )
571   {
572     if( actor == mGrabArea )
573     {
574       if( Gesture::Started == gesture.state )
575       {
576         mGrabDisplacementX = mGrabDisplacementY = 0;
577       }
578
579       mGrabDisplacementX += gesture.displacement.x;
580       mGrabDisplacementY += gesture.displacement.y;
581
582       float x = mCursor[PRIMARY_CURSOR].x + mGrabDisplacementX;
583       float y = mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height*0.5f + mGrabDisplacementY;
584
585       if( Gesture::Started    == gesture.state ||
586           Gesture::Continuing == gesture.state )
587       {
588         mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
589       }
590       else if( Gesture::Finished  == gesture.state ||
591                Gesture::Cancelled == gesture.state )
592       {
593         mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
594       }
595     }
596   }
597
598   bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
599   {
600     // TODO
601     return false;
602   }
603
604   bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
605   {
606     // TODO
607     return false;
608   }
609
610   /**
611    * Popup
612    */
613
614   void CreateOrderedListOfPopupOptions()
615   {
616     mCopyPastePopup.mOrderListOfButtons.clear();
617
618     // Create button for each possible option using Option priority
619     ResourceImage cutIcon = ResourceImage::New( OPTION_ICON_CUT );
620     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCut, mCopyPastePopup.mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon, true ) );
621
622     ResourceImage copyIcon = ResourceImage::New( OPTION_ICON_COPY );
623     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCopy, mCopyPastePopup.mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, true ) );
624
625     ResourceImage pasteIcon = ResourceImage::New( OPTION_ICON_PASTE );
626     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsPaste, mCopyPastePopup.mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, true ) );
627
628     ResourceImage selectIcon = ResourceImage::New( OPTION_ICON_SELECT );
629     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelect, mCopyPastePopup.mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon, true ) );
630
631     ResourceImage selectAllIcon = ResourceImage::New( OPTION_ICON_SELECT_ALL );
632     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelectAll, mCopyPastePopup.mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon, true ) );
633
634     ResourceImage clipboardIcon = ResourceImage::New( OPTION_ICON_CLIPBOARD );
635     mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsClipboard, mCopyPastePopup.mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true ) );
636
637     // Sort the buttons according their priorities.
638     std::sort( mCopyPastePopup.mOrderListOfButtons.begin(), mCopyPastePopup.mOrderListOfButtons.end(), PriorityCompare );
639   }
640
641   void CreateBackground( PopupImpl& popup )
642   {
643     // Create background-panel if not already created (required if we have at least one option)
644     if ( !popup.mBackground )
645     {
646       ResourceImage bgImg = ResourceImage::New( POPUP_BACKGROUND );
647       popup.mBackground = ImageActor::New( bgImg );
648       popup.mBackground.SetColor( popup.mBackgroundColor );
649       popup.mBackground.SetParentOrigin( ParentOrigin::CENTER );
650
651       NinePatchImage backgroundImageNinePatch = NinePatchImage::DownCast( bgImg );
652       if( backgroundImageNinePatch )
653       {
654         const Size ninePatchImageSize = Size( static_cast<float>( bgImg.GetWidth() ), static_cast<float>( bgImg.GetHeight() ) );
655         Rect<int> childRect = backgroundImageNinePatch.GetChildRectangle();
656
657         // -1u because of the cropping.
658         popup.mNinePatchMargins.x = childRect.x - 1u;
659         popup.mNinePatchMargins.y = ninePatchImageSize.width - ( childRect.x + childRect.width ) - 1u;
660         popup.mNinePatchMargins.z = childRect.y - 1u;
661         popup.mNinePatchMargins.w = ninePatchImageSize.height - ( childRect.y + childRect.height ) - 1u;
662       }
663
664       ResourceImage::Image bgEffectImg = ResourceImage::New( POPUP_BACKGROUND_EFFECT );
665       ImageActor backgroundEffect = ImageActor::New( bgEffectImg );
666       backgroundEffect.SetParentOrigin( ParentOrigin::CENTER );
667
668       ResourceImage::Image bgLine = ResourceImage::New( POPUP_BACKGROUND_LINE );
669       ImageActor backgroundLine = ImageActor::New( bgLine );
670       backgroundLine.SetParentOrigin( ParentOrigin::CENTER );
671       backgroundLine.SetColor( popup.mLineColor );
672
673       popup.mBackground.Add( backgroundEffect );
674       popup.mBackground.Add( backgroundLine );
675     }
676   }
677
678   void AddOption( Actor& parent, const std::string& name, const std::string& caption, const Image iconImage, bool finalOption, bool showIcons )
679   {
680     // 1. Create the backgrounds for the popup option both normal and pressed.
681     // Both containers will be added to a button.
682     Actor optionContainer = Actor::New();
683     optionContainer.SetDrawMode( DrawMode::OVERLAY );
684     //optionContainer.SetParentOrigin( ParentOrigin::CENTER );
685     optionContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
686
687     ImageActor optionPressedContainer = Toolkit::CreateSolidColorActor( mCopyPastePopup.mBackgroundPressedColor );
688     optionPressedContainer.SetDrawMode( DrawMode::OVERLAY );
689     //optionPressedContainer.SetParentOrigin( ParentOrigin::CENTER );
690     optionPressedContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
691
692     // 2. Add text.
693     Toolkit::TextLabel captionTextLabel = Toolkit::TextLabel::New();
694     captionTextLabel.SetProperty( TextLabel::Property::TEXT, caption );
695     optionContainer.Add( captionTextLabel );
696
697     Toolkit::TextLabel pressedCaptionTextLabel = Toolkit::TextLabel::New();
698     pressedCaptionTextLabel.SetProperty( TextLabel::Property::TEXT, caption );
699     optionPressedContainer.Add( pressedCaptionTextLabel );
700
701     // Calculates the icon/text position.
702     float iconTextOffsetY = 0.0f;
703
704     if ( showIcons )
705     {
706       // 3. Create the icons
707       ImageActor pressedIcon = ImageActor::New(  iconImage );
708       ImageActor icon = ImageActor::New(  iconImage );
709
710       optionContainer.Add( icon );
711       optionPressedContainer.Add( pressedIcon );
712
713       iconTextOffsetY = 0.5f * ( ( DEFAULT_POPUP_MAX_SIZE.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w ) - ( OPTION_ICON_SIZE.height + OPTION_GAP_ICON_TEXT + OPTION_TEXT_LINE_HEIGHT ) );
714
715       icon.SetParentOrigin( ParentOrigin::TOP_CENTER );
716       icon.SetAnchorPoint( AnchorPoint::TOP_CENTER );
717       icon.SetY( iconTextOffsetY );
718
719       pressedIcon.SetParentOrigin( ParentOrigin::TOP_CENTER );
720       pressedIcon.SetAnchorPoint( AnchorPoint::TOP_CENTER );
721       pressedIcon.SetY( iconTextOffsetY );
722
723       // Layout icon + gap + text
724       captionTextLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
725       pressedCaptionTextLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
726       pressedCaptionTextLabel.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
727       captionTextLabel.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
728       pressedCaptionTextLabel.SetY( -iconTextOffsetY );
729       captionTextLabel.SetY( -iconTextOffsetY );
730     }
731     else
732     {
733       // Centre option text
734       captionTextLabel.SetAnchorPoint( AnchorPoint::CENTER );
735       captionTextLabel.SetParentOrigin( ParentOrigin::CENTER );
736       pressedCaptionTextLabel.SetAnchorPoint( AnchorPoint::CENTER );
737       pressedCaptionTextLabel.SetParentOrigin( ParentOrigin::CENTER );
738     }
739
740     // Calculate the size of the text.
741     Vector3 textSize = captionTextLabel.GetNaturalSize();
742     textSize.width = std::min( textSize.width, OPTION_MAX_WIDTH - 2.f * OPTION_MARGIN_WIDTH );
743
744     // Set the size to the text. Text will be ellipsized if exceeds the max width.
745     captionTextLabel.SetSize( textSize );
746     pressedCaptionTextLabel.SetSize( textSize );
747
748     // 4. Calculate the size of option.
749
750     // The width is the max size of the text or the icon plus the margins clamped between the option min and max size.
751     // The height is the whole popup height minus the ninepatch margins.
752     const Vector2 optionSize( std::min( OPTION_MAX_WIDTH, std::max( OPTION_MIN_WIDTH, std::max( textSize.width, OPTION_ICON_SIZE.width ) + 2.f * OPTION_MARGIN_WIDTH ) ),
753                               DEFAULT_POPUP_MAX_SIZE.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w );
754
755     optionContainer.SetSize( optionSize );
756     optionPressedContainer.SetSize( optionSize );
757
758     // 5. Create a option.
759     Toolkit::PushButton option = Toolkit::PushButton::New();
760     option.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
761     option.SetSize( optionSize );
762     option.SetAnchorPoint( AnchorPoint::TOP_LEFT );
763     option.SetX( mCopyPastePopup.mContentSize.width );
764     option.SetName( name );
765     option.SetAnimationTime( 0.0f );
766     //option.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
767
768     parent.Add( option );
769
770     // 6. Set the normal option image.
771     option.SetButtonImage( optionContainer );
772
773     // 7. Set the pressed option image
774     option.SetSelectedImage( optionPressedContainer );
775
776     // 8. Update the content size.
777     mCopyPastePopup.mContentSize.width += optionSize.width;
778     mCopyPastePopup.mContentSize.height = std::max ( optionSize.height, mCopyPastePopup.mContentSize.height );
779
780     // 9. Add the divider
781     if( !finalOption )
782     {
783       const Size size( POPUP_DIVIDER_WIDTH, mCopyPastePopup.mContentSize.height );
784
785       ImageActor divider =  Toolkit::CreateSolidColorActor( Color::WHITE );
786       divider.SetSize (size);
787       divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
788       divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
789       divider.SetPosition( mCopyPastePopup.mContentSize.width - POPUP_DIVIDER_WIDTH, 0.0f );
790       parent.Add( divider );
791     }
792   }
793
794   void SetUpPopup( Actor& popupRootActor, Size& size )
795   {
796     // Create Layer and Stencil.
797     popupRootActor = Actor::New();
798     mCopyPastePopup.mStencilLayer = Layer::New();
799     ImageActor stencil = CreateSolidColorActor( Color::RED );
800     stencil.SetDrawMode( DrawMode::STENCIL );
801     stencil.SetVisible( true );
802     Actor scrollview = Actor::New();
803
804     //todo Use Size negotiation
805     mCopyPastePopup.mStencilLayer.SetSize( size ); // matches stencil size
806     popupRootActor.SetSize( size ); // matches stencil size
807     stencil.SetSize( size );
808     scrollview.SetSize( size );
809     mCopyPastePopup.mButtons.SetSize( size );
810
811     mCopyPastePopup.mStencilLayer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
812     scrollview.SetAnchorPoint(AnchorPoint::TOP_LEFT);
813     mCopyPastePopup.mButtons.SetAnchorPoint( AnchorPoint::TOP_LEFT );
814
815     mActiveLayer.Add( mCopyPastePopup.mRoot );
816     popupRootActor.Add( mCopyPastePopup.mBackground );
817     popupRootActor.Add( mCopyPastePopup.mStencilLayer );
818     mCopyPastePopup.mStencilLayer.Add( stencil );
819     mCopyPastePopup.mStencilLayer.Add( scrollview );
820     scrollview.Add( mCopyPastePopup.mButtons );
821   }
822
823   void AddPopupOptions( bool createTail, bool showIcons )
824   {
825     mCopyPastePopup.mShowIcons = showIcons;
826
827     mCopyPastePopup.mContentSize = Vector2::ZERO;
828
829     mCopyPastePopup.mButtons = Actor::New();
830
831     // Add the options into the buttons container.
832
833     // 1. Determine how many buttons are active and should be added to container.
834     std::size_t numberOfOptions = 0u;
835     for( std::vector<ButtonRequirement>::const_iterator it = mCopyPastePopup.mOrderListOfButtons.begin(), endIt = mCopyPastePopup.mOrderListOfButtons.end(); ( it != endIt ); ++it )
836     {
837       const ButtonRequirement& button( *it );
838       if( button.enabled )
839       {
840         ++numberOfOptions;
841       }
842     }
843
844     // 2. Iterate list of buttons and add active ones.
845     std::size_t optionsAdded = 0u;
846     for( std::vector<ButtonRequirement>::const_iterator it = mCopyPastePopup.mOrderListOfButtons.begin(), endIt = mCopyPastePopup.mOrderListOfButtons.end(); ( it != endIt ); ++it )
847     {
848       const ButtonRequirement& button( *it );
849       if ( button.enabled )
850       {
851         ++optionsAdded;
852         AddOption( mCopyPastePopup.mButtons, button.name, button.caption, button.icon, optionsAdded == numberOfOptions, mCopyPastePopup.mShowIcons );
853       }
854     }
855
856     // Calculate the size of the whole popup which may not be all visible.
857     mCopyPastePopup.mRequiredPopUpSize = Size( std::min( mCopyPastePopup.mMaxWidth, mCopyPastePopup.mContentSize.width + mCopyPastePopup.mNinePatchMargins.x + mCopyPastePopup.mNinePatchMargins.y ), DEFAULT_POPUP_MAX_SIZE. height );
858
859     // Set the size of the background, background line and background effect.
860     mCopyPastePopup.mBackground.SetSize( mCopyPastePopup.mRequiredPopUpSize);
861     for( std::size_t index = 0u, childCount = mCopyPastePopup.mBackground.GetChildCount(); index < childCount; ++index )
862     {
863       mCopyPastePopup.mBackground.GetChildAt( index ).SetSize( mCopyPastePopup.mRequiredPopUpSize );
864     }
865
866     // Size of the contents within the popup
867     mCopyPastePopup.mVisiblePopUpSize = Size( mCopyPastePopup.mRequiredPopUpSize.width - mCopyPastePopup.mNinePatchMargins.x - mCopyPastePopup.mNinePatchMargins.y, mCopyPastePopup.mRequiredPopUpSize.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w );
868
869   }
870
871   void CreatePopup()
872   {
873     if ( !mCopyPastePopup.mRoot )
874     {
875       mActiveCopyPastePopup = true;
876       CreateOrderedListOfPopupOptions();  //todo Currently causes all options to be shown
877       CreateBackground( mCopyPastePopup );
878       AddPopupOptions( true, true );
879       SetUpPopup( mCopyPastePopup.mRoot, mCopyPastePopup.mVisiblePopUpSize );
880     }
881
882     mCopyPastePopup.mStencilLayer.RaiseToTop();
883   }
884
885   void DestroyPopup()
886   {
887     if ( mCopyPastePopup.mRoot )
888     {
889       mActiveCopyPastePopup = false;
890       UnparentAndReset( mCopyPastePopup.mButtons );
891       UnparentAndReset( mCopyPastePopup.mRoot );
892     }
893   }
894
895   Internal::Control& mTextControlParent;
896   Observer& mObserver;
897
898   Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else.
899
900   unsigned int mActiveCursor;
901   bool         mActiveGrabHandle;
902   bool         mActiveSelection;
903   bool         mActiveCopyPastePopup;
904
905   CursorImpl mCursor[CURSOR_COUNT];
906
907   Timer mCursorBlinkTimer; // Timer to signal cursor to blink
908   unsigned int mCursorBlinkInterval;
909   float mCursorBlinkDuration;
910   bool mCursorBlinkStatus; // Flag to switch between blink on and blink off
911
912   ImageActor mPrimaryCursor;
913   ImageActor mSecondaryCursor;
914
915   ImageActor mGrabHandle;
916   Actor mGrabArea;
917   float mGrabDisplacementX;
918   float mGrabDisplacementY;
919
920   SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT];
921
922   PopupImpl mCopyPastePopup;
923
924   Image mCursorImage;
925   Image mGrabHandleImage;
926
927   TapGestureDetector mTapDetector;
928   PanGestureDetector mPanGestureDetector;
929
930   Rect<int> mBoundingBox;
931 };
932
933 DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
934 {
935   return DecoratorPtr( new Decorator(parent, observer) );
936 }
937
938 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
939 {
940   mImpl->mBoundingBox = boundingBox;
941 }
942
943 const Rect<int>& Decorator::GetBoundingBox() const
944 {
945   return mImpl->mBoundingBox;
946 }
947
948 void Decorator::Relayout( const Vector2& size, const Vector2& scrollPosition )
949 {
950   mImpl->Relayout( size, scrollPosition );
951 }
952
953 /** Cursor **/
954
955 void Decorator::SetActiveCursor( ActiveCursor activeCursor )
956 {
957   mImpl->mActiveCursor = activeCursor;
958 }
959
960 unsigned int Decorator::GetActiveCursor() const
961 {
962   return mImpl->mActiveCursor;
963 }
964
965 void Decorator::SetPosition( Cursor cursor, float x, float y, float height )
966 {
967   // Adjust grab handle displacement
968   mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].x;
969   mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].y;
970
971   mImpl->mCursor[cursor].x = x;
972   mImpl->mCursor[cursor].y = y;
973   mImpl->mCursor[cursor].height = height;
974 }
975
976 void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& height ) const
977 {
978   x = mImpl->mCursor[cursor].x;
979   y = mImpl->mCursor[cursor].y;
980   height = mImpl->mCursor[cursor].height;
981 }
982
983 void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color )
984 {
985   mImpl->mCursor[cursor].color = color;
986 }
987
988 const Dali::Vector4& Decorator::GetColor( Cursor cursor ) const
989 {
990   return mImpl->mCursor[cursor].color;
991 }
992
993 void Decorator::StartCursorBlink()
994 {
995   if ( !mImpl->mCursorBlinkTimer )
996   {
997     mImpl->mCursorBlinkTimer = Timer::New( mImpl->mCursorBlinkInterval );
998     mImpl->mCursorBlinkTimer.TickSignal().Connect( mImpl, &Decorator::Impl::OnCursorBlinkTimerTick );
999   }
1000
1001   if ( !mImpl->mCursorBlinkTimer.IsRunning() )
1002   {
1003     mImpl->mCursorBlinkTimer.Start();
1004   }
1005 }
1006
1007 void Decorator::StopCursorBlink()
1008 {
1009   if ( mImpl->mCursorBlinkTimer )
1010   {
1011     mImpl->mCursorBlinkTimer.Stop();
1012   }
1013 }
1014
1015 void Decorator::SetCursorBlinkInterval( float seconds )
1016 {
1017   mImpl->mCursorBlinkInterval = seconds*MILLISECONDS; // Convert to milliseconds
1018 }
1019
1020 float Decorator::GetCursorBlinkInterval() const
1021 {
1022   return mImpl->mCursorBlinkInterval;
1023 }
1024
1025 void Decorator::SetCursorBlinkDuration( float seconds )
1026 {
1027   mImpl->mCursorBlinkDuration = seconds;
1028 }
1029
1030 float Decorator::GetCursorBlinkDuration() const
1031 {
1032   return mImpl->mCursorBlinkDuration;
1033 }
1034
1035 /** GrabHandle **/
1036
1037 void Decorator::SetGrabHandleActive( bool active )
1038 {
1039   mImpl->mActiveGrabHandle = active;
1040 }
1041
1042 bool Decorator::IsGrabHandleActive() const
1043 {
1044   return mImpl->mActiveGrabHandle;
1045 }
1046
1047 void Decorator::SetGrabHandleImage( Dali::Image image )
1048 {
1049   mImpl->mGrabHandleImage = image;
1050 }
1051
1052 Dali::Image Decorator::GetGrabHandleImage() const
1053 {
1054   return mImpl->mGrabHandleImage;
1055 }
1056
1057 /** Selection **/
1058
1059 void Decorator::SetSelectionActive( bool active )
1060 {
1061   mImpl->mActiveSelection = active;
1062 }
1063
1064 bool Decorator::IsSelectionActive() const
1065 {
1066   return mImpl->mActiveSelection;
1067 }
1068
1069 void Decorator::SetPosition( SelectionHandle handle, float x, float y, float height )
1070 {
1071   mImpl->mSelectionHandle[handle].x = x;
1072   mImpl->mSelectionHandle[handle].y = y;
1073   mImpl->mSelectionHandle[handle].cursorHeight = height;
1074 }
1075
1076 void Decorator::GetPosition( SelectionHandle handle, float& x, float& y, float& height ) const
1077 {
1078   x = mImpl->mSelectionHandle[handle].x;
1079   y = mImpl->mSelectionHandle[handle].y;
1080   height = mImpl->mSelectionHandle[handle].cursorHeight;
1081 }
1082
1083 void Decorator::SetImage( SelectionHandle handle, SelectionHandleState state, Dali::Image image )
1084 {
1085   if( SELECTION_HANDLE_PRESSED == state )
1086   {
1087     mImpl->mSelectionHandle[handle].pressedImage = image;
1088   }
1089   else
1090   {
1091     mImpl->mSelectionHandle[handle].releasedImage = image;
1092   }
1093 }
1094
1095 Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState state ) const
1096 {
1097   if( SELECTION_HANDLE_PRESSED == state )
1098   {
1099     return mImpl->mSelectionHandle[handle].pressedImage;
1100   }
1101
1102   return mImpl->mSelectionHandle[handle].releasedImage;
1103 }
1104
1105 void Decorator::ShowPopup()
1106 {
1107   if ( !mImpl->mCopyPastePopup.mRoot )
1108   {
1109     mImpl->CreatePopup();
1110   }
1111 }
1112
1113 void Decorator::HidePopup()
1114 {
1115   if ( mImpl->mCopyPastePopup.mRoot )
1116   {
1117     mImpl->DestroyPopup();
1118   }
1119 }
1120
1121 Decorator::~Decorator()
1122 {
1123   delete mImpl;
1124 }
1125
1126 Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
1127 : mImpl( NULL )
1128 {
1129   mImpl = new Decorator::Impl( parent, observer );
1130 }
1131
1132 } // namespace Text
1133
1134 } // namespace Toolkit
1135
1136 } // namespace Dali