Fix selectors lifetime issues

This commit is contained in:
Nikita Lisitsa 2022-12-19 21:17:22 +03:00
parent 6fe5d72415
commit 79eceaa616

View file

@ -4,6 +4,7 @@
#include <psemek/ui/event_interceptor.hpp>
#include <psemek/util/recursive.hpp>
#include <psemek/util/to_shared.hpp>
#include <psemek/geom/contains.hpp>
@ -246,6 +247,12 @@ namespace psemek::ui
: event_interceptor
{
bool transparent() const override { return false; }
~opaque_event_interceptor()
{
int fuck = 42;
(void)fuck;
}
};
}
@ -256,11 +263,13 @@ namespace psemek::ui
if (!screen)
return false;
auto event_interceptor= std::make_shared<opaque_event_interceptor>();
auto event_interceptor = std::make_shared<opaque_event_interceptor>();
auto positioner = std::make_shared<struct positioner>();
positioner->set_child(selector);
event_interceptor->set_child(positioner);
auto loop = screen->loop();
auto close = [selector_root = event_interceptor.get(), selector = selector.get(), on_canceled]{
if (on_canceled)
on_canceled();
@ -270,43 +279,53 @@ namespace psemek::ui
p->remove_child(selector_root);
};
auto patch_callback = [&](struct selector * target){
std::vector<std::pair<ui::selector *, ui::selector::callback_type>> old_callbacks;
util::recursive([&](auto && self, struct selector * target) -> void{
old_callbacks.push_back({target, target->on_selected()});
for (std::size_t i = 0; i < target->size(); ++i)
if (auto s = target->submenu(i))
self(s.get());
})(selector.get());
auto revert_callbacks = [old_callbacks = util::to_shared(std::move(old_callbacks))]{
for (auto & p : *old_callbacks)
p.first->on_selected(std::move(p.second));
};
auto cancel = [close, revert_callbacks]{
close();
revert_callbacks();
};
auto patch_callback_recursive = util::recursive([&](auto && self, struct selector * target) -> void {
target->on_selected([target, close, cb = target->on_selected()](std::size_t index){
close();
if (cb)
cb(index);
target->on_selected(cb);
});
};
auto patch_callback_recursive = util::recursive([&](auto && self, struct selector * target) -> void {
patch_callback(target);
for (std::size_t i = 0; i < target->size(); ++i)
if (auto s = target->submenu(i))
self(s.get());
});
patch_callback_recursive(selector.get());
selector->on_selected([close, cb = selector->on_selected()](std::size_t index){
close();
if (cb)
cb(index);
});
event_interceptor->on_mouse_click([close](ui::mouse_click const & e) -> bool {
event_interceptor->on_mouse_click([loop, cancel](ui::mouse_click const & e) -> bool {
if (e.down && (e.button == ui::mouse_button::right || e.button == ui::mouse_button::left))
{
close();
loop->post(cancel);
return true;
}
return false;
});
event_interceptor->on_key_press([close](key_press const & e) -> bool {
event_interceptor->on_key_press([loop, cancel](key_press const & e) -> bool {
if (e.down && e.key == SDLK_ESCAPE)
{
close();
loop->post(cancel);
return true;
}