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