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