]> git.lizzy.rs Git - minetest.git/blob - src/gui/StyleSpec.h
Fix potential problem with core.get_connected_players()
[minetest.git] / src / gui / StyleSpec.h
1 /*
2 Minetest
3 Copyright (C) 2019 rubenwardy
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client/tile.h" // ITextureSource
21 #include "irrlichttypes_extrabloated.h"
22 #include "util/string.h"
23 #include <array>
24
25 #pragma once
26
27 class StyleSpec
28 {
29 public:
30         enum Property
31         {
32                 TEXTCOLOR,
33                 BGCOLOR,
34                 BGCOLOR_HOVERED,
35                 BGCOLOR_PRESSED,
36                 NOCLIP,
37                 BORDER,
38                 BGIMG,
39                 BGIMG_HOVERED,
40                 BGIMG_MIDDLE,
41                 BGIMG_PRESSED,
42                 FGIMG,
43                 FGIMG_HOVERED,
44                 FGIMG_PRESSED,
45                 ALPHA,
46                 NUM_PROPERTIES,
47                 NONE
48         };
49
50 private:
51         std::array<bool, NUM_PROPERTIES> property_set{};
52         std::array<std::string, NUM_PROPERTIES> properties;
53
54 public:
55         static Property GetPropertyByName(const std::string &name)
56         {
57                 if (name == "textcolor") {
58                         return TEXTCOLOR;
59                 } else if (name == "bgcolor") {
60                         return BGCOLOR;
61                 } else if (name == "bgcolor_hovered") {
62                         return BGCOLOR_HOVERED;
63                 } else if (name == "bgcolor_pressed") {
64                         return BGCOLOR_PRESSED;
65                 } else if (name == "noclip") {
66                         return NOCLIP;
67                 } else if (name == "border") {
68                         return BORDER;
69                 } else if (name == "bgimg") {
70                         return BGIMG;
71                 } else if (name == "bgimg_hovered") {
72                         return BGIMG_HOVERED;
73                 } else if (name == "bgimg_middle") {
74                         return BGIMG_MIDDLE;
75                 } else if (name == "bgimg_pressed") {
76                         return BGIMG_PRESSED;
77                 } else if (name == "fgimg") {
78                         return FGIMG;
79                 } else if (name == "fgimg_hovered") {
80                         return FGIMG_HOVERED;
81                 } else if (name == "fgimg_pressed") {
82                         return FGIMG_PRESSED;
83                 } else if (name == "alpha") {
84                         return ALPHA;
85                 } else {
86                         return NONE;
87                 }
88         }
89
90         std::string get(Property prop, std::string def) const
91         {
92                 const auto &val = properties[prop];
93                 return val.empty() ? def : val;
94         }
95
96         void set(Property prop, const std::string &value)
97         {
98                 properties[prop] = value;
99                 property_set[prop] = true;
100         }
101
102         video::SColor getColor(Property prop, video::SColor def) const
103         {
104                 const auto &val = properties[prop];
105                 if (val.empty()) {
106                         return def;
107                 }
108
109                 parseColorString(val, def, false, 0xFF);
110                 return def;
111         }
112
113         video::SColor getColor(Property prop) const
114         {
115                 const auto &val = properties[prop];
116                 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
117
118                 video::SColor color;
119                 parseColorString(val, color, false, 0xFF);
120                 return color;
121         }
122
123         irr::core::rect<s32> getRect(Property prop, irr::core::rect<s32> def) const
124         {
125                 const auto &val = properties[prop];
126                 if (val.empty())
127                         return def;
128
129                 irr::core::rect<s32> rect;
130                 if (!parseRect(val, &rect))
131                         return def;
132
133                 return rect;
134         }
135
136         irr::core::rect<s32> getRect(Property prop) const
137         {
138                 const auto &val = properties[prop];
139                 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
140
141                 irr::core::rect<s32> rect;
142                 parseRect(val, &rect);
143                 return rect;
144         }
145
146         video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc,
147                         video::ITexture *def) const
148         {
149                 const auto &val = properties[prop];
150                 if (val.empty()) {
151                         return def;
152                 }
153
154                 video::ITexture *texture = tsrc->getTexture(val);
155
156                 return texture;
157         }
158
159         video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc) const
160         {
161                 const auto &val = properties[prop];
162                 FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
163
164                 video::ITexture *texture = tsrc->getTexture(val);
165
166                 return texture;
167         }
168
169         bool getBool(Property prop, bool def) const
170         {
171                 const auto &val = properties[prop];
172                 if (val.empty()) {
173                         return def;
174                 }
175
176                 return is_yes(val);
177         }
178
179         inline bool isNotDefault(Property prop) const
180         {
181                 return !properties[prop].empty();
182         }
183
184         inline bool hasProperty(Property prop) const { return property_set[prop]; }
185
186         StyleSpec &operator|=(const StyleSpec &other)
187         {
188                 for (size_t i = 0; i < NUM_PROPERTIES; i++) {
189                         auto prop = (Property)i;
190                         if (other.hasProperty(prop)) {
191                                 set(prop, other.get(prop, ""));
192                         }
193                 }
194
195                 return *this;
196         }
197
198         StyleSpec operator|(const StyleSpec &other) const
199         {
200                 StyleSpec newspec = *this;
201                 newspec |= other;
202                 return newspec;
203         }
204
205 private:
206         bool parseRect(const std::string &value, irr::core::rect<s32> *parsed_rect) const
207         {
208                 irr::core::rect<s32> rect;
209                 std::vector<std::string> v_rect = split(value, ',');
210
211                 if (v_rect.size() == 1) {
212                         s32 x = stoi(v_rect[0]);
213                         rect.UpperLeftCorner = irr::core::vector2di(x, x);
214                         rect.LowerRightCorner = irr::core::vector2di(-x, -x);
215                 } else if (v_rect.size() == 2) {
216                         s32 x = stoi(v_rect[0]);
217                         s32 y = stoi(v_rect[1]);
218                         rect.UpperLeftCorner = irr::core::vector2di(x, y);
219                         rect.LowerRightCorner = irr::core::vector2di(-x, -y);
220                         // `-x` is interpreted as `w - x`
221                 } else if (v_rect.size() == 4) {
222                         rect.UpperLeftCorner = irr::core::vector2di(
223                                         stoi(v_rect[0]), stoi(v_rect[1]));
224                         rect.LowerRightCorner = irr::core::vector2di(
225                                         stoi(v_rect[2]), stoi(v_rect[3]));
226                 } else {
227                         warningstream << "Invalid rectangle string format: \"" << value
228                                         << "\"" << std::endl;
229                         return false;
230                 }
231
232                 *parsed_rect = rect;
233
234                 return true;
235         }
236 };