17using namespace std::string_literals;
26 name += std::tolower(
c);
28 for (
const auto &block :
fBlocks) {
30 auto res = block.map.Find(
name);
46 name += std::tolower(
c);
48 for (
const auto &block : fBlocks) {
49 if (block.selector == selector) {
50 auto res = block.map.Find(
name);
82 const std::string &css_code;
84 RParser(
const std::string &_code) : css_code(_code)
86 len = css_code.length();
89 bool more_data()
const {
return pos < len; }
91 char current()
const {
return css_code[pos]; }
93 void shift() { ++pos; }
95 bool check_symbol(
bool isfirst =
false)
97 auto symbol = current();
98 if (((symbol >=
'a') && (symbol <=
'z')) ||
99 ((symbol >=
'A') && (symbol <=
'Z')) || (symbol ==
'_'))
return true;
100 return (!isfirst && (symbol>=
'0') && (symbol<=
'9'));
103 std::string error_position()
const
105 std::string res =
"\nLine "s + std::to_string(nline) +
": "s;
108 while ((p<len) && (p < linebeg+100) && (css_code[p] !=
'\n')) ++p;
110 return res + css_code.substr(linebeg, p-linebeg);
115 bool skip_until_newline =
false, skip_until_endblock =
false;
118 if (current() ==
'\n') {
119 skip_until_newline =
false;
125 if (skip_until_endblock && (current() ==
'*') && (pos+1 < len) && (css_code[pos+1] ==
'/')) {
127 skip_until_endblock =
false;
131 if (skip_until_newline || skip_until_endblock || (current() ==
' ') || (current() ==
'\t')) {
136 if ((current() ==
'/') && (pos+1 < len)) {
137 if (css_code[pos+1] ==
'/') {
139 skip_until_newline =
true;
141 }
else if (css_code[pos+1] ==
'*') {
143 skip_until_endblock =
true;
154 std::string scan_identifier(
bool selector =
false)
156 if (pos >= len)
return ""s;
161 if (selector && ((current() ==
'.') || (current() ==
'#'))) shift();
163 bool is_first =
true;
165 while ((pos < len) && check_symbol(is_first)) { shift(); is_first =
false; }
167 std::string s = css_code.substr(pos0, pos-pos0);
169 std::transform(s.begin(), s.end(), s.begin(),
170 [](
unsigned char c){ return std::tolower(c); });
174 std::string scan_value()
176 if (pos >= len)
return ""s;
180 while ((pos < len) && (current() !=
';') && current() !=
'\n') shift();
187 return css_code.substr(pos0, pos - pos0 - 1);
192 RParser parser(css_code);
196 while (parser.more_data()) {
198 if (!parser.skip_empty())
201 auto sel = parser.scan_identifier(
true);
207 if (!parser.skip_empty())
210 if (parser.current() !=
'{') {
217 if (!parser.skip_empty())
222 while (parser.current() !=
'}') {
223 auto name = parser.scan_identifier();
229 if (!parser.skip_empty())
232 if (parser.current() !=
':') {
239 if (!parser.skip_empty())
242 if (parser.current() ==
';') {
244 map.AddNoValue(
name);
246 auto value = parser.scan_value();
252 map.AddBestMatch(
name, value);
255 if (!parser.skip_empty())
265 fBlocks.splice(fBlocks.end(), newstyle.
fBlocks);
276 auto style = std::make_shared<RStyle>();
277 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.