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, '|' );
+}
+
}}