X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fbuttons%2Fbutton-impl.cpp;h=2883c9a59a87fa92452bb8d1428fba3fb637deff;hb=19179e76939a18697e6919177a4c561586e8d30b;hp=0d3fcd572a2de6b752d2fe91de1ffb51fb93b873;hpb=afb47f411d700d2b4be6415b61995cde5c37126c;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/buttons/button-impl.cpp b/dali-toolkit/internal/controls/buttons/button-impl.cpp index 0d3fcd5..70e9c76 100644 --- a/dali-toolkit/internal/controls/buttons/button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/button-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,51 +19,42 @@ #include "button-impl.h" // EXTERNAL INCLUDES +#include +#include +#include +#include #include -#include #include -#include -#include +#include +#include +#include // for strcmp // INTERNAL INCLUDES -#include - -/** - * Button states and contents - * (3) mSelectedContent - * (2) mButtonContent (2) mSelectedBackgroundContent - * (1) mBackgroundContent (1) mBackgroundContent - * < unselected > ----------------------- < selected > - * | OnSelect() | - * | OnDisabled() | OnDisabled() - * | | - * < disabled > < disabled-selected > - * (2) mDisabledContent (2) mDisabledSelectedContent - * (1) mDisabledBackgroundContent (1) mDisabledBackgroundContent - * - * The drawing order of child actors is as follows. - * - * Top mLabel - * | mButtonContent / mSelectedContent / mDisabledContent / mDisabledSelectedContent - * | mSelectedBackgroundContent - * Bottom mBackgroundContent / mDisabledBackgroundContent - * - * Some of contents may be missed. - * And 2 images - fade-in image and fade-out image - in the same layer can be shown during the transition animation. Fade-in image should be above fade-out image. - */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogButtonFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_BUTTON_CONTROL"); +#endif namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { - BaseHandle Create() { // empty handle as we cannot create button (but type registered for clicked signal) @@ -71,1531 +62,1216 @@ BaseHandle Create() } // Setup properties, signals and actions using the type-registry. -DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create ); - -DALI_PROPERTY_REGISTRATION( Button, "disabled", BOOLEAN, DISABLED ) -DALI_PROPERTY_REGISTRATION( Button, "auto-repeating", BOOLEAN, AUTO_REPEATING ) -DALI_PROPERTY_REGISTRATION( Button, "initial-auto-repeating-delay", FLOAT, INITIAL_AUTO_REPEATING_DELAY ) -DALI_PROPERTY_REGISTRATION( Button, "next-auto-repeating-delay", FLOAT, NEXT_AUTO_REPEATING_DELAY ) -DALI_PROPERTY_REGISTRATION( Button, "togglable", BOOLEAN, TOGGLABLE ) -DALI_PROPERTY_REGISTRATION( Button, "selected", BOOLEAN, SELECTED ) -DALI_PROPERTY_REGISTRATION( Button, "normal-state-actor", MAP, NORMAL_STATE_ACTOR ) -DALI_PROPERTY_REGISTRATION( Button, "selected-state-actor", MAP, SELECTED_STATE_ACTOR ) -DALI_PROPERTY_REGISTRATION( Button, "disabled-state-actor", MAP, DISABLED_STATE_ACTOR ) -DALI_PROPERTY_REGISTRATION( Button, "label-actor", MAP, LABEL_ACTOR ) - -DALI_SIGNAL_REGISTRATION( Button, "pressed", SIGNAL_PRESSED ) -DALI_SIGNAL_REGISTRATION( Button, "released", SIGNAL_RELEASED ) -DALI_SIGNAL_REGISTRATION( Button, "clicked", SIGNAL_CLICKED ) -DALI_SIGNAL_REGISTRATION( Button, "state-changed", SIGNAL_STATE_CHANGED ) - -DALI_ACTION_REGISTRATION( Button, "button-click", ACTION_BUTTON_CLICK ) +DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Button, Toolkit::Control, Create) + +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "disabled", BOOLEAN, DISABLED) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "autoRepeating", BOOLEAN, AUTO_REPEATING) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "initialAutoRepeatingDelay", FLOAT, INITIAL_AUTO_REPEATING_DELAY) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "nextAutoRepeatingDelay", FLOAT, NEXT_AUTO_REPEATING_DELAY) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "togglable", BOOLEAN, TOGGLABLE) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "selected", BOOLEAN, SELECTED) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "unselectedVisual", MAP, UNSELECTED_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "selectedVisual", MAP, SELECTED_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "disabledSelectedVisual", MAP, DISABLED_SELECTED_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "disabledUnselectedVisual", MAP, DISABLED_UNSELECTED_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "unselectedBackgroundVisual", MAP, UNSELECTED_BACKGROUND_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "label", MAP, LABEL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "selectedBackgroundVisual", MAP, SELECTED_BACKGROUND_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "disabledUnselectedBackgroundVisual", MAP, DISABLED_UNSELECTED_BACKGROUND_VISUAL) +DALI_PROPERTY_REGISTRATION(Toolkit, Button, "disabledSelectedBackgroundVisual", MAP, DISABLED_SELECTED_BACKGROUND_VISUAL) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, Button, "labelRelativeAlignment", STRING, LABEL_RELATIVE_ALIGNMENT) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, Button, "labelPadding", VECTOR4, LABEL_PADDING) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, Button, "visualPadding", VECTOR4, VISUAL_PADDING) + +// Signals: +DALI_SIGNAL_REGISTRATION(Toolkit, Button, "pressed", SIGNAL_PRESSED) +DALI_SIGNAL_REGISTRATION(Toolkit, Button, "released", SIGNAL_RELEASED) +DALI_SIGNAL_REGISTRATION(Toolkit, Button, "clicked", SIGNAL_CLICKED) +DALI_SIGNAL_REGISTRATION(Toolkit, Button, "stateChanged", SIGNAL_STATE_CHANGED) + +// Actions: +DALI_ACTION_REGISTRATION(Toolkit, Button, "buttonClick", ACTION_BUTTON_CLICK) DALI_TYPE_REGISTRATION_END() -const unsigned int INITIAL_AUTOREPEATING_DELAY( 0.15f ); -const unsigned int NEXT_AUTOREPEATING_DELAY( 0.05f ); +DALI_ENUM_TO_STRING_TABLE_BEGIN(ALIGNMENT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::Button, BEGIN) + DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::Button, END) + DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::Button, TOP) + DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::Button, BOTTOM) +DALI_ENUM_TO_STRING_TABLE_END(ALIGNMENT) -} // unnamed namespace +const Scripting::StringEnum ALIGNMENT_STRING_TABLE[] = + { + {"BEGIN", Button::BEGIN}, + {"END", Button::END}, + {"TOP", Button::TOP}, + {"BOTTOM", Button::BOTTOM}, +}; -Button::Button() -: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ), - mAutoRepeatingTimer(), - mDisabled( false ), - mAutoRepeating( false ), - mTogglableButton( false ), - mSelected( false ), - mInitialAutoRepeatingDelay( INITIAL_AUTOREPEATING_DELAY ), - mNextAutoRepeatingDelay( NEXT_AUTOREPEATING_DELAY ), - mAnimationTime( 0.0f ), - mClickActionPerforming( false ), - mState( ButtonUp ), - mPaintState( UnselectedState ) -{ -} +const unsigned int ALIGNMENT_STRING_TABLE_COUNT = sizeof(ALIGNMENT_STRING_TABLE) / sizeof(ALIGNMENT_STRING_TABLE[0]); -Button::~Button() -{ - if( mAutoRepeatingTimer ) +const Property::Index VISUAL_INDEX_FOR_STATE[][Button::STATE_COUNT] = { - mAutoRepeatingTimer.Reset(); - } -} + {Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::UNSELECTED_VISUAL}, + {Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::SELECTED_VISUAL}, + {Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL}, + {Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_SELECTED_VISUAL}}; -void Button::SetDisabled( bool disabled ) +/** + * Checks if given map contains a text string + */ +bool MapContainsTextString(Property::Map& map) { - if( disabled != mDisabled ) + bool result = false; + Property::Value* value = map.Find(Toolkit::TextVisual::Property::TEXT); + if(value) { - unsigned int backgroundIndex; - unsigned int buttonIndex; - - bool animationStarted = false; - - mDisabled = disabled; - - switch( mPaintState ) + std::string textString; + value->Get(textString); + if(!textString.empty()) { - case UnselectedState: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mDisabledContent ); - - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mDisabledBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = UnselectedDisabledTransition; - } - else - { - mPaintState = DisabledUnselectedState; - } - break; - } - case SelectedState: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mDisabledSelectedContent ); - - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mDisabledBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = SelectedDisabledTransition; - } - else - { - mPaintState = DisabledSelectedState; - } - break; - } - case DisabledUnselectedState: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mButtonContent ); - - if( mDisabledBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = DisabledUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; - } - case DisabledSelectedState: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mSelectedContent ); - - if( mDisabledBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mSelectedBackgroundContent ); - InsertChild( backgroundIndex, mBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = DisabledSelectedTransition; - } - else - { - mPaintState = SelectedState; - } - break; - } - case UnselectedSelectedTransition: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mDisabledSelectedContent ); - - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mDisabledBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = SelectedDisabledTransition; - } - else - { - mPaintState = DisabledSelectedState; - } - break; - } - case SelectedUnselectedTransition: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mDisabledContent ); - - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mDisabledBackgroundContent ); - - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = UnselectedDisabledTransition; - } - else - { - mPaintState = DisabledUnselectedState; - } - break; - } - case UnselectedDisabledTransition: - { - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = DisabledUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; - } - case DisabledUnselectedTransition: - { - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = UnselectedDisabledTransition; - } - else - { - mPaintState = DisabledUnselectedState; - } - break; - } - case SelectedDisabledTransition: - { - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = DisabledSelectedTransition; - } - else - { - mPaintState = SelectedState; - } - break; - } - case DisabledSelectedTransition: - { - animationStarted = OnDisabled(); - - if( animationStarted ) - { - mPaintState = SelectedDisabledTransition; - } - else - { - mPaintState = DisabledSelectedState; - } - break; - } + result = true; } } + return result; } -bool Button::IsDisabled() const +} // unnamed namespace + +Button::Button() +: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)), + mAutoRepeatingTimer(), + mTextLabelAlignment(END), + mAutoRepeating(false), + mTogglableButton(false), + mTextStringSetFlag(false), + mInitialAutoRepeatingDelay(0.0f), + mNextAutoRepeatingDelay(0.0f), + mAnimationTime(0.0f), + mButtonPressedState(UNPRESSED), + mButtonState(UNSELECTED_STATE), + mPreviousButtonState(mButtonState), + mClickActionPerforming(false) { - return mDisabled; } -void Button::SetAutoRepeating( bool autoRepeating ) +Button::~Button() +{ +} + +void Button::SetAutoRepeating(bool autoRepeating) { mAutoRepeating = autoRepeating; - // An autorepeating button can't be a togglable button. - if( autoRepeating ) + // An autorepeating button can't be a toggle button. + if(autoRepeating) { - mTogglableButton = false; - - if( mSelected ) + if(IsSelected()) { - // Emit a signal is not wanted, only change the appearance. - SetSelected( false, false ); + SetSelected(false); // UnSelect before switching off Toggle feature. } + mTogglableButton = false; } } -bool Button::IsAutoRepeating() const +void Button::SetInitialAutoRepeatingDelay(float initialAutoRepeatingDelay) { - return mAutoRepeating; -} - -void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay ) -{ - DALI_ASSERT_ALWAYS( initialAutoRepeatingDelay > 0.f ); + DALI_ASSERT_DEBUG(initialAutoRepeatingDelay > 0.f); mInitialAutoRepeatingDelay = initialAutoRepeatingDelay; } -float Button::GetInitialAutoRepeatingDelay() const +void Button::SetNextAutoRepeatingDelay(float nextAutoRepeatingDelay) { - return mInitialAutoRepeatingDelay; -} - -void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay ) -{ - DALI_ASSERT_ALWAYS( nextAutoRepeatingDelay > 0.f ); + DALI_ASSERT_DEBUG(nextAutoRepeatingDelay > 0.f); mNextAutoRepeatingDelay = nextAutoRepeatingDelay; } -float Button::GetNextAutoRepeatingDelay() const -{ - return mNextAutoRepeatingDelay; -} - -void Button::SetTogglableButton( bool togglable ) +void Button::SetTogglableButton(bool togglable) { mTogglableButton = togglable; - // A togglable button can't be an autorepeating button. - if( togglable ) + // A toggle button can't be an autorepeating button. + if(togglable) { mAutoRepeating = false; } } -bool Button::IsTogglableButton() const +void Button::SetSelected(bool selected) { - return mTogglableButton; -} - -void Button::SetSelected( bool selected ) -{ - if( !mDisabled && mTogglableButton && ( selected != mSelected ) ) + if(mTogglableButton) { - SetSelected( selected, true ); - } -} - -void Button::SetSelected( bool selected, bool emitSignal ) -{ - unsigned int buttonIndex, backgroundIndex; - bool animationStarted = false; - - mSelected = selected; + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetSelected (%s)\n", (selected ? "true" : "false")); - switch( mPaintState ) - { - case UnselectedState: + if(selected && (mButtonState != SELECTED_STATE)) { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mSelectedContent ); - - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mSelectedBackgroundContent ); - - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); - - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } - break; + ChangeState(SELECTED_STATE); } - case SelectedState: + else if(!selected && (mButtonState != UNSELECTED_STATE)) { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mButtonContent ); - - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); - - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; + ChangeState(UNSELECTED_STATE); } - case UnselectedSelectedTransition: - { - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); + } +} - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; - } - case SelectedUnselectedTransition: - { - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); +void Button::SetDisabled(bool disabled) +{ + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetDisabled(%s) state(%d)\n", (disabled) ? "disabled" : "active", mButtonState); - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } - break; + if(disabled) + { + if(mButtonState == SELECTED_STATE) + { + ChangeState(DISABLED_SELECTED_STATE); } - case DisabledUnselectedTransition: + else if(mButtonState == UNSELECTED_STATE) { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mSelectedContent ); - - if( mDisabledBackgroundContent ) - { - if( mBackgroundContent ) - { - backgroundIndex = 2; - } - else - { - backgroundIndex = 1; - } - } - else if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } - - InsertChild( backgroundIndex, mSelectedBackgroundContent ); - - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); - - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } - break; + ChangeState(DISABLED_UNSELECTED_STATE); } - case DisabledSelectedTransition: + } + else + { + if(mButtonState == DISABLED_SELECTED_STATE) { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mButtonContent ); - - // Notifies the derived class the button has been selected. - animationStarted = OnSelected(); - - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; + ChangeState(SELECTED_STATE); } - default: + else if(mButtonState == DISABLED_UNSELECTED_STATE) { - break; + ChangeState(UNSELECTED_STATE); } } - - if( emitSignal ) - { - Toolkit::Button handle( GetOwner() ); - - // Emit signal. - mStateChangedSignal.Emit( handle ); - } - - RelayoutRequest(); } -bool Button::IsSelected() const +bool Button::IsDisabled() const { - return mTogglableButton && mSelected; + return (mButtonState == DISABLED_SELECTED_STATE || mButtonState == DISABLED_UNSELECTED_STATE); } -void Button::SetAnimationTime( float animationTime ) +bool Button::ValidateState(State requestedState) { - mAnimationTime = animationTime; -} + /* Below tables shows allowed state transitions + * Match rows in first column to following columns, if true then transition allowed. + * eg UNSELECTED_STATE to DISABLED_UNSELECTED_STATE is true so state transition allowed. + * + to| UNSELECTED_STATE | SELECTED_STATE | DISABLED_UNSELECTED_STATE | DISABLED_SELECTED_STATE |*/ + /* from*/ + bool transitionTable[4][4] = {/* UNSELECTED_STATE*/ {false, true, true, false}, + /* SELECTED_STATE*/ {true, false, false, true}, + /* DISABLED_UNSELECTED_STATE*/ {true, true, false, false}, + /* DISABLED_SELECTED_STATE*/ {false, true, false, false}}; -float Button::GetAnimationTime() const -{ - return mAnimationTime; -} + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::ValidateState ReuestedState:%d, CurrentState:%d, result:%s\n", requestedState, mButtonState, (transitionTable[mButtonState][requestedState]) ? "change-accepted" : "change-denied"); -void Button::SetLabel( const std::string& label ) -{ - Toolkit::TextView textView = Toolkit::TextView::New( label ); - textView.SetWidthExceedPolicy( Toolkit::TextView::ShrinkToFit ); // Make sure our text always fits inside the button - SetLabel( textView ); + return transitionTable[mButtonState][requestedState]; } -void Button::SetLabel( Actor label ) +void Button::ChangeState(State requestedState) { - if( mLabel != label ) - { - if( mLabel && mLabel.GetParent() ) - { - mLabel.GetParent().Remove( mLabel ); - } - - mLabel = label; - mLabel.SetPosition( 0.f, 0.f ); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d)\n", requestedState); - // label should be the top of the button - Self().Add( mLabel ); + // Validate State before changing + if(!ValidateState(requestedState)) + { + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d) not validated\n", requestedState); + return; + } - OnLabelSet(); + // If not on stage the button could have still been set to selected so update state + mPreviousButtonState = mButtonState; // Store previous state for visual removal (used when animations ended) + mButtonState = requestedState; // Update current state + if(Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + OnStateChange(mButtonState); // Notify derived buttons + SelectRequiredVisual(VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND]); + SelectRequiredVisual(VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND]); + // If animation supported then visual removal should be performed after any transition animation has completed. + // If Required Visual is not loaded before current visual is removed then a flickering will be evident. + // Derived button can override OnButtonVisualRemoval + OnButtonVisualRemoval(VISUAL_INDEX_FOR_STATE[mPreviousButtonState][BACKGROUND]); + OnButtonVisualRemoval(VISUAL_INDEX_FOR_STATE[mPreviousButtonState][FOREGROUND]); RelayoutRequest(); } -} -Actor Button::GetLabel() const -{ - return mLabel; + Toolkit::Button handle(GetOwner()); + // Emit signal. + mStateChangedSignal.Emit(handle); } -Actor& Button::GetLabel() +bool Button::IsSelected() const { - return mLabel; + bool selected = (mButtonState == SELECTED_STATE) || (mButtonState == DISABLED_SELECTED_STATE); + return mTogglableButton && selected; } -void Button::SetButtonImage( Actor image ) +void Button::MergeWithExistingLabelProperties(const Property::Map& inMap, Property::Map& outMap) { - StopAllAnimations(); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "MergeLabelProperties with %d properties\n", inMap.Count()); - if( mButtonContent && mButtonContent.GetParent() ) + /** + * Properties for the Label visual could be from a style sheet but after being set the "TEXT" property could be set. + * Hence would need to create the Text Visual with the complete merged set of properties. + * + * 1) Find Label Visual + * 2) Retrieve current properties ( settings ) + * 3) Merge with new properties ( settings ) + * 4) Return new merged map + */ + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::Button::Property::LABEL); + if(visual) { - Self().Remove( mButtonContent ); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "MergeLabelProperties Visual already exists, retrieving existing map\n"); + visual.CreatePropertyMap(outMap); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "MergeLabelProperties retrieved %d properties\n", outMap.Count()); } - mButtonContent = image; + outMap.Merge(inMap); - mButtonContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mButtonContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mButtonContent.SetPosition( 0.f, 0.f ); + // Store if a text string has been supplied. - if( mPaintState == UnselectedState ) - { - unsigned int index = FindChildIndex( mLabel ); - - Self().Insert( index, mButtonContent ); - } + mTextStringSetFlag = MapContainsTextString(outMap); - OnButtonImageSet(); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "MergeLabelProperties now has %d properties\n", outMap.Count()); } -Actor Button::GetButtonImage() const +void Button::SetLabelAlignment(Button::Align labelAlignment) { - return mButtonContent; + mTextLabelAlignment = labelAlignment; + RelayoutRequest(); } -Actor& Button::GetButtonImage() +Button::Align Button::GetLabelAlignment() { - return mButtonContent; + return mTextLabelAlignment; } -void Button::SetSelectedImage( Actor image ) +/** + * Create Visual for given index from a property map or url. + * 1) Check if value passed in is a url and create visual + * 2) Create visual from map if step (1) is false + * 3) Register visual with control with false for enable flag. Button will later enable visual when needed ( Button::SelectRequiredVisual ) + * 4) Unregister visual if empty map was provided. This is the method to remove a visual + */ +void Button::CreateVisualsForComponent(Property::Index index, const Property::Value& value, const int visualDepth) { - StopAllAnimations(); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent index(%d)\n", index); + Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get(); + Toolkit::Visual::Base buttonVisual; - if( mSelectedContent && mSelectedContent.GetParent() ) + std::string imageUrl; + if(value.Get(imageUrl)) { - Self().Remove( mSelectedContent ); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using image URL(%d)\n", index); + if(!imageUrl.empty()) + { + DALI_ASSERT_DEBUG(index != Toolkit::Button::Property::LABEL && "Creating a Image Visual instead of Text Visual "); + buttonVisual = visualFactory.CreateVisual(imageUrl, ImageDimensions()); + } } - - mSelectedContent = image; - - mSelectedContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mSelectedContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mSelectedContent.SetPosition( 0.f, 0.f ); - - if( mPaintState == SelectedState ) + else { - unsigned int index = FindChildIndex( mLabel ); - - Self().Insert( index, mSelectedContent ); + // if its not a string then get a Property::Map from the property if possible. + const Property::Map* map = value.GetMap(); + if(map && !map->Empty()) // Empty map results in current visual removal. + { + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using Map(%d)\n", index); + buttonVisual = visualFactory.CreateVisual(*map); + } } - OnSelectedImageSet(); -} - -Actor Button::GetSelectedImage() const -{ - return mSelectedContent; + if(buttonVisual) + { + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent RegisterVisual index(%d) enabled(%s)\n", index, DevelControl::IsVisualEnabled(*this, index) ? "true" : "false"); + // enable the visual if needed for current state + const bool enabled = ((index == VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND]) || + (index == VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND]) || + (index == Toolkit::Button::Property::LABEL)); + DevelControl::RegisterVisual(*this, index, buttonVisual, enabled, visualDepth); + } + else + { + DevelControl::UnregisterVisual(*this, index); + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "CreateVisualsForComponent Visual not created or empty map (clearing visual).(%d)\n", index); + } + RelayoutRequest(); } -Actor& Button::GetSelectedImage() +bool Button::GetPropertyMapForVisual(Property::Index visualIndex, Property::Map& retreivedMap) const { - return mSelectedContent; + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "GetPropertyMapForVisual visual(%d)\n", visualIndex); + bool success = false; + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, visualIndex); + if(visual) + { + visual.CreatePropertyMap(retreivedMap); + success = true; + } + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "GetPropertyMapForVisual %s\n", success ? "Success" : "Failure"); + return success; } -void Button::SetBackgroundImage( Actor image ) +bool Button::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes) { - StopAllAnimations(); + bool ret = false; - if( mBackgroundContent && mBackgroundContent.GetParent() ) - { - Self().Remove( mBackgroundContent ); - } + Dali::BaseHandle handle(object); - mBackgroundContent = image; + Toolkit::Button button = Toolkit::Button::DownCast(handle); - mBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mBackgroundContent.SetPosition( 0.f, 0.f ); + DALI_ASSERT_DEBUG(button); - if( mPaintState == UnselectedState || mPaintState == SelectedState ) + if(0 == strcmp(actionName.c_str(), ACTION_BUTTON_CLICK)) { - Self().Insert( 0, mBackgroundContent ); + ret = GetImplementation(button).DoClickAction(attributes); } - OnBackgroundImageSet(); + return ret; } -Actor Button::GetBackgroundImage() const +bool Button::DoClickAction(const Property::Map& attributes) { - return mBackgroundContent; -} + // Prevents the button signals from doing a recursive loop by sending an action + // and re-emitting the signals. + if(!mClickActionPerforming) + { + mClickActionPerforming = true; + ButtonDown(); + if(!mTogglableButton) + { + mButtonPressedState = DEPRESSED; + } + ButtonUp(); + mClickActionPerforming = false; -Actor& Button::GetBackgroundImage() -{ - return mBackgroundContent; + return true; + } + + return false; } -void Button::SetSelectedBackgroundImage( Actor image ) +void Button::ButtonDown() { - StopAllAnimations(); - - if( mSelectedBackgroundContent && mSelectedBackgroundContent.GetParent() ) + if(mTogglableButton) + { + if(mButtonState != SELECTED_STATE) + { + SetSelected(true); + mButtonPressedState = TOGGLE_DEPRESSED; + } + else + { + mButtonPressedState = DEPRESSED; + } + } + else { - Self().Remove( mSelectedBackgroundContent ); + Pressed(); + mButtonPressedState = DEPRESSED; + if(mAutoRepeating) + { + SetUpTimer(mInitialAutoRepeatingDelay); + } } - mSelectedBackgroundContent = image; + // The pressed signal should be emitted regardless of toggle mode. + Toolkit::Button handle(GetOwner()); + mPressedSignal.Emit(handle); +} - mSelectedBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mSelectedBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mSelectedBackgroundContent.SetPosition( 0.f, 0.f ); +void Button::ButtonUp() +{ + bool emitSignalsForPressAndReleaseAction = false; - if( mPaintState == SelectedState ) + if(DEPRESSED == mButtonPressedState) { - if( mBackgroundContent ) + if(mTogglableButton) // Button up will change state { - Self().Insert( 1, mSelectedBackgroundContent ); + emitSignalsForPressAndReleaseAction = OnToggleReleased(); // Derived toggle buttons can override this to provide custom behaviour } else { - Self().Insert( 0, mSelectedBackgroundContent ); + Released(); // Button up will result in unselected state + if(mAutoRepeating) + { + mAutoRepeatingTimer.Reset(); + } + emitSignalsForPressAndReleaseAction = true; } } + else if(TOGGLE_DEPRESSED == mButtonPressedState) + { + emitSignalsForPressAndReleaseAction = true; // toggle released after being pressed, a click + } - OnSelectedBackgroundImageSet(); -} - -Actor Button::GetSelectedBackgroundImage() const -{ - return mSelectedBackgroundContent; + if(emitSignalsForPressAndReleaseAction) + { + // The clicked and released signals should be emitted regardless of toggle mode. + Toolkit::Button handle(GetOwner()); + mReleasedSignal.Emit(handle); + mClickedSignal.Emit(handle); + } } -Actor& Button::GetSelectedBackgroundImage() +bool Button::OnToggleReleased() { - return mSelectedBackgroundContent; + SetSelected(!IsSelected()); + mButtonPressedState = UNPRESSED; + return true; } -void Button::SetDisabledImage( Actor image ) +void Button::OnTouchPointLeave() { - StopAllAnimations(); - - if( mDisabledContent && mDisabledContent.GetParent() ) + if(DEPRESSED == mButtonPressedState) { - Self().Remove( mDisabledContent ); - } - - mDisabledContent = image; + if(!mTogglableButton) + { + Released(); - mDisabledContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mDisabledContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mDisabledContent.SetPosition( 0.f, 0.f ); + if(mAutoRepeating) + { + mAutoRepeatingTimer.Reset(); + } + } - if( mPaintState == DisabledUnselectedState || mPaintState == DisabledSelectedState ) - { - unsigned int index = FindChildIndex( mLabel ); + mButtonPressedState = UNPRESSED; - Self().Insert( index, mDisabledContent ); + // The released signal should be emitted regardless of toggle mode. + Toolkit::Button handle(GetOwner()); + mReleasedSignal.Emit(handle); } - - OnDisabledImageSet(); } -Actor Button::GetDisabledImage() const +void Button::OnTouchPointInterrupted() { - return mDisabledContent; + OnTouchPointLeave(); } -Actor& Button::GetDisabledImage() +Toolkit::Button::ButtonSignalType& Button::PressedSignal() { - return mDisabledContent; + return mPressedSignal; } -void Button::SetDisabledSelectedImage( Actor image ) +Toolkit::Button::ButtonSignalType& Button::ReleasedSignal() { - StopAllAnimations(); - - if( mDisabledSelectedContent && mDisabledSelectedContent.GetParent() ) - { - Self().Remove( mDisabledSelectedContent ); - } - - mDisabledSelectedContent = image; - - mDisabledSelectedContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mDisabledSelectedContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mDisabledSelectedContent.SetPosition( 0.f, 0.f ); - - if( mPaintState == DisabledSelectedState ) - { - unsigned int index = FindChildIndex( mLabel ); - - Self().Insert( index, mDisabledSelectedContent ); - } - - OnDisabledSelectedImageSet(); + return mReleasedSignal; } -Actor Button::GetDisabledSelectedImage() const +Toolkit::Button::ButtonSignalType& Button::ClickedSignal() { - return mDisabledSelectedContent; + return mClickedSignal; } -Actor& Button::GetDisabledSelectedImage() +Toolkit::Button::ButtonSignalType& Button::StateChangedSignal() { - return mDisabledSelectedContent; + return mStateChangedSignal; } -void Button::SetDisabledBackgroundImage( Actor image ) +bool Button::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor) { - StopAllAnimations(); + Dali::BaseHandle handle(object); + + bool connected(true); + Toolkit::Button button = Toolkit::Button::DownCast(handle); - if( mDisabledBackgroundContent && mDisabledBackgroundContent.GetParent() ) + if(0 == strcmp(signalName.c_str(), SIGNAL_PRESSED)) { - Self().Remove( mDisabledBackgroundContent ); + button.PressedSignal().Connect(tracker, functor); } - - mDisabledBackgroundContent = image; - - mDisabledBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mDisabledBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mDisabledBackgroundContent.SetPosition( 0.f, 0.f ); - - if( mPaintState == DisabledUnselectedState || mPaintState == DisabledSelectedState ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_RELEASED)) { - Self().Insert( 0, mDisabledBackgroundContent ); + button.ReleasedSignal().Connect(tracker, functor); + } + else if(0 == strcmp(signalName.c_str(), SIGNAL_CLICKED)) + { + button.ClickedSignal().Connect(tracker, functor); + } + else if(0 == strcmp(signalName.c_str(), SIGNAL_STATE_CHANGED)) + { + button.StateChangedSignal().Connect(tracker, functor); + } + else + { + // signalName does not match any signal + connected = false; } - OnDisabledBackgroundImageSet(); -} - -Actor Button::GetDisabledBackgroundImage() const -{ - return mDisabledBackgroundContent; -} - -Actor& Button::GetDisabledBackgroundImage() -{ - return mDisabledBackgroundContent; + return connected; } -bool Button::DoAction( BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes ) +void Button::OnInitialize() { - bool ret = false; - - Dali::BaseHandle handle( object ); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::OnInitialize\n"); - Toolkit::Button button = Toolkit::Button::DownCast( handle ); + Actor self = Self(); - DALI_ASSERT_ALWAYS( button ); + mTapDetector = TapGestureDetector::New(); + mTapDetector.Attach(self); + mTapDetector.DetectedSignal().Connect(this, &Button::OnTap); - if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) ) - { - GetImplementation( button ).DoClickAction( attributes ); - ret = true; - } + self.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); + self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true); - return ret; + self.TouchedSignal().Connect(this, &Button::OnTouch); } -void Button::DoClickAction( const PropertyValueContainer& attributes ) +bool Button::OnAccessibilityActivated() { - // Prevents the button signals from doing a recursive loop by sending an action - // and re-emitting the signals. - if( !mClickActionPerforming ) - { - mClickActionPerforming = true; - OnButtonDown(); - mState = ButtonDown; - OnButtonUp(); - mClickActionPerforming = false; - } + return OnKeyboardEnter(); } -void Button::UpdatePaintTransitionState() +bool Button::OnTouch(Actor actor, const TouchEvent& touch) { - switch( mPaintState ) + if(!IsDisabled() && (actor == touch.GetHitActor(0))) { - case UnselectedSelectedTransition: + if(1 == touch.GetPointCount()) { - RemoveChild( mButtonContent ); - mPaintState = SelectedState; - break; - } - case SelectedUnselectedTransition: - { - RemoveChild( mSelectedBackgroundContent ); - RemoveChild( mSelectedContent ); - mPaintState = UnselectedState; - break; - } - case UnselectedDisabledTransition: - { - RemoveChild( mBackgroundContent ); - RemoveChild( mButtonContent ); - mPaintState = DisabledUnselectedState; - break; - } - case DisabledUnselectedTransition: - { - RemoveChild( mDisabledBackgroundContent ); - RemoveChild( mDisabledContent ); - mPaintState = UnselectedState; - break; - } - case SelectedDisabledTransition: - { - RemoveChild( mBackgroundContent ); - RemoveChild( mSelectedBackgroundContent ); - RemoveChild( mSelectedContent ); - mPaintState = DisabledSelectedState; - break; - } - case DisabledSelectedTransition: - { - RemoveChild( mDisabledBackgroundContent ); - RemoveChild( mDisabledSelectedContent ); - mPaintState = SelectedState; - break; - } - default: - { - break; - } - } -} - -void Button::OnButtonStageDisconnection() -{ - if( ButtonDown == mState ) - { - if( !mTogglableButton ) - { - Released(); - - if( mAutoRepeating ) + switch(touch.GetState(0)) { - mAutoRepeatingTimer.Reset(); + case PointState::DOWN: + { + ButtonDown(); + break; + } + case PointState::UP: + { + ButtonUp(); + break; + } + case PointState::INTERRUPTED: + { + OnTouchPointInterrupted(); + break; + } + case PointState::LEAVE: + { + OnTouchPointLeave(); + break; + } + case PointState::MOTION: + case PointState::STATIONARY: // FALLTHROUGH + { + // Nothing to do + break; + } } } - } -} - -void Button::OnButtonDown() -{ - if( !mTogglableButton ) - { - Toolkit::Button handle( GetOwner() ); - - Pressed(); - - if( mAutoRepeating ) + else if(1 < touch.GetPointCount()) { - SetUpTimer( mInitialAutoRepeatingDelay ); - } + OnTouchPointLeave(); // Notification for derived classes. - //Emit signal. - mPressedSignal.Emit( handle ); + // Sets the button state to the default + mButtonPressedState = UNPRESSED; + } } + return false; } -void Button::OnButtonUp() +bool Button::OnKeyboardEnter() { - if( ButtonDown == mState ) - { - if( mTogglableButton ) - { - SetSelected( !mSelected ); - } - else - { - Released(); + // When the enter key is pressed, or button is activated, the click action is performed. + Property::Map attributes; + bool ret = DoClickAction(attributes); - if( mAutoRepeating ) - { - mAutoRepeatingTimer.Reset(); - } - - Toolkit::Button handle( GetOwner() ); - - //Emit signal. - mReleasedSignal.Emit( handle ); - mClickedSignal.Emit( handle ); - } - } + return ret; } -void Button::OnTouchPointLeave() +void Button::OnSceneDisconnection() { - if( ButtonDown == mState ) + if(DEPRESSED == mButtonPressedState) { - if( !mTogglableButton ) + if(!mTogglableButton) { - Toolkit::Button handle( GetOwner() ); - Released(); - if( mAutoRepeating ) + if(mAutoRepeating) { mAutoRepeatingTimer.Reset(); } - - //Emit signal. - mReleasedSignal.Emit( handle ); } } -} -void Button::OnTouchPointInterrupted() -{ - OnTouchPointLeave(); -} + mButtonPressedState = UNPRESSED; -Toolkit::Button::ButtonSignalType& Button::PressedSignal() -{ - return mPressedSignal; + Control::OnSceneDisconnection(); // Visuals will be set off stage } -Toolkit::Button::ButtonSignalType& Button::ReleasedSignal() +void Button::OnSceneConnection(int depth) { - return mReleasedSignal; + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::OnSceneConnection ptr(%p) \n", this); + OnButtonVisualRemoval(VISUAL_INDEX_FOR_STATE[mPreviousButtonState][BACKGROUND]); + OnButtonVisualRemoval(VISUAL_INDEX_FOR_STATE[mPreviousButtonState][FOREGROUND]); + SelectRequiredVisual(Toolkit::Button::Property::LABEL); + SelectRequiredVisual(VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND]); + SelectRequiredVisual(VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND]); + Control::OnSceneConnection(depth); // Enabled visuals will be put on stage + RelayoutRequest(); } -Toolkit::Button::ButtonSignalType& Button::ClickedSignal() +Vector3 Button::GetNaturalSize() { - return mClickedSignal; -} + Vector3 size = Vector3::ZERO; -Toolkit::Button::ButtonSignalType& Button::StateChangedSignal() -{ - return mStateChangedSignal; -} + bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side -bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) -{ - Dali::BaseHandle handle( object ); + // Get natural size of foreground ( largest of the possible visuals ) + Size largestProvidedVisual; + Size labelSize = Size::ZERO; - bool connected( true ); - Toolkit::Button button = Toolkit::Button::DownCast( handle ); + bool foreGroundVisualUsed = false; - if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) ) - { - button.PressedSignal().Connect( tracker, functor ); - } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) ) + for(int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++) { - button.ReleasedSignal().Connect( tracker, functor ); + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, VISUAL_INDEX_FOR_STATE[state][FOREGROUND]); + Size visualSize; + if(visual) + { + visual.GetNaturalSize(visualSize); + largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width); + largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height); + foreGroundVisualUsed = true; + } } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) ) + + if(!foreGroundVisualUsed) // If foreground visual not supplied then use the background visual to calculate Natural size { - button.ClickedSignal().Connect( tracker, functor ); + for(int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++) + { + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, VISUAL_INDEX_FOR_STATE[state][BACKGROUND]); + Size visualSize; + if(visual) + { + visual.GetNaturalSize(visualSize); + largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width); + largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height); + } + } } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) ) + + // Get horizontal padding total + if(largestProvidedVisual.width > 0) // if visual exists { - button.StateChangedSignal().Connect( tracker, functor ); + size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right; } - else + // Get vertical padding total + if(largestProvidedVisual.height > 0) { - // signalName does not match any signal - connected = false; + size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom; } - return connected; -} + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n", largestProvidedVisual.width, largestProvidedVisual.height); -bool Button::OnTouchEvent(const TouchEvent& event) -{ - // Only events are processed when the button is not disabled and the touch event has only - // one touch point. - if( ( !mDisabled ) && ( 1 == event.GetPointCount() ) ) + // Get natural size of label if text has been set + if(mTextStringSetFlag) { - switch( event.GetPoint(0).state ) - { - case TouchPoint::Down: - { - OnButtonDown(); // Notification for derived classes. + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::Button::Property::LABEL); - // Sets the button state to ButtonDown. - mState = ButtonDown; - break; - } - case TouchPoint::Up: - { - OnButtonUp(); // Notification for derived classes. + if(visual) + { + visual.GetNaturalSize(labelSize); - // Sets the button state to ButtonUp. - mState = ButtonUp; - break; - } - case TouchPoint::Interrupted: - { - OnTouchPointInterrupted(); // Notification for derived classes. + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n", labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom); - // Sets the button state to the default (ButtonUp). - mState = ButtonUp; - break; - } - case TouchPoint::Leave: - { - OnTouchPointLeave(); // Notification for derived classes. + labelSize.width += mLabelPadding.left + mLabelPadding.right; + labelSize.height += mLabelPadding.top + mLabelPadding.bottom; - // Sets the button state to the default (ButtonUp). - mState = ButtonUp; - break; - } - case TouchPoint::Motion: - case TouchPoint::Stationary: // FALLTHROUGH + // Add label size to height or width depending on alignment position + if(horizontalAlignment) { - // Nothing to do - break; + size.width += labelSize.width; + size.height = std::max(size.height, labelSize.height); } - default: + else { - DALI_ASSERT_ALWAYS( !"Point status unhandled." ); - break; + size.height += labelSize.height; + size.width = std::max(size.width, labelSize.width); } } } - else if( 1 < event.GetPointCount() ) - { - OnTouchPointLeave(); // Notification for derived classes. - // Sets the button state to the default (ButtonUp). - mState = ButtonUp; + if(size.width < 1 && size.height < 1) + { + // if no image or label then use Control's natural size + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n"); + size = Control::GetNaturalSize(); } - return false; -} - -void Button::OnInitialize() -{ - Actor self = Self(); - - mTapDetector = TapGestureDetector::New(); - mTapDetector.Attach( self ); - mTapDetector.DetectedSignal().Connect(this, &Button::OnTap); + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height); - OnButtonInitialize(); - - self.SetDrawMode( DrawMode::OVERLAY ); - self.SetKeyboardFocusable( true ); + return size; } -void Button::OnActivated() +void Button::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension) { - // When the button is activated, it performs the click action - PropertyValueContainer attributes; - DoClickAction( attributes ); + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnSetResizePolicy\n"); + RelayoutRequest(); } -void Button::OnControlStageDisconnection() -{ - OnButtonStageDisconnection(); // Notification for derived classes. - mState = ButtonUp; -} +/** + * Visuals are sized and positioned in this function. + * Whilst the control has it's size negotiated it has to size it's visuals explicitly here. + */ -void Button::OnTap(Actor actor, const TapGesture& tap) +void Button::OnRelayout(const Vector2& size, RelayoutContainer& container) { - // Do nothing. -} + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState); -void Button::SetUpTimer( float delay ) -{ - mAutoRepeatingTimer = Dali::Timer::New( static_cast( 1000.f * delay ) ); - mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot ); - mAutoRepeatingTimer.Start(); -} + Toolkit::Visual::Base currentVisual = DevelControl::GetVisual(*this, VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND]); + Toolkit::Visual::Base currentBackGroundVisual = DevelControl::GetVisual(*this, VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND]); -bool Button::AutoRepeatingSlot() -{ - bool consumed = false; - if( !mDisabled ) + // Sizes and padding set to zero, if not present then values will no effect calculations. + Vector2 visualPosition = Vector2::ZERO; + Vector2 labelPosition = Vector2::ZERO; + Size visualSize = Size::ZERO; + Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f); + Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f); + + if(mTextStringSetFlag) { - // Restart the autorepeat timer. - SetUpTimer( mNextAutoRepeatingDelay ); + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width, mLabelPadding.height); + labelVisualPadding = mLabelPadding; + } - Pressed(); + if(currentVisual) + { + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width, mForegroundPadding.height); + currentVisual.GetNaturalSize(visualSize); + foregroundVisualPadding = mForegroundPadding; + } - Toolkit::Button handle( GetOwner() ); + Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN; - //Emit signal. - consumed = mReleasedSignal.Emit( handle ); - consumed |= mClickedSignal.Emit( handle ); - consumed |= mPressedSignal.Emit( handle ); - } + Vector2 visualAndPaddingSize = Vector2((foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y), + (foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height)); - return consumed; -} + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height); -void Button::Pressed() -{ - unsigned int buttonIndex, backgroundIndex; - bool animationStarted = false; + // Text Visual should take all space available after foreground visual size and all padding is considered. + // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual. + Size remainingSpaceForText = Size::ZERO; - switch( mPaintState ) + switch(mTextLabelAlignment) { - case UnselectedState: + case BEGIN: { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mSelectedContent ); + visualAnchorPoint = Toolkit::Align::TOP_END; + visualPosition.x = foregroundVisualPadding.right; + visualPosition.y = foregroundVisualPadding.top; - if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } + labelPosition.x = labelVisualPadding.x; + labelPosition.y = labelVisualPadding.top; - InsertChild( backgroundIndex, mSelectedBackgroundContent ); + remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y; + remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom; + break; + } + case END: + { + visualAnchorPoint = Toolkit::Align::TOP_BEGIN; + visualPosition.x = foregroundVisualPadding.left; + visualPosition.y = foregroundVisualPadding.top; - // Notifies the derived class the button has been pressed. - animationStarted = OnPressed(); + labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x; + labelPosition.y = labelVisualPadding.top; - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } + remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y; + remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom; break; } - case SelectedUnselectedTransition: + case TOP: { - // Notifies the derived class the button has been pressed. - animationStarted = OnPressed(); + visualAnchorPoint = Toolkit::Align::BOTTOM_END; + visualPosition.x = foregroundVisualPadding.left; + visualPosition.y = foregroundVisualPadding.bottom; + + labelPosition.x = labelVisualPadding.left; + labelPosition.y = labelVisualPadding.top; + + remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y; + remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom; - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } break; } - case DisabledUnselectedTransition: + case BOTTOM: { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mSelectedContent ); - - if( mDisabledBackgroundContent ) - { - if( mBackgroundContent ) - { - backgroundIndex = 2; - } - else - { - backgroundIndex = 1; - } - } - else if( mBackgroundContent ) - { - backgroundIndex = 1; - } - else - { - backgroundIndex = 0; - } + visualAnchorPoint = Toolkit::Align::TOP_END; + visualPosition.x = foregroundVisualPadding.left; + visualPosition.y = foregroundVisualPadding.top; - InsertChild( backgroundIndex, mSelectedBackgroundContent ); + labelPosition.x = labelVisualPadding.left; + labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top; - // Notifies the derived class the button has been pressed. - animationStarted = OnPressed(); + remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y; + remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom; - if( animationStarted ) - { - mPaintState = UnselectedSelectedTransition; - } - else - { - mPaintState = SelectedState; - } break; } - default: - break; } -} -void Button::Released() -{ - unsigned int buttonIndex; - bool animationStarted = false; + if(currentBackGroundVisual) + { + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height); + + Property::Map visualTransform; + + visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, size) + .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)); - switch( mPaintState ) + currentBackGroundVisual.SetTransformAndSize(visualTransform, size); + } + + if(currentVisual) { - case SelectedState: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mButtonContent ); + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height); - // Notifies the derived class the button has been released. - animationStarted = OnReleased(); + Property::Map visualTransform; - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; - } - case UnselectedSelectedTransition: - { - // Notifies the derived class the button has been released. - animationStarted = OnReleased(); + visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, visualSize) + .Add(Toolkit::Visual::Transform::Property::OFFSET, visualPosition) + .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) + .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint); - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else - { - mPaintState = UnselectedState; - } - break; - } - case DisabledSelectedTransition: - { - buttonIndex = FindChildIndex( mLabel ); - InsertChild( buttonIndex, mButtonContent ); + currentVisual.SetTransformAndSize(visualTransform, size); + } - // Notifies the derived class the button has been released. - animationStarted = OnReleased(); + if(mTextStringSetFlag) + { + Toolkit::Visual::Base textVisual = DevelControl::GetVisual(*this, Toolkit::Button::Property::LABEL); // No need to search for Label visual if no text set. - if( animationStarted ) - { - mPaintState = SelectedUnselectedTransition; - } - else + if(textVisual) + { + if(!currentVisual) { - mPaintState = UnselectedState; + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout Only Text\n"); + labelPosition.x = labelVisualPadding.left; + labelPosition.y = labelVisualPadding.height; } - break; - } - default: - { - break; + + Vector2 preSize = Vector2(static_cast(remainingSpaceForText.x), static_cast(remainingSpaceForText.y)); + + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y); + + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y); + + Property::Map textVisualTransform; + textVisualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, preSize) + .Add(Toolkit::Visual::Transform::Property::OFFSET, labelPosition) + .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) + .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint); + + textVisual.SetTransformAndSize(textVisualTransform, size); } } + + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout selected (%s) \n", IsSelected() ? "yes" : "no"); + + DALI_LOG_INFO(gLogButtonFilter, Debug::General, "OnRelayout << \n"); } -Button::ButtonState Button::GetState() +void Button::OnTap(Actor actor, const TapGesture& tap) { - return mState; + // Prevents Parent getting a tap event } -Button::PaintState Button::GetPaintState() +void Button::SetUpTimer(float delay) { - return mPaintState; + mAutoRepeatingTimer = Dali::Timer::New(static_cast(1000.f * delay)); + mAutoRepeatingTimer.TickSignal().Connect(this, &Button::AutoRepeatingSlot); + mAutoRepeatingTimer.Start(); } -void Button::InsertChild( unsigned int index, Actor& actor ) +bool Button::AutoRepeatingSlot() { - if( actor ) + bool consumed = false; + if(!IsDisabled()) { - Self().Insert( index, actor); + // Restart the autorepeat timer. + SetUpTimer(mNextAutoRepeatingDelay); + + Pressed(); + + Toolkit::Button handle(GetOwner()); + + //Emit signal. + consumed = mReleasedSignal.Emit(handle); + consumed = mClickedSignal.Emit(handle); + consumed |= mPressedSignal.Emit(handle); } + + return consumed; } -void Button::RemoveChild( Actor& actor ) +void Button::Pressed() { - if( actor && actor.GetParent() ) + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::Pressed\n"); + + if(mButtonState == UNSELECTED_STATE) { - Self().Remove( actor ); + ChangeState(SELECTED_STATE); + OnPressed(); // Notifies the derived class the button has been pressed. } } -unsigned int Button::FindChildIndex( Actor& actor ) +void Button::Released() { - Actor self = Self(); - unsigned int childrenNum = self.GetChildCount(); + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::Released\n"); - for( unsigned int i = 0; i < childrenNum; i++ ) + if(mButtonState == SELECTED_STATE && !mTogglableButton) { - Actor child = self.GetChildAt( i ); - if( child == actor ) - { - return i; - } + ChangeState(UNSELECTED_STATE); + OnReleased(); // // Notifies the derived class the button has been released. + } + mButtonPressedState = UNPRESSED; +} + +void Button::SelectRequiredVisual(Property::Index visualIndex) +{ + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState); + // only enable visuals that exist + if(DevelControl::GetVisual(*this, visualIndex)) + { + DevelControl::EnableVisual(*this, visualIndex, true); + } +} + +void Button::RemoveVisual(Property::Index visualIndex) +{ + // Use OnButtonVisualRemoval if want button developer to have the option to override removal. + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState); + + Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, visualIndex); + + if(visual) + { + DevelControl::EnableVisual(*this, visualIndex, false); } +} - return childrenNum; +void Button::OnButtonVisualRemoval(Property::Index visualIndex) +{ + // Derived Buttons can over ride this to prevent default removal. + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex); + RemoveVisual(visualIndex); } -void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +void Button::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) { - Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) ); + Toolkit::Button button = Toolkit::Button::DownCast(Dali::BaseHandle(object)); - if ( button ) + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index); + + if(button) { - switch ( index ) + switch(index) { case Toolkit::Button::Property::DISABLED: { - GetImplementation( button ).SetDisabled( value.Get() ); + GetImplementation(button).SetDisabled(value.Get()); break; } case Toolkit::Button::Property::AUTO_REPEATING: { - GetImplementation( button ).SetAutoRepeating( value.Get< bool >() ); + GetImplementation(button).SetAutoRepeating(value.Get()); break; } case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY: { - GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() ); + GetImplementation(button).SetInitialAutoRepeatingDelay(value.Get()); break; } case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY: { - GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() ); + GetImplementation(button).SetNextAutoRepeatingDelay(value.Get()); break; } case Toolkit::Button::Property::TOGGLABLE: { - GetImplementation( button ).SetTogglableButton( value.Get< bool >() ); + GetImplementation(button).SetTogglableButton(value.Get()); break; } case Toolkit::Button::Property::SELECTED: { - GetImplementation( button ).SetSelected( value.Get< bool >() ); + GetImplementation(button).SetSelected(value.Get()); + break; + } + + case Toolkit::Button::Property::UNSELECTED_VISUAL: + case Toolkit::Button::Property::SELECTED_VISUAL: + case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL: + case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL: + { + GetImplementation(button).CreateVisualsForComponent(index, value, DepthIndex::CONTENT); + break; + } + + case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL: + { + GetImplementation(button).CreateVisualsForComponent(index, value, DepthIndex::BACKGROUND); break; } - case Toolkit::Button::Property::NORMAL_STATE_ACTOR: + case Toolkit::Button::Property::LABEL: { - GetImplementation( button ).SetButtonImage( Scripting::NewActor( value.Get< Property::Map >() ) ); + Property::Map outTextVisualProperties; + std::string textString; + + if(value.Get(textString)) + { + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetProperty Setting TextVisual with string[%s]\n", textString.c_str()); + + Property::Map setPropertyMap; + setPropertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT) + .Add(Toolkit::TextVisual::Property::TEXT, textString); + + GetImplementation(button).MergeWithExistingLabelProperties(setPropertyMap, outTextVisualProperties); + } + else + { + // Get a Property::Map from the property if possible. + const Property::Map* setPropertyMap = value.GetMap(); + if(setPropertyMap) + { + Property::Map indexKeys = TextVisual::ConvertStringKeysToIndexKeys(*setPropertyMap); + GetImplementation(button).MergeWithExistingLabelProperties(indexKeys, outTextVisualProperties); + } + } + + if(!outTextVisualProperties.Empty()) + { + GetImplementation(button).CreateVisualsForComponent(index, outTextVisualProperties, DepthIndex::CONTENT); + } break; } - case Toolkit::Button::Property::SELECTED_STATE_ACTOR: + case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT: { - GetImplementation( button ).SetSelectedImage( Scripting::NewActor( value.Get< Property::Map >() ) ); + Button::Align labelAlignment(END); + Scripting::GetEnumeration(value.Get().c_str(), + ALIGNMENT_TABLE, + ALIGNMENT_TABLE_COUNT, + labelAlignment); + + GetImplementation(button).SetLabelAlignment(labelAlignment); break; } - case Toolkit::Button::Property::DISABLED_STATE_ACTOR: + case Toolkit::DevelButton::Property::LABEL_PADDING: { - GetImplementation( button ).SetDisabledImage( Scripting::NewActor( value.Get< Property::Map >() ) ); + Vector4 padding(value.Get()); + GetImplementation(button).SetLabelPadding(Padding(padding.x, padding.y, padding.z, padding.w)); break; } - case Toolkit::Button::Property::LABEL_ACTOR: + case Toolkit::DevelButton::Property::VISUAL_PADDING: { - GetImplementation( button ).SetLabel( Scripting::NewActor( value.Get< Property::Map >() ) ); + Vector4 padding(value.Get()); + GetImplementation(button).SetForegroundPadding(Padding(padding.x, padding.y, padding.z, padding.w)); break; } } } } -Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex ) +Property::Value Button::GetProperty(BaseObject* object, Property::Index propertyIndex) { Property::Value value; - Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) ); + Toolkit::Button button = Toolkit::Button::DownCast(Dali::BaseHandle(object)); - if ( button ) + if(button) { - switch ( propertyIndex ) + switch(propertyIndex) { case Toolkit::Button::Property::DISABLED: { - value = GetImplementation( button ).mDisabled; + value = GetImplementation(button).IsDisabled(); break; } case Toolkit::Button::Property::AUTO_REPEATING: { - value = GetImplementation( button ).mAutoRepeating; + value = GetImplementation(button).mAutoRepeating; break; } case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY: { - value = GetImplementation( button ).mInitialAutoRepeatingDelay; + value = GetImplementation(button).mInitialAutoRepeatingDelay; break; } case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY: { - value = GetImplementation( button ).mNextAutoRepeatingDelay; + value = GetImplementation(button).mNextAutoRepeatingDelay; break; } case Toolkit::Button::Property::TOGGLABLE: { - value = GetImplementation( button ).mTogglableButton; + value = GetImplementation(button).mTogglableButton; break; } case Toolkit::Button::Property::SELECTED: { - value = GetImplementation( button ).mSelected; + value = GetImplementation(button).IsSelected(); break; } - case Toolkit::Button::Property::NORMAL_STATE_ACTOR: + case Toolkit::Button::Property::UNSELECTED_VISUAL: + case Toolkit::Button::Property::SELECTED_VISUAL: + case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL: + case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL: + case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL: + case Toolkit::Button::Property::LABEL: { - Property::Map map; - Scripting::CreatePropertyMap( GetImplementation( button ).mButtonContent, map ); - value = map; + Property::Map visualProperty; + if(GetImplementation(button).GetPropertyMapForVisual(propertyIndex, visualProperty)) + { + value = visualProperty; + } break; } - case Toolkit::Button::Property::SELECTED_STATE_ACTOR: + case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT: { - Property::Map map; - Scripting::CreatePropertyMap( GetImplementation( button ).mSelectedContent, map ); - value = map; + const char* alignment = Scripting::GetEnumerationName(GetImplementation(button).GetLabelAlignment(), + ALIGNMENT_STRING_TABLE, + ALIGNMENT_STRING_TABLE_COUNT); + if(alignment) + { + value = std::string(alignment); + } + break; } - case Toolkit::Button::Property::DISABLED_STATE_ACTOR: + case Toolkit::DevelButton::Property::LABEL_PADDING: { - Property::Map map; - Scripting::CreatePropertyMap( GetImplementation( button ).mDisabledContent, map ); - value = map; + Padding padding = GetImplementation(button).GetLabelPadding(); + value = Vector4(padding.x, padding.y, padding.top, padding.bottom); break; } - case Toolkit::Button::Property::LABEL_ACTOR: + case Toolkit::DevelButton::Property::VISUAL_PADDING: { - Property::Map map; - Scripting::CreatePropertyMap( GetImplementation( button ).mLabel, map ); - value = map; - break; + Padding padding = GetImplementation(button).GetForegroundPadding(); + value = Vector4(padding.x, padding.y, padding.top, padding.bottom); } } } @@ -1603,6 +1279,70 @@ Property::Value Button::GetProperty( BaseObject* object, Property::Index propert return value; } +void Button::SetLabelPadding(const Padding& padding) +{ + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top); + mLabelPadding = Padding(padding.left, padding.right, padding.bottom, padding.top); + RelayoutRequest(); +} + +Padding Button::GetLabelPadding() +{ + return mLabelPadding; +} + +void Button::SetForegroundPadding(const Padding& padding) +{ + DALI_LOG_INFO(gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top); + mForegroundPadding = Padding(padding.left, padding.right, padding.bottom, padding.top); + RelayoutRequest(); +} + +Padding Button::GetForegroundPadding() +{ + return mForegroundPadding; +} + +std::string Button::AccessibleImpl::GetNameRaw() +{ + std::string labelText; + auto slf = Toolkit::Button::DownCast(Self()); + Property::Map labelMap = slf.GetProperty(Toolkit::Button::Property::LABEL); + + Property::Value* textPropertyPtr = labelMap.Find(Toolkit::TextVisual::Property::TEXT); + if(textPropertyPtr) + { + textPropertyPtr->Get(labelText); + } + + return labelText; +} + +Property::Index Button::AccessibleImpl::GetNamePropertyIndex() +{ + Property::Index label = Toolkit::Button::Property::LABEL; + Property::Map labelMap = Self().GetProperty(label); + + if(MapContainsTextString(labelMap)) + { + return label; + } + else + { + return Property::INVALID_INDEX; + } +} + +Dali::Accessibility::States Button::AccessibleImpl::CalculateStates() +{ + auto tmp = DevelControl::AccessibleImpl::CalculateStates(); + tmp[Dali::Accessibility::State::SELECTABLE] = true; + auto slf = Toolkit::Button::DownCast(Self()); + tmp[Dali::Accessibility::State::ENABLED] = !slf.GetProperty(Toolkit::Button::Property::DISABLED); + tmp[Dali::Accessibility::State::CHECKED] = slf.GetProperty(Toolkit::Button::Property::SELECTED); + return tmp; +} + } // namespace Internal } // namespace Toolkit