d8deaf634b92c05132ec452e7e778005410540cc
[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
37 // INTERNAL INCLUDES
38 #include <dali-toolkit/public-api/controls/control.h>
39 #include <dali-toolkit/public-api/controls/control-impl.h>
40 #include <dali-toolkit/public-api/controls/buttons/push-button.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/text-controls/text-selection-popup.h>
44
45 #ifdef DEBUG_ENABLED
46 #define DECORATOR_DEBUG
47 #endif
48
49 // Local Data
50 namespace
51 {
52
53 const char* DEFAULT_GRAB_HANDLE_IMAGE( DALI_IMAGE_DIR "insertpoint-icon.png" );
54 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
55 const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
56 //const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" );
57 //const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
58
59 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
60 const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
61
62 const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval
63 const std::size_t MILLISECONDS = 1000;
64
65 } // end of namespace
66
67 namespace Dali
68 {
69
70 namespace Toolkit
71 {
72
73 namespace Text
74 {
75
76 struct Decorator::Impl : public ConnectionTracker
77 {
78   struct CursorImpl
79   {
80     CursorImpl()
81     : x(0.0f),
82       y(0.0f),
83       height(0.0f),
84       color(Dali::Color::WHITE)
85     {
86     }
87
88     float x;
89     float y;
90     float height;
91
92     Vector4 color;
93   };
94
95   struct SelectionHandleImpl
96   {
97     SelectionHandleImpl()
98     : x(0.0f),
99       y(0.0f),
100       cursorHeight(0.0f),
101       flipped(false)
102     {
103     }
104
105     float x;
106     float y;
107     float cursorHeight; ///< Not the handle height
108     bool flipped;
109
110     ImageActor actor;
111     Actor grabArea;
112
113     Image pressedImage;
114     Image releasedImage;
115   };
116
117   Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
118   : mTextControlParent(parent),
119     mObserver(observer),
120     mActiveCursor(ACTIVE_CURSOR_NONE),
121     mActiveGrabHandle(false),
122     mActiveSelection( false ),
123     mActiveCopyPastePopup( false ),
124     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
125     mCursorBlinkDuration( 0.0f ),
126     mCursorBlinkStatus( true ),
127     mGrabDisplacementX( 0.0f ),
128     mGrabDisplacementY( 0.0f ),
129     mBoundingBox( Rect<int>() )
130   {
131   }
132
133   /**
134    * Relayout of the decorations owned by the decorator.
135    * @param[in] size The Size of the UI control the decorater is adding it's decorations to.
136    */
137   void Relayout( const Vector2& size, const Vector2& scrollPosition )
138   {
139     // TODO - Remove this if nothing is active
140     CreateActiveLayer();
141
142     // Show or hide the cursors
143     CreateCursors();
144     if( mPrimaryCursor )
145     {
146       mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x,
147                                   mCursor[PRIMARY_CURSOR].y + scrollPosition.y );
148       mPrimaryCursor.SetSize( 1.0f, mCursor[PRIMARY_CURSOR].height );
149     }
150     if( mSecondaryCursor )
151     {
152       mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].x + scrollPosition.x,
153                                     mCursor[SECONDARY_CURSOR].y + scrollPosition.y );
154       mSecondaryCursor.SetSize( 1.0f, mCursor[SECONDARY_CURSOR].height );
155     }
156
157     // Show or hide the grab handle
158     if( mActiveGrabHandle )
159     {
160       SetupTouchEvents();
161
162       CreateGrabHandle();
163
164       mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x,
165                                mCursor[PRIMARY_CURSOR].y + scrollPosition.y + mCursor[PRIMARY_CURSOR].height );
166     }
167     else if( mGrabHandle )
168     {
169       UnparentAndReset( mGrabHandle );
170     }
171
172     // Show or hide the selection handles/highlight
173     if( mActiveSelection )
174     {
175       SetupTouchEvents();
176
177       CreateSelectionHandles();
178
179       SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
180       primary.actor.SetPosition( primary.x + scrollPosition.x,
181                                  primary.y + scrollPosition.y + primary.cursorHeight );
182
183       SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
184       secondary.actor.SetPosition( secondary.x + scrollPosition.x,
185                                    secondary.y + scrollPosition.y + secondary.cursorHeight );
186
187       //CreateHighlight(); TODO
188     }
189     else
190     {
191       UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor );
192       UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor );
193     }
194
195     if ( mActiveCopyPastePopup )
196     {
197       if ( !mCopyPastePopup )
198       {
199         mCopyPastePopup = TextSelectionPopup::New();
200         mActiveLayer.Add ( mCopyPastePopup );
201       }
202       mCopyPastePopup.SetPosition( Vector3( 200.0f, -100.0f, 0.0f ) ); //todo grabhandle or selection handle positions to be used
203     }
204     else
205     {
206      if ( mCopyPastePopup )
207      {
208        UnparentAndReset( mCopyPastePopup );
209      }
210     }
211   }
212
213   void CreateCursor( ImageActor& cursor )
214   {
215     cursor = CreateSolidColorActor( Color::WHITE );
216     cursor.SetParentOrigin( ParentOrigin::TOP_LEFT );
217     cursor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
218   }
219
220   // Add or Remove cursor(s) from parent
221   void CreateCursors()
222   {
223     if( mActiveCursor == ACTIVE_CURSOR_NONE )
224     {
225       UnparentAndReset( mPrimaryCursor );
226       UnparentAndReset( mSecondaryCursor );
227     }
228     else
229     {
230       /* Create Primary and or Secondary Cursor(s) if active and add to parent */
231       if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ||
232            mActiveCursor == ACTIVE_CURSOR_BOTH )
233       {
234         if ( !mPrimaryCursor )
235         {
236           CreateCursor( mPrimaryCursor );
237 #ifdef DECORATOR_DEBUG
238           mPrimaryCursor.SetName( "PrimaryCursorActor" );
239 #endif
240           mActiveLayer.Add( mPrimaryCursor);
241         }
242       }
243
244       if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
245       {
246         if ( !mSecondaryCursor )
247         {
248           CreateCursor( mSecondaryCursor );
249 #ifdef DECORATOR_DEBUG
250           mSecondaryCursor.SetName( "SecondaryCursorActor" );
251 #endif
252           mActiveLayer.Add( mSecondaryCursor);
253         }
254       }
255     }
256   }
257
258   bool OnCursorBlinkTimerTick()
259   {
260     // Cursor blinking
261     if ( mPrimaryCursor )
262     {
263       mPrimaryCursor.SetVisible( mCursorBlinkStatus );
264     }
265     if ( mSecondaryCursor )
266     {
267       mSecondaryCursor.SetVisible( mCursorBlinkStatus );
268     }
269
270     mCursorBlinkStatus = !mCursorBlinkStatus;
271
272     return true;
273   }
274
275   void SetupTouchEvents()
276   {
277     if ( !mTapDetector )
278     {
279       mTapDetector = TapGestureDetector::New();
280       mTapDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnTap );
281     }
282
283     if ( !mPanGestureDetector )
284     {
285       mPanGestureDetector = PanGestureDetector::New();
286       mPanGestureDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
287     }
288   }
289
290   void CreateActiveLayer()
291   {
292     if( !mActiveLayer )
293     {
294       Actor parent = mTextControlParent.Self();
295
296       mActiveLayer = Layer::New();
297 #ifdef DECORATOR_DEBUG
298       mActiveLayer.SetName ( "ActiveLayerActor" );
299 #endif
300
301       mActiveLayer.SetAnchorPoint( AnchorPoint::CENTER);
302       mActiveLayer.SetParentOrigin( ParentOrigin::CENTER);
303       mActiveLayer.SetSizeMode( SIZE_EQUAL_TO_PARENT );
304       mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
305
306       parent.Add( mActiveLayer );
307     }
308
309     mActiveLayer.RaiseToTop();
310   }
311
312   void CreateGrabHandle()
313   {
314     if( !mGrabHandle )
315     {
316       if ( !mGrabHandleImage )
317       {
318         mGrabHandleImage = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE );
319       }
320
321       mGrabHandle = ImageActor::New( mGrabHandleImage );
322 #ifdef DECORATOR_DEBUG
323       mGrabHandle.SetName( "GrabHandleActor" );
324 #endif
325       mGrabHandle.SetParentOrigin( ParentOrigin::TOP_LEFT );
326       mGrabHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER );
327       mGrabHandle.SetDrawMode( DrawMode::OVERLAY );
328
329       // Area that Grab handle responds to, larger than actual handle so easier to move
330 #ifdef DECORATOR_DEBUG
331       mGrabArea = Toolkit::CreateSolidColorActor( Vector4(1.0f, 0.0f, 0.0f, 0.5f) );
332       mGrabArea.SetName( "GrabArea" );
333 #else
334       mGrabArea = Actor::New();
335 #endif
336       mGrabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
337       mGrabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
338       mGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
339       mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
340       mGrabHandle.Add(mGrabArea);
341
342       mTapDetector.Attach( mGrabArea );
343       mPanGestureDetector.Attach( mGrabArea );
344
345       mActiveLayer.Add(mGrabHandle);
346     }
347   }
348
349   void CreateSelectionHandles()
350   {
351     SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
352     if ( !primary.actor )
353     {
354       if ( !primary.releasedImage )
355       {
356         primary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
357       }
358
359       primary.actor = ImageActor::New( primary.releasedImage );
360 #ifdef DECORATOR_DEBUG
361       primary.actor.SetName("SelectionHandleOne");
362 #endif
363       primary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
364       primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
365       primary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
366       primary.flipped = false;
367
368       primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
369 #ifdef DECORATOR_DEBUG
370       primary.grabArea.SetName("SelectionHandleOneGrabArea");
371 #endif
372       primary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
373       primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
374       primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
375
376       mTapDetector.Attach( primary.grabArea );
377       mPanGestureDetector.Attach( primary.grabArea );
378       primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
379
380       primary.actor.Add( primary.grabArea );
381       mActiveLayer.Add( primary.actor );
382     }
383
384     SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
385     if ( !secondary.actor )
386     {
387       if ( !secondary.releasedImage )
388       {
389         secondary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
390       }
391
392       secondary.actor = ImageActor::New( secondary.releasedImage );
393 #ifdef DECORATOR_DEBUG
394       secondary.actor.SetName("SelectionHandleTwo");
395 #endif
396       secondary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
397       secondary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
398       secondary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
399       secondary.flipped = false;
400
401       secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
402 #ifdef DECORATOR_DEBUG
403       secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
404 #endif
405       secondary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
406       secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
407       secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
408
409       mTapDetector.Attach( secondary.grabArea );
410       mPanGestureDetector.Attach( secondary.grabArea );
411       secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
412
413       secondary.actor.Add( secondary.grabArea );
414       mActiveLayer.Add( secondary.actor );
415     }
416
417     //SetUpHandlePropertyNotifications(); TODO
418   }
419
420   void OnTap( Actor actor, const TapGesture& tap )
421   {
422     if( actor == mGrabHandle )
423     {
424       // TODO
425     }
426   }
427
428   void OnPan( Actor actor, const PanGesture& gesture )
429   {
430     if( actor == mGrabArea )
431     {
432       if( Gesture::Started == gesture.state )
433       {
434         mGrabDisplacementX = mGrabDisplacementY = 0;
435       }
436
437       mGrabDisplacementX += gesture.displacement.x;
438       mGrabDisplacementY += gesture.displacement.y;
439
440       float x = mCursor[PRIMARY_CURSOR].x + mGrabDisplacementX;
441       float y = mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height*0.5f + mGrabDisplacementY;
442
443       if( Gesture::Started    == gesture.state ||
444           Gesture::Continuing == gesture.state )
445       {
446         mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
447       }
448       else if( Gesture::Finished  == gesture.state ||
449                Gesture::Cancelled == gesture.state )
450       {
451         mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
452       }
453     }
454   }
455
456   bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
457   {
458     // TODO
459     return false;
460   }
461
462   bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
463   {
464     // TODO
465     return false;
466   }
467
468
469   Internal::Control& mTextControlParent;
470   Observer& mObserver;
471
472   Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else.
473
474   unsigned int mActiveCursor;
475   bool         mActiveGrabHandle;
476   bool         mActiveSelection;
477   bool         mActiveCopyPastePopup;
478
479   CursorImpl mCursor[CURSOR_COUNT];
480
481   Timer mCursorBlinkTimer; // Timer to signal cursor to blink
482   unsigned int mCursorBlinkInterval;
483   float mCursorBlinkDuration;
484   bool mCursorBlinkStatus; // Flag to switch between blink on and blink off
485
486   ImageActor mPrimaryCursor;
487   ImageActor mSecondaryCursor;
488
489   ImageActor mGrabHandle;
490   Actor mGrabArea;
491   float mGrabDisplacementX;
492   float mGrabDisplacementY;
493
494   SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT];
495
496   TextSelectionPopup mCopyPastePopup;
497
498   Image mCursorImage;
499   Image mGrabHandleImage;
500
501   TapGestureDetector mTapDetector;
502   PanGestureDetector mPanGestureDetector;
503
504   Rect<int> mBoundingBox;
505 };
506
507 DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
508 {
509   return DecoratorPtr( new Decorator(parent, observer) );
510 }
511
512 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
513 {
514   mImpl->mBoundingBox = boundingBox;
515 }
516
517 const Rect<int>& Decorator::GetBoundingBox() const
518 {
519   return mImpl->mBoundingBox;
520 }
521
522 void Decorator::Relayout( const Vector2& size, const Vector2& scrollPosition )
523 {
524   mImpl->Relayout( size, scrollPosition );
525 }
526
527 /** Cursor **/
528
529 void Decorator::SetActiveCursor( ActiveCursor activeCursor )
530 {
531   mImpl->mActiveCursor = activeCursor;
532 }
533
534 unsigned int Decorator::GetActiveCursor() const
535 {
536   return mImpl->mActiveCursor;
537 }
538
539 void Decorator::SetPosition( Cursor cursor, float x, float y, float height )
540 {
541   // Adjust grab handle displacement
542   mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].x;
543   mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].y;
544
545   mImpl->mCursor[cursor].x = x;
546   mImpl->mCursor[cursor].y = y;
547   mImpl->mCursor[cursor].height = height;
548 }
549
550 void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& height ) const
551 {
552   x = mImpl->mCursor[cursor].x;
553   y = mImpl->mCursor[cursor].y;
554   height = mImpl->mCursor[cursor].height;
555 }
556
557 void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color )
558 {
559   mImpl->mCursor[cursor].color = color;
560 }
561
562 const Dali::Vector4& Decorator::GetColor( Cursor cursor ) const
563 {
564   return mImpl->mCursor[cursor].color;
565 }
566
567 void Decorator::StartCursorBlink()
568 {
569   if ( !mImpl->mCursorBlinkTimer )
570   {
571     mImpl->mCursorBlinkTimer = Timer::New( mImpl->mCursorBlinkInterval );
572     mImpl->mCursorBlinkTimer.TickSignal().Connect( mImpl, &Decorator::Impl::OnCursorBlinkTimerTick );
573   }
574
575   if ( !mImpl->mCursorBlinkTimer.IsRunning() )
576   {
577     mImpl->mCursorBlinkTimer.Start();
578   }
579 }
580
581 void Decorator::StopCursorBlink()
582 {
583   if ( mImpl->mCursorBlinkTimer )
584   {
585     mImpl->mCursorBlinkTimer.Stop();
586   }
587 }
588
589 void Decorator::SetCursorBlinkInterval( float seconds )
590 {
591   mImpl->mCursorBlinkInterval = seconds*MILLISECONDS; // Convert to milliseconds
592 }
593
594 float Decorator::GetCursorBlinkInterval() const
595 {
596   return mImpl->mCursorBlinkInterval;
597 }
598
599 void Decorator::SetCursorBlinkDuration( float seconds )
600 {
601   mImpl->mCursorBlinkDuration = seconds;
602 }
603
604 float Decorator::GetCursorBlinkDuration() const
605 {
606   return mImpl->mCursorBlinkDuration;
607 }
608
609 /** GrabHandle **/
610
611 void Decorator::SetGrabHandleActive( bool active )
612 {
613   mImpl->mActiveGrabHandle = active;
614 }
615
616 bool Decorator::IsGrabHandleActive() const
617 {
618   return mImpl->mActiveGrabHandle;
619 }
620
621 void Decorator::SetGrabHandleImage( Dali::Image image )
622 {
623   mImpl->mGrabHandleImage = image;
624 }
625
626 Dali::Image Decorator::GetGrabHandleImage() const
627 {
628   return mImpl->mGrabHandleImage;
629 }
630
631 /** Selection **/
632
633 void Decorator::SetSelectionActive( bool active )
634 {
635   mImpl->mActiveSelection = active;
636 }
637
638 bool Decorator::IsSelectionActive() const
639 {
640   return mImpl->mActiveSelection;
641 }
642
643 void Decorator::SetPosition( SelectionHandle handle, float x, float y, float height )
644 {
645   mImpl->mSelectionHandle[handle].x = x;
646   mImpl->mSelectionHandle[handle].y = y;
647   mImpl->mSelectionHandle[handle].cursorHeight = height;
648 }
649
650 void Decorator::GetPosition( SelectionHandle handle, float& x, float& y, float& height ) const
651 {
652   x = mImpl->mSelectionHandle[handle].x;
653   y = mImpl->mSelectionHandle[handle].y;
654   height = mImpl->mSelectionHandle[handle].cursorHeight;
655 }
656
657 void Decorator::SetImage( SelectionHandle handle, SelectionHandleState state, Dali::Image image )
658 {
659   if( SELECTION_HANDLE_PRESSED == state )
660   {
661     mImpl->mSelectionHandle[handle].pressedImage = image;
662   }
663   else
664   {
665     mImpl->mSelectionHandle[handle].releasedImage = image;
666   }
667 }
668
669 Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState state ) const
670 {
671   if( SELECTION_HANDLE_PRESSED == state )
672   {
673     return mImpl->mSelectionHandle[handle].pressedImage;
674   }
675
676   return mImpl->mSelectionHandle[handle].releasedImage;
677 }
678
679 void Decorator::SetPopupActive( bool active )
680 {
681   mImpl->mActiveCopyPastePopup = active;
682 }
683
684 bool Decorator::IsPopupActive() const
685 {
686   return mImpl->mActiveCopyPastePopup ;
687 }
688
689 Decorator::~Decorator()
690 {
691   delete mImpl;
692 }
693
694 Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
695 : mImpl( NULL )
696 {
697   mImpl = new Decorator::Impl( parent, observer );
698 }
699
700 } // namespace Text
701
702 } // namespace Toolkit
703
704 } // namespace Dali