Support focused ui elements
This commit is contained in:
parent
c06a465f51
commit
bd6d0f9f93
2 changed files with 62 additions and 37 deletions
|
|
@ -38,6 +38,8 @@ namespace psemek::ui
|
||||||
virtual bool on_event(key_press const &) { return false; }
|
virtual bool on_event(key_press const &) { return false; }
|
||||||
virtual bool on_event(text_input const &) { return false; }
|
virtual bool on_event(text_input const &) { return false; }
|
||||||
|
|
||||||
|
virtual bool focused() const { return false; }
|
||||||
|
|
||||||
virtual struct shape const & shape() const = 0;
|
virtual struct shape const & shape() const = 0;
|
||||||
virtual void reshape(geom::box<float, 2> const & bbox) = 0;
|
virtual void reshape(geom::box<float, 2> const & bbox) = 0;
|
||||||
virtual void reshape();
|
virtual void reshape();
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ namespace psemek::ui
|
||||||
async::event_loop * loop;
|
async::event_loop * loop;
|
||||||
painter_impl painter;
|
painter_impl painter;
|
||||||
std::shared_ptr<root_proxy> root;
|
std::shared_ptr<root_proxy> root;
|
||||||
|
element * focused = nullptr;
|
||||||
std::optional<geom::point<int, 2>> mouse;
|
std::optional<geom::point<int, 2>> mouse;
|
||||||
float hint_delay = 0.f;
|
float hint_delay = 0.f;
|
||||||
float hint_timer = 0.f;
|
float hint_timer = 0.f;
|
||||||
|
|
@ -66,9 +67,9 @@ namespace psemek::ui
|
||||||
impl(async::event_loop * loop);
|
impl(async::event_loop * loop);
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
bool event(E const & e);
|
element * event(E const & e);
|
||||||
|
|
||||||
std::pair<bool, element *> event(mouse_move const & e);
|
element * hinted();
|
||||||
|
|
||||||
element * hint() const;
|
element * hint() const;
|
||||||
|
|
||||||
|
|
@ -87,49 +88,69 @@ namespace psemek::ui
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
bool controller::impl::event(E const & e)
|
element * controller::impl::event(E const & e)
|
||||||
{
|
{
|
||||||
auto visitor = util::recursive([&](auto && self, element * elem) -> bool {
|
auto visitor = util::recursive([&](auto && self, element * elem) -> element * {
|
||||||
if (elem->hidden()) return false;
|
if (elem->hidden()) return nullptr;
|
||||||
|
|
||||||
auto cs = elem->children();
|
auto cs = elem->children();
|
||||||
for (auto it = cs.rbegin(); it != cs.rend(); ++it)
|
for (auto it = cs.rbegin(); it != cs.rend(); ++it)
|
||||||
if (*it && self(*it)) return true;
|
if (*it)
|
||||||
|
if (auto p = self(*it))
|
||||||
|
return p;
|
||||||
|
|
||||||
if (elem->enabled() && elem->on_event(e)) return true;
|
if (elem->enabled() && elem->on_event(e)) return elem;
|
||||||
return false;
|
return nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
if (focused->focused())
|
||||||
|
{
|
||||||
|
auto result = focused->on_event(e);
|
||||||
|
if (!focused->focused())
|
||||||
|
focused = nullptr;
|
||||||
|
if (result)
|
||||||
|
return focused;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
focused = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root)
|
||||||
|
if (auto result = visitor(root.get()))
|
||||||
|
{
|
||||||
|
if (!focused && result->focused())
|
||||||
|
focused = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
element * controller::impl::hinted()
|
||||||
|
{
|
||||||
|
if (!mouse)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto m = geom::cast<float>(*mouse);
|
||||||
|
auto visitor = util::recursive([&](auto && self, element * elem) -> element * {
|
||||||
|
if (elem->hidden()) return nullptr;
|
||||||
|
|
||||||
|
auto cs = elem->children();
|
||||||
|
for (auto it = cs.rbegin(); it != cs.rend(); ++it)
|
||||||
|
if (*it)
|
||||||
|
if (auto p = self(*it))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
if (elem->enabled() && elem->hint() && elem->shape().contains(m))
|
||||||
|
return elem;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (root)
|
if (root)
|
||||||
return visitor(root.get());
|
return visitor(root.get());
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, element *> controller::impl::event(mouse_move const & e)
|
|
||||||
{
|
|
||||||
element * hinted = nullptr;
|
|
||||||
auto m = geom::cast<float>(e.position);
|
|
||||||
auto visitor = util::recursive([&](auto && self, element * elem) -> bool {
|
|
||||||
if (elem->hidden()) return false;
|
|
||||||
|
|
||||||
auto cs = elem->children();
|
|
||||||
for (auto it = cs.rbegin(); it != cs.rend(); ++it)
|
|
||||||
if (*it && self(*it)) return true;
|
|
||||||
|
|
||||||
if (elem->enabled())
|
|
||||||
{
|
|
||||||
if (elem->hint() && elem->shape().contains(m) && !hinted)
|
|
||||||
hinted = elem;
|
|
||||||
if (elem->on_event(e))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
if (root)
|
|
||||||
result = visitor(root.get());
|
|
||||||
return {result, hinted};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void controller::impl::update(float dt)
|
void controller::impl::update(float dt)
|
||||||
|
|
@ -194,7 +215,9 @@ namespace psemek::ui
|
||||||
bool controller::event(mouse_move const & e)
|
bool controller::event(mouse_move const & e)
|
||||||
{
|
{
|
||||||
impl().mouse = e.position;
|
impl().mouse = e.position;
|
||||||
auto [ result, new_hinted_element ] = impl().event(e);
|
auto result = impl().event(e);
|
||||||
|
|
||||||
|
auto new_hinted_element = impl().hinted();
|
||||||
|
|
||||||
if (new_hinted_element != impl().hinted_element)
|
if (new_hinted_element != impl().hinted_element)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue