15using namespace std::string_literals;
22 for (
const auto &block :
fBlocks) {
24 auto res = block.map.Find(field);
38 for (
const auto &block : fBlocks) {
39 if (block.selector == selector) {
40 auto res = block.map.Find(field);
72 const std::string &css_code;
74 RParser(
const std::string &_code) : css_code(_code)
76 len = css_code.length();
79 bool more_data()
const {
return pos < len; }
81 char current()
const {
return css_code[pos]; }
83 void shift() { ++pos; }
85 bool check_symbol(
bool isfirst =
false)
87 auto symbol = current();
88 if (((symbol >=
'a') && (symbol <=
'z')) ||
89 ((symbol >=
'A') && (symbol <=
'Z')) || (symbol ==
'_'))
return true;
90 return (!isfirst && (symbol>=
'0') && (symbol<=
'9'));
93 std::string error_position()
const
95 std::string res =
"\nLine "s + std::to_string(nline) +
": "s;
98 while ((p<len) && (p < linebeg+100) && (css_code[p] !=
'\n')) ++p;
100 return res + css_code.substr(linebeg, p-linebeg);
105 bool skip_until_newline =
false, skip_until_endblock =
false;
108 if (current() ==
'\n') {
109 skip_until_newline =
false;
115 if (skip_until_endblock && (current() ==
'*') && (pos+1 < len) && (css_code[pos+1] ==
'/')) {
117 skip_until_endblock =
false;
121 if (skip_until_newline || skip_until_endblock || (current() ==
' ') || (current() ==
'\t')) {
126 if ((current() ==
'/') && (pos+1 < len)) {
127 if (css_code[pos+1] ==
'/') {
129 skip_until_newline =
true;
131 }
else if (css_code[pos+1] ==
'*') {
133 skip_until_endblock =
true;
144 std::string scan_identifier(
bool selector =
false)
146 if (pos >= len)
return ""s;
151 if (selector && ((current() ==
'.') || (current() ==
'#'))) shift();
153 bool is_first =
true;
155 while ((pos < len) && check_symbol(is_first)) { shift(); is_first =
false; }
157 return css_code.substr(pos0, pos-pos0);
160 std::string scan_value()
162 if (pos >= len)
return ""s;
166 while ((pos < len) && (current() !=
';') && current() !=
'\n') shift();
173 return css_code.substr(pos0, pos - pos0 - 1);
178 RParser parser(css_code);
182 while (parser.more_data()) {
184 if (!parser.skip_empty())
187 auto sel = parser.scan_identifier(
true);
193 if (!parser.skip_empty())
196 if (parser.current() !=
'{') {
203 if (!parser.skip_empty())
208 while (parser.current() !=
'}') {
209 auto name = parser.scan_identifier();
215 if (!parser.skip_empty())
218 if (parser.current() !=
':') {
225 if (!parser.skip_empty())
228 if (parser.current() ==
';') {
230 map.AddNoValue(
name);
232 auto value = parser.scan_value();
238 map.AddBestMatch(
name, value);
241 if (!parser.skip_empty())
251 fBlocks.splice(fBlocks.end(), newstyle.
fBlocks);
262 auto style = std::make_shared<RStyle>();
263 if (!
style->ParseString(css_code))
return nullptr;
#define R__LOG_ERROR(...)
Base class for drawable entities: objects that can be painted on a RPad.
bool MatchSelector(const std::string &selector) const
Preliminary method which checks if drawable matches with given selector Following selector are allowe...
A set of defaults for graphics attributes, e.g.
std::list< Block_t > fBlocks
const RAttrMap::Value_t * Eval(const std::string &field, const RDrawable &drawable) const
Evaluate attribute value for provided RDrawable.
void Clear()
Parse string with CSS code inside.
bool ParseString(const std::string &css_code)
Parse string with CSS code inside All data will be append to existing style records.
RAttrMap & AddBlock(const std::string &selector)
static std::shared_ptr< RStyle > Parse(const std::string &css_code)
Parse CSS code and returns std::shared_ptr<RStyle> when successful.
RLogChannel & GPadLog()
Log channel for GPad diagnostics.