save pushing status after mouse out with pressed button

This commit is contained in:
BlackMATov
2020-05-10 08:12:39 +07:00
parent b275686081
commit 12f755e4d4
3 changed files with 278 additions and 206 deletions

View File

@@ -91,19 +91,16 @@ namespace e2d::touch_system_impl
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
m4f inv_camera_vp{m4f::identity()};
bool inv_camera_vp_success{false};
std::tie(inv_camera_vp, inv_camera_vp_success) = math::inversed(camera_vp, 0.f);
const auto [inv_camera_vp, inv_camera_vp_success] = math::inversed(camera_vp, 0.f);
if ( !inv_camera_vp_success ) {
return;
}
owner.for_joined_components<touchable, world_space_collider_t>([
&mouse_p,
&camera_vp,
&inv_camera_vp,
&camera_viewport
&mouse_p = mouse_p,
&camera_vp = camera_vp,
&inv_camera_vp = inv_camera_vp,
&camera_viewport = camera_viewport
](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(

View File

@@ -8,6 +8,81 @@
#include "touch_system_collector.hpp"
namespace
{
using namespace e2d;
using namespace e2d::touch_system_impl;
void apply_event(
gobject target,
const touchable_events::mouse_move_evt& event)
{
target.component<events<touchable_events::event>>().ensure()
.add(event);
}
void apply_event(
gobject target,
const touchable_events::mouse_hover_evt& event)
{
target.component<events<touchable_events::event>>().ensure()
.add(event);
switch ( event.type() ) {
case touchable_events::mouse_hover_evt::types::over:
target.component<touchable::hover_over>().ensure();
break;
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;
}
}
void apply_event(
gobject target,
const touchable_events::mouse_scroll_evt& event)
{
target.component<events<touchable_events::event>>().ensure()
.add(event);
}
void apply_event(
gobject target,
const touchable_events::mouse_button_evt& event)
{
target.component<events<touchable_events::event>>().ensure()
.add(event);
if ( event.button() != mouse_button::left ) {
return;
}
switch ( event.type() ) {
case touchable_events::mouse_button_evt::types::clicked:
target.component<touchable::clicked>().ensure();
break;
case touchable_events::mouse_button_evt::types::pressed:
target.component<touchable::pressed>().ensure();
break;
case touchable_events::mouse_button_evt::types::released:
target.component<touchable::released>().ensure();
break;
default:
E2D_ASSERT_MSG(false, "unexpected mouse button event type");
break;
}
}
}
namespace
{
using namespace e2d;
@@ -46,78 +121,20 @@ namespace
return gobject();
}
template < typename E >
bool dispatch_event(gobject target, const E& event);
void apply_event(gobject target, const touchable_events::mouse_move_evt& event) {
target.component<events<touchable_events::event>>().ensure()
.add(event);
}
void apply_event(gobject target, const touchable_events::mouse_hover_evt& event) {
target.component<events<touchable_events::event>>().ensure()
.add(event);
switch ( event.type() ) {
case touchable_events::mouse_hover_evt::types::over:
target.component<touchable::hover_over>().ensure();
break;
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 hover event type");
break;
}
}
void apply_event(gobject target, const touchable_events::mouse_scroll_evt& event) {
target.component<events<touchable_events::event>>().ensure()
.add(event);
}
void apply_event(gobject target, const touchable_events::mouse_button_evt& event) {
target.component<events<touchable_events::event>>().ensure()
.add(event);
if ( event.button() != mouse_button::left ) {
return;
}
switch ( event.type() ) {
case touchable_events::mouse_button_evt::types::clicked:
target.component<touchable::clicked>().ensure();
break;
case touchable_events::mouse_button_evt::types::pressed:
target.component<touchable::pressed>().ensure();
break;
case touchable_events::mouse_button_evt::types::released:
target.component<touchable::released>().ensure();
break;
default:
E2D_ASSERT_MSG(false, "unexpected mouse event type");
break;
}
}
bool capture_target(gobject target) {
if ( !target ) {
return false;
}
const_gcomponent<actor> target_actor = target.component<actor>();
const_gcomponent<touchable> target_touchable = target.component<touchable>();
const_gcomponent<actor> target_actor{target};
const_gcomponent<touchable> target_touchable{target};
if ( !target_actor || !target_touchable ) {
return false;
}
static thread_local std::vector<const_gcomponent<touchable>> parents;
static thread_local std::vector<
const_gcomponent<touchable>> parents;
const std::size_t begin_index = parents.size();
E2D_DEFER([begin_index](){
@@ -156,8 +173,9 @@ namespace
return;
}
const_gcomponent<actor> target_actor = target.component<actor>();
const_gcomponent<touchable> target_touchable = target.component<touchable>();
const_gcomponent<actor> target_actor{target};
const_gcomponent<touchable> target_touchable{target};
if ( !target_actor || !target_touchable ) {
return;
}
@@ -166,7 +184,8 @@ namespace
return;
}
static thread_local std::vector<const_gcomponent<touchable>> parents;
static thread_local std::vector<
const_gcomponent<touchable>> parents;
const std::size_t begin_index = parents.size();
E2D_DEFER([begin_index](){
@@ -215,40 +234,131 @@ namespace
}
}
namespace e2d::touch_system_impl
namespace
{
void dispatcher::dispatch_all_events(
collector& collector,
using namespace e2d;
using namespace e2d::touch_system_impl;
void process_event(
gobject target,
ecs::registry& owner,
const collector::mouse_move_event& event)
{
E2D_UNUSED(owner, event);
const_gcomponent<touchable_under_mouse> under_mouse{target};
if ( !under_mouse ) {
return;
}
dispatch_event(
target,
touchable_events::mouse_move_evt(
target,
under_mouse->local_point,
under_mouse->world_point));
}
void process_event(
gobject target,
ecs::registry& owner,
const collector::mouse_scroll_event& event)
{
E2D_UNUSED(owner);
const_gcomponent<touchable_under_mouse> under_mouse{target};
if ( !under_mouse ) {
return;
}
dispatch_event(
target,
touchable_events::mouse_scroll_evt(
target,
event.delta,
under_mouse->local_point,
under_mouse->world_point));
}
void process_event(
gobject target,
ecs::registry& owner,
const collector::mouse_button_event& event)
{
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,
type,
event.button,
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,
make_mouse_button_evt(mouse_button_evt::types::pressed));
if ( captured && event.button == mouse_button::left ) {
target.component<touchable::pushing>().ensure();
}
}
}
if ( event.action == mouse_button_action::release ) {
E2D_DEFER([&owner](){
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,
make_mouse_button_evt(mouse_button_evt::types::released));
if ( captured && event.button == mouse_button::left ) {
if ( target.component<touchable::pushing>() ) {
dispatch_event(
target,
make_mouse_button_evt(mouse_button_evt::types::clicked));
}
}
}
}
}
}
namespace
{
using namespace e2d;
using namespace e2d::touch_system_impl;
void process_new_hover_target(
gobject target,
gobject last_target,
ecs::registry& owner)
{
class touchable_last_hover final {};
class touchable_next_hover final {};
struct touchable_last_hover final {};
struct touchable_next_hover final {};
E2D_DEFER([&collector, &owner](){
collector.clear();
E2D_DEFER([&owner](){
owner.remove_all_components<touchable_next_hover>();
});
owner.remove_all_components<touchable::clicked>();
owner.remove_all_components<touchable::pressed>();
owner.remove_all_components<touchable::released>();
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);
if ( target ) {
if ( auto target_n = target.component<actor>()->node() ) {
nodes::for_extracted_components_from_parents<touchable>(target_n, [
@@ -269,19 +379,20 @@ namespace e2d::touch_system_impl
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() ) {
const bool captured = dispatch_event(
dispatch_event(
a.node()->owner(),
touchable_events::mouse_hover_evt(
mouse_hover_evt(
a.node()->owner(),
touchable_events::mouse_hover_evt::types::leave));
if ( captured ) {
e.remove_component<touchable_last_hover>();
}
mouse_hover_evt::types::leave));
e.remove_component<touchable_last_hover>();
}
const auto need_hover_enter =
@@ -291,120 +402,84 @@ namespace e2d::touch_system_impl
if ( need_hover_enter(e) && a.node() ) {
const bool captured = dispatch_event(
a.node()->owner(),
touchable_events::mouse_hover_evt(
mouse_hover_evt(
a.node()->owner(),
touchable_events::mouse_hover_evt::types::enter));
mouse_hover_evt::types::enter));
if ( captured ) {
e.ensure_component<touchable_last_hover>();
}
}
});
//
//
//
if ( target != last_target ) {
using namespace touchable_events;
if ( target != last_hover_target_ ) {
if ( last_hover_target_ ) {
dispatch_event(last_hover_target_, touchable_events::mouse_hover_evt(
last_hover_target_,
touchable_events::mouse_hover_evt::types::out));
last_hover_target_.component<touchable::pushing>().remove();
last_hover_target_.component<touchable::hovering>().remove();
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, touchable_events::mouse_hover_evt(
const bool captured = dispatch_event(target, mouse_hover_evt(
target,
touchable_events::mouse_hover_evt::types::over));
mouse_hover_evt::types::over));
if ( captured ) {
target.component<touchable::hovering>().ensure();
}
}
last_hover_target_ = target;
}
//
//
//
if ( target ) {
for ( const auto& event : collector ) {
std::visit(utils::overloaded {
[](std::monostate){},
[&target](const collector::mouse_move_event&){
const auto make_mouse_move_evt = [
&target
](){
return touchable_events::mouse_move_evt(
target,
target.component<touchable_under_mouse>()->local_point,
target.component<touchable_under_mouse>()->world_point);
};
dispatch_event(
target,
make_mouse_move_evt());
},
[&target](const collector::mouse_scroll_event& event){
const auto make_mouse_scroll_evt = [
&event,
&target
](){
return touchable_events::mouse_scroll_evt(
target,
event.delta,
target.component<touchable_under_mouse>()->local_point,
target.component<touchable_under_mouse>()->world_point);
};
dispatch_event(
target,
make_mouse_scroll_evt());
},
[&target](const collector::mouse_button_event& event){
const auto make_mouse_button_evt = [
&event,
&target
](touchable_events::mouse_button_evt::types type){
return touchable_events::mouse_button_evt(
target,
type,
event.button,
target.component<touchable_under_mouse>()->local_point,
target.component<touchable_under_mouse>()->world_point);
};
switch ( event.action ) {
case mouse_button_action::press: {
const bool captured = dispatch_event(
target,
make_mouse_button_evt(touchable_events::mouse_button_evt::types::pressed));
if ( captured && event.button == mouse_button::left ) {
target.component<touchable::pushing>().ensure();
}
break;
}
case mouse_button_action::release: {
const bool captured = dispatch_event(
target,
make_mouse_button_evt(touchable_events::mouse_button_evt::types::released));
if ( captured && event.button == mouse_button::left ) {
if ( target.component<touchable::pushing>() ) {
target.component<touchable::pushing>().remove();
dispatch_event(
target,
make_mouse_button_evt(touchable_events::mouse_button_evt::types::clicked));
}
}
break;
}
default:
E2D_ASSERT_MSG(false, "unexpected mouse button event action type");
break;
}
}
}, event);
}
}
}
}
namespace e2d::touch_system_impl
{
void dispatcher::dispatch_all_events(
collector& collector,
ecs::registry& owner)
{
E2D_DEFER([&collector](){
collector.clear();
});
owner.remove_all_components<touchable::clicked>();
owner.remove_all_components<touchable::pressed>();
owner.remove_all_components<touchable::released>();
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);
if ( target != last_target_ ) {
last_target_ = target;
}
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);
}
}, event);
}
}
}

View File

@@ -18,6 +18,6 @@ namespace e2d::touch_system_impl
collector& collector,
ecs::registry& owner);
private:
gobject last_hover_target_;
gobject last_target_;
};
}