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 "button-impl.h"
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/scripting/enum-helper.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/events/touch-event.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/size-negotiation/relayout-container.h>
29 #include <dali/devel-api/object/property-helper-devel.h>
30 #include <dali/devel-api/scripting/scripting.h>
33 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
34 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
35 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
36 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
37 #include <dali-toolkit/public-api/align-enumerations.h>
38 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
41 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
42 #include <dali-toolkit/internal/visuals/text/text-visual.h>
43 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
44 #include <dali-toolkit/public-api/visuals/visual-properties.h>
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gLogButtonFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_BUTTON_CONTROL");
64 // empty handle as we cannot create button (but type registered for clicked signal)
68 // Setup properties, signals and actions using the type-registry.
69 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create )
71 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabled", BOOLEAN, DISABLED )
72 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "autoRepeating", BOOLEAN, AUTO_REPEATING )
73 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "initialAutoRepeatingDelay", FLOAT, INITIAL_AUTO_REPEATING_DELAY )
74 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "nextAutoRepeatingDelay", FLOAT, NEXT_AUTO_REPEATING_DELAY )
75 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "togglable", BOOLEAN, TOGGLABLE )
76 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selected", BOOLEAN, SELECTED )
77 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedVisual", MAP, UNSELECTED_VISUAL )
78 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedVisual", MAP, SELECTED_VISUAL )
79 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedVisual", MAP, DISABLED_SELECTED_VISUAL )
80 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedVisual", MAP, DISABLED_UNSELECTED_VISUAL )
81 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedBackgroundVisual", MAP, UNSELECTED_BACKGROUND_VISUAL )
82 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "label", MAP, LABEL )
83 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedBackgroundVisual", MAP, SELECTED_BACKGROUND_VISUAL )
84 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedBackgroundVisual", MAP, DISABLED_UNSELECTED_BACKGROUND_VISUAL )
85 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedBackgroundVisual", MAP, DISABLED_SELECTED_BACKGROUND_VISUAL )
86 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelRelativeAlignment", STRING, LABEL_RELATIVE_ALIGNMENT )
87 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelPadding", VECTOR4, LABEL_PADDING )
88 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "visualPadding", VECTOR4, VISUAL_PADDING )
91 DALI_SIGNAL_REGISTRATION( Toolkit, Button, "pressed", SIGNAL_PRESSED )
92 DALI_SIGNAL_REGISTRATION( Toolkit, Button, "released", SIGNAL_RELEASED )
93 DALI_SIGNAL_REGISTRATION( Toolkit, Button, "clicked", SIGNAL_CLICKED )
94 DALI_SIGNAL_REGISTRATION( Toolkit, Button, "stateChanged", SIGNAL_STATE_CHANGED )
97 DALI_ACTION_REGISTRATION( Toolkit, Button, "buttonClick", ACTION_BUTTON_CLICK )
99 DALI_TYPE_REGISTRATION_END()
101 DALI_ENUM_TO_STRING_TABLE_BEGIN( ALIGNMENT )
102 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BEGIN )
103 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, END )
104 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, TOP )
105 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BOTTOM )
106 DALI_ENUM_TO_STRING_TABLE_END( ALIGNMENT )
108 const Scripting::StringEnum ALIGNMENT_STRING_TABLE[] =
110 { "BEGIN", Button::BEGIN },
111 { "END", Button::END },
112 { "TOP", Button::TOP },
113 { "BOTTOM", Button::BOTTOM },
116 const unsigned int ALIGNMENT_STRING_TABLE_COUNT = sizeof( ALIGNMENT_STRING_TABLE ) / sizeof( ALIGNMENT_STRING_TABLE[0] );
118 const Property::Index VISUAL_INDEX_FOR_STATE[][Button::STATE_COUNT] =
120 { Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::UNSELECTED_VISUAL },
121 { Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::SELECTED_VISUAL },
122 { Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL },
123 { Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_SELECTED_VISUAL }
127 * Checks if given map contains a text string
129 bool MapContainsTextString( Property::Map& map )
132 Property::Value* value = map.Find( Toolkit::TextVisual::Property::TEXT );
135 std::string textString;
136 value->Get( textString );
137 if ( !textString.empty() )
145 } // unnamed namespace
148 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
149 mAutoRepeatingTimer(),
150 mTextLabelAlignment( END ),
151 mAutoRepeating( false ),
152 mTogglableButton( false ),
153 mTextStringSetFlag( false ),
154 mInitialAutoRepeatingDelay( 0.0f ),
155 mNextAutoRepeatingDelay( 0.0f ),
156 mAnimationTime( 0.0f ),
157 mButtonPressedState( UNPRESSED ),
158 mButtonState( UNSELECTED_STATE ),
159 mPreviousButtonState( mButtonState ),
160 mClickActionPerforming( false )
168 void Button::SetAutoRepeating( bool autoRepeating )
170 mAutoRepeating = autoRepeating;
172 // An autorepeating button can't be a toggle button.
177 SetSelected( false ); // UnSelect before switching off Toggle feature.
179 mTogglableButton = false;
183 void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
185 DALI_ASSERT_DEBUG( initialAutoRepeatingDelay > 0.f );
186 mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
189 void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
191 DALI_ASSERT_DEBUG( nextAutoRepeatingDelay > 0.f );
192 mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
195 void Button::SetTogglableButton( bool togglable )
197 mTogglableButton = togglable;
199 // A toggle button can't be an autorepeating button.
202 mAutoRepeating = false;
206 void Button::SetSelected( bool selected )
208 if( mTogglableButton )
210 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetSelected (%s)\n", (selected?"true":"false") );
212 if ( selected && ( mButtonState != SELECTED_STATE ) )
214 ChangeState( SELECTED_STATE );
216 else if ( !selected && ( mButtonState != UNSELECTED_STATE ) )
218 ChangeState( UNSELECTED_STATE );
223 void Button::SetDisabled( bool disabled )
225 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetDisabled(%s) state(%d)\n", (disabled)?"disabled":"active", mButtonState );
229 if ( mButtonState == SELECTED_STATE )
231 ChangeState( DISABLED_SELECTED_STATE );
233 else if ( mButtonState == UNSELECTED_STATE )
235 ChangeState( DISABLED_UNSELECTED_STATE );
240 if ( mButtonState == DISABLED_SELECTED_STATE )
242 ChangeState( SELECTED_STATE );
244 else if ( mButtonState == DISABLED_UNSELECTED_STATE )
246 ChangeState( UNSELECTED_STATE );
251 bool Button::IsDisabled() const
253 return ( mButtonState == DISABLED_SELECTED_STATE || mButtonState == DISABLED_UNSELECTED_STATE ) ;
256 bool Button::ValidateState( State requestedState )
258 /* Below tables shows allowed state transitions
259 * Match rows in first column to following columns, if true then transition allowed.
260 * eg UNSELECTED_STATE to DISABLED_UNSELECTED_STATE is true so state transition allowed.
262 to| UNSELECTED_STATE | SELECTED_STATE | DISABLED_UNSELECTED_STATE | DISABLED_SELECTED_STATE |*/
264 bool transitionTable[4][4] = { /* UNSELECTED_STATE*/ { false, true, true, false },
265 /* SELECTED_STATE*/ { true, false, false, true },
266 /* DISABLED_UNSELECTED_STATE*/{ true, true, false, false },
267 /* DISABLED_SELECTED_STATE*/ { false, true, false, false }
270 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ValidateState ReuestedState:%d, CurrentState:%d, result:%s\n",
271 requestedState, mButtonState, (transitionTable[mButtonState][requestedState])?"change-accepted":"change-denied");
273 return transitionTable[mButtonState][requestedState];
276 void Button::ChangeState( State requestedState )
278 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d)\n", requestedState );
280 // Validate State before changing
281 if ( !ValidateState( requestedState ))
283 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d) not validated\n", requestedState );
287 // If not on stage the button could have still been set to selected so update state
288 mPreviousButtonState = mButtonState; // Store previous state for visual removal (used when animations ended)
289 mButtonState = requestedState; // Update current state
291 if ( Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
293 OnStateChange( mButtonState ); // Notify derived buttons
294 SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
295 SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
296 // If animation supported then visual removal should be performed after any transition animation has completed.
297 // If Required Visual is not loaded before current visual is removed then a flickering will be evident.
298 // Derived button can override OnButtonVisualRemoval
299 OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
300 OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
304 Toolkit::Button handle( GetOwner() );
306 mStateChangedSignal.Emit( handle );
309 bool Button::IsSelected() const
311 bool selected = ( mButtonState == SELECTED_STATE ) || ( mButtonState == DISABLED_SELECTED_STATE );
312 return mTogglableButton && selected;
315 void Button::MergeWithExistingLabelProperties( const Property::Map& inMap, Property::Map& outMap )
317 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties with %d properties\n", inMap.Count() );
320 * Properties for the Label visual could be from a style sheet but after being set the "TEXT" property could be set.
321 * Hence would need to create the Text Visual with the complete merged set of properties.
323 * 1) Find Label Visual
324 * 2) Retrieve current properties ( settings )
325 * 3) Merge with new properties ( settings )
326 * 4) Return new merged map
328 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
331 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties Visual already exists, retrieving existing map\n");
332 visual.CreatePropertyMap( outMap );
333 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties retrieved %d properties\n", outMap.Count() );
336 outMap.Merge( inMap );
338 // Store if a text string has been supplied.
340 mTextStringSetFlag = MapContainsTextString( outMap );
342 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties now has %d properties\n", outMap.Count() );
345 void Button::SetLabelAlignment( Button::Align labelAlignment)
347 mTextLabelAlignment = labelAlignment;
351 Button::Align Button::GetLabelAlignment()
353 return mTextLabelAlignment;
357 * Create Visual for given index from a property map or url.
358 * 1) Check if value passed in is a url and create visual
359 * 2) Create visual from map if step (1) is false
360 * 3) Register visual with control with false for enable flag. Button will later enable visual when needed ( Button::SelectRequiredVisual )
361 * 4) Unregister visual if empty map was provided. This is the method to remove a visual
363 void Button::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth )
365 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent index(%d)\n", index );
366 Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
367 Toolkit::Visual::Base buttonVisual;
369 std::string imageUrl;
370 if( value.Get( imageUrl ) )
372 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using image URL(%d)\n", index );
373 if ( !imageUrl.empty() )
375 DALI_ASSERT_DEBUG( index != Toolkit::Button::Property::LABEL && "Creating a Image Visual instead of Text Visual " );
376 buttonVisual = visualFactory.CreateVisual( imageUrl, ImageDimensions() );
381 // if its not a string then get a Property::Map from the property if possible.
382 Property::Map *map = value.GetMap();
383 if( map && !map->Empty() ) // Empty map results in current visual removal.
385 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using Map(%d)\n", index );
386 buttonVisual = visualFactory.CreateVisual( *map );
392 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent RegisterVisual index(%d) enabled(%s)\n",
393 index, DevelControl::IsVisualEnabled( *this, index )?"true":"false" );
394 // enable the visual if needed for current state
395 const bool enabled = ( ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] )||
396 ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] )||
397 ( index == Toolkit::Button::Property::LABEL ) );
398 DevelControl::RegisterVisual( *this, index, buttonVisual, enabled, visualDepth );
402 DevelControl::UnregisterVisual( *this, index );
403 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "CreateVisualsForComponent Visual not created or empty map (clearing visual).(%d)\n", index);
408 bool Button::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
410 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual visual(%d)\n", visualIndex);
411 bool success = false;
412 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
415 visual.CreatePropertyMap( retreivedMap );
418 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual %s\n", success?"Success":"Failure");
422 bool Button::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
426 Dali::BaseHandle handle( object );
428 Toolkit::Button button = Toolkit::Button::DownCast( handle );
430 DALI_ASSERT_DEBUG( button );
432 if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
434 ret = GetImplementation( button ).DoClickAction( attributes );
440 bool Button::DoClickAction( const Property::Map& attributes )
442 // Prevents the button signals from doing a recursive loop by sending an action
443 // and re-emitting the signals.
444 if( !mClickActionPerforming )
446 mClickActionPerforming = true;
448 if ( !mTogglableButton )
450 mButtonPressedState = DEPRESSED;
453 mClickActionPerforming = false;
461 void Button::ButtonDown()
463 if( mTogglableButton )
465 if ( mButtonState != SELECTED_STATE )
468 mButtonPressedState = TOGGLE_DEPRESSED;
472 mButtonPressedState = DEPRESSED;
478 mButtonPressedState = DEPRESSED;
481 SetUpTimer( mInitialAutoRepeatingDelay );
485 // The pressed signal should be emitted regardless of toggle mode.
486 Toolkit::Button handle( GetOwner() );
487 mPressedSignal.Emit( handle );
490 void Button::ButtonUp()
492 bool emitSignalsForPressAndReleaseAction = false;
494 if( DEPRESSED == mButtonPressedState )
496 if( mTogglableButton ) // Button up will change state
498 emitSignalsForPressAndReleaseAction = OnToggleReleased(); // Derived toggle buttons can override this to provide custom behaviour
502 Released(); // Button up will result in unselected state
505 mAutoRepeatingTimer.Reset();
507 emitSignalsForPressAndReleaseAction = true;
510 else if ( TOGGLE_DEPRESSED == mButtonPressedState )
512 emitSignalsForPressAndReleaseAction = true; // toggle released after being pressed, a click
515 if ( emitSignalsForPressAndReleaseAction )
517 // The clicked and released signals should be emitted regardless of toggle mode.
518 Toolkit::Button handle( GetOwner() );
519 mReleasedSignal.Emit( handle );
520 mClickedSignal.Emit( handle );
524 bool Button::OnToggleReleased()
526 SetSelected( !IsSelected() );
527 mButtonPressedState = UNPRESSED;
532 void Button::OnTouchPointLeave()
534 if( DEPRESSED == mButtonPressedState )
536 if( !mTogglableButton )
542 mAutoRepeatingTimer.Reset();
546 mButtonPressedState = UNPRESSED;
548 // The released signal should be emitted regardless of toggle mode.
549 Toolkit::Button handle( GetOwner() );
550 mReleasedSignal.Emit( handle );
554 void Button::OnTouchPointInterrupted()
559 Toolkit::Button::ButtonSignalType& Button::PressedSignal()
561 return mPressedSignal;
564 Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
566 return mReleasedSignal;
569 Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
571 return mClickedSignal;
574 Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
576 return mStateChangedSignal;
579 bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
581 Dali::BaseHandle handle( object );
583 bool connected( true );
584 Toolkit::Button button = Toolkit::Button::DownCast( handle );
586 if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
588 button.PressedSignal().Connect( tracker, functor );
590 else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
592 button.ReleasedSignal().Connect( tracker, functor );
594 else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
596 button.ClickedSignal().Connect( tracker, functor );
598 else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
600 button.StateChangedSignal().Connect( tracker, functor );
604 // signalName does not match any signal
611 void Button::OnInitialize()
613 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnInitialize\n" );
617 mTapDetector = TapGestureDetector::New();
618 mTapDetector.Attach( self );
619 mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
621 self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true );
623 self.TouchSignal().Connect( this, &Button::OnTouch );
626 bool Button::OnAccessibilityActivated()
628 return OnKeyboardEnter();
631 bool Button::OnTouch( Actor actor, const TouchEvent& touch )
634 // Only events are processed when the button is not disabled
635 auto result( false );
639 if ( 1 == touch.GetPointCount() )
641 switch( touch.GetState( 0 ) )
643 case PointState::DOWN:
653 case PointState::INTERRUPTED:
655 OnTouchPointInterrupted();
658 case PointState::LEAVE:
663 case PointState::MOTION:
664 case PointState::STATIONARY: // FALLTHROUGH
671 else if( 1 < touch.GetPointCount() )
673 OnTouchPointLeave(); // Notification for derived classes.
675 // Sets the button state to the default
676 mButtonPressedState = UNPRESSED;
683 bool Button::OnKeyboardEnter()
685 // When the enter key is pressed, or button is activated, the click action is performed.
686 Property::Map attributes;
687 bool ret = DoClickAction( attributes );
692 void Button::OnSceneDisconnection()
694 if( DEPRESSED == mButtonPressedState )
696 if( !mTogglableButton )
702 mAutoRepeatingTimer.Reset();
707 mButtonPressedState = UNPRESSED;
709 Control::OnSceneDisconnection(); // Visuals will be set off stage
712 void Button::OnSceneConnection( int depth )
714 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnSceneConnection ptr(%p) \n", this );
715 OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
716 OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
717 SelectRequiredVisual( Toolkit::Button::Property::LABEL );
718 SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
719 SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
720 Control::OnSceneConnection( depth ); // Enabled visuals will be put on stage
724 Vector3 Button::GetNaturalSize()
726 Vector3 size = Vector3::ZERO;
728 bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side
730 // Get natural size of foreground ( largest of the possible visuals )
731 Size largestProvidedVisual;
732 Size labelSize = Size::ZERO;
734 bool foreGroundVisualUsed = false;
736 for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
738 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
742 visual.GetNaturalSize( visualSize );
743 largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
744 largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
745 foreGroundVisualUsed = true;
749 if ( !foreGroundVisualUsed ) // If foreground visual not supplied then use the background visual to calculate Natural size
751 for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
753 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
757 visual.GetNaturalSize( visualSize );
758 largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
759 largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
764 // Get horizontal padding total
765 if ( largestProvidedVisual.width > 0 ) // if visual exists
767 size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right;
769 // Get vertical padding total
770 if ( largestProvidedVisual.height > 0 )
772 size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom;
775 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n",
776 largestProvidedVisual.width, largestProvidedVisual.height );
778 // Get natural size of label if text has been set
779 if ( mTextStringSetFlag )
781 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
785 visual.GetNaturalSize( labelSize );
787 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n",
788 labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom);
790 labelSize.width += mLabelPadding.left + mLabelPadding.right;
791 labelSize.height += mLabelPadding.top + mLabelPadding.bottom;
793 // Add label size to height or width depending on alignment position
794 if ( horizontalAlignment )
796 size.width += labelSize.width;
797 size.height = std::max(size.height, labelSize.height );
801 size.height += labelSize.height;
802 size.width = std::max(size.width, labelSize.width );
807 if( size.width < 1 && size.height < 1 )
809 // if no image or label then use Control's natural size
810 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n");
811 size = Control::GetNaturalSize();
814 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height );
819 void Button::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
821 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnSetResizePolicy\n");
826 * Visuals are sized and positioned in this function.
827 * Whilst the control has it's size negotiated it has to size it's visuals explicitly here.
830 void Button::OnRelayout( const Vector2& size, RelayoutContainer& container )
832 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState );
834 Toolkit::Visual::Base currentVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND] );
835 Toolkit::Visual::Base currentBackGroundVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND] );
837 // Sizes and padding set to zero, if not present then values will no effect calculations.
838 Vector2 visualPosition = Vector2::ZERO;
839 Vector2 labelPosition = Vector2::ZERO;
840 Size visualSize = Size::ZERO;
841 Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
842 Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
844 if ( mTextStringSetFlag )
846 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width,mLabelPadding.height );
847 labelVisualPadding = mLabelPadding;
852 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width,mForegroundPadding.height );
853 currentVisual.GetNaturalSize( visualSize );
854 foregroundVisualPadding = mForegroundPadding;
857 Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
859 Vector2 visualAndPaddingSize = Vector2( ( foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y ),
860 ( foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height ));
862 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height);
864 // Text Visual should take all space available after foreground visual size and all padding is considered.
865 // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual.
866 Size remainingSpaceForText = Size::ZERO;
868 switch ( mTextLabelAlignment )
872 visualAnchorPoint = Toolkit::Align::TOP_END;
873 visualPosition.x = foregroundVisualPadding.right;
874 visualPosition.y = foregroundVisualPadding.top;
876 labelPosition.x = labelVisualPadding.x;
877 labelPosition.y = labelVisualPadding.top;
879 remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
880 remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
885 visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
886 visualPosition.x = foregroundVisualPadding.left;
887 visualPosition.y = foregroundVisualPadding.top;
889 labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x;
890 labelPosition.y = labelVisualPadding.top;
892 remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
893 remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
898 visualAnchorPoint = Toolkit::Align::BOTTOM_END;
899 visualPosition.x = foregroundVisualPadding.left;
900 visualPosition.y = foregroundVisualPadding.bottom;
902 labelPosition.x = labelVisualPadding.left;
903 labelPosition.y = labelVisualPadding.top;
905 remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
906 remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
912 visualAnchorPoint = Toolkit::Align::TOP_END;
913 visualPosition.x = foregroundVisualPadding.left;
914 visualPosition.y = foregroundVisualPadding.top;
916 labelPosition.x = labelVisualPadding.left;
917 labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top;
919 remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
920 remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
926 if ( currentBackGroundVisual )
928 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height);
930 Property::Map visualTransform;
932 visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, size )
933 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
935 currentBackGroundVisual.SetTransformAndSize( visualTransform, size );
940 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height);
942 Property::Map visualTransform;
944 visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
945 .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
946 .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
947 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
948 .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
949 .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
951 currentVisual.SetTransformAndSize( visualTransform, size );
954 if ( mTextStringSetFlag )
956 Toolkit::Visual::Base textVisual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL ); // No need to search for Label visual if no text set.
960 if ( !currentVisual )
962 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Only Text\n");
963 labelPosition.x = labelVisualPadding.left;
964 labelPosition.y = labelVisualPadding.height;
967 Vector2 preSize = Vector2( static_cast< int >( remainingSpaceForText.x ), static_cast< int >( remainingSpaceForText.y ));
969 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y);
971 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y);
974 Property::Map textVisualTransform;
975 textVisualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, preSize )
976 .Add( Toolkit::Visual::Transform::Property::OFFSET, labelPosition )
977 .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
978 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
979 .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
980 .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
982 textVisual.SetTransformAndSize( textVisualTransform, size );
986 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout selected (%s) \n", IsSelected()?"yes":"no" );
988 DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout << \n");
991 void Button::OnTap(Actor actor, const TapGesture& tap)
993 // Prevents Parent getting a tap event
996 void Button::SetUpTimer( float delay )
998 mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
999 mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
1000 mAutoRepeatingTimer.Start();
1003 bool Button::AutoRepeatingSlot()
1005 bool consumed = false;
1008 // Restart the autorepeat timer.
1009 SetUpTimer( mNextAutoRepeatingDelay );
1013 Toolkit::Button handle( GetOwner() );
1016 consumed = mReleasedSignal.Emit( handle );
1017 consumed = mClickedSignal.Emit( handle );
1018 consumed |= mPressedSignal.Emit( handle );
1024 void Button::Pressed()
1026 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Pressed\n" );
1028 if( mButtonState == UNSELECTED_STATE )
1030 ChangeState( SELECTED_STATE );
1031 OnPressed(); // Notifies the derived class the button has been pressed.
1035 void Button::Released()
1037 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Released\n" );
1039 if( mButtonState == SELECTED_STATE && !mTogglableButton )
1041 ChangeState( UNSELECTED_STATE );
1042 OnReleased(); // // Notifies the derived class the button has been released.
1044 mButtonPressedState = UNPRESSED;
1047 void Button::SelectRequiredVisual( Property::Index visualIndex )
1049 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1050 // only enable visuals that exist
1051 if( DevelControl::GetVisual( *this, visualIndex ) )
1053 DevelControl::EnableVisual( *this, visualIndex, true );
1057 void Button::RemoveVisual( Property::Index visualIndex )
1059 // Use OnButtonVisualRemoval if want button developer to have the option to override removal.
1060 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1062 Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
1066 DevelControl::EnableVisual( *this, visualIndex, false );
1070 void Button::OnButtonVisualRemoval( Property::Index visualIndex )
1072 // Derived Buttons can over ride this to prevent default removal.
1073 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex );
1074 RemoveVisual( visualIndex );
1077 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
1079 Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1081 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index );
1087 case Toolkit::Button::Property::DISABLED:
1089 GetImplementation( button ).SetDisabled( value.Get< bool >() );
1093 case Toolkit::Button::Property::AUTO_REPEATING:
1095 GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
1099 case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1101 GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
1105 case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1107 GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
1111 case Toolkit::Button::Property::TOGGLABLE:
1113 GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
1117 case Toolkit::Button::Property::SELECTED:
1119 GetImplementation( button ).SetSelected( value.Get< bool >() );
1123 case Toolkit::Button::Property::UNSELECTED_VISUAL:
1124 case Toolkit::Button::Property::SELECTED_VISUAL:
1125 case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1126 case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1128 GetImplementation( button ).CreateVisualsForComponent( index, value, DepthIndex::CONTENT );
1132 case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1133 case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1134 case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1135 case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1137 GetImplementation( button ).CreateVisualsForComponent( index , value, DepthIndex::BACKGROUND);
1141 case Toolkit::Button::Property::LABEL:
1143 Property::Map outTextVisualProperties;
1144 std::string textString;
1146 if ( value.Get( textString ) )
1148 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty Setting TextVisual with string[%s]\n", textString.c_str() );
1150 Property::Map setPropertyMap;
1151 setPropertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
1152 .Add( Toolkit::TextVisual::Property::TEXT, textString );
1154 GetImplementation( button ).MergeWithExistingLabelProperties( setPropertyMap, outTextVisualProperties );
1158 // Get a Property::Map from the property if possible.
1159 Property::Map* setPropertyMap = value.GetMap();
1160 if( setPropertyMap )
1162 TextVisual::ConvertStringKeysToIndexKeys( *setPropertyMap );
1163 GetImplementation( button ).MergeWithExistingLabelProperties( *setPropertyMap, outTextVisualProperties );
1167 if( !outTextVisualProperties.Empty() )
1169 GetImplementation( button ).CreateVisualsForComponent( index, outTextVisualProperties, DepthIndex::CONTENT );
1174 case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1176 Button::Align labelAlignment(END);
1177 Scripting::GetEnumeration< Button::Align> ( value.Get< std::string >().c_str(),
1178 ALIGNMENT_TABLE, ALIGNMENT_TABLE_COUNT,
1181 GetImplementation( button ).SetLabelAlignment( labelAlignment );
1185 case Toolkit::DevelButton::Property::LABEL_PADDING:
1187 Vector4 padding ( value.Get< Vector4 >() );
1188 GetImplementation( button ).SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1192 case Toolkit::DevelButton::Property::VISUAL_PADDING:
1194 Vector4 padding ( value.Get< Vector4 >() );
1195 GetImplementation( button ).SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1202 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
1204 Property::Value value;
1206 Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1210 switch ( propertyIndex )
1212 case Toolkit::Button::Property::DISABLED:
1214 value = GetImplementation( button ).IsDisabled();
1218 case Toolkit::Button::Property::AUTO_REPEATING:
1220 value = GetImplementation( button ).mAutoRepeating;
1224 case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1226 value = GetImplementation( button ).mInitialAutoRepeatingDelay;
1230 case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1232 value = GetImplementation( button ).mNextAutoRepeatingDelay;
1236 case Toolkit::Button::Property::TOGGLABLE:
1238 value = GetImplementation( button ).mTogglableButton;
1242 case Toolkit::Button::Property::SELECTED:
1244 value = GetImplementation( button ).IsSelected();
1248 case Toolkit::Button::Property::UNSELECTED_VISUAL:
1249 case Toolkit::Button::Property::SELECTED_VISUAL:
1250 case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1251 case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1252 case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1253 case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1254 case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1255 case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1256 case Toolkit::Button::Property::LABEL:
1258 Property::Map visualProperty;
1259 if ( GetImplementation( button ).GetPropertyMapForVisual( propertyIndex, visualProperty ) )
1261 value = visualProperty;
1266 case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1268 const char* alignment = Scripting::GetEnumerationName< Button::Align >( GetImplementation( button ).GetLabelAlignment(),
1269 ALIGNMENT_STRING_TABLE,
1270 ALIGNMENT_STRING_TABLE_COUNT );
1273 value = std::string( alignment );
1279 case Toolkit::DevelButton::Property::LABEL_PADDING:
1281 Padding padding = GetImplementation( button ).GetLabelPadding();
1282 value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1286 case Toolkit::DevelButton::Property::VISUAL_PADDING:
1288 Padding padding = GetImplementation( button ).GetForegroundPadding();
1289 value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1297 void Button::SetLabelPadding( const Padding& padding)
1299 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1300 mLabelPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1304 Padding Button::GetLabelPadding()
1306 return mLabelPadding;
1309 void Button::SetForegroundPadding( const Padding& padding)
1311 DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1312 mForegroundPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1316 Padding Button::GetForegroundPadding()
1318 return mForegroundPadding;
1321 } // namespace Internal
1323 } // namespace Toolkit