Implement ui element hinting support
This commit is contained in:
parent
c03689c5b4
commit
b6ddd70989
4 changed files with 86 additions and 1 deletions
|
|
@ -4,6 +4,7 @@
|
|||
#include <psemek/ui/font.hpp>
|
||||
#include <psemek/gfx/render_target.hpp>
|
||||
#include <psemek/util/pimpl.hpp>
|
||||
#include <psemek/util/function.hpp>
|
||||
|
||||
namespace psemek::ui
|
||||
{
|
||||
|
|
@ -18,6 +19,9 @@ namespace psemek::ui
|
|||
std::shared_ptr<element> set_root(std::shared_ptr<element> r);
|
||||
element * root();
|
||||
|
||||
void set_hint_delay(float seconds);
|
||||
void on_hint(util::function<void(element *)> callback);
|
||||
|
||||
void reshape(geom::box<float, 2> const & shape);
|
||||
|
||||
bool event(mouse_move const & e);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <psemek/util/function.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace psemek::ui
|
||||
{
|
||||
|
|
@ -59,6 +61,9 @@ namespace psemek::ui
|
|||
virtual void style_updated();
|
||||
virtual void own_style_updated();
|
||||
|
||||
virtual std::optional<std::string> const & hint() const { return hint_; }
|
||||
virtual std::optional<std::string> set_hint(std::optional<std::string> hint);
|
||||
|
||||
virtual void update(float /* dt */) {}
|
||||
|
||||
virtual void draw(painter & p) const = 0;
|
||||
|
|
@ -88,6 +93,8 @@ namespace psemek::ui
|
|||
|
||||
mutable std::vector<util::function<void()>> delayed_callbacks_;
|
||||
|
||||
std::optional<std::string> hint_;
|
||||
|
||||
void post_delayed_callbacks() const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -57,12 +57,21 @@ namespace psemek::ui
|
|||
painter_impl painter;
|
||||
std::shared_ptr<root_proxy> root;
|
||||
std::optional<geom::point<int, 2>> mouse;
|
||||
float hint_delay = 0.f;
|
||||
float hint_timer = 0.f;
|
||||
util::function<void(element *)> on_hint;
|
||||
element * hinted_element = nullptr;
|
||||
bool hint_called = false;
|
||||
|
||||
impl(async::event_loop * loop);
|
||||
|
||||
template <typename E>
|
||||
bool event(E const & e);
|
||||
|
||||
std::pair<bool, element *> event(mouse_move const & e);
|
||||
|
||||
element * hint() const;
|
||||
|
||||
void update(float dt);
|
||||
};
|
||||
|
||||
|
|
@ -96,6 +105,33 @@ namespace psemek::ui
|
|||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto visitor = util::recursive([dt](auto && self, element * elem) -> void {
|
||||
|
|
@ -140,6 +176,16 @@ namespace psemek::ui
|
|||
return impl().root->root.get();
|
||||
}
|
||||
|
||||
void controller::set_hint_delay(float seconds)
|
||||
{
|
||||
impl().hint_delay = seconds;
|
||||
}
|
||||
|
||||
void controller::on_hint(util::function<void(element *)> callback)
|
||||
{
|
||||
impl().on_hint = std::move(callback);
|
||||
}
|
||||
|
||||
void controller::reshape(geom::box<float, 2> const & shape)
|
||||
{
|
||||
impl().root->reshape(shape);
|
||||
|
|
@ -148,7 +194,18 @@ namespace psemek::ui
|
|||
bool controller::event(mouse_move const & e)
|
||||
{
|
||||
impl().mouse = e.position;
|
||||
return impl().event(e);
|
||||
auto [ result, new_hinted_element ] = impl().event(e);
|
||||
|
||||
if (new_hinted_element != impl().hinted_element)
|
||||
{
|
||||
if (impl().hint_called && impl().on_hint)
|
||||
impl().on_hint(nullptr);
|
||||
impl().hint_timer = 0.f;
|
||||
impl().hint_called = false;
|
||||
}
|
||||
impl().hinted_element = new_hinted_element;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool controller::event(mouse_click const & e)
|
||||
|
|
@ -169,6 +226,17 @@ namespace psemek::ui
|
|||
void controller::update(float dt)
|
||||
{
|
||||
impl().update(dt);
|
||||
|
||||
if (impl().hinted_element && !impl().hint_called)
|
||||
{
|
||||
impl().hint_timer += dt;
|
||||
if (impl().hint_timer >= impl().hint_delay)
|
||||
{
|
||||
if (impl().on_hint)
|
||||
impl().on_hint(impl().hinted_element);
|
||||
impl().hint_called = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void controller::render(gfx::render_target const & rt)
|
||||
|
|
|
|||
|
|
@ -137,6 +137,12 @@ namespace psemek::ui
|
|||
return merged_own_style_;
|
||||
}
|
||||
|
||||
std::optional<std::string> element::set_hint(std::optional<std::string> hint)
|
||||
{
|
||||
std::swap(hint_, hint);
|
||||
return hint;
|
||||
}
|
||||
|
||||
element::~element()
|
||||
{
|
||||
set_style(nullptr);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue