Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RStyle.cxx
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
3 * All rights reserved. *
4 * *
5 * For the licensing terms see $ROOTSYS/LICENSE. *
6 * For the list of contributors see $ROOTSYS/README/CREDITS. *
7 *************************************************************************/
8
9#include <ROOT/RStyle.hxx>
10
11#include "ROOT/RAttrBase.hxx" // for GPadLog()
12#include <ROOT/RDrawable.hxx>
13#include <ROOT/RLogger.hxx>
14
15#include <algorithm>
16
17using namespace std::string_literals;
18
19///////////////////////////////////////////////////////////////////////////////
20/// Evaluate attribute value for provided RDrawable
21
22const ROOT::Experimental::RAttrMap::Value_t *ROOT::Experimental::RStyle::Eval(const std::string &field, const RDrawable &drawable) const
23{
24 std::string name;
25 for(auto &c : field)
26 name += std::tolower(c);
27
28 for (const auto &block : fBlocks) {
29 if (drawable.MatchSelector(block.selector)) {
30 auto res = block.map.Find(name);
31 if (res)
32 return res;
33 }
34 }
35
36 return nullptr;
37}
38
39///////////////////////////////////////////////////////////////////////////////
40/// Evaluate attribute value for provided selector - exact match is expected
41
42const ROOT::Experimental::RAttrMap::Value_t *ROOT::Experimental::RStyle::Eval(const std::string &field, const std::string &selector) const
43{
44 std::string name;
45 for(auto &c : field)
46 name += std::tolower(c);
47
48 for (const auto &block : fBlocks) {
49 if (block.selector == selector) {
50 auto res = block.map.Find(name);
51 if (res)
52 return res;
53 }
54 }
55
56 return nullptr;
57}
58
59
60///////////////////////////////////////////////////////////////////////////////
61/// Parse string with CSS code inside
62
64{
65 fBlocks.clear();
66}
67
68///////////////////////////////////////////////////////////////////////////////
69/// Parse string with CSS code inside
70/// All data will be append to existing style records
71
72bool ROOT::Experimental::RStyle::ParseString(const std::string &css_code)
73{
74 if (css_code.empty())
75 return true;
76
77 struct RParser {
78 int pos{0};
79 int nline{1};
80 int linebeg{0};
81 int len{0};
82 const std::string &css_code;
83
84 RParser(const std::string &_code) : css_code(_code)
85 {
86 len = css_code.length();
87 }
88
89 bool more_data() const { return pos < len; }
90
91 char current() const { return css_code[pos]; }
92
93 void shift() { ++pos; }
94
95 bool check_symbol(bool isfirst = false)
96 {
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'));
101 }
102
103 std::string error_position() const
104 {
105 std::string res = "\nLine "s + std::to_string(nline) + ": "s;
106
107 int p = linebeg;
108 while ((p<len) && (p < linebeg+100) && (css_code[p] != '\n')) ++p;
109
110 return res + css_code.substr(linebeg, p-linebeg);
111 }
112
113 bool skip_empty()
114 {
115 bool skip_until_newline = false, skip_until_endblock = false;
116
117 while (pos < len) {
118 if (current() == '\n') {
119 skip_until_newline = false;
120 linebeg = ++pos;
121 ++nline;
122 continue;
123 }
124
125 if (skip_until_endblock && (current() == '*') && (pos+1 < len) && (css_code[pos+1] == '/')) {
126 pos+=2;
127 skip_until_endblock = false;
128 continue;
129 }
130
131 if (skip_until_newline || skip_until_endblock || (current() == ' ') || (current() == '\t')) {
132 shift();
133 continue;
134 }
135
136 if ((current() == '/') && (pos+1 < len)) {
137 if (css_code[pos+1] == '/') {
138 pos+=2;
139 skip_until_newline = true;
140 continue;
141 } else if (css_code[pos+1] == '*') {
142 pos+=2;
143 skip_until_endblock = true;
144 continue;
145 }
146 }
147
148 return true;
149 }
150
151 return false;
152 }
153
154 std::string scan_identifier(bool selector = false)
155 {
156 if (pos >= len) return ""s;
157
158 int pos0 = pos;
159
160 // start symbols of selector
161 if (selector && ((current() == '.') || (current() == '#'))) shift();
162
163 bool is_first = true;
164
165 while ((pos < len) && check_symbol(is_first)) { shift(); is_first = false; }
166
167 std::string s = css_code.substr(pos0, pos-pos0);
168 if (!selector)
169 std::transform(s.begin(), s.end(), s.begin(),
170 [](unsigned char c){ return std::tolower(c); });
171 return s;
172 }
173
174 std::string scan_value()
175 {
176 if (pos >= len) return ""s;
177
178 int pos0 = pos;
179
180 while ((pos < len) && (current() != ';') && current() != '\n') shift();
181
182 if (pos >= len)
183 return ""s;
184
185 shift();
186
187 return css_code.substr(pos0, pos - pos0 - 1);
188 }
189
190 };
191
192 RParser parser(css_code);
193
194 RStyle newstyle;
195
196 while (parser.more_data()) {
197
198 if (!parser.skip_empty())
199 return false;
200
201 auto sel = parser.scan_identifier(true);
202 if (sel.empty()) {
203 R__LOG_ERROR(GPadLog()) << "Fail to find selector" << parser.error_position();
204 return false;
205 }
206
207 if (!parser.skip_empty())
208 return false;
209
210 if (parser.current() != '{') {
211 R__LOG_ERROR(GPadLog()) << "Fail to find starting {" << parser.error_position();
212 return false;
213 }
214
215 parser.shift();
216
217 if (!parser.skip_empty())
218 return false;
219
220 auto &map = newstyle.AddBlock(sel);
221
222 while (parser.current() != '}') {
223 auto name = parser.scan_identifier();
224 if (name.empty()) {
225 R__LOG_ERROR(GPadLog()) << "not able to extract identifier" << parser.error_position();
226 return false;
227 }
228
229 if (!parser.skip_empty())
230 return false;
231
232 if (parser.current() != ':') {
233 R__LOG_ERROR(GPadLog()) << "not able to find separator :" << parser.error_position();
234 return false;
235 }
236
237 parser.shift();
238
239 if (!parser.skip_empty())
240 return false;
241
242 if (parser.current() == ';') {
243 parser.shift();
244 map.AddNoValue(name);
245 } else {
246 auto value = parser.scan_value();
247 if (value.empty()) {
248 R__LOG_ERROR(GPadLog()) << "not able to find value" << parser.error_position();
249 return false;
250 }
251
252 map.AddBestMatch(name, value);
253 }
254
255 if (!parser.skip_empty())
256 return false;
257 }
258
259 parser.shift();
260
261 parser.skip_empty(); // after closing } end of file is possible
262 }
263
264 // finally move all read blocks to this
265 fBlocks.splice(fBlocks.end(), newstyle.fBlocks);
266
267 return true;
268}
269
270
271///////////////////////////////////////////////////////////////////////////////
272/// Parse CSS code and returns std::shared_ptr<RStyle> when successful
273
274std::shared_ptr<ROOT::Experimental::RStyle> ROOT::Experimental::RStyle::Parse(const std::string &css_code)
275{
276 auto style = std::make_shared<RStyle>();
277 if (!style->ParseString(css_code)) return nullptr;
278 return style;
279}
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
#define c(i)
Definition RSha256.hxx:101
char name[80]
Definition TGX11.cxx:110
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...
Definition RDrawable.cxx:59
A set of defaults for graphics attributes, e.g.
Definition RStyle.hxx:32
std::list< Block_t > fBlocks
Definition RStyle.hxx:64
const RAttrMap::Value_t * Eval(const std::string &field, const RDrawable &drawable) const
Evaluate attribute value for provided RDrawable.
Definition RStyle.cxx:22
void Clear()
Parse string with CSS code inside.
Definition RStyle.cxx:63
bool ParseString(const std::string &css_code)
Parse string with CSS code inside All data will be append to existing style records.
Definition RStyle.cxx:72
RAttrMap & AddBlock(const std::string &selector)
Definition RStyle.hxx:50
static std::shared_ptr< RStyle > Parse(const std::string &css_code)
Parse CSS code and returns std::shared_ptr<RStyle> when successful.
Definition RStyle.cxx:274
RLogChannel & GPadLog()
Log channel for GPad diagnostics.
Definition RAttrBase.cxx:17
TCanvas * style()
Definition style.C:1