mirror of
https://github.com/enduro2d/enduro2d.git
synced 2026-09-28 07:50:02 +07:00
impl simple drag events
This commit is contained in:
@@ -38,8 +38,6 @@ namespace e2d
|
||||
|
||||
class hover_over final {};
|
||||
class hover_out final {};
|
||||
class hover_enter final {};
|
||||
class hover_leave final {};
|
||||
public:
|
||||
touchable() = default;
|
||||
|
||||
@@ -108,14 +106,6 @@ namespace e2d
|
||||
class factory_loader<touchable::hover_out> final
|
||||
: public empty_factory_loader<touchable::hover_out> {};
|
||||
|
||||
template <>
|
||||
class factory_loader<touchable::hover_enter> final
|
||||
: public empty_factory_loader<touchable::hover_enter> {};
|
||||
|
||||
template <>
|
||||
class factory_loader<touchable::hover_leave> final
|
||||
: public empty_factory_loader<touchable::hover_leave> {};
|
||||
|
||||
template <>
|
||||
class factory_loader<events<touchable_events::event>> final
|
||||
: public empty_factory_loader<events<touchable_events::event>> {};
|
||||
@@ -223,14 +213,12 @@ namespace e2d::touchable_events
|
||||
public:
|
||||
ENUM_HPP_CLASS_DECL(types, u8,
|
||||
(over)
|
||||
(out)
|
||||
(enter)
|
||||
(leave))
|
||||
(out))
|
||||
public:
|
||||
mouse_hover_evt(
|
||||
gobject target,
|
||||
types type)
|
||||
: base_evt(target, type == types::over || type == types::out)
|
||||
: base_evt(target, true)
|
||||
, type_(type) {}
|
||||
|
||||
[[nodiscard]] types type() const noexcept { return type_; }
|
||||
|
||||
@@ -30,12 +30,6 @@ local touchable = {
|
||||
---@type boolean
|
||||
hover_out = false,
|
||||
|
||||
---@type boolean
|
||||
hover_enter = false,
|
||||
|
||||
---@type boolean
|
||||
hover_leave = false,
|
||||
|
||||
---@type boolean
|
||||
bubbling = true,
|
||||
|
||||
|
||||
@@ -13,6 +13,13 @@ end
|
||||
---@param type string
|
||||
---@param event touchable_event
|
||||
function M:on_event(go, type, event)
|
||||
if type == "touchable.mouse_hover_evt" then
|
||||
the_debug:trace(string.format("event: %q\n-->type: %q\n-->target: %q",
|
||||
type,
|
||||
event.type,
|
||||
event.target.named and event.target.named.name or "[unnamed]"))
|
||||
end
|
||||
|
||||
if type == "touchable.mouse_drag_evt" then
|
||||
the_debug:trace(string.format("event: %q\n-->type: %q\n-->target: %q\n-->local_point: %s\n-->world_point: %s",
|
||||
type,
|
||||
|
||||
@@ -154,32 +154,6 @@ namespace e2d::bindings::high
|
||||
}
|
||||
),
|
||||
|
||||
"hover_enter", sol::property(
|
||||
[](const gcomponent<touchable>& c) -> bool {
|
||||
return c.component<touchable::hover_enter>().exists();
|
||||
},
|
||||
[](gcomponent<touchable>& c, bool yesno){
|
||||
if ( yesno ) {
|
||||
c.component<touchable::hover_enter>().ensure();
|
||||
} else {
|
||||
c.component<touchable::hover_enter>().remove();
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
"hover_leave", sol::property(
|
||||
[](const gcomponent<touchable>& c) -> bool {
|
||||
return c.component<touchable::hover_leave>().exists();
|
||||
},
|
||||
[](gcomponent<touchable>& c, bool yesno){
|
||||
if ( yesno ) {
|
||||
c.component<touchable::hover_leave>().ensure();
|
||||
} else {
|
||||
c.component<touchable::hover_leave>().remove();
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
"bubbling", sol::property(
|
||||
[](const gcomponent<touchable>& c) -> bool {
|
||||
return c->bubbling();
|
||||
|
||||
@@ -166,34 +166,6 @@ namespace e2d
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
//
|
||||
// hover_enter/hover_leave
|
||||
//
|
||||
|
||||
if ( bool hover_enter = c.component<touchable::hover_enter>().exists();
|
||||
ImGui::Checkbox("hover_enter", &hover_enter) )
|
||||
{
|
||||
if ( hover_enter ) {
|
||||
c.component<touchable::hover_enter>().ensure();
|
||||
} else {
|
||||
c.component<touchable::hover_enter>().remove();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if ( bool hover_leave = c.component<touchable::hover_leave>().exists();
|
||||
ImGui::Checkbox("hover_leave", &hover_leave) )
|
||||
{
|
||||
if ( hover_leave ) {
|
||||
c.component<touchable::hover_leave>().ensure();
|
||||
} else {
|
||||
c.component<touchable::hover_leave>().remove();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
//
|
||||
// bubbling/capturing
|
||||
//
|
||||
|
||||
@@ -241,8 +241,6 @@ namespace e2d
|
||||
.register_component<touchable::released>("touchable.released")
|
||||
.register_component<touchable::hover_over>("touchable.hover_over")
|
||||
.register_component<touchable::hover_out>("touchable.hover_out")
|
||||
.register_component<touchable::hover_enter>("touchable.hover_enter")
|
||||
.register_component<touchable::hover_leave>("touchable.hover_leave")
|
||||
.register_component<events<touchable_events::event>>("touchable.events")
|
||||
.register_component<widget>("widget")
|
||||
.register_component<widget::dirty>("widget.dirty")
|
||||
@@ -287,8 +285,6 @@ namespace e2d
|
||||
//.register_component<touchable::released>("touchable.released")
|
||||
//.register_component<touchable::hover_over>("touchable.hover_over")
|
||||
//.register_component<touchable::hover_out>("touchable.hover_out")
|
||||
//.register_component<touchable::hover_enter>("touchable.hover_enter")
|
||||
//.register_component<touchable::hover_leave>("touchable.hover_leave")
|
||||
//.register_component<events<touchable_events::event>>("touchable.events")
|
||||
.register_component<widget>("widget")
|
||||
//.register_component<widget::dirty>("widget.dirty")
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace e2d
|
||||
internal_state(input& i, window& w)
|
||||
: input_(i)
|
||||
, window_(w)
|
||||
, collector_(window_.register_event_listener<collector>(i)) {}
|
||||
, collector_(window_.register_event_listener<collector>(i, w)) {}
|
||||
|
||||
~internal_state() noexcept {
|
||||
window_.unregister_event_listener(collector_);
|
||||
|
||||
@@ -25,8 +25,16 @@ namespace e2d::touch_system_impl
|
||||
namespace e2d::touch_system_impl
|
||||
{
|
||||
struct touchable_under_mouse final {
|
||||
gobject input_camera;
|
||||
v2f local_point{v2f::zero()};
|
||||
v2f world_point{v2f::zero()};
|
||||
touchable_under_mouse(
|
||||
gobject input_camera,
|
||||
const v2f& local_point,
|
||||
const v2f& world_point)
|
||||
: input_camera(input_camera)
|
||||
, local_point(local_point)
|
||||
, world_point(world_point) {}
|
||||
};
|
||||
|
||||
struct world_space_collider_base {
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
namespace e2d::touch_system_impl
|
||||
{
|
||||
collector::collector(input& i)
|
||||
: input_(i) {}
|
||||
collector::collector(input& i,window& w)
|
||||
: input_(i)
|
||||
, window_(w) {}
|
||||
|
||||
void collector::clear() noexcept {
|
||||
events_.clear();
|
||||
@@ -42,12 +43,14 @@ namespace e2d::touch_system_impl
|
||||
void collector::on_move_cursor(const v2f& pos) noexcept {
|
||||
E2D_UNUSED(pos);
|
||||
events_.push_back(mouse_move_event(
|
||||
window_,
|
||||
input_.mouse().cursor_pos()));
|
||||
}
|
||||
|
||||
void collector::on_mouse_scroll(const v2f& delta) noexcept {
|
||||
E2D_UNUSED(delta);
|
||||
events_.push_back(mouse_scroll_event(
|
||||
window_,
|
||||
input_.mouse().cursor_pos(),
|
||||
input_.mouse().scroll_delta()));
|
||||
}
|
||||
@@ -62,6 +65,7 @@ namespace e2d::touch_system_impl
|
||||
}
|
||||
|
||||
events_.push_back(mouse_button_event(
|
||||
window_,
|
||||
input_.mouse().cursor_pos(),
|
||||
button,
|
||||
action));
|
||||
|
||||
@@ -13,24 +13,29 @@ namespace e2d::touch_system_impl
|
||||
class collector final : public window::event_listener {
|
||||
public:
|
||||
struct mouse_event {
|
||||
window& event_window;
|
||||
v2f screen_point{v2f::zero()};
|
||||
mouse_event(
|
||||
window& w,
|
||||
const v2f& screen_point)
|
||||
: screen_point(screen_point) {}
|
||||
: event_window(w)
|
||||
, screen_point(screen_point) {}
|
||||
};
|
||||
|
||||
struct mouse_move_event : mouse_event {
|
||||
mouse_move_event(
|
||||
window& w,
|
||||
const v2f& screen_point)
|
||||
: mouse_event(screen_point) {}
|
||||
: mouse_event(w, screen_point) {}
|
||||
};
|
||||
|
||||
struct mouse_scroll_event : mouse_event {
|
||||
v2f delta{v2f::zero()};
|
||||
mouse_scroll_event(
|
||||
window& w,
|
||||
const v2f& screen_point,
|
||||
const v2f& delta)
|
||||
: mouse_event(screen_point)
|
||||
: mouse_event(w, screen_point)
|
||||
, delta(delta) {}
|
||||
};
|
||||
|
||||
@@ -38,10 +43,11 @@ namespace e2d::touch_system_impl
|
||||
mouse_button button{mouse_button::unknown};
|
||||
mouse_button_action action{mouse_button_action::unknown};
|
||||
mouse_button_event(
|
||||
window& w,
|
||||
const v2f& screen_point,
|
||||
mouse_button button,
|
||||
mouse_button_action action)
|
||||
: mouse_event(screen_point)
|
||||
: mouse_event(w, screen_point)
|
||||
, button(button)
|
||||
, action(action) {}
|
||||
};
|
||||
@@ -52,7 +58,7 @@ namespace e2d::touch_system_impl
|
||||
mouse_button_event>;
|
||||
using events = vector<event>;
|
||||
public:
|
||||
collector(input& i);
|
||||
collector(input& i, window& w);
|
||||
|
||||
void clear() noexcept;
|
||||
|
||||
@@ -75,6 +81,7 @@ namespace e2d::touch_system_impl
|
||||
mouse_button_action action) noexcept final;
|
||||
private:
|
||||
input& input_;
|
||||
window& window_;
|
||||
vector<event> events_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,17 +174,28 @@ namespace e2d::touch_system_impl
|
||||
|
||||
void update_world_space_colliders_under_mouse(input& input, window& window, ecs::registry& owner) {
|
||||
owner.remove_all_components<touchable_under_mouse>();
|
||||
owner.for_joined_components<camera::input, camera>([&input, &window, &owner](
|
||||
|
||||
const auto camera_comp = [](const auto& l, const auto& r) noexcept {
|
||||
return std::get<camera>(l).depth() >= std::get<camera>(r).depth();
|
||||
};
|
||||
|
||||
const auto camera_func = [&input, &window, &owner](
|
||||
const ecs::const_entity&,
|
||||
const camera::input&,
|
||||
const camera& camera)
|
||||
const camera& camera,
|
||||
const actor& camera_a)
|
||||
{
|
||||
const v2u& target_size = camera.target()
|
||||
? camera.target()->size()
|
||||
: window.framebuffer_size();
|
||||
if ( camera.target() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gobject camera_go = camera_a.node() ? camera_a.node()->owner() : gobject();
|
||||
if ( !camera_go ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const v2f& mouse_p = math::normalized_to_point(
|
||||
b2f(target_size.cast_to<f32>()),
|
||||
b2f(window.framebuffer_size().cast_to<f32>()),
|
||||
math::point_to_normalized(
|
||||
b2f(window.real_size().cast_to<f32>()),
|
||||
input.mouse().cursor_pos()));
|
||||
@@ -193,32 +204,53 @@ namespace e2d::touch_system_impl
|
||||
camera.view() * camera.projection();
|
||||
|
||||
const b2f& camera_viewport = b2f(
|
||||
camera.viewport().position * target_size.cast_to<f32>(),
|
||||
camera.viewport().size * target_size.cast_to<f32>());
|
||||
camera.viewport().position * window.framebuffer_size().cast_to<f32>(),
|
||||
camera.viewport().size * window.framebuffer_size().cast_to<f32>());
|
||||
|
||||
if ( !math::inside(camera_viewport, mouse_p) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
impl::update_world_space_colliders_under_mouse<world_space_rect_collider>(
|
||||
owner,
|
||||
mouse_p,
|
||||
camera_vp,
|
||||
camera_viewport);
|
||||
const auto under_mouse_func = [
|
||||
&camera_go
|
||||
](ecs::entity e, const v2f& local_point, const v2f& world_point){
|
||||
if ( e.exists_component<touchable_under_mouse>() ) {
|
||||
return;
|
||||
}
|
||||
e.ensure_component<touchable_under_mouse>(
|
||||
camera_go,
|
||||
local_point,
|
||||
world_point);
|
||||
};
|
||||
|
||||
impl::update_world_space_colliders_under_mouse<world_space_circle_collider>(
|
||||
impl::for_world_space_colliders_under_mouse<world_space_rect_collider>(
|
||||
owner,
|
||||
mouse_p,
|
||||
camera_vp,
|
||||
camera_viewport);
|
||||
camera_viewport,
|
||||
under_mouse_func);
|
||||
|
||||
impl::update_world_space_colliders_under_mouse<world_space_polygon_collider>(
|
||||
impl::for_world_space_colliders_under_mouse<world_space_circle_collider>(
|
||||
owner,
|
||||
mouse_p,
|
||||
camera_vp,
|
||||
camera_viewport);
|
||||
}, !ecs::exists_any<
|
||||
disabled<actor>,
|
||||
disabled<camera>>());
|
||||
camera_viewport,
|
||||
under_mouse_func);
|
||||
|
||||
impl::for_world_space_colliders_under_mouse<world_space_polygon_collider>(
|
||||
owner,
|
||||
mouse_p,
|
||||
camera_vp,
|
||||
camera_viewport,
|
||||
under_mouse_func);
|
||||
};
|
||||
|
||||
ecsex::for_extracted_sorted_components<camera::input, camera, actor>(
|
||||
owner,
|
||||
camera_comp,
|
||||
camera_func,
|
||||
!ecs::exists_any<
|
||||
disabled<actor>,
|
||||
disabled<camera>>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,12 +81,13 @@ namespace e2d::touch_system_impl
|
||||
const m4f& camera_vp,
|
||||
const b2f& camera_viewport);
|
||||
|
||||
template < typename WorldSpaceCollider >
|
||||
void update_world_space_colliders_under_mouse(
|
||||
template < typename WorldSpaceCollider, typename F >
|
||||
void for_world_space_colliders_under_mouse(
|
||||
ecs::registry& owner,
|
||||
const v2f& mouse_p,
|
||||
const m4f& camera_vp,
|
||||
const b2f& camera_viewport)
|
||||
const b2f& camera_viewport,
|
||||
F&& f)
|
||||
{
|
||||
using world_space_collider_t = WorldSpaceCollider;
|
||||
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
|
||||
@@ -100,7 +101,8 @@ namespace e2d::touch_system_impl
|
||||
&mouse_p = mouse_p,
|
||||
&camera_vp = camera_vp,
|
||||
&inv_camera_vp = inv_camera_vp,
|
||||
&camera_viewport = camera_viewport
|
||||
&camera_viewport = camera_viewport,
|
||||
&f = f
|
||||
](ecs::entity e, const touchable&, const world_space_collider_t& c){
|
||||
if ( is_world_space_collider_under_mouse(c, mouse_p, camera_vp, camera_viewport) ) {
|
||||
const auto& [world_point, world_point_success] = math::unproject(
|
||||
@@ -119,11 +121,9 @@ namespace e2d::touch_system_impl
|
||||
return;
|
||||
}
|
||||
|
||||
touchable_under_mouse& under_mouse_c
|
||||
= e.ensure_component<touchable_under_mouse>();
|
||||
const v2f& local_point = v2f(v4f(world_point, 1.f) * world_to_local);
|
||||
|
||||
under_mouse_c.world_point = v2f(world_point);
|
||||
under_mouse_c.local_point = v2f(v4f(world_point, 1.f) * world_to_local);
|
||||
std::invoke(f, e, v2f(local_point), v2f(world_point));
|
||||
}
|
||||
}, !ecs::exists_any<
|
||||
disabled<touchable>,
|
||||
|
||||
@@ -13,6 +13,56 @@ namespace
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
std::pair<v2f, bool> screen_to_world_point(
|
||||
const gobject& input_camera,
|
||||
const collector::mouse_event& event)
|
||||
{
|
||||
if ( !input_camera || !input_camera.component<camera>() ) {
|
||||
return {v2f::zero(), false};
|
||||
}
|
||||
|
||||
const camera& cam = *input_camera.component<camera>();
|
||||
|
||||
const v2f& mouse_p = math::normalized_to_point(
|
||||
b2f(event.event_window.framebuffer_size().cast_to<f32>()),
|
||||
math::point_to_normalized(
|
||||
b2f(event.event_window.real_size().cast_to<f32>()),
|
||||
event.screen_point));
|
||||
|
||||
const m4f& cam_vp =
|
||||
cam.view() * cam.projection();
|
||||
|
||||
const b2f& cam_viewport = b2f(
|
||||
cam.viewport().position * event.event_window.framebuffer_size().cast_to<f32>(),
|
||||
cam.viewport().size * event.event_window.framebuffer_size().cast_to<f32>());
|
||||
|
||||
const auto [inv_cam_vp, inv_cam_vp_success] = math::inversed(cam_vp, 0.f);
|
||||
if ( !inv_cam_vp_success ) {
|
||||
return {v2f::zero(), false};
|
||||
}
|
||||
|
||||
const auto& [world_point, world_point_success] = math::unproject(
|
||||
v3f(mouse_p, 0.f),
|
||||
inv_cam_vp,
|
||||
cam_viewport);
|
||||
|
||||
return std::make_pair(v2f(world_point), world_point_success);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
void apply_event(
|
||||
gobject target,
|
||||
const touchable_events::mouse_drag_evt& event)
|
||||
{
|
||||
target.component<events<touchable_events::event>>().ensure()
|
||||
.add(event);
|
||||
}
|
||||
|
||||
void apply_event(
|
||||
gobject target,
|
||||
const touchable_events::mouse_move_evt& event)
|
||||
@@ -35,12 +85,6 @@ namespace
|
||||
case touchable_events::mouse_hover_evt::types::out:
|
||||
target.component<touchable::hover_out>().ensure();
|
||||
break;
|
||||
case touchable_events::mouse_hover_evt::types::enter:
|
||||
target.component<touchable::hover_enter>().ensure();
|
||||
break;
|
||||
case touchable_events::mouse_hover_evt::types::leave:
|
||||
target.component<touchable::hover_leave>().ensure();
|
||||
break;
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected mouse hover event type");
|
||||
break;
|
||||
@@ -88,7 +132,7 @@ namespace
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
gobject find_event_target(const ecs::registry& owner) {
|
||||
gobject find_current_target(const ecs::registry& owner) {
|
||||
static thread_local vector<std::tuple<
|
||||
ecs::const_entity,
|
||||
scene,
|
||||
@@ -239,79 +283,134 @@ namespace
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
void process_event(
|
||||
gobject target,
|
||||
hovering_info_opt process_hover_target(
|
||||
ecs::registry& owner,
|
||||
gobject current_target,
|
||||
hovering_info_opt hovering,
|
||||
dragging_info_opt dragging)
|
||||
{
|
||||
E2D_UNUSED(owner, dragging);
|
||||
using namespace touchable_events;
|
||||
|
||||
if ( gobject last_target = hovering ? hovering->target : gobject();
|
||||
last_target != current_target )
|
||||
{
|
||||
if ( last_target ) {
|
||||
dispatch_event(last_target, mouse_hover_evt(
|
||||
last_target,
|
||||
mouse_hover_evt::types::out));
|
||||
|
||||
last_target.component<touchable::hovering>().remove();
|
||||
}
|
||||
|
||||
if ( current_target ) {
|
||||
const bool captured = dispatch_event(current_target, mouse_hover_evt(
|
||||
current_target,
|
||||
mouse_hover_evt::types::over));
|
||||
|
||||
if ( captured ) {
|
||||
current_target.component<touchable::hovering>().ensure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const_gcomponent<touchable_under_mouse> current_target_under_mouse{current_target};
|
||||
return current_target_under_mouse && current_target_under_mouse->input_camera
|
||||
? std::make_optional<hovering_info>(
|
||||
current_target,
|
||||
current_target_under_mouse->input_camera)
|
||||
: std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
void process_hovering_target_event(
|
||||
ecs::registry& owner,
|
||||
const hovering_info_opt& hovering,
|
||||
const dragging_info_opt& dragging,
|
||||
const collector::mouse_move_event& event)
|
||||
{
|
||||
E2D_UNUSED(owner, event);
|
||||
E2D_UNUSED(owner, dragging, event);
|
||||
|
||||
const_gcomponent<touchable_under_mouse> under_mouse = hovering
|
||||
? hovering->target
|
||||
: const_gcomponent<touchable_under_mouse>();
|
||||
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{target};
|
||||
if ( !under_mouse ) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_event(
|
||||
target,
|
||||
hovering->target,
|
||||
touchable_events::mouse_move_evt(
|
||||
target,
|
||||
hovering->target,
|
||||
under_mouse->local_point,
|
||||
under_mouse->world_point));
|
||||
}
|
||||
|
||||
void process_event(
|
||||
gobject target,
|
||||
void process_hovering_target_event(
|
||||
ecs::registry& owner,
|
||||
const hovering_info_opt& hovering,
|
||||
const dragging_info_opt& dragging,
|
||||
const collector::mouse_scroll_event& event)
|
||||
{
|
||||
E2D_UNUSED(owner);
|
||||
E2D_UNUSED(owner, dragging);
|
||||
using namespace touchable_events;
|
||||
|
||||
const_gcomponent<touchable_under_mouse> under_mouse = hovering
|
||||
? hovering->target
|
||||
: const_gcomponent<touchable_under_mouse>();
|
||||
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{target};
|
||||
if ( !under_mouse ) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_event(
|
||||
target,
|
||||
touchable_events::mouse_scroll_evt(
|
||||
target,
|
||||
hovering->target,
|
||||
mouse_scroll_evt(
|
||||
hovering->target,
|
||||
event.delta,
|
||||
under_mouse->local_point,
|
||||
under_mouse->world_point));
|
||||
}
|
||||
|
||||
void process_event(
|
||||
gobject target,
|
||||
void process_hovering_target_event(
|
||||
ecs::registry& owner,
|
||||
const hovering_info_opt& hovering,
|
||||
const dragging_info_opt& dragging,
|
||||
const collector::mouse_button_event& event)
|
||||
{
|
||||
E2D_UNUSED(owner, dragging);
|
||||
using namespace touchable_events;
|
||||
|
||||
gobject current_target = hovering ? hovering->target : gobject();
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{current_target};
|
||||
|
||||
const auto make_mouse_button_evt = [
|
||||
&event,
|
||||
&target
|
||||
](touchable_events::mouse_button_evt::types type){
|
||||
touchable_under_mouse& under_mouse =
|
||||
*target.component<touchable_under_mouse>();
|
||||
|
||||
return touchable_events::mouse_button_evt(
|
||||
target,
|
||||
&under_mouse,
|
||||
¤t_target
|
||||
](mouse_button_evt::types type){
|
||||
return mouse_button_evt(
|
||||
current_target,
|
||||
type,
|
||||
event.button,
|
||||
under_mouse.local_point,
|
||||
under_mouse.world_point);
|
||||
under_mouse->local_point,
|
||||
under_mouse->world_point);
|
||||
};
|
||||
|
||||
if ( event.action == mouse_button_action::press ) {
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{target};
|
||||
|
||||
if ( under_mouse ) {
|
||||
using namespace touchable_events;
|
||||
|
||||
const bool captured = dispatch_event(
|
||||
target,
|
||||
current_target,
|
||||
make_mouse_button_evt(mouse_button_evt::types::pressed));
|
||||
|
||||
if ( captured && event.button == mouse_button::left ) {
|
||||
target.component<touchable::pushing>().ensure();
|
||||
current_target.component<touchable::pushing>().ensure();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,19 +420,15 @@ namespace
|
||||
owner.remove_all_components<touchable::pushing>();
|
||||
});
|
||||
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{target};
|
||||
|
||||
if ( under_mouse ) {
|
||||
using namespace touchable_events;
|
||||
|
||||
const bool captured = dispatch_event(
|
||||
target,
|
||||
current_target,
|
||||
make_mouse_button_evt(mouse_button_evt::types::released));
|
||||
|
||||
if ( captured && event.button == mouse_button::left ) {
|
||||
if ( target.component<touchable::pushing>() ) {
|
||||
if ( current_target.component<touchable::pushing>() ) {
|
||||
dispatch_event(
|
||||
target,
|
||||
current_target,
|
||||
make_mouse_button_evt(mouse_button_evt::types::clicked));
|
||||
}
|
||||
}
|
||||
@@ -347,92 +442,110 @@ namespace
|
||||
using namespace e2d;
|
||||
using namespace e2d::touch_system_impl;
|
||||
|
||||
void process_new_hover_target(
|
||||
gobject target,
|
||||
gobject last_target,
|
||||
ecs::registry& owner)
|
||||
dragging_info_opt process_dragging_target_event(
|
||||
ecs::registry& owner,
|
||||
hovering_info_opt hovering,
|
||||
dragging_info_opt dragging,
|
||||
const collector::mouse_move_event& event)
|
||||
{
|
||||
struct touchable_last_hover final {};
|
||||
struct touchable_next_hover final {};
|
||||
E2D_UNUSED(owner, hovering);
|
||||
using namespace touchable_events;
|
||||
|
||||
E2D_DEFER([&owner](){
|
||||
owner.remove_all_components<touchable_next_hover>();
|
||||
});
|
||||
if ( !dragging || !dragging->target || !dragging->camera ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if ( target ) {
|
||||
if ( auto target_n = target.component<actor>()->node() ) {
|
||||
nodes::for_extracted_components_from_parents<touchable>(target_n, [
|
||||
](const const_gcomponent<touchable>& parent){
|
||||
const bool parent_disabled = ecs::exists_any<
|
||||
disabled<actor>,
|
||||
disabled<touchable>
|
||||
>()(parent.owner().raw_entity());
|
||||
const auto& [world_point, world_point_success] = screen_to_world_point(
|
||||
dragging->camera,
|
||||
event);
|
||||
|
||||
if ( !parent_disabled ) {
|
||||
parent.owner().component<touchable_next_hover>().ensure();
|
||||
if ( !world_point_success ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const_gcomponent<actor> dragging_target_a{dragging->target};
|
||||
if ( !dragging_target_a || !dragging_target_a->node() ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
v2f local_point = v2f(dragging_target_a->node()->world_to_local(
|
||||
v4f(world_point, 0.f, 1.f)));
|
||||
|
||||
dispatch_event(dragging->target, mouse_drag_evt(
|
||||
dragging->target,
|
||||
mouse_drag_evt::types::move,
|
||||
local_point,
|
||||
world_point));
|
||||
|
||||
return dragging;
|
||||
}
|
||||
|
||||
dragging_info_opt process_dragging_target_event(
|
||||
ecs::registry& owner,
|
||||
hovering_info_opt hovering,
|
||||
dragging_info_opt dragging,
|
||||
const collector::mouse_scroll_event& event)
|
||||
{
|
||||
E2D_UNUSED(owner, hovering, dragging, event);
|
||||
return dragging;
|
||||
}
|
||||
|
||||
dragging_info_opt process_dragging_target_event(
|
||||
ecs::registry& owner,
|
||||
hovering_info_opt hovering,
|
||||
dragging_info_opt dragging,
|
||||
const collector::mouse_button_event& event)
|
||||
{
|
||||
E2D_UNUSED(hovering);
|
||||
using namespace touchable_events;
|
||||
|
||||
if ( event.action == mouse_button_action::press ) {
|
||||
gobject current_target = hovering ? hovering->target : gobject();
|
||||
const_gcomponent<touchable_under_mouse> under_mouse{current_target};
|
||||
|
||||
if ( under_mouse ) {
|
||||
const bool captured = dispatch_event(current_target, mouse_drag_evt(
|
||||
current_target,
|
||||
mouse_drag_evt::types::start,
|
||||
under_mouse->local_point,
|
||||
under_mouse->world_point));
|
||||
|
||||
if ( captured && event.button == mouse_button::left ) {
|
||||
current_target.component<touchable::dragging>().ensure();
|
||||
dragging = std::make_optional<dragging_info>(
|
||||
current_target,
|
||||
under_mouse->input_camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( event.action == mouse_button_action::release ) {
|
||||
E2D_DEFER([&owner, &dragging](){
|
||||
dragging.reset();
|
||||
owner.remove_all_components<touchable::dragging>();
|
||||
});
|
||||
|
||||
if ( dragging && dragging->target && dragging->camera ) {
|
||||
const auto& [world_point, world_point_success] = screen_to_world_point(
|
||||
dragging->camera,
|
||||
event);
|
||||
|
||||
if ( world_point_success ) {
|
||||
const_gcomponent<actor> dragging_target_a{dragging->target};
|
||||
if ( dragging_target_a && dragging_target_a->node() ) {
|
||||
v2f local_point = v2f(dragging_target_a->node()->world_to_local(
|
||||
v4f(world_point, 0.f, 1.f)));
|
||||
dispatch_event(dragging->target, mouse_drag_evt(
|
||||
dragging->target,
|
||||
mouse_drag_evt::types::end,
|
||||
local_point,
|
||||
world_point));
|
||||
}
|
||||
}, nodes::options()
|
||||
.recursive(true)
|
||||
.include_root(true));
|
||||
}
|
||||
}
|
||||
|
||||
owner.for_joined_components<touchable, actor>([
|
||||
](ecs::entity e, const touchable&, const actor& a){
|
||||
using namespace touchable_events;
|
||||
|
||||
const auto need_hover_leave =
|
||||
ecs::exists<touchable_last_hover>() &&
|
||||
!ecs::exists<touchable_next_hover>();
|
||||
|
||||
if ( need_hover_leave(e) && a.node() ) {
|
||||
dispatch_event(
|
||||
a.node()->owner(),
|
||||
mouse_hover_evt(
|
||||
a.node()->owner(),
|
||||
mouse_hover_evt::types::leave));
|
||||
|
||||
e.remove_component<touchable_last_hover>();
|
||||
}
|
||||
|
||||
const auto need_hover_enter =
|
||||
!ecs::exists<touchable_last_hover>() &&
|
||||
ecs::exists<touchable_next_hover>();
|
||||
|
||||
if ( need_hover_enter(e) && a.node() ) {
|
||||
const bool captured = dispatch_event(
|
||||
a.node()->owner(),
|
||||
mouse_hover_evt(
|
||||
a.node()->owner(),
|
||||
mouse_hover_evt::types::enter));
|
||||
|
||||
if ( captured ) {
|
||||
e.ensure_component<touchable_last_hover>();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if ( target != last_target ) {
|
||||
using namespace touchable_events;
|
||||
|
||||
if ( last_target ) {
|
||||
dispatch_event(last_target, mouse_hover_evt(
|
||||
last_target,
|
||||
mouse_hover_evt::types::out));
|
||||
|
||||
last_target.component<touchable::hovering>().remove();
|
||||
}
|
||||
|
||||
if ( target ) {
|
||||
const bool captured = dispatch_event(target, mouse_hover_evt(
|
||||
target,
|
||||
mouse_hover_evt::types::over));
|
||||
|
||||
if ( captured ) {
|
||||
target.component<touchable::hovering>().ensure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dragging;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,32 +565,34 @@ namespace e2d::touch_system_impl
|
||||
|
||||
owner.remove_all_components<touchable::hover_over>();
|
||||
owner.remove_all_components<touchable::hover_out>();
|
||||
owner.remove_all_components<touchable::hover_enter>();
|
||||
owner.remove_all_components<touchable::hover_leave>();
|
||||
|
||||
owner.for_each_component<events<touchable_events::event>>([
|
||||
](const ecs::const_entity&, events<touchable_events::event>& es) {
|
||||
es.clear();
|
||||
});
|
||||
|
||||
gobject target = find_event_target(owner);
|
||||
process_new_hover_target(target, last_target_, owner);
|
||||
gobject target = find_current_target(owner);
|
||||
|
||||
if ( target != last_target_ ) {
|
||||
last_target_ = target;
|
||||
}
|
||||
hovering_ = process_hover_target(
|
||||
owner,
|
||||
target,
|
||||
hovering_,
|
||||
dragging_);
|
||||
|
||||
for ( const auto& event : collector ) {
|
||||
std::visit(utils::overloaded {
|
||||
[](std::monostate){},
|
||||
[&owner, &target](const collector::mouse_move_event& event){
|
||||
process_event(target, owner, event);
|
||||
},
|
||||
[&owner, &target](const collector::mouse_scroll_event& event){
|
||||
process_event(target, owner, event);
|
||||
},
|
||||
[&owner, &target](const collector::mouse_button_event& event){
|
||||
process_event(target, owner, event);
|
||||
[this, &owner](const auto& event){
|
||||
process_hovering_target_event(
|
||||
owner,
|
||||
hovering_,
|
||||
dragging_,
|
||||
event);
|
||||
dragging_ = process_dragging_target_event(
|
||||
owner,
|
||||
hovering_,
|
||||
dragging_,
|
||||
event);
|
||||
}
|
||||
}, event);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,25 @@
|
||||
|
||||
namespace e2d::touch_system_impl
|
||||
{
|
||||
struct hovering_info {
|
||||
gobject target;
|
||||
gobject camera;
|
||||
hovering_info(gobject target, gobject camera)
|
||||
: target(std::move(target))
|
||||
, camera(std::move(camera)) {}
|
||||
};
|
||||
|
||||
struct dragging_info {
|
||||
gobject target;
|
||||
gobject camera;
|
||||
dragging_info(gobject target, gobject camera)
|
||||
: target(std::move(target))
|
||||
, camera(std::move(camera)) {}
|
||||
};
|
||||
|
||||
using hovering_info_opt = std::optional<hovering_info>;
|
||||
using dragging_info_opt = std::optional<dragging_info>;
|
||||
|
||||
class dispatcher final {
|
||||
public:
|
||||
dispatcher() = default;
|
||||
@@ -18,6 +37,7 @@ namespace e2d::touch_system_impl
|
||||
collector& collector,
|
||||
ecs::registry& owner);
|
||||
private:
|
||||
gobject last_target_;
|
||||
hovering_info_opt hovering_;
|
||||
dragging_info_opt dragging_;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user