diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 710e2f6a8..70c0893bb 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -207,9 +207,31 @@ Tooltip { #test_3 > .rooter:hover .outer:hover .inner { background: #DABA22; + layout_marginLeft: 16dp; } #test_3 > .rooter:hover .outer:hover .inner:hover { background: #CCC; } +#test_4 { + backgroundColor: #221122; +} + +#test_4 > RelativeLayout { + backgroundColor: #331133; + padding: 8dp; +} + +#test_4 > RelativeLayout:hover { + backgroundColor: #442244; +} + +#test_4 > RelativeLayout > TextView { + transition: all 0.125s; +/* layout_marginLeft: 0dp;*/ +} + +#test_4 > RelativeLayout:hover > TextView { + layout_marginLeft: 8dp; +} diff --git a/bin/assets/layouts/test.xml b/bin/assets/layouts/test.xml index 16425bff4..9fb6e2083 100644 --- a/bin/assets/layouts/test.xml +++ b/bin/assets/layouts/test.xml @@ -58,9 +58,15 @@ + + + + + + diff --git a/include/eepp/graphics/fonthelper.hpp b/include/eepp/graphics/fonthelper.hpp index c6a6a8f56..9b32d6741 100644 --- a/include/eepp/graphics/fonthelper.hpp +++ b/include/eepp/graphics/fonthelper.hpp @@ -1,6 +1,8 @@ #ifndef EE_GRAPHICSFONTHELPER_HPP #define EE_GRAPHICSFONTHELPER_HPP +#include + namespace EE { namespace Graphics { enum EE_FONT_TYPE { diff --git a/include/eepp/math/originpoint.hpp b/include/eepp/math/originpoint.hpp index d0953d782..289242fde 100644 --- a/include/eepp/math/originpoint.hpp +++ b/include/eepp/math/originpoint.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace EE { namespace Math { @@ -40,6 +41,8 @@ class tOriginPoint : public Vector2 { { } + std::string toString() const; + tOriginPoint& operator=(const Vector2& v); }; @@ -50,6 +53,13 @@ tOriginPoint& tOriginPoint::operator=(const Vector2& v) { return *this; } +template +std::string tOriginPoint::toString() const { + if ( OriginType == OriginCenter ) return "center"; + else if ( OriginType == OriginTopLeft ) return "topleft"; + return String::toStr(this->x) + "," + String::toStr(this->y); +} + typedef tOriginPoint OriginPoint; typedef tOriginPoint OriginPointi; diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 4c5c7124c..38bde727d 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -289,7 +289,7 @@ class EE_API Node : public Transformable { void disableReportSizeChangeToChilds(); - bool reportSizeChangeToChilds(); + bool reportSizeChangeToChilds() const; void centerHorizontal(); diff --git a/include/eepp/ui/css/stylesheetstyle.hpp b/include/eepp/ui/css/stylesheetstyle.hpp index 4520e3c73..6910a1298 100644 --- a/include/eepp/ui/css/stylesheetstyle.hpp +++ b/include/eepp/ui/css/stylesheetstyle.hpp @@ -21,6 +21,8 @@ class EE_API StyleSheetStyle { StyleSheetProperty getPropertyByName( const std::string& name ) const; void setProperty( const StyleSheetProperty& property ); + + void clearProperties(); protected: StyleSheetSelector mSelector; StyleSheetProperties mProperties; diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index d71624dfe..9def26262 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -109,6 +109,8 @@ class EE_API UINode : public Node { UINode * setForegroundRadius( const unsigned int& corners ); + Uint32 getForegroundRadius() const; + RectangleDrawable * setBorderEnabled( bool enabled ); UINode * setBorderColor( const Color& color ); @@ -117,6 +119,8 @@ class EE_API UINode : public Node { UINode * setBorderWidth( const unsigned int& width ); + Float getBorderWidth() const; + const Uint32& getFlags() const; virtual UINode * setFlags( const Uint32& flags ); diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index defd2de76..6ab3e9b97 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -200,6 +200,16 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { void reportStyleStateChange(); bool isSceneNodeLoading() const; + + std::string getLayoutWidthRulesString() const; + + std::string getLayoutHeightRulesString() const; + + std::string getLayoutGravityString() const; + + std::string getGravityString() const; + + std::string getFlagsString() const; }; }} diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index abac3fad6..f80571023 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1386,7 +1386,7 @@ void Node::sendParentSizeChange( const Vector2f& SizeChange ) { } } -bool Node::reportSizeChangeToChilds() { +bool Node::reportSizeChangeToChilds() const { return 0 != ( mNodeFlags & NODE_FLAG_REPORT_SIZE_CHANGE_TO_CHILDS ); } diff --git a/src/eepp/scene/nodeattribute.cpp b/src/eepp/scene/nodeattribute.cpp index 663985522..1640d9929 100644 --- a/src/eepp/scene/nodeattribute.cpp +++ b/src/eepp/scene/nodeattribute.cpp @@ -133,8 +133,8 @@ static OriginPoint toOriginPoint( std::string val ) { Float x = 0; Float y = 0; - bool Res1 = String::fromString( x, parts[0] ); - bool Res2 = String::fromString( y, parts[1] ); + bool Res1 = String::fromString( x, String::trim(parts[0]) ); + bool Res2 = String::fromString( y, String::trim(parts[1]) ); if ( Res1 && Res2 ) { return OriginPoint( x, y ); @@ -174,8 +174,8 @@ Vector2f NodeAttribute::asVector2f( const Vector2f & defaultValue ) const { if ( xySplit.size() == 2 ) { Float val; - vector.x = String::fromString( val, xySplit[0] ) ? val : defaultValue.x; - vector.y = String::fromString( val, xySplit[1] ) ? val : defaultValue.y; + vector.x = String::fromString( val, String::trim(xySplit[0]) ) ? val : defaultValue.x; + vector.y = String::fromString( val, String::trim(xySplit[1]) ) ? val : defaultValue.y; return vector; } else if ( xySplit.size() == 1 ) { @@ -198,8 +198,8 @@ Vector2i NodeAttribute::asVector2i( const Vector2i & defaultValue ) const { if ( xySplit.size() == 2 ) { int val; - vector.x = String::fromString( val, xySplit[0] ) ? val : defaultValue.x; - vector.y = String::fromString( val, xySplit[1] ) ? val : defaultValue.y; + vector.x = String::fromString( val, String::trim(xySplit[0]) ) ? val : defaultValue.x; + vector.y = String::fromString( val, String::trim(xySplit[1]) ) ? val : defaultValue.y; return vector; } else if ( xySplit.size() == 1 ) { diff --git a/src/eepp/ui/css/stylesheetstyle.cpp b/src/eepp/ui/css/stylesheetstyle.cpp index 3043bc85f..4a5d4a5c7 100644 --- a/src/eepp/ui/css/stylesheetstyle.cpp +++ b/src/eepp/ui/css/stylesheetstyle.cpp @@ -47,4 +47,8 @@ void StyleSheetStyle::setProperty( const StyleSheetProperty & property ) { mProperties[ property.getName() ] = property; } +void StyleSheetStyle::clearProperties() { + mProperties.clear(); +} + }}} diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 9e8d278bf..c54062c31 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -504,6 +504,20 @@ UINode * UINode::setForegroundRadius( const unsigned int& corners ) { return this; } +Uint32 UINode::getForegroundRadius() const { + if ( NULL != mForegroundState && NULL != mForegroundState->getSkin() ) { + Drawable * stateDrawable = mForegroundState->getSkin()->getStateDrawable( UIState::StateFlagNormal ); + + if ( stateDrawable->getDrawableType() == Drawable::RECTANGLE ) { + RectangleDrawable * rectangleDrawable = static_cast( stateDrawable ); + + return rectangleDrawable->getCorners(); + } + } + + return 0; +} + RectangleDrawable * UINode::setBorderEnabled( bool enabled ) { writeFlag( UI_BORDER, enabled ? 1 : 0 ); @@ -534,6 +548,10 @@ UINode * UINode::setBorderWidth( const unsigned int& width ) { return this; } +Float UINode::getBorderWidth() const { + return NULL != mBorder ? mBorder->getLineWidth() : 1.f; +} + const Uint32& UINode::getFlags() const { return mFlags; } diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index d9ebf7067..278a53af2 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -657,10 +657,10 @@ bool UIWidget::setAttribute( const std::string& name, const std::string& value, #define SAVE_NORMAL_STATE_ATTR( ATTR_FORMATED ) \ if ( state != UIState::StateFlagNormal ) { \ - CSS::StyleSheetProperty oldAttribute = mStyle->getStatelessStyleSheetProperty( attribute.getName() ); \ - if ( oldAttribute.isEmpty() && mStyle->getPreviousState() == UIState::StateFlagNormal ) \ - mStyle->addStyleSheetProperty( CSS::StyleSheetProperty( attribute.getName(), ATTR_FORMATED ) ); \ - } \ + CSS::StyleSheetProperty oldAttribute = mStyle->getStatelessStyleSheetProperty( attribute.getName() ); \ + if ( oldAttribute.isEmpty() && mStyle->getPreviousState() == UIState::StateFlagNormal ) \ + mStyle->addStyleSheetProperty( CSS::StyleSheetProperty( attribute.getName(), ATTR_FORMATED ) ); \ + } bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state ) { const std::string& name = attribute.getName(); @@ -779,6 +779,7 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state } } else if ( "backgroundimage" == name ) { NodeAttribute::FunctionType functionType = NodeAttribute::FunctionType::parse( attribute.getValue() ); + Drawable * res = NULL; if ( !functionType.isEmpty() ) { if ( functionType.getName() == "linear-gradient" && functionType.getParameters().size() >= 2 ) { @@ -818,6 +819,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setBackgroundDrawable( drawable, true ); } + } else if ( NULL != ( res = DrawableSearcher::searchByName( attribute.getValue() ) ) ) { + setBackgroundDrawable( res, res->getDrawableType() == Drawable::SPRITE ); } } else if ( "foreground" == name ) { Drawable * res = NULL; @@ -846,6 +849,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setForegroundColor( color ); } } else if ( "foregroundradius" == name ) { + SAVE_NORMAL_STATE_ATTR( String::toStr( getForegroundRadius() ) ); + setForegroundRadius( attribute.asUint() ); } else if ( "bordercolor" == name ) { SAVE_NORMAL_STATE_ATTR( getBorderColor().toHexString() ) @@ -866,6 +871,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setBorderColor( color ); } } else if ( "borderwidth" == name ) { + SAVE_NORMAL_STATE_ATTR( String::toStr( getBorderWidth() ) ); + setBorderWidth( attribute.asDpDimensionI("1") ); } else if ( "borderradius" == name ) { SAVE_NORMAL_STATE_ATTR( String::format( "%d", getBorderRadius() ) ); @@ -886,15 +893,23 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setBorderRadius( attribute.asUint() ); } } else if ( "visible" == name ) { + SAVE_NORMAL_STATE_ATTR( isVisible() ? "true" : "false" ); + setVisible( attribute.asBool() ); } else if ( "enabled" == name ) { + SAVE_NORMAL_STATE_ATTR( isEnabled() ? "true" : "false" ); + setEnabled( attribute.asBool() ); } else if ( "theme" == name ) { + if ( NULL != mTheme ) + SAVE_NORMAL_STATE_ATTR( mTheme->getName() ); + setThemeByName( attribute.asString() ); if ( !mSkinName.empty() ) setThemeSkin( mSkinName ); } else if ( "skin" == name ) { + SAVE_NORMAL_STATE_ATTR( mSkinName ); mSkinName = attribute.asString(); setThemeSkin( mSkinName ); } else if ( "skincolor" == name ) { @@ -946,6 +961,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state notifyLayoutAttrChange(); } } else if ( "flags" == name ) { + SAVE_NORMAL_STATE_ATTR( getFlagsString() ); + std::string flags = attribute.asString(); String::toLowerInPlace( flags ); std::vector strings = String::split( flags, '|' ); @@ -971,6 +988,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state } } } else if ( String::startsWith( name, "layout_margin" ) ) { + SAVE_NORMAL_STATE_ATTR( String::format( "%d %d %d %d", mLayoutMargin.Left, mLayoutMargin.Top, mLayoutMargin.Right, mLayoutMargin.Bottom ) ); + Rect margin; Uint32 marginFlag = 0; @@ -1020,8 +1039,12 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state } else if ( "tooltip" == name ) { setTooltipText( attribute.asString() ); } else if ( "layout_weight" == name ) { + SAVE_NORMAL_STATE_ATTR( String::toStr( getLayoutWeight() ) ); + setLayoutWeight( attribute.asFloat() ); } else if ( "layout_gravity" == name ) { + SAVE_NORMAL_STATE_ATTR( getLayoutGravityString() ); + std::string gravityStr = attribute.asString(); String::toLowerInPlace( gravityStr ); std::vector strings = String::split( gravityStr, '|' ); @@ -1052,6 +1075,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setLayoutGravity( gravity ); } } else if ( "layout_width" == name ) { + SAVE_NORMAL_STATE_ATTR( getLayoutWidthRulesString() ); + std::string val = attribute.asString(); String::toLowerInPlace( val ); @@ -1069,6 +1094,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state onSizeChange(); } } else if ( "layout_height" == name ) { + SAVE_NORMAL_STATE_ATTR( getLayoutHeightRulesString() ); + std::string val = attribute.asString(); String::toLowerInPlace( val ); @@ -1086,6 +1113,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state onSizeChange(); } } else if ( String::startsWith( name, "layout_to_" ) || String::startsWith( name, "layoutto" ) ) { + // @TODO: SAVE_NORMAL_STATE_ATTR + LayoutPositionRules rule = NONE; if ( "layout_to_left_of" == name || "layouttoleftof" == name ) rule = LEFT_OF; else if ( "layout_to_right_of" == name || "layouttorightof" == name ) rule = RIGHT_OF; @@ -1102,6 +1131,8 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setLayoutPositionRule( rule, widget ); } } else if ( "clip" == name ) { + SAVE_NORMAL_STATE_ATTR( isClipped() ? "true" : "false" ); + if ( attribute.asBool() ) clipEnable(); else @@ -1137,18 +1168,23 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state setScale( attribute.asVector2f() ); } } else if ( "rotationoriginpoint" == name ) { + SAVE_NORMAL_STATE_ATTR( getRotationOriginPoint().toString() ); + setRotationOriginPoint( attribute.asOriginPoint() ); } else if ( "scaleoriginpoint" == name ) { + SAVE_NORMAL_STATE_ATTR( getScaleOriginPoint().toString() ); + setScaleOriginPoint( attribute.asOriginPoint() ); } else if ( "blendmode" == name ) { + // @TODO: SAVE_NORMAL_STATE_ATTR setBlendMode( attribute.asBlendMode() ); } else if ( String::startsWith( name, "padding" ) ) { + SAVE_NORMAL_STATE_ATTR( String::format( "%2.f %2.f %2.f %2.f", mPadding.Left, mPadding.Top, mPadding.Right, mPadding.Bottom ) ); + Rectf padding; Uint32 paddingFlag = 0; if ( "padding" == name ) { - SAVE_NORMAL_STATE_ATTR( String::format( "%2.f %2.f %2.f %2.f", mPadding.Left, mPadding.Top, mPadding.Right, mPadding.Bottom ) ) - padding = ( attribute.asRectf() ); paddingFlag = Actions::PaddingTransition::All; } else if ( "paddingleft" == name ) { @@ -1210,6 +1246,7 @@ bool UIWidget::setAttribute( const NodeAttribute& attribute, const Uint32& state } } else if ( "cursor" == name ) { SAVE_NORMAL_STATE_ATTR( "arrow" ); + mSceneNode->setCursor( Cursor::fromName( attribute.getValue() ) ); } else { attributeSet = false; @@ -1228,4 +1265,62 @@ void UIWidget::loadFromXmlNode( const pugi::xml_node& node ) { endAttributesTransaction(); } +std::string UIWidget::getLayoutWidthRulesString() const { + LayoutSizeRules rules = getLayoutWidthRules(); + + if ( rules == LayoutSizeRules::MATCH_PARENT ) return "match_parent"; + else if ( rules == LayoutSizeRules::WRAP_CONTENT ) return "wrap_content"; + return String::toStr( getSize().getHeight() ) + "dp"; +} + +std::string UIWidget::getLayoutHeightRulesString() const { + LayoutSizeRules rules = getLayoutHeightRules(); + + if ( rules == LayoutSizeRules::MATCH_PARENT ) return "match_parent"; + else if ( rules == LayoutSizeRules::WRAP_CONTENT ) return "wrap_content"; + return String::toStr( getSize().getHeight() ) + "dp"; +} + +static std::string getGravityStringFromUint( const Uint32& gravity ) { + std::vector gravec; + + if ( HAlignGet( gravity ) == UI_HALIGN_RIGHT ) { + gravec.push_back( "right" ); + } else if ( HAlignGet( gravity ) == UI_HALIGN_CENTER ) { + gravec.push_back( "center_horizontal" ); + } else { + gravec.push_back( "left" ); + } + + if ( VAlignGet( gravity ) == UI_VALIGN_BOTTOM ) { + gravec.push_back( "bottom" ); + } else if ( VAlignGet( gravity ) == UI_VALIGN_CENTER ) { + gravec.push_back( "center_vertical" ); + } else { + gravec.push_back( "top" ); + } + + return String::join( gravec, '|' ); +} + +std::string UIWidget::getLayoutGravityString() const { + return getGravityStringFromUint( getLayoutGravity() ); +} + +std::string UIWidget::getGravityString() const { + return getGravityStringFromUint( getHorizontalAlign() | getVerticalAlign() ); +} + +std::string UIWidget::getFlagsString() const { + std::vector flagvec; + + if ( mFlags & UI_AUTO_SIZE ) flagvec.push_back( "autosize" ); + if ( mFlags & UI_MULTI_SELECT ) flagvec.push_back( "multi" ); + if ( mFlags & UI_AUTO_PADDING ) flagvec.push_back( "autopadding" ); + if ( reportSizeChangeToChilds() ) flagvec.push_back( "reportsizechangetochilds" ); + if ( isClipped() ) flagvec.push_back( "clip" ); + + return String::join( flagvec, '|' ); +} + }}