diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 5ca62475d..e2830b334 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -79,6 +79,8 @@ Tooltip { backgroundColor: #33FF3333; backgroundImage: linear-gradient( #8c8886, #585857 ); borderRadius: 12; + textSize: 24dp; + padding: 12dp; transition: scale 0.25s, rotation 0.25s 0.25s, borderColor 0.25s, backgroundColor 0.25s, borderRadius 0.25s; } @@ -94,6 +96,7 @@ Tooltip { layout_marginLeft: 0; padding: 24dp; opacity: 0.8; + textSize: 24dp; backgroundColor: #333; transition: all 0.25s; } @@ -132,9 +135,16 @@ Tooltip { padding: 22dp 12dp 120dp 12dp; } +#chbox, +#rdbut { + textSize:24dp; + padding: 12dp; + backgroundColor: #333; +} + #tres { -/* width: 32dp; - height: 32dp;*/ + backgroundColor: #444; + padding: 8dp; transition: all 0.25s; } @@ -150,3 +160,171 @@ Tooltip { #pbut:hover { skinColor: #66ff44; } + +#test_2 > #rtest { + padding: 8dp; + background: #221122; +} + +#test_2 > #rtest #rttv { + background: #333; + textSize: 24dp; + borderRadius: 8; + padding: 8dp; + transition: all 0.125s; +} + +#test_2 > #rtest #rttv:hover { + background: #666; +} + +#test_2 > #rtest:hover #rttv { + background: #005522; +} + +#test_2 > #rtest:hover #rttv:hover { + background: #008822; +} + +#test_2 > #rtest:hover #rttv:pressed { + background: lime; + textColor: #333; +} + +#test_3 { + background: #221122; +} + +#test_3 > .rooter { + background: red; +} + +#test_3 > .rooter .outer { + background: blue; + transition: all 0.125s; +} + +#test_3 > .rooter:hover .outer { + background: green; +} + +#test_3 > .rooter:hover .outer:hover { + background: yellow; +} + +#test_3 > .rooter .inner { + background: #123456; + transition: all 0.125s; +} + +#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; + transition: all 0.125s; +} + +#test_4 > RelativeLayout:hover { + backgroundColor: #442244; + cursor: hand; +} + +#test_4 > RelativeLayout:pressed { + backgroundColor: #662266; +} + +#test_4 > RelativeLayout > TextView { + transition: all 0.125s; +} + +#test_4 > RelativeLayout:hover > TextView { + layout_marginLeft: 8dp; +} + +TabWidget { + paddingLeft: 8dp; + paddingRight: 8dp; + paddingBottom: 8dp; + paddingTop: 20dp; + backgroundColor: #656565; +} + +#lvbox { + backgroundColor: #222; + padding: 12dp; +} + +.list { + textSize: 16dp; + padding: 8dp; +} + +#tviewl { + textSize: 24dp; + backgroundColor: #333; +} + +#tinput { + textSize: 24dp; + padding: 24dp; +} + +#rvbox { + backgroundColor: #323232; + padding: 12dp; +} + +#rrl { + backgroundColor: #999; + padding: 24dp; +} + +#rrl > #tmap { + textSize: 24dp; + padding: 12dp; + backgroundColor: #333; +} + +.eltv { + textSize: 24dp; + padding: 12dp; + backgroundColor: #242424; +} + +#rrl > #el2, +#rrl > #tm, +#rrl > #tmp { + layout_margin: 12dp; +} + +#rrl > #slider { + padding: 32dp; + backgroundColor: #555; +} + +#rrl > #scrollbar { + padding: 8dp; + backgroundColor: #12345666; +} + +#rrl > #spinbox { + padding: 8dp; + backgroundColor: #54345666; +} + +#rrl > TextEdit { + padding: 16dp; + layout_marginBottom: 140dp; +} diff --git a/bin/assets/layouts/test.xml b/bin/assets/layouts/test.xml index 5627678a5..c543d255e 100644 --- a/bin/assets/layouts/test.xml +++ b/bin/assets/layouts/test.xml @@ -1,56 +1,71 @@ - + - - - + + + - - - - - + + + + + Test Test 2 Test 3 - + Test Test 2 Test 3 - + - - - - - - - + + + + + + + - - - - + - + - + - + - + + + + + + + + + + + + + + + + + + + diff --git a/bin/assets/layouts/test_widgets.xml b/bin/assets/layouts/test_widgets.xml index f89f09682..fee28a16a 100644 --- a/bin/assets/layouts/test_widgets.xml +++ b/bin/assets/layouts/test_widgets.xml @@ -1,7 +1,7 @@ - + - + @@ -31,17 +31,17 @@ - - - - - - - + + + + + + + - - + + 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/graphics/fontsprite.hpp b/include/eepp/graphics/fontsprite.hpp index ad57bf509..7ae7f9d0e 100644 --- a/include/eepp/graphics/fontsprite.hpp +++ b/include/eepp/graphics/fontsprite.hpp @@ -21,13 +21,13 @@ class EE_API FontSprite : public Font { ~FontSprite(); - bool loadFromFile(const std::string& filename, Color key = Color::Magenta, Uint32 firstChar = 32, int spacing = 0); + bool loadFromFile(const std::string& filename, Color key = Color::Fuchsia, Uint32 firstChar = 32, int spacing = 0); - bool loadFromMemory(const void* data, std::size_t sizeInBytes, Color key = Color::Magenta, Uint32 firstChar = 32, int spacing = 0); + bool loadFromMemory(const void* data, std::size_t sizeInBytes, Color key = Color::Fuchsia, Uint32 firstChar = 32, int spacing = 0); - bool loadFromStream( IOStream& stream, Color key = Color::Magenta, Uint32 firstChar = 32, int spacing = 0 ); + bool loadFromStream( IOStream& stream, Color key = Color::Fuchsia, Uint32 firstChar = 32, int spacing = 0 ); - bool loadFromPack( Pack * pack, std::string filePackPath, Color key = Color::Magenta, Uint32 firstChar = 32, int spacing = 0 ); + bool loadFromPack( Pack * pack, std::string filePackPath, Color key = Color::Fuchsia, Uint32 firstChar = 32, int spacing = 0 ); const Font::Info& getInfo() const; diff --git a/include/eepp/graphics/texturefactory.hpp b/include/eepp/graphics/texturefactory.hpp index d16bf5051..d0fadbd8b 100755 --- a/include/eepp/graphics/texturefactory.hpp +++ b/include/eepp/graphics/texturefactory.hpp @@ -26,9 +26,10 @@ class EE_API TextureFactory : protected Mutex { * @param ClampMode Defines the CLAMP MODE * @param CompressTexture If use the DXT compression on the texture loading ( if the card can display them, will convert RGB to DXT1, RGBA to DXT5 ) * @param KeepLocalCopy Keep the array data copy. ( useful if want to reload the texture ) + * @param FileName A filename to recognize the texture. * @return Internal Texture Id */ - Uint32 createEmptyTexture( const unsigned int& Width, const unsigned int& Height, const unsigned int& Channels = 4, const Color& DefaultColor = Color(0,0,0,255), const bool& Mipmap = false, const Texture::ClampMode& ClampMode = Texture::ClampMode::ClampToEdge, const bool& CompressTexture = false, const bool& KeepLocalCopy = false ); + Uint32 createEmptyTexture( const unsigned int& Width, const unsigned int& Height, const unsigned int& Channels = 4, const Color& DefaultColor = Color(0,0,0,255), const bool& Mipmap = false, const Texture::ClampMode& ClampMode = Texture::ClampMode::ClampToEdge, const bool& CompressTexture = false, const bool& KeepLocalCopy = false, const std::string& Filename = std::string("") ); /** Loads a RAW Texture from Memory * @param Pixels The Texture array diff --git a/include/eepp/graphics/textureloader.hpp b/include/eepp/graphics/textureloader.hpp index 5bae18e83..c10ccf10c 100644 --- a/include/eepp/graphics/textureloader.hpp +++ b/include/eepp/graphics/textureloader.hpp @@ -109,20 +109,20 @@ class EE_API TextureLoader : public ObjectLoader { Int32 mImgHeight; std::string mFilepath; - unsigned int mWidth; - unsigned int mHeight; + unsigned int mWidth; + unsigned int mHeight; bool mMipmap; Int32 mChannels; Texture::ClampMode mClampMode; bool mCompressTexture; bool mLocalCopy; - Pack * mPack; + Pack * mPack; IOStream * mStream; const Uint8 * mImagePtr; Uint32 mSize; - RGB * mColorKey; + RGB * mColorKey; Image::FormatConfiguration mFormatConfiguration; void start(); 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/event.hpp b/include/eepp/scene/event.hpp index 344f8790d..8830deb22 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -52,6 +52,7 @@ class EE_API Event { OnClose, // Warning: Only some controls will report this event. OnDragStart, OnDragStop, + OnPaddingChange, UserEvent, NoEvent = eeINDEX_NOT_FOUND }; 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/scene/nodeattribute.hpp b/include/eepp/scene/nodeattribute.hpp index 7ed311d21..acf32f196 100644 --- a/include/eepp/scene/nodeattribute.hpp +++ b/include/eepp/scene/nodeattribute.hpp @@ -62,7 +62,7 @@ class NodeAttribute { const std::string& getName() const; - const std::vector getParameters() const; + const std::vector& getParameters() const; bool isEmpty() const; protected: @@ -73,10 +73,12 @@ class NodeAttribute { NodeAttribute(); - NodeAttribute( std::string name, std::string value ); + NodeAttribute( std::string name, std::string value, bool isVolatile = false ); bool isEmpty() const; + bool isVolatile() const; + std::string getName() const; void setName(const std::string & name); @@ -141,6 +143,7 @@ class NodeAttribute { protected: std::string mName; std::string mValue; + bool mVolatile; }; }} diff --git a/include/eepp/system/color.hpp b/include/eepp/system/color.hpp index 98e38c7f5..4d7d36b25 100755 --- a/include/eepp/system/color.hpp +++ b/include/eepp/system/color.hpp @@ -241,22 +241,22 @@ class EE_API Color : public tColor static bool isColorString( std::string str ); static const Color Transparent; - static const Color White; static const Color Black; - static const Color Red; - static const Color Green; - static const Color Blue; - static const Color Yellow; - static const Color Cyan; - static const Color Magenta; static const Color Silver; static const Color Gray; + static const Color White; static const Color Maroon; - static const Color Olive; - static const Color OfficeGreen; + static const Color Red; static const Color Purple; - static const Color Teal; + static const Color Fuchsia; + static const Color Green; + static const Color Lime; + static const Color Olive; + static const Color Yellow; static const Color Navy; + static const Color Blue; + static const Color Teal; + static const Color Aqua; }; typedef Color ColorA; diff --git a/include/eepp/ui/css/stylesheet.hpp b/include/eepp/ui/css/stylesheet.hpp index 869b55891..d82e7899d 100644 --- a/include/eepp/ui/css/stylesheet.hpp +++ b/include/eepp/ui/css/stylesheet.hpp @@ -23,14 +23,8 @@ class EE_API StyleSheet { void combineStyleSheet( const StyleSheet& styleSheet ); - StyleSheetPseudoClassProperties getElementPropertiesByState( StyleSheetElement * element ); - StyleSheetStyleVector getElementStyles( StyleSheetElement * element, const bool& applyPseudo = false ); - StyleSheetStyleVector getCacheableElementStyles( StyleSheetElement * element, const bool& applyPseudo = false ); - - StyleSheetStyleVector getNoncacheableElementStyles( StyleSheetElement * element, const bool& applyPseudo = false ); - const StyleSheetStyleList& getStyles() const; protected: StyleSheetStyleList mNodes; diff --git a/include/eepp/ui/css/stylesheetpropertiesparser.hpp b/include/eepp/ui/css/stylesheetpropertiesparser.hpp index b85cf438b..8ccaad29b 100644 --- a/include/eepp/ui/css/stylesheetpropertiesparser.hpp +++ b/include/eepp/ui/css/stylesheetpropertiesparser.hpp @@ -26,7 +26,7 @@ class EE_API StyleSheetPropertiesParser { ReadingComment }; - ReadState prevRs; + ReadState mPrevRs; StyleSheetProperties mProperties; @@ -39,6 +39,8 @@ class EE_API StyleSheetPropertiesParser { int readComment( ReadState& rs, std::size_t pos, std::string& buffer, const std::string& str ); int readValueUrl( ReadState& rs, std::size_t pos, std::string& buffer, const std::string& str ); + + void addProperty( const std::string& name, std::string value ); }; }}} diff --git a/include/eepp/ui/css/stylesheetproperty.hpp b/include/eepp/ui/css/stylesheetproperty.hpp index 9dff66cae..1c2b6f42d 100644 --- a/include/eepp/ui/css/stylesheetproperty.hpp +++ b/include/eepp/ui/css/stylesheetproperty.hpp @@ -13,7 +13,7 @@ class EE_API StyleSheetProperty { explicit StyleSheetProperty( const std::string& name, const std::string& value ); - explicit StyleSheetProperty( const std::string& name, const std::string& value, const Uint32& specificity ); + explicit StyleSheetProperty( const std::string& name, const std::string& value, const Uint32& specificity, const bool& isVolatile = false ); const std::string& getName() const; @@ -28,10 +28,15 @@ class EE_API StyleSheetProperty { void setName(const std::string & name); void setValue(const std::string & value); + + const bool& isVolatile() const; + + void setVolatile( const bool& isVolatile ); protected: std::string mName; std::string mValue; Uint32 mSpecificity; + bool mVolatile; }; typedef std::map StyleSheetProperties; diff --git a/include/eepp/ui/css/stylesheetselector.hpp b/include/eepp/ui/css/stylesheetselector.hpp index 7d1b367fd..d2f519abe 100644 --- a/include/eepp/ui/css/stylesheetselector.hpp +++ b/include/eepp/ui/css/stylesheetselector.hpp @@ -23,6 +23,12 @@ class EE_API StyleSheetSelector { bool select( StyleSheetElement * element, const bool& applyPseudo = true ) const; const bool& isCacheable() const; + + bool hasPseudoClass(const std::string& cls) const; + + bool hasPseudoClasses() const; + + std::vector getRelatedElements( StyleSheetElement * element, const bool& applyPseudo = true ) const; protected: std::string mName; std::string mPseudoClass; diff --git a/include/eepp/ui/css/stylesheetselectorrule.hpp b/include/eepp/ui/css/stylesheetselectorrule.hpp index 3c081b1a0..8674f94b6 100644 --- a/include/eepp/ui/css/stylesheetselectorrule.hpp +++ b/include/eepp/ui/css/stylesheetselectorrule.hpp @@ -26,6 +26,8 @@ class StyleSheetSelectorRule { }; enum SpecificityVal { + SpecificityImportant = UINT32_MAX, + SpecificityInline = UINT32_MAX - 1, SpecificityId = 1000000, SpecificityClass = 100000, SpecificityTag = 10000, @@ -57,7 +59,7 @@ class StyleSheetSelectorRule { bool hasPseudoClasses() const; - bool hasPseudoClass(const std::string & cls) const; + bool hasPseudoClass(const std::string& cls) const; const std::vector& getPseudoClasses() const; diff --git a/include/eepp/ui/css/stylesheetstyle.hpp b/include/eepp/ui/css/stylesheetstyle.hpp index 0ef26ac12..bfe65926d 100644 --- a/include/eepp/ui/css/stylesheetstyle.hpp +++ b/include/eepp/ui/css/stylesheetstyle.hpp @@ -12,32 +12,24 @@ class EE_API StyleSheetStyle { explicit StyleSheetStyle( const std::string& selector, const StyleSheetProperties& properties ); - void print(); + std::string build(); const StyleSheetSelector& getSelector() const; const StyleSheetProperties& getProperties() const; + StyleSheetProperty getPropertyByName( const std::string& name ) const; + void setProperty( const StyleSheetProperty& property ); + + void clearProperties(); protected: StyleSheetSelector mSelector; StyleSheetProperties mProperties; }; -class EE_API StyleSheetStyleUsed { - public: - StyleSheetStyle style; - bool used; - - StyleSheetStyleUsed( StyleSheetStyle style, bool used ) : - style( style ), - used( used ) - {} -}; - typedef std::map StyleSheetStyleList; typedef std::vector StyleSheetStyleVector; -typedef std::vector StyleSheetStyleUsedVector; }}} diff --git a/include/eepp/ui/uicombobox.hpp b/include/eepp/ui/uicombobox.hpp index 075028870..3a1b3520f 100644 --- a/include/eepp/ui/uicombobox.hpp +++ b/include/eepp/ui/uicombobox.hpp @@ -42,6 +42,8 @@ class EE_API UIComboBox : public UIWidget { virtual void onPositionChange(); + virtual void onPaddingChange(); + virtual void onAutoSize(); }; diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index d2f023253..9def26262 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -89,44 +89,28 @@ class EE_API UINode : public Node { UISkin * setBackgroundFillEnabled( bool enabled ); - UINode * setBackgroundDrawable( const Uint32 & state, Drawable * drawable , bool ownIt = false ); - UINode * setBackgroundDrawable( Drawable * drawable , bool ownIt = false ); - UINode * setBackgroundColor( const Uint32 & state, const Color& color ); - UINode * setBackgroundColor( const Color& color ); - Color getBackgroundColor( const Uint32 & state ) const; - Color getBackgroundColor() const; - UINode * setBorderRadius( const Uint32 & state, const unsigned int& corners ); - UINode * setBorderRadius( const unsigned int& corners ); - Uint32 getBorderRadius( const Uint32& state ) const; - Uint32 getBorderRadius() const; UISkin * setForegroundFillEnabled( bool enabled ); - UINode * setForegroundDrawable( const Uint32 & state, Drawable * drawable , bool ownIt = false ); - UINode * setForegroundDrawable( Drawable * drawable , bool ownIt = false ); - UINode * setForegroundColor( const Uint32 & state, const Color& color ); - UINode * setForegroundColor( const Color& color ); - Color getForegroundColor( const Uint32 & state ) const; - Color getForegroundColor() const; - UINode * setForegroundRadius( const Uint32 & state, const unsigned int& corners ); - UINode * setForegroundRadius( const unsigned int& corners ); + Uint32 getForegroundRadius() const; + RectangleDrawable * setBorderEnabled( bool enabled ); UINode * setBorderColor( const Color& color ); @@ -135,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 ); @@ -165,13 +151,9 @@ class EE_API UINode : public Node { UINode * setSkin( UISkin * skin ); - UINode * setSkinColor( const Uint32& state, const Color& color ); - UINode * setSkinColor( const Color& color ); - Color getSkinColor( const Uint32& state )const; - - Color getSkinColor() const; + const Color& getSkinColor() const; void removeSkin(); @@ -213,6 +195,7 @@ class EE_API UINode : public Node { RectangleDrawable * mBorder; Vector2f mDragPoint; Uint32 mDragButton; + Color mSkinColor; virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags ); diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 5efa9dd1c..ac73484c4 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -44,8 +44,12 @@ class EE_API UISceneNode : public SceneNode { void setStyleSheet( const CSS::StyleSheet& styleSheet ); + void setStyleSheet( const std::string& inlineStyleSheet ); + void combineStyleSheet( const CSS::StyleSheet& styleSheet ); + void combineStyleSheet( const std::string& inlineStyleSheet ); + CSS::StyleSheet& getStyleSheet(); bool hasStyleSheet(); diff --git a/include/eepp/ui/uiscrollview.hpp b/include/eepp/ui/uiscrollview.hpp index 7767f2da8..e7fc5e044 100644 --- a/include/eepp/ui/uiscrollview.hpp +++ b/include/eepp/ui/uiscrollview.hpp @@ -38,7 +38,7 @@ class EE_API UIScrollView : public UITouchDragableWidget { UIScrollBar * getHorizontalScrollBar() const; - UINode * getContainer() const; + UIWidget * getContainer() const; virtual bool setAttribute( const NodeAttribute& attribute, const Uint32& state = UIState::StateFlagNormal ); protected: @@ -47,7 +47,7 @@ class EE_API UIScrollView : public UITouchDragableWidget { UI_SCROLLBAR_MODE mHScrollMode; UIScrollBar * mVScroll; UIScrollBar * mHScroll; - UINode * mContainer; + UIWidget * mContainer; Node * mScrollView; Uint32 mSizeChangeCb; diff --git a/include/eepp/ui/uistate.hpp b/include/eepp/ui/uistate.hpp index 74d059218..b7f235441 100644 --- a/include/eepp/ui/uistate.hpp +++ b/include/eepp/ui/uistate.hpp @@ -37,6 +37,8 @@ class EE_API UIState { static int getStateNumber(const std::string & State); + static const char * getStateNameFromStateFlag( const Uint32& stateFlag ); + static const Uint32& getStateFlag( const Uint32& stateIndex ); static Uint32 getStateFlagFromName( const std::string& name ); diff --git a/include/eepp/ui/uistyle.hpp b/include/eepp/ui/uistyle.hpp index 697356a9a..812387880 100644 --- a/include/eepp/ui/uistyle.hpp +++ b/include/eepp/ui/uistyle.hpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include using namespace EE::Scene; @@ -31,7 +33,7 @@ class EE_API UIStyle : public UIState { Ease::Interpolation getTimingFunction() const { return timingFunction; } - const Time& getDelay() const { return delay; }; + const Time& getDelay() const { return delay; } const Time& getDuration() const { return duration; } @@ -53,33 +55,49 @@ class EE_API UIStyle : public UIState { void onStateChange(); - CSS::StyleSheetProperty getStyleSheetProperty( const Uint32& state, const std::string& attributeName ) const; + CSS::StyleSheetProperty getStatelessStyleSheetProperty( const std::string& propertyName ) const; - CSS::StyleSheetProperty getStyleSheetPropertyFromNames( const Uint32& state, const std::vector& propertiesNames ) const; + CSS::StyleSheetProperty getStyleSheetProperty( const std::string& propertyName ) const; - NodeAttribute getNodeAttribute( const Uint32& state, const std::string& attributeName ) const; + NodeAttribute getNodeAttribute(const std::string& attributeName ) const; - bool hasStyleSheetProperty( const Uint32& state, const std::string& propertyName ) const; + void setStyleSheetProperties( const CSS::StyleSheetProperties& properties ); - void addStyleSheetProperties( const Uint32& state, const CSS::StyleSheetProperties& properties ); + void setStyleSheetProperty( const CSS::StyleSheetProperty& property ); - void addStyleSheetProperty( const Uint32& state, const CSS::StyleSheetProperty& property ); + bool hasTransition( const std::string& propertyName ); - bool hasTransition( const Uint32& state, const std::string& propertyName ); - - TransitionInfo getTransition( const Uint32& state, const std::string& propertyName ); + TransitionInfo getTransition( const std::string& propertyName ); protected: typedef std::map TransitionsMap; UIWidget * mWidget; - std::map mStates; - std::map mTransitions; - std::map> mTransitionAttributes; + CSS::StyleSheetStyleVector mCacheableStyles; CSS::StyleSheetStyleVector mNoncacheableStyles; + CSS::StyleSheetStyle mElementStyle; + CSS::StyleSheetProperties mProperties; + std::vector mTransitionAttributes; + TransitionsMap mTransitions; + std::set mRelatedWidgets; + std::set mSubscribedWidgets; + + void tryApplyStyle( const CSS::StyleSheetStyle& style ); void updateState(); - void parseTransitions( const Uint32& state ); + void parseTransitions(); + + void subscribeNonCacheableStyles(); + + void unsubscribeNonCacheableStyles(); + + void subscribeRelated( UIWidget * widget ); + + void unsubscribeRelated( UIWidget * widget ); + + void removeFromSubscribedWidgets( UIWidget * widget ); + + void removeRelatedWidgets(); }; }} diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index d99a9f64a..9463425d6 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -92,7 +92,7 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { void notifyLayoutAttrChangeParent(); - bool setAttribute( const std::string& name, const std::string& value, const Uint32& state = UIState::StateFlagNormal ); + void setStyleSheetProperty( const std::string& name, const std::string& value, const Uint32& specificity = UINT32_MAX - 1/*SpecificityInline*/ ); virtual bool setAttribute( const NodeAttribute& attribute, const Uint32& state = UIState::StateFlagNormal ); @@ -191,6 +191,8 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { virtual void onThemeLoaded(); + virtual void onParentChange(); + void updateAnchors( const Vector2f & SizeChange ); void alignAgainstLayout(); @@ -198,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/graphics/fontsprite.cpp b/src/eepp/graphics/fontsprite.cpp index 022079d28..98e5b5077 100644 --- a/src/eepp/graphics/fontsprite.cpp +++ b/src/eepp/graphics/fontsprite.cpp @@ -130,7 +130,7 @@ bool FontSprite::loadFromStream( IOStream& stream, Color key, Uint32 firstChar, xPosToRead = charSpacing; } - img.createMaskFromColor( Color::Magenta, 0 ); + img.createMaskFromColor( Color::Fuchsia, 0 ); Uint32 texId = TextureFactory::instance()->loadFromPixels( img.getPixelsPtr(), img.getWidth(), img.getHeight(), img.getChannels() ); diff --git a/src/eepp/graphics/rectangledrawable.cpp b/src/eepp/graphics/rectangledrawable.cpp index 8b2024e7e..3e4290182 100644 --- a/src/eepp/graphics/rectangledrawable.cpp +++ b/src/eepp/graphics/rectangledrawable.cpp @@ -94,9 +94,11 @@ Uint32 RectangleDrawable::getCorners() const { } void RectangleDrawable::setCorners(const Uint32 & corners) { - mCorners = corners; - mNeedsUpdate = true; - mRecreateVertexBuffer = true; + if ( corners != mCorners ) { + mCorners = corners; + mNeedsUpdate = true; + mRecreateVertexBuffer = true; + } } RectColors RectangleDrawable::getRectColors() const { diff --git a/src/eepp/graphics/texture.cpp b/src/eepp/graphics/texture.cpp index 8ea9c2b0a..8c60e482c 100755 --- a/src/eepp/graphics/texture.cpp +++ b/src/eepp/graphics/texture.cpp @@ -7,6 +7,10 @@ #include #include #include +#include +#include + +using namespace EE::Window; using namespace EE::Graphics::Private; namespace EE { namespace Graphics { @@ -123,8 +127,14 @@ void Texture::setName(const std::string & name) { } Uint8 * Texture::iLock( const bool& ForceRGBA, const bool& KeepFormat ) { + bool threaded = Engine::instance()->isSharedGLContextEnabled() && + Thread::getCurrentThreadId() != Engine::instance()->getMainThreadId(); + #ifndef EE_GLES if ( !( mFlags & TEX_FLAG_LOCKED ) ) { + if ( threaded ) + Engine::instance()->getCurrentWindow()->setGLContextThread(); + if ( ForceRGBA ) mChannels = 4; @@ -163,29 +173,40 @@ Uint8 * Texture::iLock( const bool& ForceRGBA, const bool& KeepFormat ) { mFlags |= TEX_FLAG_LOCKED; } + if ( threaded ) + Engine::instance()->getCurrentWindow()->unsetGLContextThread(); + return &mPixels[0]; #else if ( !( mFlags & TEX_FLAG_LOCKED ) ) { - TextureSaver saver( mTexture ); + if ( threaded ) + Engine::instance()->getCurrentWindow()->setGLContextThread(); - GLuint frameBuffer = 0; - GLi->genFramebuffers(1, &frameBuffer); + { + TextureSaver saver( mTexture ); - if ( frameBuffer ) { - allocate( mWidth * mHeight * 4 ); + GLuint frameBuffer = 0; + GLi->genFramebuffers(1, &frameBuffer); - GLint previousFrameBuffer; - glGetIntegerv( GL_FRAMEBUFFER_BINDING, &previousFrameBuffer ); - GLi->bindFramebuffer( GL_FRAMEBUFFER, frameBuffer ); - GLi->framebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0 ); - glReadPixels( 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &mPixels[0] ); - GLi->deleteFramebuffers(1, &frameBuffer); - GLi->bindFramebuffer( GL_FRAMEBUFFER, previousFrameBuffer ); + if ( frameBuffer ) { + allocate( mWidth * mHeight * 4 ); - mFlags |= TEX_FLAG_LOCKED; + GLint previousFrameBuffer; + glGetIntegerv( GL_FRAMEBUFFER_BINDING, &previousFrameBuffer ); + GLi->bindFramebuffer( GL_FRAMEBUFFER, frameBuffer ); + GLi->framebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0 ); + glReadPixels( 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &mPixels[0] ); + GLi->deleteFramebuffers(1, &frameBuffer); + GLi->bindFramebuffer( GL_FRAMEBUFFER, previousFrameBuffer ); - return &mPixels[0]; + mFlags |= TEX_FLAG_LOCKED; + } } + + if ( threaded ) + Engine::instance()->getCurrentWindow()->unsetGLContextThread(); + + return NULL != mPixels ? &mPixels[0] : NULL; } return NULL; @@ -389,38 +410,49 @@ void Texture::reload() { Int32 width = (Int32)mWidth; Int32 height = (Int32)mHeight; - TextureSaver saver( mTexture ); + bool threaded = Engine::instance()->isSharedGLContextEnabled() && + Thread::getCurrentThreadId() != Engine::instance()->getMainThreadId(); - Uint32 flags = ( mFlags & TEX_FLAG_MIPMAP ) ? SOIL_FLAG_MIPMAPS : 0; - flags = (mClampMode == ClampRepeat) ? (flags | SOIL_FLAG_TEXTURE_REPEATS) : flags; + if ( threaded ) + Engine::instance()->getCurrentWindow()->setGLContextThread(); - if ( ( mFlags & TEX_FLAG_COMPRESSED ) ) { - if ( isGrabed() ) - mTexture = SOIL_create_OGL_texture( reinterpret_cast ( &mPixels[0] ), &width, &height, mChannels, mTexture, flags | SOIL_FLAG_COMPRESS_TO_DXT ); - else - glCompressedTexImage2D( mTexture, 0, mInternalFormat, width, height, 0, mSize, &mPixels[0] ); - } else { - mTexture = SOIL_create_OGL_texture( reinterpret_cast ( &mPixels[0] ), &width, &height, mChannels, mTexture, flags ); + { + TextureSaver saver( mTexture ); - TextureFactory::instance()->mMemSize -= mSize; + Uint32 flags = ( mFlags & TEX_FLAG_MIPMAP ) ? SOIL_FLAG_MIPMAPS : 0; + flags = (mClampMode == ClampRepeat) ? (flags | SOIL_FLAG_TEXTURE_REPEATS) : flags; - mSize = mWidth * mHeight * mChannels; + if ( ( mFlags & TEX_FLAG_COMPRESSED ) ) { + if ( isGrabed() ) + mTexture = SOIL_create_OGL_texture( reinterpret_cast ( &mPixels[0] ), &width, &height, mChannels, mTexture, flags | SOIL_FLAG_COMPRESS_TO_DXT ); + else + glCompressedTexImage2D( mTexture, 0, mInternalFormat, width, height, 0, mSize, &mPixels[0] ); + } else { + mTexture = SOIL_create_OGL_texture( reinterpret_cast ( &mPixels[0] ), &width, &height, mChannels, mTexture, flags ); - if ( getMipmap() ) { - int w = mWidth; - int h = mHeight; + TextureFactory::instance()->mMemSize -= mSize; - while( w > 2 && h > 2 ) { - w>>=1; - h>>=1; - mSize += ( w * h * mChannels ); + mSize = mWidth * mHeight * mChannels; + + if ( getMipmap() ) { + int w = mWidth; + int h = mHeight; + + while( w > 2 && h > 2 ) { + w>>=1; + h>>=1; + mSize += ( w * h * mChannels ); + } } + + TextureFactory::instance()->mMemSize += mSize; } - TextureFactory::instance()->mMemSize += mSize; + iTextureFilter( mFilter ); } - iTextureFilter( mFilter ); + if ( threaded ) + Engine::instance()->getCurrentWindow()->unsetGLContextThread(); } else { iLock(false,true); reload(); @@ -442,15 +474,26 @@ static unsigned int convertPixelFormatToGLFormat( Image::PixelFormat pf ) { void Texture::update( const Uint8* pixels, Uint32 width, Uint32 height, Uint32 x, Uint32 y, PixelFormat pf ) { if ( NULL != pixels && mTexture && x + width <= mWidth && y + height <= mHeight ) { - TextureSaver saver( mTexture ); + bool threaded = Engine::instance()->isSharedGLContextEnabled() && + Thread::getCurrentThreadId() != Engine::instance()->getMainThreadId(); - glTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, (unsigned int)convertPixelFormatToGLFormat( pf ), GL_UNSIGNED_BYTE, pixels ); + if ( threaded ) + Engine::instance()->getCurrentWindow()->setGLContextThread(); - if ( hasLocalCopy() ) { - Image image( pixels, width, height, mChannels ); + { + TextureSaver saver( mTexture ); - Image::copyImage( &image, x, y ); + glTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, (unsigned int)convertPixelFormatToGLFormat( pf ), GL_UNSIGNED_BYTE, pixels ); + + if ( hasLocalCopy() ) { + Image image( pixels, width, height, mChannels ); + + Image::copyImage( &image, x, y ); + } } + + if ( threaded ) + Engine::instance()->getCurrentWindow()->unsetGLContextThread(); } } @@ -463,27 +506,38 @@ void Texture::update( Image *image, Uint32 x, Uint32 y ) { } void Texture::replace( Image * image ) { - Uint32 flags = ( mFlags & TEX_FLAG_MIPMAP ) ? SOIL_FLAG_MIPMAPS : 0; - flags = (mClampMode == ClampRepeat) ? (flags | SOIL_FLAG_TEXTURE_REPEATS) : flags; + bool threaded = Engine::instance()->isSharedGLContextEnabled() && + Thread::getCurrentThreadId() != Engine::instance()->getMainThreadId(); - TextureSaver textureSaver; + if ( threaded ) + Engine::instance()->getCurrentWindow()->setGLContextThread(); - Int32 width = (Int32)image->getWidth(); - Int32 height = (Int32)image->getHeight(); - mTexture = SOIL_create_OGL_texture( image->getPixelsPtr(), &width, &height, image->getChannels(), mTexture, flags ); - mWidth = mImgWidth = width; - mHeight = mImgHeight = height; - mChannels = image->getChannels(); + { + Uint32 flags = ( mFlags & TEX_FLAG_MIPMAP ) ? SOIL_FLAG_MIPMAPS : 0; + flags = (mClampMode == ClampRepeat) ? (flags | SOIL_FLAG_TEXTURE_REPEATS) : flags; - TextureFactory::instance()->mMemSize -= mSize; - mSize = mWidth * mHeight * mChannels; - TextureFactory::instance()->mMemSize += mSize; + TextureSaver textureSaver; - if ( hasLocalCopy() ) { - // Renew the local copy - allocate( image->getMemSize(), Color(0,0,0,0), false ); - Image::copyImage( image ); + Int32 width = (Int32)image->getWidth(); + Int32 height = (Int32)image->getHeight(); + mTexture = SOIL_create_OGL_texture( image->getPixelsPtr(), &width, &height, image->getChannels(), mTexture, flags ); + mWidth = mImgWidth = width; + mHeight = mImgHeight = height; + mChannels = image->getChannels(); + + TextureFactory::instance()->mMemSize -= mSize; + mSize = mWidth * mHeight * mChannels; + TextureFactory::instance()->mMemSize += mSize; + + if ( hasLocalCopy() ) { + // Renew the local copy + allocate( image->getMemSize(), Color(0,0,0,0), false ); + Image::copyImage( image ); + } } + + if ( threaded ) + Engine::instance()->getCurrentWindow()->unsetGLContextThread(); } const Uint32& Texture::getHashName() const { diff --git a/src/eepp/graphics/texturefactory.cpp b/src/eepp/graphics/texturefactory.cpp index 7dc9817d9..724b321fe 100755 --- a/src/eepp/graphics/texturefactory.cpp +++ b/src/eepp/graphics/texturefactory.cpp @@ -31,9 +31,9 @@ TextureFactory::~TextureFactory() { unloadTextures(); } -Uint32 TextureFactory::createEmptyTexture( const unsigned int& Width, const unsigned int& Height, const unsigned int& Channels, const Color& DefaultColor, const bool& Mipmap, const Texture::ClampMode& ClampMode, const bool& CompressTexture, const bool& KeepLocalCopy ) { +Uint32 TextureFactory::createEmptyTexture( const unsigned int& Width, const unsigned int& Height, const unsigned int& Channels, const Color& DefaultColor, const bool& Mipmap, const Texture::ClampMode& ClampMode, const bool& CompressTexture, const bool& KeepLocalCopy, const std::string& Filename ) { Image TmpImg( Width, Height, Channels, DefaultColor ); - return loadFromPixels( TmpImg.getPixelsPtr(), Width, Height, Channels, Mipmap, ClampMode, CompressTexture, KeepLocalCopy ); + return loadFromPixels( TmpImg.getPixelsPtr(), Width, Height, Channels, Mipmap, ClampMode, CompressTexture, KeepLocalCopy, Filename ); } Uint32 TextureFactory::loadFromPixels( const unsigned char * Pixels, const unsigned int& Width, const unsigned int& Height, const unsigned int& Channels, const bool& Mipmap, const Texture::ClampMode& ClampMode, const bool& CompressTexture, const bool& KeepLocalCopy, const std::string& FileName ) { diff --git a/src/eepp/scene/actions/resizeborderradius.cpp b/src/eepp/scene/actions/resizeborderradius.cpp index 167c7260f..cc612a1ab 100644 --- a/src/eepp/scene/actions/resizeborderradius.cpp +++ b/src/eepp/scene/actions/resizeborderradius.cpp @@ -24,7 +24,7 @@ void ResizeBorderRadius::onUpdate( const Time& ) { if ( NULL != mNode && mNode->isWidget() ) { UIWidget * widget = static_cast( mNode ); - widget->setBorderRadius( widget->getStyleState(), mInterpolation.getPosition() ); + widget->setBorderRadius( mInterpolation.getPosition() ); } } diff --git a/src/eepp/scene/actions/tint.cpp b/src/eepp/scene/actions/tint.cpp index 263d19caa..1f5cfa783 100644 --- a/src/eepp/scene/actions/tint.cpp +++ b/src/eepp/scene/actions/tint.cpp @@ -126,7 +126,7 @@ void Tint::onUpdate( const Time& ) { switch ( mColorInterpolationType ) { case Background: { - widget->setBackgroundColor( widget->getStyleState(), + widget->setBackgroundColor( Color( mInterpolationR.getPosition(), mInterpolationG.getPosition(), mInterpolationB.getPosition(), @@ -137,7 +137,7 @@ void Tint::onUpdate( const Time& ) { } case Foreground: { - widget->setForegroundColor( widget->getStyleState(), + widget->setForegroundColor( Color( mInterpolationR.getPosition(), mInterpolationG.getPosition(), mInterpolationB.getPosition(), @@ -148,7 +148,7 @@ void Tint::onUpdate( const Time& ) { } case Skin: { - widget->setSkinColor( widget->getStyleState(), + widget->setSkinColor( Color( mInterpolationR.getPosition(), mInterpolationG.getPosition(), mInterpolationB.getPosition(), 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 4672c61d6..2557fad6c 100644 --- a/src/eepp/scene/nodeattribute.cpp +++ b/src/eepp/scene/nodeattribute.cpp @@ -33,15 +33,20 @@ const std::vector& NodeAttribute::Info::getNames() const { NodeAttribute::NodeAttribute() {} -NodeAttribute::NodeAttribute( std::string name, std::string value ) : +NodeAttribute::NodeAttribute( std::string name, std::string value, bool isVolatile ) : mName( String::toLower( name ) ), - mValue( value ) + mValue( value ), + mVolatile( isVolatile ) {} bool NodeAttribute::isEmpty() const { return mName.empty(); } +bool NodeAttribute::isVolatile() const { + return mVolatile; +} + std::string NodeAttribute::getName() const { return mName; } @@ -133,8 +138,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 +179,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 +203,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 ) { @@ -365,7 +370,7 @@ const std::string& NodeAttribute::FunctionType::getName() const { return name; } -const std::vector NodeAttribute::FunctionType::getParameters() const { +const std::vector& NodeAttribute::FunctionType::getParameters() const { return parameters; } diff --git a/src/eepp/scene/scenemanager.cpp b/src/eepp/scene/scenemanager.cpp index 87f821f3d..f43c3ddf7 100644 --- a/src/eepp/scene/scenemanager.cpp +++ b/src/eepp/scene/scenemanager.cpp @@ -22,8 +22,7 @@ SceneManager::~SceneManager() { mResources.clear(); } -void SceneManager::draw() -{ +void SceneManager::draw() { for ( auto it = mResources.begin() ; it != mResources.end(); it++ ) { SceneNode * sceneNode = (*it); @@ -43,8 +42,7 @@ void SceneManager::update() { update( mClock.getElapsed() ); } -bool SceneManager::isShootingDown() const -{ +bool SceneManager::isShootingDown() const { return mIsShootingDown; } diff --git a/src/eepp/system/color.cpp b/src/eepp/system/color.cpp index 95d3e1234..0741667af 100644 --- a/src/eepp/system/color.cpp +++ b/src/eepp/system/color.cpp @@ -7,23 +7,25 @@ namespace EE { namespace System { -const Color Color::Transparent = Color(0,0,0,0); -const Color Color::White = Color(255,255,255); -const Color Color::Black = Color(0,0,0); -const Color Color::Red = Color(255,0,0); -const Color Color::Green = Color(0,255,0); -const Color Color::Blue = Color(0,0,255); -const Color Color::Yellow = Color(255,255,0); -const Color Color::Cyan = Color(0,255,255); -const Color Color::Magenta = Color(255,0,255); -const Color Color::Silver = Color(192,0,192); -const Color Color::Gray = Color(128,128,128); -const Color Color::Maroon = Color(128,0,0); -const Color Color::Olive = Color(128,128,0); -const Color Color::OfficeGreen = Color(0,128,0); -const Color Color::Purple = Color(128,0,128); -const Color Color::Teal = Color(0,128,128); -const Color Color::Navy = Color(0,0,128); +// @TODO: Support all CSS3 color keywords. +// Reference: https://www.w3.org/TR/2018/REC-css-color-3-20180619/ +const Color Color::Transparent = Color(0x00000000); +const Color Color::Black = Color(0x000000FF); +const Color Color::Silver = Color(0xC0C0C0FF); +const Color Color::Gray = Color(0x808080FF); +const Color Color::White = Color(0xFFFFFFFF); +const Color Color::Maroon = Color(0x800000FF); +const Color Color::Red = Color(0xFF0000FF); +const Color Color::Purple = Color(0x800080FF); +const Color Color::Fuchsia = Color(0xFF00FFFF); +const Color Color::Green = Color(0x008000FF); +const Color Color::Lime = Color(0x00FF00FF); +const Color Color::Olive = Color(0x808000FF); +const Color Color::Yellow = Color(0xFFFF00FF); +const Color Color::Navy = Color(0x000080FF); +const Color Color::Blue = Color(0x0000FFFF); +const Color Color::Teal = Color(0x008080FF); +const Color Color::Aqua = Color(0x00FFFFFF); RGB::RGB() : tRGB() { @@ -303,22 +305,22 @@ Color Color::fromString( std::string str ) { } else if ( size >= 3 && isalpha( str[0] ) && isalpha( str[1] ) && isalpha( str[2] ) ) { String::toLowerInPlace( str ); if ( "transparent" == str ) return Color::Transparent; - else if ( "white" == str ) return Color::White; else if ( "black" == str ) return Color::Black; - else if ( "red" == str ) return Color::Red; - else if ( "green" == str ) return Color::Green; - else if ( "blue" == str ) return Color::Blue; - else if ( "yellow" == str ) return Color::Yellow; - else if ( "cyan" == str ) return Color::Cyan; - else if ( "magenta" == str ) return Color::Magenta; else if ( "silver" == str ) return Color::Silver; else if ( "gray" == str ) return Color::Gray; + else if ( "white" == str ) return Color::White; else if ( "maroon" == str ) return Color::Maroon; - else if ( "olive" == str ) return Color::Olive; - else if ( "officegreen" == str ) return Color::OfficeGreen; + else if ( "red" == str ) return Color::Red; else if ( "purple" == str ) return Color::Purple; - else if ( "teal" == str ) return Color::Teal; + else if ( "fuchsia" == str ) return Color::Fuchsia; + else if ( "green" == str ) return Color::Green; + else if ( "lime" == str ) return Color::Lime; + else if ( "olive" == str ) return Color::Olive; + else if ( "yellow" == str ) return Color::Yellow; else if ( "navy" == str ) return Color::Navy; + else if ( "blue" == str ) return Color::Blue; + else if ( "teal" == str ) return Color::Teal; + else if ( "aqua" == str ) return Color::Aqua; } if ( size < 6 ) { @@ -343,22 +345,22 @@ bool Color::isColorString( std::string str ) { String::toLowerInPlace( str ); if ( "transparent" == str ) return true; - else if ( "white" == str ) return true; else if ( "black" == str ) return true; - else if ( "red" == str ) return true; - else if ( "green" == str ) return true; - else if ( "blue" == str ) return true; - else if ( "yellow" == str ) return true; - else if ( "cyan" == str ) return true; - else if ( "magenta" == str ) return true; else if ( "silver" == str ) return true; else if ( "gray" == str ) return true; + else if ( "white" == str ) return true; else if ( "maroon" == str ) return true; - else if ( "olive" == str ) return true; - else if ( "officegreen" == str ) return true; + else if ( "red" == str ) return true; else if ( "purple" == str ) return true; - else if ( "teal" == str ) return true; + else if ( "fuchsia" == str ) return true; + else if ( "green" == str ) return true; + else if ( "lime" == str ) return true; + else if ( "olive" == str ) return true; + else if ( "yellow" == str ) return true; else if ( "navy" == str ) return true; + else if ( "blue" == str ) return true; + else if ( "teal" == str ) return true; + else if ( "aqua" == str ) return true; return false; } diff --git a/src/eepp/ui/css/stylesheet.cpp b/src/eepp/ui/css/stylesheet.cpp index 58aca908d..da58a5ca7 100644 --- a/src/eepp/ui/css/stylesheet.cpp +++ b/src/eepp/ui/css/stylesheet.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace EE { namespace UI { namespace CSS { @@ -20,8 +21,8 @@ void StyleSheet::combineStyle( const StyleSheetStyle& node ) { auto currentNode = nodeIt->second; if ( node.getSelector().getSpecificity() > currentNode.getSelector().getSpecificity() ) { - for ( auto pit = node.getProperties().begin(); pit != node.getProperties().end(); ++pit ) - currentNode.setProperty( pit->second ); + for ( auto& pit : node.getProperties() ) + currentNode.setProperty( pit.second ); } } } @@ -31,46 +32,24 @@ bool StyleSheet::isEmpty() const { } void StyleSheet::print() { - for ( auto it = mNodes.begin(); it != mNodes.end(); ++it ) { - StyleSheetStyle& style = it->second; + for ( auto& it : mNodes ) { + StyleSheetStyle& style = it.second; - style.print(); + std::cout << style.build(); } } void StyleSheet::combineStyleSheet( const StyleSheet& styleSheet ) { - for ( auto it = styleSheet.getStyles().begin(); it != styleSheet.getStyles().end(); ++it ) { - combineStyle( it->second ); + for ( auto& it : styleSheet.getStyles() ) { + combineStyle( it.second ); } } -StyleSheet::StyleSheetPseudoClassProperties StyleSheet::getElementPropertiesByState( StyleSheetElement * element ) { - StyleSheetPseudoClassProperties propertiesSelectedByPseudoClass; - - for ( auto it = mNodes.begin(); it != mNodes.end(); ++it ) { - StyleSheetStyle& node = it->second; - const StyleSheetSelector& selector = node.getSelector(); - - if ( selector.isCacheable() && selector.select( element, false ) ) { - for ( auto pit = node.getProperties().begin(); pit != node.getProperties().end(); ++pit ) { - StyleSheetProperties& pseudoClassProperties = propertiesSelectedByPseudoClass[selector.getPseudoClass()]; - auto pcit = pseudoClassProperties.find( pit->second.getName() ); - - if ( pcit == pseudoClassProperties.end() || pit->second.getSpecificity() >= pcit->second.getSpecificity() ) { - pseudoClassProperties[ pit->second.getName() ] = pit->second; - } - } - } - } - - return propertiesSelectedByPseudoClass; -} - StyleSheetStyleVector StyleSheet::getElementStyles( StyleSheetElement * element , const bool& applyPseudo ) { StyleSheetStyleVector styles; - for ( auto it = mNodes.begin(); it != mNodes.end(); ++it ) { - StyleSheetStyle& node = it->second; + for ( const auto& it : mNodes ) { + const StyleSheetStyle& node = it.second; const StyleSheetSelector& selector = node.getSelector(); if ( selector.select( element, applyPseudo ) ) { @@ -81,36 +60,6 @@ StyleSheetStyleVector StyleSheet::getElementStyles( StyleSheetElement * element return styles; } -StyleSheetStyleVector StyleSheet::getCacheableElementStyles( StyleSheetElement * element, const bool& applyPseudo ) { - StyleSheetStyleVector styles; - - for ( auto it = mNodes.begin(); it != mNodes.end(); ++it ) { - StyleSheetStyle& node = it->second; - const StyleSheetSelector& selector = node.getSelector(); - - if ( selector.isCacheable() && selector.select( element, applyPseudo ) ) { - styles.push_back( node ); - } - } - - return styles; -} - -StyleSheetStyleVector StyleSheet::getNoncacheableElementStyles( StyleSheetElement * element, const bool& applyPseudo ) { - StyleSheetStyleVector styles; - - for ( auto it = mNodes.begin(); it != mNodes.end(); ++it ) { - StyleSheetStyle& node = it->second; - const StyleSheetSelector& selector = node.getSelector(); - - if ( !selector.isCacheable() && selector.select( element, applyPseudo ) ) { - styles.push_back( node ); - } - } - - return styles; -} - const StyleSheetStyleList& StyleSheet::getStyles() const { return mNodes; } diff --git a/src/eepp/ui/css/stylesheetpropertiesparser.cpp b/src/eepp/ui/css/stylesheetpropertiesparser.cpp index cceb7b0cd..78255891d 100644 --- a/src/eepp/ui/css/stylesheetpropertiesparser.cpp +++ b/src/eepp/ui/css/stylesheetpropertiesparser.cpp @@ -1,4 +1,9 @@ #include +#include +#include + +using namespace EE::UI; +using namespace EE::Scene; namespace EE { namespace UI { namespace CSS { @@ -18,7 +23,7 @@ const StyleSheetProperties & StyleSheetPropertiesParser::getProperties() const { void StyleSheetPropertiesParser::parse( std::string propsstr ) { ReadState rs = ReadingPropertyName; - prevRs = rs; + mPrevRs = rs; std::size_t pos = 0; std::string buffer; @@ -45,7 +50,7 @@ void StyleSheetPropertiesParser::parse( std::string propsstr ) { } int StyleSheetPropertiesParser::readPropertyName(StyleSheetPropertiesParser::ReadState & rs, std::size_t pos, std::string & buffer, const std::string& str) { - prevRs = rs; + mPrevRs = rs; buffer.clear(); while ( pos < str.size() ) { @@ -73,7 +78,7 @@ int StyleSheetPropertiesParser::readPropertyValue(StyleSheetPropertiesParser::Re buffer.clear(); - prevRs = rs; + mPrevRs = rs; while ( pos < str.size() ) { if ( str[pos] == '/' && str.size() > pos + 1 && str[pos+1] == '*' ) { @@ -89,7 +94,7 @@ int StyleSheetPropertiesParser::readPropertyValue(StyleSheetPropertiesParser::Re if ( str[pos] == ';' ) { rs = ReadingPropertyName; - mProperties[ propName ] = StyleSheetProperty( propName, buffer ); + addProperty( propName, buffer ); return pos + 1; } @@ -102,7 +107,7 @@ int StyleSheetPropertiesParser::readPropertyValue(StyleSheetPropertiesParser::Re if ( pos == str.size() ) { rs = ReadingPropertyName; - mProperties[ propName ] = StyleSheetProperty( propName, buffer ); + addProperty( propName, buffer ); return pos + 1; } @@ -116,7 +121,7 @@ int StyleSheetPropertiesParser::readComment(StyleSheetPropertiesParser::ReadStat while ( pos < str.size() ) { if ( str[pos] == '*' && str.size() > pos + 1 && str[pos+1] == '/' ) { - rs = prevRs; + rs = mPrevRs; return pos + 2; } @@ -159,4 +164,25 @@ int StyleSheetPropertiesParser::readValueUrl(StyleSheetPropertiesParser::ReadSta return pos; } +void StyleSheetPropertiesParser::addProperty( const std::string& name, std::string value ) { + if ( name == "padding" ) { + value = String::toLower( String::trim( value ) ); + Rectf rect( NodeAttribute( name, value ).asRectf() ); + mProperties[ "paddingleft" ] = StyleSheetProperty( "paddingleft", String::toStr( rect.Left ) ); + mProperties[ "paddingright" ] = StyleSheetProperty( "paddingright", String::toStr( rect.Right ) ); + mProperties[ "paddingtop" ] = StyleSheetProperty( "paddingtop", String::toStr( rect.Top ) ); + mProperties[ "paddingbottom" ] = StyleSheetProperty( "paddingbottom", String::toStr( rect.Bottom ) ); + } else if ( name == "layout_margin" ) { + value = String::toLower( String::trim( value ) ); + Rect rect( NodeAttribute( name, value ).asRect() ); + mProperties[ "layout_marginleft" ] = StyleSheetProperty( "layout_marginleft", String::toStr( rect.Left ) ); + mProperties[ "layout_marginright" ] = StyleSheetProperty( "layout_marginright", String::toStr( rect.Right ) ); + mProperties[ "layout_margintop" ] = StyleSheetProperty( "layout_margintop", String::toStr( rect.Top ) ); + mProperties[ "layout_marginbottom" ] = StyleSheetProperty( "layout_marginbottom", String::toStr( rect.Bottom ) ); + } else { + mProperties[ name ] = StyleSheetProperty( name, value ); + } +} + }}} + diff --git a/src/eepp/ui/css/stylesheetproperty.cpp b/src/eepp/ui/css/stylesheetproperty.cpp index c66e8402a..95f7e2e4e 100644 --- a/src/eepp/ui/css/stylesheetproperty.cpp +++ b/src/eepp/ui/css/stylesheetproperty.cpp @@ -12,13 +12,15 @@ StyleSheetProperty::StyleSheetProperty() StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::string& value ) : mName( String::toLower( String::trim( name ) ) ), - mValue( String::trim( value ) ) + mValue( String::trim( value ) ), + mSpecificity( 0 ) {} -StyleSheetProperty::StyleSheetProperty( const std::string & name, const std::string& value, const Uint32 & specificity ) : +StyleSheetProperty::StyleSheetProperty( const std::string & name, const std::string& value, const Uint32 & specificity, const bool& isVolatile ) : mName( String::toLower( String::trim( name ) ) ), mValue( String::trim( value ) ), - mSpecificity( specificity ) + mSpecificity( specificity ), + mVolatile( isVolatile ) {} const std::string &StyleSheetProperty::getName() const { @@ -49,4 +51,12 @@ void StyleSheetProperty::setValue( const std::string& value ) { mValue = value; } +const bool &StyleSheetProperty::isVolatile() const { + return mVolatile; +} + +void StyleSheetProperty::setVolatile( const bool & isVolatile ) { + mVolatile = isVolatile; +} + }}} diff --git a/src/eepp/ui/css/stylesheetselector.cpp b/src/eepp/ui/css/stylesheetselector.cpp index ad653d3fb..95585b6a8 100644 --- a/src/eepp/ui/css/stylesheetselector.cpp +++ b/src/eepp/ui/css/stylesheetselector.cpp @@ -4,9 +4,12 @@ namespace EE { namespace UI { namespace CSS { StyleSheetSelector::StyleSheetSelector() : + mName( "*" ), mSpecificity(0), mCacheable(true) -{} +{ + parseSelector( mName ); +} StyleSheetSelector::StyleSheetSelector( const std::string& selectorName ) : mName( String::toLower( selectorName ) ), @@ -22,13 +25,14 @@ const std::string &StyleSheetSelector::getName() const { const std::string& StyleSheetSelector::getPseudoClass() const { return mPseudoClass; -}; +} const Uint32& StyleSheetSelector::getSpecificity() const { return mSpecificity; } void removeExtraSpaces( std::string& string ) { + // @TODO: Optimize this string = String::trim( string ); String::replaceAll( string, " ", " " ); String::replaceAll( string, " ", " " ); @@ -105,6 +109,14 @@ const bool &StyleSheetSelector::isCacheable() const { return mCacheable; } +bool StyleSheetSelector::hasPseudoClass( const std::string& cls ) const { + return mSelectorRules.empty() ? false : ( cls.empty() ? true : mSelectorRules[0].hasPseudoClass( cls ) ); +} + +bool StyleSheetSelector::hasPseudoClasses() const { + return mSelectorRules.empty() || mSelectorRules[0].hasPseudoClasses(); +} + bool StyleSheetSelector::select( StyleSheetElement * element, const bool& applyPseudo ) const { if ( mSelectorRules.empty() ) return false; @@ -194,4 +206,113 @@ bool StyleSheetSelector::select( StyleSheetElement * element, const bool& applyP return true; } +std::vector StyleSheetSelector::getRelatedElements( StyleSheetElement * element, const bool& applyPseudo ) const { + static std::vector EMPTY_ELEMENTS; + std::vector elements; + if ( mSelectorRules.empty() ) + return elements; + + StyleSheetElement * curElement = element; + + for ( size_t i = 0; i < mSelectorRules.size(); i++ ) { + const StyleSheetSelectorRule& selectorRule = mSelectorRules[i]; + + switch ( selectorRule.getPatternMatch() ) { + case StyleSheetSelectorRule::ANY: + { + if ( !selectorRule.matches( curElement, applyPseudo ) ) + return EMPTY_ELEMENTS; + + break; // continue evaluating + } + case StyleSheetSelectorRule::DESCENDANT: + { + bool foundDescendant = false; + + curElement = curElement->getStyleSheetParentElement(); + + while ( NULL != curElement && !foundDescendant ) { + if ( selectorRule.matches( curElement, applyPseudo ) ) { + foundDescendant = true; + } else { + curElement = curElement->getStyleSheetParentElement(); + } + } + + if ( !foundDescendant ) + return EMPTY_ELEMENTS; + + if ( 0 != i && ( selectorRule.hasPseudoClasses() || selectorRule.hasStructuralPseudoClasses() ) ) { + elements.push_back( curElement ); + } + + break; // continue evaluating + } + case StyleSheetSelectorRule::CHILD: + { + curElement = curElement->getStyleSheetParentElement(); + + if ( NULL == curElement || !selectorRule.matches( curElement, applyPseudo ) ) + return EMPTY_ELEMENTS; + + if ( 0 != i && ( selectorRule.hasPseudoClasses() || selectorRule.hasStructuralPseudoClasses() ) ) { + elements.push_back( curElement ); + } + + break; // continue evaluating + } + case StyleSheetSelectorRule::DIRECT_SIBLING: + { + curElement = curElement->getStyleSheetPreviousSiblingElement(); + + if ( NULL == curElement || !selectorRule.matches( curElement, applyPseudo ) ) + return EMPTY_ELEMENTS; + + if ( 0 != i && ( selectorRule.hasPseudoClasses() || selectorRule.hasStructuralPseudoClasses() ) ) { + elements.push_back( curElement ); + } + + break; // continue evaluating + } + case StyleSheetSelectorRule::SIBLING: + { + bool foundSibling = false; + StyleSheetElement * prevSibling = curElement->getStyleSheetPreviousSiblingElement(); + StyleSheetElement * nextSibling = curElement->getStyleSheetNextSiblingElement(); + + while ( NULL != prevSibling && !foundSibling ) { + if ( selectorRule.matches( prevSibling, applyPseudo ) ) { + foundSibling = true; + curElement = prevSibling; + } else { + prevSibling = prevSibling->getStyleSheetPreviousSiblingElement(); + } + } + + if ( !foundSibling ) { + while ( NULL != nextSibling && !foundSibling ) { + if ( selectorRule.matches( nextSibling, applyPseudo ) ) { + foundSibling = true; + curElement = nextSibling; + } else { + nextSibling = nextSibling->getStyleSheetNextSiblingElement(); + } + } + } + + if ( !foundSibling ) + return EMPTY_ELEMENTS; + + if ( 0 != i && ( selectorRule.hasPseudoClasses() || selectorRule.hasStructuralPseudoClasses() ) ) { + elements.push_back( curElement ); + } + + break; // continue evaluating + } + } + } + + return elements; +} + }}} diff --git a/src/eepp/ui/css/stylesheetselectorparser.cpp b/src/eepp/ui/css/stylesheetselectorparser.cpp index 5b222d53e..da5db7e8a 100644 --- a/src/eepp/ui/css/stylesheetselectorparser.cpp +++ b/src/eepp/ui/css/stylesheetselectorparser.cpp @@ -4,12 +4,10 @@ namespace EE { namespace UI { namespace CSS { StyleSheetSelectorParser::StyleSheetSelectorParser(){} -StyleSheetSelectorParser::StyleSheetSelectorParser( std::string name ) -{ +StyleSheetSelectorParser::StyleSheetSelectorParser( std::string name ) { std::vector sels = String::split( name, ',' ); - for ( auto it = sels.begin(); it != sels.end(); ++it ) - { + for ( auto it = sels.begin(); it != sels.end(); ++it ) { std::string cur = String::trim( *it ); String::replaceAll( cur, "\n", "" ); String::replaceAll( cur, "\t", "" ); diff --git a/src/eepp/ui/css/stylesheetselectorrule.cpp b/src/eepp/ui/css/stylesheetselectorrule.cpp index a5baf5330..0a63392ef 100644 --- a/src/eepp/ui/css/stylesheetselectorrule.cpp +++ b/src/eepp/ui/css/stylesheetselectorrule.cpp @@ -242,8 +242,8 @@ bool StyleSheetSelectorRule::matches( StyleSheetElement * element, const bool& a if ( !mClasses.empty() && !element->getStyleSheetClasses().empty() ) { bool hasClasses = true; - for ( auto cit = element->getStyleSheetClasses().begin(); cit != element->getStyleSheetClasses().end(); ++cit ) { - if ( !hasClass( *cit ) ) { + for ( const auto& cls : element->getStyleSheetClasses() ) { + if ( !hasClass( cls ) ) { hasClasses = false; break; } @@ -255,14 +255,12 @@ bool StyleSheetSelectorRule::matches( StyleSheetElement * element, const bool& a } if ( applyPseudo ) { - if ( mPseudoClasses.empty() && !element->getStyleSheetPseudoClasses().empty() ) { - flags |= PseudoClass; - } else if ( !mPseudoClasses.empty() && !element->getStyleSheetPseudoClasses().empty() ) { + if ( !mPseudoClasses.empty() && !element->getStyleSheetPseudoClasses().empty() ) { bool hasPseudoClasses = false; const std::vector& elPseudoClasses = element->getStyleSheetPseudoClasses(); - for ( auto cit = elPseudoClasses.begin(); cit != elPseudoClasses.end(); ++cit ) { - if ( hasPseudoClass( *cit ) ) { + for ( const auto& cls : elPseudoClasses ) { + if ( hasPseudoClass( cls ) ) { hasPseudoClasses = true; break; } diff --git a/src/eepp/ui/css/stylesheetstyle.cpp b/src/eepp/ui/css/stylesheetstyle.cpp index ddf070c78..5db6fd7f7 100644 --- a/src/eepp/ui/css/stylesheetstyle.cpp +++ b/src/eepp/ui/css/stylesheetstyle.cpp @@ -1,5 +1,4 @@ #include -#include namespace EE { namespace UI { namespace CSS { @@ -10,32 +9,53 @@ StyleSheetStyle::StyleSheetStyle( const std::string& selector, const StyleSheetP mSelector( selector ), mProperties( properties ) { - for ( auto it = mProperties.begin(); it != mProperties.end(); ++it ) - it->second.setSpecificity( mSelector.getSpecificity() ); + for ( auto& it : mProperties ) { + it.second.setSpecificity( mSelector.getSpecificity() ); + it.second.setVolatile( !mSelector.isCacheable() ); + } } -void StyleSheetStyle::print() { - std::cout << mSelector.getName() << " {" << std::endl; +std::string StyleSheetStyle::build() { + std::string css; - for ( StyleSheetProperties::iterator it = mProperties.begin(); it != mProperties.end(); ++it ) { - StyleSheetProperty& prop = it->second; + css += mSelector.getName() + " {"; - std::cout << "\t" << prop.getName() << ": " << prop.getValue() << ";" << std::endl; + + for ( auto& it : mProperties ) { + StyleSheetProperty& prop = it.second; + + css += "\t" + prop.getName() + ": " + prop.getValue() + ";\n"; } - std::cout << "}" << std::endl; + css += "}\n"; + + return css; } -const StyleSheetSelector &StyleSheetStyle::getSelector() const { + +const StyleSheetSelector& StyleSheetStyle::getSelector() const { return mSelector; } -const StyleSheetProperties &StyleSheetStyle::getProperties() const { +const StyleSheetProperties& StyleSheetStyle::getProperties() const { return mProperties; } +StyleSheetProperty StyleSheetStyle::getPropertyByName( const std::string& name ) const { + auto it = mProperties.find( name ); + + if ( it != mProperties.end() ) + return it->second; + + return StyleSheetProperty(); +} + void StyleSheetStyle::setProperty( const StyleSheetProperty & property ) { mProperties[ property.getName() ] = property; } +void StyleSheetStyle::clearProperties() { + mProperties.clear(); +} + }}} diff --git a/src/eepp/ui/uicombobox.cpp b/src/eepp/ui/uicombobox.cpp index 1f5b64ff4..2344dd048 100644 --- a/src/eepp/ui/uicombobox.cpp +++ b/src/eepp/ui/uicombobox.cpp @@ -37,6 +37,9 @@ void UIComboBox::setTheme( UITheme * Theme ) { mDropDownList->setEnabled( true ); mDropDownList->setAllowEditing( true ); mDropDownList->getInputTextBuffer()->setFreeEditing( true ); + mDropDownList->addEventListener( Event::OnPaddingChange, [this](const Event*) { + this->onPaddingChange(); + }); } if ( NULL == mButton ) { @@ -84,6 +87,8 @@ void UIComboBox::loadFromXmlNode(const pugi::xml_node& node) { mDropDownList->loadFromXmlNode( node ); endAttributesTransaction(); + + updateControls(); } Uint32 UIComboBox::onMessage( const NodeMessage * Msg ) { @@ -109,19 +114,26 @@ void UIComboBox::updateControls() { } void UIComboBox::onSizeChange() { - UIWidget::onSizeChange(); - updateControls(); + + UIWidget::onSizeChange(); } void UIComboBox::onPositionChange() { - UIWidget::onPositionChange(); - updateControls(); + + UIWidget::onPositionChange(); +} + +void UIComboBox::onPaddingChange() { + updateControls(); + + UIWidget::onPaddingChange(); } void UIComboBox::onAutoSize() { - setInternalHeight( mDropDownList->getSkinSize().getHeight() + mDropDownList->getPadding().Top + mDropDownList->getPadding().Bottom ); + if ( NULL != mDropDownList ) + setInternalHeight( mDropDownList->getSkinSize().getHeight() + mDropDownList->getPadding().Top + mDropDownList->getPadding().Bottom ); } }} diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index fb92c0e57..8fa488d26 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -58,9 +58,9 @@ void UIDropDownList::setTheme( UITheme * Theme ) { } void UIDropDownList::onSizeChange() { - UIWidget::onSizeChange(); - onAutoSize(); + + UIWidget::onSizeChange(); } void UIDropDownList::onThemeLoaded() { diff --git a/src/eepp/ui/uilinearlayout.cpp b/src/eepp/ui/uilinearlayout.cpp index 6c2e6ce55..c3e719431 100644 --- a/src/eepp/ui/uilinearlayout.cpp +++ b/src/eepp/ui/uilinearlayout.cpp @@ -97,7 +97,7 @@ void UILinearLayout::packVertical() { { int w = mDpSize.getWidth() - widget->getLayoutMargin().Left - widget->getLayoutMargin().Right - mPadding.Left - mPadding.Right; - if ( widget->getSize().getWidth() != w ) + if ( (int)widget->getSize().getWidth() != w ) widget->setSize( w, widget->getSize().getHeight() ); break; @@ -166,14 +166,14 @@ void UILinearLayout::packVertical() { if ( getLayoutHeightRules() == WRAP_CONTENT ) { curY += mPadding.Bottom; - if ( curY != mDpSize.getHeight() ) { + if ( curY != (int)mDpSize.getHeight() ) { setInternalHeight( curY ); notifyLayoutAttrChangeParent(); } } else if ( getLayoutHeightRules() == MATCH_PARENT ) { int h = getParent()->getSize().getHeight() - mLayoutMargin.Top - mLayoutMargin.Bottom; - if ( h != mDpSize.getHeight() ) + if ( h != (int)mDpSize.getHeight() ) setInternalHeight( h ); } @@ -215,7 +215,7 @@ void UILinearLayout::packHorizontal() { { int h = mDpSize.getHeight() - widget->getLayoutMargin().Top - widget->getLayoutMargin().Bottom - mPadding.Top - mPadding.Bottom; - if ( h != widget->getSize().getHeight() ) + if ( h != (int)widget->getSize().getHeight() ) widget->setSize( widget->getSize().getWidth(), h ); break; @@ -284,14 +284,14 @@ void UILinearLayout::packHorizontal() { if ( getLayoutWidthRules() == WRAP_CONTENT ) { curX += mPadding.Right; - if ( curX != mDpSize.getWidth() ) { + if ( curX != (int)mDpSize.getWidth() ) { setInternalWidth( curX ); notifyLayoutAttrChangeParent(); } } else if ( getLayoutWidthRules() == MATCH_PARENT ) { int w = getParent()->getSize().getWidth() - mLayoutMargin.Left - mLayoutMargin.Right; - if ( w != mDpSize.getWidth() ) + if ( w != (int)mDpSize.getWidth() ) setInternalWidth( w ); } diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index a4240ebd8..0a28b34c3 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -36,7 +36,8 @@ UINode::UINode() : mBackgroundState( NULL ), mForegroundState( NULL ), mBorder( NULL ), - mDragButton( EE_BUTTON_LMASK ) + mDragButton( EE_BUTTON_LMASK ), + mSkinColor( Color::White ) { mNodeFlags |= NODE_FLAG_UINODE | NODE_FLAG_OVER_FIND_ALLOWED; @@ -56,6 +57,9 @@ UINode::~UINode() { eeSAFE_DELETE( mBackgroundState ); eeSAFE_DELETE( mForegroundState ); eeSAFE_DELETE( mBorder ); + + if ( isDragging() ) + getEventDispatcher()->setNodeDragging( NULL ); } void UINode::worldToNodeTranslation( Vector2f& Pos ) const { @@ -258,6 +262,8 @@ void UINode::drawBox() { void UINode::drawSkin() { if ( NULL != mSkinState ) { + mSkinState->setStateColor( mSkinState->getCurrentState(), mSkinColor ); + if ( mFlags & UI_SKIN_KEEP_SIZE_ON_DRAW ) { Sizef rSize = PixelDensity::dpToPx( getSkinSize( getSkin(), mSkinState->getCurrentState() ) ); Sizef diff = ( mSize - rSize ) * 0.5f; @@ -390,88 +396,59 @@ UISkin * UINode::setBackgroundFillEnabled( bool enabled ) { return NULL != mBackgroundState ? mBackgroundState->getSkin() : NULL; } -UINode * UINode::setBackgroundDrawable( const Uint32& state, Drawable * drawable, bool ownIt ) { - setBackgroundFillEnabled( true )->setStateDrawable( state, drawable, ownIt ); +UINode * UINode::setBackgroundDrawable( Drawable * drawable, bool ownIt ) { + setBackgroundFillEnabled( true )->setStateDrawable( UIState::StateFlagNormal, drawable, ownIt ); return this; } -UINode * UINode::setBackgroundDrawable( Drawable * drawable, bool ownIt ) { - return setBackgroundDrawable( UIState::StateFlagNormal, drawable, ownIt ); -} - -UINode * UINode::setBackgroundColor( const Uint32 & state, const Color& color ) { +UINode * UINode::setBackgroundColor( const Color& color ) { UISkin * background = setBackgroundFillEnabled( true ); - Drawable * stateDrawable = background->getStateDrawable( state ); + Drawable * stateDrawable = background->getStateDrawable( UIState::StateFlagNormal ); if ( NULL == stateDrawable ) - setBackgroundDrawable( state, RectangleDrawable::New(), true ); + setBackgroundDrawable( RectangleDrawable::New(), true ); if ( NULL != mBackgroundState ) - mBackgroundState->setStateColor( state, color ); + mBackgroundState->setStateColor( UIState::StateFlagNormal, color ); return this; } Color UINode::getBackgroundColor() const { - return getBackgroundColor( mState ); -} - -Color UINode::getBackgroundColor( const Uint32 & state ) const { if ( NULL != mBackgroundState ) - return mBackgroundState->getStateColor( state ); + return mBackgroundState->getStateColor( UIState::StateFlagNormal ); - return Color::White; + return Color::Transparent; } -UINode * UINode::setBackgroundColor( const Color& color ) { - return setBackgroundColor( UIState::StateFlagNormal, color ); -} +UINode * UINode::setBorderRadius( const unsigned int& corners ) { + setBorderEnabled( true )->setCorners( corners ); -UINode * UINode::setBorderRadius( const Uint32 & state, const unsigned int& corners ) { UISkin * background = setBackgroundFillEnabled( true ); - Drawable * stateDrawable = background->getStateDrawable( state ); + Drawable * stateDrawable = background->getStateDrawable( UIState::StateFlagNormal ); if ( NULL == stateDrawable ) { - setBackgroundColor( state, Color::Black ); + setBackgroundColor( Color::Transparent ); - stateDrawable = background->getStateDrawable( state ); + stateDrawable = background->getStateDrawable( UIState::StateFlagNormal ); } if ( stateDrawable->getDrawableType() == Drawable::RECTANGLE ) { - RectangleDrawable * rectangleDrawable = static_cast( stateDrawable ); - - rectangleDrawable->setCorners( corners ); + static_cast( stateDrawable )->setCorners( corners ); } return this; } -Uint32 UINode::getBorderRadius( const Uint32& state ) const { - if ( NULL != mBackgroundState && NULL != mBackgroundState->getSkin() ) { - Drawable * stateDrawable = mBackgroundState->getSkin()->getStateDrawable( state ); - - if ( NULL != stateDrawable ) { - if ( stateDrawable->getDrawableType() == Drawable::RECTANGLE ) { - RectangleDrawable * rectangleDrawable = static_cast( stateDrawable ); - - return rectangleDrawable->getCorners(); - } - } - } +Uint32 UINode::getBorderRadius() const { + if ( NULL != mBorder ) + return mBorder->getCorners(); return 0; } -Uint32 UINode::getBorderRadius() const { - return getBorderRadius( UIState::StateFlagNormal ); -} - -UINode * UINode::setBorderRadius( const unsigned int& corners ) { - return setBorderRadius( UIState::StateFlagNormal, corners ); -} - UISkin * UINode::setForegroundFillEnabled( bool enabled ) { writeFlag( UI_FILL_FOREGROUND, enabled ? 1 : 0 ); @@ -484,53 +461,41 @@ UISkin * UINode::setForegroundFillEnabled( bool enabled ) { return NULL != mForegroundState ? mForegroundState->getSkin() : NULL; } -UINode * UINode::setForegroundDrawable( const Uint32 & state, Drawable * drawable, bool ownIt ) { - setForegroundFillEnabled( true )->setStateDrawable( state, drawable, ownIt ); - return this; -} - UINode * UINode::setForegroundDrawable( Drawable * drawable, bool ownIt ) { - return setForegroundDrawable( UIState::StateFlagNormal, drawable, ownIt ); + setForegroundFillEnabled( true )->setStateDrawable( UIState::StateFlagNormal, drawable, ownIt ); + return this; } Color UINode::getForegroundColor() const { - return getForegroundColor( mState ); -} - -Color UINode::getForegroundColor( const Uint32 & state ) const { if ( NULL != mForegroundState ) - return mForegroundState->getStateColor( state ); + return mForegroundState->getStateColor( UIState::StateFlagNormal ); - return Color::White; + return Color::Transparent; } -UINode * UINode::setForegroundColor( const Uint32 & state, const Color& color ) { +UINode * UINode::setForegroundColor( const Color& color ) { UISkin * foreground = setForegroundFillEnabled( true ); - Drawable * stateDrawable = foreground->getStateDrawable( state ); + Drawable * stateDrawable = foreground->getStateDrawable( UIState::StateFlagNormal ); if ( NULL == stateDrawable ) - setForegroundDrawable( state, RectangleDrawable::New(), true ); + setForegroundDrawable( RectangleDrawable::New(), true ); if ( NULL != mForegroundState ) - mForegroundState->setStateColor( state, color ); + mForegroundState->setStateColor( UIState::StateFlagNormal, color ); return this; } -UINode * UINode::setForegroundColor( const Color& color ) { - return setForegroundColor( UIState::StateFlagNormal, color ); -} - -UINode * UINode::setForegroundRadius( const Uint32& state, const unsigned int& corners ) { +UINode * UINode::setForegroundRadius( const unsigned int& corners ) { UISkin * foreground = setForegroundFillEnabled( true ); - Drawable * stateDrawable = foreground->getStateDrawable( state ); + Drawable * stateDrawable = foreground->getStateDrawable( UIState::StateFlagNormal ); if ( NULL == stateDrawable ) { - setForegroundColor( state, Color::Black ); + setForegroundColor( Color::Black ); - stateDrawable = foreground->getStateDrawable( state ); + stateDrawable = foreground->getStateDrawable( UIState::StateFlagNormal ); } if ( stateDrawable->getDrawableType() == Drawable::RECTANGLE ) { @@ -542,8 +507,18 @@ UINode * UINode::setForegroundRadius( const Uint32& state, const unsigned int& c return this; } -UINode * UINode::setForegroundRadius( const unsigned int& corners ) { - return setForegroundRadius( UIState::StateFlagNormal, corners ); +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 ) { @@ -576,6 +551,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; } @@ -610,7 +589,7 @@ UINode * UINode::unsetFlags(const Uint32 & flags) { return this; } -UINode *UINode::resetFlags( Uint32 newFlags ) { +UINode * UINode::resetFlags( Uint32 newFlags ) { mFlags = newFlags; return this; } @@ -629,18 +608,8 @@ void UINode::drawForeground() { void UINode::drawBorder() { if ( ( mFlags & UI_BORDER ) && NULL != mBorder ) { - if ( NULL != mBorder && NULL != mBackgroundState && NULL != mBackgroundState->getSkin() ) { - Drawable * backDrawable = mBackgroundState->getSkin()->getStateDrawable( mBackgroundState->getCurrentState() ); - - if ( NULL != backDrawable && backDrawable->getDrawableType() == Drawable::RECTANGLE ) { - RectangleDrawable * backgroundDrawable = static_cast( backDrawable ); - - getBorder()->setCorners( backgroundDrawable->getCorners() ); - } - } - Uint8 alpha = mBorder->getAlpha(); - mBorder->setAlpha( eemax( mAlpha * alpha / 255.f, 255 ) ); + mBorder->setAlpha( eemin( mAlpha * alpha / 255.f, 255 ) ); mBorder->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ), Sizef( eefloor(mSize.getWidth()), eefloor(mSize.getHeight()) ) ); mBorder->setAlpha( alpha ); } @@ -694,6 +663,7 @@ UISkin * UINode::getForeground() { RectangleDrawable * UINode::getBorder() { if ( NULL == mBorder ) { mBorder = RectangleDrawable::New(); + mBorder->setColor( Color::Transparent ); mBorder->setFillMode( PrimitiveFillMode::DRAW_LINE ); mBorder->setLineWidth( PixelDensity::dpToPx(1) ); } @@ -757,26 +727,13 @@ UINode * UINode::setSkin( UISkin * skin ) { return this; } -UINode * UINode::setSkinColor( const Uint32& state, const Color& color ) { - if ( NULL != mSkinState ) - mSkinState->setStateColor( state, color ); - +UINode * UINode::setSkinColor( const Color& color ) { + mSkinColor = color; return this; } -UINode * UINode::setSkinColor( const Color& color ) { - return setSkinColor( UIState::StateFlagNormal, color ); -} - -Color UINode::getSkinColor( const Uint32& state ) const { - if ( NULL != mSkinState ) - return mSkinState->getStateColor( state ); - - return Color::White; -} - -Color UINode::getSkinColor() const { - return getSkinColor( UIState::StateFlagNormal ); +const Color& UINode::getSkinColor() const { + return mSkinColor; } void UINode::removeSkin() { diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index cc454ee3c..b258db4db 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace EE { namespace UI { @@ -29,7 +30,7 @@ UISceneNode::UISceneNode( EE::Window::Window * window ) : } void UISceneNode::resizeControl( EE::Window::Window * ) { - setSize( (Float)mWindow->getWidth() / PixelDensity::getPixelDensity(), (Float)mWindow->getHeight() / PixelDensity::getPixelDensity() ); + setSize( eefloor( mWindow->getWidth() / PixelDensity::getPixelDensity() ), eefloor(mWindow->getHeight() / PixelDensity::getPixelDensity()) ); sendMsg( this, NodeMessage::WindowResize ); } @@ -123,12 +124,26 @@ void UISceneNode::setStyleSheet( const CSS::StyleSheet& styleSheet ) { reloadStyle(); } -void UISceneNode::combineStyleSheet(const CSS::StyleSheet & styleSheet) { +void UISceneNode::setStyleSheet( const std::string& inlineStyleSheet ) { + CSS::StyleSheetParser parser; + + if ( parser.loadFromString( inlineStyleSheet ) ) + setStyleSheet( parser.getStyleSheet() ); +} + +void UISceneNode::combineStyleSheet( const CSS::StyleSheet& styleSheet ) { mStyleSheet.combineStyleSheet( styleSheet ); reloadStyle(); } +void UISceneNode::combineStyleSheet( const std::string& inlineStyleSheet ) { + CSS::StyleSheetParser parser; + + if ( parser.loadFromString( inlineStyleSheet ) ) + combineStyleSheet( parser.getStyleSheet() ); +} + CSS::StyleSheet& UISceneNode::getStyleSheet() { return mStyleSheet; } diff --git a/src/eepp/ui/uiscrollview.cpp b/src/eepp/ui/uiscrollview.cpp index ab8ac9bc5..15598d19d 100644 --- a/src/eepp/ui/uiscrollview.cpp +++ b/src/eepp/ui/uiscrollview.cpp @@ -15,7 +15,7 @@ UIScrollView::UIScrollView() : mHScrollMode( UI_SCROLLBAR_AUTO ), mVScroll( UIScrollBar::NewVertical() ), mHScroll( UIScrollBar::NewHorizontal() ), - mContainer( UINode::New() ), + mContainer( UIWidget::NewWithTag( "scrollview::container" ) ), mScrollView( NULL ), mSizeChangeCb( 0 ) { @@ -131,7 +131,7 @@ UIScrollBar * UIScrollView::getHorizontalScrollBar() const { return mHScroll; } -UINode * UIScrollView::getContainer() const { +UIWidget * UIScrollView::getContainer() const { return mContainer; } diff --git a/src/eepp/ui/uistate.cpp b/src/eepp/ui/uistate.cpp index ba4fd9737..f80dcdb3b 100644 --- a/src/eepp/ui/uistate.cpp +++ b/src/eepp/ui/uistate.cpp @@ -39,6 +39,16 @@ int UIState::getStateNumber( const std::string& State ) { return -1; } +const char * UIState::getStateNameFromStateFlag( const Uint32& stateFlag ) { + for ( int i = 0; i < UIState::StateCount; i++ ) { + if ( stateFlag == UIStateFlags[i] ) { + return UIStatesNames[i]; + } + } + + return NULL; +} + const Uint32& UIState::getStateFlag( const Uint32& stateIndex ) { return UIStateFlags[ stateIndex ]; } diff --git a/src/eepp/ui/uistyle.cpp b/src/eepp/ui/uistyle.cpp index f09645e6b..6730ba65c 100644 --- a/src/eepp/ui/uistyle.cpp +++ b/src/eepp/ui/uistyle.cpp @@ -8,7 +8,7 @@ using namespace EE::UI::CSS; namespace EE { namespace UI { -UIStyle * EE::UI::UIStyle::New( UIWidget * widget ) { +UIStyle * UIStyle::New( UIWidget * widget ) { return eeNew( UIStyle, ( widget ) ); } @@ -18,42 +18,38 @@ UIStyle::UIStyle( UIWidget * widget ) : load(); } -UIStyle::~UIStyle() -{} - -bool UIStyle::stateExists( const EE::Uint32 & state ) const { - return mStates.find( state ) != mStates.end(); +UIStyle::~UIStyle() { + removeRelatedWidgets(); + unsubscribeNonCacheableStyles(); } -void UIStyle::addStyleSheetProperty( const Uint32& state, const StyleSheetProperty& attribute ) { +bool UIStyle::stateExists( const EE::Uint32& ) const { + return true; +} + +void UIStyle::setStyleSheetProperty( const StyleSheetProperty& attribute ) { if ( attribute.getName() == "padding" ) { Rectf rect( NodeAttribute( attribute.getName(), attribute.getValue() ).asRectf() ); - mStates[ state ][ "paddingleft" ] = StyleSheetProperty( "paddingleft", String::toStr( rect.Left ), attribute.getSpecificity() ); - mStates[ state ][ "paddingright" ] = StyleSheetProperty( "paddingright", String::toStr( rect.Right ), attribute.getSpecificity() ); - mStates[ state ][ "paddingtop" ] = StyleSheetProperty( "paddingtop", String::toStr( rect.Top ), attribute.getSpecificity() ); - mStates[ state ][ "paddingbottom" ] = StyleSheetProperty( "paddingbottom", String::toStr( rect.Bottom ), attribute.getSpecificity() ); + mElementStyle.setProperty( StyleSheetProperty( "paddingleft", String::toStr( rect.Left ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "paddingright", String::toStr( rect.Right ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "paddingtop", String::toStr( rect.Top ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "paddingbottom", String::toStr( rect.Bottom ), attribute.getSpecificity(), attribute.isVolatile() ) ); } else if ( attribute.getName() == "layout_margin" ) { Rect rect( NodeAttribute( attribute.getName(), attribute.getValue() ).asRect() ); - mStates[ state ][ "layout_marginleft" ] = StyleSheetProperty( "layout_marginleft", String::toStr( rect.Left ), attribute.getSpecificity() ); - mStates[ state ][ "layout_marginright" ] = StyleSheetProperty( "layout_marginright", String::toStr( rect.Right ), attribute.getSpecificity() ); - mStates[ state ][ "layout_margintop" ] = StyleSheetProperty( "layout_margintop", String::toStr( rect.Top ), attribute.getSpecificity() ); - mStates[ state ][ "layout_marginbottom" ] = StyleSheetProperty( "layout_marginbottom", String::toStr( rect.Bottom ), attribute.getSpecificity() ); + mElementStyle.setProperty( StyleSheetProperty( "layout_marginleft", String::toStr( rect.Left ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "layout_marginright", String::toStr( rect.Right ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "layout_margintop", String::toStr( rect.Top ), attribute.getSpecificity(), attribute.isVolatile() ) ); + mElementStyle.setProperty( StyleSheetProperty( "layout_marginbottom", String::toStr( rect.Bottom ), attribute.getSpecificity(), attribute.isVolatile() ) ); } else { - mStates[ state ][ attribute.getName() ] = attribute; - } - - if ( String::startsWith( attribute.getName(), "transition" ) ) { - mTransitionAttributes[ state ].push_back( attribute ); - - parseTransitions( state ); + mElementStyle.setProperty( attribute ); } } void UIStyle::load() { - mStates.clear(); + unsubscribeNonCacheableStyles(); + + mCacheableStyles.clear(); mNoncacheableStyles.clear(); - mTransitions.clear(); - mTransitionAttributes.clear(); UISceneNode * uiSceneNode = mWidget->getSceneNode()->isUISceneNode() ? static_cast( mWidget->getSceneNode() ) : NULL; @@ -61,165 +57,140 @@ void UIStyle::load() { CSS::StyleSheet& styleSheet = uiSceneNode->getStyleSheet(); if ( !styleSheet.isEmpty() ) { - CSS::StyleSheet::StyleSheetPseudoClassProperties propertiesByPseudoClass = styleSheet.getElementPropertiesByState( mWidget ); + StyleSheetStyleVector styles = styleSheet.getElementStyles( mWidget ); - if ( !propertiesByPseudoClass.empty() ) { - Uint32 stateFlag; + for ( auto& style : styles ) { + const StyleSheetSelector& selector = style.getSelector(); - for ( auto it = propertiesByPseudoClass.begin(); it != propertiesByPseudoClass.end(); ++it ) { - stateFlag = getStateFlagFromName( it->first ); - - if ( eeINDEX_NOT_FOUND != stateFlag ) - addStyleSheetProperties( stateFlag, it->second ); + if ( selector.isCacheable() ) { + mCacheableStyles.push_back( style ); + } else { + mNoncacheableStyles.push_back( style ); } } - mNoncacheableStyles = styleSheet.getNoncacheableElementStyles( mWidget ); + subscribeNonCacheableStyles(); } } } -void UIStyle::addStyleSheetProperties(const Uint32 & state, const CSS::StyleSheetProperties& properties ) { +void UIStyle::setStyleSheetProperties( const CSS::StyleSheetProperties& properties ) { if ( !properties.empty() ) { - for ( auto it = properties.begin(); it != properties.end(); ++it ) { - CSS::StyleSheetProperty property = it->second; - - addStyleSheetProperty( state, property ); + for ( const auto& it : properties ) { + setStyleSheetProperty( it.second ); } } } -bool UIStyle::hasTransition( const Uint32& state, const std::string& propertyName ) { - bool ret = mTransitions.find( state ) != mTransitions.end() && - ( mTransitions[ state ].find( propertyName ) != mTransitions[ state ].end() || - mTransitions[ state ].find( "all" ) != mTransitions[ state ].end() - ); - - // When transitions are declared without state are global - if ( !ret && state != StateFlagNormal ) { - ret = mTransitions.find( StateFlagNormal ) != mTransitions.end() && ( - mTransitions[ StateFlagNormal ].find( propertyName ) != mTransitions[ StateFlagNormal ].end() || - mTransitions[ StateFlagNormal ].find( "all" ) != mTransitions[ StateFlagNormal ].end() - ); - } - - return ret; +bool UIStyle::hasTransition( const std::string& propertyName ) { + return mTransitions.find( propertyName ) != mTransitions.end() || mTransitions.find( "all" ) != mTransitions.end(); } -UIStyle::TransitionInfo UIStyle::getTransition( const Uint32& state, const std::string& propertyName ) { - if ( mTransitions.find( state ) != mTransitions.end() ) { - auto propertyTransitionIt = mTransitions[ state ].find( propertyName ); +UIStyle::TransitionInfo UIStyle::getTransition( const std::string& propertyName ) { + auto propertyTransitionIt = mTransitions.find( propertyName ); - if ( propertyTransitionIt != mTransitions[ state ].end() ) { - return propertyTransitionIt->second; - } else if ( ( propertyTransitionIt = mTransitions[ state ].find( "all" ) ) != mTransitions[ state ].end() ) { - return propertyTransitionIt->second; - } else if ( mTransitions.find( StateFlagNormal ) != mTransitions.end() ) { - propertyTransitionIt = mTransitions[ StateFlagNormal ].find( propertyName ); - - if ( propertyTransitionIt != mTransitions[ StateFlagNormal ].end() ) { - return propertyTransitionIt->second; - } else if ( ( propertyTransitionIt = mTransitions[ StateFlagNormal ].find( "all" ) ) != mTransitions[ state ].end() ) { - return propertyTransitionIt->second; - } - } - } else if ( mTransitions.find( StateFlagNormal ) != mTransitions.end() ) { - auto propertyTransitionIt = mTransitions[ StateFlagNormal ].find( propertyName ); - - if ( propertyTransitionIt != mTransitions[ StateFlagNormal ].end() ) { - return propertyTransitionIt->second; - } else if ( ( propertyTransitionIt = mTransitions[ StateFlagNormal ].find( "all" ) ) != mTransitions[ state ].end() ) { - return propertyTransitionIt->second; - } + if ( propertyTransitionIt != mTransitions.end() ) { + return propertyTransitionIt->second; + } else if ( ( propertyTransitionIt = mTransitions.find( "all" ) ) != mTransitions.end() ) { + return propertyTransitionIt->second; } return TransitionInfo(); } +void UIStyle::subscribeRelated( UIWidget * widget ) { + mRelatedWidgets.insert( widget ); +} + +void UIStyle::unsubscribeRelated( UIWidget * widget ) { + mRelatedWidgets.erase( widget ); +} + +void UIStyle::tryApplyStyle( const StyleSheetStyle& style ) { + if ( style.getSelector().select( mWidget ) ) { + for ( const auto& prop : style.getProperties() ) { + const StyleSheetProperty& property = prop.second; + const auto& it = mProperties.find( property.getName() ); + + if ( it == mProperties.end() || property.getSpecificity() >= it->second.getSpecificity() ) { + mProperties[ property.getName() ] = property; + + if ( String::startsWith( property.getName(), "transition" ) ) + mTransitionAttributes.push_back( property ); + } + } + } +} + void UIStyle::onStateChange() { if ( NULL != mWidget ) { - StyleSheetProperties properties; + mProperties.clear(); + mTransitionAttributes.clear(); - auto& props = mStates[ mCurrentState ]; + tryApplyStyle( mElementStyle ); - for ( auto& prop : props ) { - auto& property = prop.second; - auto it = properties.find( property.getName() ); - - if ( it == properties.end() || property.getSpecificity() >= it->second.getSpecificity() ) { - properties[ property.getName() ] = property; - } + for ( auto& style : mCacheableStyles ) { + tryApplyStyle( style ); } for ( auto& style : mNoncacheableStyles ) { - if ( style.getSelector().select( mWidget ) ) { - for ( auto& prop : style.getProperties() ) { - auto& property = prop.second; - auto it = properties.find( property.getName() ); - - if ( it == properties.end() || property.getSpecificity() >= it->second.getSpecificity() ) { - properties[ property.getName() ] = property; - } - } - } + tryApplyStyle( style ); } + parseTransitions(); + mWidget->beginAttributesTransaction(); - for ( auto& prop : properties ) { - auto& property = prop.second; + for ( const auto& prop : mProperties ) { + const StyleSheetProperty& property = prop.second; - mWidget->setAttribute( property.getName(), property.getValue(), mCurrentState ); + mWidget->setAttribute( NodeAttribute( property.getName(), property.getValue(), property.isVolatile() ), mCurrentState ); } mWidget->endAttributesTransaction(); - } -} -StyleSheetProperty UIStyle::getStyleSheetProperty( const Uint32& state, const std::string& attributeName ) const { - if ( !attributeName.empty() && stateExists( state ) ) { - auto& attributesMap = mStates.at( state ); - - auto attributeFound = attributesMap.find( attributeName ); - - if ( attributeFound != attributesMap.end() ) { - return attributeFound->second; - } - } - - return StyleSheetProperty(); -} - -StyleSheetProperty UIStyle::getStyleSheetPropertyFromNames( const Uint32& state, const std::vector& propertiesNames ) const { - if ( !propertiesNames.empty() && stateExists( state ) ) { - auto& attributesMap = mStates.at( state ); - - for ( size_t i = 0; i < propertiesNames.size(); i++ ) { - const std::string& name = propertiesNames[i]; - auto attributeFound = attributesMap.find( name ); - - if ( attributeFound != attributesMap.end() ) { - return attributeFound->second; + for ( auto& related : mRelatedWidgets ) { + if ( NULL != related->getUIStyle() ) { + related->getUIStyle()->onStateChange(); } + } + } +} +StyleSheetProperty UIStyle::getStatelessStyleSheetProperty( const std::string& propertyName ) const { + if ( !propertyName.empty() ) { + if ( !mElementStyle.getSelector().hasPseudoClasses() ) { + StyleSheetProperty property = mElementStyle.getPropertyByName( propertyName ); + + if ( !property.isEmpty() ) + return property; + } + + for ( const StyleSheetStyle& style : mCacheableStyles ) { + if ( !style.getSelector().hasPseudoClasses() ) { + StyleSheetProperty property = style.getPropertyByName( propertyName ); + + if ( !property.isEmpty() ) + return property; + } } } return StyleSheetProperty(); } -NodeAttribute UIStyle::getNodeAttribute( const Uint32& state, const std::string& attributeName ) const { - StyleSheetProperty property( getStyleSheetProperty( state, attributeName ) ); - return NodeAttribute( property.getName(), property.getValue() ); +StyleSheetProperty UIStyle::getStyleSheetProperty( const std::string& propertyName ) const { + auto propertyIt = mProperties.find( propertyName ); + + if ( propertyIt != mProperties.end() ) + return propertyIt->second; + + return StyleSheetProperty(); } -bool UIStyle::hasStyleSheetProperty( const Uint32 & state, const std::string& propertyName ) const { - if ( !propertyName.empty() && stateExists( state ) ) { - auto& attributesMap = mStates.at( state ); - return attributesMap.find( propertyName ) != attributesMap.end(); - } - - return false; +NodeAttribute UIStyle::getNodeAttribute( const std::string& attributeName ) const { + StyleSheetProperty property( getStyleSheetProperty( attributeName ) ); + return NodeAttribute( property.getName(), property.getValue() ); } void UIStyle::updateState() { @@ -229,36 +200,65 @@ void UIStyle::updateState() { if ( mCurrentState != getStateFlag(i) ) { mPreviousState = mCurrentState; mCurrentState = getStateFlag(i); - onStateChange(); + break; } - - return; } } } - Uint32 currentState = mCurrentState; + onStateChange(); +} - mCurrentState = StateFlagNormal; +void UIStyle::subscribeNonCacheableStyles() { + for ( auto& style : mNoncacheableStyles ) { + std::vector elements = style.getSelector().getRelatedElements( mWidget, false ); - if ( currentState != StateFlagNormal ) { - onStateChange(); + if ( !elements.empty() ) { + for ( auto& element : elements ) { + UIWidget * widget = dynamic_cast( element ); + + if ( NULL != widget && NULL != widget->getUIStyle() ) { + widget->getUIStyle()->subscribeRelated( mWidget ); + + mSubscribedWidgets.insert( widget ); + } + } + } } } -void UIStyle::parseTransitions( const Uint32& state ) { +void UIStyle::unsubscribeNonCacheableStyles() { + for ( auto& widget : mSubscribedWidgets ) { + if ( NULL != widget->getUIStyle() ) { + widget->getUIStyle()->unsubscribeRelated( mWidget ); + } + } + + mSubscribedWidgets.clear(); +} + +void UIStyle::removeFromSubscribedWidgets( UIWidget * widget ) { + mSubscribedWidgets.erase( widget ); +} + +void UIStyle::removeRelatedWidgets() { + for ( auto& widget : mRelatedWidgets ) { + if ( NULL != widget->getUIStyle() ) { + widget->getUIStyle()->removeFromSubscribedWidgets( mWidget ); + } + } + + mRelatedWidgets.clear(); +} + +void UIStyle::parseTransitions() { std::vector properties; std::vector