diff --git a/include/eepp/ui/css/stylesheetelement.hpp b/include/eepp/ui/css/stylesheetelement.hpp index 53232b935..2cf0c7ba9 100644 --- a/include/eepp/ui/css/stylesheetelement.hpp +++ b/include/eepp/ui/css/stylesheetelement.hpp @@ -20,6 +20,8 @@ class EE_API StyleSheetElement { virtual StyleSheetElement * getStyleSheetPreviousSiblingElement() const = 0; virtual StyleSheetElement * getStyleSheetNextSiblingElement() const = 0; + + virtual const std::vector& getStyleSheetPseudoClasses() const = 0; }; }}} diff --git a/include/eepp/ui/css/stylesheetselector.hpp b/include/eepp/ui/css/stylesheetselector.hpp index 95da92591..4ea1c0a00 100644 --- a/include/eepp/ui/css/stylesheetselector.hpp +++ b/include/eepp/ui/css/stylesheetselector.hpp @@ -2,6 +2,7 @@ #define EE_UI_CSS_STYLESHEETSELECTOR_HPP #include +#include namespace EE { namespace UI { namespace CSS { @@ -9,72 +10,6 @@ class StyleSheetElement; class EE_API StyleSheetSelector { public: - enum SelectorType { - TagName = 1 << 0, - Id = 1 << 1, - Class = 1 << 2, - PseudoClass = 1 << 3 - }; - - enum SpecificityVal { - SpecificityId = 1000000, - SpecificityClass = 100000, - SpecificityTag = 10000, - SpecificityPseudoClass = 100, - SpecificityGlobal = 1 - }; - - enum PatternMatch { - ANY = '*', - DESCENDANT = ' ', - CHILD = '>', - DIRECT_SIBLING = '+', - SIBLING = '~' - }; - - enum SelectoryTypeIdentifier { - TAG = 0, - GLOBAL = '*', - CLASS = '.', - ID = '#', - PSEUDO_CLASS = ':', - STRUCTURAL_PSEUDO_CLASS = ':' - }; - - class SelectorRule { - public: - SelectorRule( const std::string& selectorFragment, PatternMatch patternMatch ); - - void pushSelectorTypeIdentifier( SelectoryTypeIdentifier selectorTypeIdentifier, std::string name ); - - void parseFragment( const std::string& selectorFragment ); - - const PatternMatch& getPatternMatch() const { return patternMatch; } - - const int& getSpecificity() const { return specificity; } - - bool matches( StyleSheetElement * element ) const; - - bool hasClass( const std::string& cls ) const; - - bool hasPseudoClasses() const; - - const std::vector& getPseudoClasses() const; - - bool hasStructuralPseudoClasses() const; - - const std::vector& getStructuralPseudoClasses() const; - - int specificity; - PatternMatch patternMatch; - std::string tagName; - std::string id; - std::vector classes; - std::vector pseudoClasses; - std::vector structuralPseudoClasses; - Uint32 requirementFlags; - }; - StyleSheetSelector(); explicit StyleSheetSelector( const std::string& selectorName ); @@ -86,13 +21,16 @@ class EE_API StyleSheetSelector { const Uint32& getSpecificity() const; bool matches( StyleSheetElement * element ) const; + + const bool& isCacheable() const; protected: std::string mName; std::string mPseudoClass; Uint32 mSpecificity; - std::vector mSelectorRules; + std::vector mSelectorRules; + bool mCacheable; - void addSelectorRule(std::string& buffer, PatternMatch& curPatternMatch, const PatternMatch & newPatternMatch ); + void addSelectorRule(std::string& buffer, StyleSheetSelectorRule::PatternMatch& curPatternMatch, const StyleSheetSelectorRule::PatternMatch & newPatternMatch ); void parseSelector( std::string selector ); }; diff --git a/include/eepp/ui/css/stylesheetselectorrule.hpp b/include/eepp/ui/css/stylesheetselectorrule.hpp new file mode 100644 index 000000000..b67ae5afa --- /dev/null +++ b/include/eepp/ui/css/stylesheetselectorrule.hpp @@ -0,0 +1,82 @@ +#ifndef STYLESHEETSELECTORRULE_HPP +#define STYLESHEETSELECTORRULE_HPP + +#include + +namespace EE { namespace UI { namespace CSS { + +class StyleSheetElement; + +class StyleSheetSelectorRule { + public: + enum TypeIdentifier { + TAG = 0, + GLOBAL = '*', + CLASS = '.', + ID = '#', + PSEUDO_CLASS = ':', + STRUCTURAL_PSEUDO_CLASS = ':' + }; + + enum SelectorType { + TagName = 1 << 0, + Id = 1 << 1, + Class = 1 << 2, + PseudoClass = 1 << 3 + }; + + enum SpecificityVal { + SpecificityId = 1000000, + SpecificityClass = 100000, + SpecificityTag = 10000, + SpecificityPseudoClass = 100, + SpecificityGlobal = 1 + }; + + enum PatternMatch { + ANY = '*', + DESCENDANT = ' ', + CHILD = '>', + DIRECT_SIBLING = '+', + SIBLING = '~' + }; + + StyleSheetSelectorRule( const std::string& selectorFragment, PatternMatch mPatternMatch ); + + void pushSelectorTypeIdentifier( TypeIdentifier selectorTypeIdentifier, std::string name ); + + void parseFragment( const std::string& selectorFragment ); + + const PatternMatch& getPatternMatch() const { return mPatternMatch; } + + const int& getSpecificity() const { return mSpecificity; } + + bool matches( StyleSheetElement * element ) const; + + bool hasClass( const std::string& cls ) const; + + bool hasPseudoClasses() const; + + bool hasPseudoClass(const std::string & cls) const; + + const std::vector& getPseudoClasses() const; + + bool hasStructuralPseudoClasses() const; + + const std::vector& getStructuralPseudoClasses() const; + + bool hasStructuralPseudoClass(const std::string & cls) const; + + int mSpecificity; + PatternMatch mPatternMatch; + std::string mTagName; + std::string mId; + std::vector mClasses; + std::vector mPseudoClasses; + std::vector mStructuralPseudoClasses; + Uint32 mRequirementFlags; +}; + +}}} + +#endif diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index c40d151ca..cdc500697 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -112,6 +112,8 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { StyleSheetElement * getStyleSheetNextSiblingElement() const; + const std::vector& getStyleSheetPseudoClasses() const; + void addClass( const std::string& cls ); void addClasses( const std::vector& classes ); @@ -161,9 +163,12 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement { int mAttributesTransactionCount; std::string mSkinName; std::vector mClasses; + std::vector mPseudoClasses; explicit UIWidget( const std::string& tag ); + void updatePseudoClasses(); + void createTooltip(); virtual Uint32 onMouseMove( const Vector2i& Pos, const Uint32& Flags ); diff --git a/projects/linux/ee.files b/projects/linux/ee.files index ed9b2d90c..c6b4d52ba 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -310,6 +310,7 @@ ../../include/eepp/ui/css/stylesheetproperty.hpp ../../include/eepp/ui/css/stylesheetselector.hpp ../../include/eepp/ui/css/stylesheetselectorparser.hpp +../../include/eepp/ui/css/stylesheetselectorrule.hpp ../../include/eepp/ui/marginmove/scale.hpp ../../include/eepp/ui/tools/textureatlaseditor.hpp ../../include/eepp/ui/uicheckbox.hpp @@ -719,6 +720,7 @@ ../../src/eepp/ui/css/stylesheetproperty.cpp ../../src/eepp/ui/css/stylesheetselector.cpp ../../src/eepp/ui/css/stylesheetselectorparser.cpp +../../src/eepp/ui/css/stylesheetselectorrule.cpp ../../src/eepp/ui/tools/textureatlaseditor.cpp ../../src/eepp/ui/tools/textureatlasnew.cpp ../../src/eepp/ui/tools/textureatlasnew.hpp diff --git a/src/eepp/ui/css/stylesheetselector.cpp b/src/eepp/ui/css/stylesheetselector.cpp index bc04236c5..9ad56b580 100644 --- a/src/eepp/ui/css/stylesheetselector.cpp +++ b/src/eepp/ui/css/stylesheetselector.cpp @@ -1,252 +1,17 @@ #include #include -#include namespace EE { namespace UI { namespace CSS { -static const char * StatePseudoClasses[] = { - "normal", - "focus", - "selected", - "hover", - "pressed", - "selectedhover", - "selectedpressed", - "disabled" -}; - -static bool isPseudoClassState( const std::string& pseudoClass ) { - for ( Uint32 i = 0; i < eeARRAY_SIZE(StatePseudoClasses); i++ ) { - if ( pseudoClass == StatePseudoClasses[i] ) - return true; - } - - return false; -} - -static const char * StructuralPseudoClasses[] = { - "root", - "nth-child", - "nth-last-child", - "nth-of-type", - "nth-last-of-type", - "nth-child", - "nth-last-child", - "first-of-type", - "last-of-type", - "only-child", - "only-of-type", - "empty" -}; - -static bool isStructuralPseudoClass( const std::string& pseudoClass ) { - for ( Uint32 i = 0; i < eeARRAY_SIZE(StructuralPseudoClasses); i++ ) { - if ( String::startsWith( StructuralPseudoClasses[i], pseudoClass ) ) - return true; - } - - return false; -} - -static void splitSelectorPseudoClass( const std::string& selector, std::string& realSelector, std::string& realPseudoClass ) { - if ( !selector.empty() ) { - bool lastWasColon = false; - - for ( int i = (Int32)selector.size() - 1; i >= 0; i-- ) { - char curChar = selector[i]; - - if ( lastWasColon ) { - if ( StyleSheetSelector::PSEUDO_CLASS == curChar ) { - // no pseudo class - realSelector = selector; - } else { - if ( i+2 <= (int)selector.size() ) { - realSelector = selector.substr(0,i+1); - realPseudoClass = selector.substr(i+2); - } else { - realSelector = selector; - } - } - - return; - } else if ( StyleSheetSelector::PSEUDO_CLASS == curChar ) { - lastWasColon = true; - } - } - - if ( lastWasColon ) { - if ( selector.size() > 1 ) - realPseudoClass = selector.substr(1); - } else { - realSelector = selector; - } - } -} - -StyleSheetSelector::SelectorRule::SelectorRule( const std::string& selectorFragment, StyleSheetSelector::PatternMatch patternMatch ) : - specificity(0), - patternMatch( patternMatch ), - requirementFlags(0) -{ - parseFragment( selectorFragment ); -} - -void StyleSheetSelector::SelectorRule::pushSelectorTypeIdentifier( SelectoryTypeIdentifier selectorTypeIdentifier, std::string name ) { - switch ( selectorTypeIdentifier ) { - case GLOBAL: - tagName = name; - specificity += StyleSheetSelector::SpecificityGlobal; - case TAG: - tagName = name; - specificity += StyleSheetSelector::SpecificityTag; - break; - case CLASS: - classes.push_back( name ); - specificity += StyleSheetSelector::SpecificityClass; - break; - case ID: - id = name; - specificity += StyleSheetSelector::SpecificityId; - break; - default: - break; - } -} - -void StyleSheetSelector::SelectorRule::parseFragment( const std::string& selectorFragment ) { - std::string selector = selectorFragment; - std::string realSelector = ""; - std::string pseudoClass = ""; - - do { - pseudoClass.clear(); - realSelector.clear(); - - splitSelectorPseudoClass( selector, realSelector, pseudoClass ); - - if ( !pseudoClass.empty() ) { - if ( isPseudoClassState( pseudoClass ) ) { - pseudoClasses.push_back( pseudoClass ); - } else if ( isStructuralPseudoClass( pseudoClass ) ) { - structuralPseudoClasses.push_back( pseudoClass ); - } - - selector = realSelector; - } - } while ( !pseudoClass.empty() ); - - SelectoryTypeIdentifier curSelectorType = TAG; - std::string buffer; - - for ( auto charIt = selector.begin(); charIt != selector.end(); ++charIt ) { - char curChar = *charIt; - - switch ( curChar ) { - case CLASS: - { - if ( !buffer.empty() ) { - pushSelectorTypeIdentifier( curSelectorType, buffer ); - buffer.clear(); - } - - curSelectorType = CLASS; - - break; - } - case ID: - { - if ( !buffer.empty() ) { - pushSelectorTypeIdentifier( curSelectorType, buffer ); - buffer.clear(); - } - - curSelectorType = ID; - - break; - } - default: - { - buffer += curChar; - break; - } - } - } - - if ( !buffer.empty() ) { - if ( buffer.size() == 1 && buffer[0] == GLOBAL ) - curSelectorType = GLOBAL; - - pushSelectorTypeIdentifier( curSelectorType, buffer ); - } - - if ( !tagName.empty() ) - requirementFlags |= StyleSheetSelector::TagName; - - if ( !id.empty() ) - requirementFlags |= StyleSheetSelector::Id; - - if ( !classes.empty() ) - requirementFlags |= StyleSheetSelector::Class; -} - -bool StyleSheetSelector::SelectorRule::hasClass( const std::string& cls ) const { - return std::find(classes.begin(), classes.end(), cls) != classes.end(); -} - -bool StyleSheetSelector::SelectorRule::hasPseudoClasses() const { - return !pseudoClasses.empty(); -} - -const std::vector &StyleSheetSelector::SelectorRule::getPseudoClasses() const { - return pseudoClasses; -} - -bool StyleSheetSelector::SelectorRule::hasStructuralPseudoClasses() const { - return !structuralPseudoClasses.empty(); -} - -const std::vector &StyleSheetSelector::SelectorRule::getStructuralPseudoClasses() const { - return structuralPseudoClasses; -} - -bool StyleSheetSelector::SelectorRule::matches( StyleSheetElement * element ) const { - Uint32 flags = 0; - - if ( tagName == "*" ) - return true; - - if ( !tagName.empty() && !element->getStyleSheetTag().empty() && tagName == element->getStyleSheetTag() ) { - flags |= StyleSheetSelector::TagName; - } - - if ( !id.empty() && !element->getStyleSheetId().empty() && id == element->getStyleSheetId() ) { - flags |= StyleSheetSelector::Id; - } - - if ( !classes.empty() && !element->getStyleSheetClasses().empty() ) { - bool hasClasses = true; - for ( auto cit = element->getStyleSheetClasses().begin(); cit != element->getStyleSheetClasses().end(); ++cit ) { - if ( !hasClass( *cit ) ) { - hasClasses = false; - break; - } - } - - if ( hasClasses ) { - flags |= StyleSheetSelector::Class; - } - } - - return requirementFlags == flags; -} - StyleSheetSelector::StyleSheetSelector() : - mSpecificity(0) + mSpecificity(0), + mCacheable(true) {} StyleSheetSelector::StyleSheetSelector( const std::string& selectorName ) : mName( String::toLower( selectorName ) ), - mSpecificity(0) + mSpecificity(0), + mCacheable(true) { parseSelector( mName ); } @@ -272,8 +37,8 @@ void removeExtraSpaces( std::string& string ) { String::replaceAll( string, " ~ ", "~" ); } -void StyleSheetSelector::addSelectorRule(std::string& buffer, PatternMatch& curPatternMatch , const PatternMatch& newPatternMatch ) { - SelectorRule selectorRule( buffer, curPatternMatch ); +void StyleSheetSelector::addSelectorRule(std::string& buffer, StyleSheetSelectorRule::PatternMatch& curPatternMatch , const StyleSheetSelectorRule::PatternMatch& newPatternMatch ) { + StyleSheetSelectorRule selectorRule( buffer, curPatternMatch ); mSelectorRules.push_back( selectorRule ); curPatternMatch = newPatternMatch; buffer.clear(); @@ -290,23 +55,23 @@ void StyleSheetSelector::parseSelector( std::string selector ) { removeExtraSpaces( selector ); std::string buffer; - PatternMatch curPatternMatch = ANY; + StyleSheetSelectorRule::PatternMatch curPatternMatch = StyleSheetSelectorRule::ANY; for ( auto charIt = selector.rbegin(); charIt != selector.rend(); ++charIt ) { char curChar = *charIt; switch ( curChar ) { - case DESCENDANT: - addSelectorRule( buffer, curPatternMatch, DESCENDANT ); + case StyleSheetSelectorRule::DESCENDANT: + addSelectorRule( buffer, curPatternMatch, StyleSheetSelectorRule::DESCENDANT ); break; - case CHILD: - addSelectorRule( buffer, curPatternMatch, CHILD ); + case StyleSheetSelectorRule::CHILD: + addSelectorRule( buffer, curPatternMatch, StyleSheetSelectorRule::CHILD ); break; - case DIRECT_SIBLING: - addSelectorRule( buffer, curPatternMatch, DIRECT_SIBLING ); + case StyleSheetSelectorRule::DIRECT_SIBLING: + addSelectorRule( buffer, curPatternMatch, StyleSheetSelectorRule::DIRECT_SIBLING ); break; - case SIBLING: - addSelectorRule( buffer, curPatternMatch, SIBLING ); + case StyleSheetSelectorRule::SIBLING: + addSelectorRule( buffer, curPatternMatch, StyleSheetSelectorRule::SIBLING ); break; default: buffer = curChar + buffer; @@ -315,16 +80,31 @@ void StyleSheetSelector::parseSelector( std::string selector ) { } if ( !buffer.empty() ) { - addSelectorRule( buffer, curPatternMatch, ANY ); + addSelectorRule( buffer, curPatternMatch, StyleSheetSelectorRule::ANY ); buffer.clear(); } if ( !mSelectorRules.empty() && mSelectorRules[0].hasPseudoClasses() ) { mPseudoClass = mSelectorRules[0].getPseudoClasses()[0]; } + + if ( !mSelectorRules.empty() && mSelectorRules.size() > 1 ) { + mCacheable = true; + + for ( size_t i = 1; i < mSelectorRules.size(); i++ ) { + if ( mSelectorRules[i].hasPseudoClasses() || mSelectorRules[i].hasStructuralPseudoClasses() ) { + mCacheable = false; + break; + } + } + } } } +const bool &StyleSheetSelector::isCacheable() const { + return mCacheable; +} + bool StyleSheetSelector::matches( StyleSheetElement * element ) const { if ( mSelectorRules.empty() ) return false; @@ -332,17 +112,17 @@ bool StyleSheetSelector::matches( StyleSheetElement * element ) const { StyleSheetElement * curElement = element; for ( size_t i = 0; i < mSelectorRules.size(); i++ ) { - const SelectorRule& selectorRule = mSelectorRules[i]; + const StyleSheetSelectorRule& selectorRule = mSelectorRules[i]; switch ( selectorRule.getPatternMatch() ) { - case ANY: + case StyleSheetSelectorRule::ANY: { if ( !selectorRule.matches( curElement ) ) return false; break; // continue evaluating } - case DESCENDANT: + case StyleSheetSelectorRule::DESCENDANT: { bool foundDescendant = false; @@ -361,7 +141,7 @@ bool StyleSheetSelector::matches( StyleSheetElement * element ) const { break; // continue evaluating } - case CHILD: + case StyleSheetSelectorRule::CHILD: { curElement = curElement->getStyleSheetParentElement(); @@ -370,7 +150,7 @@ bool StyleSheetSelector::matches( StyleSheetElement * element ) const { break; // continue evaluating } - case DIRECT_SIBLING: + case StyleSheetSelectorRule::DIRECT_SIBLING: { curElement = curElement->getStyleSheetPreviousSiblingElement(); @@ -379,7 +159,7 @@ bool StyleSheetSelector::matches( StyleSheetElement * element ) const { break; // continue evaluating } - case SIBLING: + case StyleSheetSelectorRule::SIBLING: { bool foundSibling = false; StyleSheetElement * prevSibling = curElement->getStyleSheetPreviousSiblingElement(); diff --git a/src/eepp/ui/css/stylesheetselectorrule.cpp b/src/eepp/ui/css/stylesheetselectorrule.cpp new file mode 100644 index 000000000..4d243863a --- /dev/null +++ b/src/eepp/ui/css/stylesheetselectorrule.cpp @@ -0,0 +1,279 @@ +#include +#include +#include + +namespace EE { namespace UI { namespace CSS { + +static const char * StatePseudoClasses[] = { + "normal", + "focus", + "selected", + "hover", + "pressed", + "selectedhover", + "selectedpressed", + "disabled" +}; + +static bool isPseudoClassState( const std::string& pseudoClass ) { + for ( Uint32 i = 0; i < eeARRAY_SIZE(StatePseudoClasses); i++ ) { + if ( pseudoClass == StatePseudoClasses[i] ) + return true; + } + + return false; +} + +static const char * StructuralPseudoClasses[] = { + "root", + "nth-child", + "nth-last-child", + "nth-of-type", + "nth-last-of-type", + "nth-child", + "nth-last-child", + "first-of-type", + "last-of-type", + "only-child", + "only-of-type", + "empty" +}; + +static bool isStructuralPseudoClass( const std::string& pseudoClass ) { + for ( Uint32 i = 0; i < eeARRAY_SIZE(StructuralPseudoClasses); i++ ) { + if ( String::startsWith( StructuralPseudoClasses[i], pseudoClass ) ) + return true; + } + + return false; +} + +static void splitSelectorPseudoClass( const std::string& selector, std::string& realSelector, std::string& realPseudoClass ) { + if ( !selector.empty() ) { + bool lastWasColon = false; + + for ( int i = (Int32)selector.size() - 1; i >= 0; i-- ) { + char curChar = selector[i]; + + if ( lastWasColon ) { + if ( StyleSheetSelectorRule::PSEUDO_CLASS == curChar ) { + // no pseudo class + realSelector = selector; + } else { + if ( i+2 <= (int)selector.size() ) { + realSelector = selector.substr(0,i+1); + realPseudoClass = selector.substr(i+2); + } else { + realSelector = selector; + } + } + + return; + } else if ( StyleSheetSelectorRule::PSEUDO_CLASS == curChar ) { + lastWasColon = true; + } + } + + if ( lastWasColon ) { + if ( selector.size() > 1 ) + realPseudoClass = selector.substr(1); + } else { + realSelector = selector; + } + } +} + + +StyleSheetSelectorRule::StyleSheetSelectorRule( const std::string& selectorFragment, PatternMatch patternMatch ) : + mSpecificity(0), + mPatternMatch( patternMatch ), + mRequirementFlags(0) +{ + parseFragment( selectorFragment ); +} + +void StyleSheetSelectorRule::pushSelectorTypeIdentifier( TypeIdentifier selectorTypeIdentifier, std::string name ) { + switch ( selectorTypeIdentifier ) { + case GLOBAL: + mTagName = name; + mSpecificity += SpecificityGlobal; + case TAG: + mTagName = name; + mSpecificity += SpecificityTag; + break; + case CLASS: + mClasses.push_back( name ); + mSpecificity += SpecificityClass; + break; + case ID: + mId = name; + mSpecificity += SpecificityId; + break; + default: + break; + } +} + +void StyleSheetSelectorRule::parseFragment( const std::string& selectorFragment ) { + std::string selector = selectorFragment; + std::string realSelector = ""; + std::string pseudoClass = ""; + + do { + pseudoClass.clear(); + realSelector.clear(); + + splitSelectorPseudoClass( selector, realSelector, pseudoClass ); + + if ( !pseudoClass.empty() ) { + if ( isPseudoClassState( pseudoClass ) ) { + mPseudoClasses.push_back( pseudoClass ); + } else if ( isStructuralPseudoClass( pseudoClass ) ) { + mStructuralPseudoClasses.push_back( pseudoClass ); + } + + selector = realSelector; + } + } while ( !pseudoClass.empty() ); + + TypeIdentifier curSelectorType = TAG; + std::string buffer; + + for ( auto charIt = selector.begin(); charIt != selector.end(); ++charIt ) { + char curChar = *charIt; + + switch ( curChar ) { + case CLASS: + { + if ( !buffer.empty() ) { + pushSelectorTypeIdentifier( curSelectorType, buffer ); + buffer.clear(); + } + + curSelectorType = CLASS; + + break; + } + case ID: + { + if ( !buffer.empty() ) { + pushSelectorTypeIdentifier( curSelectorType, buffer ); + buffer.clear(); + } + + curSelectorType = ID; + + break; + } + default: + { + buffer += curChar; + break; + } + } + } + + if ( !buffer.empty() ) { + if ( buffer.size() == 1 && buffer[0] == GLOBAL ) + curSelectorType = GLOBAL; + + pushSelectorTypeIdentifier( curSelectorType, buffer ); + } + + if ( !mTagName.empty() ) + mRequirementFlags |= TagName; + + if ( !mId.empty() ) + mRequirementFlags |= Id; + + if ( !mClasses.empty() ) + mRequirementFlags |= Class; + + if ( !mPseudoClasses.empty() ) { + //requirementFlags |= PseudoClass; + + for ( auto it = mPseudoClasses.begin(); it != mPseudoClasses.end(); ++it ) { + mSpecificity += SpecificityPseudoClass; + } + } +} + +bool StyleSheetSelectorRule::hasClass( const std::string& cls ) const { + return std::find(mClasses.begin(), mClasses.end(), cls) != mClasses.end(); +} + +bool StyleSheetSelectorRule::hasPseudoClasses() const { + return !mPseudoClasses.empty(); +} + +bool StyleSheetSelectorRule::hasPseudoClass( const std::string& cls ) const { + return std::find(mPseudoClasses.begin(), mPseudoClasses.end(), cls) != mPseudoClasses.end(); +} + +const std::vector &StyleSheetSelectorRule::getPseudoClasses() const { + return mPseudoClasses; +} + +bool StyleSheetSelectorRule::hasStructuralPseudoClasses() const { + return !mStructuralPseudoClasses.empty(); +} + +const std::vector &StyleSheetSelectorRule::getStructuralPseudoClasses() const { + return mStructuralPseudoClasses; +} + +bool StyleSheetSelectorRule::hasStructuralPseudoClass( const std::string& cls ) const { + return std::find(mStructuralPseudoClasses.begin(), mStructuralPseudoClasses.end(), cls) != mStructuralPseudoClasses.end(); +} + +bool StyleSheetSelectorRule::matches( StyleSheetElement * element ) const { + Uint32 flags = 0; + + if ( mTagName == "*" ) + return true; + + if ( !mTagName.empty() && !element->getStyleSheetTag().empty() && mTagName == element->getStyleSheetTag() ) { + flags |= TagName; + } + + if ( !mId.empty() && !element->getStyleSheetId().empty() && mId == element->getStyleSheetId() ) { + flags |= Id; + } + + if ( !mClasses.empty() && !element->getStyleSheetClasses().empty() ) { + bool hasClasses = true; + for ( auto cit = element->getStyleSheetClasses().begin(); cit != element->getStyleSheetClasses().end(); ++cit ) { + if ( !hasClass( *cit ) ) { + hasClasses = false; + break; + } + } + + if ( hasClasses ) { + flags |= Class; + } + } + + /*if ( pseudoClasses.empty() && !element->getStyleSheetPseudoClasses().empty() ) { + flags |= PseudoClass; + } else if ( !pseudoClasses.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 ) ) { + hasPseudoClasses = true; + break; + } + } + + if ( hasPseudoClasses ) { + flags |= PseudoClass; + } + }*/ + + return mRequirementFlags == flags; +} + + +}}} diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index aa00f51f8..f2ddd032c 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -480,6 +480,31 @@ CSS::StyleSheetElement * UIWidget::getStyleSheetNextSiblingElement() const { return NULL != mNext && mNext->isWidget() ? dynamic_cast( mNext ) : NULL; } +const std::vector &UIWidget::getStyleSheetPseudoClasses() const { + return mPseudoClasses; +} + +void UIWidget::updatePseudoClasses() { + mPseudoClasses.clear(); + + if ( mState & UIState::StateFlagHover ) + mPseudoClasses.push_back( "hover" ); + + if ( mState & UIState::StateFlagFocus ) + mPseudoClasses.push_back( "focus" ); + + if ( mState & UIState::StateFlagSelected ) + mPseudoClasses.push_back( "selected" ); + + if ( mState & UIState::StateFlagPressed ) + mPseudoClasses.push_back( "pressed" ); + + if ( mState & UIState::StateFlagDisabled ) + mPseudoClasses.push_back( "disabled" ); + + invalidateDraw(); +} + void UIWidget::addClass( const std::string& cls ) { if ( !cls.empty() && !containsClass( cls ) ) { mClasses.push_back( cls ); @@ -528,19 +553,29 @@ const std::string& UIWidget::getElementTag() const { void UIWidget::pushState( const Uint32& State, bool emitEvent ) { if ( !( mState & ( 1 << State ) ) ) { - if ( NULL != mStyle ) - mStyle->pushState( State ); + UINode::pushState( State, false ); - UINode::pushState( State, emitEvent ); + if ( NULL != mStyle ) { + mStyle->pushState( State ); + updatePseudoClasses(); + } + + if ( emitEvent ) + onStateChange(); } } void UIWidget::popState( const Uint32& State, bool emitEvent ) { if ( mState & ( 1 << State ) ) { - if ( NULL != mStyle ) - mStyle->popState( State ); + UINode::popState( State, false ); - UINode::popState( State, emitEvent ); + if ( NULL != mStyle ) { + mStyle->popState( State ); + updatePseudoClasses(); + } + + if ( emitEvent ) + onStateChange(); } } @@ -556,7 +591,7 @@ void UIWidget::reloadStyle( const bool& reloadChilds ) { if ( NULL != mStyle ) { mStyle->load(); - mStyle->onStateChange(); + reportStyleStateChange(); if ( NULL != mChild && reloadChilds ) { Node * ChildLoop = mChild;