Merge "Add APIs of webview settings." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-selection-toolbar-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-toolbar-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/math/vector2.h>
23 #include <dali/public-api/math/vector4.h>
24 #include <dali/public-api/object/property-map.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <cfloat>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
30 #include <dali-toolkit/devel-api/controls/control-devel.h>
31 #include <dali-toolkit/internal/helpers/color-conversion.h>
32 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
33
34 namespace Dali
35 {
36 namespace Toolkit
37 {
38 namespace Internal
39 {
40 namespace
41 {
42 const Dali::Vector2 DEFAULT_SCROLL_BAR_PADDING(8.0f, 6.0f);
43
44 BaseHandle Create()
45 {
46   return Toolkit::TextSelectionToolbar::New();
47 }
48
49 // Setup properties, signals and actions using the type-registry.
50
51 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextSelectionToolbar, Toolkit::Control, Create);
52
53 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionToolbar, "maxSize", VECTOR2, MAX_SIZE)
54 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionToolbar, "enableOvershoot", BOOLEAN, ENABLE_OVERSHOOT)
55 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionToolbar, "enableScrollBar", BOOLEAN, ENABLE_SCROLL_BAR)
56 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionToolbar, "scrollBarPadding", VECTOR2, SCROLL_BAR_PADDING)
57 DALI_PROPERTY_REGISTRATION(Toolkit, TextSelectionToolbar, "scrollView", MAP, SCROLL_VIEW)
58
59 DALI_TYPE_REGISTRATION_END()
60
61 } // namespace
62
63 Dali::Toolkit::TextSelectionToolbar TextSelectionToolbar::New()
64 {
65   // Create the implementation, temporarily owned by this handle on stack
66   IntrusivePtr<TextSelectionToolbar> impl = new TextSelectionToolbar();
67
68   // Pass ownership to CustomActor handle
69   Dali::Toolkit::TextSelectionToolbar handle(*impl);
70
71   // Second-phase init of the implementation
72   // This can only be done after the CustomActor connection has been made...
73   impl->Initialize();
74
75   return handle;
76 }
77
78 void TextSelectionToolbar::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
79 {
80   Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast(Dali::BaseHandle(object));
81
82   if(selectionPopup)
83   {
84     TextSelectionToolbar& impl(GetImpl(selectionPopup));
85
86     switch(index)
87     {
88       case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
89       {
90         impl.SetPopupMaxSize(value.Get<Vector2>());
91         break;
92       }
93       case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
94       {
95         if(!impl.mScrollView)
96         {
97           impl.mScrollView = Toolkit::ScrollView::New();
98         }
99         impl.mScrollView.SetOvershootEnabled(value.Get<bool>());
100         break;
101       }
102       case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
103       {
104         impl.SetUpScrollBar(value.Get<bool>());
105         break;
106       }
107       case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
108       {
109         impl.SetScrollBarPadding(value.Get<Vector2>());
110         break;
111       }
112       case Toolkit::TextSelectionToolbar::Property::SCROLL_VIEW:
113       {
114         // Get a Property::Map from the property if possible.
115         Property::Map setPropertyMap;
116         if(value.Get(setPropertyMap))
117         {
118           impl.ConfigureScrollview(setPropertyMap);
119         }
120         break;
121       }
122     } // switch
123   }   // TextSelectionToolbar
124 }
125
126 Property::Value TextSelectionToolbar::GetProperty(BaseObject* object, Property::Index index)
127 {
128   Property::Value value;
129
130   Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast(Dali::BaseHandle(object));
131
132   if(selectionPopup)
133   {
134     TextSelectionToolbar& impl(GetImpl(selectionPopup));
135
136     switch(index)
137     {
138       case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
139       {
140         value = impl.GetPopupMaxSize();
141         break;
142       }
143       case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
144       {
145         value = impl.mScrollView.IsOvershootEnabled();
146         break;
147       }
148       case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
149       {
150         value = impl.mScrollBar ? true : false;
151         break;
152       }
153       case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
154       {
155         value = impl.GetScrollBarPadding();
156         break;
157       }
158     } // switch
159   }
160   return value;
161 }
162
163 void TextSelectionToolbar::OnInitialize()
164 {
165   SetUp();
166
167   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
168     return std::unique_ptr<Dali::Accessibility::Accessible>(
169       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::TOOL_BAR));
170   });
171 }
172
173 void TextSelectionToolbar::OnRelayout(const Vector2& size, RelayoutContainer& container)
174 {
175   float width = std::max(mTableOfButtons.GetNaturalSize().width, size.width);
176   mRulerX->SetDomain(RulerDomain(0.0, width, true));
177   mScrollView.SetRulerX(mRulerX);
178
179   if(mScrollBar)
180   {
181     float barWidth = std::min(mTableOfButtons.GetNaturalSize().width, size.width) - 2.f * mScrollBarPadding.x;
182     mScrollBar.SetProperty(Actor::Property::SIZE, Vector2(0.0f, barWidth));
183   }
184 }
185
186 void TextSelectionToolbar::SetPopupMaxSize(const Size& maxSize)
187 {
188   mMaxSize = maxSize;
189   if(mScrollView && mToolbarActor)
190   {
191     mScrollView.SetProperty(Actor::Property::MAXIMUM_SIZE, mMaxSize);
192     mToolbarActor.SetProperty(Actor::Property::MAXIMUM_SIZE, mMaxSize);
193   }
194 }
195
196 const Dali::Vector2& TextSelectionToolbar::GetPopupMaxSize() const
197 {
198   return mMaxSize;
199 }
200
201 void TextSelectionToolbar::SetUpScrollView()
202 {
203   mScrollView.SetProperty(Dali::Actor::Property::NAME, "TextSelectionScrollView");
204   mScrollView.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
205   mScrollView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
206   mScrollView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
207
208   mScrollView.SetScrollingDirection(PanGestureDetector::DIRECTION_HORIZONTAL, Degree(40.0f));
209   mScrollView.SetAxisAutoLock(true);
210   mScrollView.ScrollStartedSignal().Connect(this, &TextSelectionToolbar::OnScrollStarted);
211   mScrollView.ScrollCompletedSignal().Connect(this, &TextSelectionToolbar::OnScrollCompleted);
212   mScrollView.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX); // In a new layer, so clip to scroll-view's bounding box
213
214   mRulerX = new DefaultRuler(); // IntrusivePtr which is unreferenced when ScrollView is destroyed.
215
216   RulerPtr rulerY = new DefaultRuler(); // IntrusivePtr which is unreferenced when ScrollView is destroyed.
217   rulerY->Disable();
218   mScrollView.SetRulerY(rulerY);
219
220   mScrollView.SetOvershootEnabled(true);
221 }
222
223 void TextSelectionToolbar::SetUp()
224 {
225   Actor self = Self();
226
227   self.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
228
229   // Create Actor to house the toolbar.
230   mToolbarActor = Actor::New();
231   mToolbarActor.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
232   mToolbarActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
233   mToolbarActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
234
235   if(!mScrollView)
236   {
237     mScrollView = Toolkit::ScrollView::New();
238   }
239   SetUpScrollView();
240
241   // Toolbar must start with at least one option, adding further options with increase it's size
242   mTableOfButtons = Dali::Toolkit::TableView::New(1, 1);
243   mTableOfButtons.SetFitHeight(0);
244   mTableOfButtons.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
245   mTableOfButtons.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
246
247   mScrollView.Add(mTableOfButtons);
248   mToolbarActor.Add(mScrollView);
249
250   self.Add(mToolbarActor);
251 }
252
253 void TextSelectionToolbar::SetUpScrollBar(bool enable)
254 {
255   if(enable)
256   {
257     if(!mScrollBar)
258     {
259       Toolkit::ImageView indicator = Toolkit::ImageView::New();
260       indicator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
261       indicator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
262       indicator.SetStyleName("TextSelectionScrollIndicator");
263
264       mScrollBar = Toolkit::ScrollBar::New(Toolkit::ScrollBar::HORIZONTAL);
265       mScrollBar.SetProperty(Dali::Actor::Property::NAME, "Text popup scroll bar");
266       mScrollBar.SetStyleName("TextSelectionScrollBar");
267       mScrollBar.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_LEFT);
268       mScrollBar.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
269       mScrollBar.SetProperty(Actor::Property::POSITION, Vector2(mScrollBarPadding.x, -mScrollBarPadding.y));
270       mScrollBar.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
271       mScrollBar.SetProperty(Actor::Property::ORIENTATION, Quaternion(Quaternion(Radian(1.5f * Math::PI), Vector3::ZAXIS)));
272       mScrollBar.SetScrollIndicator(indicator);
273       mScrollBar.GetPanGestureDetector().DetachAll();
274       mScrollView.Add(mScrollBar);
275     }
276   }
277   else
278   {
279     UnparentAndReset(mScrollBar);
280   }
281 }
282
283 void TextSelectionToolbar::OnScrollStarted(const Vector2& position)
284 {
285   if(mFirstScrollEnd)
286   {
287     mScrollView.SetOvershootEnabled(true);
288   }
289   mTableOfButtons.SetProperty(Actor::Property::SENSITIVE, false);
290 }
291
292 void TextSelectionToolbar::OnScrollCompleted(const Vector2& position)
293 {
294   mFirstScrollEnd = true;
295   mTableOfButtons.SetProperty(Actor::Property::SENSITIVE, true);
296 }
297
298 void TextSelectionToolbar::AddOption(Actor& option)
299 {
300   mTableOfButtons.AddChild(option, Toolkit::TableView::CellPosition(0, mIndexInTable));
301   mTableOfButtons.SetFitWidth(mIndexInTable);
302   mIndexInTable++;
303 }
304
305 void TextSelectionToolbar::AddDivider(Actor& divider)
306 {
307   AddOption(divider);
308   mDividerIndexes.PushBack(mIndexInTable - 1u);
309 }
310
311 void TextSelectionToolbar::ResizeDividers(Size& size)
312 {
313   for(unsigned int i = 0; i < mDividerIndexes.Count(); ++i)
314   {
315     Actor divider = mTableOfButtons.GetChildAt(Toolkit::TableView::CellPosition(0, mDividerIndexes[i]));
316     divider.SetProperty(Actor::Property::SIZE, size);
317   }
318   RelayoutRequest();
319 }
320
321 void TextSelectionToolbar::RaiseAbove(Actor target)
322 {
323   mToolbarActor.RaiseAbove(target);
324 }
325
326 void TextSelectionToolbar::SetScrollBarPadding(const Vector2& padding)
327 {
328   mScrollBarPadding = padding;
329   if(mScrollBar)
330   {
331     mScrollBar.SetProperty(Actor::Property::POSITION, Vector2(mScrollBarPadding.x, -mScrollBarPadding.y));
332   }
333
334   RelayoutRequest();
335 }
336
337 void TextSelectionToolbar::ScrollTo(const Vector2& position)
338 {
339   mFirstScrollEnd = false;
340   mScrollView.SetOvershootEnabled(false);
341   mScrollView.ScrollTo(position, 0.f);
342 }
343
344 void TextSelectionToolbar::ConfigureScrollview(const Property::Map& properties)
345 {
346   // Set any properties specified for the label by iterating through all property key-value pairs.
347   for(unsigned int i = 0, mapCount = properties.Count(); i < mapCount; ++i)
348   {
349     const StringValuePair& propertyPair(properties.GetPair(i));
350
351     // Convert the property string to a property index.
352     Property::Index setPropertyIndex = mScrollView.GetPropertyIndex(propertyPair.first);
353     if(setPropertyIndex != Property::INVALID_INDEX)
354     {
355       // Convert the string representation of a color into a Vector4
356       if(setPropertyIndex == Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR)
357       {
358         Vector4 color;
359         if(ConvertPropertyToColor(propertyPair.second, color))
360         {
361           mScrollView.SetOvershootEffectColor(color);
362         }
363       }
364       else
365       {
366         // If the conversion worked, we have a valid property index,
367         // Set the property to the new value.
368         mScrollView.SetProperty(setPropertyIndex, propertyPair.second);
369       }
370     }
371   }
372
373   RelayoutRequest();
374 }
375
376 const Vector2& TextSelectionToolbar::GetScrollBarPadding() const
377 {
378   return mScrollBarPadding;
379 }
380
381 TextSelectionToolbar::TextSelectionToolbar()
382 : Control(ControlBehaviour(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))),
383   mMaxSize(),
384   mScrollBarPadding(DEFAULT_SCROLL_BAR_PADDING),
385   mIndexInTable(0),
386   mDividerIndexes(),
387   mFirstScrollEnd(false)
388 {
389 }
390
391 TextSelectionToolbar::~TextSelectionToolbar()
392 {
393   mRulerX.Reset();
394 }
395
396 } // namespace Internal
397
398 } // namespace Toolkit
399
400 } // namespace Dali