Tizen 2.4 SDK Rev6 Release
[framework/graphics/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-selection-popup-impl.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/controls/text-controls/text-selection-popup-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
23 #include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
24 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
25 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
26
27 // EXTERNAL INCLUDES
28 #include <dali/public-api/animation/animation.h>
29 #include <dali/public-api/animation/constraints.h>
30 #include <dali/public-api/images/nine-patch-image.h>
31 #include <dali/public-api/math/vector2.h>
32 #include <dali/public-api/math/vector4.h>
33 #include <dali/public-api/object/property-map.h>
34 #include <dali/devel-api/object/type-registry-helper.h>
35 #include <dali/integration-api/debug.h>
36
37 #include <libintl.h>
38 #include <cfloat>
39 #include <feedback/feedback.h>
40
41 namespace Dali
42 {
43
44 namespace Toolkit
45 {
46
47 namespace Internal
48 {
49
50 namespace
51 {
52 // todo Move this to adaptor??
53 #define GET_LOCALE_TEXT(string) dgettext("dali-toolkit", string)
54
55 const std::string TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME( "textselectionpopupbutton" );
56 const Dali::Vector4 DEFAULT_OPTION_PRESSED_COLOR( Dali::Vector4( 0.24f, 0.72f, 0.8f, 1.0f ) );
57
58 #if defined(DEBUG_ENABLED)
59   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
60 #endif
61
62 #ifdef DGETTEXT_ENABLED
63
64 #define POPUP_CUT_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CUT")
65 #define POPUP_COPY_STRING GET_LOCALE_TEXT("IDS_COM_BODY_COPY")
66 #define POPUP_PASTE_STRING GET_LOCALE_TEXT("IDS_COM_BODY_PASTE")
67 #define POPUP_SELECT_STRING GET_LOCALE_TEXT("IDS_COM_SK_SELECT")
68 #define POPUP_SELECT_ALL_STRING GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL")
69 #define POPUP_CLIPBOARD_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD")
70
71 #else
72
73 #define POPUP_CUT_STRING  "Cut"
74 #define POPUP_COPY_STRING  "Copy"
75 #define POPUP_PASTE_STRING  "Paste"
76 #define POPUP_SELECT_STRING  "Select"
77 #define POPUP_SELECT_ALL_STRING  "Select All"
78 #define POPUP_CLIPBOARD_STRING  "Clipboard"
79
80 #endif
81
82 const char* const OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
83 const char* const OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
84 const char* const OPTION_CUT("option-cut");                                        // "Cut" popup option.
85 const char* const OPTION_COPY("option-copy");                                      // "Copy" popup option.
86 const char* const OPTION_PASTE("option-paste");                                    // "Paste" popup option.
87 const char* const OPTION_CLIPBOARD("option-clipboard");                            // "Clipboard" popup option.
88
89 BaseHandle Create()
90 {
91   return Toolkit::TextSelectionPopup::New( NULL );
92 }
93
94 // Setup properties, signals and actions using the type-registry.
95
96 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionPopup, Toolkit::Control, Create );
97
98 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-max-size", VECTOR2,   POPUP_MAX_SIZE )
99 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-min-size", VECTOR2,   POPUP_MIN_SIZE )
100 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-max-size", VECTOR2,   OPTION_MAX_SIZE )
101 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-min-size", VECTOR2,   OPTION_MIN_SIZE )
102 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-divider-size", VECTOR2,   OPTION_DIVIDER_SIZE )
103 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-clipboard-button-image", STRING, POPUP_CLIPBOARD_BUTTON_ICON_IMAGE )
104 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-cut-button-image", STRING, POPUP_CUT_BUTTON_ICON_IMAGE )
105 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-copy-button-image", STRING, POPUP_COPY_BUTTON_ICON_IMAGE )
106 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-paste-button-image", STRING, POPUP_PASTE_BUTTON_ICON_IMAGE )
107 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-select-button-image", STRING, POPUP_SELECT_BUTTON_ICON_IMAGE )
108 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-select-all-button-image", STRING, POPUP_SELECT_ALL_BUTTON_ICON_IMAGE )
109 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-divider-color", VECTOR4, POPUP_DIVIDER_COLOR )
110 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-icon-color", VECTOR4, POPUP_ICON_COLOR )
111 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-pressed-color", VECTOR4, POPUP_PRESSED_COLOR )
112 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-pressed-image", STRING, POPUP_PRESSED_IMAGE )
113 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-fade-in-duration", FLOAT, POPUP_FADE_IN_DURATION )
114 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-fade-out-duration", FLOAT, POPUP_FADE_OUT_DURATION )
115 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-background-image", MAP, POPUP_BACKGROUND_IMAGE )
116
117 DALI_TYPE_REGISTRATION_END()
118
119 // Popup's background.
120
121 const std::string TEXTURE_UNIFORM_NAME = "sTexture";
122
123 unsigned int gBackgroundQuadIndex[] = {  0,  4,  1,
124                                          1,  4,  5,
125                                          1,  5,  2,
126                                          2,  5,  6,
127                                          2,  6,  3,
128                                          3,  6,  7,
129                                          4,  8,  5,
130                                          5,  8,  9,
131                                          5,  9,  6,
132                                          6,  9, 10,
133                                          6, 10,  7,
134                                          7, 10, 11,
135                                          8, 12,  9,
136                                          9, 12, 13,
137                                          9, 13, 10,
138                                         10, 13, 14,
139                                         10, 14, 11,
140                                         11, 14, 15 };
141
142 const char* VERTEX_SHADER_COLOR = DALI_COMPOSE_SHADER(
143   attribute mediump vec2 aPosition;\n
144   attribute mediump vec2 aTextCoord;\n
145   varying mediump vec2 vTexCoord;\n
146   uniform mediump mat4 uMvpMatrix;\n
147   \n
148   void main()\n
149   {\n
150     vTexCoord = aTextCoord;\n
151     gl_Position = uMvpMatrix * vec4( aPosition, 0.0, 1.0 );\n
152   }\n
153 );
154
155 const char* FRAGMENT_SHADER_COLOR = DALI_COMPOSE_SHADER(
156   varying mediump vec2 vTexCoord;\n
157   uniform sampler2D sTexture;\n
158   uniform lowp vec4 uColor;\n
159   uniform lowp vec4 uBackgroundColor;\n
160   uniform lowp vec4 uStrokeColor;\n
161   \n
162   void main()\n
163   {\n
164     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
165   }\n
166 );
167
168 } // namespace
169
170
171 Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New( TextSelectionPopupCallbackInterface* callbackInterface )
172 {
173   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextSelectionPopup::New\n" );
174
175    // Create the implementation, temporarily owned by this handle on stack
176   IntrusivePtr< TextSelectionPopup > impl = new TextSelectionPopup( callbackInterface );
177
178   // Pass ownership to CustomActor handle
179   Dali::Toolkit::TextSelectionPopup handle( *impl );
180
181   // Second-phase init of the implementation
182   // This can only be done after the CustomActor connection has been made...
183   impl->Initialize();
184
185   return handle;
186 }
187
188 void TextSelectionPopup::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
189 {
190   Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast( Dali::BaseHandle( object ) );
191
192   if( selectionPopup )
193   {
194     TextSelectionPopup& impl( GetImpl( selectionPopup ) );
195
196     switch( index )
197     {
198       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
199       {
200        impl.SetDimensionToCustomise( POPUP_MAXIMUM_SIZE, value.Get< Vector2 >() );
201        break;
202       }
203       case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
204       {
205         impl.SetDimensionToCustomise( OPTION_MAXIMUM_SIZE, value.Get< Vector2 >() );
206         break;
207       }
208       case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
209       {
210         impl.SetDimensionToCustomise( OPTION_MINIMUM_SIZE, value.Get< Vector2>() );
211         break;
212       }
213       case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
214       {
215         impl.SetDimensionToCustomise( OPTION_DIVIDER_SIZE, value.Get< Vector2>() );
216         break;
217       }
218       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
219       {
220         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
221         impl.SetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD, image );
222         break;
223       }
224       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
225       {
226         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
227         impl.SetButtonImage( Toolkit::TextSelectionPopup::CUT, image );
228         break;
229       }
230       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
231       {
232         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
233         impl.SetButtonImage( Toolkit::TextSelectionPopup::COPY, image );
234         break;
235       }
236       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
237       {
238         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
239         impl.SetButtonImage( Toolkit::TextSelectionPopup::PASTE, image );
240         break;
241       }
242       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
243       {
244         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
245         impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT, image );
246         break;
247       }
248       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
249       {
250         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
251         impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL, image );
252         break;
253       }
254       case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
255       {
256         impl.mDividerColor = value.Get< Vector4 >();
257         break;
258       }
259       case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
260       {
261         impl.mIconColor = value.Get< Vector4 >();
262         break;
263       }
264       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
265       {
266         impl.mPressedColor = value.Get< Vector4 >();
267         break;
268       }
269       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
270       {
271         impl.SetPressedImage( value.Get< std::string >() );
272         break;
273       }
274       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
275       {
276         impl.mFadeInDuration = value.Get < float >();
277         break;
278       }
279       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
280       {
281         impl.mFadeOutDuration = value.Get < float >();
282         break;
283       }
284       case Toolkit::TextSelectionPopup::Property::POPUP_BACKGROUND_IMAGE:
285       {
286         const Property::Map* map = value.GetMap();
287
288         if( map )
289         {
290           // used to retrieve the POPUP_BACKGROUND_IMAGE property.
291           impl.mBackgroundMap = *map;
292
293           Image backgroundImage;
294
295           std::string filename;
296
297           const Property::Value* value = map->Find( "filename" );
298           if( value )
299           {
300             value->Get( filename );
301           }
302
303           // if empty file, no need to go further
304           if( filename.empty() )
305           {
306             DALI_LOG_ERROR( "No filename\n" );
307           }
308           else
309           {
310             backgroundImage = ResourceImage::New( filename );
311
312             Vector4 backgroundColor;
313             Vector4 strokeColor;
314
315             value = map->Find( "background-color" );
316             if( value )
317             {
318               backgroundColor = value->Get<Vector4>();
319             }
320
321             value = map->Find( "stroke-color" );
322             if( value )
323             {
324               strokeColor = value->Get<Vector4>();
325             }
326
327             impl.SetPopupBackgroundImage( backgroundImage, backgroundColor, strokeColor );
328           }
329         }
330         break;
331       }
332     } // switch
333   } // TextSelectionPopup
334 }
335
336 Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::Index index )
337 {
338   Property::Value value;
339
340   Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast( Dali::BaseHandle( object ) );
341
342   if( selectionPopup )
343   {
344     TextSelectionPopup& impl( GetImpl( selectionPopup ) );
345
346     switch( index )
347     {
348       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
349       {
350         value = impl.GetDimensionToCustomise( POPUP_MAXIMUM_SIZE );
351         break;
352       }
353       case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
354       {
355         value = impl.GetDimensionToCustomise( OPTION_MAXIMUM_SIZE );
356         break;
357       }
358       case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
359       {
360         value = impl.GetDimensionToCustomise( OPTION_MINIMUM_SIZE );
361         break;
362       }
363       case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
364       {
365         value = impl.GetDimensionToCustomise( OPTION_DIVIDER_SIZE );
366         break;
367       }
368       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
369       {
370         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD ) );
371         if( image )
372         {
373           value = image.GetUrl();
374         }
375         break;
376       }
377       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
378       {
379         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CUT ) );
380         if( image )
381         {
382           value = image.GetUrl();
383         }
384         break;
385       }
386       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
387       {
388         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::COPY ) );
389         if( image )
390         {
391           value = image.GetUrl();
392         }
393         break;
394       }
395       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
396       {
397         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::PASTE ) );
398         if( image )
399         {
400           value = image.GetUrl();
401         }
402         break;
403       }
404       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
405       {
406         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT ) );
407         if( image )
408         {
409           value = image.GetUrl();
410         }
411         break;
412       }
413       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
414       {
415         ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL ) );
416         if( image )
417         {
418           value = image.GetUrl();
419         }
420         break;
421       }
422       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
423       {
424         value = impl.GetPressedImage();
425         break;
426       }
427       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
428       {
429         value = impl.mFadeInDuration;
430         break;
431       }
432       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
433       {
434         value = impl.mFadeOutDuration;
435         break;
436       }
437       case Toolkit::TextSelectionPopup::Property::POPUP_BACKGROUND_IMAGE:
438       {
439         value = impl.mBackgroundMap;
440         break;
441       }
442     } // switch
443   }
444   return value;
445 }
446
447 void TextSelectionPopup::EnableButtons( Toolkit::TextSelectionPopup::Buttons buttonsToEnable )
448 {
449   mEnabledButtons = buttonsToEnable;
450   mButtonsChanged = true;
451 }
452
453 void TextSelectionPopup::RaiseAbove( Layer target )
454 {
455   if( mToolbar )
456   {
457     mToolbar.RaiseAbove( target );
458   }
459 }
460
461 void TextSelectionPopup::ShowPopup()
462 {
463   if ( !mPopupShowing || mButtonsChanged )
464   {
465     Actor self = Self();
466     AddPopupOptionsToToolbar( mShowIcons, mShowCaptions );
467
468     Animation animation = Animation::New( mFadeInDuration );
469     animation.AnimateTo( Property(self, Actor::Property::COLOR_ALPHA), 1.0f  );
470     animation.Play();
471     mPopupShowing = true;
472   }
473 }
474
475 void TextSelectionPopup::HidePopup()
476 {
477   if ( mPopupShowing )
478   {
479     mPopupShowing = false;
480     Actor self = Self();
481     Animation animation = Animation::New( mFadeOutDuration );
482     animation.AnimateTo( Property(self, Actor::Property::COLOR_ALPHA), 0.0f  );
483     animation.FinishedSignal().Connect( this, &TextSelectionPopup::HideAnimationFinished );
484     animation.Play();
485   }
486 }
487
488 void TextSelectionPopup::OnInitialize()
489 {
490   DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::OnInitialize\n" );
491   Actor self = Self();
492   self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
493   self.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
494
495   self.OnRelayoutSignal().Connect( this, &TextSelectionPopup::RelayoutComplete );
496 }
497
498 void TextSelectionPopup::OnStageConnection( int depth )
499 {
500   DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::OnStageConnection\n" );
501   // Call the Control::OnStageConnection() to set the depth of the background.
502   Control::OnStageConnection( depth );
503
504   // TextSelectionToolbar::OnStageConnection() will set the depths of all the popup's components.
505 }
506
507 void TextSelectionPopup::HideAnimationFinished( Animation& animation )
508 {
509   Actor self = Self();
510   if( !mPopupShowing ) // During the Hide/Fade animation there could be a call to Show the Popup again, mPopupShowing will be true in this case.
511   {
512     DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::HideAnimationFinished\n" );
513     UnparentAndReset( mToolbar );
514   }
515 }
516
517 bool TextSelectionPopup::OnCutButtonPressed( Toolkit::Button button )
518 {
519   if( mCallbackInterface )
520   {
521     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
522     mCallbackInterface->TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
523   }
524
525   return true;
526 }
527
528 bool TextSelectionPopup::OnCopyButtonPressed( Toolkit::Button button )
529 {
530   if( mCallbackInterface )
531   {
532     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
533     mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::COPY );
534   }
535
536   return true;
537 }
538
539 bool TextSelectionPopup::OnPasteButtonPressed( Toolkit::Button button )
540 {
541   if( mCallbackInterface )
542   {
543     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
544     mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::PASTE );
545   }
546
547   return true;
548 }
549
550 bool TextSelectionPopup::OnSelectButtonPressed( Toolkit::Button button )
551 {
552   if( mCallbackInterface )
553   {
554     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
555     mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT );
556   }
557
558   return true;
559 }
560
561 bool TextSelectionPopup::OnSelectAllButtonPressed( Toolkit::Button button )
562 {
563   if( mCallbackInterface )
564   {
565     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
566     mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT_ALL );
567   }
568
569   return true;
570 }
571
572 bool TextSelectionPopup::OnClipboardButtonPressed( Toolkit::Button button )
573 {
574   if( mCallbackInterface )
575   {
576     feedback_play_type( FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_TAP );
577     mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::CLIPBOARD );
578   }
579
580   return true;
581 }
582
583 void TextSelectionPopup::SetDimensionToCustomise( const PopupCustomisations& settingToCustomise, const Size& dimension )
584 {
585   switch( settingToCustomise )
586   {
587     case POPUP_MAXIMUM_SIZE :
588     {
589       mPopupMaxSize = dimension;
590       if ( mToolbar )
591       {
592         mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, dimension );
593       }
594       break;
595     }
596     case OPTION_MAXIMUM_SIZE :
597     {
598       mOptionMaxSize = dimension;
599       // Option max size not currently currently supported
600       break;
601     }
602     case OPTION_MINIMUM_SIZE :
603     {
604       mOptionMinSize = dimension;
605       // Option min size not currently currently supported
606       break;
607     }
608     case OPTION_DIVIDER_SIZE :
609     {
610       mOptionDividerSize = dimension;
611       if ( mToolbar )
612       {
613         // Resize Dividers not currently supported
614       }
615       break;
616     }
617   } // switch
618 }
619
620 Size TextSelectionPopup::GetDimensionToCustomise( const PopupCustomisations& settingToCustomise )
621 {
622   switch( settingToCustomise )
623   {
624     case POPUP_MAXIMUM_SIZE :
625     {
626       if ( mToolbar )
627       {
628         return mToolbar.GetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE ).Get< Vector2 >();
629       }
630       else
631       {
632         return mPopupMaxSize;
633       }
634     }
635     case OPTION_MAXIMUM_SIZE :
636     {
637       return mOptionMaxSize;
638     }
639     case OPTION_MINIMUM_SIZE :
640     {
641       return mOptionMinSize;
642     }
643     case OPTION_DIVIDER_SIZE :
644     {
645       return mOptionDividerSize;
646     }
647   } // switch
648
649   return Size::ZERO;
650 }
651
652 void TextSelectionPopup::SetButtonImage( Toolkit::TextSelectionPopup::Buttons button, Dali::Image image )
653 {
654    switch ( button )
655    {
656    break;
657    case Toolkit::TextSelectionPopup::CLIPBOARD:
658    {
659      mClipboardIconImage  = image;
660    }
661    break;
662    case Toolkit::TextSelectionPopup::CUT :
663    {
664      mCutIconImage = image;
665    }
666    break;
667    case Toolkit::TextSelectionPopup::COPY :
668    {
669      mCopyIconImage = image;
670    }
671    break;
672    case Toolkit::TextSelectionPopup::PASTE :
673    {
674      mPasteIconImage = image;
675    }
676    break;
677    case Toolkit::TextSelectionPopup::SELECT :
678    {
679      mSelectIconImage = image;
680    }
681    break;
682    case Toolkit::TextSelectionPopup::SELECT_ALL :
683    {
684      mSelectAllIconImage = image;
685    }
686    break;
687    default :
688    {
689      DALI_ASSERT_DEBUG( "TextSelectionPopup SetPopupImage Unknown Button" );
690    }
691    } // switch
692 }
693
694 Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::Buttons button )
695 {
696   switch ( button )
697   {
698   case Toolkit::TextSelectionPopup::CLIPBOARD :
699   {
700     return mClipboardIconImage;
701   }
702   break;
703   case Toolkit::TextSelectionPopup::CUT :
704   {
705     return mCutIconImage;
706   }
707   break;
708   case Toolkit::TextSelectionPopup::COPY :
709   {
710     return mCopyIconImage;
711   }
712   break;
713   case Toolkit::TextSelectionPopup::PASTE :
714   {
715     return mPasteIconImage;
716   }
717   break;
718   case Toolkit::TextSelectionPopup::SELECT :
719   {
720     return mSelectIconImage;
721   }
722   break;
723   case Toolkit::TextSelectionPopup::SELECT_ALL :
724   {
725     return mSelectAllIconImage;
726   }
727   break;
728   default :
729   {
730     DALI_ASSERT_DEBUG( "TextSelectionPopup GetPopupImage Unknown Button" );
731   }
732   } // switch
733
734   return Dali::Image();
735 }
736
737 void TextSelectionPopup::SetPressedImage( const std::string& filename )
738 {
739   mPressedImage = filename;
740 }
741
742 std::string TextSelectionPopup::GetPressedImage() const
743 {
744   return mPressedImage;
745 }
746
747  void TextSelectionPopup::CreateOrderedListOfPopupOptions()
748  {
749    mOrderListOfButtons.clear();
750    mOrderListOfButtons.reserve( 8u );
751
752    // Create button for each possible option using Option priority
753    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CUT, mCutOptionPriority, OPTION_CUT, POPUP_CUT_STRING , mCutIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::CUT)  ) );
754    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::COPY, mCopyOptionPriority, OPTION_COPY, POPUP_COPY_STRING, mCopyIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::COPY)  ) );
755    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::PASTE, mPasteOptionPriority, OPTION_PASTE, POPUP_PASTE_STRING, mPasteIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::PASTE)  ) );
756    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT, mSelectOptionPriority, OPTION_SELECT_WORD, POPUP_SELECT_STRING, mSelectIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT)  ) );
757    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT_ALL, mSelectAllOptionPriority, OPTION_SELECT_ALL, POPUP_SELECT_ALL_STRING, mSelectAllIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT_ALL)  ) );
758    mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CLIPBOARD, mClipboardOptionPriority, OPTION_CLIPBOARD, POPUP_CLIPBOARD_STRING, mClipboardIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::CLIPBOARD)  ) );
759
760    // Sort the buttons according their priorities.
761    std::sort( mOrderListOfButtons.begin(), mOrderListOfButtons.end(), TextSelectionPopup::ButtonPriorityCompare() );
762  }
763
764  void TextSelectionPopup::AddOption( const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption  )
765  {
766    // 1. Create a option.
767    DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::AddOption\n" );
768
769    Toolkit::PushButton option = Toolkit::PushButton::New();
770    option.SetName( button.name );
771    option.SetAnimationTime( 0.0f );
772    option.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
773
774    switch( button.id )
775    {
776      case Toolkit::TextSelectionPopup::CUT:
777      {
778        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCutButtonPressed );
779        break;
780      }
781      case Toolkit::TextSelectionPopup::COPY:
782      {
783        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCopyButtonPressed );
784        break;
785      }
786      case Toolkit::TextSelectionPopup::PASTE:
787      {
788        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnPasteButtonPressed );
789        break;
790      }
791      case Toolkit::TextSelectionPopup::SELECT:
792      {
793        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectButtonPressed );
794        break;
795      }
796      case Toolkit::TextSelectionPopup::SELECT_ALL:
797      {
798        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectAllButtonPressed );
799        break;
800      }
801      case Toolkit::TextSelectionPopup::CLIPBOARD:
802      {
803        option.ClickedSignal().Connect( this, &TextSelectionPopup::OnClipboardButtonPressed );
804        break;
805      }
806      case Toolkit::TextSelectionPopup::NONE:
807      {
808        // Nothing to do:
809        break;
810      }
811    }
812
813    // 2. Set the options contents.
814    if( showCaption )
815    {
816      // PushButton layout properties.
817      option.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 32.0f, 32.0f, 20.0f, 20.0f ) );
818
819      // Label properties.
820      Property::Map buttonLabelProperties;
821      buttonLabelProperties.Insert( "text", button.caption );
822      option.SetProperty( Toolkit::Button::Property::LABEL, buttonLabelProperties );
823    }
824    if( showIcons )
825    {
826      option.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
827      option.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "TOP" );
828
829      // TODO: This is temporarily disabled until the text-selection-popup image API is changed to strings.
830      //option.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, button.icon );
831      //option.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, button.icon );
832    }
833
834    // 3. Set the normal option image (blank / Transparent).
835    option.SetUnselectedImage( "" );
836
837    // 4. Set the pressed option image.
838    // The image can be blank, the color can be used regardless.
839    option.SetSelectedImage( mPressedImage );
840    option.SetProperty( Toolkit::Button::Property::SELECTED_COLOR, mPressedColor );
841    option.SetProperty( Toolkit::Control::Property::STYLE_NAME, TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME );
842
843    // 5 Add option to tool bar
844    mToolbar.AddOption( option );
845
846    // 6. Add the divider
847    if( showDivider )
848    {
849      const Size size( mOptionDividerSize.width, 0.0f ); // Height FILL_TO_PARENT
850
851      ImageActor divider = Toolkit::CreateSolidColorActor( Color::WHITE );
852 #ifdef DECORATOR_DEBUG
853      divider.SetName("Text's popup divider");
854 #endif
855      divider.SetSize( size );
856      divider.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
857      divider.SetColor( mDividerColor );
858      divider.SetSortModifier( DECORATION_DEPTH_INDEX );
859      mToolbar.AddDivider( divider );
860    }
861  }
862
863  std::size_t TextSelectionPopup::GetNumberOfEnabledOptions()
864  {
865    std::size_t numberOfOptions = 0u;
866    for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
867    {
868      const ButtonRequirement& button( *it );
869      if( button.enabled )
870      {
871        ++numberOfOptions;
872      }
873    }
874
875    return numberOfOptions;
876  }
877
878  void TextSelectionPopup::AddPopupOptionsToToolbar( bool showIcons, bool showCaptions )
879  {
880    DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::AddPopupOptionsToToolbar\n" );
881
882    CreateOrderedListOfPopupOptions();
883
884    mButtonsChanged = false;
885    UnparentAndReset( mToolbar );
886
887    if( !mToolbar )
888    {
889      Actor self = Self();
890      mToolbar = Toolkit::TextSelectionToolbar::New();
891      if ( mPopupMaxSize != Vector2::ZERO ) // If PopupMaxSize property set then apply to Toolbar. Toolbar currently is not retriving this from json
892      {
893        mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, mPopupMaxSize );
894      }
895      mToolbar.SetParentOrigin( ParentOrigin::CENTER );
896 #ifdef DECORATOR_DEBUG
897      mToolbar.SetName("TextSelectionToolbar");
898 #endif
899      self.Add( mToolbar );
900    }
901
902    // Iterate list of buttons and add active ones to Toolbar
903    std::size_t numberOfOptionsRequired =  GetNumberOfEnabledOptions();
904    std::size_t numberOfOptionsAdded = 0u;
905    for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
906    {
907      const ButtonRequirement& button( *it );
908      if ( button.enabled )
909      {
910        numberOfOptionsAdded++;
911        AddOption(  button, ( numberOfOptionsAdded < numberOfOptionsRequired ) , showIcons, showCaptions );
912      }
913    }
914  }
915
916 void TextSelectionPopup::SetPopupBackgroundImage( Image image,
917                                                   const Vector4& backgroundColor,
918                                                   const Vector4& strokeColor )
919 {
920   NinePatchImage ninePatch = NinePatchImage::DownCast( image );
921
922   if( ninePatch )
923   {
924     mNinePatchBorder = static_cast<float>( ninePatch.GetChildRectangle().x );
925     mNinePatchBorderPercentage = mNinePatchBorder / static_cast<float>( ninePatch.GetWidth() );
926
927     if( !mBackgroundVertexBuffer )
928     {
929       Property::Map vertexFormat;
930       vertexFormat["aPosition"] = Property::VECTOR2;
931       vertexFormat["aTextCoord"] = Property::VECTOR2;
932
933       //Create a vertex buffer for vertex positions
934       mBackgroundVertexBuffer = PropertyBuffer::New( vertexFormat, 16u );
935
936       Vector<Vector2> geometry;
937       geometry.Resize( 32u );
938       mBackgroundVertexBuffer.SetData( geometry.Begin() );
939     }
940
941     if( !mBackgroundRenderer )
942     {
943       Image croppedImage = ninePatch.CreateCroppedBufferImage();
944       if( croppedImage )
945       {
946         Shader shader = Shader::New( VERTEX_SHADER_COLOR, FRAGMENT_SHADER_COLOR, Shader::HINT_OUTPUT_IS_TRANSPARENT );
947
948         Material material = Material::New( shader );
949         material.AddTexture( croppedImage, TEXTURE_UNIFORM_NAME );
950
951         //Create the index buffer
952         Property::Map indexFormat;
953         indexFormat["indices"] = Property::INTEGER;
954         PropertyBuffer indexBuffer = PropertyBuffer::New( indexFormat, 54u );
955         indexBuffer.SetData( gBackgroundQuadIndex );
956
957         //Create the geometry
958         Geometry mesh = Geometry::New();
959         mesh.AddVertexBuffer( mBackgroundVertexBuffer );
960         mesh.SetIndexBuffer( indexBuffer );
961
962         //Add uniforms to the shader
963         mBackgroundColorIndex = shader.RegisterProperty( "uBackgroundColor", backgroundColor );
964         mStrokeColorIndex = shader.RegisterProperty( "uStrokeColor", strokeColor );
965
966         Actor parent = Self();
967
968         //Create the renderer
969         mBackgroundRenderer = Renderer::New( mesh, material );
970         mBackgroundRenderer.SetDepthIndex( parent.GetHierarchyDepth() + BACKGROUND_DEPTH_INDEX );
971
972         //Create the actor
973         Actor backgroundActor = Actor::New();
974         backgroundActor.SetSize( Vector3::ONE );
975
976         backgroundActor.SetPositionInheritanceMode( USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
977         backgroundActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_ALPHA );
978
979         backgroundActor.AddRenderer( mBackgroundRenderer );
980
981         //Constraint scale of the mesh actor to the size of the control
982         Constraint constraint = Constraint::New<Vector3>( backgroundActor,
983                                                           Actor::Property::SCALE,
984                                                           EqualToConstraint() );
985
986         constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
987         constraint.Apply();
988
989         // The actor does not need to be inserted to guarantee order.
990         parent.Add( backgroundActor );
991       }
992     }
993     else
994     {
995       // Set the new image to the sampler.
996       Image croppedImage = ninePatch.CreateCroppedBufferImage();
997
998       if( croppedImage )
999       {
1000         Material material = mBackgroundRenderer.GetMaterial();
1001         material.AddTexture( croppedImage, TEXTURE_UNIFORM_NAME );
1002
1003         // Set the new colors to the shader.
1004         Shader shader = material.GetShader();
1005         shader.SetProperty( mBackgroundColorIndex, backgroundColor );
1006         shader.SetProperty( mStrokeColorIndex, strokeColor );
1007       }
1008     }
1009   }
1010   else
1011   {
1012     SetBackgroundImage( image );
1013   }
1014 }
1015
1016 void TextSelectionPopup::RelayoutComplete( Actor actor )
1017 {
1018   if( mBackgroundVertexBuffer )
1019   {
1020     Actor self = Self();
1021
1022     const float width = mNinePatchBorder / self.GetRelayoutSize( Dimension::WIDTH );
1023     const float height = mNinePatchBorder / self.GetRelayoutSize( Dimension::HEIGHT );
1024
1025     const float textCoord = mNinePatchBorderPercentage;
1026
1027     Vector2 geometry[] =
1028     {
1029       Vector2( -0.5f,             -0.5f ),             //  0
1030       Vector2(  0.0f,              0.0f ),
1031       Vector2( -0.5f + width,     -0.5f ),             //  1
1032       Vector2(  0.0f + textCoord,  0.0f ),
1033       Vector2(  0.5f - width,     -0.5f ),             //  2
1034       Vector2(  1.0f - textCoord,  0.0f ),
1035       Vector2(  0.5f,             -0.5f ),             //  3
1036       Vector2(  1.0f,              0.0f ),
1037       Vector2( -0.5f,             -0.5f + height ),    //  4
1038       Vector2(  0.0f,              0.0f + textCoord ),
1039       Vector2( -0.5f + width,     -0.5f + height ),    //  5
1040       Vector2(  0.0f + textCoord,  0.0f + textCoord ),
1041       Vector2(  0.5f - width,     -0.5f + height ),    //  6
1042       Vector2(  1.0f - textCoord,  0.0f + textCoord ),
1043       Vector2(  0.5f,             -0.5f + height ),    //  7
1044       Vector2(  1.0f,              0.0f + textCoord ),
1045       Vector2( -0.5f,              0.5f - height ),    //  8
1046       Vector2(  0.0f,              1.0f - textCoord ),
1047       Vector2( -0.5f + width,      0.5f - height ),    //  9
1048       Vector2(  0.0f + textCoord,  1.0f - textCoord ),
1049       Vector2(  0.5f - width,      0.5f - height ),    // 10
1050       Vector2(  1.0f - textCoord,  1.0f - textCoord ),
1051       Vector2(  0.5f,              0.5f - height ),    // 11
1052       Vector2(  1.0f,              1.0f - textCoord ),
1053       Vector2( -0.5f,              0.5f ),             // 12
1054       Vector2(  0.0f,              1.0f ),
1055       Vector2( -0.5f + width,      0.5f ),             // 13
1056       Vector2(  0.0f + textCoord,  1.0f ),
1057       Vector2(  0.5f - width,      0.5f ),             // 14
1058       Vector2(  1.0f - textCoord,  1.0f ),
1059       Vector2(  0.5f,              0.5f ),             // 15
1060       Vector2(  1.0f,              1.0f )
1061     };
1062     mBackgroundVertexBuffer.SetData( geometry );
1063   }
1064 }
1065
1066 TextSelectionPopup::TextSelectionPopup( TextSelectionPopupCallbackInterface* callbackInterface )
1067 : Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
1068   mToolbar(),
1069   mBackgroundColorIndex( 0 ),
1070   mStrokeColorIndex( 0 ),
1071   mPopupMaxSize(),
1072   mOptionMaxSize(),
1073   mOptionMinSize(),
1074   mOptionDividerSize(),
1075   mEnabledButtons( Toolkit::TextSelectionPopup::NONE ),
1076   mCallbackInterface( callbackInterface ),
1077   mPressedColor( DEFAULT_OPTION_PRESSED_COLOR ),
1078   mDividerColor( Color::WHITE ),
1079   mIconColor( Color::WHITE ),
1080   mSelectOptionPriority( 1 ),
1081   mSelectAllOptionPriority ( 2 ),
1082   mCutOptionPriority ( 4 ),
1083   mCopyOptionPriority ( 3 ),
1084   mPasteOptionPriority ( 5 ),
1085   mClipboardOptionPriority( 6 ),
1086   mFadeInDuration(0.0f),
1087   mFadeOutDuration(0.0f),
1088   mNinePatchBorder( 0.f ),
1089   mNinePatchBorderPercentage( 0.f ),
1090   mShowIcons( false ),
1091   mShowCaptions( true ),
1092   mPopupShowing( false ),
1093   mButtonsChanged( false )
1094 {
1095 }
1096
1097 TextSelectionPopup::~TextSelectionPopup()
1098 {
1099 }
1100
1101
1102 } // namespace Internal
1103
1104 } // namespace Toolkit
1105
1106 } // namespace Dali
1107
1108