diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 664b8525f..e29e80cfd 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -66,3 +66,12 @@ Tooltip { padding: 8dp; textColor: black; } + +#tpad { + scale: 1; +} + +#tpad:hover { + scale: 1.1; + transition: scale 0.25s; +} diff --git a/include/eepp/math/ease.hpp b/include/eepp/math/ease.hpp index 1347f5e2c..18825fd25 100644 --- a/include/eepp/math/ease.hpp +++ b/include/eepp/math/ease.hpp @@ -1,6 +1,8 @@ #ifndef EE_MATH_EASE #define EE_MATH_EASE +#include + namespace EE { namespace Math { /** @brief Container class of the Interpolation types. */ @@ -40,6 +42,41 @@ class Ease { ElasticOut, ElasticInOut }; + + static Interpolation fromName( const std::string& name, const Interpolation& defaultInterpolation = Ease::Linear ) { + if ( "linear" == name ) return Ease::Linear; + if ( "quadraticin" == name || "quadratic-in" == name ) return Ease::QuadraticIn; + if ( "quadraticout" == name || "quadratic-out" == name ) return Ease::QuadraticOut; + if ( "quadraticinout" == name || "quadratic-in-out" == name ) return Ease::QuadraticInOut; + if ( "sinein" == name || "sine-in" == name ) return Ease::SineIn; + if ( "sineout" == name || "sine-out" == name ) return Ease::SineOut; + if ( "sineinout" == name || "sine-in-out" == name ) return Ease::SineInOut; + if ( "exponentialin" == name || "exponential-in" == name ) return Ease::ExponentialIn; + if ( "exponentialout" == name || "exponential-out" == name ) return Ease::ExponentialOut; + if ( "exponentialinout" == name || "exponential-in-out" == name ) return Ease::ExponentialInOut; + if ( "quarticin" == name || "quartic-in" == name ) return Ease::QuarticIn; + if ( "quarticout" == name || "quartic-out" == name ) return Ease::QuarticOut; + if ( "quarticinout" == name || "quartic-in-out" == name ) return Ease::QuarticInOut; + if ( "quinticin" == name || "quintic-in" == name ) return Ease::QuinticIn; + if ( "quinticout" == name || "quintic-out" == name ) return Ease::QuinticOut; + if ( "quinticinout" == name || "quintic-in-out" == name ) return Ease::QuinticInOut; + if ( "circularin" == name || "circular-in" == name ) return Ease::CircularIn; + if ( "circularout" == name || "circular-out" == name ) return Ease::CircularOut; + if ( "circularinout" == name || "circular-in-out" == name ) return Ease::CircularInOut; + if ( "cubicin" == name || "cubic-in" == name ) return Ease::CubicIn; + if ( "cubicout" == name || "cubic-out" == name ) return Ease::CubicOut; + if ( "cubicinout" == name || "cubic-in-out" == name ) return Ease::CubicInOut; + if ( "backin" == name || "back-in" == name ) return Ease::BackIn; + if ( "backout" == name || "back-out" == name ) return Ease::BackOut; + if ( "backinout" == name || "back-in-out" == name ) return Ease::BackInOut; + if ( "bouncein" == name || "bounce-in" == name ) return Ease::BounceIn; + if ( "bounceout" == name || "bounce-out" == name ) return Ease::BounceOut; + if ( "bounceinout" == name || "bounce-in-out" == name ) return Ease::BounceInOut; + if ( "elasticin" == name || "elastic-in" == name ) return Ease::ElasticIn; + if ( "elasticout" == name || "elastic-out" == name ) return Ease::ElasticOut; + if ( "elasticinout" == name || "elastic-in-out" == name ) return Ease::ElasticInOut; + return defaultInterpolation; + } }; }} diff --git a/include/eepp/scene/nodeattribute.hpp b/include/eepp/scene/nodeattribute.hpp index 920b66256..a6169fe53 100644 --- a/include/eepp/scene/nodeattribute.hpp +++ b/include/eepp/scene/nodeattribute.hpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include using namespace EE::System; @@ -116,6 +118,10 @@ class NodeAttribute { Rectf asRectf( const Rectf& defaultValue = Rectf() ) const; Uint32 asFontStyle() const; + + Time asTime( const Time& defaultTime = Seconds(0) ); + + Ease::Interpolation asInterpolation( const Ease::Interpolation& defaultInterpolation = Ease::Linear ); protected: std::string mName; std::string mValue; diff --git a/include/eepp/ui/uistyle.hpp b/include/eepp/ui/uistyle.hpp index de21bf336..ac6b6186f 100644 --- a/include/eepp/ui/uistyle.hpp +++ b/include/eepp/ui/uistyle.hpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace EE::Scene; @@ -18,6 +19,27 @@ class UIWidget; class EE_API UIStyle : public UIState { public: + class TransitionInfo + { + public: + TransitionInfo() : + timingFunction( Ease::Linear ) + {} + + const std::string& getProperty() const { return property; } + + Ease::Interpolation getTimingFunction() const { return timingFunction; } + + const Time& getDelay() const { return delay; }; + + const Time& getDuration() const { return duration; } + + std::string property; + Ease::Interpolation timingFunction; + Time delay; + Time duration; + }; + static UIStyle * New( UIWidget * widget ); explicit UIStyle( UIWidget * widget ); @@ -50,16 +72,25 @@ class EE_API UIStyle : public UIState { NodeAttribute getAttribute( const Uint32& state, std::vector attributeNames ) const; - void addStyleSheetProperties( int state, const CSS::StyleSheetProperties& properties ); + void addStyleSheetProperties( const Uint32& state, const CSS::StyleSheetProperties& properties ); - void addStyleSheetProperty( int state, const CSS::StyleSheetProperty& property ); + void addStyleSheetProperty( const Uint32& state, const CSS::StyleSheetProperty& property ); + + bool hasTransition( const Uint32& state, const std::string& propertyName ); + + TransitionInfo getTransition( const Uint32& state, const std::string& propertyName ); protected: typedef std::map AttributesMap; + typedef std::map TransitionsMap; UIWidget * mWidget; - std::map mStates; + std::map mStates; + std::map mTransitions; + std::map> mTransitionAttributes; void updateState(); + + void parseTransitions( const Uint32& state ); }; }} diff --git a/src/eepp/scene/nodeattribute.cpp b/src/eepp/scene/nodeattribute.cpp index 99c65c3a4..fb4bbdab5 100644 --- a/src/eepp/scene/nodeattribute.cpp +++ b/src/eepp/scene/nodeattribute.cpp @@ -305,4 +305,20 @@ Uint32 NodeAttribute::asFontStyle() const { return flags; } +Time NodeAttribute::asTime( const Time & defaultTime ) { + if ( !mValue.empty() ) { + if ( mValue[ mValue.size() -1 ] == 'm' ) { + return Milliseconds( asFloat() ); + } else { + return Seconds( asFloat() ); + } + } + + return defaultTime; +} + +Ease::Interpolation NodeAttribute::asInterpolation( const Ease::Interpolation& defaultInterpolation ) { + return Ease::fromName( mValue, defaultInterpolation ); +} + }} diff --git a/src/eepp/ui/uistyle.cpp b/src/eepp/ui/uistyle.cpp index 76461180f..da6fdef0a 100644 --- a/src/eepp/ui/uistyle.cpp +++ b/src/eepp/ui/uistyle.cpp @@ -26,6 +26,12 @@ bool UIStyle::stateExists( const EE::Uint32 & state ) const { void UIStyle::addAttribute( int state, NodeAttribute attribute ) { mStates[ state ][ attribute.getName() ] = attribute; + + if ( String::startsWith( attribute.getName(), "transition" ) ) { + mTransitionAttributes[ state ].push_back( attribute ); + + parseTransitions( state ); + } } void UIStyle::load() { @@ -53,7 +59,7 @@ void UIStyle::load() { } } -void UIStyle::addStyleSheetProperties( int state, const CSS::StyleSheetProperties& properties ) { +void UIStyle::addStyleSheetProperties(const Uint32 & state, const CSS::StyleSheetProperties& properties ) { if ( !properties.empty() ) { for ( auto it = properties.begin(); it != properties.end(); ++it ) { CSS::StyleSheetProperty property = it->second; @@ -63,10 +69,39 @@ void UIStyle::addStyleSheetProperties( int state, const CSS::StyleSheetPropertie } } -void UIStyle::addStyleSheetProperty( int state, const CSS::StyleSheetProperty& property ) { +void UIStyle::addStyleSheetProperty( const Uint32& state, const CSS::StyleSheetProperty& property ) { addAttribute( state, NodeAttribute( property.getName(), property.getValue() ) ); } +bool UIStyle::hasTransition( const Uint32& state, const std::string& propertyName ) { + bool ret = mTransitions.find( state ) != mTransitions.end() && mTransitions[ state ].find( propertyName ) != mTransitions[ state ].end(); + + // When transitions are declared without state are global + if ( state != StateFlagNormal ) { + ret = mTransitions.find( StateFlagNormal ) != mTransitions.end() && mTransitions[ StateFlagNormal ].find( propertyName ) != mTransitions[ state ].end(); + } + + return ret; +} + +UIStyle::TransitionInfo UIStyle::getTransition( const Uint32& state, const std::string& propertyName ) { + if ( mTransitions.find( state ) != mTransitions.end() ) { + auto propertyTransitionIt = mTransitions[ state ].find( propertyName ); + + if ( propertyTransitionIt != mTransitions[ state ].end() ) { + return propertyTransitionIt->second; + } else if ( mTransitions.find( StateFlagNormal ) != mTransitions.end() ) { + propertyTransitionIt = mTransitions[ StateFlagNormal ].find( propertyName ); + + if ( propertyTransitionIt != mTransitions[ state ].end() ) { + return propertyTransitionIt->second; + } + } + } + + return TransitionInfo(); +} + void UIStyle::onStateChange() { if ( NULL != mWidget && stateExists( mCurrentState ) ) { AttributesMap& attrs = mStates[ mCurrentState ]; @@ -188,4 +223,119 @@ void UIStyle::updateState() { } } +void UIStyle::parseTransitions( const Uint32& state ) { + std::vector properties; + std::vector