diff --git a/bin/assets/layouts/test2.css b/bin/assets/layouts/test2.css new file mode 100644 index 000000000..5c9d1811f --- /dev/null +++ b/bin/assets/layouts/test2.css @@ -0,0 +1,23 @@ +LinearLayout { + layout-width: match_parent; + layout-height: match_parent; + background-color: #cecece; +} + +Widget { + clip: false; + margin-left: 200dp; + margin-top: 200dp; + width: 200px; + height: 200px; + background-color: white; + border-radius: 50dp; + border-color: rgba(255, 0, 0, 0.5); + border-width: 100dp; + border-type: outside; + transition: all 0.5s; +} + +Widget:hover { + border-radius: 0dp; +} diff --git a/bin/assets/layouts/test2.xml b/bin/assets/layouts/test2.xml new file mode 100644 index 000000000..53307a38a --- /dev/null +++ b/bin/assets/layouts/test2.xml @@ -0,0 +1,3 @@ + + + diff --git a/include/eepp/graphics/drawable.hpp b/include/eepp/graphics/drawable.hpp index 97f8a603d..ce9492655 100644 --- a/include/eepp/graphics/drawable.hpp +++ b/include/eepp/graphics/drawable.hpp @@ -28,6 +28,7 @@ class EE_API Drawable { SKIN, UINODEDRAWABLE, UINODEDRAWABLE_LAYERDRAWABLE, + UIBORDERDRAWABLE, CUSTOM }; diff --git a/include/eepp/ui/css/propertydefinition.hpp b/include/eepp/ui/css/propertydefinition.hpp index 52995f36b..0785423f2 100644 --- a/include/eepp/ui/css/propertydefinition.hpp +++ b/include/eepp/ui/css/propertydefinition.hpp @@ -206,7 +206,8 @@ enum class PropertyId : Uint32 { MaxEdgeResistance = String::hash( "max-edge-resistance" ), PageTransitionDuration = String::hash( "page-transition-duration" ), TimingFunction = String::hash( "timing-function" ), - PageLocked = String::hash( "page-locked" ) + PageLocked = String::hash( "page-locked" ), + BorderType = String::hash( "border-type" ) }; enum class PropertyType : Uint32 { diff --git a/include/eepp/ui/uiborderdrawable.hpp b/include/eepp/ui/uiborderdrawable.hpp new file mode 100644 index 000000000..d5aa7e7aa --- /dev/null +++ b/include/eepp/ui/uiborderdrawable.hpp @@ -0,0 +1,113 @@ +#ifndef EE_UI_UIBORDERDRAWABLE_HPP +#define EE_UI_UIBORDERDRAWABLE_HPP + +#include +#include + +namespace EE { namespace Graphics { +class VertexBuffer; +}} // namespace EE::Graphics +using namespace EE::Graphics; + +namespace EE { namespace UI { + +enum class BorderType : Uint32 { Inside, Outside }; + +class EE_API UIBorderDrawable : public Drawable { + public: + static UIBorderDrawable* New(); + + UIBorderDrawable(); + + virtual ~UIBorderDrawable(); + + virtual Sizef getSize(); + + virtual void draw(); + + virtual void draw( const Vector2f& position ); + + virtual void draw( const Vector2f& position, const Sizef& size ); + + virtual bool isStateful(); + + /** Set the line width to draw primitives */ + virtual void setLineWidth( const Float& width ); + + /** @return The line with to draw primitives */ + Float getLineWidth() const; + + Int32 getRadius() const; + + void setRadius( const Int32& radius ); + + Color getColorLeft() const; + + void setColorLeft( const Color& colorLeft ); + + Color getColorRight() const; + + void setColorRight( const Color& colorRight ); + + Color getColorTop() const; + + void setColorTop( const Color& colorTop ); + + Color getColorBottom() const; + + void setColorBottom( const Color& colorBottom ); + + const BorderType& getBorderType() const; + + void setBorderType( const BorderType& borderType ); + + protected: + VertexBuffer* mVertexBuffer; + + struct Border { + int width = 0; + Color color; + }; + + struct BorderRadiuses { + Float topLeftX = 0; + Float topLeftY = 0; + Float topRightX = 0; + Float topRightY = 0; + Float bottomRightX = 0; + Float bottomRightY = 0; + Float bottomLeftX = 0; + Float bottomLeftY = 0; + }; + + struct Borders { + Border left; + Border top; + Border right; + Border bottom; + BorderRadiuses radius; + }; + + Borders mBorders; + BorderType mBorderType; + Sizef mSize; + bool mNeedsUpdate; + bool mColorNeedsUpdate; + + virtual void onAlphaChange(); + + virtual void onColorFilterChange(); + + virtual void onPositionChange(); + + void update(); + + void updateColor(); + + void createBorders( VertexBuffer* vbo, const UIBorderDrawable::Borders& borders, + const Vector2f& pos, const Sizef& size ); +}; + +}} // namespace EE::UI + +#endif // EE_UI_UIBORDERDRAWABLE_HPP diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index 77d6e40a6..ac38cf10b 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -11,7 +11,6 @@ namespace EE { namespace Graphics { class Drawable; -class RectangleDrawable; }} // namespace EE::Graphics namespace EE { namespace Scene { @@ -25,6 +24,7 @@ namespace EE { namespace UI { class UISceneNode; class UITheme; class UINodeDrawable; +class UIBorderDrawable; class EE_API UINode : public Node { public: @@ -132,7 +132,7 @@ class EE_API UINode : public Node { Uint32 getForegroundRadius() const; - RectangleDrawable* setBorderEnabled( bool enabled ); + UIBorderDrawable* setBorderEnabled( bool enabled ); UINode* setBorderColor( const Color& color ); @@ -154,7 +154,7 @@ class EE_API UINode : public Node { UINodeDrawable* getForeground(); - RectangleDrawable* getBorder(); + UIBorderDrawable* getBorder(); void setThemeByName( const std::string& Theme ); @@ -223,7 +223,7 @@ class EE_API UINode : public Node { UISkinState* mSkinState; UINodeDrawable* mBackground; UINodeDrawable* mForeground; - RectangleDrawable* mBorder; + UIBorderDrawable* mBorder; Vector2f mDragPoint; Uint32 mDragButton; Color mSkinColor; diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index ec02bbd82..4b248fb5d 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -79,7 +79,7 @@ {6d057187-158a-4883-8d5b-d470a6b6b025} 10 0 - 0 + 15 ../../make/linux @@ -1531,7 +1531,7 @@ eepp-UIEditor-debug ProjectExplorer.CustomExecutableRunConfiguration - -x assets/layouts/test.xml -c assets/layouts/test.css -u + -x assets/layouts/test2.xml -c assets/layouts/test2.css -u false true diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 5a02faf60..98eb6cc0b 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -311,6 +311,7 @@ ../../include/eepp/ui/marginmove/scale.hpp ../../include/eepp/ui/tools/textureatlaseditor.hpp ../../include/eepp/ui/tools/uicolorpicker.hpp +../../include/eepp/ui/uiborderdrawable.hpp ../../include/eepp/ui/uicheckbox.hpp ../../include/eepp/ui/uicombobox.hpp ../../include/eepp/ui/uicommondialog.hpp @@ -745,6 +746,7 @@ ../../src/eepp/ui/tools/textureatlastextureregioneditor.cpp ../../src/eepp/ui/tools/textureatlastextureregioneditor.hpp ../../src/eepp/ui/tools/uicolorpicker.cpp +../../src/eepp/ui/uiborderdrawable.cpp ../../src/eepp/ui/uicheckbox.cpp ../../src/eepp/ui/uicombobox.cpp ../../src/eepp/ui/uicommondialog.cpp diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index e2e702abb..f9f04350b 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -343,6 +343,7 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "timing-function", "linear" ).setType( PropertyType::String ); registerProperty( "page-locked", "" ).setType( PropertyType::Bool ); + registerProperty( "border-type", "inside" ).setType( PropertyType::String ); // Shorthands registerShorthand( "margin", {"margin-top", "margin-right", "margin-bottom", "margin-left"}, diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp new file mode 100644 index 000000000..8e61cc050 --- /dev/null +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -0,0 +1,492 @@ +#include +#include +#include +#include +#include + +namespace EE { namespace UI { + +static void borderAddArc( VertexBuffer* vbo, Vector2f pos, Float radiW, Float radiH, + double arcStartAngle, double arcEndAngle, Color color, Float lineW, + Vector2f basePos, bool decrease = false ) { + Float angleShift = 1; + double startAngle = eemin( arcStartAngle, arcEndAngle ); + double endAngle = eemax( arcStartAngle, arcEndAngle ); + Vector2f startPos = ( radiW > lineW ) ? pos : basePos; + + if ( decrease ) { + for ( double i = endAngle; i >= startAngle; i -= angleShift ) { + if ( radiW > lineW ) { + vbo->addVertex( Vector2f( pos.x + ( radiW - lineW ) * Math::cosAng( i ), + pos.y + ( radiH - lineW ) * Math::sinAng( i ) ) ); + } else { + vbo->addVertex( startPos ); + } + + vbo->addColor( color ); + + if ( i + angleShift < endAngle ) { + vbo->addVertex( Vector2f( pos.x + radiW * Math::cosAng( i + angleShift ), + pos.y + radiH * Math::sinAng( i + angleShift ) ) ); + } else { + vbo->addVertex( Vector2f( pos.x + radiW * Math::cosAng( endAngle ), + pos.y + radiH * Math::sinAng( endAngle ) ) ); + } + + vbo->addColor( color ); + + vbo->addVertex( + Vector2f( pos.x + radiW * Math::cosAng( i ), pos.y + radiH * Math::sinAng( i ) ) ); + vbo->addColor( color ); + + if ( radiW > lineW ) { + vbo->addVertex( Vector2f( pos.x + ( radiW - lineW ) * Math::cosAng( i ), + pos.y + ( radiH - lineW ) * Math::sinAng( i ) ) ); + } else { + vbo->addVertex( startPos ); + } + + vbo->addColor( color ); + } + } else { + for ( double i = startAngle; i <= endAngle; i += angleShift ) { + if ( radiW > lineW ) { + vbo->addVertex( Vector2f( pos.x + ( radiW - lineW ) * Math::cosAng( i ), + pos.y + ( radiH - lineW ) * Math::sinAng( i ) ) ); + } else { + vbo->addVertex( startPos ); + } + + vbo->addColor( color ); + + vbo->addVertex( + Vector2f( pos.x + radiW * Math::cosAng( i ), pos.y + radiH * Math::sinAng( i ) ) ); + vbo->addColor( color ); + + if ( i + angleShift < endAngle ) { + vbo->addVertex( Vector2f( pos.x + radiW * Math::cosAng( i + angleShift ), + pos.y + radiH * Math::sinAng( i + angleShift ) ) ); + } else { + vbo->addVertex( Vector2f( pos.x + radiW * Math::cosAng( endAngle ), + pos.y + radiH * Math::sinAng( endAngle ) ) ); + } + vbo->addColor( color ); + + if ( radiW > lineW ) { + vbo->addVertex( Vector2f( pos.x + ( radiW - lineW ) * Math::cosAng( i ), + pos.y + ( radiH - lineW ) * Math::sinAng( i ) ) ); + } else { + vbo->addVertex( startPos ); + } + + vbo->addColor( color ); + } + } +} + +void UIBorderDrawable::createBorders( VertexBuffer* vbo, const UIBorderDrawable::Borders& borders, + const Vector2f& pos, const Sizef& size ) { + vbo->clear(); + + int borderTop = 0; + int borderBottom = 0; + int borderLeft = 0; + int borderRight = 0; + Float halfWidth = size.getWidth() * 0.5f; + Float halfHeight = size.getHeight() * 0.5f; + + if ( borders.top.width >= 0 ) { + borderTop = eemin( (int)( size.getHeight() * 0.5f ), (int)borders.top.width ); + } + + if ( borders.bottom.width >= 0 ) { + borderBottom = eemin( (int)( size.getHeight() * 0.5f ), (int)borders.bottom.width ); + } + + if ( borders.left.width >= 0 ) { + borderLeft = eemin( (int)( size.getWidth() * 0.5f ), (int)borders.left.width ); + } + + if ( borders.right.width >= 0 ) { + borderRight = eemin( (int)( size.getWidth() * 0.5f ), (int)borders.right.width ); + } + + // draw top border + if ( borderTop ) { + double leftW = eemin( halfWidth, eemax( 0.f, borders.radius.topLeftX ) ); + double rightW = eemin( halfHeight, eemax( 0.f, borders.radius.topRightX ) ); + double leftH = eemin( halfWidth, eemax( 0.f, borders.radius.topLeftY ) ); + double rightH = eemin( halfHeight, eemax( 0.f, borders.radius.topRightY ) ); + + if ( leftW ) { + double endAngle = Math::degrees( M_PI * 3.0 / 2.0 ); + double startAngle = Math::degrees( + M_PI * 3.0 / 2.0 - M_PI / 2.0 / ( (double)borderLeft / (double)borderTop + 1 ) ); + + borderAddArc( vbo, Vector2f( pos.x + leftW, pos.y + leftH ), leftW, leftH, startAngle, + 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 ); + } + + if ( rightW ) { + vbo->addVertex( Vector2f( pos.x + size.getWidth() - rightW, pos.y ) ); + vbo->addColor( borders.top.color ); + + Vector2f basePos( pos.x + size.getWidth() - borderRight, pos.y + borderTop ); + + double startAngle = Math::degrees( M_PI * 3.0 / 2.0 ); + double endAngle = Math::degrees( + M_PI * 3.0 / 2.0 + M_PI / 2.0 / ( (double)borderRight / (double)borderTop + 1 ) ); + + borderAddArc( vbo, Vector2f( pos.x + size.getWidth() - rightW, pos.y + rightH ), 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 ); + } + } + + // draw right border + if ( borderRight ) { + double topW = eemin( halfWidth, eemax( 0.f, borders.radius.topRightX ) ); + double bottomW = eemin( halfHeight, eemax( 0.f, borders.radius.bottomRightX ) ); + double topH = eemin( halfWidth, eemax( 0.f, borders.radius.topRightY ) ); + double bottomH = eemin( halfHeight, eemax( 0.f, borders.radius.bottomRightY ) ); + + if ( topW ) { + double endAngle = Math::degrees( 2 * M_PI ); + double startAngle = Math::degrees( + 2 * M_PI - M_PI / 2.0 / ( (double)borderTop / (double)borderRight + 1 ) ); + + Vector2f basePos( pos.x + size.getWidth() - borderRight, pos.y + borderTop ); + + 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 ); + } + + if ( bottomH ) { + vbo->addVertex( + Vector2f( pos.x + size.getWidth(), pos.y + size.getHeight() - bottomH ) ); + vbo->addColor( borders.right.color ); + + Vector2f basePos( pos.x + size.getWidth() - borderRight, + pos.y + size.getHeight() - borderBottom ); + double startAngle = Math::degrees( 0 ); + double endAngle = + Math::degrees( M_PI / 2.0 / ( (double)borderBottom / (double)borderRight + 1 ) ); + + borderAddArc( + vbo, + Vector2f( pos.x + size.getWidth() - bottomW, pos.y + size.getHeight() - bottomH ), + bottomW, bottomH, startAngle, endAngle, borders.right.color, 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 ); + } + } + + // draw bottom border + if ( borderBottom ) { + double leftW = eemin( halfWidth, eemax( 0.f, borders.radius.bottomLeftX ) ); + double rightW = eemin( halfHeight, eemax( 0.f, borders.radius.bottomRightX ) ); + double leftH = eemin( halfWidth, eemax( 0.f, borders.radius.bottomLeftY ) ); + double rightH = eemin( halfHeight, eemax( 0.f, borders.radius.bottomRightY ) ); + + if ( rightW ) { + double endAngle = Math::degrees( M_PI / 2.0 ); + double startAngle = Math::degrees( + M_PI / 2.0 - M_PI / 2.0 / ( (double)borderRight / (double)borderBottom + 1 ) ); + Vector2f basePos( pos.x + size.getWidth() - borderRight, + pos.y + size.getHeight() - borderBottom ); + borderAddArc( + vbo, + 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 ); + } + + if ( leftW ) { + double startAngle = Math::degrees( M_PI / 2.0 ); + double endAngle = Math::degrees( + M_PI / 2.0 + M_PI / 2.0 / ( (double)borderLeft / (double)borderBottom + 1 ) ); + + Vector2f basePos( pos.x + borderLeft, pos.y + size.getHeight() - borderBottom ); + + Vector2f tPos( Vector2f( pos.x + leftW, pos.y + size.getHeight() - leftH ) ); + vbo->addVertex( Vector2f( tPos.x + leftW * Math::cosAng( startAngle ), + tPos.y + leftH * Math::sinAng( startAngle ) ) ); + vbo->addColor( borders.bottom.color ); + + 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 ); + } + } + + // draw left border + if ( borderLeft ) { + double topW = eemin( halfWidth, eemax( 0.f, borders.radius.topLeftX ) ); + double bottomW = eemin( halfHeight, eemax( 0.f, borders.radius.bottomLeftX ) ); + double topH = eemin( halfWidth, eemax( 0.f, borders.radius.topLeftY ) ); + double bottomH = eemin( halfHeight, eemax( 0.f, borders.radius.bottomLeftY ) ); + + if ( bottomW ) { + Vector2f basePos( pos.x + borderLeft, pos.y + size.getHeight() - borderBottom ); + + double endAngle = Math::degrees( M_PI ); + double startAngle = Math::degrees( + M_PI - M_PI / 2.0 / ( (double)borderBottom / (double)borderLeft + 1 ) ); + + borderAddArc( vbo, Vector2f( pos.x + bottomW, pos.y + size.getHeight() - bottomH ), + 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 ); + } + + if ( topW ) { + double startAngle = Math::degrees( M_PI ); + double endAngle = + Math::degrees( M_PI + M_PI / 2.0 / ( (double)borderTop / (double)borderLeft + 1 ) ); + + Vector2f basePos( pos.x + borderLeft, pos.y + borderTop ); + Vector2f tPos( pos.x + topW, pos.y + topW ); + vbo->addVertex( Vector2f( tPos.x + topW * Math::cosAng( startAngle ), + tPos.y + topH * Math::sinAng( startAngle ) ) ); + vbo->addColor( borders.left.color ); + + 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 ); + } + } +} + +UIBorderDrawable* UIBorderDrawable::New() { + return eeNew( UIBorderDrawable, () ); +} + +UIBorderDrawable::UIBorderDrawable() : + Drawable( UIBORDERDRAWABLE ), + mVertexBuffer( + VertexBuffer::NewVertexArray( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_STRIP ) ), + mBorderType( BorderType::Inside ), + mNeedsUpdate( false ), + mColorNeedsUpdate( false ) {} + +UIBorderDrawable::~UIBorderDrawable() {} + +void UIBorderDrawable::draw() {} + +void UIBorderDrawable::draw( const Vector2f& position ) {} + +void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { + if ( mPosition != position ) { + mPosition = position; + mNeedsUpdate = true; + } + + if ( mSize != size ) { + mSize = size; + mNeedsUpdate = true; + } + + if ( mNeedsUpdate || mColorNeedsUpdate ) { + update(); + } + + mVertexBuffer->bind(); + //GLi->enable( GL_CULL_FACE ); + mVertexBuffer->draw(); + //GLi->disable( GL_CULL_FACE ); + mVertexBuffer->unbind(); +} + +bool UIBorderDrawable::isStateful() { + return false; +} + +void UIBorderDrawable::setLineWidth( const Float& width ) { + if ( mBorders.top.width != width || mBorders.left.width != width || + mBorders.right.width != width || mBorders.bottom.width != width ) { + mBorders.top.width = mBorders.left.width = mBorders.right.width = mBorders.bottom.width = + width; + mNeedsUpdate = true; + } +} + +Sizef UIBorderDrawable::getSize() { + return mSize; +} + +Float UIBorderDrawable::getLineWidth() const { + return mBorders.top.width; +} + +Int32 UIBorderDrawable::getRadius() const { + return mBorders.radius.topLeftX; +} + +void UIBorderDrawable::setRadius( const Int32& radius ) { + if ( mBorders.radius.topLeftX != radius ) { + mBorders.radius.topLeftX = radius; + mBorders.radius.topLeftY = radius; + mBorders.radius.topRightX = radius; + mBorders.radius.topRightY = radius; + mBorders.radius.bottomLeftX = radius; + mBorders.radius.bottomLeftY = radius; + mBorders.radius.bottomRightX = radius; + mBorders.radius.bottomRightY = radius; + mNeedsUpdate = true; + } +} + +Color UIBorderDrawable::getColorLeft() const { + return mBorders.left.color; +} + +void UIBorderDrawable::setColorLeft( const Color& colorLeft ) { + if ( mBorders.left.color != colorLeft ) { + mBorders.left.color = colorLeft; + mColorNeedsUpdate = true; + } +} + +Color UIBorderDrawable::getColorRight() const { + return mBorders.right.color; +} + +void UIBorderDrawable::setColorRight( const Color& colorRight ) { + if ( mBorders.left.color != colorRight ) { + mBorders.left.color = colorRight; + mColorNeedsUpdate = true; + } +} + +Color UIBorderDrawable::getColorTop() const { + return mBorders.top.color; +} + +void UIBorderDrawable::setColorTop( const Color& colorTop ) { + if ( mBorders.top.color != colorTop ) { + mBorders.top.color = colorTop; + mColorNeedsUpdate = true; + } +} + +Color UIBorderDrawable::getColorBottom() const { + return mBorders.bottom.color; +} + +void UIBorderDrawable::setColorBottom( const Color& colorBottom ) { + if ( mBorders.bottom.color != colorBottom ) { + mBorders.bottom.color = colorBottom; + mColorNeedsUpdate = true; + } +} + +const BorderType& UIBorderDrawable::getBorderType() const { + return mBorderType; +} + +void UIBorderDrawable::setBorderType( const BorderType& borderType ) { + if ( mBorderType != borderType ) { + mBorderType = borderType; + mNeedsUpdate = true; + } +} + +void UIBorderDrawable::onAlphaChange() { + mBorders.left.color.a = mBorders.right.color.a = mBorders.top.color.a = + mBorders.bottom.color.a = mColor.a; + mColorNeedsUpdate = true; +} + +void UIBorderDrawable::onColorFilterChange() { + Drawable::onColorFilterChange(); + mBorders.left.color = mBorders.right.color = mBorders.top.color = mBorders.bottom.color = + mColor; + mColorNeedsUpdate = true; +} + +void UIBorderDrawable::onPositionChange() { + mNeedsUpdate = true; +} + +void UIBorderDrawable::update() { + switch ( mBorderType ) { + case BorderType::Outside: { + Vector2f pos( mPosition ); + Sizef size( mSize ); + + if ( mBorders.top.width > 0 ) { + pos.y -= mBorders.top.width; + } + + if ( mBorders.left.width > 0 ) { + pos.x -= mBorders.left.width; + } + + if ( mBorders.right.width > 0 ) { + size.x += mBorders.right.width * 2; + } + + if ( mBorders.bottom.width > 0 ) { + size.y += mBorders.bottom.width * 2; + } + + createBorders( mVertexBuffer, mBorders, pos, size ); + + break; + } + case BorderType::Inside: { + createBorders( mVertexBuffer, mBorders, mPosition, mSize ); + break; + } + } + + mColorNeedsUpdate = false; + mNeedsUpdate = false; +} + +void UIBorderDrawable::updateColor() { + update(); +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 27b24d1e6..96f4c499f 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -12,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -443,13 +443,13 @@ Color UINode::getBackgroundColor() const { } UINode* UINode::setBorderRadius( const unsigned int& corners ) { - setBorderEnabled( true )->setCorners( corners ); + setBorderEnabled( true )->setRadius( corners ); setBackgroundFillEnabled( true )->setBorderRadius( corners ); return this; } Uint32 UINode::getBorderRadius() const { - return NULL != mBorder ? mBorder->getCorners() : 0; + return NULL != mBorder ? mBorder->getRadius() : 0; } UINodeDrawable* UINode::setForegroundFillEnabled( bool enabled ) { @@ -512,7 +512,7 @@ Uint32 UINode::getForegroundRadius() const { return NULL != mForeground ? mForeground->getBorderRadius() : 0; } -RectangleDrawable* UINode::setBorderEnabled( bool enabled ) { +UIBorderDrawable* UINode::setBorderEnabled( bool enabled ) { writeFlag( UI_BORDER, enabled ? 1 : 0 ); if ( enabled && NULL == mBorder ) { @@ -587,16 +587,13 @@ UINode* UINode::resetFlags( Uint32 newFlags ) { void UINode::drawBackground() { if ( ( mFlags & UI_FILL_BACKGROUND ) && NULL != mBackground ) { - mBackground->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), - Sizef( eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ) ), - mAlpha ); + mBackground->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), mSize.floor(), mAlpha ); } } void UINode::drawForeground() { if ( ( mFlags & UI_FILL_FOREGROUND ) && NULL != mForeground ) { - mForeground->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), - Sizef( eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ) ), + mForeground->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), mSize.floor(), (Uint32)mAlpha ); } } @@ -605,8 +602,7 @@ void UINode::drawBorder() { if ( ( mFlags & UI_BORDER ) && NULL != mBorder ) { Uint8 alpha = mBorder->getAlpha(); mBorder->setAlpha( eemin( mAlpha * alpha / 255.f, 255 ) ); - mBorder->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), - Sizef( eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ) ) ); + mBorder->draw( mScreenPosi.asFloat(), mSize.floor() ); mBorder->setAlpha( alpha ); } } @@ -666,11 +662,10 @@ UINodeDrawable* UINode::getForeground() { return mForeground; } -RectangleDrawable* UINode::getBorder() { +UIBorderDrawable* UINode::getBorder() { if ( NULL == mBorder ) { - mBorder = RectangleDrawable::New(); + mBorder = UIBorderDrawable::New(); mBorder->setColor( Color::Transparent ); - mBorder->setFillMode( PrimitiveFillMode::DRAW_LINE ); mBorder->setLineWidth( PixelDensity::dpToPx( 1 ) ); } diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 6a3abbae7..f9c33f16a 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -1167,6 +1168,8 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, return String::toStr( getBorderRadius() ); case PropertyId::BorderWidth: return String::fromFloat( getBorderWidth() ); + case PropertyId::BorderType: + return getBorder()->getBorderType() == BorderType::Inside ? "inside" : "outside"; case PropertyId::SkinColor: return getSkinColor().toHexString(); case PropertyId::Rotation: @@ -1300,6 +1303,10 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::BorderRadius: setBorderRadius( lengthFromValue( attribute ) ); break; + case PropertyId::BorderType: + getBorder()->setBorderType( attribute.getValue() == "inside" ? BorderType::Inside + : BorderType::Outside ); + break; case PropertyId::Visible: setVisible( attribute.asBool() ); break;