Minetest 5.9.0-dev
 
Loading...
Searching...
No Matches
StyleSpec.h
Go to the documentation of this file.
1/*
2Minetest
3Copyright (C) 2019 rubenwardy
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation; either version 2.1 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU Lesser General Public License for more details.
14
15You should have received a copy of the GNU Lesser General Public License along
16with this program; if not, write to the Free Software Foundation, Inc.,
1751 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*/
19
21#include "client/fontengine.h"
22#include "debug.h"
24#include "util/string.h"
25#include <algorithm>
26#include <array>
27#include <vector>
28
29#pragma once
30
32{
33public:
35 {
38 BGCOLOR_HOVERED, // Note: Deprecated property
39 BGCOLOR_PRESSED, // Note: Deprecated property
43 BGIMG_HOVERED, // Note: Deprecated property
45 BGIMG_PRESSED, // Note: Deprecated property
47 FGIMG_HOVERED, // Note: Deprecated property
49 FGIMG_PRESSED, // Note: Deprecated property
62 NONE
63 };
64
65 // State is a bitfield, it's possible to have multiple of these at once
66 enum State : u8
67 {
69 STATE_FOCUSED = 1 << 0,
70 STATE_HOVERED = 1 << 1,
71 STATE_PRESSED = 1 << 2,
72 NUM_STATES = 1 << 3, // This includes all permutations
73 STATE_INVALID = 1 << 4,
74 };
75
76private:
77 std::array<bool, NUM_PROPERTIES> property_set{};
78 std::array<std::string, NUM_PROPERTIES> properties;
80
81public:
82 static Property GetPropertyByName(const std::string &name)
83 {
84 if (name == "textcolor") {
85 return TEXTCOLOR;
86 } else if (name == "bgcolor") {
87 return BGCOLOR;
88 } else if (name == "bgcolor_hovered") {
89 return BGCOLOR_HOVERED;
90 } else if (name == "bgcolor_pressed") {
91 return BGCOLOR_PRESSED;
92 } else if (name == "noclip") {
93 return NOCLIP;
94 } else if (name == "border") {
95 return BORDER;
96 } else if (name == "bgimg") {
97 return BGIMG;
98 } else if (name == "bgimg_hovered") {
99 return BGIMG_HOVERED;
100 } else if (name == "bgimg_middle") {
101 return BGIMG_MIDDLE;
102 } else if (name == "bgimg_pressed") {
103 return BGIMG_PRESSED;
104 } else if (name == "fgimg") {
105 return FGIMG;
106 } else if (name == "fgimg_hovered") {
107 return FGIMG_HOVERED;
108 } else if (name == "fgimg_middle") {
109 return FGIMG_MIDDLE;
110 } else if (name == "fgimg_pressed") {
111 return FGIMG_PRESSED;
112 } else if (name == "alpha") {
113 return ALPHA;
114 } else if (name == "content_offset") {
115 return CONTENT_OFFSET;
116 } else if (name == "padding") {
117 return PADDING;
118 } else if (name == "font") {
119 return FONT;
120 } else if (name == "font_size") {
121 return FONT_SIZE;
122 } else if (name == "colors") {
123 return COLORS;
124 } else if (name == "bordercolors") {
125 return BORDERCOLORS;
126 } else if (name == "borderwidths") {
127 return BORDERWIDTHS;
128 } else if (name == "sound") {
129 return SOUND;
130 } else if (name == "spacing") {
131 return SPACING;
132 } else if (name == "size") {
133 return SIZE;
134 } else {
135 return NONE;
136 }
137 }
138
139 std::string get(Property prop, std::string def) const
140 {
141 const auto &val = properties[prop];
142 return val.empty() ? def : val;
143 }
144
145 void set(Property prop, const std::string &value)
146 {
147 properties[prop] = value;
148 property_set[prop] = true;
149 }
150
152 static State getStateByName(const std::string &name)
153 {
154 if (name == "default") {
155 return STATE_DEFAULT;
156 } else if (name == "focused") {
157 return STATE_FOCUSED;
158 } else if (name == "hovered") {
159 return STATE_HOVERED;
160 } else if (name == "pressed") {
161 return STATE_PRESSED;
162 } else {
163 return STATE_INVALID;
164 }
165 }
166
169 {
170 return state_map;
171 }
172
174 void addState(State state)
175 {
176 FATAL_ERROR_IF(state >= NUM_STATES, "Out-of-bounds state received");
177
178 state_map = static_cast<State>(state_map | state);
179 }
180
182 // combined style for a state by propagating values in its component states
183 static StyleSpec getStyleFromStatePropagation(const std::array<StyleSpec, NUM_STATES> &styles, State state)
184 {
185 StyleSpec temp = styles[StyleSpec::STATE_DEFAULT];
186 temp.state_map = state;
187 for (int i = StyleSpec::STATE_DEFAULT + 1; i <= state; i++) {
188 if ((state & i) != 0) {
189 temp = temp | styles[i];
190 }
191 }
192
193 return temp;
194 }
195
196 video::SColor getColor(Property prop, video::SColor def) const
197 {
198 const auto &val = properties[prop];
199 if (val.empty()) {
200 return def;
201 }
202
203 parseColorString(val, def, false, 0xFF);
204 return def;
205 }
206
207 video::SColor getColor(Property prop) const
208 {
209 const auto &val = properties[prop];
210 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
211
212 video::SColor color;
213 parseColorString(val, color, false, 0xFF);
214 return color;
215 }
216
217 std::array<video::SColor, 4> getColorArray(Property prop,
218 std::array<video::SColor, 4> def) const
219 {
220 const auto &val = properties[prop];
221 if (val.empty())
222 return def;
223
224 std::vector<std::string> strs;
225 if (!parseArray(val, strs))
226 return def;
227
228 for (size_t i = 0; i <= 3; i++) {
229 video::SColor color;
230 if (parseColorString(strs[i], color, false, 0xff))
231 def[i] = color;
232 }
233
234 return def;
235 }
236
237 std::array<s32, 4> getIntArray(Property prop, std::array<s32, 4> def) const
238 {
239 const auto &val = properties[prop];
240 if (val.empty())
241 return def;
242
243 std::vector<std::string> strs;
244 if (!parseArray(val, strs))
245 return def;
246
247 for (size_t i = 0; i <= 3; i++)
248 def[i] = stoi(strs[i]);
249
250 return def;
251 }
252
253 irr::core::rect<s32> getRect(Property prop, irr::core::rect<s32> def) const
254 {
255 const auto &val = properties[prop];
256 if (val.empty())
257 return def;
258
259 irr::core::rect<s32> rect;
260 if (!parseRect(val, &rect))
261 return def;
262
263 return rect;
264 }
265
266 irr::core::rect<s32> getRect(Property prop) const
267 {
268 const auto &val = properties[prop];
269 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
270
271 irr::core::rect<s32> rect;
272 parseRect(val, &rect);
273 return rect;
274 }
275
277 {
278 const auto &val = properties[prop];
279 if (val.empty())
280 return def;
281
282 v2f32 vec;
283 if (!parseVector2f(val, &vec))
284 return def;
285
286 return vec;
287 }
288
290 {
291 const auto &val = properties[prop];
292 if (val.empty())
293 return def;
294
295 v2f32 vec;
296 if (!parseVector2f(val, &vec))
297 return def;
298
299 return v2s32(vec.X, vec.Y);
300 }
301
303 {
304 const auto &val = properties[prop];
305 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
306
307 v2f32 vec;
308 parseVector2f(val, &vec);
309 return v2s32(vec.X, vec.Y);
310 }
311
312 gui::IGUIFont *getFont() const
313 {
314 FontSpec spec(FONT_SIZE_UNSPECIFIED, FM_Standard, false, false);
315
316 const std::string &font = properties[FONT];
317 const std::string &size = properties[FONT_SIZE];
318
319 if (font.empty() && size.empty())
320 return nullptr;
321
322 std::vector<std::string> modes = split(font, ',');
323
324 for (size_t i = 0; i < modes.size(); i++) {
325 if (modes[i] == "normal")
326 spec.mode = FM_Standard;
327 else if (modes[i] == "mono")
328 spec.mode = FM_Mono;
329 else if (modes[i] == "bold")
330 spec.bold = true;
331 else if (modes[i] == "italic")
332 spec.italic = true;
333 }
334
335 if (!size.empty()) {
336 int calc_size = 1;
337
338 if (size[0] == '*') {
339 std::string new_size = size.substr(1); // Remove '*' (invalid for stof)
340 calc_size = stof(new_size) * g_fontengine->getFontSize(spec.mode);
341 } else if (size[0] == '+' || size[0] == '-') {
342 calc_size = stoi(size) + g_fontengine->getFontSize(spec.mode);
343 } else {
344 calc_size = stoi(size);
345 }
346
347 spec.size = (unsigned)std::min(std::max(calc_size, 1), 999);
348 }
349
350 return g_fontengine->getFont(spec);
351 }
352
353 video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc,
354 video::ITexture *def) const
355 {
356 const auto &val = properties[prop];
357 if (val.empty()) {
358 return def;
359 }
360
361 video::ITexture *texture = tsrc->getTexture(val);
362
363 return texture;
364 }
365
366 video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc) const
367 {
368 const auto &val = properties[prop];
369 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
370
371 video::ITexture *texture = tsrc->getTexture(val);
372
373 return texture;
374 }
375
376 bool getBool(Property prop, bool def) const
377 {
378 const auto &val = properties[prop];
379 if (val.empty()) {
380 return def;
381 }
382
383 return is_yes(val);
384 }
385
386 inline bool isNotDefault(Property prop) const
387 {
388 return !properties[prop].empty();
389 }
390
391 inline bool hasProperty(Property prop) const { return property_set[prop]; }
392
394 {
395 for (size_t i = 0; i < NUM_PROPERTIES; i++) {
396 auto prop = (Property)i;
397 if (other.hasProperty(prop)) {
398 set(prop, other.get(prop, ""));
399 }
400 }
401
402 return *this;
403 }
404
405 StyleSpec operator|(const StyleSpec &other) const
406 {
407 StyleSpec newspec = *this;
408 newspec |= other;
409 return newspec;
410 }
411
412private:
413 bool parseArray(const std::string &value, std::vector<std::string> &arr) const
414 {
415 std::vector<std::string> strs = split(value, ',');
416
417 if (strs.size() == 1) {
418 arr = {strs[0], strs[0], strs[0], strs[0]};
419 } else if (strs.size() == 2) {
420 arr = {strs[0], strs[1], strs[0], strs[1]};
421 } else if (strs.size() == 4) {
422 arr = strs;
423 } else {
424 warningstream << "Invalid array size (" << strs.size()
425 << " arguments): \"" << value << "\"" << std::endl;
426 return false;
427 }
428 return true;
429 }
430
431 bool parseRect(const std::string &value, irr::core::rect<s32> *parsed_rect) const
432 {
433 irr::core::rect<s32> rect;
434 std::vector<std::string> v_rect = split(value, ',');
435
436 if (v_rect.size() == 1) {
437 s32 x = stoi(v_rect[0]);
438 rect.UpperLeftCorner = irr::core::vector2di(x, x);
439 rect.LowerRightCorner = irr::core::vector2di(-x, -x);
440 } else if (v_rect.size() == 2) {
441 s32 x = stoi(v_rect[0]);
442 s32 y = stoi(v_rect[1]);
443 rect.UpperLeftCorner = irr::core::vector2di(x, y);
444 rect.LowerRightCorner = irr::core::vector2di(-x, -y);
445 // `-x` is interpreted as `w - x`
446 } else if (v_rect.size() == 4) {
447 rect.UpperLeftCorner = irr::core::vector2di(
448 stoi(v_rect[0]), stoi(v_rect[1]));
449 rect.LowerRightCorner = irr::core::vector2di(
450 stoi(v_rect[2]), stoi(v_rect[3]));
451 } else {
452 warningstream << "Invalid rectangle string format: \"" << value
453 << "\"" << std::endl;
454 return false;
455 }
456
457 *parsed_rect = rect;
458
459 return true;
460 }
461
462 bool parseVector2f(const std::string &value, v2f32 *parsed_vec) const
463 {
464 v2f32 vec;
465 std::vector<std::string> v_vector = split(value, ',');
466
467 if (v_vector.size() == 1) {
468 f32 x = stof(v_vector[0]);
469 vec.X = x;
470 vec.Y = x;
471 } else if (v_vector.size() == 2) {
472 vec.X = stof(v_vector[0]);
473 vec.Y = stof(v_vector[1]);
474 } else {
475 warningstream << "Invalid 2d vector string format: \"" << value
476 << "\"" << std::endl;
477 return false;
478 }
479
480 *parsed_vec = vec;
481
482 return true;
483 }
484};
unsigned int getFontSize(FontMode mode)
get font size for a specific mode
Definition: fontengine.cpp:163
irr::gui::IGUIFont * getFont(FontSpec spec)
Definition: fontengine.cpp:91
Definition: texturesource.h:34
virtual video::ITexture * getTexture(const std::string &name, u32 *id=nullptr)=0
Definition: StyleSpec.h:32
gui::IGUIFont * getFont() const
Definition: StyleSpec.h:312
static State getStateByName(const std::string &name)
Parses a name and returns the corresponding state enum.
Definition: StyleSpec.h:152
video::SColor getColor(Property prop) const
Definition: StyleSpec.h:207
std::array< bool, NUM_PROPERTIES > property_set
Definition: StyleSpec.h:77
bool getBool(Property prop, bool def) const
Definition: StyleSpec.h:376
State
Definition: StyleSpec.h:67
@ STATE_HOVERED
Definition: StyleSpec.h:70
@ STATE_INVALID
Definition: StyleSpec.h:73
@ STATE_FOCUSED
Definition: StyleSpec.h:69
@ STATE_DEFAULT
Definition: StyleSpec.h:68
@ STATE_PRESSED
Definition: StyleSpec.h:71
@ NUM_STATES
Definition: StyleSpec.h:72
bool parseVector2f(const std::string &value, v2f32 *parsed_vec) const
Definition: StyleSpec.h:462
State getState() const
Gets the state that this style is intended for.
Definition: StyleSpec.h:168
std::string get(Property prop, std::string def) const
Definition: StyleSpec.h:139
v2s32 getVector2i(Property prop) const
Definition: StyleSpec.h:302
Property
Definition: StyleSpec.h:35
@ FONT_SIZE
Definition: StyleSpec.h:54
@ BGCOLOR_PRESSED
Definition: StyleSpec.h:39
@ SOUND
Definition: StyleSpec.h:58
@ BORDERCOLORS
Definition: StyleSpec.h:56
@ BGIMG_PRESSED
Definition: StyleSpec.h:45
@ ALPHA
Definition: StyleSpec.h:50
@ BGCOLOR_HOVERED
Definition: StyleSpec.h:38
@ SPACING
Definition: StyleSpec.h:59
@ BGIMG_MIDDLE
Definition: StyleSpec.h:44
@ NOCLIP
Definition: StyleSpec.h:40
@ SIZE
Definition: StyleSpec.h:60
@ PADDING
Definition: StyleSpec.h:52
@ NUM_PROPERTIES
Definition: StyleSpec.h:61
@ COLORS
Definition: StyleSpec.h:55
@ FONT
Definition: StyleSpec.h:53
@ BORDER
Definition: StyleSpec.h:41
@ FGIMG_PRESSED
Definition: StyleSpec.h:49
@ NONE
Definition: StyleSpec.h:62
@ TEXTCOLOR
Definition: StyleSpec.h:36
@ BGCOLOR
Definition: StyleSpec.h:37
@ BGIMG
Definition: StyleSpec.h:42
@ BGIMG_HOVERED
Definition: StyleSpec.h:43
@ FGIMG
Definition: StyleSpec.h:46
@ BORDERWIDTHS
Definition: StyleSpec.h:57
@ FGIMG_MIDDLE
Definition: StyleSpec.h:48
@ CONTENT_OFFSET
Definition: StyleSpec.h:51
@ FGIMG_HOVERED
Definition: StyleSpec.h:47
v2s32 getVector2i(Property prop, v2s32 def) const
Definition: StyleSpec.h:289
static StyleSpec getStyleFromStatePropagation(const std::array< StyleSpec, NUM_STATES > &styles, State state)
Using a list of styles mapped to state values, calculate the final.
Definition: StyleSpec.h:183
std::array< video::SColor, 4 > getColorArray(Property prop, std::array< video::SColor, 4 > def) const
Definition: StyleSpec.h:217
static Property GetPropertyByName(const std::string &name)
Definition: StyleSpec.h:82
irr::core::rect< s32 > getRect(Property prop) const
Definition: StyleSpec.h:266
bool isNotDefault(Property prop) const
Definition: StyleSpec.h:386
StyleSpec operator|(const StyleSpec &other) const
Definition: StyleSpec.h:405
void addState(State state)
Set the given state on this style.
Definition: StyleSpec.h:174
bool parseArray(const std::string &value, std::vector< std::string > &arr) const
Definition: StyleSpec.h:413
video::ITexture * getTexture(Property prop, ISimpleTextureSource *tsrc) const
Definition: StyleSpec.h:366
irr::core::rect< s32 > getRect(Property prop, irr::core::rect< s32 > def) const
Definition: StyleSpec.h:253
video::SColor getColor(Property prop, video::SColor def) const
Definition: StyleSpec.h:196
State state_map
Definition: StyleSpec.h:79
StyleSpec & operator|=(const StyleSpec &other)
Definition: StyleSpec.h:393
void set(Property prop, const std::string &value)
Definition: StyleSpec.h:145
video::ITexture * getTexture(Property prop, ISimpleTextureSource *tsrc, video::ITexture *def) const
Definition: StyleSpec.h:353
bool parseRect(const std::string &value, irr::core::rect< s32 > *parsed_rect) const
Definition: StyleSpec.h:431
std::array< s32, 4 > getIntArray(Property prop, std::array< s32, 4 > def) const
Definition: StyleSpec.h:237
bool hasProperty(Property prop) const
Definition: StyleSpec.h:391
std::array< std::string, NUM_PROPERTIES > properties
Definition: StyleSpec.h:78
v2f32 getVector2f(Property prop, v2f32 def) const
Definition: StyleSpec.h:276
#define FATAL_ERROR_IF(expr, msg)
Definition: debug.h:51
FontEngine * g_fontengine
reference to access font engine, has to be initialized by main
Definition: fontengine.cpp:31
@ FM_Standard
Definition: fontengine.h:34
@ FM_Mono
Definition: fontengine.h:35
#define FONT_SIZE_UNSPECIFIED
Definition: fontengine.h:31
core::vector2d< f32 > v2f32
Definition: irr_v2d.h:30
core::vector2d< s32 > v2s32
Definition: irr_v2d.h:28
thread_local LogStream warningstream
bool parseColorString(const std::string &value, video::SColor &color, bool quiet, unsigned char default_alpha)
Definition: string.cpp:582
#define stoi
Definition: string.h:423
#define stof
Definition: string.h:424
std::vector< std::basic_string< T > > split(const std::basic_string< T > &s, T delim)
Definition: string.h:603
bool is_yes(std::string_view str)
Returns whether str should be regarded as (bool) true.
Definition: string.h:373
Definition: fontengine.h:41
bool italic
Definition: fontengine.h:56
bool bold
Definition: fontengine.h:55
unsigned int size
Definition: fontengine.h:53
FontMode mode
Definition: fontengine.h:54