Adding TextSelectionPopup control
[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       mGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
330 #ifdef DECORATOR_DEBUG
331       mGrabArea.SetName( "GrabArea" );
332 #endif
333       mGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
334       mGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
335       mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
336       mGrabHandle.Add(mGrabArea);
337
338       mTapDetector.Attach( mGrabArea );
339       mPanGestureDetector.Attach( mGrabArea );
340
341       mActiveLayer.Add(mGrabHandle);
342     }
343   }
344
345   void CreateSelectionHandles()
346   {
347     SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
348     if ( !primary.actor )
349     {
350       if ( !primary.releasedImage )
351       {
352         primary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
353       }
354
355       primary.actor = ImageActor::New( primary.releasedImage );
356 #ifdef DECORATOR_DEBUG
357       primary.actor.SetName("SelectionHandleOne");
358 #endif
359       primary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
360       primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
361       primary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
362       primary.flipped = false;
363
364       primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
365 #ifdef DECORATOR_DEBUG
366       primary.grabArea.SetName("SelectionHandleOneGrabArea");
367 #endif
368       primary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
369       primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
370       primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
371
372       mTapDetector.Attach( primary.grabArea );
373       mPanGestureDetector.Attach( primary.grabArea );
374       primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
375
376       primary.actor.Add( primary.grabArea );
377       mActiveLayer.Add( primary.actor );
378     }
379
380     SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
381     if ( !secondary.actor )
382     {
383       if ( !secondary.releasedImage )
384       {
385         secondary.releasedImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
386       }
387
388       secondary.actor = ImageActor::New( secondary.releasedImage );
389 #ifdef DECORATOR_DEBUG
390       secondary.actor.SetName("SelectionHandleTwo");
391 #endif
392       secondary.actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
393       secondary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
394       secondary.actor.SetDrawMode( DrawMode::OVERLAY ); // ensure grab handle above text
395       secondary.flipped = false;
396
397       secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
398 #ifdef DECORATOR_DEBUG
399       secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
400 #endif
401       secondary.grabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT );
402       secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
403       secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
404
405       mTapDetector.Attach( secondary.grabArea );
406       mPanGestureDetector.Attach( secondary.grabArea );
407       secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
408
409       secondary.actor.Add( secondary.grabArea );
410       mActiveLayer.Add( secondary.actor );
411     }
412
413     //SetUpHandlePropertyNotifications(); TODO
414   }
415
416   void OnTap( Actor actor, const TapGesture& tap )
417   {
418     if( actor == mGrabHandle )
419     {
420       // TODO
421     }
422   }
423
424   void OnPan( Actor actor, const PanGesture& gesture )
425   {
426     if( actor == mGrabArea )
427     {
428       if( Gesture::Started == gesture.state )
429       {
430         mGrabDisplacementX = mGrabDisplacementY = 0;
431       }
432
433       mGrabDisplacementX += gesture.displacement.x;
434       mGrabDisplacementY += gesture.displacement.y;
435
436       float x = mCursor[PRIMARY_CURSOR].x + mGrabDisplacementX;
437       float y = mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height*0.5f + mGrabDisplacementY;
438
439       if( Gesture::Started    == gesture.state ||
440           Gesture::Continuing == gesture.state )
441       {
442         mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
443       }
444       else if( Gesture::Finished  == gesture.state ||
445                Gesture::Cancelled == gesture.state )
446       {
447         mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
448       }
449     }
450   }
451
452   bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
453   {
454     // TODO
455     return false;
456   }
457
458   bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
459   {
460     // TODO
461     return false;
462   }
463
464
465   Internal::Control& mTextControlParent;
466   Observer& mObserver;
467
468   Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else.
469
470   unsigned int mActiveCursor;
471   bool         mActiveGrabHandle;
472   bool         mActiveSelection;
473   bool         mActiveCopyPastePopup;
474
475   CursorImpl mCursor[CURSOR_COUNT];
476
477   Timer mCursorBlinkTimer; // Timer to signal cursor to blink
478   unsigned int mCursorBlinkInterval;
479   float mCursorBlinkDuration;
480   bool mCursorBlinkStatus; // Flag to switch between blink on and blink off
481
482   ImageActor mPrimaryCursor;
483   ImageActor mSecondaryCursor;
484
485   ImageActor mGrabHandle;
486   Actor mGrabArea;
487   float mGrabDisplacementX;
488   float mGrabDisplacementY;
489
490   SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT];
491
492   TextSelectionPopup mCopyPastePopup;
493
494   Image mCursorImage;
495   Image mGrabHandleImage;
496
497   TapGestureDetector mTapDetector;
498   PanGestureDetector mPanGestureDetector;
499
500   Rect<int> mBoundingBox;
501 };
502
503 DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
504 {
505   return DecoratorPtr( new Decorator(parent, observer) );
506 }
507
508 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
509 {
510   mImpl->mBoundingBox = boundingBox;
511 }
512
513 const Rect<int>& Decorator::GetBoundingBox() const
514 {
515   return mImpl->mBoundingBox;
516 }
517
518 void Decorator::Relayout( const Vector2& size, const Vector2& scrollPosition )
519 {
520   mImpl->Relayout( size, scrollPosition );
521 }
522
523 /** Cursor **/
524
525 void Decorator::SetActiveCursor( ActiveCursor activeCursor )
526 {
527   mImpl->mActiveCursor = activeCursor;
528 }
529
530 unsigned int Decorator::GetActiveCursor() const
531 {
532   return mImpl->mActiveCursor;
533 }
534
535 void Decorator::SetPosition( Cursor cursor, float x, float y, float height )
536 {
537   // Adjust grab handle displacement
538   mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].x;
539   mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].y;
540
541   mImpl->mCursor[cursor].x = x;
542   mImpl->mCursor[cursor].y = y;
543   mImpl->mCursor[cursor].height = height;
544 }
545
546 void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& height ) const
547 {
548   x = mImpl->mCursor[cursor].x;
549   y = mImpl->mCursor[cursor].y;
550   height = mImpl->mCursor[cursor].height;
551 }
552
553 void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color )
554 {
555   mImpl->mCursor[cursor].color = color;
556 }
557
558 const Dali::Vector4& Decorator::GetColor( Cursor cursor ) const
559 {
560   return mImpl->mCursor[cursor].color;
561 }
562
563 void Decorator::StartCursorBlink()
564 {
565   if ( !mImpl->mCursorBlinkTimer )
566   {
567     mImpl->mCursorBlinkTimer = Timer::New( mImpl->mCursorBlinkInterval );
568     mImpl->mCursorBlinkTimer.TickSignal().Connect( mImpl, &Decorator::Impl::OnCursorBlinkTimerTick );
569   }
570
571   if ( !mImpl->mCursorBlinkTimer.IsRunning() )
572   {
573     mImpl->mCursorBlinkTimer.Start();
574   }
575 }
576
577 void Decorator::StopCursorBlink()
578 {
579   if ( mImpl->mCursorBlinkTimer )
580   {
581     mImpl->mCursorBlinkTimer.Stop();
582   }
583 }
584
585 void Decorator::SetCursorBlinkInterval( float seconds )
586 {
587   mImpl->mCursorBlinkInterval = seconds*MILLISECONDS; // Convert to milliseconds
588 }
589
590 float Decorator::GetCursorBlinkInterval() const
591 {
592   return mImpl->mCursorBlinkInterval;
593 }
594
595 void Decorator::SetCursorBlinkDuration( float seconds )
596 {
597   mImpl->mCursorBlinkDuration = seconds;
598 }
599
600 float Decorator::GetCursorBlinkDuration() const
601 {
602   return mImpl->mCursorBlinkDuration;
603 }
604
605 /** GrabHandle **/
606
607 void Decorator::SetGrabHandleActive( bool active )
608 {
609   mImpl->mActiveGrabHandle = active;
610 }
611
612 bool Decorator::IsGrabHandleActive() const
613 {
614   return mImpl->mActiveGrabHandle;
615 }
616
617 void Decorator::SetGrabHandleImage( Dali::Image image )
618 {
619   mImpl->mGrabHandleImage = image;
620 }
621
622 Dali::Image Decorator::GetGrabHandleImage() const
623 {
624   return mImpl->mGrabHandleImage;
625 }
626
627 /** Selection **/
628
629 void Decorator::SetSelectionActive( bool active )
630 {
631   mImpl->mActiveSelection = active;
632 }
633
634 bool Decorator::IsSelectionActive() const
635 {
636   return mImpl->mActiveSelection;
637 }
638
639 void Decorator::SetPosition( SelectionHandle handle, float x, float y, float height )
640 {
641   mImpl->mSelectionHandle[handle].x = x;
642   mImpl->mSelectionHandle[handle].y = y;
643   mImpl->mSelectionHandle[handle].cursorHeight = height;
644 }
645
646 void Decorator::GetPosition( SelectionHandle handle, float& x, float& y, float& height ) const
647 {
648   x = mImpl->mSelectionHandle[handle].x;
649   y = mImpl->mSelectionHandle[handle].y;
650   height = mImpl->mSelectionHandle[handle].cursorHeight;
651 }
652
653 void Decorator::SetImage( SelectionHandle handle, SelectionHandleState state, Dali::Image image )
654 {
655   if( SELECTION_HANDLE_PRESSED == state )
656   {
657     mImpl->mSelectionHandle[handle].pressedImage = image;
658   }
659   else
660   {
661     mImpl->mSelectionHandle[handle].releasedImage = image;
662   }
663 }
664
665 Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState state ) const
666 {
667   if( SELECTION_HANDLE_PRESSED == state )
668   {
669     return mImpl->mSelectionHandle[handle].pressedImage;
670   }
671
672   return mImpl->mSelectionHandle[handle].releasedImage;
673 }
674
675 void Decorator::SetPopupActive( bool active )
676 {
677   mImpl->mActiveCopyPastePopup = active;
678 }
679
680 bool Decorator::IsPopupActive() const
681 {
682   return mImpl->mActiveCopyPastePopup ;
683 }
684
685 Decorator::~Decorator()
686 {
687   delete mImpl;
688 }
689
690 Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
691 : mImpl( NULL )
692 {
693   mImpl = new Decorator::Impl( parent, observer );
694 }
695
696 } // namespace Text
697
698 } // namespace Toolkit
699
700 } // namespace Dali