From 3921f81cedb1c0f88c57d8ef083f90f6d8d50521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 13 Mar 2020 05:10:53 -0300 Subject: [PATCH] Added border-radius support. Added alias support for shorthands. Added BorderType::Outline. Added support for background/foreground masks. Fixes to the border rendering. Several fixes and clean up. --- bin/assets/layouts/test2.css | 15 +- include/eepp/ui/border.hpp | 26 ++- include/eepp/ui/css/propertydefinition.hpp | 34 ++-- include/eepp/ui/css/shorthanddefinition.hpp | 21 ++- .../ui/css/stylesheetpropertiesparser.hpp | 2 +- include/eepp/ui/uibackgrounddrawable.hpp | 26 ++- include/eepp/ui/uiborderdrawable.hpp | 30 +++- include/eepp/ui/uinode.hpp | 35 +++- include/eepp/ui/uinodedrawable.hpp | 2 + include/eepp/ui/uiwidget.hpp | 22 --- projects/linux/ee.creator.user | 4 +- src/eepp/ui/border.cpp | 66 +++++-- src/eepp/ui/css/propertyspecification.cpp | 2 +- src/eepp/ui/css/shorthanddefinition.cpp | 73 +++++++- .../ui/css/stylesheetpropertiesparser.cpp | 5 +- .../ui/css/stylesheetpropertyanimation.cpp | 14 ++ src/eepp/ui/css/stylesheetspecification.cpp | 45 +++-- src/eepp/ui/uibackgrounddrawable.cpp | 74 +++++++- src/eepp/ui/uiborderdrawable.cpp | 147 ++++++++++++++- src/eepp/ui/uinode.cpp | 108 ++++++++++- src/eepp/ui/uinodedrawable.cpp | 20 +++ src/eepp/ui/uiwidget.cpp | 167 ++++++++---------- 22 files changed, 740 insertions(+), 198 deletions(-) diff --git a/bin/assets/layouts/test2.css b/bin/assets/layouts/test2.css index c55b96d12..8bcbb0b79 100644 --- a/bin/assets/layouts/test2.css +++ b/bin/assets/layouts/test2.css @@ -11,14 +11,21 @@ Widget { width: 200px; height: 200px; background-color: white; - border-radius: 100dp; + border-top-left-radius: 50px 100px; + border-top-right-radius: 100px 50px; + border-bottom-left-radius: 100px 50%; + border-bottom-right-radius: 100% 50%; border-color: rgba(255, 0, 0, 0.5); - border-width: 0dp; - border-type: inside; + border-width: 20dp; + border-type: outline; transition: all 0.5s; + clip: true; } Widget:hover { - border-radius: 20dp; + border-top-left-radius: 5px 10px; + border-top-right-radius: 10px 5px; + border-bottom-left-radius: 100px 100%; + border-bottom-right-radius: 100% 30%; border-width: 10dp; } diff --git a/include/eepp/ui/border.hpp b/include/eepp/ui/border.hpp index 7e74b9fc8..002c032f8 100644 --- a/include/eepp/ui/border.hpp +++ b/include/eepp/ui/border.hpp @@ -13,8 +13,9 @@ using namespace EE::System; using namespace EE::Math; namespace EE { namespace UI { +class UINode; -enum class BorderType : Uint32 { Inside, Outside }; +enum class BorderType : Uint32 { Inside, Outside, Outline }; struct EE_API Border { int width = 0; @@ -35,6 +36,12 @@ struct EE_API Borders { Border bottom; BorderRadiuses radius; + static std::string fromBorderType( const BorderType& borderType ); + + static BorderType toBorderType( const std::string& borderType ); + + static Sizef radiusFromString( UINode* node, const std::string& val ); + /** Creates the border geometry into the VertexBuffer provided. The VertexBuffer must be a * a EE::Graphics::PrimitiveType::PRIMITIVE_TRIANGLE_STRIP with VERTEX_FLAGS_PRIMITIVE flags. */ static void createBorders( VertexBuffer* vbo, const Borders& borders, const Vector2f& pos, @@ -46,6 +53,23 @@ struct EE_API Borders { const Vector2f& pos, const Sizef& size, const Color& color ); }; +struct BorderRadiuseStr { + std::string topLeft; + std::string topRight; + std::string bottomLeft; + std::string bottomRight; +}; + +struct BorderStr { + struct { + std::string left; + std::string right; + std::string top; + std::string bottom; + } width; + BorderRadiuseStr radius; +}; + }} // namespace EE::UI #endif // EE_BORDER_HPP diff --git a/include/eepp/ui/css/propertydefinition.hpp b/include/eepp/ui/css/propertydefinition.hpp index 0785423f2..5ada9cd85 100644 --- a/include/eepp/ui/css/propertydefinition.hpp +++ b/include/eepp/ui/css/propertydefinition.hpp @@ -6,18 +6,6 @@ namespace EE { namespace UI { namespace CSS { -/* Shorthands: - * - * background - * foreground - * margin - * layout_margin - * padding - * background-position - * rotation-origin-point - * scale-origin-point - * */ - enum class PropertyId : Uint32 { Id = String::hash( "id" ), Class = String::hash( "class" ), @@ -38,9 +26,6 @@ enum class PropertyId : Uint32 { ForegroundRepeat = String::hash( "foreground-repeat" ), ForegroundSize = String::hash( "foreground-size" ), ForegroundRadius = String::hash( "foreground-radius" ), - BorderColor = String::hash( "border-color" ), - BorderWidth = String::hash( "border-width" ), - BorderRadius = String::hash( "border-radius" ), Visible = String::hash( "visible" ), Enabled = String::hash( "enabled" ), Theme = String::hash( "theme" ), @@ -207,7 +192,19 @@ enum class PropertyId : Uint32 { PageTransitionDuration = String::hash( "page-transition-duration" ), TimingFunction = String::hash( "timing-function" ), PageLocked = String::hash( "page-locked" ), - BorderType = String::hash( "border-type" ) + BorderType = String::hash( "border-type" ), + BorderLeftColor = String::hash( "border-left-color" ), + BorderRightColor = String::hash( "border-right-color" ), + BorderTopColor = String::hash( "border-top-color" ), + BorderBottomColor = String::hash( "border-bottom-color" ), + BorderLeftWidth = String::hash( "border-left-width" ), + BorderRightWidth = String::hash( "border-right-width" ), + BorderTopWidth = String::hash( "border-top-width" ), + BorderBottomWidth = String::hash( "border-bottom-width" ), + BorderTopLeftRadius = String::hash( "border-top-left-radius" ), + BorderTopRightRadius = String::hash( "border-top-right-radius" ), + BorderBottomLeftRadius = String::hash( "border-bottom-left-radius" ), + BorderBottomRightRadius = String::hash( "border-bottom-right-radius" ), }; enum class PropertyType : Uint32 { @@ -217,6 +214,7 @@ enum class PropertyType : Uint32 { NumberInt, NumberFloat, NumberLength, + RadiusLength, Color, Vector2, BackgroundSize, @@ -236,7 +234,9 @@ enum class PropertyRelativeTarget : Uint32 { BackgroundWidth, BackgroundHeight, ForegroundWidth, - ForegroundHeight + ForegroundHeight, + LocalBlockRadiusWidth, + LocalBlockRadiusHeight }; class EE_API PropertyDefinition { diff --git a/include/eepp/ui/css/shorthanddefinition.hpp b/include/eepp/ui/css/shorthanddefinition.hpp index 237038357..68567e5d9 100644 --- a/include/eepp/ui/css/shorthanddefinition.hpp +++ b/include/eepp/ui/css/shorthanddefinition.hpp @@ -19,7 +19,10 @@ enum class ShorthandId : Uint32 { LayoutMarginUnderscore = String::hash( "layout_margin" ), FillerPadding = String::hash( "filler-padding" ), RotationOriginPoint = String::hash( "rotation-origin-point" ), - ScaleOriginPoint = String::hash( "scale-origin-point" ) + ScaleOriginPoint = String::hash( "scale-origin-point" ), + BorderColor = String::hash( "border-color" ), + BorderWidth = String::hash( "border-width" ), + BorderRadius = String::hash( "border-radius" ) }; enum class ShorthandType : Uint32 { @@ -27,7 +30,9 @@ enum class ShorthandType : Uint32 { Background, Vector2, SingleValueVector, - BackgroundPosition + BackgroundPosition, + BorderBox, + Radius }; class ShorthandDefinition { @@ -46,6 +51,16 @@ class ShorthandDefinition { const Uint32& getId() const; + ShorthandDefinition& addAlias( const std::string& alias ); + + bool isAlias( const std::string& alias ) const; + + bool isAlias( const Uint32& id ) const; + + bool isDefinition( const std::string& name ) const; + + bool isDefinition( const Uint32& id ) const; + ShorthandId getShorthandId() const; const std::vector& getProperties() const; @@ -55,6 +70,8 @@ class ShorthandDefinition { protected: std::string mName; Uint32 mId; + std::vector mAliases; + std::vector mAliasesHash; std::vector mProperties; ShorthandType mType; }; diff --git a/include/eepp/ui/css/stylesheetpropertiesparser.hpp b/include/eepp/ui/css/stylesheetpropertiesparser.hpp index 9736d7f9c..650328516 100644 --- a/include/eepp/ui/css/stylesheetpropertiesparser.hpp +++ b/include/eepp/ui/css/stylesheetpropertiesparser.hpp @@ -39,7 +39,7 @@ class EE_API StyleSheetPropertiesParser { int readComment( ReadState& rs, std::size_t pos, std::string& buffer, const std::string& str ); - void addProperty( const std::string& name, std::string value ); + void addProperty( std::string name, std::string value ); }; }}} // namespace EE::UI::CSS diff --git a/include/eepp/ui/uibackgrounddrawable.hpp b/include/eepp/ui/uibackgrounddrawable.hpp index 762a4570d..9890c1997 100644 --- a/include/eepp/ui/uibackgrounddrawable.hpp +++ b/include/eepp/ui/uibackgrounddrawable.hpp @@ -8,11 +8,13 @@ using namespace EE::Graphics; namespace EE { namespace UI { +class UINode; + class EE_API UIBackgroundDrawable : public Drawable { public: - static UIBackgroundDrawable* New(); + static UIBackgroundDrawable* New( UINode* owner ); - UIBackgroundDrawable(); + UIBackgroundDrawable( UINode* owner ); virtual ~UIBackgroundDrawable(); @@ -30,13 +32,31 @@ class EE_API UIBackgroundDrawable : public Drawable { const BorderRadiuses& getRadiuses() const; + bool hasRadius() const; + void setRadiuses( const BorderRadiuses& radiuses ); void setRadius( const Uint32& radius ); Int32 getRadius() const; + void invalidate(); + + void setTopWidth( const std::string& topWidth ); + + void setBottomWidth( const std::string& bottomWidth ); + + void setTopLeftRadius( const std::string& radius ); + + void setTopRightRadius( const std::string& radius ); + + void setBottomLeftRadius( const std::string& radius ); + + void setBottomRightRadius( const std::string& radius ); + protected: + UINode* mOwner; + BorderRadiuseStr mRadiusesStr; VertexBuffer* mVertexBuffer; Sizef mSize; BorderRadiuses mRadiuses; @@ -50,6 +70,8 @@ class EE_API UIBackgroundDrawable : public Drawable { virtual void onPositionChange(); void update(); + + void updateRadiuses(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uiborderdrawable.hpp b/include/eepp/ui/uiborderdrawable.hpp index 23eba1192..847198651 100644 --- a/include/eepp/ui/uiborderdrawable.hpp +++ b/include/eepp/ui/uiborderdrawable.hpp @@ -6,11 +6,13 @@ namespace EE { namespace UI { +class UINode; + class EE_API UIBorderDrawable : public Drawable { public: - static UIBorderDrawable* New(); + static UIBorderDrawable* New( UINode* owner ); - UIBorderDrawable(); + UIBorderDrawable( UINode* owner ); virtual ~UIBorderDrawable(); @@ -54,9 +56,31 @@ class EE_API UIBorderDrawable : public Drawable { void setBorderType( const BorderType& borderType ); + void invalidate(); + + void setLeftWidth( const std::string& leftWidth ); + + void setRightWidth( const std::string& rightWidth ); + + void setTopWidth( const std::string& topWidth ); + + void setBottomWidth( const std::string& bottomWidth ); + + void setTopLeftRadius( const std::string& radius ); + + void setTopRightRadius( const std::string& radius ); + + void setBottomLeftRadius( const std::string& radius ); + + void setBottomRightRadius( const std::string& radius ); + + const Borders& getBorders() const; + protected: + UINode* mOwner; VertexBuffer* mVertexBuffer; Borders mBorders; + BorderStr mBorderStr; BorderType mBorderType; Sizef mSize; bool mNeedsUpdate; @@ -69,6 +93,8 @@ class EE_API UIBorderDrawable : public Drawable { virtual void onPositionChange(); void update(); + + void updateBorders(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index ac38cf10b..baa62e516 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include #include #include @@ -108,6 +110,14 @@ class EE_API UINode : public Node { UINode* setBorderRadius( const unsigned int& corners ); + UINode* setTopLeftRadius( const std::string& radius ); + + UINode* setTopRightRadius( const std::string& radius ); + + UINode* setBottomLeftRadius( const std::string& radius ); + + UINode* setBottomRightRadius( const std::string& radius ); + Uint32 getBorderRadius() const; UINodeDrawable* setForegroundFillEnabled( bool enabled ); @@ -208,11 +218,34 @@ class EE_API UINode : public Node { virtual void setFocus(); + Float + getPropertyRelativeTargetContainerLength( const CSS::PropertyRelativeTarget& relativeTarget, + const Float& defaultValue = 0, + const Uint32& propertyIndex = 0 ); + virtual Float convertLength( const CSS::StyleSheetLength& length, const Float& containerLength ); Float convertLengthAsDp( const CSS::StyleSheetLength& length, const Float& containerLength ); + Float lengthFromValue( const std::string& value, + const CSS::PropertyRelativeTarget& relativeTarget, + const Float& defaultValue = 0, const Float& defaultContainerValue = 0, + const Uint32& propertyIndex = 0 ); + + Float lengthFromValue( const CSS::StyleSheetProperty& property, const Float& defaultValue = 0, + const Float& defaultContainerValue = 0 ); + + Float lengthFromValueAsDp( const std::string& value, + const CSS::PropertyRelativeTarget& relativeTarget, + const Float& defaultValue = 0, + const Float& defaultContainerValue = 0, + const Uint32& propertyIndex = 0 ); + + Float lengthFromValueAsDp( const CSS::StyleSheetProperty& property, + const Float& defaultValue = 0, + const Float& defaultContainerValue = 0 ); + UISceneNode* getUISceneNode(); protected: @@ -250,7 +283,7 @@ class EE_API UINode : public Node { virtual void onThemeLoaded(); - virtual void onChildCountChange( Node * child, const bool& removed ); + virtual void onChildCountChange( Node* child, const bool& removed ); virtual Uint32 onCalculateDrag( const Vector2f& position, const Uint32& flags ); diff --git a/include/eepp/ui/uinodedrawable.hpp b/include/eepp/ui/uinodedrawable.hpp index 6d5e9d6b4..95e3ab033 100644 --- a/include/eepp/ui/uinodedrawable.hpp +++ b/include/eepp/ui/uinodedrawable.hpp @@ -159,6 +159,8 @@ class EE_API UINodeDrawable : public Drawable { UINode* getOwner() { return mOwner; } + UIBackgroundDrawable& getBackgroundDrawable(); + protected: UINode* mOwner; UIBackgroundDrawable mBackgroundColor; diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index b9c516c22..33aeecde4 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -205,28 +205,6 @@ class EE_API UIWidget : public UINode { bool isSceneNodeLoading() const; - Float - getPropertyRelativeTargetContainerLength( const CSS::PropertyRelativeTarget& relativeTarget, - const Float& defaultValue = 0, - const Uint32& propertyIndex = 0 ); - - Float lengthFromValue( const std::string& value, - const CSS::PropertyRelativeTarget& relativeTarget, - const Float& defaultValue = 0, const Float& defaultContainerValue = 0, - const Uint32& propertyIndex = 0 ); - - Float lengthFromValue( const StyleSheetProperty& property, const Float& defaultValue = 0, - const Float& defaultContainerValue = 0 ); - - Float lengthFromValueAsDp( const std::string& value, - const CSS::PropertyRelativeTarget& relativeTarget, - const Float& defaultValue = 0, - const Float& defaultContainerValue = 0, - const Uint32& propertyIndex = 0 ); - - Float lengthFromValueAsDp( const StyleSheetProperty& property, const Float& defaultValue = 0, - const Float& defaultContainerValue = 0 ); - const std::string& getMinWidthEq() const; void setMinWidthEq( const std::string& minWidthEq ); diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index d8aa276a8..e5836acc9 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -1531,7 +1531,7 @@ eepp-UIEditor-debug ProjectExplorer.CustomExecutableRunConfiguration - -x assets/layouts/test2.xml -c assets/layouts/test2.css -u + -x assets/layouts/test.xml -c assets/layouts/test.css -u false true diff --git a/src/eepp/ui/border.cpp b/src/eepp/ui/border.cpp index d493f91de..cd90c5801 100644 --- a/src/eepp/ui/border.cpp +++ b/src/eepp/ui/border.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace EE { namespace UI { @@ -90,6 +91,36 @@ static void borderAddArc( VertexBuffer* vbo, Vector2f pos, Float radiW, Float ra } } +std::string Borders::fromBorderType( const BorderType& borderType ) { + switch ( borderType ) { + case BorderType::Outside: + return "outside"; + case BorderType::Outline: + return "outline"; + case BorderType::Inside: + default: + return "inside"; + } +} + +BorderType Borders::toBorderType( const std::string& borderType ) { + if ( borderType == "outside" ) { + return BorderType::Outside; + } else if ( borderType == "outline" ) { + return BorderType::Outline; + } + return BorderType::Inside; +} + +Sizef Borders::radiusFromString( UINode* node, const std::string& val ) { + auto split = String::split( val, ' ' ); + Sizef size; + size.x = node->lengthFromValue( split[0], CSS::PropertyRelativeTarget::LocalBlockRadiusWidth ); + size.y = node->lengthFromValue( split[split.size() > 1 ? 1 : 0], + CSS::PropertyRelativeTarget::LocalBlockRadiusHeight ); + return size; +} + void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Vector2f& pos, const Sizef& size ) { vbo->clear(); @@ -132,10 +163,10 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve endAngle, borders.top.color, borderTop, Vector2f( pos.x + borderLeft, pos.y + borderTop ) ); } else { - vbo->addVertex( Vector2f( pos.x, pos.y ) ); - vbo->addColor( borders.top.color ); vbo->addVertex( Vector2f( pos.x + borderLeft, pos.y + borderTop ) ); vbo->addColor( borders.top.color ); + vbo->addVertex( Vector2f( pos.x, pos.y ) ); + vbo->addColor( borders.top.color ); } if ( rightW ) { @@ -160,10 +191,10 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve borderAddArc( vbo, tPos, rightW, rightH, startAngle, endAngle, borders.top.color, borderTop, basePos ); } else { - vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y ) ); - vbo->addColor( borders.top.color ); vbo->addVertex( Vector2f( pos.x + size.getWidth() - borderRight, pos.y + borderTop ) ); vbo->addColor( borders.top.color ); + vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y ) ); + vbo->addColor( borders.top.color ); } } @@ -182,10 +213,10 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve borderAddArc( vbo, Vector2f( pos.x + size.getWidth() - topW, pos.y + topH ), topW, topH, startAngle, endAngle, borders.right.color, borderRight, basePos ); } else { - vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y ) ); - vbo->addColor( borders.right.color ); vbo->addVertex( Vector2f( pos.x + size.getWidth() - borderRight, pos.y + borderTop ) ); vbo->addColor( borders.right.color ); + vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y ) ); + vbo->addColor( borders.right.color ); } if ( bottomH ) { @@ -212,11 +243,11 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve borderRight, basePos ); } else { - vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y + size.getHeight() ) ); - vbo->addColor( borders.right.color ); vbo->addVertex( Vector2f( pos.x + size.getWidth() - borderRight, pos.y + size.getHeight() - borderBottom ) ); vbo->addColor( borders.right.color ); + vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y + size.getHeight() ) ); + vbo->addColor( borders.right.color ); } } @@ -238,12 +269,11 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve Vector2f( pos.x + size.getWidth() - rightW, pos.y + size.getHeight() - rightH ), rightW, rightH, startAngle, endAngle, borders.bottom.color, borderBottom, basePos ); } else { - vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y + size.getHeight() ) ); - vbo->addColor( borders.bottom.color ); - vbo->addVertex( Vector2f( pos.x + size.getWidth() - borderRight, pos.y + size.getHeight() - borderBottom ) ); vbo->addColor( borders.bottom.color ); + vbo->addVertex( Vector2f( pos.x + size.getWidth(), pos.y + size.getHeight() ) ); + vbo->addColor( borders.bottom.color ); } if ( leftW ) { @@ -269,11 +299,11 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve borderAddArc( vbo, tPos, leftW, leftH, startAngle, endAngle, borders.bottom.color, borderBottom, basePos ); } else { - vbo->addVertex( Vector2f( pos.x, pos.y + size.getHeight() ) ); - vbo->addColor( borders.bottom.color ); vbo->addVertex( Vector2f( pos.x + borderLeft, pos.y + size.getHeight() - borderBottom ) ); vbo->addColor( borders.bottom.color ); + vbo->addVertex( Vector2f( pos.x, pos.y + size.getHeight() ) ); + vbo->addColor( borders.bottom.color ); } } @@ -293,18 +323,18 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve bottomW, bottomH, startAngle, endAngle, borders.left.color, borderLeft, basePos ); } else { - vbo->addVertex( Vector2f( pos.x, pos.y + size.getHeight() ) ); - vbo->addColor( borders.left.color ); vbo->addVertex( Vector2f( pos.x + borderLeft, pos.y + size.getHeight() - borderBottom ) ); vbo->addColor( borders.left.color ); + vbo->addVertex( Vector2f( pos.x, pos.y + size.getHeight() ) ); + vbo->addColor( borders.left.color ); } if ( topW ) { double startAngle = 180; double endAngle = 225; Vector2f basePos( pos.x + borderLeft, pos.y + borderTop ); - Vector2f tPos( pos.x + topW, pos.y + topW ); + Vector2f tPos( pos.x + topW, pos.y + topH ); if ( topW > borderLeft ) { vbo->addVertex( @@ -324,10 +354,10 @@ void Borders::createBorders( VertexBuffer* vbo, const Borders& borders, const Ve borderAddArc( vbo, tPos, topW, topH, startAngle, endAngle, borders.left.color, borderLeft, basePos ); } else { - vbo->addVertex( Vector2f( pos.x, pos.y ) ); - vbo->addColor( borders.left.color ); vbo->addVertex( Vector2f( pos.x + borderLeft, pos.y + borderTop ) ); vbo->addColor( borders.left.color ); + vbo->addVertex( Vector2f( pos.x, pos.y ) ); + vbo->addColor( borders.left.color ); } } } diff --git a/src/eepp/ui/css/propertyspecification.cpp b/src/eepp/ui/css/propertyspecification.cpp index bdce2c5ef..0883259ca 100644 --- a/src/eepp/ui/css/propertyspecification.cpp +++ b/src/eepp/ui/css/propertyspecification.cpp @@ -60,7 +60,7 @@ PropertySpecification::registerShorthand( const std::string& name, const ShorthandDefinition* PropertySpecification::getShorthand( const Uint32& id ) const { for ( auto& shorthand : mShorthands ) { - if ( shorthand->getId() == id ) { + if ( shorthand->isDefinition( id ) ) { return shorthand; } } diff --git a/src/eepp/ui/css/shorthanddefinition.cpp b/src/eepp/ui/css/shorthanddefinition.cpp index 80fe2dc55..3abffee9c 100644 --- a/src/eepp/ui/css/shorthanddefinition.cpp +++ b/src/eepp/ui/css/shorthanddefinition.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -15,7 +16,15 @@ ShorthandDefinition* ShorthandDefinition::New( const std::string& name, ShorthandDefinition::ShorthandDefinition( const std::string& name, const std::vector& properties, const ShorthandType& shorthandType ) : - mName( name ), mId( String::hash( name ) ), mProperties( properties ), mType( shorthandType ) {} + mName( name ), mId( String::hash( name ) ), mProperties( properties ), mType( shorthandType ) { + for ( auto& sep : {"-", "_"} ) { + if ( mName.find( sep ) != std::string::npos ) { + std::string alias( name ); + String::replaceAll( alias, sep, "" ); + addAlias( alias ); + } + } +} const std::string& ShorthandDefinition::getName() const { return mName; @@ -47,6 +56,28 @@ static int getIndexEndingWith( const std::vector& vec, const std::s return -1; } +ShorthandDefinition& ShorthandDefinition::addAlias( const std::string& alias ) { + mAliases.push_back( alias ); + mAliasesHash.push_back( String::hash( alias ) ); + return *this; +} + +bool ShorthandDefinition::isAlias( const std::string& alias ) const { + return isAlias( String::hash( alias ) ); +} + +bool ShorthandDefinition::isAlias( const Uint32& id ) const { + return std::find( mAliasesHash.begin(), mAliasesHash.end(), id ) != mAliasesHash.end(); +} + +bool ShorthandDefinition::isDefinition( const std::string& name ) const { + return isDefinition( String::hash( name ) ); +} + +bool ShorthandDefinition::isDefinition( const Uint32& id ) const { + return mId == id || isAlias( id ); +} + std::vector ShorthandDefinition::parseShorthand( const ShorthandDefinition* shorthand, std::string value ) { value = String::trim( value ); @@ -100,12 +131,11 @@ ShorthandDefinition::parseShorthand( const ShorthandDefinition* shorthand, std:: auto values = String::split( value, ' ' ); - if ( values.size() >= 2 ) { - properties.emplace_back( StyleSheetProperty( propNames[0], values[0] ) ); - properties.emplace_back( StyleSheetProperty( propNames[1], values[1] ) ); - } else if ( values.size() == 1 ) { - properties.emplace_back( StyleSheetProperty( propNames[0], values[0] ) ); - properties.emplace_back( StyleSheetProperty( propNames[1], values[0] ) ); + if ( !values.empty() ) { + for ( size_t i = 0; i < propNames.size(); i++ ) { + properties.emplace_back( + StyleSheetProperty( propNames[0], values[i % values.size()] ) ); + } } break; } @@ -157,6 +187,35 @@ ShorthandDefinition::parseShorthand( const ShorthandDefinition* shorthand, std:: break; } + case ShorthandType::BorderBox: { + auto ltrbSplit = String::split( value, " ", "", "(\"" ); + if ( !ltrbSplit.empty() ) { + for ( size_t i = 0; i < propNames.size(); i++ ) { + properties.emplace_back( + StyleSheetProperty( propNames[i], ltrbSplit[i % ltrbSplit.size()] ) ); + } + } + break; + } + case ShorthandType::Radius: { + String::trim( value ); + auto splits = String::split( value, '/' ); + auto widths = String::split( splits[0], ' ' ); + std::vector heights; + if ( splits.size() >= 2 ) { + heights = String::split( splits[1], ' ' ); + } + if ( !widths.empty() ) { + for ( size_t i = 0; i < propNames.size(); i++ ) { + std::string val = widths[i % widths.size()]; + if ( !heights.empty() ) { + val += " " + heights[i % heights.size()]; + } + properties.emplace_back( StyleSheetProperty( propNames[i], val ) ); + } + } + break; + } default: break; } diff --git a/src/eepp/ui/css/stylesheetpropertiesparser.cpp b/src/eepp/ui/css/stylesheetpropertiesparser.cpp index bf5ef36ab..17d8824b7 100644 --- a/src/eepp/ui/css/stylesheetpropertiesparser.cpp +++ b/src/eepp/ui/css/stylesheetpropertiesparser.cpp @@ -134,7 +134,10 @@ int StyleSheetPropertiesParser::readComment( StyleSheetPropertiesParser::ReadSta return pos; } -void StyleSheetPropertiesParser::addProperty( const std::string& name, std::string value ) { +void StyleSheetPropertiesParser::addProperty( std::string name, std::string value ) { + String::toLowerInPlace( name ); + String::trimInPlace( name ); + if ( StyleSheetSpecification::instance()->isShorthand( name ) ) { std::vector properties = ShorthandDefinition::parseShorthand( StyleSheetSpecification::instance()->getShorthand( name ), value ); diff --git a/src/eepp/ui/css/stylesheetpropertyanimation.cpp b/src/eepp/ui/css/stylesheetpropertyanimation.cpp index 0e22ab5db..4f27605bf 100644 --- a/src/eepp/ui/css/stylesheetpropertyanimation.cpp +++ b/src/eepp/ui/css/stylesheetpropertyanimation.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -65,6 +66,18 @@ void StyleSheetPropertyAnimation::tweenProperty( UIWidget* widget, const Float& } break; } + case PropertyType::RadiusLength: { + Sizef start( Borders::radiusFromString( widget, startValue ) ); + Sizef end( Borders::radiusFromString( widget, endValue ) ); + Float x = easingCb[timingFunction]( normalizedProgress, start.x, end.x - start.x, 1.f ); + Float y = easingCb[timingFunction]( normalizedProgress, start.y, end.y - start.y, 1.f ); + widget->applyProperty( StyleSheetProperty( + property, String::fromFloat( x ) + " " + String::fromFloat( y ), propertyIndex ) ); + if ( isDone ) { + widget->applyProperty( StyleSheetProperty( property, endValue, propertyIndex ) ); + } + break; + } case PropertyType::Vector2: { Vector2f start( StyleSheetProperty( property, startValue ).asVector2f() ); Vector2f end( StyleSheetProperty( property, endValue ).asVector2f() ); @@ -153,6 +166,7 @@ bool StyleSheetPropertyAnimation::animationSupported( const PropertyType& type ) case PropertyType::Vector2: case PropertyType::BackgroundSize: case PropertyType::ForegroundSize: + case PropertyType::RadiusLength: return true; default: return false; diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index f9f04350b..7b09a6aea 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -7,13 +7,6 @@ SINGLETON_DECLARE_IMPLEMENTATION( StyleSheetSpecification ) StyleSheetSpecification::StyleSheetSpecification() { // TODO: Add correct "background" and "foreground" shorthand. - // TODO: Support border-color top right bottom left. - // TODO: Support border-radius top right bottom left. - // TODO: Create a rule to set the border position against its box. - // Something like: "border-type", with the following options: - // inside: The border is drawn inside the box. - // outside: The border is drawn outside the box. - // over: The border is drawn in the middle point of inside and outside. registerDefaultProperties(); registerDefaultNodeSelectors(); } @@ -97,9 +90,6 @@ void StyleSheetSpecification::registerDefaultProperties() { .setType( PropertyType::ForegroundSize ) .setIndexed(); registerProperty( "foreground-radius", "0px" ).setType( PropertyType::NumberLength ); - registerProperty( "border-color", "" ).setType( PropertyType::Color ); - registerProperty( "border-width", "" ).setType( PropertyType::NumberLength ); - registerProperty( "border-radius", "0px" ).setType( PropertyType::NumberLength ); registerProperty( "visible", "true" ).setType( PropertyType::Bool ); registerProperty( "enabled", "true" ).setType( PropertyType::Bool ); registerProperty( "theme", "" ); @@ -343,7 +333,29 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "timing-function", "linear" ).setType( PropertyType::String ); registerProperty( "page-locked", "" ).setType( PropertyType::Bool ); + registerProperty( "border-type", "inside" ).setType( PropertyType::String ); + registerProperty( "border-left-color", "transparent" ).setType( PropertyType::Color ); + registerProperty( "border-right-color", "transparent" ).setType( PropertyType::Color ); + registerProperty( "border-top-color", "transparent" ).setType( PropertyType::Color ); + registerProperty( "border-bottom-color", "transparent" ).setType( PropertyType::Color ); + registerProperty( "border-left-width", "0" ) + .setType( PropertyType::NumberLength ) + .setRelativeTarget( PropertyRelativeTarget::LocalBlockRadiusWidth ); + registerProperty( "border-right-width", "0" ) + .setType( PropertyType::NumberLength ) + .setRelativeTarget( PropertyRelativeTarget::LocalBlockRadiusWidth ); + registerProperty( "border-top-width", "0" ) + .setType( PropertyType::NumberLength ) + .setRelativeTarget( PropertyRelativeTarget::LocalBlockRadiusWidth ); + registerProperty( "border-bottom-width", "0" ) + .setType( PropertyType::NumberLength ) + .setRelativeTarget( PropertyRelativeTarget::LocalBlockRadiusWidth ); + + registerProperty( "border-top-left-radius", "0" ).setType( PropertyType::RadiusLength ); + registerProperty( "border-top-right-radius", "0" ).setType( PropertyType::RadiusLength ); + registerProperty( "border-bottom-left-radius", "0" ).setType( PropertyType::RadiusLength ); + registerProperty( "border-bottom-right-radius", "0" ).setType( PropertyType::RadiusLength ); // Shorthands registerShorthand( "margin", {"margin-top", "margin-right", "margin-bottom", "margin-left"}, @@ -370,6 +382,19 @@ void StyleSheetSpecification::registerDefaultProperties() { ShorthandType::BackgroundPosition ); registerShorthand( "foreground-position", {"foreground-position-x", "foreground-position-y"}, ShorthandType::BackgroundPosition ); + registerShorthand( + "border-color", + {"border-top-color", "border-right-color", "border-bottom-color", "border-left-color"}, + ShorthandType::BorderBox ); + registerShorthand( + "border-width", + {"border-top-width", "border-right-width", "border-bottom-width", "border-left-width"}, + ShorthandType::BorderBox ); + + registerShorthand( "border-radius", + {"border-top-left-radius", "border-top-right-radius", + "border-bottom-right-radius", "border-bottom-left-radius"}, + ShorthandType::Radius ); /*registerShorthand( "rotation-origin-point", {"rotation-origin-point-x", "rotation-origin-point-y"}, ShorthandType::Vector2 ); registerShorthand( "scale-origin-point", {"scale-origin-point-x", "scale-origin-point-y"}, diff --git a/src/eepp/ui/uibackgrounddrawable.cpp b/src/eepp/ui/uibackgrounddrawable.cpp index b502b15ae..3b56d2659 100644 --- a/src/eepp/ui/uibackgrounddrawable.cpp +++ b/src/eepp/ui/uibackgrounddrawable.cpp @@ -1,15 +1,17 @@ #include #include +#include namespace EE { namespace UI { -UIBackgroundDrawable* UIBackgroundDrawable::New() { - return eeNew( UIBackgroundDrawable, () ); +UIBackgroundDrawable* UIBackgroundDrawable::New( UINode* owner ) { + return eeNew( UIBackgroundDrawable, ( owner ) ); } -UIBackgroundDrawable::UIBackgroundDrawable() : +UIBackgroundDrawable::UIBackgroundDrawable( UINode* owner ) : Drawable( UIBACKGROUNDDRAWABLE ), - mVertexBuffer( VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ) ), + mOwner( owner ), + mVertexBuffer( VertexBuffer::NewVertexArray( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ) ), mNeedsUpdate( false ), mColorNeedsUpdate( false ) {} @@ -17,9 +19,13 @@ UIBackgroundDrawable::~UIBackgroundDrawable() { eeSAFE_DELETE( mVertexBuffer ); } -void UIBackgroundDrawable::draw() {} +void UIBackgroundDrawable::draw() { + draw( mPosition, mSize ); +} -void UIBackgroundDrawable::draw( const Vector2f& position ) {} +void UIBackgroundDrawable::draw( const Vector2f& position ) { + draw( position, mSize ); +} void UIBackgroundDrawable::draw( const Vector2f& position, const Sizef& size ) { if ( mPosition != position ) { @@ -36,6 +42,8 @@ void UIBackgroundDrawable::draw( const Vector2f& position, const Sizef& size ) { update(); } + // TODO: Optimize rendering for square backgrounds (no radius) + // It will be cheaper to use the batch renderer for those cases. mVertexBuffer->bind(); mVertexBuffer->draw(); mVertexBuffer->unbind(); @@ -49,6 +57,13 @@ const BorderRadiuses& UIBackgroundDrawable::getRadiuses() const { return mRadiuses; } +bool UIBackgroundDrawable::hasRadius() const { + return !mRadiusesStr.topLeft.empty() || !mRadiusesStr.topRight.empty() || + !mRadiusesStr.bottomLeft.empty() || !mRadiusesStr.bottomRight.empty() || + mRadiuses.topLeft != Sizef::Zero || mRadiuses.topRight != Sizef::Zero || + mRadiuses.bottomLeft != Sizef::Zero || mRadiuses.bottomRight != Sizef::Zero; +} + void UIBackgroundDrawable::setRadiuses( const BorderRadiuses& radiuses ) { mRadiuses = radiuses; mNeedsUpdate = true; @@ -68,10 +83,42 @@ void UIBackgroundDrawable::setRadius( const Uint32& radius ) { } } +void UIBackgroundDrawable::setTopLeftRadius( const std::string& radius ) { + if ( mRadiusesStr.topLeft != radius ) { + mRadiusesStr.topLeft = radius; + mNeedsUpdate = true; + } +} + +void UIBackgroundDrawable::setTopRightRadius( const std::string& radius ) { + if ( mRadiusesStr.topRight != radius ) { + mRadiusesStr.topRight = radius; + mNeedsUpdate = true; + } +} + +void UIBackgroundDrawable::setBottomLeftRadius( const std::string& radius ) { + if ( mRadiusesStr.bottomLeft != radius ) { + mRadiusesStr.bottomLeft = radius; + mNeedsUpdate = true; + } +} + +void UIBackgroundDrawable::setBottomRightRadius( const std::string& radius ) { + if ( mRadiusesStr.bottomRight != radius ) { + mRadiusesStr.bottomRight = radius; + mNeedsUpdate = true; + } +} + Int32 UIBackgroundDrawable::getRadius() const { return mRadiuses.topLeft.x; } +void UIBackgroundDrawable::invalidate() { + mNeedsUpdate = true; +} + void UIBackgroundDrawable::setSize( const Sizef& size ) { if ( size != mSize ) { mSize = size; @@ -96,9 +143,24 @@ void UIBackgroundDrawable::onPositionChange() { } void UIBackgroundDrawable::update() { + updateRadiuses(); Borders::createBackground( mVertexBuffer, mRadiuses, mPosition, mSize, mColor ); mColorNeedsUpdate = false; mNeedsUpdate = false; } +void UIBackgroundDrawable::updateRadiuses() { + if ( !mRadiusesStr.topLeft.empty() ) + mRadiuses.topLeft = Borders::radiusFromString( mOwner, mRadiusesStr.topLeft ); + + if ( !mRadiusesStr.topRight.empty() ) + mRadiuses.topRight = Borders::radiusFromString( mOwner, mRadiusesStr.topRight ); + + if ( !mRadiusesStr.bottomLeft.empty() ) + mRadiuses.bottomLeft = Borders::radiusFromString( mOwner, mRadiusesStr.bottomLeft ); + + if ( !mRadiusesStr.bottomRight.empty() ) + mRadiuses.bottomRight = Borders::radiusFromString( mOwner, mRadiusesStr.bottomRight ); +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp index 10a067529..3c7976db4 100644 --- a/src/eepp/ui/uiborderdrawable.cpp +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -1,15 +1,17 @@ #include #include #include +#include namespace EE { namespace UI { -UIBorderDrawable* UIBorderDrawable::New() { - return eeNew( UIBorderDrawable, () ); +UIBorderDrawable* UIBorderDrawable::New( UINode* owner ) { + return eeNew( UIBorderDrawable, ( owner ) ); } -UIBorderDrawable::UIBorderDrawable() : +UIBorderDrawable::UIBorderDrawable( UINode* owner ) : Drawable( UIBORDERDRAWABLE ), + mOwner( owner ), mVertexBuffer( VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_STRIP ) ), mBorderType( BorderType::Inside ), mNeedsUpdate( false ), @@ -19,9 +21,13 @@ UIBorderDrawable::~UIBorderDrawable() { eeSAFE_DELETE( mVertexBuffer ); } -void UIBorderDrawable::draw() {} +void UIBorderDrawable::draw() { + draw( mPosition, mSize ); +} -void UIBorderDrawable::draw( const Vector2f& position ) {} +void UIBorderDrawable::draw( const Vector2f& position ) { + draw( position, mSize ); +} void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { if ( mPosition != position ) { @@ -34,6 +40,7 @@ void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { mNeedsUpdate = true; } + // TODO: Implement color update. if ( mNeedsUpdate || mColorNeedsUpdate ) { update(); } @@ -98,8 +105,8 @@ Color UIBorderDrawable::getColorRight() const { } void UIBorderDrawable::setColorRight( const Color& colorRight ) { - if ( mBorders.left.color != colorRight ) { - mBorders.left.color = colorRight; + if ( mBorders.right.color != colorRight ) { + mBorders.right.color = colorRight; mColorNeedsUpdate = true; } } @@ -137,6 +144,70 @@ void UIBorderDrawable::setBorderType( const BorderType& borderType ) { } } +void UIBorderDrawable::invalidate() { + mNeedsUpdate = true; +} + +void UIBorderDrawable::setLeftWidth( const std::string& leftWidth ) { + if ( mBorderStr.width.left != leftWidth ) { + mBorderStr.width.left = leftWidth; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setRightWidth( const std::string& rightWidth ) { + if ( mBorderStr.width.right != rightWidth ) { + mBorderStr.width.right = rightWidth; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setTopWidth( const std::string& topWidth ) { + if ( mBorderStr.width.top != topWidth ) { + mBorderStr.width.top = topWidth; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setBottomWidth( const std::string& bottomWidth ) { + if ( mBorderStr.width.bottom != bottomWidth ) { + mBorderStr.width.bottom = bottomWidth; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setTopLeftRadius( const std::string& radius ) { + if ( mBorderStr.radius.topLeft != radius ) { + mBorderStr.radius.topLeft = radius; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setTopRightRadius( const std::string& radius ) { + if ( mBorderStr.radius.topRight != radius ) { + mBorderStr.radius.topRight = radius; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setBottomLeftRadius( const std::string& radius ) { + if ( mBorderStr.radius.bottomLeft != radius ) { + mBorderStr.radius.bottomLeft = radius; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::setBottomRightRadius( const std::string& radius ) { + if ( mBorderStr.radius.bottomRight != radius ) { + mBorderStr.radius.bottomRight = radius; + mNeedsUpdate = true; + } +} + +const Borders& UIBorderDrawable::getBorders() const { + return mBorders; +} + void UIBorderDrawable::onAlphaChange() { mBorders.left.color.a = mBorders.right.color.a = mBorders.top.color.a = mBorders.bottom.color.a = mColor.a; @@ -155,6 +226,8 @@ void UIBorderDrawable::onPositionChange() { } void UIBorderDrawable::update() { + updateBorders(); + switch ( mBorderType ) { case BorderType::Outside: { Vector2f pos( mPosition ); @@ -184,10 +257,70 @@ void UIBorderDrawable::update() { Borders::createBorders( mVertexBuffer, mBorders, mPosition, mSize ); break; } + case BorderType::Outline: { + Vector2f pos( mPosition ); + Sizef size( mSize ); + + if ( mBorders.top.width > 0 ) { + pos.y -= mBorders.top.width * 0.5f; + } + + if ( mBorders.left.width > 0 ) { + pos.x -= mBorders.left.width * 0.5f; + } + + if ( mBorders.right.width > 0 ) { + size.x += mBorders.right.width; + } + + if ( mBorders.bottom.width > 0 ) { + size.y += mBorders.bottom.width; + } + + Borders::createBorders( mVertexBuffer, mBorders, pos, size ); + + break; + } } mColorNeedsUpdate = false; mNeedsUpdate = false; } +void UIBorderDrawable::updateBorders() { + if ( !mBorderStr.width.left.empty() ) { + mBorders.left.width = mOwner->lengthFromValue( + mBorderStr.width.left, CSS::PropertyRelativeTarget::LocalBlockRadiusWidth ); + } + + if ( !mBorderStr.width.right.empty() ) { + mBorders.right.width = mOwner->lengthFromValue( + mBorderStr.width.right, CSS::PropertyRelativeTarget::LocalBlockRadiusWidth ); + } + + if ( !mBorderStr.width.top.empty() ) { + mBorders.top.width = mOwner->lengthFromValue( + mBorderStr.width.top, CSS::PropertyRelativeTarget::LocalBlockRadiusHeight ); + } + + if ( !mBorderStr.width.bottom.empty() ) { + mBorders.bottom.width = mOwner->lengthFromValue( + mBorderStr.width.bottom, CSS::PropertyRelativeTarget::LocalBlockRadiusHeight ); + } + + if ( !mBorderStr.radius.topLeft.empty() ) + mBorders.radius.topLeft = Borders::radiusFromString( mOwner, mBorderStr.radius.topLeft ); + + if ( !mBorderStr.radius.topRight.empty() ) + mBorders.radius.topRight = Borders::radiusFromString( mOwner, mBorderStr.radius.topRight ); + + if ( !mBorderStr.radius.bottomLeft.empty() ) + mBorders.radius.bottomLeft = + Borders::radiusFromString( mOwner, mBorderStr.radius.bottomLeft ); + + if ( !mBorderStr.radius.bottomRight.empty() ) + mBorders.radius.bottomRight = + Borders::radiusFromString( mOwner, mBorderStr.radius.bottomRight ); +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 96f4c499f..40e20e9fc 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -245,7 +245,7 @@ void UINode::updateDebugData() { } text += String::format( "X: %2.4f Y: %2.4f\nW: %2.4f H: %2.4f", mDpPos.x, mDpPos.y, - mDpSize.x, mDpSize.y ); + mDpSize.x, mDpSize.y ); widget->setTooltipText( text ); } @@ -448,6 +448,30 @@ UINode* UINode::setBorderRadius( const unsigned int& corners ) { return this; } +UINode* UINode::setTopLeftRadius( const std::string& radius ) { + setBorderEnabled( true )->setTopLeftRadius( radius ); + setBackgroundFillEnabled( true )->getBackgroundDrawable().setTopLeftRadius( radius ); + return this; +} + +UINode* UINode::setTopRightRadius( const std::string& radius ) { + setBorderEnabled( true )->setTopRightRadius( radius ); + setBackgroundFillEnabled( true )->getBackgroundDrawable().setTopRightRadius( radius ); + return this; +} + +UINode* UINode::setBottomLeftRadius( const std::string& radius ) { + setBorderEnabled( true )->setBottomLeftRadius( radius ); + setBackgroundFillEnabled( true )->getBackgroundDrawable().setBottomLeftRadius( radius ); + return this; +} + +UINode* UINode::setBottomRightRadius( const std::string& radius ) { + setBorderEnabled( true )->setBottomRightRadius( radius ); + setBackgroundFillEnabled( true )->getBackgroundDrawable().setBottomRightRadius( radius ); + return this; +} + Uint32 UINode::getBorderRadius() const { return NULL != mBorder ? mBorder->getRadius() : 0; } @@ -664,7 +688,7 @@ UINodeDrawable* UINode::getForeground() { UIBorderDrawable* UINode::getBorder() { if ( NULL == mBorder ) { - mBorder = UIBorderDrawable::New(); + mBorder = UIBorderDrawable::New( this ); mBorder->setColor( Color::Transparent ); mBorder->setLineWidth( PixelDensity::dpToPx( 1 ) ); } @@ -1024,6 +1048,86 @@ void UINode::setFocus() { getEventDispatcher()->setFocusControl( this ); } +Float UINode::getPropertyRelativeTargetContainerLength( + const CSS::PropertyRelativeTarget& relativeTarget, const Float& defaultValue, + const Uint32& propertyIndex ) { + Float containerLength = defaultValue; + switch ( relativeTarget ) { + case PropertyRelativeTarget::ContainingBlockWidth: + containerLength = getParent()->getPixelsSize().getWidth(); + break; + case PropertyRelativeTarget::ContainingBlockHeight: + containerLength = getParent()->getPixelsSize().getHeight(); + case PropertyRelativeTarget::LocalBlockWidth: + containerLength = getPixelsSize().getWidth(); + break; + case PropertyRelativeTarget::LocalBlockHeight: + containerLength = getPixelsSize().getHeight(); + break; + case PropertyRelativeTarget::BackgroundWidth: + containerLength = + getPixelsSize().getWidth() - + getBackground()->getLayer( propertyIndex )->getDrawableSize().getWidth(); + break; + case PropertyRelativeTarget::BackgroundHeight: + containerLength = + getPixelsSize().getHeight() - + getBackground()->getLayer( propertyIndex )->getDrawableSize().getHeight(); + break; + case PropertyRelativeTarget::ForegroundWidth: + containerLength = + getPixelsSize().getWidth() - + getForeground()->getLayer( propertyIndex )->getDrawableSize().getWidth(); + break; + case PropertyRelativeTarget::ForegroundHeight: + containerLength = + getPixelsSize().getHeight() - + getForeground()->getLayer( propertyIndex )->getDrawableSize().getHeight(); + break; + case PropertyRelativeTarget::LocalBlockRadiusWidth: + containerLength = getPixelsSize().getWidth() * 0.5f; + break; + case PropertyRelativeTarget::LocalBlockRadiusHeight: + containerLength = getPixelsSize().getHeight() * 0.5f; + break; + default: + break; + } + return containerLength; +} + +Float UINode::lengthFromValue( const std::string& value, + const PropertyRelativeTarget& relativeTarget, + const Float& defaultValue, const Float& defaultContainerValue, + const Uint32& propertyIndex ) { + Float containerLength = + getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex ); + return convertLength( CSS::StyleSheetLength( value, defaultValue ), containerLength ); +} + +Float UINode::lengthFromValue( const CSS::StyleSheetProperty& property, const Float& defaultValue, + const Float& defaultContainerValue ) { + return lengthFromValue( property.getValue(), + property.getPropertyDefinition()->getRelativeTarget(), defaultValue, + defaultContainerValue, property.getIndex() ); +} + +Float UINode::lengthFromValueAsDp( const std::string& value, + const PropertyRelativeTarget& relativeTarget, + const Float& defaultValue, const Float& defaultContainerValue, + const Uint32& propertyIndex ) { + Float containerLength = + getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex ); + return convertLengthAsDp( CSS::StyleSheetLength( value, defaultValue ), containerLength ); +} + +Float UINode::lengthFromValueAsDp( const CSS::StyleSheetProperty& property, + const Float& defaultValue, const Float& defaultContainerValue ) { + return lengthFromValue( property.getValue(), + property.getPropertyDefinition()->getRelativeTarget(), defaultValue, + defaultContainerValue, property.getIndex() ); +} + Uint32 UINode::onFocus() { pushState( UIState::StateFocus ); diff --git a/src/eepp/ui/uinodedrawable.cpp b/src/eepp/ui/uinodedrawable.cpp index 4a79f3bcd..eaecf900e 100644 --- a/src/eepp/ui/uinodedrawable.cpp +++ b/src/eepp/ui/uinodedrawable.cpp @@ -31,6 +31,7 @@ UINodeDrawable* UINodeDrawable::New( UINode* owner ) { UINodeDrawable::UINodeDrawable( UINode* owner ) : Drawable( Drawable::UINODEDRAWABLE ), mOwner( owner ), + mBackgroundColor( owner ), mNeedsUpdate( true ), mClipEnabled( false ) { mBackgroundColor.setColor( Color::Transparent ); @@ -123,6 +124,11 @@ void UINodeDrawable::setClipEnabled( bool clipEnabled ) { void UINodeDrawable::invalidate() { mNeedsUpdate = true; + mBackgroundColor.invalidate(); +} + +UIBackgroundDrawable& UINodeDrawable::getBackgroundDrawable() { + return mBackgroundColor; } Sizef UINodeDrawable::getSize() { @@ -169,6 +175,16 @@ void UINodeDrawable::draw( const Vector2f& position, const Sizef& size, const Ui } } + bool masked = false; + ClippingMask* clippingMask = GLi->getClippingMask(); + if ( !mGroup.empty() && mBackgroundColor.hasRadius() ) { + masked = true; + clippingMask->setMaskMode( ClippingMask::Inclusive ); + clippingMask->clearMasks(); + clippingMask->appendMask( mBackgroundColor ); + clippingMask->stencilMaskEnable(); + } + // Draw in reverse order to respect the background-image specification: // "The background images are drawn on stacking context layers on top of each other. The first // layer specified is drawn as if it is closest to the user." @@ -185,6 +201,10 @@ void UINodeDrawable::draw( const Vector2f& position, const Sizef& size, const Ui } } + if ( masked ) { + clippingMask->stencilMaskDisable(); + } + if ( mClipEnabled ) GLi->getClippingMask()->clipPlaneDisable(); } diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index f9c33f16a..7b9751162 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -451,6 +451,9 @@ void UIWidget::onVisibilityChange() { void UIWidget::onSizeChange() { UINode::onSizeChange(); + if ( mBorder != NULL ) + mBorder->invalidate(); + if ( mBackground != NULL ) mBackground->invalidate(); @@ -559,80 +562,6 @@ bool UIWidget::isSceneNodeLoading() const { : false; } -Float UIWidget::getPropertyRelativeTargetContainerLength( - const PropertyRelativeTarget& relativeTarget, const Float& defaultValue, - const Uint32& propertyIndex ) { - Float containerLength = defaultValue; - switch ( relativeTarget ) { - case PropertyRelativeTarget::ContainingBlockWidth: - containerLength = getParent()->getPixelsSize().getWidth(); - break; - case PropertyRelativeTarget::ContainingBlockHeight: - containerLength = getParent()->getPixelsSize().getHeight(); - case PropertyRelativeTarget::LocalBlockWidth: - containerLength = getPixelsSize().getWidth(); - break; - case PropertyRelativeTarget::LocalBlockHeight: - containerLength = getPixelsSize().getHeight(); - break; - case PropertyRelativeTarget::BackgroundWidth: - containerLength = - getPixelsSize().getWidth() - - getBackground()->getLayer( propertyIndex )->getDrawableSize().getWidth(); - break; - case PropertyRelativeTarget::BackgroundHeight: - containerLength = - getPixelsSize().getHeight() - - getBackground()->getLayer( propertyIndex )->getDrawableSize().getHeight(); - break; - case PropertyRelativeTarget::ForegroundWidth: - containerLength = - getPixelsSize().getWidth() - - getForeground()->getLayer( propertyIndex )->getDrawableSize().getWidth(); - break; - case PropertyRelativeTarget::ForegroundHeight: - containerLength = - getPixelsSize().getHeight() - - getForeground()->getLayer( propertyIndex )->getDrawableSize().getHeight(); - break; - default: - break; - } - return containerLength; -} - -Float UIWidget::lengthFromValue( const std::string& value, - const PropertyRelativeTarget& relativeTarget, - const Float& defaultValue, const Float& defaultContainerValue, - const Uint32& propertyIndex ) { - Float containerLength = - getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex ); - return convertLength( CSS::StyleSheetLength( value, defaultValue ), containerLength ); -} - -Float UIWidget::lengthFromValue( const StyleSheetProperty& property, const Float& defaultValue, - const Float& defaultContainerValue ) { - return lengthFromValue( property.getValue(), - property.getPropertyDefinition()->getRelativeTarget(), defaultValue, - defaultContainerValue, property.getIndex() ); -} - -Float UIWidget::lengthFromValueAsDp( const std::string& value, - const PropertyRelativeTarget& relativeTarget, - const Float& defaultValue, const Float& defaultContainerValue, - const Uint32& propertyIndex ) { - Float containerLength = - getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex ); - return convertLengthAsDp( CSS::StyleSheetLength( value, defaultValue ), containerLength ); -} - -Float UIWidget::lengthFromValueAsDp( const StyleSheetProperty& property, const Float& defaultValue, - const Float& defaultContainerValue ) { - return lengthFromValue( property.getValue(), - property.getPropertyDefinition()->getRelativeTarget(), defaultValue, - defaultContainerValue, property.getIndex() ); -} - const std::string& UIWidget::getMinWidthEq() const { return mMinWidthEq; } @@ -1162,14 +1091,8 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, return getForegroundColor().toHexString(); case PropertyId::ForegroundRadius: return String::toStr( getForegroundRadius() ); - case PropertyId::BorderColor: - return getBorderColor().toHexString(); - case PropertyId::BorderRadius: - return String::toStr( getBorderRadius() ); - case PropertyId::BorderWidth: - return String::fromFloat( getBorderWidth() ); case PropertyId::BorderType: - return getBorder()->getBorderType() == BorderType::Inside ? "inside" : "outside"; + return Borders::fromBorderType( setBorderEnabled( true )->getBorderType() ); case PropertyId::SkinColor: return getSkinColor().toHexString(); case PropertyId::Rotation: @@ -1224,6 +1147,38 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, return mMinHeightEq; case PropertyId::MaxHeight: return mMaxHeightEq; + case PropertyId::BorderLeftColor: + return setBorderEnabled( true )->getColorLeft().toHexString(); + case PropertyId::BorderRightColor: + return setBorderEnabled( true )->getColorRight().toHexString(); + case PropertyId::BorderTopColor: + return setBorderEnabled( true )->getColorTop().toHexString(); + case PropertyId::BorderBottomColor: + return setBorderEnabled( true )->getColorBottom().toHexString(); + case PropertyId::BorderLeftWidth: + return String::fromFloat( setBorderEnabled( true )->getBorders().left.width, "px" ); + case PropertyId::BorderRightWidth: + return String::fromFloat( setBorderEnabled( true )->getBorders().right.width, "px" ); + case PropertyId::BorderTopWidth: + return String::fromFloat( setBorderEnabled( true )->getBorders().top.width, "px" ); + case PropertyId::BorderBottomWidth: + return String::fromFloat( setBorderEnabled( true )->getBorders().bottom.width, "px" ); + case PropertyId::BorderTopLeftRadius: + return String::format( "%.2fpx %.2fpx", + setBorderEnabled( true )->getBorders().radius.topLeft.x, + getBorder()->getBorders().radius.topLeft.y ); + case PropertyId::BorderTopRightRadius: + return String::format( "%.2fpx %.2fpx", + setBorderEnabled( true )->getBorders().radius.topRight.x, + getBorder()->getBorders().radius.topRight.y ); + case PropertyId::BorderBottomLeftRadius: + return String::format( "%.2fpx %.2fpx", + setBorderEnabled( true )->getBorders().radius.bottomLeft.x, + getBorder()->getBorders().radius.bottomLeft.y ); + case PropertyId::BorderBottomRightRadius: + return String::format( "%.2fpx %.2fpx", + setBorderEnabled( true )->getBorders().radius.bottomRight.x, + getBorder()->getBorders().radius.bottomRight.y ); default: break; } @@ -1294,18 +1249,9 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::ForegroundSize: setForegroundSize( attribute.value(), attribute.getIndex() ); break; - case PropertyId::BorderColor: - setBorderColor( attribute.asColor() ); - break; - case PropertyId::BorderWidth: - setBorderWidth( lengthFromValue( attribute, PixelDensity::dpToPx( 1 ) ) ); - break; - case PropertyId::BorderRadius: - setBorderRadius( lengthFromValue( attribute ) ); - break; case PropertyId::BorderType: - getBorder()->setBorderType( attribute.getValue() == "inside" ? BorderType::Inside - : BorderType::Outside ); + setBorderEnabled( true )->setBorderType( + Borders::toBorderType( attribute.getValue() ) ); break; case PropertyId::Visible: setVisible( attribute.asBool() ); @@ -1573,6 +1519,43 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::MaxHeight: setMaxHeightEq( attribute.getValue() ); break; + case PropertyId::BorderLeftColor: + setBorderEnabled( true )->setColorLeft( attribute.asColor() ); + invalidateDraw(); + break; + case PropertyId::BorderRightColor: + setBorderEnabled( true )->setColorRight( attribute.asColor() ); + break; + case PropertyId::BorderTopColor: + setBorderEnabled( true )->setColorTop( attribute.asColor() ); + break; + case PropertyId::BorderBottomColor: + setBorderEnabled( true )->setColorBottom( attribute.asColor() ); + break; + case PropertyId::BorderLeftWidth: + setBorderEnabled( true )->setLeftWidth( attribute.asString() ); + break; + case PropertyId::BorderRightWidth: + setBorderEnabled( true )->setRightWidth( attribute.asString() ); + break; + case PropertyId::BorderTopWidth: + setBorderEnabled( true )->setTopWidth( attribute.asString() ); + break; + case PropertyId::BorderBottomWidth: + setBorderEnabled( true )->setBottomWidth( attribute.asString() ); + break; + case PropertyId::BorderTopLeftRadius: + setTopLeftRadius( attribute.asString() ); + break; + case PropertyId::BorderBottomLeftRadius: + setBottomLeftRadius( attribute.asString() ); + break; + case PropertyId::BorderTopRightRadius: + setTopRightRadius( attribute.asString() ); + break; + case PropertyId::BorderBottomRightRadius: + setBottomRightRadius( attribute.asString() ); + break; default: attributeSet = false; break;