/** 构造函数 */ static void Widget_Init(LCUI_Widget widget) { ZEROSET(widget, LCUI_Widget); widget->state = LCUI_WSTATE_CREATED; widget->trigger = EventTrigger(); widget->style = StyleSheet(); widget->custom_style = StyleSheet(); widget->inherited_style = StyleSheet(); widget->computed_style.opacity = 1.0; widget->computed_style.visible = TRUE; widget->computed_style.focusable = FALSE; widget->computed_style.display = SV_BLOCK; widget->computed_style.position = SV_STATIC; widget->computed_style.pointer_events = SV_AUTO; widget->computed_style.box_sizing = SV_CONTENT_BOX; widget->computed_style.margin.top.type = LCUI_STYPE_PX; widget->computed_style.margin.right.type = LCUI_STYPE_PX; widget->computed_style.margin.bottom.type = LCUI_STYPE_PX; widget->computed_style.margin.left.type = LCUI_STYPE_PX; widget->computed_style.padding.top.type = LCUI_STYPE_PX; widget->computed_style.padding.right.type = LCUI_STYPE_PX; widget->computed_style.padding.bottom.type = LCUI_STYPE_PX; widget->computed_style.padding.left.type = LCUI_STYPE_PX; Widget_InitBackground(widget); LinkedList_Init(&widget->children); LinkedList_Init(&widget->children_show); }
namespace stylesheets { class PathElement { public: PathElement(const std::string& typeName, const std::vector<std::string>& classNames = {}) : mTypeName(typeName) , mClassNames(classNames) { } bool operator==(const PathElement& other) const { return mTypeName == other.mTypeName && mClassNames == other.mClassNames; } bool operator!=(const PathElement& other) const { return !(*this == other); } std::string mTypeName; std::vector<std::string> mClassNames; }; std::size_t hash_value(const PathElement& pathElement); using UiItemPath = std::vector<PathElement>; struct UiItemPathHasher { std::size_t operator()(const UiItemPath& path) const; }; std::ostream& operator<<(std::ostream& os, const UiItemPath& path); std::string pathToString(const UiItemPath& path); using PropertyMap = std::map<QString, Property>; class IStyleMatchTree { }; std::unique_ptr<IStyleMatchTree> createMatchTree( const StyleSheet& stylesheet, const StyleSheet& defaultStylesheet = StyleSheet()); PropertyMap matchPath(const IStyleMatchTree* tree, const UiItemPath& path); std::string describeMatchedPath(const IStyleMatchTree* tree, const UiItemPath& path); } // namespace stylesheets
namespace stylesheets { class SourceLocation { public: SourceLocation() : mSourceLayer(0) , mLocInfo() { } SourceLocation(int sourceLayer, const LocInfo& locInfo) : mSourceLayer(sourceLayer) , mLocInfo(locInfo) { } bool operator<(const SourceLocation& other) const { return std::tie(mSourceLayer, mLocInfo.byteofs) < std::tie(other.mSourceLayer, other.mLocInfo.byteofs); } int mSourceLayer; LocInfo mLocInfo; }; class PropertyDef { public: PropertyDef(const SourceLocation& loc, const QVariant& value) : mSourceLoc(loc) , mValue(value) { } SourceLocation mSourceLoc; QVariant mValue; }; using PropertyDefMap = std::unordered_map<std::string, PropertyDef>; /*! The basic building block for a "match tree" * * A StyleMatchTree is constructed as a tree of @c MatchNode instances. It * is built over the selectors defined in a style sheet. Each node is a * dictionary of type/class name mapping to further match nodes. * Ultimately, a match node carries a set of property definitions (in * member propmap). * * The tree is built upside down: A selector "A B C" leads to a tree * starting at the root "C". * * All selectors from all stylesheets are merged in one matchnode tree, * i.e. the two selectors "Gaz > Bar" and "Foo > Gaz > Bar" will result in * a match node tree like this (where "{}" denote the empty property * definition set): * * @code * Bar -> {} * Gaz -> { properties } * Foo -> { properties } * @endcode * * Note the properties both at node "Gaz" and "Bar". * * Descendants selectors are constructed using the special axis denotator * "::desc::". A selector "Foo > Gaz Bar" will be constructed like this: * * @code * Bar -> {} * ::desc:: -> {} * Gaz -> {} * Foo -> { properties } * @endcode */ class MatchNode { public: MatchNode() { } MatchNode(const PropertyDefMap* pProperties) { if (pProperties) { properties = *pProperties; } } MatchNode(const MatchNode&) = delete; MatchNode& operator=(const MatchNode&) = delete; #if defined(DEBUG) void dump(const std::string& path) const; #endif PropertyDefMap properties; using Matches = std::unordered_map<std::string, std::unique_ptr<MatchNode> >; Matches matches; }; class StyleMatchTree { public: StyleMatchTree() : rootMatches(estd::make_unique<MatchNode>()) { } // For some reason visual studio 2013 wasn't capable of default-creating the // move ctors here, so we provide them explicitly here. StyleMatchTree(StyleMatchTree&& other) : rootMatches(std::move(other.rootMatches)) { } StyleMatchTree& operator=(StyleMatchTree&& other) { if (this != &other) { rootMatches = std::move(other.rootMatches); } return *this; } #if defined(DEBUG) void dump() const; #endif std::unique_ptr<MatchNode> rootMatches; }; class PathElement { public: PathElement(const std::string& typeName, const std::vector<std::string>& classNames = {}) : mTypeName(typeName) , mClassNames(classNames) { } bool operator==(const PathElement& other) const { return mTypeName == other.mTypeName && mClassNames == other.mClassNames; } bool operator!=(const PathElement& other) const { return !(*this == other); } std::string mTypeName; std::vector<std::string> mClassNames; }; using UiItemPath = std::vector<PathElement>; std::ostream& operator<<(std::ostream& os, const UiItemPath& path); std::string pathToString(const UiItemPath& path); using PropertyMap = std::map<QString, QVariant>; #if defined(DEBUG) void dumpPropertyMap(const PropertyMap& properties); #endif void mergeInheritableProperties(PropertyMap& dest, const PropertyMap& b); StyleMatchTree createMatchTree(const StyleSheet& stylesheet, const StyleSheet& defaultStylesheet = StyleSheet()); PropertyMap matchPath(const StyleMatchTree& tree, const UiItemPath& path); std::string describeMatchedPath(const StyleMatchTree& tree, const UiItemPath& path); } // namespace stylesheets
void Qss::AddSheet(int type, bool cover) { if(cover) _sheet = _p->styleSheet(); _sheet += StyleSheet(type); }
/** 载入CSS代码块,用于实现CSS代码的分块载入 */ static int LCUI_LoadCSSBlock( CSSParserContext ctx, const char *str ) { size_t size = 0; LCUI_Selector s; LinkedListNode *node; ctx->ptr = str; for( ; *ctx->ptr && size < ctx->buffer_size; ++ctx->ptr, ++size ) { switch( ctx->target ) { case TARGET_SELECTOR: switch( *ctx->ptr ) { case '/': goto proc_comment; case '{': ctx->target = TARGET_KEY; ctx->css = StyleSheet(); case ',': ctx->buffer[ctx->pos] = 0; ctx->pos = 0; DEBUG_MSG("selector: %s\n", ctx->buffer); s = Selector( ctx->buffer ); if( !s ) { // 解析出错 ... break; } LinkedList_Append( &ctx->selectors, s ); break; default: ctx->buffer[ctx->pos++] = *ctx->ptr; break; } break; case TARGET_KEY: switch( *ctx->ptr ) { case '/': goto proc_comment; case ' ': case '\n': case '\r': case '\t': case ';': ctx->pos = 0; continue; case ':': break; case '}': ctx->target = TARGET_NONE; goto put_css; default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } goto select_parser; case TARGET_VALUE: switch( *ctx->ptr ) { case '/': goto proc_comment; case '}': case ';': goto parse_value; case '\n': case '\r': case '\t': case ' ': if( ctx->pos == 0 ) { continue; } default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } break; case TARGET_COMMENT: if( ctx->is_line_comment ) { if( *ctx->ptr == '\n' ) { ctx->target = ctx->target_bak; } break; } if( *ctx->ptr == '/' && *(ctx->ptr - 1) == '*' ) { ctx->target = ctx->target_bak; } break; case TARGET_NONE: default: switch( *ctx->ptr ) { case '/': goto proc_comment; case '\n': case '\t': case '\r': case ' ': case ',': case '{': case '\\': case '"': case '}': continue; default: break; } ctx->pos = 0; ctx->buffer[ctx->pos++] = *ctx->ptr; ctx->target = TARGET_SELECTOR; break; } continue; proc_comment: switch( *(ctx->ptr + 1) ) { case '/': ctx->is_line_comment = TRUE; break; case '*': ctx->is_line_comment = FALSE; break; default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } if( ctx->target_bak != TARGET_COMMENT ) { ctx->target_bak = ctx->target; ctx->target = TARGET_COMMENT; } continue; put_css: DEBUG_MSG("put css\n"); /* 将记录的样式表添加至匹配到的选择器中 */ for( LinkedList_Each( node, &ctx->selectors ) ) { LCUI_PutStyleSheet( node->data, ctx->css, ctx->space ); } LinkedList_Clear( &ctx->selectors, (FuncPtr)Selector_Delete ); StyleSheet_Delete( ctx->css ); continue; select_parser: ctx->target = TARGET_VALUE; ctx->buffer[ctx->pos] = 0; ctx->pos = 0; ctx->parser = Dict_FetchValue( self.parsers, ctx->buffer ); DEBUG_MSG("select style: %s, parser: %p\n", ctx->buffer, ctx->parser); continue; parse_value: if( *ctx->ptr == ';' ) { ctx->target = TARGET_KEY; } if( !ctx->parser ) { continue; } ctx->buffer[ctx->pos] = 0; ctx->pos = 0; ctx->parser->parse( ctx->css, ctx->parser->key, ctx->buffer ); DEBUG_MSG("parse style value: %s, result: %d\n", ctx->buffer); if( *ctx->ptr == '}' ) { ctx->target = TARGET_NONE; goto put_css; } } return size; }