lxgui
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 
16 namespace lxgui::gui {
17 
25 public:
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 
213 protected:
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 
230 public:
231  layout_node() = default;
232  layout_node(const layout_node&) = default;
233  layout_node(layout_node&&) = default;
234  layout_node& operator=(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 
444  attribute_view get_attributes() const noexcept {
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 
484 private:
485  child_list child_list_;
486  attribute_list attr_list_;
487 };
488 
489 template<>
490 inline std::optional<std::string> layout_attribute::try_get_value<std::string>() const noexcept {
491  accessed_ = true;
492  return value_;
493 }
494 
495 template<>
496 inline std::string layout_attribute::get_value<std::string>() const {
497  accessed_ = true;
498  return value_;
499 }
500 
501 template<>
502 inline 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.
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.
layout_attribute & operator=(layout_attribute &&)=default
bool is_access_check_bypassed() const noexcept
Check if this node should be bypassed for access checks.
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.
layout_attribute & operator=(const layout_attribute &)=default
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
std::optional< T > try_get_value() const noexcept
Returns this node's value converted to a specific type, or nullopt if conversion failed.
void set_location(std::string location) noexcept
Set this node's location.
An node in a layout file.
layout_node(const layout_node &)=default
std::vector< layout_attribute > attribute_list
utils::view::adaptor< const attribute_list, utils::view::standard_dereferencer, utils::view::no_filter > attribute_view
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.
const layout_node & get_child(std::size_t index) const noexcept
Returns a specific child of this node, by index.
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.
layout_node & add_child()
Add a new child to this node.
children_view get_children() const noexcept
Returns a view to the list of children.
layout_node & operator=(layout_node &&)=default
const layout_attribute * try_get_attribute(std::string_view name) const noexcept
Returns the attribute with the provided name, or null if none.
std::size_t get_child_count() const noexcept
Returns the number of children of 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.
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.
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.
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::string_view name) const
Returns the first child with a given name, and throws 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.
utils::view::adaptor< const child_list, utils::view::standard_dereferencer, name_filter > filtered_children_view
layout_attribute & add_attribute()
Add a new attribute to this node.
layout_node & operator=(const layout_node &)=default
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...
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.
Allow iterating over a container without access to the container itself.
Definition: utils_view.hpp:60
std::ostream out
const std::string warning
Definition: gui_out.cpp:6
bool is_included(const BaseIterator &iter) const noexcept