diff --git a/libs/ui/source/controller.cpp b/libs/ui/source/controller.cpp index abddd714..f60e4f82 100644 --- a/libs/ui/source/controller.cpp +++ b/libs/ui/source/controller.cpp @@ -56,12 +56,12 @@ namespace psemek::ui async::event_loop * loop; painter_impl painter; std::shared_ptr root; - element * focused = nullptr; + std::weak_ptr focused; std::optional> mouse; float hint_delay = 0.f; float hint_timer = 0.f; util::function on_hint; - element * hinted_element = nullptr; + std::optional> hinted_element = std::nullopt; std::optional hint_called = std::nullopt; impl(async::event_loop * loop); @@ -69,9 +69,7 @@ namespace psemek::ui template element * event(E const & e); - element * hinted(); - - element * hint() const; + element * hinted() const; void update(float dt); }; @@ -103,31 +101,31 @@ namespace psemek::ui return nullptr; }); - if (focused) + if (auto p = focused.lock()) { - if (focused->focused()) + if (p->focused()) { - auto result = focused->on_event(e); - if (!focused->focused()) - focused = nullptr; + auto result = p->on_event(e); + if (!p->focused()) + focused.reset(); if (result) - return focused; + return p.get(); } else - focused = nullptr; + focused.reset(); } if (root) if (auto result = visitor(root.get())) { - if (!focused && result->focused()) - focused = result; + if (!focused.lock() && result->focused()) + focused = result->weak_from_this(); } return nullptr; } - element * controller::impl::hinted() + element * controller::impl::hinted() const { if (!mouse) return nullptr; @@ -217,16 +215,37 @@ namespace psemek::ui impl().mouse = e.position; auto result = impl().event(e); + if (impl().hinted_element) + { + auto p = impl().hinted_element->lock(); + if (!p) + { + if (impl().hint_called && impl().on_hint) + impl().on_hint(nullptr); + impl().hinted_element = std::nullopt; + impl().hint_timer = 0.f; + impl().hint_called = std::nullopt; + } + } + auto new_hinted_element = impl().hinted(); - if (new_hinted_element != impl().hinted_element) + std::shared_ptr old_hinted_element; + if (impl().hinted_element) + old_hinted_element = impl().hinted_element->lock(); + + if (new_hinted_element != old_hinted_element.get()) { if (impl().hint_called && impl().on_hint) impl().on_hint(nullptr); impl().hint_timer = 0.f; impl().hint_called = std::nullopt; + + if (new_hinted_element) + impl().hinted_element = new_hinted_element->weak_from_this(); + else + impl().hinted_element = std::nullopt; } - impl().hinted_element = new_hinted_element; return result; } @@ -255,14 +274,30 @@ namespace psemek::ui { impl().update(dt); - if (impl().hinted_element && (!impl().hint_called || *impl().hint_called != *impl().hinted_element->hint())) + std::shared_ptr p; + + if (impl().hinted_element) + { + p = impl().hinted_element->lock(); + + if (!p) + { + if (impl().hint_called && impl().on_hint) + impl().on_hint(nullptr); + impl().hinted_element = std::nullopt; + impl().hint_timer = 0.f; + impl().hint_called = std::nullopt; + } + } + + if (p && (!impl().hint_called || *impl().hint_called != *p->hint())) { impl().hint_timer += dt; if (impl().hint_timer >= impl().hint_delay) { if (impl().on_hint) - impl().on_hint(impl().hinted_element); - impl().hint_called = *impl().hinted_element->hint(); + impl().on_hint(p.get()); + impl().hint_called = *p->hint(); } } }