[AT-SPI] Remove SetAccessibilityConstructor()
[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   Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::TOOL_BAR);
168 }
169
170 void TextSelectionToolbar::OnRelayout(const Vector2& size, RelayoutContainer& container)
171 {
172   float width = std::max(mTableOfButtons.GetNaturalSize().width, size.width);
173   mRulerX->SetDomain(RulerDomain(0.0, width, true));
174   mScrollView.SetRulerX(mRulerX);
175
176   if(mScrollBar)
177   {
178     float barWidth = std::min(mTableOfButtons.GetNaturalSize().width, size.width) - 2.f * mScrollBarPadding.x;
179     mScrollBar.SetProperty(Actor::Property::SIZE, Vector2(0.0f, barWidth));
180   }
181 }
182
183 void TextSelectionToolbar::SetPopupMaxSize(const Size& maxSize)
184 {
185   mMaxSize = maxSize;
186   if(mScrollView && mToolbarActor)
187   {
188     mScrollView.SetProperty(Actor::Property::MAXIMUM_SIZE, mMaxSize);
189     mToolbarActor.SetProperty(Actor::Property::MAXIMUM_SIZE, mMaxSize);
190   }
191 }
192
193 const Dali::Vector2& TextSelectionToolbar::GetPopupMaxSize() const
194 {
195   return mMaxSize;
196 }
197
198 void TextSelectionToolbar::SetUpScrollView()
199 {
200   mScrollView.SetProperty(Dali::Actor::Property::NAME, "TextSelectionScrollView");
201   mScrollView.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
202   mScrollView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
203   mScrollView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
204
205   mScrollView.SetScrollingDirection(PanGestureDetector::DIRECTION_HORIZONTAL, Degree(40.0f));
206   mScrollView.SetAxisAutoLock(true);
207   mScrollView.ScrollStartedSignal().Connect(this, &TextSelectionToolbar::OnScrollStarted);
208   mScrollView.ScrollCompletedSignal().Connect(this, &TextSelectionToolbar::OnScrollCompleted);
209   mScrollView.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX); // In a new layer, so clip to scroll-view's bounding box
210
211   mRulerX = new DefaultRuler(); // IntrusivePtr which is unreferenced when ScrollView is destroyed.
212
213   RulerPtr rulerY = new DefaultRuler(); // IntrusivePtr which is unreferenced when ScrollView is destroyed.
214   rulerY->Disable();
215   mScrollView.SetRulerY(rulerY);
216
217   mScrollView.SetOvershootEnabled(true);
218 }
219
220 void TextSelectionToolbar::SetUp()
221 {
222   Actor self = Self();
223
224   self.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
225
226   // Create Actor to house the toolbar.
227   mToolbarActor = Actor::New();
228   mToolbarActor.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
229   mToolbarActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
230   mToolbarActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
231
232   if(!mScrollView)
233   {
234     mScrollView = Toolkit::ScrollView::New();
235   }
236   SetUpScrollView();
237
238   // Toolbar must start with at least one option, adding further options with increase it's size
239   mTableOfButtons = Dali::Toolkit::TableView::New(1, 1);
240   mTableOfButtons.SetFitHeight(0);
241   mTableOfButtons.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
242   mTableOfButtons.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
243
244   mScrollView.Add(mTableOfButtons);
245   mToolbarActor.Add(mScrollView);
246
247   self.Add(mToolbarActor);
248 }
249
250 void TextSelectionToolbar::SetUpScrollBar(bool enable)
251 {
252   if(enable)
253   {
254     if(!mScrollBar)
255     {
256       Toolkit::ImageView indicator = Toolkit::ImageView::New();
257       indicator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
258       indicator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
259       indicator.SetStyleName("TextSelectionScrollIndicator");
260
261       mScrollBar = Toolkit::ScrollBar::New(Toolkit::ScrollBar::HORIZONTAL);
262       mScrollBar.SetProperty(Dali::Actor::Property::NAME, "Text popup scroll bar");
263       mScrollBar.SetStyleName("TextSelectionScrollBar");
264       mScrollBar.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_LEFT);
265       mScrollBar.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
266       mScrollBar.SetProperty(Actor::Property::POSITION, Vector2(mScrollBarPadding.x, -mScrollBarPadding.y));
267       mScrollBar.SetResizePolicy(Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH);
268       mScrollBar.SetProperty(Actor::Property::ORIENTATION, Quaternion(Quaternion(Radian(1.5f * Math::PI), Vector3::ZAXIS)));
269       mScrollBar.SetScrollIndicator(indicator);
270       mScrollBar.GetPanGestureDetector().DetachAll();
271       mScrollView.Add(mScrollBar);
272     }
273   }
274   else
275   {
276     UnparentAndReset(mScrollBar);
277   }
278 }
279
280 void TextSelectionToolbar::OnScrollStarted(const Vector2& position)
281 {
282   if(mFirstScrollEnd)
283   {
284     mScrollView.SetOvershootEnabled(true);
285   }
286   mTableOfButtons.SetProperty(Actor::Property::SENSITIVE, false);
287 }
288
289 void TextSelectionToolbar::OnScrollCompleted(const Vector2& position)
290 {
291   mFirstScrollEnd = true;
292   mTableOfButtons.SetProperty(Actor::Property::SENSITIVE, true);
293 }
294
295 void TextSelectionToolbar::AddOption(Actor& option)
296 {
297   mTableOfButtons.AddChild(option, Toolkit::TableView::CellPosition(0, mIndexInTable));
298   mTableOfButtons.SetFitWidth(mIndexInTable);
299   mIndexInTable++;
300 }
301
302 void TextSelectionToolbar::AddDivider(Actor& divider)
303 {
304   AddOption(divider);
305   mDividerIndexes.PushBack(mIndexInTable - 1u);
306 }
307
308 void TextSelectionToolbar::ResizeDividers(Size& size)
309 {
310   for(unsigned int i = 0; i < mDividerIndexes.Count(); ++i)
311   {
312     Actor divider = mTableOfButtons.GetChildAt(Toolkit::TableView::CellPosition(0, mDividerIndexes[i]));
313     divider.SetProperty(Actor::Property::SIZE, size);
314   }
315   RelayoutRequest();
316 }
317
318 void TextSelectionToolbar::RaiseAbove(Actor target)
319 {
320   mToolbarActor.RaiseAbove(target);
321 }
322
323 void TextSelectionToolbar::SetScrollBarPadding(const Vector2& padding)
324 {
325   mScrollBarPadding = padding;
326   if(mScrollBar)
327   {
328     mScrollBar.SetProperty(Actor::Property::POSITION, Vector2(mScrollBarPadding.x, -mScrollBarPadding.y));
329   }
330
331   RelayoutRequest();
332 }
333
334 void TextSelectionToolbar::ScrollTo(const Vector2& position)
335 {
336   mFirstScrollEnd = false;
337   mScrollView.SetOvershootEnabled(false);
338   mScrollView.ScrollTo(position, 0.f);
339 }
340
341 void TextSelectionToolbar::ConfigureScrollview(const Property::Map& properties)
342 {
343   // Set any properties specified for the label by iterating through all property key-value pairs.
344   for(unsigned int i = 0, mapCount = properties.Count(); i < mapCount; ++i)
345   {
346     const StringValuePair& propertyPair(properties.GetPair(i));
347
348     // Convert the property string to a property index.
349     Property::Index setPropertyIndex = mScrollView.GetPropertyIndex(propertyPair.first);
350     if(setPropertyIndex != Property::INVALID_INDEX)
351     {
352       // Convert the string representation of a color into a Vector4
353       if(setPropertyIndex == Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR)
354       {
355         Vector4 color;
356         if(ConvertPropertyToColor(propertyPair.second, color))
357         {
358           mScrollView.SetOvershootEffectColor(color);
359         }
360       }
361       else
362       {
363         // If the conversion worked, we have a valid property index,
364         // Set the property to the new value.
365         mScrollView.SetProperty(setPropertyIndex, propertyPair.second);
366       }
367     }
368   }
369
370   RelayoutRequest();
371 }
372
373 const Vector2& TextSelectionToolbar::GetScrollBarPadding() const
374 {
375   return mScrollBarPadding;
376 }
377
378 TextSelectionToolbar::TextSelectionToolbar()
379 : Control(ControlBehaviour(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))),
380   mMaxSize(),
381   mScrollBarPadding(DEFAULT_SCROLL_BAR_PADDING),
382   mIndexInTable(0),
383   mDividerIndexes(),
384   mFirstScrollEnd(false)
385 {
386 }
387
388 TextSelectionToolbar::~TextSelectionToolbar()
389 {
390   mRulerX.Reset();
391 }
392
393 } // namespace Internal
394
395 } // namespace Toolkit
396
397 } // namespace Dali