diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 35e544b69..5ca62475d 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -113,6 +113,8 @@ Tooltip { borderRadius: 3; padding: 12dp; transition: all 0.25; + textStyle: shadow; + textColor: white; } #tpad3:hover { @@ -120,12 +122,14 @@ Tooltip { borderColor: #1d1f1fd7; borderRadius: 3; cursor: hand; + textShadowColor: black; + padding: 18dp 12dp 100dp 12dp; } #tpad3:pressed { backgroundImage: linear-gradient( #4e4f4d, #414141 ); borderColor: #222320d7; - cursor: hand; + padding: 22dp 12dp 120dp 12dp; } #tres { diff --git a/include/eepp/graphics/text.hpp b/include/eepp/graphics/text.hpp index dcc7bfb84..85fd5e02e 100644 --- a/include/eepp/graphics/text.hpp +++ b/include/eepp/graphics/text.hpp @@ -19,6 +19,10 @@ class EE_API Text { Shadow = 1 << 4 ///< Draw a shadow below the text }; + static std::string styleFlagToString( const Uint32& flags ); + + static Uint32 stringToStyleFlag( const std::string& str ); + static Text * New(); static Text * New(const String& string, Font * font, unsigned int characterSize = 30); diff --git a/include/eepp/scene/actions/tint.hpp b/include/eepp/scene/actions/tint.hpp index 7d3ddc4d6..2855c30a1 100644 --- a/include/eepp/scene/actions/tint.hpp +++ b/include/eepp/scene/actions/tint.hpp @@ -17,7 +17,9 @@ class EE_API Tint : public Action { Foreground, Skin, Border, - Text + Text, + TextShadow, + TextOutline }; static Tint * New( const Color& start, const Color& end, const bool& interpolateAlpha, const Time& duration, const Ease::Interpolation& type = Ease::Linear, const TintType& colorInterpolationType = Background ); diff --git a/include/eepp/ui/uitextview.hpp b/include/eepp/ui/uitextview.hpp index 6785a4887..505b855fb 100644 --- a/include/eepp/ui/uitextview.hpp +++ b/include/eepp/ui/uitextview.hpp @@ -25,8 +25,6 @@ class EE_API UITextView : public UIWidget { virtual void draw(); - virtual void setAlpha( const Float& alpha ); - Graphics::Font * getFont() const; UITextView * setFont( Graphics::Font * font ); @@ -120,6 +118,8 @@ class EE_API UITextView : public UIWidget { virtual void onFontChanged(); + virtual void onAlphaChange(); + virtual Uint32 onFocusLoss(); virtual Uint32 onMouseDoubleClick( const Vector2i& position, const Uint32 flags ); diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index db5d9fd6b..ed351e233 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -10,6 +10,62 @@ namespace EE { namespace Graphics { +std::string Text::styleFlagToString( const Uint32& flags ) { + std::string str; + + if ( flags & Bold ) + str += "bold"; + + if ( flags & Italic ) { + str += ( str.empty() ? "" : "|" ); + str += "italic"; + } + + if ( flags & Underlined ) { + str += ( str.empty() ? "" : "|" ); + str += "underline"; + } + + if ( flags & StrikeThrough ) { + str += ( str.empty() ? "" : "|" ); + str += "strikethrough"; + } + + if ( flags & Shadow ) { + str += ( str.empty() ? "" : "|" ); + str += "shadow"; + } + + return str; +} + +Uint32 Text::stringToStyleFlag( const std::string& str ) { + std::string valStr = str; + String::toLowerInPlace( valStr ); + std::vector strings = String::split( valStr, '|' ); + Uint32 flags = Text::Regular; + + if ( strings.size() ) { + for ( std::size_t i = 0; i < strings.size(); i++ ) { + std::string cur = strings[i]; + String::toLowerInPlace( cur ); + + if ( "underlined" == cur || "underline" == cur ) + flags |= Text::Underlined; + else if ( "bold" == cur ) + flags |= Text::Bold; + else if ( "italic" == cur ) + flags |= Text::Italic; + else if ( "strikethrough" == cur ) + flags |= Text::StrikeThrough; + else if ( "shadowed" == cur || "shadow" == cur ) + flags |= Text::Shadow; + } + } + + return flags; +} + Text * Text::New() { return eeNew( Text, () ); } diff --git a/src/eepp/scene/actions/tint.cpp b/src/eepp/scene/actions/tint.cpp index e747f4ac2..263d19caa 100644 --- a/src/eepp/scene/actions/tint.cpp +++ b/src/eepp/scene/actions/tint.cpp @@ -179,6 +179,32 @@ void Tint::onUpdate( const Time& ) { mInterpolateAlpha ? mInterpolationA.getPosition() : 255 ) ); } + break; + } + case TextShadow: + { + if ( widget->isType( UI_TYPE_TEXTVIEW ) ) { + UITextView * textView = static_cast( widget ); + + textView->setFontShadowColor( Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 ) ); + } + + break; + } + case TextOutline: + { + if ( widget->isType( UI_TYPE_TEXTVIEW ) ) { + UITextView * textView = static_cast( widget ); + + textView->setOutlineColor( Color( mInterpolationR.getPosition(), + mInterpolationG.getPosition(), + mInterpolationB.getPosition(), + mInterpolateAlpha ? mInterpolationA.getPosition() : 255 ) ); + } + break; } } diff --git a/src/eepp/scene/nodeattribute.cpp b/src/eepp/scene/nodeattribute.cpp index d4b9e0fe3..4672c61d6 100644 --- a/src/eepp/scene/nodeattribute.cpp +++ b/src/eepp/scene/nodeattribute.cpp @@ -277,32 +277,7 @@ Rectf NodeAttribute::asRectf( const Rectf& defaultValue ) const { } Uint32 NodeAttribute::asFontStyle() const { - std::string valStr = asString(); - String::toLowerInPlace( valStr ); - std::vector strings = String::split( valStr, '|' ); - Uint32 flags = Text::Regular; - - if ( strings.size() ) { - for ( std::size_t i = 0; i < strings.size(); i++ ) { - std::string cur = strings[i]; - String::toLowerInPlace( cur ); - - if ( "underlined" == cur || "underline" == cur ) - flags |= Text::Underlined; - else if ( "bold" == cur ) - flags |= Text::Bold; - else if ( "italic" == cur ) - flags |= Text::Italic; - else if ( "strikethrough" == cur ) - flags |= Text::StrikeThrough; - else if ( "shadowed" == cur || "shadow" == cur ) - flags |= Text::Shadow; - else if ( "wordwrap" == cur ) - flags |= UI::UI_WORD_WRAP; - } - } - - return flags; + return Text::stringToStyleFlag( getValue() ); } Time NodeAttribute::asTime( const Time & defaultTime ) { diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index c0ae24757..0bfe08745 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -1,11 +1,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include namespace EE { namespace UI { @@ -147,8 +149,9 @@ const Color &UITextView::getOutlineColor() const { UITextView * UITextView::setOutlineColor(const Color & outlineColor) { if ( mFontStyleConfig.OutlineColor != outlineColor ) { - mTextCache->setOutlineColor( outlineColor ); mFontStyleConfig.OutlineColor = outlineColor; + Color newColor( outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a * mAlpha / 255.f ); + mTextCache->setOutlineColor( newColor ); invalidateDraw(); } @@ -200,9 +203,9 @@ const Color& UITextView::getFontColor() const { } UITextView * UITextView::setFontColor( const Color& color ) { - Color newColor( color.r, color.g, color.b, mAlpha ); - if ( mFontStyleConfig.FontColor != newColor ) { - mFontStyleConfig.FontColor = newColor; + if ( mFontStyleConfig.FontColor != color ) { + mFontStyleConfig.FontColor = color; + Color newColor( color.r, color.g, color.b, color.a * mAlpha / 255.f ); mTextCache->setFillColor( newColor ); } @@ -216,7 +219,8 @@ const Color& UITextView::getFontShadowColor() const { UITextView * UITextView::setFontShadowColor( const Color& color ) { if ( mFontStyleConfig.ShadowColor != color ) { mFontStyleConfig.ShadowColor = color; - mTextCache->setShadowColor( mFontStyleConfig.ShadowColor ); + Color newColor( color.r, color.g, color.b, color.a * mAlpha / 255.f ); + mTextCache->setShadowColor( newColor ); invalidateDraw(); } @@ -236,16 +240,6 @@ UITextView * UITextView::setSelectionBackColor( const Color& color ) { return this; } -void UITextView::setAlpha( const Float& alpha ) { - if ( mAlpha != alpha ) { - UINode::setAlpha( alpha ); - mFontStyleConfig.FontColor.a = (Uint8)alpha; - mFontStyleConfig.ShadowColor.a = (Uint8)alpha; - - mTextCache->setAlpha( mFontStyleConfig.FontColor.a ); - } -} - void UITextView::autoShrink() { if ( mFlags & UI_WORD_WRAP ) { shrinkText( mSize.getWidth() ); @@ -328,6 +322,20 @@ void UITextView::onFontChanged() { invalidateDraw(); } +void UITextView::onAlphaChange() { + Color color( getFontColor() ); + Color newColor( color.r, color.g, color.b, color.a * mAlpha / 255.f ); + mTextCache->setFillColor( newColor ); + + color = getFontShadowColor(); + newColor = Color( color.r, color.g, color.b, color.a * mAlpha / 255.f ); + mTextCache->setShadowColor( newColor ); + + color = getOutlineColor(); + newColor = Color( color.r, color.g, color.b, color.a * mAlpha / 255.f ); + mTextCache->setOutlineColor( newColor ); +} + void UITextView::setTheme( UITheme * Theme ) { UIWidget::setTheme( Theme ); @@ -543,6 +551,11 @@ void UITextView::resetSelCache() { onSelectionChange(); } +#define SAVE_NORMAL_STATE_ATTR( ATTR_FORMATED ) \ + NodeAttribute oldAttribute = mStyle->getAttribute( UIState::StateFlagNormal, attribute.getName() ); \ + if ( oldAttribute.isEmpty() && mStyle->getPreviousState() == UIState::StateFlagNormal ) \ + mStyle->addAttribute( UIState::StateFlagNormal, NodeAttribute( attribute.getName(), ATTR_FORMATED ) ); \ + bool UITextView::setAttribute( const NodeAttribute& attribute, const Uint32& state ) { const std::string& name = attribute.getName(); @@ -550,20 +563,56 @@ bool UITextView::setAttribute( const NodeAttribute& attribute, const Uint32& sta if ( NULL != mSceneNode && mSceneNode->isUISceneNode() ) setText( static_cast( mSceneNode )->getTranslatorString( attribute.asString() ) ); } else if ( "textcolor" == name ) { - setFontColor( attribute.asColor() ); + SAVE_NORMAL_STATE_ATTR( getFontColor().toHexString() ); + + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + + Action * action = Actions::Tint::New( getFontColor(), color, true, transitionInfo.duration, transitionInfo.timingFunction, Actions::Tint::Text ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setFontColor( color ); + } } else if ( "textshadowcolor" == name ) { - setFontShadowColor( attribute.asColor() ); + SAVE_NORMAL_STATE_ATTR( getFontShadowColor().toHexString() ); + + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + + Action * action = Actions::Tint::New( getFontShadowColor(), color, true, transitionInfo.duration, transitionInfo.timingFunction, Actions::Tint::TextShadow ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setFontShadowColor( color ); + } } else if ( "textselectedcolor" == name ) { mFontStyleConfig.FontSelectedColor = attribute.asColor(); } else if ( "textselectionbackcolor" == name ) { setSelectionBackColor( attribute.asColor() ); } else if ( "fontfamily" == name || "fontname" == name ) { + SAVE_NORMAL_STATE_ATTR( getFont()->getName() ); + setFont( FontManager::instance()->getByName( attribute.asString() ) ); } else if ( "textsize" == name || "fontsize" == name || "charactersize" == name ) { + SAVE_NORMAL_STATE_ATTR( String::format( "%dpx", getCharacterSize() ) ); + setCharacterSize( attribute.asDpDimensionI() ); } else if ( "textstyle" == name || "fontstyle" == name ) { Uint32 flags = attribute.asFontStyle(); + SAVE_NORMAL_STATE_ATTR( Text::styleFlagToString( getFontStyle() ) ); + if ( flags & UI_WORD_WRAP ) { mFlags |= UI_WORD_WRAP; flags &= ~ UI_WORD_WRAP; @@ -573,9 +622,26 @@ bool UITextView::setAttribute( const NodeAttribute& attribute, const Uint32& sta setFontStyle( flags ); } else if ( "fontoutlinethickness" == name ) { - setOutlineThickness( attribute.asDpDimension() ); + SAVE_NORMAL_STATE_ATTR( String::toStr( PixelDensity::dpToPx( getOutlineThickness() ) ) ) + + setOutlineThickness( PixelDensity::dpToPx( attribute.asDpDimension() ) ); } else if ( "fontoutlinecolor" == name ) { - setOutlineColor( attribute.asColor() ); + SAVE_NORMAL_STATE_ATTR( getOutlineColor().toHexString() ); + + Color color = attribute.asColor(); + + if ( !isSceneNodeLoading() && NULL != mStyle && mStyle->hasTransition( state, attribute.getName() ) ) { + UIStyle::TransitionInfo transitionInfo( mStyle->getTransition( state, attribute.getName() ) ); + + Action * action = Actions::Tint::New( getOutlineColor(), color, true, transitionInfo.duration, transitionInfo.timingFunction, Actions::Tint::TextOutline ); + + if ( Time::Zero != transitionInfo.delay ) + action = Actions::Sequence::New( Actions::Delay::New( transitionInfo.delay ), action ); + + runAction( action ); + } else { + setOutlineColor( color ); + } } else if ( "textselection" == name ) { mFlags|= UI_TEXT_SELECTION_ENABLED; } else {