mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 01:56:31 +03:00
CSS clean up.
--HG-- branch : dev
This commit is contained in:
@@ -20,6 +20,8 @@ class EE_API StyleSheetElement {
|
||||
virtual StyleSheetElement * getStyleSheetPreviousSiblingElement() const = 0;
|
||||
|
||||
virtual StyleSheetElement * getStyleSheetNextSiblingElement() const = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getStyleSheetPseudoClasses() const = 0;
|
||||
};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define EE_UI_CSS_STYLESHEETSELECTOR_HPP
|
||||
|
||||
#include <eepp/core.hpp>
|
||||
#include <eepp/ui/css/stylesheetselectorrule.hpp>
|
||||
|
||||
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<std::string>& getPseudoClasses() const;
|
||||
|
||||
bool hasStructuralPseudoClasses() const;
|
||||
|
||||
const std::vector<std::string>& getStructuralPseudoClasses() const;
|
||||
|
||||
int specificity;
|
||||
PatternMatch patternMatch;
|
||||
std::string tagName;
|
||||
std::string id;
|
||||
std::vector<std::string> classes;
|
||||
std::vector<std::string> pseudoClasses;
|
||||
std::vector<std::string> 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<SelectorRule> mSelectorRules;
|
||||
std::vector<StyleSheetSelectorRule> 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 );
|
||||
};
|
||||
|
||||
82
include/eepp/ui/css/stylesheetselectorrule.hpp
Normal file
82
include/eepp/ui/css/stylesheetselectorrule.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef STYLESHEETSELECTORRULE_HPP
|
||||
#define STYLESHEETSELECTORRULE_HPP
|
||||
|
||||
#include <eepp/core.hpp>
|
||||
|
||||
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<std::string>& getPseudoClasses() const;
|
||||
|
||||
bool hasStructuralPseudoClasses() const;
|
||||
|
||||
const std::vector<std::string>& getStructuralPseudoClasses() const;
|
||||
|
||||
bool hasStructuralPseudoClass(const std::string & cls) const;
|
||||
|
||||
int mSpecificity;
|
||||
PatternMatch mPatternMatch;
|
||||
std::string mTagName;
|
||||
std::string mId;
|
||||
std::vector<std::string> mClasses;
|
||||
std::vector<std::string> mPseudoClasses;
|
||||
std::vector<std::string> mStructuralPseudoClasses;
|
||||
Uint32 mRequirementFlags;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -112,6 +112,8 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement {
|
||||
|
||||
StyleSheetElement * getStyleSheetNextSiblingElement() const;
|
||||
|
||||
const std::vector<std::string>& getStyleSheetPseudoClasses() const;
|
||||
|
||||
void addClass( const std::string& cls );
|
||||
|
||||
void addClasses( const std::vector<std::string>& classes );
|
||||
@@ -161,9 +163,12 @@ class EE_API UIWidget : public UINode, public CSS::StyleSheetElement {
|
||||
int mAttributesTransactionCount;
|
||||
std::string mSkinName;
|
||||
std::vector<std::string> mClasses;
|
||||
std::vector<std::string> mPseudoClasses;
|
||||
|
||||
explicit UIWidget( const std::string& tag );
|
||||
|
||||
void updatePseudoClasses();
|
||||
|
||||
void createTooltip();
|
||||
|
||||
virtual Uint32 onMouseMove( const Vector2i& Pos, const Uint32& Flags );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,252 +1,17 @@
|
||||
#include <eepp/ui/css/stylesheetselector.hpp>
|
||||
#include <eepp/ui/css/stylesheetelement.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
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<std::string> &StyleSheetSelector::SelectorRule::getPseudoClasses() const {
|
||||
return pseudoClasses;
|
||||
}
|
||||
|
||||
bool StyleSheetSelector::SelectorRule::hasStructuralPseudoClasses() const {
|
||||
return !structuralPseudoClasses.empty();
|
||||
}
|
||||
|
||||
const std::vector<std::string> &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();
|
||||
|
||||
279
src/eepp/ui/css/stylesheetselectorrule.cpp
Normal file
279
src/eepp/ui/css/stylesheetselectorrule.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include <eepp/ui/css/stylesheetselectorrule.hpp>
|
||||
#include <eepp/ui/css/stylesheetelement.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
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<std::string> &StyleSheetSelectorRule::getPseudoClasses() const {
|
||||
return mPseudoClasses;
|
||||
}
|
||||
|
||||
bool StyleSheetSelectorRule::hasStructuralPseudoClasses() const {
|
||||
return !mStructuralPseudoClasses.empty();
|
||||
}
|
||||
|
||||
const std::vector<std::string> &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<std::string>& 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;
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
@@ -480,6 +480,31 @@ CSS::StyleSheetElement * UIWidget::getStyleSheetNextSiblingElement() const {
|
||||
return NULL != mNext && mNext->isWidget() ? dynamic_cast<CSS::StyleSheetElement*>( mNext ) : NULL;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &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;
|
||||
|
||||
Reference in New Issue
Block a user