Add callbacks for form repost decision and frame rendering.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-selection-popup-impl.cpp
1 /*
2  * Copyright (c) 2021 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 // EXTERNAL INCLUDES
22 #if defined(__GLIBC__)
23 #include <libintl.h>
24 #endif
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/animation/animation.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/public-api/math/vector4.h>
29 #include <dali/public-api/object/property-map.h>
30 #include <dali/public-api/object/type-registry-helper.h>
31 #include <string.h>
32 #include <cfloat>
33
34 // INTERNAL INCLUDES
35 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
36 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
37 #include <dali-toolkit/devel-api/controls/control-devel.h>
38 #include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
39 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
40 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
41 #include <dali-toolkit/internal/helpers/color-conversion.h>
42 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
43 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
44 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
45 #include <dali-toolkit/public-api/visuals/visual-properties.h>
46
47 namespace Dali
48 {
49 namespace Toolkit
50 {
51 namespace Internal
52 {
53 namespace
54 {
55 #if defined(__GLIBC__)
56 #define GET_LOCALE_TEXT(string) dgettext("dali-toolkit", string)
57 #endif
58
59 const std::string   TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME("TextSelectionPopupButton");
60 const Dali::Vector4 DEFAULT_OPTION_PRESSED_COLOR(Dali::Vector4(0.24f, 0.72f, 0.8f, 1.0f));
61
62 #if defined(DEBUG_ENABLED)
63 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
64 #endif
65
66 #ifdef DGETTEXT_ENABLED
67
68 #define POPUP_CUT_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CUT")
69 #define POPUP_COPY_STRING GET_LOCALE_TEXT("IDS_COM_BODY_COPY")
70 #define POPUP_PASTE_STRING GET_LOCALE_TEXT("IDS_COM_BODY_PASTE")
71 #define POPUP_SELECT_STRING GET_LOCALE_TEXT("IDS_COM_SK_SELECT")
72 #define POPUP_SELECT_ALL_STRING GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL")
73 #define POPUP_CLIPBOARD_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD")
74
75 #else
76
77 #define POPUP_CUT_STRING "Cut"
78 #define POPUP_COPY_STRING "Copy"
79 #define POPUP_PASTE_STRING "Paste"
80 #define POPUP_SELECT_STRING "Select"
81 #define POPUP_SELECT_ALL_STRING "Select All"
82 #define POPUP_CLIPBOARD_STRING "Clipboard"
83
84 #endif
85
86 const char* const OPTION_SELECT_WORD = "option-select_word"; // "Select Word" popup option.
87 const char* const OPTION_SELECT_ALL("option-select_all");    // "Select All" popup option.
88 const char* const OPTION_CUT("optionCut");                   // "Cut" popup option.
89 const char* const OPTION_COPY("optionCopy");                 // "Copy" popup option.
90 const char* const OPTION_PASTE("optionPaste");               // "Paste" popup option.
91 const char* const OPTION_CLIPBOARD("optionClipboard");       // "Clipboard" popup option.
92
93 const std::string IDS_LTR("IDS_LTR");
94 const std::string RTL_DIRECTION("RTL");
95
96 BaseHandle Create()
97 {
98   return Toolkit::TextSelectionPopup::New(NULL);
99 }
100
101 // Setup properties, signals and actions using the type-registry.
102
103 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextSelectionPopup, Toolkit::Control, Create);
104
105 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupMaxSize", VECTOR2, POPUP_MAX_SIZE)
106 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupMinSize", VECTOR2, POPUP_MIN_SIZE)
107 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "optionMaxSize", VECTOR2, OPTION_MAX_SIZE)
108 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "optionMinSize", VECTOR2, OPTION_MIN_SIZE)
109 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "optionDividerSize", VECTOR2, OPTION_DIVIDER_SIZE)
110 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupClipboardButtonImage", STRING, POPUP_CLIPBOARD_BUTTON_ICON_IMAGE)
111 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupCutButtonImage", STRING, POPUP_CUT_BUTTON_ICON_IMAGE)
112 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupCopyButtonImage", STRING, POPUP_COPY_BUTTON_ICON_IMAGE)
113 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupPasteButtonImage", STRING, POPUP_PASTE_BUTTON_ICON_IMAGE)
114 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupSelectButtonImage", STRING, POPUP_SELECT_BUTTON_ICON_IMAGE)
115 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupSelectAllButtonImage", STRING, POPUP_SELECT_ALL_BUTTON_ICON_IMAGE)
116 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupDividerColor", VECTOR4, POPUP_DIVIDER_COLOR)
117 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupIconColor", VECTOR4, POPUP_ICON_COLOR)
118 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupPressedColor", VECTOR4, POPUP_PRESSED_COLOR)
119 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupPressedImage", STRING, POPUP_PRESSED_IMAGE)
120 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupFadeInDuration", FLOAT, POPUP_FADE_IN_DURATION)
121 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "popupFadeOutDuration", FLOAT, POPUP_FADE_OUT_DURATION)
122 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionPopup, "backgroundBorder", MAP, BACKGROUND_BORDER)
123
124 DALI_TYPE_REGISTRATION_END()
125
126 } // namespace
127
128 Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New(TextSelectionPopupCallbackInterface* callbackInterface)
129 {
130   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextSelectionPopup::New\n");
131
132   // Create the implementation, temporarily owned by this handle on stack
133   IntrusivePtr<TextSelectionPopup> impl = new TextSelectionPopup(callbackInterface);
134
135   // Pass ownership to CustomActor handle
136   Dali::Toolkit::TextSelectionPopup handle(*impl);
137
138   // Second-phase init of the implementation
139   // This can only be done after the CustomActor connection has been made...
140   impl->Initialize();
141
142   return handle;
143 }
144
145 void TextSelectionPopup::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
146 {
147   Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast(Dali::BaseHandle(object));
148
149   if(selectionPopup)
150   {
151     TextSelectionPopup& impl(GetImpl(selectionPopup));
152
153     switch(index)
154     {
155       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
156       {
157         impl.SetDimensionToCustomise(POPUP_MAXIMUM_SIZE, value.Get<Vector2>());
158         break;
159       }
160       case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
161       {
162         impl.SetDimensionToCustomise(OPTION_MAXIMUM_SIZE, value.Get<Vector2>());
163         break;
164       }
165       case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
166       {
167         impl.SetDimensionToCustomise(OPTION_MINIMUM_SIZE, value.Get<Vector2>());
168         break;
169       }
170       case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
171       {
172         impl.SetDimensionToCustomise(OPTION_DIVIDER_SIZE, value.Get<Vector2>());
173         break;
174       }
175       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
176       {
177         impl.SetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD, value.Get<std::string>());
178         break;
179       }
180       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
181       {
182         impl.SetButtonImage(Toolkit::TextSelectionPopup::CUT, value.Get<std::string>());
183         break;
184       }
185       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
186       {
187         impl.SetButtonImage(Toolkit::TextSelectionPopup::COPY, value.Get<std::string>());
188         break;
189       }
190       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
191       {
192         impl.SetButtonImage(Toolkit::TextSelectionPopup::PASTE, value.Get<std::string>());
193         break;
194       }
195       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
196       {
197         impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT, value.Get<std::string>());
198         break;
199       }
200       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
201       {
202         impl.SetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL, value.Get<std::string>());
203         break;
204       }
205       case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
206       {
207         impl.mDividerColor = value.Get<Vector4>();
208         break;
209       }
210       case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
211       {
212         impl.mIconColor = value.Get<Vector4>();
213         break;
214       }
215       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
216       {
217         impl.mPressedColor = value.Get<Vector4>();
218         break;
219       }
220       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
221       {
222         impl.SetPressedImage(value.Get<std::string>());
223         break;
224       }
225       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
226       {
227         impl.mFadeInDuration = value.Get<float>();
228         break;
229       }
230       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
231       {
232         impl.mFadeOutDuration = value.Get<float>();
233         break;
234       }
235       case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
236       {
237         Property::Map map = value.Get<Property::Map>();
238         impl.CreateBackgroundBorder(map);
239         break;
240       }
241     } // switch
242   }   // TextSelectionPopup
243 }
244
245 Property::Value TextSelectionPopup::GetProperty(BaseObject* object, Property::Index index)
246 {
247   Property::Value value;
248
249   Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast(Dali::BaseHandle(object));
250
251   if(selectionPopup)
252   {
253     TextSelectionPopup& impl(GetImpl(selectionPopup));
254
255     switch(index)
256     {
257       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
258       {
259         value = impl.GetDimensionToCustomise(POPUP_MAXIMUM_SIZE);
260         break;
261       }
262       case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
263       {
264         value = impl.GetDimensionToCustomise(OPTION_MAXIMUM_SIZE);
265         break;
266       }
267       case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
268       {
269         value = impl.GetDimensionToCustomise(OPTION_MINIMUM_SIZE);
270         break;
271       }
272       case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
273       {
274         value = impl.GetDimensionToCustomise(OPTION_DIVIDER_SIZE);
275         break;
276       }
277       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
278       {
279         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CLIPBOARD);
280         break;
281       }
282       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
283       {
284         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::CUT);
285         break;
286       }
287       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
288       {
289         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::COPY);
290         break;
291       }
292       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
293       {
294         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::PASTE);
295         break;
296       }
297       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
298       {
299         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT);
300         break;
301       }
302       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
303       {
304         value = impl.GetButtonImage(Toolkit::TextSelectionPopup::SELECT_ALL);
305         break;
306       }
307       case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
308       {
309         value = impl.GetPressedImage();
310         break;
311       }
312       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
313       {
314         value = impl.mFadeInDuration;
315         break;
316       }
317       case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
318       {
319         value = impl.mFadeOutDuration;
320         break;
321       }
322       case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
323       {
324         Property::Map         map;
325         Toolkit::Visual::Base visual = DevelControl::GetVisual(impl, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER);
326         if(visual)
327         {
328           visual.CreatePropertyMap(map);
329         }
330         value = map;
331         break;
332       }
333     } // switch
334   }
335   return value;
336 }
337
338 void TextSelectionPopup::EnableButtons(Toolkit::TextSelectionPopup::Buttons buttonsToEnable)
339 {
340   mEnabledButtons = buttonsToEnable;
341   mButtonsChanged = true;
342 }
343
344 void TextSelectionPopup::RaiseAbove(Actor target)
345 {
346   if(mToolbar)
347   {
348     mToolbar.RaiseAbove(target);
349   }
350 }
351
352 void TextSelectionPopup::ShowPopup()
353 {
354   if((!mPopupShowing || mButtonsChanged) &&
355      (Toolkit::TextSelectionPopup::NONE != mEnabledButtons))
356   {
357     Actor self = Self();
358     AddPopupOptionsToToolbar(mShowIcons, mShowCaptions);
359
360     Animation animation = Animation::New(mFadeInDuration);
361     animation.AnimateTo(Property(self, Actor::Property::COLOR_ALPHA), 1.0f);
362     animation.Play();
363     mPopupShowing = true;
364   }
365 }
366
367 void TextSelectionPopup::HidePopup()
368 {
369   if(mPopupShowing)
370   {
371     mPopupShowing       = false;
372     Actor     self      = Self();
373     Animation animation = Animation::New(mFadeOutDuration);
374     animation.AnimateTo(Property(self, Actor::Property::COLOR_ALPHA), 0.0f);
375     animation.FinishedSignal().Connect(this, &TextSelectionPopup::HideAnimationFinished);
376     animation.Play();
377   }
378 }
379
380 void TextSelectionPopup::OnInitialize()
381 {
382   DALI_LOG_INFO(gLogFilter, Debug::General, "TextSelectionPopup::OnInitialize\n");
383   Actor self = Self();
384   self.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
385   self.SetProperty(Actor::Property::COLOR_ALPHA, 0.0f);
386
387   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
388     return std::unique_ptr<Dali::Accessibility::Accessible>(
389       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::DIALOG, true));
390   });
391
392   //Enable highightability
393   self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
394 }
395
396 void TextSelectionPopup::HideAnimationFinished(Animation& animation)
397 {
398   Actor self = Self();
399   if(!mPopupShowing) // During the Hide/Fade animation there could be a call to Show the Popup again, mPopupShowing will be true in this case.
400   {
401     DALI_LOG_INFO(gLogFilter, Debug::General, "TextSelectionPopup::HideAnimationFinished\n");
402     UnparentAndReset(mToolbar);
403   }
404 }
405
406 bool TextSelectionPopup::OnCutButtonPressed(Toolkit::Button button)
407 {
408   if(mCallbackInterface)
409   {
410     mCallbackInterface->TextPopupButtonTouched(Toolkit::TextSelectionPopup::CUT);
411   }
412
413   return true;
414 }
415
416 bool TextSelectionPopup::OnCopyButtonPressed(Toolkit::Button button)
417 {
418   if(mCallbackInterface)
419   {
420     mCallbackInterface->TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::COPY);
421   }
422
423   return true;
424 }
425
426 bool TextSelectionPopup::OnPasteButtonPressed(Toolkit::Button button)
427 {
428   if(mCallbackInterface)
429   {
430     mCallbackInterface->TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::PASTE);
431   }
432
433   return true;
434 }
435
436 bool TextSelectionPopup::OnSelectButtonPressed(Toolkit::Button button)
437 {
438   if(mCallbackInterface)
439   {
440     mCallbackInterface->TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::SELECT);
441   }
442
443   return true;
444 }
445
446 bool TextSelectionPopup::OnSelectAllButtonPressed(Toolkit::Button button)
447 {
448   if(mCallbackInterface)
449   {
450     mCallbackInterface->TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::SELECT_ALL);
451   }
452
453   return true;
454 }
455
456 bool TextSelectionPopup::OnClipboardButtonPressed(Toolkit::Button button)
457 {
458   if(mCallbackInterface)
459   {
460     mCallbackInterface->TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::CLIPBOARD);
461   }
462
463   return true;
464 }
465
466 void TextSelectionPopup::SetDimensionToCustomise(const PopupCustomisations& settingToCustomise, const Size& dimension)
467 {
468   switch(settingToCustomise)
469   {
470     case POPUP_MAXIMUM_SIZE:
471     {
472       mPopupMaxSize = dimension;
473       if(mToolbar)
474       {
475         mToolbar.SetProperty(Toolkit::TextSelectionToolbar::Property::MAX_SIZE, dimension);
476       }
477       break;
478     }
479     case OPTION_MAXIMUM_SIZE:
480     {
481       mOptionMaxSize = dimension;
482       // Option max size not currently currently supported
483       break;
484     }
485     case OPTION_MINIMUM_SIZE:
486     {
487       mOptionMinSize = dimension;
488       // Option min size not currently currently supported
489       break;
490     }
491     case OPTION_DIVIDER_SIZE:
492     {
493       mOptionDividerSize = dimension;
494       if(mToolbar)
495       {
496         // Resize Dividers not currently supported
497       }
498       break;
499     }
500   } // switch
501 }
502
503 Size TextSelectionPopup::GetDimensionToCustomise(const PopupCustomisations& settingToCustomise) const
504 {
505   switch(settingToCustomise)
506   {
507     case POPUP_MAXIMUM_SIZE:
508     {
509       if(mToolbar)
510       {
511         return mToolbar.GetProperty(Toolkit::TextSelectionToolbar::Property::MAX_SIZE).Get<Vector2>();
512       }
513       else
514       {
515         return mPopupMaxSize;
516       }
517     }
518     case OPTION_MAXIMUM_SIZE:
519     {
520       return mOptionMaxSize;
521     }
522     case OPTION_MINIMUM_SIZE:
523     {
524       return mOptionMinSize;
525     }
526     case OPTION_DIVIDER_SIZE:
527     {
528       return mOptionDividerSize;
529     }
530   } // switch
531
532   return Size::ZERO;
533 }
534
535 void TextSelectionPopup::SetButtonImage(Toolkit::TextSelectionPopup::Buttons button, const std::string& image)
536 {
537   switch(button)
538   {
539     case Toolkit::TextSelectionPopup::CLIPBOARD:
540     {
541       mClipboardIconImage = image;
542       break;
543     }
544     case Toolkit::TextSelectionPopup::CUT:
545     {
546       mCutIconImage = image;
547       break;
548     }
549     case Toolkit::TextSelectionPopup::COPY:
550     {
551       mCopyIconImage = image;
552       break;
553     }
554     case Toolkit::TextSelectionPopup::PASTE:
555     {
556       mPasteIconImage = image;
557       break;
558     }
559     case Toolkit::TextSelectionPopup::SELECT:
560     {
561       mSelectIconImage = image;
562       break;
563     }
564     case Toolkit::TextSelectionPopup::SELECT_ALL:
565     {
566       mSelectAllIconImage = image;
567       break;
568     }
569     default:
570     {
571       DALI_ASSERT_DEBUG("TextSelectionPopup SetPopupImage Unknown Button");
572     }
573   } // switch
574 }
575
576 const std::string& TextSelectionPopup::GetButtonImage(Toolkit::TextSelectionPopup::Buttons button) const
577 {
578   switch(button)
579   {
580     case Toolkit::TextSelectionPopup::CLIPBOARD:
581     {
582       return mClipboardIconImage;
583       break;
584     }
585     case Toolkit::TextSelectionPopup::CUT:
586     {
587       return mCutIconImage;
588       break;
589     }
590     case Toolkit::TextSelectionPopup::COPY:
591     {
592       return mCopyIconImage;
593       break;
594     }
595     case Toolkit::TextSelectionPopup::PASTE:
596     {
597       return mPasteIconImage;
598       break;
599     }
600     case Toolkit::TextSelectionPopup::SELECT:
601     {
602       return mSelectIconImage;
603       break;
604     }
605     case Toolkit::TextSelectionPopup::SELECT_ALL:
606     {
607       return mSelectAllIconImage;
608       break;
609     }
610     case Toolkit::TextSelectionPopup::NONE:
611     {
612       break;
613     }
614   } // switch
615
616   DALI_ASSERT_DEBUG("TextSelectionPopup GetPopupImage Unknown Button");
617   static std::string empty;
618   return empty;
619 }
620
621 void TextSelectionPopup::SetPressedImage(const std::string& filename)
622 {
623   mPressedImage = filename;
624 }
625
626 std::string TextSelectionPopup::GetPressedImage() const
627 {
628   return mPressedImage;
629 }
630
631 void TextSelectionPopup::CreateOrderedListOfPopupOptions()
632 {
633   mOrderListOfButtons.clear();
634   mOrderListOfButtons.reserve(8u);
635
636   // Create button for each possible option using Option priority
637   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::CUT, mCutOptionPriority, OPTION_CUT, POPUP_CUT_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::CUT)));
638   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::COPY, mCopyOptionPriority, OPTION_COPY, POPUP_COPY_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::COPY)));
639   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::PASTE, mPasteOptionPriority, OPTION_PASTE, POPUP_PASTE_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::PASTE)));
640   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::SELECT, mSelectOptionPriority, OPTION_SELECT_WORD, POPUP_SELECT_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::SELECT)));
641   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::SELECT_ALL, mSelectAllOptionPriority, OPTION_SELECT_ALL, POPUP_SELECT_ALL_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::SELECT_ALL)));
642   mOrderListOfButtons.push_back(ButtonRequirement(Toolkit::TextSelectionPopup::CLIPBOARD, mClipboardOptionPriority, OPTION_CLIPBOARD, POPUP_CLIPBOARD_STRING, 0 != (mEnabledButtons & Toolkit::TextSelectionPopup::CLIPBOARD)));
643
644   // Sort the buttons according their priorities.
645   std::sort(mOrderListOfButtons.begin(), mOrderListOfButtons.end(), TextSelectionPopup::ButtonPriorityCompare());
646 }
647
648 void TextSelectionPopup::AddOption(const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption)
649 {
650   // 1. Create a option.
651   DALI_LOG_INFO(gLogFilter, Debug::General, "TextSelectionPopup::AddOption\n");
652
653   Toolkit::PushButton option = Toolkit::PushButton::New();
654   option.SetProperty(Dali::Actor::Property::NAME, button.name);
655   option.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
656
657   switch(button.id)
658   {
659     case Toolkit::TextSelectionPopup::CUT:
660     {
661       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnCutButtonPressed);
662       break;
663     }
664     case Toolkit::TextSelectionPopup::COPY:
665     {
666       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnCopyButtonPressed);
667       break;
668     }
669     case Toolkit::TextSelectionPopup::PASTE:
670     {
671       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnPasteButtonPressed);
672       break;
673     }
674     case Toolkit::TextSelectionPopup::SELECT:
675     {
676       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnSelectButtonPressed);
677       break;
678     }
679     case Toolkit::TextSelectionPopup::SELECT_ALL:
680     {
681       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnSelectAllButtonPressed);
682       break;
683     }
684     case Toolkit::TextSelectionPopup::CLIPBOARD:
685     {
686       option.ClickedSignal().Connect(this, &TextSelectionPopup::OnClipboardButtonPressed);
687       break;
688     }
689     case Toolkit::TextSelectionPopup::NONE:
690     {
691       // Nothing to do:
692       break;
693     }
694   }
695
696   // 2. Set the options contents.
697   if(showCaption)
698   {
699     // PushButton layout properties.
700     option.SetProperty(Toolkit::PushButton::Property::LABEL_PADDING, Vector4(24.0f, 24.0f, 14.0f, 14.0f));
701
702     // Label properties.
703     Property::Map buttonLabelProperties;
704     buttonLabelProperties.Insert(Toolkit::TextVisual::Property::TEXT, button.caption);
705     option.SetProperty(Toolkit::Button::Property::LABEL, buttonLabelProperties);
706   }
707   if(showIcons)
708   {
709     option.SetProperty(Toolkit::PushButton::Property::ICON_PADDING, Vector4(10.0f, 10.0f, 10.0f, 10.0f));
710     option.SetProperty(Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT, "BOTTOM");
711
712     // TODO: This is temporarily disabled until the text-selection-popup image API is changed to strings.
713     //option.SetProperty(  Toolkit::Button::Property::SELECTED_VISUAL, button.icon );
714     //option.SetProperty(  Toolkit::Button::Property::UNSELECTED_VISUAL, button.icon );
715   }
716
717   // 3. Set the normal option image (blank / Transparent).
718   option.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, "");
719
720   // 4. Set the pressed option image.
721   Property::Value selectedBackgroundValue(mPressedImage);
722   if(mPressedImage.empty())
723   {
724     // The image can be blank, the color can be used in that case.
725     selectedBackgroundValue = Property::Value{{Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR},
726                                               {Toolkit::ColorVisual::Property::MIX_COLOR, mPressedColor}};
727   }
728   option.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, selectedBackgroundValue);
729   option.SetProperty(Toolkit::Control::Property::STYLE_NAME, TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME);
730
731   // 5 Add option to tool bar
732   mToolbar.AddOption(option);
733
734   // 6. Add the divider
735   if(showDivider)
736   {
737     const Size size(mOptionDividerSize.width, 0.0f); // Height FILL_TO_PARENT
738
739     Toolkit::Control divider = Toolkit::Control::New();
740 #ifdef DECORATOR_DEBUG
741     divider.SetProperty(Dali::Actor::Property::NAME, "Text's popup divider");
742 #endif
743     divider.SetProperty(Actor::Property::SIZE, size);
744     divider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT);
745     divider.SetBackgroundColor(mDividerColor);
746     mToolbar.AddDivider(divider);
747   }
748 }
749
750 std::size_t TextSelectionPopup::GetNumberOfEnabledOptions() const
751 {
752   std::size_t numberOfOptions = 0u;
753   for(std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); (it != endIt); ++it)
754   {
755     const ButtonRequirement& button(*it);
756     if(button.enabled)
757     {
758       ++numberOfOptions;
759     }
760   }
761
762   return numberOfOptions;
763 }
764
765 void TextSelectionPopup::AddPopupOptionsToToolbar(bool showIcons, bool showCaptions)
766 {
767   DALI_LOG_INFO(gLogFilter, Debug::General, "TextSelectionPopup::AddPopupOptionsToToolbar\n");
768
769   CreateOrderedListOfPopupOptions();
770
771   mButtonsChanged = false;
772   UnparentAndReset(mToolbar);
773
774   if(!mToolbar)
775   {
776     Actor self = Self();
777     mToolbar   = Toolkit::TextSelectionToolbar::New();
778     if(mPopupMaxSize != Vector2::ZERO) // If PopupMaxSize property set then apply to Toolbar. Toolbar currently is not retriving this from json
779     {
780       mToolbar.SetProperty(Toolkit::TextSelectionToolbar::Property::MAX_SIZE, mPopupMaxSize);
781     }
782     mToolbar.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
783 #ifdef DECORATOR_DEBUG
784     mToolbar.SetProperty(Dali::Actor::Property::NAME, "TextSelectionToolbar");
785 #endif
786     self.Add(mToolbar);
787   }
788
789   // Whether to mirror the list of buttons (for right to left languages)
790   bool mirror = false;
791 #if defined(__GLIBC__)
792   char* idsLtr = GET_LOCALE_TEXT(IDS_LTR.c_str());
793   if(NULL != idsLtr)
794   {
795     mirror = (0 == strcmp(idsLtr, RTL_DIRECTION.c_str()));
796
797     if(mirror)
798     {
799       std::reverse(mOrderListOfButtons.begin(), mOrderListOfButtons.end());
800     }
801   }
802 #endif
803
804   // Iterate list of buttons and add active ones to Toolbar
805   std::size_t numberOfOptionsRequired = GetNumberOfEnabledOptions();
806   std::size_t numberOfOptionsAdded    = 0u;
807   for(std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); (it != endIt); ++it)
808   {
809     const ButtonRequirement& button(*it);
810     if(button.enabled)
811     {
812       numberOfOptionsAdded++;
813       AddOption(button, (numberOfOptionsAdded < numberOfOptionsRequired), showIcons, showCaptions);
814     }
815   }
816
817   if(mirror)
818   {
819     mToolbar.ScrollTo(Vector2(mPopupMaxSize.x, 0.f));
820   }
821 }
822
823 void TextSelectionPopup::CreateBackgroundBorder(Property::Map& propertyMap)
824 {
825   // Removes previous image if necessary
826   DevelControl::UnregisterVisual(*this, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER);
827
828   if(!propertyMap.Empty())
829   {
830     Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
831
832     if(visual)
833     {
834       DevelControl::RegisterVisual(*this, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER, visual, DepthIndex::CONTENT);
835     }
836   }
837 }
838
839 TextSelectionPopup::TextSelectionPopup(TextSelectionPopupCallbackInterface* callbackInterface)
840 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
841   mToolbar(),
842   mPopupMaxSize(),
843   mOptionMaxSize(),
844   mOptionMinSize(),
845   mOptionDividerSize(),
846   mEnabledButtons(Toolkit::TextSelectionPopup::NONE),
847   mCallbackInterface(callbackInterface),
848   mPressedColor(DEFAULT_OPTION_PRESSED_COLOR),
849   mDividerColor(Color::WHITE),
850   mIconColor(Color::WHITE),
851   mSelectOptionPriority(1),
852   mSelectAllOptionPriority(2),
853   mCutOptionPriority(4),
854   mCopyOptionPriority(3),
855   mPasteOptionPriority(5),
856   mClipboardOptionPriority(6),
857   mFadeInDuration(0.0f),
858   mFadeOutDuration(0.0f),
859   mShowIcons(false),
860   mShowCaptions(true),
861   mPopupShowing(false),
862   mButtonsChanged(false)
863 {
864 }
865
866 TextSelectionPopup::~TextSelectionPopup()
867 {
868 }
869
870 } // namespace Internal
871
872 } // namespace Toolkit
873
874 } // namespace Dali