2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "toggle-button-impl.h"
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/devel-api/scripting/scripting.h>
25 #include <dali/public-api/object/property-array.h>
26 #include <dali/integration-api/debug.h>
29 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
30 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
31 #include <dali-toolkit/devel-api/controls/control-devel.h>
32 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
33 #include <dali-toolkit/public-api/visuals/visual-properties.h>
34 #include <dali-toolkit/public-api/align-enumerations.h>
35 #include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
36 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
37 #include <dali-toolkit/devel-api/controls/control-devel.h>
39 #if defined(DEBUG_ENABLED)
40 extern Debug::Filter* gLogButtonFilter;
57 return Toolkit::ToggleButton::New();
61 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToggleButton, Toolkit::Button, Create )
63 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "stateVisuals", ARRAY, STATE_VISUALS )
64 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "tooltips", ARRAY, TOOLTIPS )
65 DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "currentStateIndex", INTEGER, CURRENT_STATE_INDEX )
67 DALI_TYPE_REGISTRATION_END()
69 } // unnamed namespace
71 Dali::Toolkit::ToggleButton ToggleButton::New()
73 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::New\n" );
74 // Create the implementation, temporarily owned on stack
75 IntrusivePtr< ToggleButton > internalToggleButton = new ToggleButton();
77 // Pass ownership to CustomActor
78 Dali::Toolkit::ToggleButton toggleButton( *internalToggleButton );
80 // Second-phase init of the implementation
81 // This can only be done after the CustomActor connection has been made...
82 internalToggleButton->Initialize();
87 ToggleButton::ToggleButton()
91 mToggleSelectedVisuals(),
92 mToggleDisabledVisuals(),
93 mToggleDisabledSelectedVisuals(),
95 mCurrentToggleIndex(0)
97 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Constructor\n" );
98 SetTogglableButton( false );
101 ToggleButton::~ToggleButton()
105 void ToggleButton::OnInitialize()
107 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnInitialize\n" );
108 Button::OnInitialize();
110 // Toggle button requires the Leave event.
112 self.SetProperty( Actor::Property::LEAVE_REQUIRED, true );
114 DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
115 return std::unique_ptr< Dali::Accessibility::Accessible >(
116 new AccessibleImpl( actor, Dali::Accessibility::Role::TOGGLE_BUTTON ) );
120 void ToggleButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
122 Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
124 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::SetProperty index[%d]\n", propertyIndex );
128 ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
130 switch ( propertyIndex )
132 case Toolkit::ToggleButton::Property::STATE_VISUALS:
134 Property::Array stateArray;
135 if( value.Get( stateArray ) )
137 toggleButtonImpl.SetToggleStates( stateArray );
142 case Toolkit::ToggleButton::Property::TOOLTIPS:
144 const Property::Array* tipArray = value.GetArray();
147 std::vector<std::string> tips;
148 size_t tipsCount = tipArray->Count();
149 tips.resize( tipsCount );
150 for( size_t i = 0; i != tipsCount; ++i )
152 tipArray->GetElementAt( i ).Get( tips[i] );
154 toggleButtonImpl.SetToggleTooltips(tips);
166 Property::Value ToggleButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
168 Property::Value value;
170 Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
172 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::GetProperty index[%d]\n", propertyIndex );
176 ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
178 switch ( propertyIndex )
180 case Toolkit::ToggleButton::Property::STATE_VISUALS:
182 Property::Array array = toggleButtonImpl.GetToggleStates();
183 value = Property::Value( array );
186 case Toolkit::ToggleButton::Property::TOOLTIPS:
188 Property::Value value1( Property::ARRAY );
189 Property::Array* tipArray = value1.GetArray();
193 std::vector<std::string> tips = toggleButtonImpl.GetToggleTooltips();
194 size_t tipsCount( tips.size() );
195 for( size_t i( 0 ); i != tipsCount; ++i )
197 tipArray->PushBack( tips[i] );
203 case Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX:
205 value = static_cast<int>(toggleButtonImpl.mCurrentToggleIndex);
214 void ToggleButton::CreateVisualsForAllStates( const Property::Array& states, std::vector<Toolkit::Visual::Base>& visuals )
216 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::CreateVisualsForAllStates\n" );
220 for ( unsigned int i = 0; i < states.Count(); i++ )
222 Property::Value value( states[i] );
224 Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
225 Toolkit::Visual::Base stateVisual;
227 if ( value.GetType() == Property::MAP )
229 Property::Map *map = value.GetMap();
230 if( map && !map->Empty() ) // Empty map results in current visual removal.
232 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using Map\n" );
233 stateVisual = visualFactory.CreateVisual( *map );
236 else if ( value.GetType() == Property::STRING )
238 std::string imageUrl = value.Get<std::string>();
239 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using image URL\n" );
240 if ( !imageUrl.empty() )
242 stateVisual = visualFactory.CreateVisual( imageUrl, ImageDimensions() );
248 stateVisual.SetDepthIndex( DepthIndex::CONTENT );
249 visuals.push_back( stateVisual );
252 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals mToggleVisuals:%d\n", mToggleVisuals.size() );
255 void ToggleButton::SetToggleStates( const Property::Array& states )
256 { //this should really be generalized to be either string or maps so that any visual can be created.
257 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleStates\n" );
258 if ( !states.Empty() )
260 mToggleStates.Clear();
261 mToggleStates = states;
262 /* New toggle button index from 0. */
263 mCurrentToggleIndex = 0;
265 // Create all visuals, save to mToggleVisuals.
266 CreateVisualsForAllStates( states, mToggleVisuals );
267 CreateVisualsForAllStates( states, mToggleSelectedVisuals );
268 CreateVisualsForAllStates( states, mToggleDisabledVisuals );
269 CreateVisualsForAllStates( states, mToggleDisabledSelectedVisuals );
271 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Began to register visual.\n" );
273 PrepareVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
274 PrepareVisual( Toolkit::Button::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
275 PrepareVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
276 PrepareVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
282 Property::Array ToggleButton::GetToggleStates() const
284 return mToggleStates;
287 void ToggleButton::SetToggleTooltips( std::vector<std::string>& tips )
289 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleTooltips\n" );
292 mToggleTooltips.clear();
293 mToggleTooltips.swap( tips );
296 if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
298 Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
304 const std::vector<std::string>& ToggleButton::GetToggleTooltips() const
306 return mToggleTooltips;
309 void ToggleButton::PrepareVisual(Property::Index index, Toolkit::Visual::Base& visual)
311 bool enabled = false; // Disabled by default
313 // Unregister the visual with the given index if registered previously
314 if( DevelControl::GetVisual( *this, index ) )
316 // Check whether it was enabled to ensure we do the same with the new visual we're registering
317 enabled = DevelControl::IsVisualEnabled( *this, index );
318 DevelControl::UnregisterVisual( *this, index );
321 DevelControl::RegisterVisual( *this, index, visual, enabled );
324 void ToggleButton::RelayoutVisual( Property::Index index, const Vector2& size )
326 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, index );
329 Size visualSize = Size::ZERO;
330 Vector2 visualPosition = Vector2::ZERO;
332 visual.GetNaturalSize( visualSize );
334 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height );
335 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual position to(%f,%f)\n", visualPosition.x, visualPosition.y );
337 Property::Map visualTransform;
338 visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
339 .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
340 .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
341 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
342 .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::CENTER )
343 .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::CENTER );
345 visual.SetTransformAndSize( visualTransform, size );
349 void ToggleButton::OnRelayout( const Vector2& size, RelayoutContainer& container )
351 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout targetSize(%f,%f) ptr(%p)\n", size.width, size.height, this );
353 RelayoutVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, size );
354 RelayoutVisual( Toolkit::Button::Property::SELECTED_VISUAL, size );
355 RelayoutVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, size );
356 RelayoutVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, size );
359 void ToggleButton::OnPressed()
361 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnPressed\n" );
362 // State index will add 1 only when button is pressed.
363 mCurrentToggleIndex = ( mCurrentToggleIndex + 1 ) % mToggleVisuals.size();
365 // Both create SelectedVisual and UnselectedVisual
366 PrepareVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
367 PrepareVisual( Toolkit::Button::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
368 PrepareVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
369 PrepareVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
371 //Need to check mCurrentToggleIndex, it must less than the size of mToggleTooltips.
372 if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
374 Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
380 Dali::Accessibility::States ToggleButton::AccessibleImpl::CalculateStates()
382 auto states = Button::AccessibleImpl::CalculateStates();
383 auto button = Toolkit::ToggleButton::DownCast( self );
384 if( button.GetProperty<int>( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ) )
385 states[Dali::Accessibility::State::CHECKED] = true;
389 std::string ToggleButton::AccessibleImpl::GetDescriptionRaw()
391 auto button = Toolkit::ToggleButton::DownCast( self );
392 auto index = button.GetProperty<int>( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX );
393 auto tooltips = button.GetProperty<Property::Array>( Toolkit::ToggleButton::Property::TOOLTIPS );
395 return tooltips[index].Get<std::string>();
398 Property::Index ToggleButton::AccessibleImpl::GetDescriptionPropertyIndex()
400 return Toolkit::ToggleButton::Property::TOOLTIPS;
403 void ToggleButton::OnStateChange( State newState )
405 // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
406 if (Dali::Accessibility::IsUp() && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
408 Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged(
409 Dali::Accessibility::State::CHECKED, mCurrentToggleIndex ? 1 : 0, 0
412 if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
414 Dali::Accessibility::Accessible::Get(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
419 } // namespace Internal
421 } // namespace Toolkit