+116
-3
@@ -11,6 +11,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
#include <luma.hpp>
|
||||
|
||||
@@ -22,6 +23,11 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto touch_hold_duration = std::chrono::milliseconds{700};
|
||||
constexpr auto touch_double_tap_duration = std::chrono::milliseconds{220};
|
||||
|
||||
using touch_handler = std::function<std::bool_t(luma::touch_event const&)>;
|
||||
|
||||
auto bind_port(vamp_zero::config const& config) -> std::uint16_t {
|
||||
auto const& bind = config.control.endpoint.bind;
|
||||
auto colon = bind.rfind(':');
|
||||
@@ -404,7 +410,7 @@ auto draw_score(luma::draw_context& context, luma::rect bounds, vamp_zero::app_s
|
||||
|
||||
class vamp_root_control final : public luma::control {
|
||||
public:
|
||||
explicit vamp_root_control(vamp_zero::ui_state state) : state_{std::move(state)} {}
|
||||
explicit vamp_root_control(vamp_zero::ui_state state, touch_handler on_touch) : state_{std::move(state)}, on_touch_{std::move(on_touch)} {}
|
||||
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size override {
|
||||
return luma::clamp({.width = 1024.0F, .height = 600.0F}, limits);
|
||||
}
|
||||
@@ -438,13 +444,117 @@ public:
|
||||
draw_main_menu(context, content, state_.app);
|
||||
}
|
||||
}
|
||||
auto handle_touch(luma::touch_event const& event) -> std::bool_t override {
|
||||
return on_touch_ ? on_touch_(event) : false;
|
||||
}
|
||||
private:
|
||||
vamp_zero::ui_state state_{};
|
||||
touch_handler on_touch_{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
vamp_zero::zero_ui::zero_ui(boost::asio::any_io_executor executor, luma::application_config config) : executor_{std::move(executor)}, application_{std::move(config)} {}
|
||||
vamp_zero::zero_ui::zero_ui(boost::asio::any_io_executor executor, luma::application_config config, vamp_zero::zero_ui::command_handler command_handler)
|
||||
: executor_{std::move(executor)}, tap_timer_{executor_}, application_{std::move(config)}, command_handler_{std::move(command_handler)} {}
|
||||
|
||||
auto vamp_zero::zero_ui::send_touch_command(vamp_protocol::page_command command) -> void {
|
||||
if (!command_handler_) {
|
||||
return;
|
||||
}
|
||||
boost::asio::post(executor_, [handler = command_handler_, command] {
|
||||
handler(command);
|
||||
});
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::cancel_pending_tap_locked() -> void {
|
||||
pending_tap_ = false;
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::arm_pending_tap() -> void {
|
||||
tap_timer_.expires_after(touch_double_tap_duration);
|
||||
tap_timer_.async_wait([this](boost::system::error_code const& error) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
auto send_next = false;
|
||||
{
|
||||
auto lock = std::scoped_lock{touch_mutex_};
|
||||
send_next = pending_tap_;
|
||||
pending_tap_ = false;
|
||||
}
|
||||
if (send_next) {
|
||||
send_touch_command(vamp_protocol::page_command::NEXT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::handle_touch(luma::touch_event const& event) -> std::bool_t {
|
||||
if (!command_handler_ || event.points.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto consumed = false;
|
||||
auto commands = std::vector<vamp_protocol::page_command>{};
|
||||
auto arm_tap = false;
|
||||
{
|
||||
auto lock = std::scoped_lock{touch_mutex_};
|
||||
for (auto const& point : event.points) {
|
||||
if (point.phase == luma::touch_phase::DOWN && !active_touch_id_) {
|
||||
active_touch_id_ = point.id;
|
||||
touch_down_time_ = event.time;
|
||||
hold_sent_ = false;
|
||||
tap_timer_.cancel();
|
||||
consumed = true;
|
||||
continue;
|
||||
}
|
||||
if (!active_touch_id_ || point.id != *active_touch_id_) {
|
||||
continue;
|
||||
}
|
||||
consumed = true;
|
||||
if (point.phase == luma::touch_phase::CANCEL) {
|
||||
active_touch_id_.reset();
|
||||
hold_sent_ = false;
|
||||
cancel_pending_tap_locked();
|
||||
tap_timer_.cancel();
|
||||
continue;
|
||||
}
|
||||
if (point.phase == luma::touch_phase::MOVE) {
|
||||
if (!hold_sent_ && event.time - touch_down_time_ >= touch_hold_duration) {
|
||||
hold_sent_ = true;
|
||||
cancel_pending_tap_locked();
|
||||
tap_timer_.cancel();
|
||||
commands.push_back(vamp_protocol::page_command::SELECT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (point.phase == luma::touch_phase::UP) {
|
||||
active_touch_id_.reset();
|
||||
if (!hold_sent_ && event.time - touch_down_time_ >= touch_hold_duration) {
|
||||
commands.push_back(vamp_protocol::page_command::SELECT);
|
||||
} else if (!hold_sent_) {
|
||||
if (pending_tap_ && event.time - last_tap_time_ <= touch_double_tap_duration) {
|
||||
cancel_pending_tap_locked();
|
||||
tap_timer_.cancel();
|
||||
commands.push_back(vamp_protocol::page_command::PREVIOUS);
|
||||
} else {
|
||||
pending_tap_ = true;
|
||||
last_tap_time_ = event.time;
|
||||
arm_tap = true;
|
||||
}
|
||||
}
|
||||
hold_sent_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto command : commands) {
|
||||
send_touch_command(command);
|
||||
}
|
||||
if (arm_tap) {
|
||||
arm_pending_tap();
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::run() -> std::expected<void, modulus::error> {
|
||||
auto state = snapshot();
|
||||
@@ -459,6 +569,7 @@ auto vamp_zero::zero_ui::run() -> std::expected<void, modulus::error> {
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::stop() -> void {
|
||||
tap_timer_.cancel();
|
||||
application_.request_stop();
|
||||
}
|
||||
|
||||
@@ -482,7 +593,9 @@ auto vamp_zero::zero_ui::snapshot() const -> vamp_zero::ui_state {
|
||||
}
|
||||
|
||||
auto vamp_zero::zero_ui::make_root(vamp_zero::ui_state const& state) -> std::expected<std::unique_ptr<luma::control>, modulus::error> {
|
||||
return std::make_unique<vamp_root_control>(state);
|
||||
return std::make_unique<vamp_root_control>(state, [this](luma::touch_event const& event) {
|
||||
return handle_touch(event);
|
||||
});
|
||||
}
|
||||
|
||||
auto vamp_zero::make_ui_state(vamp_zero::config const& config, vamp_zero::app_state app) -> vamp_zero::ui_state {
|
||||
|
||||
Reference in New Issue
Block a user