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