diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 36873954c..561d9837b 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -81,7 +81,8 @@ Tooltip { #tpad2 { layout_marginLeft: 0; padding: 24dp; - opacity: 0.5; + opacity: 0.8; + backgroundColor: #333; transition: all 0.25s; } @@ -89,4 +90,5 @@ Tooltip { layout_marginLeft: 8dp; padding: 28dp; opacity: 1; + backgroundColor: #656; } diff --git a/include/eepp/scene/actions/actions.hpp b/include/eepp/scene/actions/actions.hpp index b6e616c4e..feaa6dd0e 100644 --- a/include/eepp/scene/actions/actions.hpp +++ b/include/eepp/scene/actions/actions.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #endif diff --git a/include/eepp/scene/actions/colorinterpolation.hpp b/include/eepp/scene/actions/colorinterpolation.hpp new file mode 100644 index 000000000..7f1ab0315 --- /dev/null +++ b/include/eepp/scene/actions/colorinterpolation.hpp @@ -0,0 +1,71 @@ +#ifndef EE_SCENE_ACTIONS_COLORINTERPOLATION_HPP +#define EE_SCENE_ACTIONS_COLORINTERPOLATION_HPP + +#include + +#include +#include +#include +using namespace EE::Math; + +namespace EE { namespace Scene { namespace Actions { + +class EE_API ColorInterpolation : public Action { + public: + enum ColorInterpolationType { + Background, + Foreground, + Skin, + Border, + Text + }; + + static ColorInterpolation * New( const Color& start, const Color& end, const bool& interpolateAlpha, const Time& duration, const Ease::Interpolation& type = Ease::Linear, const ColorInterpolationType& colorInterpolationType = Background ); + + void start() override; + + void stop() override; + + void update( const Time& time ) override; + + bool isDone() override; + + virtual Action * clone() const override; + + Action * reverse() const override; + + Interpolation1d getInterpolationR() const; + + void setInterpolationR(const Interpolation1d & interpolationR); + + Interpolation1d getInterpolationG() const; + + void setInterpolationG(const Interpolation1d & interpolationG); + + Interpolation1d getInterpolationB() const; + + void setInterpolationB(const Interpolation1d & interpolationB); + + Interpolation1d getInterpolationA() const; + + void setInterpolationA(const Interpolation1d & interpolationA); + protected: + ColorInterpolation( const Color& start, const Color& end, const bool& interpolateAlpha, const Time & duration, const Ease::Interpolation & type, const ColorInterpolationType& colorInterpolationType ); + + void onStart() override; + + virtual void onUpdate( const Time& time ) override; + + ColorInterpolation(); + + Interpolation1d mInterpolationR; + Interpolation1d mInterpolationG; + Interpolation1d mInterpolationB; + Interpolation1d mInterpolationA; + ColorInterpolationType mColorInterpolationType; + bool mInterpolateAlpha; +}; + +}}} + +#endif diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index ec39ba1a2..0dfacf3ac 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -99,6 +99,10 @@ class EE_API UINode : public Node { UINode * setBackgroundColor( const Color& color ); + Color getBackgroundColor( const Uint32 & state ); + + Color getBackgroundColor(); + UINode * setBackgroundCorners( const Uint32 & state, const unsigned int& corners ); UINode * setBackgroundCorners( const unsigned int& corners ); @@ -113,6 +117,10 @@ class EE_API UINode : public Node { UINode * setForegroundColor( const Color& color ); + Color getForegroundColor( const Uint32 & state ); + + Color getForegroundColor(); + UINode * setForegroundCorners( const Uint32 & state, const unsigned int& corners ); UINode * setForegroundCorners( const unsigned int& corners ); @@ -123,6 +131,10 @@ class EE_API UINode : public Node { UINode * setBorderColor( const Color& color ); + Color getBorderColor( const Uint32 & state ); + + Color getBorderColor(); + UINode * setBorderWidth( const Uint32 & state, const unsigned int& width ); UINode * setBorderWidth( const unsigned int& width ); diff --git a/include/eepp/ui/uistate.hpp b/include/eepp/ui/uistate.hpp index b040c4287..74d059218 100644 --- a/include/eepp/ui/uistate.hpp +++ b/include/eepp/ui/uistate.hpp @@ -57,10 +57,13 @@ class EE_API UIState { virtual bool stateExists( const Uint32& State ) const = 0; - Uint32 getCurrentState() const; + const Uint32& getCurrentState() const; + + const Uint32& getPreviousState() const; protected: Uint32 mState; Uint32 mCurrentState; + Uint32 mPreviousState; virtual void updateState() = 0; diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 79de60486..b4257a10b 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -133,6 +133,10 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { void beginAttributesTransaction(); void endAttributesTransaction(); + + const Uint32& getStyleState() const; + + const Uint32& getStylePreviousState() const; protected: friend class UIManager; friend class UISceneNode; diff --git a/projects/linux/ee.files b/projects/linux/ee.files index a3d937d78..5f1992a6d 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -210,6 +210,7 @@ ../../include/eepp/scene/actions/actioninterpolation2d.hpp ../../include/eepp/scene/actions/actions.hpp ../../include/eepp/scene/actions/close.hpp +../../include/eepp/scene/actions/colorinterpolation.hpp ../../include/eepp/scene/actions/delay.hpp ../../include/eepp/scene/actions/disable.hpp ../../include/eepp/scene/actions/enable.hpp @@ -632,6 +633,7 @@ ../../src/eepp/scene/actions/actioninterpolation1d.cpp ../../src/eepp/scene/actions/actioninterpolation2d.cpp ../../src/eepp/scene/actions/close.cpp +../../src/eepp/scene/actions/colorinterpolation.cpp ../../src/eepp/scene/actions/delay.cpp ../../src/eepp/scene/actions/disable.cpp ../../src/eepp/scene/actions/enable.cpp diff --git a/src/eepp/scene/actions/colorinterpolation.cpp b/src/eepp/scene/actions/colorinterpolation.cpp new file mode 100644 index 000000000..a6cda17a3 --- /dev/null +++ b/src/eepp/scene/actions/colorinterpolation.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +using namespace EE::UI; + +namespace EE { namespace Scene { namespace Actions { + +ColorInterpolation * ColorInterpolation::New( const Color& start, const Color& end, const bool& interpolateAlpha, const Time& duration, const Ease::Interpolation& type, const ColorInterpolationType& colorInterpolationType ) { + return eeNew( ColorInterpolation, ( start, end, interpolateAlpha, duration, type, colorInterpolationType ) ); +} + +ColorInterpolation::ColorInterpolation() +{} + +Interpolation1d ColorInterpolation::getInterpolationA() const { + return mInterpolationA; +} + +void ColorInterpolation::setInterpolationA(const Interpolation1d & interpolationA) { + mInterpolationA = interpolationA; +} + +Interpolation1d ColorInterpolation::getInterpolationB() const { + return mInterpolationB; +} + +void ColorInterpolation::setInterpolationB(const Interpolation1d& interpolationB) { + mInterpolationB = interpolationB; +} + +Interpolation1d ColorInterpolation::getInterpolationG() const { + return mInterpolationG; +} + +void ColorInterpolation::setInterpolationG(const Interpolation1d & interpolationG) { + mInterpolationG = interpolationG; +} + +Interpolation1d ColorInterpolation::getInterpolationR() const { + return mInterpolationR; +} + +void ColorInterpolation::setInterpolationR(const Interpolation1d & interpolationR) { + mInterpolationR = interpolationR; +} + +ColorInterpolation::ColorInterpolation( const Color& start, const Color & end, const bool& interpolateAlpha, const Time& duration, const Ease::Interpolation& type, const ColorInterpolationType& colorInterpolationType ) : + mColorInterpolationType( colorInterpolationType ), + mInterpolateAlpha( interpolateAlpha ) +{ + mInterpolationR.clear().add( start.r, duration ).add( end.r ).setType( type ); + mInterpolationG.clear().add( start.g, duration ).add( end.g ).setType( type ); + mInterpolationB.clear().add( start.b, duration ).add( end.b ).setType( type ); + + if ( interpolateAlpha ) + mInterpolationA.clear().add( start.a, duration ).add( end.a ).setType( type ); +} + +void ColorInterpolation::start() { + mInterpolationR.start(); + mInterpolationG.start(); + mInterpolationB.start(); + + if ( mInterpolateAlpha ) + mInterpolationA.start(); + + onStart(); + + sendEvent( ActionType::OnStart ); +} + +void ColorInterpolation::stop() { + mInterpolationR.stop(); + mInterpolationG.stop(); + mInterpolationB.stop(); + + if ( mInterpolateAlpha ) + mInterpolationA.stop(); + + onStop(); + + sendEvent( ActionType::OnStop ); +} + +void ColorInterpolation::update( const Time& time ) { + mInterpolationR.update( time ); + mInterpolationG.update( time ); + mInterpolationB.update( time ); + mInterpolationA.update( time ); + + onUpdate( time ); +} + +bool ColorInterpolation::isDone() { + return mInterpolationR.ended() && + mInterpolationG.ended() && + mInterpolationB.ended() && ( + !mInterpolateAlpha || + mInterpolationA.ended() ); +} + + +void ColorInterpolation::onStart() { + if ( NULL != mNode && mNode->isWidget() ) { + onUpdate( Time::Zero ); + } +} + +Action * ColorInterpolation::clone() const { + ColorInterpolation * action = eeNew( ColorInterpolation, () ); + action->setInterpolationR( mInterpolationR ); + action->setInterpolationG( mInterpolationG ); + action->setInterpolationB( mInterpolationB ); + action->setInterpolationA( mInterpolationA ); + return action; +} + +Action * ColorInterpolation::reverse() const { + return NULL; +} + +void ColorInterpolation::onUpdate( const Time& ) { + if ( NULL != mNode && mNode->isWidget() ) { + UIWidget * widget = static_cast( mNode ); + + switch ( mColorInterpolationType ) { + case Background: + { + widget->setBackgroundColor( widget->getStyleState(), + Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 + ) ); + + break; + } + case Foreground: + { + widget->setForegroundColor( widget->getStyleState(), + Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 + ) ); + + break; + } + case Skin: + { + /* + widget->setSkinColor( widget->getStyleState(), + Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 + ) ); + */ + break; + } + case Border: + { + widget->setBorderColor( widget->getStyleState(), + Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 + ) ); + + break; + } + case Text: + { + if ( widget->isType( UI_TYPE_TEXTVIEW ) ) { + UITextView * textView = static_cast( widget ); + + textView->setFontColor( Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 ) ); + } + + break; + } + } + } +} + +}}} diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index cb56193b4..4a4b6614d 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -31,7 +31,7 @@ UINode * UINode::New() { UINode::UINode() : Node(), mFlags( UI_CONTROL_DEFAULT_FLAGS ), - mState(0), + mState(UIState::StateFlagNormal), mSkinState( NULL ), mBackgroundState( NULL ), mForegroundState( NULL ), @@ -424,6 +424,24 @@ UINode * UINode::setBackgroundColor( const Uint32 & state, const Color& color ) return this; } +Color UINode::getBackgroundColor() { + return getBackgroundColor( mState ); +} + +Color UINode::getBackgroundColor( const Uint32 & state ) { + UISkin * background = setBackgroundFillEnabled( true ); + + Drawable * stateDrawable = background->getStateDrawable( state ); + + if ( NULL == stateDrawable ) { + RectangleDrawable * colorDrawable = RectangleDrawable::New(); + + return colorDrawable->getColor(); + } else { + return stateDrawable->getColor(); + } +} + UINode * UINode::setBackgroundColor( const Color& color ) { return setBackgroundColor( UIState::StateFlagNormal, color ); } @@ -473,6 +491,24 @@ UINode * UINode::setForegroundDrawable( Drawable * drawable, bool ownIt ) { return setForegroundDrawable( UIState::StateFlagNormal, drawable, ownIt ); } +Color UINode::getForegroundColor() { + return getForegroundColor( mState ); +} + +Color UINode::getForegroundColor( const Uint32 & state ) { + UISkin * foreground = setForegroundFillEnabled( true ); + + Drawable * stateDrawable = foreground->getStateDrawable( state ); + + if ( NULL == stateDrawable ) { + RectangleDrawable * colorDrawable = RectangleDrawable::New(); + + return colorDrawable->getColor(); + } else { + return stateDrawable->getColor(); + } +} + UINode * UINode::setForegroundColor( const Uint32 & state, const Color& color ) { UISkin * foreground = setForegroundFillEnabled( true ); @@ -557,6 +593,25 @@ UINode * UINode::setBorderColor( const Color& color ) { return setBorderColor( UIState::StateFlagNormal, color ); } +Color UINode::getBorderColor() { + return getBorderColor( mState ); +} + +Color UINode::getBorderColor( const Uint32 & state ) { + UISkin * border = setBorderEnabled( true ); + + Drawable * stateDrawable = border->getStateDrawable( state ); + + if ( NULL == stateDrawable ) { + RectangleDrawable * borderDrawable = RectangleDrawable::New(); + borderDrawable->setFillMode( PrimitiveFillMode::DRAW_LINE ); + + return borderDrawable->getColor(); + } else { + return stateDrawable->getColor(); + } +} + UINode * UINode::setBorderWidth( const Uint32& state, const unsigned int& width ) { UISkin * border = setBorderEnabled( true ); diff --git a/src/eepp/ui/uiskinstate.cpp b/src/eepp/ui/uiskinstate.cpp index fdf072909..93dda6ce2 100644 --- a/src/eepp/ui/uiskinstate.cpp +++ b/src/eepp/ui/uiskinstate.cpp @@ -37,6 +37,7 @@ void UISkinState::updateState() { for ( int i = StateFlagCount - 1; i >= 0; i-- ) { if ( ( mState & getStateFlag(i) ) == getStateFlag(i) ) { if ( stateExists( getStateFlag(i) ) ) { + mPreviousState = mCurrentState; mCurrentState = getStateFlag(i); onStateChange(); return; diff --git a/src/eepp/ui/uistate.cpp b/src/eepp/ui/uistate.cpp index 38c03ed42..ba4fd9737 100644 --- a/src/eepp/ui/uistate.cpp +++ b/src/eepp/ui/uistate.cpp @@ -67,7 +67,8 @@ bool UIState::isStateName( const std::string& State ) { UIState::UIState() : mState(StateFlagNormal), - mCurrentState(StateFlagNormal) + mCurrentState(StateFlagNormal), + mPreviousState(StateFlagNormal) { } @@ -102,10 +103,14 @@ void UIState::popState(const Uint32 & State) { } } -Uint32 UIState::getCurrentState() const { +const Uint32& UIState::getCurrentState() const { return mCurrentState; } +const Uint32 &UIState::getPreviousState() const { + return mPreviousState; +} + void UIState::onStateChange() { } diff --git a/src/eepp/ui/uistyle.cpp b/src/eepp/ui/uistyle.cpp index 0101edbf4..f6e6c7f0a 100644 --- a/src/eepp/ui/uistyle.cpp +++ b/src/eepp/ui/uistyle.cpp @@ -240,6 +240,7 @@ void UIStyle::updateState() { if ( ( mState & getStateFlag(i) ) == getStateFlag(i) ) { if ( stateExists( getStateFlag(i) ) ) { if ( mCurrentState != getStateFlag(i) ) { + mPreviousState = mCurrentState; mCurrentState = getStateFlag(i); onStateChange(); } diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index c8d4f76c7..556f26343 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -570,6 +570,14 @@ void UIWidget::endAttributesTransaction() { } } +const Uint32& UIWidget::getStyleState() const { + return NULL != mStyle ? mStyle->getCurrentState() : mState; +} + +const Uint32& UIWidget::getStylePreviousState() const { + return NULL != mStyle ? mStyle->getPreviousState() : mState; +} + bool UIWidget::setAttribute( const std::string& name, const std::string& value, const Uint32& state ) { return setAttribute( NodeAttribute( name, value ), state ); } @@ -604,7 +612,21 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setBackgroundDrawable( state, res, res->getDrawableType() == Drawable::SPRITE ); } } else if ( "backgroundcolor" == name ) { - setBackgroundColor( state, attribute.asColor() ); + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + Color start( getBackgroundColor( getStylePreviousState() ) ); + + Action * action = Actions::ColorInterpolation::New( start, color, false, transitionInfo.duration, transitionInfo.timingFunction, Actions::ColorInterpolation::Background ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setBackgroundColor( state, color ); + } } else if ( "foreground" == name ) { Drawable * res = NULL; @@ -616,11 +638,39 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setForegroundDrawable( state, res, res->getDrawableType() == Drawable::SPRITE ); } } else if ( "foregroundcolor" == name ) { - setForegroundColor( state, attribute.asColor() ); + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + Color start( getForegroundColor( getStylePreviousState() ) ); + + Action * action = Actions::ColorInterpolation::New( start, color, false, transitionInfo.duration, transitionInfo.timingFunction, Actions::ColorInterpolation::Foreground ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setForegroundColor( state, color ); + } } else if ( "foregroundcorners" == name ) { setForegroundCorners( state, attribute.asUint() ); } else if ( "bordercolor" == name ) { - setBorderColor( state, attribute.asColor() ); + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + Color start( getBorderColor( getStylePreviousState() ) ); + + Action * action = Actions::ColorInterpolation::New( start, color, false, transitionInfo.duration, transitionInfo.timingFunction, Actions::ColorInterpolation::Border ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setBorderColor( state, color ); + } } else if ( "borderwidth" == name ) { setBorderWidth( state, attribute.asDpDimensionI("1") ); } else if ( "bordercorners" == name || "backgroundcorners" == name ) {