[Tizen][ATSPI] Accessibility initial implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / toggle-button-impl.cpp
1 /*
2  * Copyright (c) 2017 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 "toggle-button-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/images/resource-image.h>
25 #include <dali/devel-api/scripting/scripting.h>
26 #include <dali/public-api/object/property-array.h>
27 #include <dali/integration-api/debug.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/devel-api/controls/control-devel.h>
33 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
34 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
35 #include <dali-toolkit/public-api/visuals/visual-properties.h>
36 #include <dali-toolkit/public-api/align-enumerations.h>
37 #include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
38 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40
41 #if defined(DEBUG_ENABLED)
42   extern Debug::Filter* gLogButtonFilter;
43 #endif
44
45 namespace Dali
46 {
47
48 namespace Toolkit
49 {
50
51 namespace Internal
52 {
53
54 namespace
55 {
56
57 BaseHandle Create()
58 {
59   return Toolkit::ToggleButton::New();
60 }
61
62 // Properties
63 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToggleButton, Toolkit::Button, Create )
64
65 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "stateVisuals",       ARRAY,     STATE_VISUALS        )
66 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "tooltips",           ARRAY,     TOOLTIPS             )
67 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "currentStateIndex",  INTEGER,   CURRENT_STATE_INDEX  )
68
69 DALI_TYPE_REGISTRATION_END()
70
71 } // unnamed namespace
72
73 Dali::Toolkit::ToggleButton ToggleButton::New()
74 {
75   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::New\n" );
76   // Create the implementation, temporarily owned on stack
77   IntrusivePtr< ToggleButton > internalToggleButton = new ToggleButton();
78
79   // Pass ownership to CustomActor
80   Dali::Toolkit::ToggleButton toggleButton( *internalToggleButton );
81
82   // Second-phase init of the implementation
83   // This can only be done after the CustomActor connection has been made...
84   internalToggleButton->Initialize();
85
86   return toggleButton;
87 }
88
89 ToggleButton::ToggleButton()
90 : Button(),
91   mToggleStates(),
92   mToggleVisuals(),
93   mToggleSelectedVisuals(),
94   mToggleDisabledVisuals(),
95   mToggleDisabledSelectedVisuals(),
96   mToggleTooltips(),
97   mCurrentToggleIndex(0)
98 {
99   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Constructor\n" );
100   SetTogglableButton( false );
101   SetAccessibilityConstructor( []( Dali::Actor actor ) {
102     return std::unique_ptr< Dali::Accessibility::Accessible >(
103         new AccessibleImpl( actor, Dali::Accessibility::Role::ToggleButton ) );
104   } );
105 }
106
107 ToggleButton::~ToggleButton()
108 {
109 }
110
111 void ToggleButton::OnInitialize()
112 {
113   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnInitialize\n" );
114   Button::OnInitialize();
115
116   // Toggle button requires the Leave event.
117   Actor self = Self();
118   self.SetLeaveRequired( true );
119 }
120
121 void ToggleButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
122 {
123   Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
124
125   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::SetProperty index[%d]\n", propertyIndex );
126
127   if ( toggleButton )
128   {
129     ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
130
131     switch ( propertyIndex )
132     {
133       case Toolkit::ToggleButton::Property::STATE_VISUALS:
134       {
135         Property::Array stateArray;
136         if( value.Get( stateArray ) )
137         {
138           toggleButtonImpl.SetToggleStates( stateArray );
139         }
140
141         break;
142       }
143       case Toolkit::ToggleButton::Property::TOOLTIPS:
144       {
145         Property::Array* tipArray = value.GetArray();
146         if( tipArray )
147         {
148           std::vector<std::string> tips;
149           size_t tipsCount = tipArray->Count();
150           tips.resize( tipsCount );
151           for( size_t i = 0; i != tipsCount; ++i )
152           {
153             tipArray->GetElementAt( i ).Get( tips[i] );
154           }
155           toggleButtonImpl.SetToggleTooltips(tips);
156         }
157         break;
158       }
159       default :
160       {
161         break;
162       }
163     } // end of switch
164   }
165 }
166
167 Property::Value ToggleButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
168 {
169   Property::Value value;
170
171   Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
172
173   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::GetProperty index[%d]\n", propertyIndex );
174
175   if ( toggleButton )
176   {
177     ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
178
179     switch ( propertyIndex )
180     {
181       case Toolkit::ToggleButton::Property::STATE_VISUALS:
182       {
183         Property::Array array = toggleButtonImpl.GetToggleStates();
184         value = Property::Value( array );
185         break;
186       }
187       case Toolkit::ToggleButton::Property::TOOLTIPS:
188       {
189         Property::Value value1( Property::ARRAY );
190         Property::Array* tipArray = value1.GetArray();
191
192         if( tipArray )
193         {
194           std::vector<std::string> tips = toggleButtonImpl.GetToggleTooltips();
195           size_t tipsCount( tips.size() );
196           for( size_t i( 0 ); i != tipsCount; ++i )
197           {
198             tipArray->PushBack( tips[i] );
199           }
200         }
201         value = value1;
202         break;
203       }
204       case Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX:
205       {
206         value = static_cast<int>(toggleButtonImpl.mCurrentToggleIndex);
207         break;
208       }
209     } // end of switch
210   }
211
212   return value;
213 }
214
215 void ToggleButton::CreateVisualsForAllStates( const Property::Array& states, std::vector<Toolkit::Visual::Base>& visuals )
216 {
217   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::CreateVisualsForAllStates\n" );
218
219   visuals.clear();
220
221   for ( unsigned int i = 0; i < states.Count(); i++ )
222   {
223     Property::Value value(  states[i] );
224
225     Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
226     Toolkit::Visual::Base stateVisual;
227
228     if ( value.GetType() == Property::MAP )
229     {
230       Property::Map *map = value.GetMap();
231       if( map && !map->Empty() ) // Empty map results in current visual removal.
232       {
233         DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using Map\n" );
234         stateVisual = visualFactory.CreateVisual( *map );
235       }
236     }
237     else if ( value.GetType() ==  Property::STRING )
238     {
239       std::string imageUrl = value.Get<std::string>();
240       DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using image URL\n" );
241       if ( !imageUrl.empty() )
242       {
243         stateVisual = visualFactory.CreateVisual( imageUrl, ImageDimensions() );
244       }
245     }
246
247     if ( stateVisual )
248     {
249       stateVisual.SetDepthIndex( DepthIndex::CONTENT );
250       visuals.push_back( stateVisual );
251     }
252   } // end of for
253   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals mToggleVisuals:%d\n", mToggleVisuals.size() );
254 }
255
256 void ToggleButton::SetToggleStates( const Property::Array& states )
257 { //this should really be generalized to be either string or maps so that any visual can be created.
258   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleStates\n" );
259   if ( !states.Empty() )
260   {
261     mToggleStates.Clear();
262     mToggleStates = states;
263     /* New toggle button index from 0. */
264     mCurrentToggleIndex = 0;
265
266     // Create all visuals, save to mToggleVisuals.
267     CreateVisualsForAllStates( states, mToggleVisuals );
268     CreateVisualsForAllStates( states, mToggleSelectedVisuals );
269     CreateVisualsForAllStates( states, mToggleDisabledVisuals );
270     CreateVisualsForAllStates( states, mToggleDisabledSelectedVisuals );
271
272     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Began to register visual.\n" );
273
274     PrepareVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
275     PrepareVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
276     PrepareVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
277     PrepareVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
278
279     RelayoutRequest();
280   }
281 }
282
283 Property::Array ToggleButton::GetToggleStates() const
284 {
285   return mToggleStates;
286 }
287
288 void ToggleButton::SetToggleTooltips( std::vector<std::string>& tips )
289 {
290   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleTooltips\n" );
291   if ( !tips.empty() )
292   {
293     mToggleTooltips.clear();
294     mToggleTooltips.swap( tips );
295   }
296
297   if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
298   {
299     Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
300   }
301
302   RelayoutRequest();
303 }
304
305 const std::vector<std::string>& ToggleButton::GetToggleTooltips() const
306 {
307   return mToggleTooltips;
308 }
309
310 void ToggleButton::PrepareVisual(Property::Index index, Toolkit::Visual::Base& visual)
311 {
312   DevelControl::RegisterVisual( *this, index, visual, true );
313   DevelControl::EnableVisual( *this, index, false );
314 }
315
316 void ToggleButton::RelayoutVisual( Property::Index index, const Vector2& size )
317 {
318   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, index );
319   if ( visual )
320   {
321     Size visualSize = Size::ZERO;
322     Vector2 visualPosition = Vector2::ZERO;
323
324     visual.GetNaturalSize( visualSize );
325
326     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height );
327     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual position to(%f,%f)\n", visualPosition.x, visualPosition.y );
328
329     Property::Map visualTransform;
330     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
331                    .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
332                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
333                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
334                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::CENTER )
335                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::CENTER );
336
337     visual.SetTransformAndSize( visualTransform, size );
338   }
339 }
340
341 void ToggleButton::OnRelayout( const Vector2& size, RelayoutContainer& container )
342 {
343   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout targetSize(%f,%f) ptr(%p)\n", size.width, size.height, this );
344
345   RelayoutVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, size );
346   RelayoutVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, size );
347   RelayoutVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, size );
348   RelayoutVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, size );
349 }
350
351 void ToggleButton::OnPressed()
352 {
353   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnPressed\n" );
354   // State index will add 1 only when button is pressed.
355   mCurrentToggleIndex = ( mCurrentToggleIndex + 1 ) % mToggleVisuals.size();
356
357   // Both create SelectedVisual and UnselectedVisual
358   PrepareVisual( Toolkit::DevelButton::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
359   PrepareVisual( Toolkit::DevelButton::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
360   PrepareVisual( Toolkit::DevelButton::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
361   PrepareVisual( Toolkit::DevelButton::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
362
363   //Need to check mCurrentToggleIndex, it must less than the size of mToggleTooltips.
364   if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
365   {
366     Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
367   }
368
369   RelayoutRequest();
370 }
371
372 } // namespace Internal
373
374 } // namespace Toolkit
375
376 } // namespace Dali