Пример #1
0
/** 构造函数 */
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);
}
Пример #2
0
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
Пример #4
0
void Qss::AddSheet(int type, bool cover)
{
    if(cover)
        _sheet = _p->styleSheet();
    _sheet += StyleSheet(type);
}
Пример #5
0
/** 载入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;
}