lxgui
gui_frame.cpp
1 #include "lxgui/gui_frame.hpp"
2 
3 #include "lxgui/gui_addon_registry.hpp"
4 #include "lxgui/gui_alive_checker.hpp"
5 #include "lxgui/gui_backdrop.hpp"
6 #include "lxgui/gui_event_emitter.hpp"
7 #include "lxgui/gui_factory.hpp"
8 #include "lxgui/gui_frame_renderer.hpp"
9 #include "lxgui/gui_layered_region.hpp"
10 #include "lxgui/gui_manager.hpp"
11 #include "lxgui/gui_out.hpp"
12 #include "lxgui/gui_region_tpl.hpp"
13 #include "lxgui/utils_range.hpp"
14 #include "lxgui/utils_std.hpp"
15 #include "lxgui/utils_string.hpp"
16 
17 #include <functional>
18 #include <lxgui/extern_sol2_as_args.hpp>
19 #include <lxgui/extern_sol2_state.hpp>
20 #include <lxgui/extern_sol2_variadic_args.hpp>
21 #include <sstream>
22 
23 namespace lxgui::gui {
24 
25 frame::frame(utils::control_block& block, manager& mgr, const frame_core_attributes& attr) :
26  base(block, mgr, attr), event_receiver_(mgr.get_event_emitter()), frame_renderer_(attr.rdr) {
27 
28  initialize_(*this, attr);
29 
30  if (parent_) {
31  level_ = parent_->get_level() + 1;
32  }
33 
36 
37  if (!is_virtual_) {
38  // Tell the renderer to render this region
39  get_effective_frame_renderer()->notify_rendered_frame(observer_from(this), true);
40  }
41 }
42 
44  // Disable callbacks
45  signal_list_.clear();
46 
47  // Children must be destroyed first
48  child_list_.clear();
49  region_list_.clear();
50  title_region_ = nullptr;
51 
52  if (!is_virtual_) {
53  // Tell the renderer to no longer render this region
54  get_effective_frame_renderer()->notify_rendered_frame(observer_from(this), false);
55  }
56 
58 
59  set_focus(false);
60 }
61 
62 void frame::render() const {
63  base::render();
64 
65  if (!is_visible() || !is_valid_)
66  return;
67 
68  if (backdrop_) {
69  backdrop_->render();
70  }
71 
72  // Render child regions
73  for (const auto& layer : layer_list_) {
74  if (layer.is_disabled) {
75  continue;
76  }
77 
78  for (const auto& reg : layer.region_list) {
79  reg->render();
80  }
81  }
82 }
83 
84 std::string frame::serialize(const std::string& tab) const {
85  std::ostringstream str;
86 
87  str << base::serialize(tab);
88  if (auto frame_renderer = utils::dynamic_pointer_cast<frame>(effective_frame_renderer_))
89  str << tab << " # Man. render: " << frame_renderer->get_name() << "\n";
90  str << tab << " # Strata : "
91  << (strata_.has_value() ? utils::to_string(strata_.value()) : "parent") << "\n";
92  str << tab << " # Level : " << level_ << "\n";
93  str << tab << " # TopLevel : " << is_top_level_;
95  str << " (" << get_top_level_parent()->get_name() << ")\n";
96  else
97  str << "\n";
99  str << tab << " # Inputs : none\n";
100  else {
101  str << tab << " # Inputs :\n";
102  str << tab << " |-###\n";
104  str << tab << " | # mouse click\n";
106  str << tab << " | # mouse move\n";
108  str << tab << " | # mouse wheel\n";
109  str << tab << " |-###\n";
110  }
111  str << tab << " # Movable : " << is_movable_ << "\n";
112  str << tab << " # Resizable : " << is_resizable_ << "\n";
113  str << tab << " # Clamped : " << is_clamped_to_screen_ << "\n";
114  str << tab << " # HRect inset :\n";
115  str << tab << " |-###\n";
116  str << tab << " | # left : " << abs_hit_rect_inset_list_.left << "\n";
117  str << tab << " | # right : " << abs_hit_rect_inset_list_.right << "\n";
118  str << tab << " | # top : " << abs_hit_rect_inset_list_.top << "\n";
119  str << tab << " | # bottom: " << abs_hit_rect_inset_list_.bottom << "\n";
120  str << tab << " |-###\n";
121  str << tab << " # Min width : " << min_width_ << "\n";
122  str << tab << " # Max width : " << max_width_ << "\n";
123  str << tab << " # Min height : " << min_height_ << "\n";
124  str << tab << " # Max height : " << max_height_ << "\n";
125  str << tab << " # Scale : " << scale_ << "\n";
126  str << tab << " # Update rate : " << update_rate_ << "\n";
127  if (title_region_) {
128  str << tab << " # Title reg. :\n";
129  str << tab << " |-###\n";
130  str << title_region_->serialize(tab + " | ");
131  str << tab << " |-###\n";
132  }
133  if (backdrop_) {
134  const bounds2f& insets = backdrop_->get_background_insets();
135 
136  str << tab << " # Backdrop :\n";
137  str << tab << " |-###\n";
138  str << tab << " | # Background: " << backdrop_->get_background_file() << "\n";
139  str << tab << " | # Tilling : " << backdrop_->is_background_tilling() << "\n";
140  if (backdrop_->is_background_tilling())
141  str << tab << " | # Tile size : " << backdrop_->get_tile_size() << "\n";
142  str << tab << " | # BG Insets :\n";
143  str << tab << " | |-###\n";
144  str << tab << " | | # left : " << insets.left << "\n";
145  str << tab << " | | # right : " << insets.right << "\n";
146  str << tab << " | | # top : " << insets.top << "\n";
147  str << tab << " | | # bottom: " << insets.bottom << "\n";
148  str << tab << " | |-###\n";
149  str << tab << " | # Edge : " << backdrop_->get_edge_file() << "\n";
150  str << tab << " | # Edge size : " << backdrop_->get_edge_size() << "\n";
151  str << tab << " |-###\n";
152  }
153 
154  if (!region_list_.empty()) {
155  if (child_list_.size() == 1)
156  str << tab << " # Region: \n";
157  else
158  str << tab << " # Regions : " << region_list_.size() << "\n";
159  str << tab << " |-###\n";
160 
161  for (auto& obj : get_regions()) {
162  str << obj.serialize(tab + " | ");
163  str << tab << " |-###\n";
164  }
165  }
166 
167  if (!child_list_.empty()) {
168  if (child_list_.size() == 1)
169  str << tab << " # Child: \n";
170  else
171  str << tab << " # Children : " << child_list_.size() << "\n";
172  str << tab << " |-###\n";
173 
174  for (const auto& child : get_children()) {
175  str << child.serialize(tab + " | ");
176  str << tab << " |-###\n";
177  }
178  }
179 
180  return str.str();
181 }
182 
183 bool frame::can_use_script(const std::string& script_name) const {
184  return script_name == "OnChar" || script_name == "OnDragStart" || script_name == "OnDragStop" ||
185  script_name == "OnDragMove" || script_name == "OnEnter" || script_name == "OnEvent" ||
186  script_name == "OnFocusGained" || script_name == "OnFocusLost" ||
187  script_name == "OnHide" || script_name == "OnKeyDown" || script_name == "OnKeyUp" ||
188  script_name == "OnKeyRepeat" || script_name == "OnLeave" || script_name == "OnLoad" ||
189  script_name == "OnMouseDown" || script_name == "OnMouseUp" ||
190  script_name == "OnMouseMove" || script_name == "OnDoubleClick" ||
191  script_name == "OnMouseWheel" || script_name == "OnReceiveDrag" ||
192  script_name == "OnShow" || script_name == "OnSizeChanged" || script_name == "OnUpdate";
193 }
194 
195 void frame::copy_from(const region& obj) {
196  base::copy_from(obj);
197 
198  const frame* frame_obj = down_cast<frame>(&obj);
199  if (!frame_obj)
200  return;
201 
202  for (const auto& item : frame_obj->signal_list_) {
203  for (const auto& function : frame_obj->get_script(item.first)) {
204  this->add_script(item.first, function);
205  }
206  }
207 
208  this->set_strata(frame_obj->get_strata());
209  // NB: level is not inherited on purpose; this is difficult to make sense of
210  this->set_top_level(frame_obj->is_top_level());
211 
213  this->set_mouse_move_enabled(frame_obj->is_mouse_move_enabled());
215  this->set_keyboard_enabled(frame_obj->is_keyboard_enabled());
216 
217  this->set_movable(frame_obj->is_movable());
218  this->set_clamped_to_screen(frame_obj->is_clamped_to_screen());
219  this->set_resizable(frame_obj->is_resizable());
220 
223 
224  this->set_max_dimensions(frame_obj->get_max_dimensions());
225  this->set_min_dimensions(frame_obj->get_min_dimensions());
226 
227  this->set_scale(frame_obj->get_scale());
228 
229  this->set_update_rate(frame_obj->get_update_rate());
230 
231  for (const auto& art : frame_obj->region_list_) {
232  if (!art || art->is_manually_inherited())
233  continue;
234 
236  attr.object_type = art->get_region_type();
237  attr.name = art->get_raw_name();
238  attr.inheritance = {art};
239 
240  auto new_art = create_layered_region(art->get_draw_layer(), std::move(attr));
241  if (!new_art)
242  continue;
243 
244  new_art->notify_loaded();
245  }
246 
247  if (frame_obj->backdrop_) {
248  backdrop_ = std::unique_ptr<backdrop>(new backdrop(*this));
249  backdrop_->copy_from(*frame_obj->backdrop_);
250  }
251 
252  if (frame_obj->title_region_) {
253  this->create_title_region();
254  if (title_region_)
255  title_region_->copy_from(*frame_obj->title_region_);
256  }
257 
258  for (const auto& child : frame_obj->child_list_) {
259  if (!child || child->is_manually_inherited())
260  continue;
261 
263  attr.object_type = child->get_region_type();
264  attr.name = child->get_raw_name();
265  attr.inheritance = {child};
266 
267  auto new_child = create_child(std::move(attr));
268  if (!new_child)
269  continue;
270 
271  new_child->notify_loaded();
272  }
273 }
274 
276  if (title_region_) {
277  gui::out << gui::warning << "gui::" << get_region_type() << ": \"" << name_
278  << "\" already has a title region." << std::endl;
279  return;
280  }
281 
283  attr.object_type = "Region";
284  attr.is_virtual = is_virtual();
285  attr.name = "$parentTitleRegion";
286  attr.parent = observer_from(this);
287 
288  auto title_region = get_manager().get_factory().create_region(get_registry(), attr);
289 
290  if (!title_region)
291  return;
292 
293  title_region->set_manually_inherited(true);
294 
295  if (!title_region->is_virtual()) {
296  // Add shortcut to region as entry in Lua table
297  auto& lua = get_lua_();
298  lua[get_name()]["TitleRegion"] = lua[title_region->get_name()];
299  }
300 
301  title_region_ = std::move(title_region);
302  title_region_->notify_loaded();
303 }
304 
305 utils::observer_ptr<const frame> frame::get_child(const std::string& name) const {
306  for (const auto& child : child_list_) {
307  if (!child)
308  continue;
309 
310  if (child->get_name() == name)
311  return child;
312 
313  const std::string& raw_name = child->get_raw_name();
314  if (utils::starts_with(raw_name, "$parent") && raw_name.substr(7) == name)
315  return child;
316  }
317 
318  return nullptr;
319 }
320 
323 }
324 
327 }
328 
329 utils::observer_ptr<const layered_region> frame::get_region(const std::string& name) const {
330  for (const auto& reg : region_list_) {
331  if (!reg)
332  continue;
333 
334  if (reg->get_name() == name)
335  return reg;
336 
337  const std::string& raw_name = reg->get_raw_name();
338  if (utils::starts_with(raw_name, "$parent") && raw_name.substr(7) == name)
339  return reg;
340  }
341 
342  return nullptr;
343 }
344 
345 void frame::set_dimensions(const vector2f& dimensions) {
347  std::min(std::max(dimensions.x, min_width_), max_width_),
348  std::min(std::max(dimensions.y, min_height_), max_height_)));
349 }
350 
351 void frame::set_width(float abs_width) {
352  base::set_width(std::min(std::max(abs_width, min_width_), max_width_));
353 }
354 
355 void frame::set_height(float abs_height) {
356  base::set_height(std::min(std::max(abs_height, min_height_), max_height_));
357 }
358 
362  } else if (borders_.right - borders_.left > max_width_) {
364  }
365 
368  } else if (borders_.bottom - borders_.top > max_height_) {
370  }
371 
372  if (is_clamped_to_screen_) {
373  vector2f screen_dimensions = get_effective_frame_renderer()->get_target_dimensions();
374 
375  if (borders_.right > screen_dimensions.x) {
376  float width = borders_.right - borders_.left;
377  if (width > screen_dimensions.x) {
378  borders_.left = 0;
379  borders_.right = screen_dimensions.x;
380  } else {
381  borders_.right = screen_dimensions.x;
382  borders_.left = screen_dimensions.x - width;
383  }
384  }
385 
386  if (borders_.left < 0) {
387  float width = borders_.right - borders_.left;
388  if (borders_.right - borders_.left > screen_dimensions.x) {
389  borders_.left = 0;
390  borders_.right = screen_dimensions.x;
391  } else {
392  borders_.left = 0;
393  borders_.right = width;
394  }
395  }
396 
397  if (borders_.bottom > screen_dimensions.y) {
398  float height = borders_.bottom - borders_.top;
399  if (height > screen_dimensions.y) {
400  borders_.top = 0;
401  borders_.bottom = screen_dimensions.y;
402  } else {
403  borders_.bottom = screen_dimensions.y;
404  borders_.top = screen_dimensions.y - height;
405  }
406  }
407 
408  if (borders_.top < 0) {
409  float height = borders_.bottom - borders_.top;
410  if (height > screen_dimensions.y) {
411  borders_.top = 0;
412  borders_.bottom = screen_dimensions.y;
413  } else {
414  borders_.top = 0;
415  borders_.bottom = height;
416  }
417  }
418  }
419 }
420 
422  layer_container& layer = layer_list_[static_cast<std::size_t>(layer_id)];
423  if (!layer.is_disabled) {
424  layer.is_disabled = true;
426  }
427 }
428 
430  layer_container& layer = layer_list_[static_cast<std::size_t>(layer_id)];
431  if (!layer.is_disabled) {
432  layer.is_disabled = false;
434  }
435 }
436 
437 void frame::set_mouse_enabled(bool is_mouse_enabled) {
438  set_mouse_click_enabled(is_mouse_enabled);
439  set_mouse_move_enabled(is_mouse_enabled);
440 }
441 
442 void frame::set_mouse_click_enabled(bool is_mouse_enabled) {
443  is_mouse_click_enabled_ = is_mouse_enabled;
444 }
445 
446 void frame::set_mouse_move_enabled(bool is_mouse_enabled) {
447  is_mouse_move_enabled_ = is_mouse_enabled;
448 }
449 
450 void frame::set_mouse_wheel_enabled(bool is_mouse_wheel_enabled) {
452 }
453 
454 void frame::set_keyboard_enabled(bool is_keyboard_enabled) {
456 }
457 
458 void frame::enable_key_capture(const std::string& key_name) {
459  reg_key_list_.insert(key_name);
460 }
461 
463  reg_key_list_.insert(std::string{input::get_key_codename(key_id)});
464 }
465 
466 void frame::disable_key_capture(const std::string& key_name) {
467  reg_key_list_.erase(key_name);
468 }
469 
471  reg_key_list_.erase(std::string{input::get_key_codename(key_id)});
472 }
473 
475  reg_key_list_.clear();
476 }
477 
480 
481  if (!is_virtual_) {
482  alive_checker checker(*this);
483  fire_script("OnLoad");
484  if (!checker.is_alive())
485  return;
486  }
487 }
488 
490  // Clear layers' content
491  for (auto& layer : layer_list_)
492  layer.region_list.clear();
493 
494  // Fill layers with regions (sorted by region level within the same layer)
495  for (const auto& reg : region_list_) {
496  if (reg) {
497  layer_list_[static_cast<std::size_t>(reg->get_draw_layer())].region_list.push_back(reg);
498  }
499  }
500 
501  // Sort each layer by region level (this enables rendering text above textures)
502  for (auto& layer : layer_list_) {
503  std::stable_sort(
504  layer.region_list.begin(), layer.region_list.end(),
505  [](const auto& reg1, const auto& reg2) {
506  return reg1->get_region_level() < reg2->get_region_level();
507  });
508  }
509 
511 }
512 
513 void frame::set_parent_(utils::observer_ptr<frame> parent) {
514  auto* raw_new_parent = parent.get();
515  auto* raw_prev_parent = get_parent().get();
516 
517  if (!is_virtual()) {
518  if (raw_prev_parent) {
519  // Remove shortcut to child
520  std::string raw_name = get_raw_name();
521  if (utils::starts_with(raw_name, "$parent")) {
522  raw_name.erase(0, std::string("$parent").size());
523  sol::state& lua = get_lua_();
524  lua[raw_prev_parent->get_name()][raw_name] = sol::lua_nil;
525  }
526  }
527  }
528 
529  base::set_parent_(parent);
530 
531  if (!is_virtual()) {
532  // Notify visibility
533  if (raw_new_parent) {
534  if (raw_new_parent->is_visible() && is_shown())
535  notify_visible();
536  else
538  } else {
539  if (is_shown())
540  notify_visible();
541  else
543  }
544 
545  if (raw_new_parent) {
546  // Add shortcut to child as entry in Lua table
547  std::string raw_name = get_raw_name();
548  if (utils::starts_with(raw_name, "$parent")) {
549  raw_name.erase(0, std::string("$parent").size());
550  auto& lua = get_lua_();
551  lua[raw_new_parent->get_name()][raw_name] = lua[get_name()];
552  }
553  }
554 
555  const auto new_top_level_renderer = compute_top_level_frame_renderer_();
556  if (new_top_level_renderer != effective_frame_renderer_) {
557  notify_frame_renderer_changed_(new_top_level_renderer);
558  }
559 
560  const auto new_strata = compute_effective_strata_();
561  if (new_strata != effective_strata_) {
562  notify_strata_changed_(new_strata);
563  }
564  }
565 }
566 
568  const auto old_strata = effective_strata_;
569 
570  effective_strata_ = new_strata_id;
571 
572  get_effective_frame_renderer()->notify_strata_changed(
573  observer_from(this), old_strata, effective_strata_);
574 
575  for (const auto& child : child_list_) {
576  if (!child)
577  continue;
578 
579  if (!child->get_strata().has_value())
580  child->notify_strata_changed_(new_strata_id);
581  }
582 }
583 
584 bool frame::has_script(const std::string& script_name) const {
585  const auto iter = signal_list_.find(script_name);
586  if (iter == signal_list_.end())
587  return false;
588 
589  return !iter->second.empty();
590 }
591 
592 utils::observer_ptr<layered_region> frame::add_region(utils::owner_ptr<layered_region> reg) {
593  if (!reg)
594  return nullptr;
595 
596  reg->set_parent_(observer_from(this));
597 
598  utils::observer_ptr<layered_region> added_region = reg;
599  region_list_.push_back(std::move(reg));
600 
602 
603  if (!is_virtual_) {
604  // Add shortcut to region as entry in Lua table
605  std::string raw_name = added_region->get_raw_name();
606  if (utils::starts_with(raw_name, "$parent")) {
607  raw_name.erase(0, std::string("$parent").size());
608  auto& lua = get_lua_();
609  lua[get_name()][raw_name] = lua[added_region->get_name()];
610  }
611  }
612 
613  return added_region;
614 }
615 
617 frame::remove_region(const utils::observer_ptr<layered_region>& reg) {
618  if (!reg)
619  return nullptr;
620 
621  layered_region* raw_pointer = reg.get();
622 
623  auto iter = utils::find_if(region_list_, [&](auto& obj) { return obj.get() == raw_pointer; });
624 
625  if (iter == region_list_.end()) {
626  gui::out << gui::warning << "gui::" << get_region_type() << ": "
627  << "Trying to remove \"" << reg->get_name() << "\" from \"" << name_
628  << "\"'s children, but it was not one of this frame's children." << std::endl;
629  return nullptr;
630  }
631 
632  // NB: the iterator is not removed yet; it will be removed later in update().
633  auto removed_region = std::move(*iter);
634 
636  removed_region->set_parent_(nullptr);
637 
638  if (!is_virtual_) {
639  // Remove shortcut to region
640  std::string raw_name = removed_region->get_raw_name();
641  if (utils::starts_with(raw_name, "$parent")) {
642  raw_name.erase(0, std::string("$parent").size());
643  sol::state& lua = get_lua_();
644  lua[get_name()][raw_name] = sol::lua_nil;
645  }
646  }
647 
648  return removed_region;
649 }
650 
651 utils::observer_ptr<layered_region>
653  attr.is_virtual = is_virtual();
654  attr.parent = observer_from(this);
655 
657 
658  if (!reg)
659  return nullptr;
660 
661  reg->set_draw_layer(layer_id);
662 
663  return add_region(std::move(reg));
664 }
665 
666 utils::observer_ptr<frame> frame::create_child(frame_core_attributes attr) {
667  attr.is_virtual = is_virtual();
668  attr.parent = observer_from(this);
669 
670  auto new_frame = get_manager().get_factory().create_frame(get_registry(), attr);
671 
672  if (!new_frame)
673  return nullptr;
674 
675  return add_child(std::move(new_frame));
676 }
677 
678 utils::observer_ptr<frame> frame::add_child(utils::owner_ptr<frame> child) {
679  if (!child)
680  return nullptr;
681 
682  child->set_parent_(observer_from(this));
683 
684  utils::observer_ptr<frame> added_child = child;
685  child_list_.push_back(std::move(child));
686 
687  return added_child;
688 }
689 
690 utils::owner_ptr<frame> frame::remove_child(const utils::observer_ptr<frame>& child) {
691  if (!child)
692  return nullptr;
693 
694  frame* raw_pointer = child.get();
695  auto iter = utils::find_if(child_list_, [&](auto& obj) { return obj.get() == raw_pointer; });
696 
697  if (iter == child_list_.end()) {
698  gui::out << gui::warning << "gui::" << get_region_type() << ": "
699  << "Trying to remove \"" << child->get_name() << "\" from \"" << name_
700  << "\"'s children, but it was not one of this frame's children." << std::endl;
701  return nullptr;
702  }
703 
704  // NB: the iterator is not removed yet; it will be removed later in update().
705  auto removed_child = std::move(*iter);
706 
707  removed_child->set_parent_(nullptr);
708 
709  return removed_child;
710 }
711 
714 }
715 
718 }
719 
721  if (parent_)
722  return scale_ * parent_->get_effective_scale();
723  else
724  return scale_;
725 }
726 
727 int frame::get_level() const {
728  return level_;
729 }
730 
731 std::optional<strata> frame::get_strata() const {
732  return strata_;
733 }
734 
736  return effective_strata_;
737 }
738 
740  if (strata_.has_value())
741  return strata_.value();
742 
743  if (parent_ && parent_->get_effective_frame_renderer() == get_effective_frame_renderer())
744  return parent_->get_effective_strata();
745 
746  // Default if no defined strata and no parent set.
747  return strata::medium;
748 }
749 
750 utils::observer_ptr<const frame> frame::get_top_level_parent() const {
751  auto obj = observer_from(this);
752  do {
753  if (obj->is_top_level())
754  return obj;
755 
756  obj = obj->get_parent();
757  } while (obj);
758 
759  return nullptr;
760 }
761 
763  return backdrop_.get();
764 }
765 
767  return backdrop_.get();
768 }
769 
771  if (!backdrop_)
772  backdrop_ = std::unique_ptr<backdrop>(new backdrop(*this));
773 
774  return *backdrop_;
775 }
776 
779 }
780 
783 }
784 
787 }
788 
791 }
792 
793 std::size_t frame::get_child_count() const {
794  return std::count_if(
795  child_list_.begin(), child_list_.end(), [](const auto& child) { return child != nullptr; });
796 }
797 
799  return child_list_.size();
800 }
801 
802 std::size_t frame::get_layered_region_count() const {
803  return std::count_if(
804  region_list_.begin(), region_list_.end(), [](const auto& reg) { return reg != nullptr; });
805 }
806 
808  return region_list_.size();
809 }
810 
811 float frame::get_scale() const {
812  return scale_;
813 }
814 
816  return is_clamped_to_screen_;
817 }
818 
819 bool frame::is_in_region(const vector2f& position) const {
820  if (title_region_ && title_region_->is_in_region(position))
821  return true;
822 
823  bool is_in_x_range = borders_.left + abs_hit_rect_inset_list_.left <= position.x &&
824  position.x <= borders_.right - abs_hit_rect_inset_list_.right - 1.0f;
825  bool is_in_y_range = borders_.top + abs_hit_rect_inset_list_.top <= position.y &&
826  position.y <= borders_.bottom - abs_hit_rect_inset_list_.bottom - 1.0f;
827 
828  return is_in_x_range && is_in_y_range;
829 }
830 
831 utils::observer_ptr<const frame>
832 frame::find_topmost_frame(const std::function<bool(const frame&)>& predicate) const {
833  if (predicate(*this))
834  return observer_from(this);
835 
836  return nullptr;
837 }
838 
841 }
842 
844  return is_mouse_move_enabled_;
845 }
846 
849 }
850 
851 bool frame::is_drag_enabled(const std::string& button_name) const {
852  return reg_drag_list_.find(button_name) != reg_drag_list_.end();
853 }
854 
856  return is_keyboard_enabled_;
857 }
858 
859 bool frame::is_key_capture_enabled(const std::string& key_name) const {
860  return reg_key_list_.find(key_name) != reg_key_list_.end();
861 }
862 
863 bool frame::is_movable() const {
864  return is_movable_;
865 }
866 
867 bool frame::is_resizable() const {
868  return is_resizable_;
869 }
870 
871 bool frame::is_top_level() const {
872  return is_top_level_;
873 }
874 
875 bool frame::is_user_placed() const {
876  return is_user_placed_;
877 }
878 
879 std::string frame::get_adjusted_script_name(const std::string& script_name) {
880  std::string adjusted_name = script_name;
881  for (auto iter = adjusted_name.begin(); iter != adjusted_name.end(); ++iter) {
882  if ('A' <= *iter && *iter <= 'Z') {
883  *iter = std::tolower(*iter);
884  if (iter != adjusted_name.begin())
885  iter = adjusted_name.insert(iter, '_');
886  }
887  }
888 
889  return adjusted_name;
890 }
891 
892 std::string
893 hijack_sol_error_line(std::string original_message, const std::string& file, std::size_t line_nbr) {
894  auto pos1 = original_message.find("[string \"" + file);
895  if (pos1 == std::string::npos)
896  return original_message;
897 
898  auto pos2 = original_message.find_first_of('"', pos1 + 9);
899  if (pos2 == std::string::npos)
900  return original_message;
901 
902  original_message.erase(pos1, pos2 - pos1 + 2);
903  original_message.insert(pos1, file);
904 
905  auto pos3 = original_message.find_first_of(':', pos1 + file.size());
906  if (pos3 == std::string::npos)
907  return original_message;
908 
909  auto pos4 = original_message.find_first_of(":>", pos3 + 1);
910  if (pos4 == std::string::npos)
911  return original_message;
912 
913  auto offset =
914  utils::from_string<std::size_t>(original_message.substr(pos3 + 1, pos4 - pos3 - 1));
915  if (!offset.has_value())
916  return original_message;
917 
918  original_message.erase(pos3 + 1, pos4 - pos3 - 1);
919  original_message.insert(pos3 + 1, utils::to_string(line_nbr + offset.value() - 1));
920  pos4 = original_message.find_first_of(':', pos3 + 1);
921 
922  auto pos5 = original_message.find("[string \"" + file, pos4);
923  if (pos5 == std::string::npos)
924  return original_message;
925 
926  std::string message = original_message.substr(pos4 + 1);
927  original_message.erase(pos4 + 1);
928  original_message += hijack_sol_error_line(message, file, line_nbr);
929 
930  return original_message;
931 }
932 
934  std::string_view original_message, const std::string& file, std::size_t line_nbr) {
935  std::string new_error;
936  for (auto line : utils::cut(original_message, "\n")) {
937  if (!new_error.empty())
938  new_error += '\n';
939 
940  new_error += hijack_sol_error_line(std::string{line}, file, line_nbr);
941  }
942 
943  return new_error;
944 }
945 
946 bool frame::check_script_(const std::string& script_name) const {
947  if (!can_use_script(script_name)) {
948  gui::out << gui::error << get_region_type() << ": "
949  << "\"" << get_name() << "\" cannot use script \"" << script_name << "\"."
950  << std::endl;
951  return false;
952  }
953 
954  return true;
955 }
956 
958  const std::string& script_name,
959  const std::string& content,
960  bool append,
961  const script_info& info) {
962 
963  // Create the Lua function from the provided string
964  sol::state& lua = get_lua_();
965 
966  std::string str = "return function(self";
967 
968  constexpr std::size_t max_args = 9;
969  for (std::size_t i = 0; i < max_args; ++i)
970  str += ", arg" + utils::to_string(i + 1);
971 
972  str += ") " + content + " end";
973 
974  auto result = lua.do_string(str, info.file_name);
975 
976  if (!result.valid()) {
977  std::string err = hijack_sol_error_message(
978  result.get<sol::error>().what(), info.file_name, info.line_nbr);
979 
980  gui::out << gui::error << err << std::endl;
981 
982  get_manager().get_event_emitter().fire_event("LUA_ERROR", {err});
983  return {};
984  }
985 
986  sol::protected_function handler = result;
987 
988  // Forward it as any other Lua function
989  return define_script_(script_name, std::move(handler), append, info);
990 }
991 
993  const std::string& script_name,
994  sol::protected_function handler,
995  bool append,
996  const script_info& info) {
997 
998  auto wrapped_handler = [handler = std::move(handler),
999  info](frame& self, const event_data& args) {
1000  sol::state& lua = self.get_manager().get_lua();
1001  lua_State* lua_raw = lua.lua_state();
1002 
1003  std::vector<sol::object> lua_args;
1004 
1005  // Set arguments
1006  for (std::size_t i = 0; i < args.get_param_count(); ++i) {
1007  const utils::variant& arg = args.get(i);
1008  if (std::holds_alternative<utils::empty>(arg))
1009  lua_args.emplace_back(sol::lua_nil);
1010  else
1011  lua_args.emplace_back(lua_raw, sol::in_place, arg);
1012  }
1013 
1014  // Get a reference to self
1015  sol::object self_lua = lua[self.get_name()];
1016  if (self_lua == sol::lua_nil)
1017  throw gui::exception("Lua glue object is nil");
1018 
1019  // Call the function
1020  auto result = handler(self_lua, sol::as_args(lua_args));
1021  // WARNING: after this point, the frame (self_lua) may be deleted.
1022  // Do not use any member variable or member function directly.
1023 
1024  // Handle errors
1025  if (!result.valid()) {
1027  result.get<sol::error>().what(), info.file_name, info.line_nbr));
1028  }
1029  };
1030 
1031  return define_script_(script_name, std::move(wrapped_handler), append, info);
1032 }
1033 
1035  const std::string& script_name,
1036  script_function handler,
1037  bool append,
1038  const script_info& /*info*/) {
1039 
1040  if (!is_virtual()) {
1041  // Register the function so it can be called directly from Lua
1042  std::string adjusted_name = get_adjusted_script_name(script_name);
1043 
1044  get_lua_()[get_name()][adjusted_name].set_function(
1045  [=](frame& self, sol::variadic_args v_args) {
1046  event_data data;
1047  for (auto&& arg : v_args) {
1048  lxgui::utils::variant variant;
1049  if (!arg.is<sol::lua_nil_t>())
1050  variant = arg;
1051 
1052  data.add(std::move(variant));
1053  }
1054 
1055  self.fire_script(script_name, data);
1056  });
1057  }
1058 
1059  auto& handler_list = signal_list_[script_name];
1060  if (!append) {
1061  // Just disable existing scripts, it may not be safe to modify the handler list
1062  // if this script is being defined during a handler execution.
1063  // They will be deleted later, when we know it is safe.
1064  handler_list.disconnect_all();
1065  }
1066 
1067  // TODO: add file/line info if the handler comes from C++
1068  // https://github.com/cschreib/lxgui/issues/96
1069  return handler_list.connect(std::move(handler));
1070 }
1071 
1072 script_list_view frame::get_script(const std::string& script_name) const {
1073  auto iter_h = signal_list_.find(script_name);
1074  if (iter_h == signal_list_.end())
1075  throw gui::exception(get_region_type(), "no script registered for " + script_name);
1076 
1077  return iter_h->second.slots();
1078 }
1079 
1080 void frame::remove_script(const std::string& script_name) {
1081  auto iter_h = signal_list_.find(script_name);
1082  if (iter_h == signal_list_.end())
1083  return;
1084 
1085  // Just disable existing scripts, it may not be safe to modify the handler list
1086  // if this script is being defined during a handler execution.
1087  // They will be deleted later, when we know it is safe.
1088  iter_h->second.disconnect_all();
1089 
1090  if (!is_virtual()) {
1091  std::string adjusted_name = get_adjusted_script_name(script_name);
1092  get_lua_()[get_name()][adjusted_name] = sol::lua_nil;
1093  }
1094 }
1095 
1096 void frame::on_event_(std::string_view event_name, const event_data& event) {
1097  event_data data;
1098  data.add(std::string(event_name));
1099  for (std::size_t i = 0; i < event.get_param_count(); ++i)
1100  data.add(event.get(i));
1101 
1102  fire_script("OnEvent", data);
1103 }
1104 
1105 void frame::fire_script(const std::string& script_name, const event_data& data) {
1106  if (!is_loaded())
1107  return;
1108 
1109  auto iter_h = signal_list_.find(script_name);
1110  if (iter_h == signal_list_.end())
1111  return;
1112 
1113  // Make a copy of useful pointers: in case the frame is deleted, we will need this
1116  const auto* old_addon = addon_registry.get_current_addon();
1118 
1119  try {
1120  // Call the handlers
1121  iter_h->second(*this, data);
1122  } catch (const std::exception& e) {
1123  std::string err = e.what();
1124  gui::out << gui::error << err << std::endl;
1125  event_emitter.fire_event("LUA_ERROR", {err});
1126  }
1127 
1128  addon_registry.set_current_addon(old_addon);
1129 }
1130 
1131 void frame::register_event(const std::string& event_name) {
1132  if (is_virtual_)
1133  return;
1134 
1136  event_name, [=](const event_data& event) { return on_event_(event_name, event); });
1137 }
1138 
1139 void frame::unregister_event(const std::string& event_name) {
1140  if (is_virtual_)
1141  return;
1142 
1143  event_receiver_.unregister_event(event_name);
1144 }
1145 
1146 void frame::set_update_rate(float rate) {
1147  update_rate_ = rate;
1148 }
1149 
1150 float frame::get_update_rate() const {
1151  return update_rate_;
1152 }
1153 
1154 void frame::enable_drag(const std::string& button_name) {
1155  reg_drag_list_.insert(button_name);
1156 }
1157 
1159  reg_drag_list_.insert(std::string{input::get_mouse_button_codename(button_id)});
1160 }
1161 
1162 void frame::disable_drag(const std::string& button_name) {
1163  reg_drag_list_.erase(button_name);
1164 }
1165 
1167  reg_drag_list_.erase(std::string{input::get_mouse_button_codename(button_id)});
1168 }
1169 
1171  reg_drag_list_.clear();
1172 }
1173 
1174 void frame::set_clamped_to_screen(bool is_clamped_to_screen) {
1176 }
1177 
1178 void frame::set_strata(std::optional<strata> strata_id) {
1179  strata_ = strata_id;
1180 
1181  const auto new_effective_strata = compute_effective_strata_();
1182 
1183  if (!is_virtual() && new_effective_strata != effective_strata_) {
1184  notify_strata_changed_(new_effective_strata);
1185  }
1186 }
1187 
1188 void frame::set_backdrop(std::unique_ptr<backdrop> bdrop) {
1189  backdrop_ = std::move(bdrop);
1191 }
1192 
1194  abs_hit_rect_inset_list_ = insets;
1195 }
1196 
1198  rel_hit_rect_inset_list_ = insets;
1199 }
1200 
1201 void frame::set_level(int level_id) {
1202  if (level_id == level_)
1203  return;
1204 
1205  std::swap(level_id, level_);
1206 
1207  if (!is_virtual_) {
1208  get_effective_frame_renderer()->notify_level_changed(observer_from(this), level_id, level_);
1209  }
1210 }
1211 
1213  set_max_width(max.x);
1214  set_max_height(max.y);
1215 }
1216 
1218  set_min_width(min.x);
1219  set_min_height(min.y);
1220 }
1221 
1222 void frame::set_max_height(float max_height) {
1223  if (max_height < 0.0f)
1224  max_height = std::numeric_limits<float>::infinity();
1225 
1226  if (max_height >= min_height_)
1227  max_height_ = max_height;
1228 
1229  if (max_height_ != max_height && !is_virtual_)
1231 }
1232 
1233 void frame::set_max_width(float max_width) {
1234  if (max_width < 0.0f)
1235  max_width = std::numeric_limits<float>::infinity();
1236 
1237  if (max_width >= min_width_)
1238  max_width_ = max_width;
1239 
1240  if (max_width_ != max_width && !is_virtual_)
1242 }
1243 
1244 void frame::set_min_height(float min_height) {
1245  if (min_height <= max_height_)
1246  min_height_ = min_height;
1247 
1248  if (min_height_ != min_height && !is_virtual_)
1250 }
1251 
1252 void frame::set_min_width(float min_width) {
1253  if (min_width <= max_width_)
1254  min_width_ = min_width;
1255 
1256  if (min_width_ != min_width && !is_virtual_)
1258 }
1259 
1260 void frame::set_movable(bool is_movable) {
1262 }
1263 
1265  utils::observer_ptr<frame> self = observer_from(this);
1266  if (parent_)
1267  return parent_->remove_child(self);
1268  else
1269  return get_manager().get_root().remove_root_frame(self);
1270 }
1271 
1272 void frame::set_resizable(bool is_resizable) {
1274 }
1275 
1276 void frame::set_scale(float scale) {
1277  scale_ = scale;
1278  if (scale_ != scale)
1280 }
1281 
1282 void frame::set_top_level(bool is_top_level) {
1284 }
1285 
1287  if (!is_top_level_)
1288  return;
1289 
1290  int old_level = level_;
1291  auto rdr = get_effective_frame_renderer();
1292  int top_level = rdr->get_highest_level(get_effective_strata());
1293 
1294  if (old_level == top_level) {
1295  // This frame is already on top, nothing to do.
1296  return;
1297  }
1298 
1299  level_ = top_level + 1;
1300  int diff = level_ - old_level;
1301 
1302  if (!is_virtual()) {
1303  rdr->notify_level_changed(observer_from(this), old_level, level_);
1304  }
1305 
1306  for (auto& child : get_children())
1307  child.add_level_(diff);
1308 }
1309 
1310 void frame::enable_auto_focus(bool enable) {
1311  is_auto_focus_ = enable;
1312 }
1313 
1315  return is_auto_focus_;
1316 }
1317 
1318 void frame::set_focus(bool focus) {
1319  auto& root = get_manager().get_root();
1320  if (focus)
1322  else
1323  root.release_focus(*this);
1324 }
1325 
1326 bool frame::has_focus() const {
1327  return is_focused_;
1328 }
1329 
1330 void frame::notify_focus(bool focus) {
1331  if (is_focused_ == focus)
1332  return;
1333 
1334  is_focused_ = focus;
1335 
1336  if (is_focused_)
1337  fire_script("OnFocusGained");
1338  else
1339  fire_script("OnFocusLost");
1340 }
1341 
1342 void frame::add_level_(int amount) {
1343  int old_level = level_;
1344  level_ += amount;
1345 
1346  if (!is_virtual()) {
1347  get_effective_frame_renderer()->notify_level_changed(
1348  observer_from(this), old_level, level_);
1349  }
1350 
1351  for (auto& child : get_children())
1352  child.add_level_(amount);
1353 }
1354 
1355 void frame::set_user_placed(bool is_user_placed) {
1357 }
1358 
1360  if (!is_movable_)
1361  return;
1362 
1363  set_user_placed(true);
1365 }
1366 
1368  if (get_manager().get_root().is_moving(*this))
1370 }
1371 
1372 void frame::start_sizing(const point& p) {
1373  if (!is_resizable_)
1374  return;
1375 
1376  set_user_placed(true);
1378 }
1379 
1381  if (get_manager().get_root().is_sizing(*this))
1383 }
1384 
1386  const utils::observer_ptr<frame_renderer>& new_renderer) {
1387 
1388  effective_frame_renderer_->notify_rendered_frame(observer_from(this), false);
1389  effective_frame_renderer_ = new_renderer;
1390  effective_frame_renderer_->notify_rendered_frame(observer_from(this), true);
1391 
1392  for (const auto& child : child_list_) {
1393  if (auto* raw_ptr = child.get(); raw_ptr && !raw_ptr->get_frame_renderer())
1394  child->notify_frame_renderer_changed_(new_renderer);
1395  }
1396 }
1397 
1398 void frame::set_frame_renderer(utils::observer_ptr<frame_renderer> rdr) {
1399  if (rdr == frame_renderer_)
1400  return;
1401 
1402  frame_renderer_ = std::move(rdr);
1403  const auto new_effective_renderer = compute_top_level_frame_renderer_();
1404 
1405  if (effective_frame_renderer_ != new_effective_renderer) {
1406  notify_frame_renderer_changed_(new_effective_renderer);
1407  }
1408 }
1409 
1410 utils::observer_ptr<const frame_renderer> frame::get_effective_frame_renderer() const {
1412 }
1413 
1414 utils::observer_ptr<const frame_renderer> frame::compute_top_level_frame_renderer_() const {
1415  if (frame_renderer_)
1416  return frame_renderer_;
1417  else if (parent_)
1418  return parent_->get_effective_frame_renderer();
1419  else
1420  return get_manager().get_root().observer_from_this();
1421 }
1422 
1424  alive_checker checker(*this);
1425 
1426  if (is_auto_focus_) {
1427  set_focus(true);
1428  if (!checker.is_alive())
1429  return;
1430  }
1431 
1433 
1434  for (auto& obj : get_regions()) {
1435  if (obj.is_shown()) {
1436  obj.notify_visible();
1437  if (!checker.is_alive())
1438  return;
1439  }
1440  }
1441 
1442  for (auto& child : get_children()) {
1443  if (child.is_shown()) {
1444  child.notify_visible();
1445  if (!checker.is_alive())
1446  return;
1447  }
1448  }
1449 
1450  fire_script("OnShow");
1451  if (!checker.is_alive())
1452  return;
1453 
1455 }
1456 
1458  alive_checker checker(*this);
1459 
1460  set_focus(false);
1461  if (!checker.is_alive())
1462  return;
1463 
1465 
1466  for (auto& child : get_children()) {
1467  if (child.is_shown()) {
1468  child.notify_invisible();
1469  if (!checker.is_alive())
1470  return;
1471  }
1472  }
1473 
1474  fire_script("OnHide");
1475  if (!checker.is_alive())
1476  return;
1477 
1479 }
1480 
1482  if (is_virtual_)
1483  return;
1484 
1485  get_effective_frame_renderer()->notify_strata_needs_redraw(get_effective_strata());
1486 }
1487 
1490 
1491  if (title_region_)
1492  title_region_->notify_scaling_factor_updated();
1493 
1494  for (auto& child : get_children())
1495  child.notify_scaling_factor_updated();
1496 
1497  for (auto& obj : get_regions())
1498  obj.notify_scaling_factor_updated();
1499 }
1500 
1501 void frame::notify_mouse_in_frame(bool mouse_in_frame, const vector2f& /*position*/) {
1502  if (mouse_in_frame == is_mouse_in_frame_)
1503  return;
1504 
1505  is_mouse_in_frame_ = mouse_in_frame;
1506 
1507  alive_checker checker(*this);
1508  if (is_mouse_in_frame_) {
1509  fire_script("OnEnter");
1510  if (!checker.is_alive())
1511  return;
1512  } else {
1513  fire_script("OnLeave");
1514  if (!checker.is_alive())
1515  return;
1516  }
1517 }
1518 
1520  const bool old_valid = is_valid_;
1521  const auto old_border_list = borders_;
1522 
1524 
1525  check_position_();
1526 
1527  if (borders_ != old_border_list || is_valid_ != old_valid) {
1528  if (borders_.width() != old_border_list.width() ||
1529  borders_.height() != old_border_list.height()) {
1530  alive_checker checker(*this);
1531  fire_script("OnSizeChanged");
1532  if (!checker.is_alive())
1533  return;
1534  }
1535 
1537 
1538  if (backdrop_)
1539  backdrop_->notify_borders_updated();
1540  }
1541 }
1542 
1543 void frame::update(float delta) {
1544  base::update(delta);
1545 
1546  if (update_rate_ > 0) {
1547  time_since_last_update_ += delta;
1548 
1549  if (time_since_last_update_ < 1.0f / update_rate_) {
1550  return;
1551  }
1552 
1553  delta = time_since_last_update_;
1554  }
1555 
1556  time_since_last_update_ = 0.0f;
1557 
1558  update_(delta);
1559 }
1560 
1561 void frame::update_(float delta) {
1562  alive_checker checker(*this);
1563 
1564  if (is_visible()) {
1565  fire_script("OnUpdate", {delta});
1566  if (!checker.is_alive())
1567  return;
1568  }
1569 
1570  if (title_region_)
1571  title_region_->update(delta);
1572 
1573  // Update regions
1574  for (auto& obj : get_regions()) {
1575  obj.update(delta);
1576  }
1577 
1578  // Remove deleted regions
1579  {
1580  auto iter_remove = std::remove_if(
1581  region_list_.begin(), region_list_.end(), [](auto& obj) { return obj == nullptr; });
1582 
1583  region_list_.erase(iter_remove, region_list_.end());
1584  }
1585 
1586  // Update children
1587  for (auto& child : get_children()) {
1588  child.update(delta);
1589  if (!checker.is_alive())
1590  return;
1591  }
1592 
1593  // Remove deleted children
1594  {
1595  auto iter_remove = std::remove_if(
1596  child_list_.begin(), child_list_.end(), [](auto& obj) { return obj == nullptr; });
1597 
1598  child_list_.erase(iter_remove, child_list_.end());
1599  }
1600 
1601  // Remove empty handlers
1602  {
1603  auto iter_list = signal_list_.begin();
1604  while (iter_list != signal_list_.end()) {
1605  if (iter_list->second.empty()) {
1606  iter_list = signal_list_.erase(iter_list);
1607  } else {
1608  ++iter_list;
1609  }
1610  }
1611  }
1612 }
1613 
1614 const std::vector<std::string>& frame::get_type_list_() const {
1615  return get_type_list_impl_<frame>();
1616 }
1617 
1618 } // namespace lxgui::gui
Loads and owns addons.
const addon * get_current_addon()
Returns the addon that is being parsed.
void set_current_addon(const addon *a)
Sets the current addon.
Utility class for safe checking of region validity.
bool is_alive() const
Check if the wrapped region is still alive.
Draws borders and background of a frame.
Stores a variable number of arguments for an event.
const utils::variant & get(std::size_t index) const
Returns a parameter of this event.
void add(T &&value)
Adds a parameter to this event.
Generates events and keep tracks of registered callbacks.
void fire_event(const std::string &event_name, event_data data=event_data{})
Emmit a new event.
void register_event(const std::string &event_name, event_handler_function callback)
Enables reaction to an event.
void unregister_event(const std::string &event_name)
Disables reaction to an event.
Exception to be thrown by GUI code.
utils::owner_ptr< layered_region > create_layered_region(registry &reg, const region_core_attributes &attr)
Creates a new layered_region.
Definition: gui_factory.cpp:57
utils::owner_ptr< region > create_region(registry &reg, const region_core_attributes &attr)
Creates a new region.
Definition: gui_factory.cpp:14
utils::owner_ptr< frame > create_frame(registry &reg, const frame_core_attributes &attr)
Creates a new frame.
Definition: gui_factory.cpp:35
utils::owner_ptr< frame > remove_root_frame(const utils::observer_ptr< frame > &obj)
Remove a frame from the list of frames owned by this frame_container.
Abstract class for layering and rendering frames.
A region that can contain other regions and react to events.
Definition: gui_frame.hpp:255
bool check_script_(const std::string &script_name) const
Definition: gui_frame.cpp:946
bool is_auto_focus_enabled() const
Checks if automatic focus is enabled.
Definition: gui_frame.cpp:1314
utils::observer_ptr< frame_renderer > effective_frame_renderer_
Definition: gui_frame.hpp:1820
utils::observer_ptr< frame > add_child(utils::owner_ptr< frame > child)
Adds a frame to this frame's children.
Definition: gui_frame.cpp:678
void remove_script(const std::string &script_name)
Removes a script from this frame.
Definition: gui_frame.cpp:1080
utils::view::adaptor< region_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > region_list_view
Definition: gui_frame.hpp:287
script_list_view get_script(const std::string &script_name) const
Return a view into this frame's handler scripts, registered for the given event.
Definition: gui_frame.cpp:1072
void set_height(float abs_height) override
Changes this region's absolute height (in pixels).
Definition: gui_frame.cpp:355
void stop_moving()
ends moving this frame.
Definition: gui_frame.cpp:1367
~frame() override
Destructor.
Definition: gui_frame.cpp:43
void notify_invisible() override
Notifies this region that it is no longer visible on screen.
Definition: gui_frame.cpp:1457
bounds2f abs_hit_rect_inset_list_
Definition: gui_frame.hpp:1833
utils::observer_ptr< const frame_renderer > compute_top_level_frame_renderer_() const
Definition: gui_frame.cpp:1414
vector2f get_min_dimensions() const
Returns this frame's min dimensions.
Definition: gui_frame.cpp:789
bool is_mouse_wheel_enabled() const
Checks if this frame can receive mouse wheel input.
Definition: gui_frame.cpp:847
void add_level_(int amount)
Definition: gui_frame.cpp:1342
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Definition: gui_frame.cpp:84
utils::view::adaptor< const child_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > const_child_list_view
Definition: gui_frame.hpp:274
void render() const override
Renders this region on the current render target.
Definition: gui_frame.cpp:62
float get_scale() const
Returns this frame's scale.
Definition: gui_frame.cpp:811
strata effective_strata_
Definition: gui_frame.hpp:1816
bool is_movable() const
Checks if this frame can be moved.
Definition: gui_frame.cpp:863
utils::owner_ptr< region > release_from_parent() override
Removes this region from its parent and return an owning pointer.
Definition: gui_frame.cpp:1264
void enable_auto_focus(bool enable)
Enables automatic focus when this frame is shown or raised.
Definition: gui_frame.cpp:1310
std::optional< strata > strata_
Definition: gui_frame.hpp:1815
void stop_sizing()
ends resizing this frame.
Definition: gui_frame.cpp:1380
child_list_view get_children()
Returns the child list.
Definition: gui_frame.cpp:712
const std::vector< std::string > & get_type_list_() const override
Definition: gui_frame.cpp:1614
bool is_resizable() const
Checks if this frame can be resized.
Definition: gui_frame.cpp:867
bool is_user_placed() const
Checks if this frame has been moved by the user.
Definition: gui_frame.cpp:875
static std::string get_adjusted_script_name(const std::string &script_name)
Returns the "adjusted" script name: "OnEvent" becomes "on_event".
Definition: gui_frame.cpp:879
void set_backdrop(std::unique_ptr< backdrop > bdrop)
Sets this frames' backdrop.
Definition: gui_frame.cpp:1188
bool is_in_region(const vector2f &position) const override
Checks if the provided coordinates are inside this frame.
Definition: gui_frame.cpp:819
void copy_from(const region &obj) override
Copies a region's parameters into this frame (inheritance).
Definition: gui_frame.cpp:195
void set_resizable(bool is_resizable)
Sets if this frame can be resized by the user.
Definition: gui_frame.cpp:1272
std::set< std::string > reg_drag_list_
Definition: gui_frame.hpp:1811
void unregister_event(const std::string &event_name)
Tells the frame not to react to a certain event.
Definition: gui_frame.cpp:1139
void disable_drag()
Tells this frame to not react to mouse drag from any mouse button.
Definition: gui_frame.cpp:1170
std::array< layer_container, num_layers > layer_list_
Definition: gui_frame.hpp:1806
strata compute_effective_strata_() const
Definition: gui_frame.cpp:739
vector2f get_max_dimensions() const
Returns this frame's max dimensions.
Definition: gui_frame.cpp:785
void set_clamped_to_screen(bool is_clamped_to_screen)
Sets if this frame is clamped to screen.
Definition: gui_frame.cpp:1174
void set_max_width(float max_width)
Sets this frame's maximum width.
Definition: gui_frame.cpp:1233
void set_level(int level_id)
Sets this frame's level.
Definition: gui_frame.cpp:1201
void create_title_region()
Creates a new title region for this frame.
Definition: gui_frame.cpp:275
void set_max_height(float max_height)
Sets this frame's maximum height.
Definition: gui_frame.cpp:1222
backdrop & get_or_create_backdrop()
Returns this frame's backdrop, creating it if needed.
Definition: gui_frame.cpp:770
void notify_layers_need_update()
Tells this frame to rebuild its layer list.
Definition: gui_frame.cpp:489
utils::observer_ptr< frame_renderer > frame_renderer_
Definition: gui_frame.hpp:1819
event_receiver event_receiver_
Definition: gui_frame.hpp:1809
void set_scale(float scale)
Sets this frame's scale.
Definition: gui_frame.cpp:1276
void start_sizing(const point &p)
Starts resizing this frame with the mouse.
Definition: gui_frame.cpp:1372
std::size_t get_layered_region_count() const
Returns the number of layered regions of this frame.
Definition: gui_frame.cpp:802
void enable_key_capture(const std::string &key_name)
Marks this frame as able to receive keyboard input from a specific key.
Definition: gui_frame.cpp:458
std::size_t get_layered_region_count_upper_bound() const
Returns the approximate number of regions of this frame.
Definition: gui_frame.cpp:807
void update(float delta) final
Updates this region's logic.
Definition: gui_frame.cpp:1543
region_list region_list_
Definition: gui_frame.hpp:1802
bool has_script(const std::string &script_name) const
Checks if this frame has a script defined.
Definition: gui_frame.cpp:584
void notify_visible() override
Notifies this region that it is now visible on screen.
Definition: gui_frame.cpp:1423
void set_abs_hit_rect_insets(const bounds2f &insets)
Sets this frame's absolute hit rect insets.
Definition: gui_frame.cpp:1193
utils::observer_ptr< const frame > get_child(const std::string &name) const
Returns one of this frame's children.
Definition: gui_frame.cpp:305
void set_min_height(float min_height)
Sets this frame's minimum height.
Definition: gui_frame.cpp:1244
bool is_clamped_to_screen() const
Checks if this frame is clamped to screen.
Definition: gui_frame.cpp:815
bool is_drag_enabled(const std::string &button_name) const
Checks if this frame is registered for drag events with the provided mouse button.
Definition: gui_frame.cpp:851
void set_frame_renderer(utils::observer_ptr< frame_renderer > rdr)
Flags this object as rendered by another object.
Definition: gui_frame.cpp:1398
bool is_key_capture_enabled(const std::string &key_name) const
Checks if this frame can receive keyboard input from a specific key.
Definition: gui_frame.cpp:859
void set_dimensions(const vector2f &dimensions) override
Changes this region's absolute dimensions (in pixels).
Definition: gui_frame.cpp:345
void disable_key_capture()
Marks this frame as unable to receive keyboard input from any key.
Definition: gui_frame.cpp:474
void set_top_level(bool is_top_level)
Sets if this frame is at top level.
Definition: gui_frame.cpp:1282
void on_event_(std::string_view event_name, const event_data &event)
Definition: gui_frame.cpp:1096
void register_event(const std::string &event_name)
Tells this frame to react to a certain event.
Definition: gui_frame.cpp:1131
const backdrop * get_backdrop() const
Returns this frame's backdrop.
Definition: gui_frame.cpp:762
const bounds2f & get_abs_hit_rect_insets() const
Returns this frame's absolute hit rect insets.
Definition: gui_frame.cpp:777
std::set< std::string > reg_key_list_
Definition: gui_frame.hpp:1812
virtual void fire_script(const std::string &script_name, const event_data &data=event_data{})
Calls a script.
Definition: gui_frame.cpp:1105
void set_mouse_move_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse move input.
Definition: gui_frame.cpp:446
utils::connection add_script(const std::string &script_name, std::string content, script_info info=script_info{})
Adds an additional handler script to this frame (executed after existing scripts).
Definition: gui_frame.hpp:1125
std::optional< strata > get_strata() const
Returns this frame's strata.
Definition: gui_frame.cpp:731
void set_width(float abs_width) override
Changes this region's absolute width (in pixels).
Definition: gui_frame.cpp:351
bool is_mouse_click_enabled_
Definition: gui_frame.hpp:1824
const bounds2f & get_rel_hit_rect_insets() const
Returns this frame's relative hit rect insets.
Definition: gui_frame.cpp:781
void set_mouse_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse input (click & move).
Definition: gui_frame.cpp:437
std::unordered_map< std::string, script_signal > signal_list_
Definition: gui_frame.hpp:1808
utils::observer_ptr< layered_region > create_layered_region(layer layer_id, region_core_attributes attr)
Creates a new region as child of this frame.
Definition: gui_frame.cpp:652
bool is_top_level() const
Checks if this frame is at top level.
Definition: gui_frame.cpp:871
virtual void update_(float delta)
Definition: gui_frame.cpp:1561
utils::view::adaptor< const region_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > const_region_list_view
Definition: gui_frame.hpp:291
bounds2f rel_hit_rect_inset_list_
Definition: gui_frame.hpp:1834
int get_level() const
Returns this frame's level.
Definition: gui_frame.cpp:727
void notify_renderer_need_redraw() override
Notifies the renderer of this region that it needs to be redrawn.
Definition: gui_frame.cpp:1481
void set_min_width(float min_width)
Sets this frame's minimum width.
Definition: gui_frame.cpp:1252
void set_keyboard_enabled(bool is_keyboard_enabled)
Sets if this frame can receive any keyboard input.
Definition: gui_frame.cpp:454
virtual bool can_use_script(const std::string &script_name) const
Returns 'true' if this frame can use a script.
Definition: gui_frame.cpp:183
utils::observer_ptr< const frame > get_top_level_parent() const
Returns this frame's top-level parent.
Definition: gui_frame.cpp:750
void set_min_dimensions(const vector2f &min)
Sets this frame's minimum size.
Definition: gui_frame.cpp:1217
void set_parent_(utils::observer_ptr< frame > parent) override
Changes this region's parent.
Definition: gui_frame.cpp:513
bool is_mouse_move_enabled() const
Checks if this frame can receive mouse movement input.
Definition: gui_frame.cpp:843
bool is_mouse_click_enabled() const
Checks if this frame can receive mouse click input.
Definition: gui_frame.cpp:839
void notify_loaded() override
Notifies this region that it has been fully loaded.
Definition: gui_frame.cpp:478
bool has_focus() const
Check if this frame currently has focus.
Definition: gui_frame.cpp:1326
void check_position_()
Definition: gui_frame.cpp:359
float get_effective_scale() const
Calculates effective scale.
Definition: gui_frame.cpp:720
void set_update_rate(float rate)
Sets a maximum update rate (in updates per seconds).
Definition: gui_frame.cpp:1146
strata get_effective_strata() const
Returns this frame's effective strata.
Definition: gui_frame.cpp:735
utils::owner_ptr< layered_region > remove_region(const utils::observer_ptr< layered_region > &reg)
Removes a layered_region from this frame's children.
Definition: gui_frame.cpp:617
void set_rel_hit_rect_insets(const bounds2f &insets)
Sets this frame's relative hit rect insets.
Definition: gui_frame.cpp:1197
std::size_t get_child_count() const
Returns the number of children of this frame.
Definition: gui_frame.cpp:793
std::list< utils::owner_ptr< layered_region > > region_list
Type of the region list (internal).
Definition: gui_frame.hpp:285
child_list child_list_
Definition: gui_frame.hpp:1801
bool is_mouse_wheel_enabled_
Definition: gui_frame.hpp:1826
void update_borders_() override
Definition: gui_frame.cpp:1519
bool is_keyboard_enabled() const
Checks if this frame can receive any keyboard input.
Definition: gui_frame.cpp:855
void set_user_placed(bool is_user_placed)
Sets if this frame has been moved by the user.
Definition: gui_frame.cpp:1355
void set_strata(std::optional< strata > strata_id)
Sets this frame's strata.
Definition: gui_frame.cpp:1178
void set_mouse_click_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse click input.
Definition: gui_frame.cpp:442
virtual void notify_focus(bool focus)
Notifies this frame that it has received or lost focus.
Definition: gui_frame.cpp:1330
utils::owner_ptr< frame > remove_child(const utils::observer_ptr< frame > &child)
Removes a frame from this frame's children.
Definition: gui_frame.cpp:690
void set_focus(bool focus)
Asks for focus for this frame.
Definition: gui_frame.cpp:1318
utils::observer_ptr< const frame_renderer > get_effective_frame_renderer() const final
Returns the renderer of this object or its parents, nullptr if none.
Definition: gui_frame.cpp:1410
std::unique_ptr< backdrop > backdrop_
Definition: gui_frame.hpp:1822
utils::observer_ptr< const layered_region > get_region(const std::string &name) const
Returns one of this frame's region.
Definition: gui_frame.cpp:329
utils::owner_ptr< region > title_region_
Definition: gui_frame.hpp:1848
float get_update_rate() const
Gets the maximum update rate (in upates per seconds).
Definition: gui_frame.cpp:1150
void set_mouse_wheel_enabled(bool is_mouse_wheel_enabled)
Sets if this frame can receive mouse wheel input.
Definition: gui_frame.cpp:450
void enable_draw_layer(layer layer_id)
Enables a layer.
Definition: gui_frame.cpp:429
void set_movable(bool is_movable)
Sets if this frame can be moved by the user.
Definition: gui_frame.cpp:1260
virtual void notify_mouse_in_frame(bool mouse_in_frame, const vector2f &mouse_pos)
Tells this frame it is being hovered by the mouse.
Definition: gui_frame.cpp:1501
utils::observer_ptr< frame > create_child(frame_core_attributes attr)
Creates a new frame as child of this frame.
Definition: gui_frame.cpp:666
region_list_view get_regions()
Returns the region list.
Definition: gui_frame.cpp:321
float time_since_last_update_
Definition: gui_frame.hpp:1844
virtual utils::observer_ptr< const frame > find_topmost_frame(const std::function< bool(const frame &)> &predicate) const
Find the topmost frame matching the provided predicate.
Definition: gui_frame.cpp:832
void set_max_dimensions(const vector2f &max)
Sets this frame's maximum size.
Definition: gui_frame.cpp:1212
std::size_t get_child_count_upper_bound() const
Returns the approximate number of children of this frame.
Definition: gui_frame.cpp:798
void notify_strata_changed_(strata new_strata_id)
Definition: gui_frame.cpp:567
utils::view::adaptor< child_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > child_list_view
Definition: gui_frame.hpp:270
utils::observer_ptr< layered_region > add_region(utils::owner_ptr< layered_region > reg)
Adds a layered_region to this frame's children.
Definition: gui_frame.cpp:592
void notify_scaling_factor_updated() override
Tells this region that the global interface scaling factor has changed.
Definition: gui_frame.cpp:1488
void start_moving()
Starts moving this frame with the mouse.
Definition: gui_frame.cpp:1359
utils::connection define_script_(const std::string &script_name, const std::string &content, bool append, const script_info &info)
Definition: gui_frame.cpp:957
void notify_frame_renderer_changed_(const utils::observer_ptr< frame_renderer > &new_renderer)
Definition: gui_frame.cpp:1385
void disable_draw_layer(layer layer_id)
Disables a layer.
Definition: gui_frame.cpp:421
void enable_drag(const std::string &button_name)
Tells this frame to react to mouse drag.
Definition: gui_frame.cpp:1154
void raise()
Increases this frame's level so it's the highest of the strata.
Definition: gui_frame.cpp:1286
A region that can be rendered in a layer.
Manages the user interface.
Definition: gui_manager.hpp:44
const event_emitter & get_event_emitter() const
Returns the gui event emitter.
factory & get_factory()
Returns the UI object factory, which is used to create new objects.
addon_registry * get_addon_registry()
Returns the addon registry, which keeps track of loaded addons.
root & get_root()
Returns the UI root object, which contains root frames.
The base class of all elements in the GUI.
Definition: gui_region.hpp:161
virtual void set_width(float abs_width)
Changes this region's absolute width (in pixels).
Definition: gui_region.cpp:227
virtual void set_parent_(utils::observer_ptr< frame > parent)
Changes this region's parent.
Definition: gui_region.cpp:312
const std::string & get_region_type() const
Returns the type of this region.
Definition: gui_region.cpp:148
void initialize_(T &self, const region_core_attributes &attr)
Set up function to call in all derived class constructors.
bool is_virtual() const
Checks if this region is virtual.
Definition: gui_region.cpp:553
registry & get_registry()
Returns the UI object registry, which keeps track of all objects in the UI.
Definition: gui_region.cpp:850
bool is_visible() const
Checks if this region can be seen on the screen.
Definition: gui_region.cpp:207
utils::observer_ptr< frame > parent_
Definition: gui_region.hpp:807
manager & get_manager()
Returns this region's manager.
Definition: gui_region.hpp:693
virtual void notify_loaded()
Notifies this region that it has been fully loaded.
Definition: gui_region.cpp:794
virtual void notify_visible()
Notifies this region that it is now visible on screen.
Definition: gui_region.cpp:808
virtual void render() const
Renders this region on the current render target.
Definition: gui_region.cpp:765
virtual void set_height(float abs_height)
Changes this region's absolute height (in pixels).
Definition: gui_region.cpp:239
const std::string & get_name() const
Returns this region's name.
Definition: gui_region.cpp:140
bool is_shown() const
Checks if this region is shown.
Definition: gui_region.cpp:203
virtual void notify_invisible()
Notifies this region that it is no longer visible on screen.
Definition: gui_region.cpp:813
std::string name_
Definition: gui_region.hpp:804
const std::string & get_raw_name() const
Returns this region's raw name.
Definition: gui_region.cpp:144
virtual void set_dimensions(const vector2f &dimensions)
Changes this region's absolute dimensions (in pixels).
Definition: gui_region.cpp:215
virtual void update(float delta)
Updates this region's logic.
Definition: gui_region.cpp:763
utils::observer_ptr< const frame > get_parent() const
Returns this region's parent.
Definition: gui_region.hpp:229
bool is_loaded() const
Checks if this region has been fully loaded.
Definition: gui_region.cpp:798
virtual void notify_borders_need_update()
Tells this region that its borders need updating.
Definition: gui_region.cpp:744
virtual void copy_from(const region &obj)
Copies a region's parameters into this region (inheritance).
Definition: gui_region.cpp:128
const addon * get_addon() const
Returns this frame's addon.
Definition: gui_region.cpp:843
sol::state & get_lua_()
Definition: gui_region.cpp:767
virtual std::string serialize(const std::string &tab) const
Prints all relevant information about this region in a string.
Definition: gui_region.cpp:91
virtual void notify_scaling_factor_updated()
Tells this region that the global interface scaling factor has changed.
Definition: gui_region.cpp:759
virtual void update_borders_()
Definition: gui_region.cpp:669
Root of the UI object hierarchy.
Definition: gui_root.hpp:39
void start_moving(utils::observer_ptr< region > obj, anchor *a=nullptr, constraint constraint=constraint::none, std::function< void()> apply_constraint_func=nullptr)
Start manually moving a region with the mouse.
Definition: gui_root.cpp:303
void stop_sizing()
Stops sizing for the current object.
Definition: gui_root.cpp:406
void request_focus(utils::observer_ptr< frame > receiver)
Sets whether keyboard input should be focused.
Definition: gui_root.cpp:447
void notify_hovered_frame_dirty()
Notifies the root that it should update the hovered frame.
Definition: gui_root.cpp:299
void start_sizing(utils::observer_ptr< region > obj, point p)
Starts manually resizing a region with the mouse.
Definition: gui_root.cpp:340
void stop_moving()
Stops movement for the current object.
Definition: gui_root.cpp:331
void release_focus(const frame &receiver)
Give up focus of keyboard input.
Definition: gui_root.cpp:461
Object representing the connection between a slot and a signal.
Allow iterating over a container without access to the container itself.
Definition: utils_view.hpp:60
layer
ID of a layer for rendering inside a frame.
vector2< float > vector2f
Holds 2D coordinates (as floats)
script_signal::function_type script_function
C++ function type for UI script handlers.
Definition: gui_frame.hpp:51
utils::observer_ptr< ObjectType > observer_from(ObjectType *self)
Obtain an observer pointer from a raw pointer (typically 'this')
Definition: gui_region.hpp:946
std::ostream out
const std::string warning
Definition: gui_out.cpp:6
std::string hijack_sol_error_line(std::string original_message, const std::string &file, std::size_t line_nbr)
Definition: gui_frame.cpp:893
const std::string error
Definition: gui_out.cpp:7
std::string hijack_sol_error_message(std::string_view original_message, const std::string &file, std::size_t line_nbr)
Definition: gui_frame.cpp:933
std::string_view get_mouse_button_codename(mouse_button button_id)
Returns a standard English name for the provided mouse button.
Definition: input_keys.cpp:7
std::string_view get_key_codename(key key_id)
Returns a standard English name for the provided key.
Definition: input_keys.cpp:105
std::variant< empty, bool, std::int64_t, std::int32_t, std::int16_t, std::int8_t, std::uint64_t, std::uint32_t, std::uint16_t, std::uint8_t, double, float, std::string > variant
Type-erased value for passing arguments to events.
auto find_if(C &v, T &&f)
Definition: utils_std.hpp:19
oup::observable_sealed_ptr< T > owner_ptr
T height() const noexcept
Definition: gui_bounds2.hpp:56
T width() const noexcept
Definition: gui_bounds2.hpp:52
Struct holding all the core information about a frame necessary for its creation.
Contains gui::layered_region.
Definition: gui_frame.hpp:33
Struct holding all the core information about a region necessary for its creation.
std::vector< utils::observer_ptr< const region > > inheritance
Holds file/line information for a script.
Definition: gui_frame.hpp:39