lxgui
Loading...
Searching...
No Matches
gui_layout_node.hpp
1#ifndef LXGUI_GUI_LAYOUT_NODE_HPP
2#define LXGUI_GUI_LAYOUT_NODE_HPP
3
4#include "lxgui/gui_out.hpp"
5#include "lxgui/lxgui.hpp"
6#include "lxgui/utils.hpp"
7#include "lxgui/utils_exception.hpp"
8#include "lxgui/utils_string.hpp"
9#include "lxgui/utils_view.hpp"
10
11#include <optional>
12#include <string>
13#include <string_view>
14#include <vector>
15
16namespace lxgui::gui {
17
25public:
26 layout_attribute() = default;
31
36 std::string_view get_location() const noexcept {
37 return location_;
38 }
39
44 std::string_view get_value_location() const noexcept {
45 return value_location_;
46 }
47
52 std::string_view get_filename() const noexcept {
53 auto pos = location_.find(':');
54 return std::string_view(location_.c_str(), pos == location_.npos ? location_.size() : pos);
55 }
56
61 std::size_t get_line_number() const noexcept {
62 std::size_t line = std::numeric_limits<std::size_t>::max();
63 auto pos = location_.find(':');
64 if (pos != location_.npos && pos < location_.size() - 1) {
65 line = utils::from_string<std::size_t>(location_.substr(pos + 1)).value_or(line);
66 }
67 return line;
68 }
69
74 std::size_t get_value_line_number() const noexcept {
75 std::size_t line = std::numeric_limits<std::size_t>::max();
76 auto pos = value_location_.find(':');
77 if (pos != value_location_.npos && pos < value_location_.size() - 1) {
78 line = utils::from_string<std::size_t>(value_location_.substr(pos + 1)).value_or(line);
79 }
80 return line;
81 }
82
87 std::string_view get_name() const noexcept {
88 return name_;
89 }
90
96 std::string_view get_value() const noexcept {
97 accessed_ = true;
98 return value_;
99 }
100
105 template<typename T>
106 std::optional<T> try_get_value() const noexcept {
107 accessed_ = true;
108 auto value = utils::from_string<T>(value_);
109 if (!value.has_value()) {
110 gui::out << gui::warning << std::string(get_location())
111 << ": could not parse value for '" << std::string(name_) << "': '"
112 << std::string(value_) << "'; ignoring" << std::endl;
113 }
114 return value;
115 }
116
123 template<typename T>
124 T get_value() const {
125 accessed_ = true;
126 auto value = utils::from_string<T>(value_);
127 if (!value.has_value()) {
128 throw utils::exception(
129 std::string(get_location()) + ": could not parse value for '" + std::string(name_) +
130 "': '" + std::string(value_) + "'");
131 }
132
133 return value.value();
134 }
135
141 template<typename T>
142 T get_value_or(T fallback) const noexcept {
143 accessed_ = true;
144 auto value = utils::from_string<T>(value_);
145 if (!value.has_value()) {
146 gui::out << gui::warning << std::string(get_location())
147 << ": could not parse value for '" << std::string(name_) << "': '"
148 << std::string(value_) << "'; using '" << utils::to_string(fallback) << "'"
149 << std::endl;
150 return fallback;
151 }
152 return value.value();
153 }
154
159 void set_location(std::string location) noexcept {
160 location_ = std::move(location);
161 }
162
167 void set_value_location(std::string location) noexcept {
168 value_location_ = std::move(location);
169 }
170
175 void set_name(std::string name) noexcept {
176 name_ = std::move(name);
177 }
178
183 void set_value(std::string value) noexcept {
184 value_ = std::move(value);
185 }
186
188 void mark_as_not_accessed() const noexcept {
189 accessed_ = false;
190 }
191
193 void bypass_access_check() const noexcept {
194 access_bypass_ = true;
195 }
196
201 bool was_accessed() const noexcept {
202 return accessed_;
203 }
204
209 bool is_access_check_bypassed() const noexcept {
210 return access_bypass_;
211 }
212
213protected:
214 std::string name_;
215 std::string value_;
216 std::string location_;
217 std::string value_location_;
218
219 mutable bool accessed_ = false;
220 mutable bool access_bypass_ = false;
221};
222
230public:
231 layout_node() = default;
232 layout_node(const layout_node&) = default;
236
237 using child_list = std::vector<layout_node>;
238 using children_view = utils::view::
239 adaptor<const child_list, utils::view::standard_dereferencer, utils::view::no_filter>;
240
245 std::size_t get_child_count() const noexcept {
246 return child_list_.size();
247 }
248
254 const layout_node& get_child(std::size_t index) const noexcept {
255 accessed_ = true;
256 return child_list_[index];
257 }
258
263 children_view get_children() const noexcept {
264 accessed_ = true;
265 return children_view(child_list_);
266 }
267
268 template<typename BaseIterator>
269 struct name_filter {
270 std::string_view filter;
271
272 bool is_included(const BaseIterator& iter) const noexcept {
273 return iter->get_name() == filter;
274 }
275 };
276
279
285 filtered_children_view get_children(std::string_view name) const noexcept {
286 accessed_ = true;
287 return filtered_children_view(child_list_, {}, {name});
288 }
289
295 const layout_node* try_get_child(std::string_view name) const noexcept {
296 accessed_ = true;
297 for (const layout_node& node : get_children(name)) {
298 return &node;
299 }
300
301 return nullptr;
302 }
303
311 const layout_node& get_child(std::string_view name) const {
312 if (const auto* child = try_get_child(name))
313 return *child;
314
315 throw utils::exception(
316 std::string(get_location()) + ": no child found with name '" + std::string(name) +
317 "' in '" + std::string(name_) + "'");
318 }
319
325 bool has_child(std::string_view name) const noexcept {
326 return try_get_child(name) != nullptr;
327 }
328
334 const layout_attribute* try_get_attribute(std::string_view name) const noexcept {
335 accessed_ = true;
336 for (const layout_attribute& node : attr_list_) {
337 if (node.get_name() == name)
338 return &node;
339 }
340
341 return nullptr;
342 }
343
351 const layout_attribute& get_attribute(std::string_view name) const {
352 if (const auto* attr = try_get_attribute(name))
353 return *attr;
354
355 throw utils::exception(
356 std::string(get_location()) + ": no attribute found with name '" + std::string(name) +
357 "' in '" + std::string(name_) + "'");
358 }
359
365 bool has_attribute(std::string_view name) const noexcept {
366 return try_get_attribute(name) != nullptr;
367 }
368
374 std::optional<std::string_view> try_get_attribute_value(std::string_view name) const noexcept {
375 if (const auto* attr = try_get_attribute(name))
376 return attr->get_value();
377
378 return std::nullopt;
379 }
380
388 template<typename T>
389 std::optional<T> try_get_attribute_value(std::string_view name) const noexcept {
390 if (const auto* attr = try_get_attribute(name))
391 return attr->try_get_value<T>();
392
393 return std::nullopt;
394 }
395
404 template<typename T>
405 T get_attribute_value_or(std::string_view name, T fallback) const noexcept {
406 if (const auto* attr = try_get_attribute(name))
407 return attr->get_value_or<T>(fallback);
408
409 return fallback;
410 }
411
419 std::string_view get_attribute_value(std::string_view name) const {
420 return get_attribute(name).get_value();
421 }
422
431 template<typename T>
432 T get_attribute_value(std::string_view name) const {
433 return get_attribute(name).get_value<T>();
434 }
435
436 using attribute_list = std::vector<layout_attribute>;
437 using attribute_view = utils::view::
438 adaptor<const attribute_list, utils::view::standard_dereferencer, utils::view::no_filter>;
439
445 accessed_ = true;
446 return attribute_view(attr_list_);
447 }
448
454 return child_list_.emplace_back();
455 }
456
462 return attr_list_.emplace_back();
463 }
464
473 std::string_view get_or_set_attribute_value(std::string_view name, std::string_view value) {
474 accessed_ = true;
475 if (const auto* attr = try_get_attribute(name))
476 return attr->get_value();
477
478 auto& attr = add_attribute();
479 attr.set_name(std::string(name));
480 attr.set_value(std::string(value));
481 return value;
482 }
483
484private:
485 child_list child_list_;
486 attribute_list attr_list_;
487};
488
489template<>
490inline std::optional<std::string> layout_attribute::try_get_value<std::string>() const noexcept {
491 accessed_ = true;
492 return value_;
493}
494
495template<>
496inline std::string layout_attribute::get_value<std::string>() const {
497 accessed_ = true;
498 return value_;
499}
500
501template<>
502inline std::string layout_attribute::get_value_or<std::string>(std::string) const noexcept {
503 accessed_ = true;
504 return value_;
505}
506
507} // namespace lxgui::gui
508
509#endif
An attribute in a layout file.
std::size_t get_value_line_number() const noexcept
Returns the line number on which this node's value is located.
layout_attribute & operator=(layout_attribute &&)=default
std::string_view get_value() const noexcept
Returns this node's value as string.
T get_value() const
Returns this node's value converted to a specific type.
void mark_as_not_accessed() const noexcept
Flag this node as "not accessed" for later warnings.
std::optional< T > try_get_value() const noexcept
Returns this node's value converted to a specific type, or nullopt if conversion failed.
bool is_access_check_bypassed() const noexcept
Check if this node should be bypassed for access checks.
layout_attribute & operator=(const layout_attribute &)=default
std::string_view get_name() const noexcept
Returns this node's name.
void set_value(std::string value) noexcept
Set this node's value.
bool was_accessed() const noexcept
Check if this node was accessed by the parser.
void set_name(std::string name) noexcept
Set this node's name.
std::string_view get_value_location() const noexcept
Returns this node's value location in the file as {file}:{line}.
layout_attribute(const layout_attribute &)=default
std::string_view get_filename() const noexcept
Returns the file in which this node is located.
std::string_view get_location() const noexcept
Returns this node's location in the file as {file}:{line}.
T get_value_or(T fallback) const noexcept
Returns this node's value converted to a specific type, or a default value.
void bypass_access_check() const noexcept
Flag this node as "fully accessed" for later warnings; no check will be done.
void set_value_location(std::string location) noexcept
Set this node's value location.
std::size_t get_line_number() const noexcept
Returns the line number on which this node is located.
layout_attribute(layout_attribute &&)=default
void set_location(std::string location) noexcept
Set this node's location.
An node in a layout file.
layout_node(const layout_node &)=default
layout_node & add_child()
Add a new child to this node.
const layout_node * try_get_child(std::string_view name) const noexcept
Returns the first child with a given name, or null if none.
std::vector< layout_attribute > attribute_list
utils::view::adaptor< const attribute_list, utils::view::standard_dereferencer, utils::view::no_filter > attribute_view
const layout_node & get_child(std::string_view name) const
Returns the first child with a given name, and throws if none.
layout_node & operator=(layout_node &&)=default
bool has_attribute(std::string_view name) const noexcept
Checks if a given attribute has been specified.
std::string_view get_or_set_attribute_value(std::string_view name, std::string_view value)
Returns the value of the attribute with the provided name, or set it if none.
const layout_attribute & get_attribute(std::string_view name) const
Returns the value of the first child with the provided name, throws if none.
children_view get_children() const noexcept
Returns a view to the list of children.
std::size_t get_child_count() const noexcept
Returns the number of children of this node.
utils::view::adaptor< const child_list, utils::view::standard_dereferencer, utils::view::no_filter > children_view
filtered_children_view get_children(std::string_view name) const noexcept
Returns a view to the list of children with a given name.
std::optional< std::string_view > try_get_attribute_value(std::string_view name) const noexcept
Returns the value of the attribute with the provided name, nullopt if not found.
attribute_view get_attributes() const noexcept
Returns a view to the list of attributes.
std::string_view get_attribute_value(std::string_view name) const
Returns the value of the attribute with the provided name, throws if none.
layout_attribute & add_attribute()
Add a new attribute to this node.
T get_attribute_value(std::string_view name) const
Returns the value of the attribute with the provided name, throws if not found or parsing failed.
const layout_node & get_child(std::size_t index) const noexcept
Returns a specific child of this node, by index.
layout_node & operator=(const layout_node &)=default
utils::view::adaptor< const child_list, utils::view::standard_dereferencer, name_filter > filtered_children_view
std::optional< T > try_get_attribute_value(std::string_view name) const noexcept
Returns the value of the attribute with the provided name, nullopt if not found or parsing failed.
layout_node(layout_node &&)=default
std::vector< layout_node > child_list
bool has_child(std::string_view name) const noexcept
Checks if at least one child exists with the given name.
T get_attribute_value_or(std::string_view name, T fallback) const noexcept
Returns the value of the attribute with the provided name, or a default if not found or parsing faile...
const layout_attribute * try_get_attribute(std::string_view name) const noexcept
Returns the attribute with the provided name, or null if none.
Allow iterating over a container without access to the container itself.
std::ostream out
const std::string warning
Definition gui_out.cpp:6
bool is_included(const BaseIterator &iter) const noexcept