[Tizen](ATSPI) squashed implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-selection-toolbar-impl.cpp
1 /*
2  * Copyright (c) 2018 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 <cfloat>
23 #include <dali/public-api/images/buffer-image.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/math/vector4.h>
26 #include <dali/public-api/object/property-map.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
31 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
32 #include <dali-toolkit/internal/helpers/color-conversion.h>
33 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46
47 const Dali::Vector2 DEFAULT_SCROLL_BAR_PADDING( 8.0f, 6.0f );
48
49 BaseHandle Create()
50 {
51   return Toolkit::TextSelectionToolbar::New();
52 }
53
54 // Setup properties, signals and actions using the type-registry.
55
56 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionToolbar, Toolkit::Control, Create );
57
58 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "maxSize",  VECTOR2, MAX_SIZE )
59 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "enableOvershoot",  BOOLEAN, ENABLE_OVERSHOOT )
60 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "enableScrollBar", BOOLEAN, ENABLE_SCROLL_BAR )
61 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "scrollBarPadding", VECTOR2, SCROLL_BAR_PADDING )
62 DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "scrollView",  MAP, SCROLL_VIEW )
63
64 DALI_TYPE_REGISTRATION_END()
65
66 } // namespace
67
68 Dali::Toolkit::TextSelectionToolbar TextSelectionToolbar::New()
69 {
70   // Create the implementation, temporarily owned by this handle on stack
71   IntrusivePtr< TextSelectionToolbar > impl = new TextSelectionToolbar();
72
73   // Pass ownership to CustomActor handle
74   Dali::Toolkit::TextSelectionToolbar handle( *impl );
75
76   // Second-phase init of the implementation
77   // This can only be done after the CustomActor connection has been made...
78   impl->Initialize();
79
80   return handle;
81 }
82
83 void TextSelectionToolbar::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
84 {
85   Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
86
87   if( selectionPopup )
88   {
89     TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
90
91     switch( index )
92     {
93       case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
94       {
95        impl.SetPopupMaxSize( value.Get< Vector2 >() );
96        break;
97       }
98       case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
99       {
100         if( !impl.mScrollView )
101         {
102           impl.mScrollView  = Toolkit::ScrollView::New();
103         }
104         impl.mScrollView.SetOvershootEnabled( value.Get< bool >() );
105         break;
106       }
107       case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
108       {
109         impl.SetUpScrollBar( value.Get< bool >() );
110         break;
111       }
112       case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
113       {
114         impl.SetScrollBarPadding( value.Get< Vector2 >() );
115         break;
116       }
117       case Toolkit::TextSelectionToolbar::Property::SCROLL_VIEW:
118       {
119         // Get a Property::Map from the property if possible.
120         Property::Map setPropertyMap;
121         if( value.Get( setPropertyMap ) )
122         {
123           impl.ConfigureScrollview( setPropertyMap );
124         }
125         break;
126       }
127     } // switch
128   } // TextSelectionToolbar
129 }
130
131 Property::Value TextSelectionToolbar::GetProperty( BaseObject* object, Property::Index index )
132 {
133   Property::Value value;
134
135   Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
136
137   if( selectionPopup )
138   {
139     TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
140
141     switch( index )
142     {
143       case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
144       {
145         value = impl.GetPopupMaxSize();
146         break;
147       }
148       case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
149       {
150         value = impl.mScrollView.IsOvershootEnabled();
151         break;
152       }
153       case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
154       {
155         value = impl.mScrollBar ? true : false;
156         break;
157       }
158       case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
159       {
160         value = impl.GetScrollBarPadding();
161         break;
162       }
163     } // switch
164   }
165   return value;
166 }
167
168 void TextSelectionToolbar::OnInitialize()
169 {
170   SetUp();
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.SetSize( Vector2( 0.0f, barWidth ) );
183   }
184 }
185
186 void TextSelectionToolbar::SetPopupMaxSize( const Size& maxSize )
187 {
188   mMaxSize = maxSize;
189   if (mScrollView && mToolbarLayer )
190   {
191     mScrollView.SetMaximumSize( mMaxSize );
192     mToolbarLayer.SetMaximumSize( mMaxSize );
193   }
194 }
195
196 const Dali::Vector2& TextSelectionToolbar::GetPopupMaxSize() const
197 {
198   return mMaxSize;
199 }
200
201 void TextSelectionToolbar::SetUpScrollView()
202 {
203   mScrollView.SetName("TextSelectionScrollView");
204   mScrollView.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
205   mScrollView.SetParentOrigin( ParentOrigin::CENTER_LEFT );
206   mScrollView.SetAnchorPoint( 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 Layer to house the toolbar.
230   mToolbarLayer = Layer::New();
231   mToolbarLayer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
232   mToolbarLayer.SetAnchorPoint( AnchorPoint::CENTER );
233   mToolbarLayer.SetParentOrigin( 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.SetParentOrigin( ParentOrigin::CENTER_LEFT );
245   mTableOfButtons.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
246
247   mScrollView.Add( mTableOfButtons );
248   mToolbarLayer.Add( mScrollView );
249
250   self.Add( mToolbarLayer );
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.SetParentOrigin( ParentOrigin::TOP_LEFT );
261       indicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
262       indicator.SetStyleName( "TextSelectionScrollIndicator" );
263
264       mScrollBar = Toolkit::ScrollBar::New( Toolkit::ScrollBar::Horizontal );
265       mScrollBar.SetName( "Text popup scroll bar" );
266       mScrollBar.SetStyleName( "TextSelectionScrollBar" );
267       mScrollBar.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
268       mScrollBar.SetAnchorPoint( AnchorPoint::TOP_LEFT );
269       mScrollBar.SetPosition( mScrollBarPadding.x, -mScrollBarPadding.y );
270       mScrollBar.SetResizePolicy( Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH );
271       mScrollBar.SetOrientation( 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.SetSensitive( false );
290 }
291
292 void TextSelectionToolbar::OnScrollCompleted( const Vector2& position )
293 {
294   mFirstScrollEnd = true;
295   mTableOfButtons.SetSensitive( 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.SetSize( size );
317   }
318   RelayoutRequest();
319 }
320
321 void TextSelectionToolbar::RaiseAbove( Layer target )
322 {
323   mToolbarLayer.RaiseAbove( target );
324 }
325
326 void TextSelectionToolbar::SetScrollBarPadding( const Vector2& padding )
327 {
328   mScrollBarPadding = padding;
329   if( mScrollBar )
330   {
331     mScrollBar.SetPosition( 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   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor )
390     {
391       return std::unique_ptr< Dali::Accessibility::Accessible >(
392         new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TOOL_BAR, true ) );
393     }
394   );
395 }
396
397 TextSelectionToolbar::~TextSelectionToolbar()
398 {
399   mRulerX.Reset();
400 }
401
402 } // namespace Internal
403
404 } // namespace Toolkit
405
406 } // namespace Dali