lxgui
Loading...
Searching...
No Matches
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
23namespace lxgui::gui {
24
25frame::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
62void frame::render() const {
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
84std::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
183bool 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
195void 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
215 this->set_keyboard_enabled(frame_obj->is_keyboard_enabled());
216
217 this->set_movable(frame_obj->is_movable());
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
305utils::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
324
328
329utils::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
345void 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
351void frame::set_width(float abs_width) {
352 base::set_width(std::min(std::max(abs_width, min_width_), max_width_));
353}
354
355void 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
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
437void 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
442void frame::set_mouse_click_enabled(bool is_mouse_enabled) {
443 is_mouse_click_enabled_ = is_mouse_enabled;
444}
445
446void frame::set_mouse_move_enabled(bool is_mouse_enabled) {
447 is_mouse_move_enabled_ = is_mouse_enabled;
448}
449
453
454void frame::set_keyboard_enabled(bool is_keyboard_enabled) {
456}
457
458void 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
466void 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
513void 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())
536 else
538 } else {
539 if (is_shown())
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
584bool 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
592utils::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
617frame::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
651utils::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
666utils::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
678utils::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
690utils::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
715
719
721 if (parent_)
722 return scale_ * parent_->get_effective_scale();
723 else
724 return scale_;
725}
726
727int frame::get_level() const {
728 return level_;
729}
730
731std::optional<strata> frame::get_strata() const {
732 return strata_;
733}
734
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
750utils::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
780
784
788
792
793std::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
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
811float frame::get_scale() const {
812 return scale_;
813}
814
818
819bool 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
831utils::observer_ptr<const frame>
832frame::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
842
846
850
851bool frame::is_drag_enabled(const std::string& button_name) const {
852 return reg_drag_list_.find(button_name) != reg_drag_list_.end();
853}
854
857}
858
859bool 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
863bool frame::is_movable() const {
864 return is_movable_;
865}
866
868 return is_resizable_;
869}
870
872 return is_top_level_;
873}
874
876 return is_user_placed_;
877}
878
879std::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
892std::string
893hijack_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
946bool 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
1072script_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
1080void 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
1096void 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
1105void 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
1129}
1130
1131void 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
1139void frame::unregister_event(const std::string& event_name) {
1140 if (is_virtual_)
1141 return;
1142
1144}
1145
1146void frame::set_update_rate(float rate) {
1147 update_rate_ = rate;
1148}
1149
1151 return update_rate_;
1152}
1153
1154void 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
1162void 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
1174void frame::set_clamped_to_screen(bool is_clamped_to_screen) {
1176}
1177
1178void 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
1188void 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
1201void 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
1222void 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
1233void 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
1244void 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
1252void 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
1260void 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
1272void frame::set_resizable(bool is_resizable) {
1274}
1275
1276void frame::set_scale(float scale) {
1277 scale_ = scale;
1278 if (scale_ != scale)
1280}
1281
1282void 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
1310void frame::enable_auto_focus(bool enable) {
1311 is_auto_focus_ = enable;
1312}
1313
1315 return is_auto_focus_;
1316}
1317
1318void frame::set_focus(bool focus) {
1319 auto& root = get_manager().get_root();
1320 if (focus)
1322 else
1323 root.release_focus(*this);
1324}
1325
1326bool frame::has_focus() const {
1327 return is_focused_;
1328}
1329
1330void 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
1342void 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
1355void 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
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
1398void 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
1410utils::observer_ptr<const frame_renderer> frame::get_effective_frame_renderer() const {
1412}
1413
1414utils::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
1501void 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
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
1543void frame::update(float delta) {
1544 base::update(delta);
1545
1546 if (update_rate_ > 0) {
1547 time_since_last_update_ += delta;
1548
1550 return;
1551 }
1552
1554 }
1555
1557
1558 update_(delta);
1559}
1560
1561void 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
1614const std::vector<std::string>& frame::get_type_list_() const {
1615 return get_type_list_impl_<frame>();
1616}
1617
1618} // namespace lxgui::gui
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.
utils::owner_ptr< region > create_region(registry &reg, const region_core_attributes &attr)
Creates a new region.
utils::owner_ptr< frame > create_frame(registry &reg, const frame_core_attributes &attr)
Creates a new frame.
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.
bool check_script_(const std::string &script_name) const
bool is_auto_focus_enabled() const
Checks if automatic focus is enabled.
utils::observer_ptr< frame_renderer > effective_frame_renderer_
utils::observer_ptr< frame > add_child(utils::owner_ptr< frame > child)
Adds a frame to this frame's children.
void remove_script(const std::string &script_name)
Removes a script from this frame.
utils::view::adaptor< region_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > region_list_view
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.
void set_height(float abs_height) override
Changes this region's absolute height (in pixels).
void stop_moving()
ends moving this frame.
~frame() override
Destructor.
Definition gui_frame.cpp:43
void notify_invisible() override
Notifies this region that it is no longer visible on screen.
bounds2f abs_hit_rect_inset_list_
utils::observer_ptr< const frame_renderer > compute_top_level_frame_renderer_() const
vector2f get_min_dimensions() const
Returns this frame's min dimensions.
bool is_mouse_wheel_enabled() const
Checks if this frame can receive mouse wheel input.
void add_level_(int amount)
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
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.
bool is_movable() const
Checks if this frame can be moved.
utils::owner_ptr< region > release_from_parent() override
Removes this region from its parent and return an owning pointer.
void enable_auto_focus(bool enable)
Enables automatic focus when this frame is shown or raised.
std::optional< strata > strata_
void stop_sizing()
ends resizing this frame.
child_list_view get_children()
Returns the child list.
const std::vector< std::string > & get_type_list_() const override
bool is_resizable() const
Checks if this frame can be resized.
bool is_user_placed() const
Checks if this frame has been moved by the user.
static std::string get_adjusted_script_name(const std::string &script_name)
Returns the "adjusted" script name: "OnEvent" becomes "on_event".
void set_backdrop(std::unique_ptr< backdrop > bdrop)
Sets this frames' backdrop.
bool is_in_region(const vector2f &position) const override
Checks if the provided coordinates are inside this frame.
void copy_from(const region &obj) override
Copies a region's parameters into this frame (inheritance).
void set_resizable(bool is_resizable)
Sets if this frame can be resized by the user.
std::set< std::string > reg_drag_list_
void unregister_event(const std::string &event_name)
Tells the frame not to react to a certain event.
void disable_drag()
Tells this frame to not react to mouse drag from any mouse button.
std::array< layer_container, num_layers > layer_list_
strata compute_effective_strata_() const
vector2f get_max_dimensions() const
Returns this frame's max dimensions.
void set_clamped_to_screen(bool is_clamped_to_screen)
Sets if this frame is clamped to screen.
void set_max_width(float max_width)
Sets this frame's maximum width.
void set_level(int level_id)
Sets this frame's level.
void create_title_region()
Creates a new title region for this frame.
void set_max_height(float max_height)
Sets this frame's maximum height.
backdrop & get_or_create_backdrop()
Returns this frame's backdrop, creating it if needed.
void notify_layers_need_update()
Tells this frame to rebuild its layer list.
utils::observer_ptr< frame_renderer > frame_renderer_
event_receiver event_receiver_
void set_scale(float scale)
Sets this frame's scale.
void start_sizing(const point &p)
Starts resizing this frame with the mouse.
std::size_t get_layered_region_count() const
Returns the number of layered regions of this frame.
void enable_key_capture(const std::string &key_name)
Marks this frame as able to receive keyboard input from a specific key.
std::size_t get_layered_region_count_upper_bound() const
Returns the approximate number of regions of this frame.
void update(float delta) final
Updates this region's logic.
region_list region_list_
bool has_script(const std::string &script_name) const
Checks if this frame has a script defined.
void notify_visible() override
Notifies this region that it is now visible on screen.
void set_abs_hit_rect_insets(const bounds2f &insets)
Sets this frame's absolute hit rect insets.
utils::observer_ptr< const frame > get_child(const std::string &name) const
Returns one of this frame's children.
void set_min_height(float min_height)
Sets this frame's minimum height.
bool is_clamped_to_screen() const
Checks if this frame is clamped to screen.
bool is_drag_enabled(const std::string &button_name) const
Checks if this frame is registered for drag events with the provided mouse button.
void set_frame_renderer(utils::observer_ptr< frame_renderer > rdr)
Flags this object as rendered by another object.
bool is_key_capture_enabled(const std::string &key_name) const
Checks if this frame can receive keyboard input from a specific key.
void set_dimensions(const vector2f &dimensions) override
Changes this region's absolute dimensions (in pixels).
void disable_key_capture()
Marks this frame as unable to receive keyboard input from any key.
void set_top_level(bool is_top_level)
Sets if this frame is at top level.
void on_event_(std::string_view event_name, const event_data &event)
void register_event(const std::string &event_name)
Tells this frame to react to a certain event.
const backdrop * get_backdrop() const
Returns this frame's backdrop.
const bounds2f & get_abs_hit_rect_insets() const
Returns this frame's absolute hit rect insets.
std::set< std::string > reg_key_list_
virtual void fire_script(const std::string &script_name, const event_data &data=event_data{})
Calls a script.
void set_mouse_move_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse move input.
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).
std::optional< strata > get_strata() const
Returns this frame's strata.
void set_width(float abs_width) override
Changes this region's absolute width (in pixels).
const bounds2f & get_rel_hit_rect_insets() const
Returns this frame's relative hit rect insets.
void set_mouse_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse input (click & move).
std::unordered_map< std::string, script_signal > signal_list_
utils::observer_ptr< layered_region > create_layered_region(layer layer_id, region_core_attributes attr)
Creates a new region as child of this frame.
bool is_top_level() const
Checks if this frame is at top level.
virtual void update_(float delta)
utils::view::adaptor< const region_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > const_region_list_view
bounds2f rel_hit_rect_inset_list_
int get_level() const
Returns this frame's level.
void notify_renderer_need_redraw() override
Notifies the renderer of this region that it needs to be redrawn.
void set_min_width(float min_width)
Sets this frame's minimum width.
void set_keyboard_enabled(bool is_keyboard_enabled)
Sets if this frame can receive any keyboard input.
virtual bool can_use_script(const std::string &script_name) const
Returns 'true' if this frame can use a script.
utils::observer_ptr< const frame > get_top_level_parent() const
Returns this frame's top-level parent.
void set_min_dimensions(const vector2f &min)
Sets this frame's minimum size.
void set_parent_(utils::observer_ptr< frame > parent) override
Changes this region's parent.
bool is_mouse_move_enabled() const
Checks if this frame can receive mouse movement input.
bool is_mouse_click_enabled() const
Checks if this frame can receive mouse click input.
void notify_loaded() override
Notifies this region that it has been fully loaded.
bool has_focus() const
Check if this frame currently has focus.
float get_effective_scale() const
Calculates effective scale.
void set_update_rate(float rate)
Sets a maximum update rate (in updates per seconds).
strata get_effective_strata() const
Returns this frame's effective strata.
utils::owner_ptr< layered_region > remove_region(const utils::observer_ptr< layered_region > &reg)
Removes a layered_region from this frame's children.
void set_rel_hit_rect_insets(const bounds2f &insets)
Sets this frame's relative hit rect insets.
std::size_t get_child_count() const
Returns the number of children of this frame.
std::list< utils::owner_ptr< layered_region > > region_list
Type of the region list (internal).
child_list child_list_
void update_borders_() override
bool is_keyboard_enabled() const
Checks if this frame can receive any keyboard input.
void set_user_placed(bool is_user_placed)
Sets if this frame has been moved by the user.
void set_strata(std::optional< strata > strata_id)
Sets this frame's strata.
void set_mouse_click_enabled(bool is_mouse_enabled)
Sets if this frame can receive mouse click input.
virtual void notify_focus(bool focus)
Notifies this frame that it has received or lost focus.
utils::owner_ptr< frame > remove_child(const utils::observer_ptr< frame > &child)
Removes a frame from this frame's children.
void set_focus(bool focus)
Asks for focus for this frame.
utils::observer_ptr< const frame_renderer > get_effective_frame_renderer() const final
Returns the renderer of this object or its parents, nullptr if none.
std::unique_ptr< backdrop > backdrop_
utils::observer_ptr< const layered_region > get_region(const std::string &name) const
Returns one of this frame's region.
utils::owner_ptr< region > title_region_
float get_update_rate() const
Gets the maximum update rate (in upates per seconds).
void set_mouse_wheel_enabled(bool is_mouse_wheel_enabled)
Sets if this frame can receive mouse wheel input.
void enable_draw_layer(layer layer_id)
Enables a layer.
void set_movable(bool is_movable)
Sets if this frame can be moved by the user.
virtual void notify_mouse_in_frame(bool mouse_in_frame, const vector2f &mouse_pos)
Tells this frame it is being hovered by the mouse.
utils::observer_ptr< frame > create_child(frame_core_attributes attr)
Creates a new frame as child of this frame.
region_list_view get_regions()
Returns the region list.
float time_since_last_update_
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.
void set_max_dimensions(const vector2f &max)
Sets this frame's maximum size.
std::size_t get_child_count_upper_bound() const
Returns the approximate number of children of this frame.
void notify_strata_changed_(strata new_strata_id)
utils::view::adaptor< child_list, utils::view::smart_ptr_dereferencer, utils::view::non_null_filter > child_list_view
utils::observer_ptr< layered_region > add_region(utils::owner_ptr< layered_region > reg)
Adds a layered_region to this frame's children.
void notify_scaling_factor_updated() override
Tells this region that the global interface scaling factor has changed.
void start_moving()
Starts moving this frame with the mouse.
utils::connection define_script_(const std::string &script_name, const std::string &content, bool append, const script_info &info)
void notify_frame_renderer_changed_(const utils::observer_ptr< frame_renderer > &new_renderer)
void disable_draw_layer(layer layer_id)
Disables a layer.
void enable_drag(const std::string &button_name)
Tells this frame to react to mouse drag.
void raise()
Increases this frame's level so it's the highest of the strata.
A region that can be rendered in a layer.
Manages the user interface.
root & get_root()
Returns the UI root object, which contains root frames.
addon_registry * get_addon_registry()
Returns the addon registry, which keeps track of loaded addons.
factory & get_factory()
Returns the UI object factory, which is used to create new objects.
sol::state & get_lua()
Returns the GUI Lua state (sol wrapper).
const event_emitter & get_event_emitter() const
Returns the gui event emitter.
The base class of all elements in the GUI.
virtual void set_width(float abs_width)
Changes this region's absolute width (in pixels).
virtual void set_parent_(utils::observer_ptr< frame > parent)
Changes this region's parent.
const std::string & get_region_type() const
Returns the type of this region.
manager & get_manager()
Returns this region's manager.
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.
utils::observer_ptr< const frame > get_parent() const
Returns this region's parent.
registry & get_registry()
Returns the UI object registry, which keeps track of all objects in the UI.
bool is_visible() const
Checks if this region can be seen on the screen.
utils::observer_ptr< frame > parent_
virtual void notify_loaded()
Notifies this region that it has been fully loaded.
virtual void notify_visible()
Notifies this region that it is now visible on screen.
virtual void render() const
Renders this region on the current render target.
virtual void set_height(float abs_height)
Changes this region's absolute height (in pixels).
const std::string & get_name() const
Returns this region's name.
bool is_shown() const
Checks if this region is shown.
virtual void notify_invisible()
Notifies this region that it is no longer visible on screen.
const std::string & get_raw_name() const
Returns this region's raw name.
virtual void set_dimensions(const vector2f &dimensions)
Changes this region's absolute dimensions (in pixels).
virtual void update(float delta)
Updates this region's logic.
bool is_loaded() const
Checks if this region has been fully loaded.
virtual void notify_borders_need_update()
Tells this region that its borders need updating.
virtual void copy_from(const region &obj)
Copies a region's parameters into this region (inheritance).
const addon * get_addon() const
Returns this frame's addon.
sol::state & get_lua_()
virtual std::string serialize(const std::string &tab) const
Prints all relevant information about this region in a string.
virtual void notify_scaling_factor_updated()
Tells this region that the global interface scaling factor has changed.
virtual void update_borders_()
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.
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
std::ostream out
utils::observer_ptr< ObjectType > observer_from(ObjectType *self)
Obtain an observer pointer from a raw pointer (typically 'this')
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)
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)
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.
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
T width() const noexcept
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