Files
panopainter/src/legacy_ui_node_event.cpp

310 lines
8.7 KiB
C++

#include "pch.h"
#include "legacy_ui_node_event.h"
#include "node.h"
#include "layout.h"
namespace pp::panopainter {
namespace {
void transfer_mouse_focus(Node& node, Event* e)
{
if (e->m_cat != kEventCategory::MouseEvent)
return;
if (node.child_mouse_focus == node.current_mouse_capture)
return;
if (!node.is_child(node.current_mouse_capture.get()))
return;
MouseEvent* me = static_cast<MouseEvent*>(e);
if (node.child_mouse_focus)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseUnfocus;
node.child_mouse_focus->handle_event(&e2);
node.child_mouse_focus->m_mouse_focus = false;
}
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseFocus;
node.current_mouse_capture->handle_event(&e2);
node.child_mouse_focus = node.current_mouse_capture;
node.child_mouse_focus->m_mouse_focus = true;
}
bool should_skip_children(Node& node, Event* e)
{
bool skip_children = false;
if (e->m_cat == kEventCategory::MouseEvent)
{
MouseEvent* me = static_cast<MouseEvent*>(e);
skip_children |= !node.m_mouse_inside && !point_in_rect(me->m_pos, node.m_clip);
}
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
(node.m_mouse_captured) && (node.root()->current_mouse_capture.get() == &node) && node.m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed
return skip_children;
}
void handle_mouse_focus_transition(Node& node, Event* e, const std::shared_ptr<Node>& child)
{
if (e->m_cat != kEventCategory::MouseEvent || node.child_mouse_focus.get() == child.get())
return;
MouseEvent* me = static_cast<MouseEvent*>(e);
if (node.child_mouse_focus && !node.child_mouse_focus->m_destroyed)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseUnfocus;
node.child_mouse_focus->handle_event(&e2);
node.child_mouse_focus->m_mouse_focus = false;
}
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseFocus;
child->handle_event(&e2);
if (!child->m_destroyed)
{
node.child_mouse_focus = child;
node.child_mouse_focus->m_mouse_focus = true;
}
}
void update_mouse_inside(Node& node, MouseEvent* me)
{
bool old_inside = node.m_mouse_inside;
node.m_mouse_inside = point_in_rect(me->m_pos, node.m_clip);
if (old_inside == false && node.m_mouse_inside == true)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseEnter;
node.handle_event(&e2);
}
if (old_inside == true && node.m_mouse_inside == false)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseLeave;
node.handle_event(&e2);
}
}
} // namespace
kEventResult handle_legacy_ui_node_event(Node& node, Event* e)
{
kEventResult ret = kEventResult::Available;
if (e->m_cat == kEventCategory::KeyEvent && node.current_key_capture)
return node.current_key_capture->on_event(e);
if (node.current_mouse_capture && node.current_mouse_capture.get() != &node)
{
transfer_mouse_focus(node, e);
return node.current_mouse_capture->on_event(e);
}
// skip mouse events if outside
if (!node.m_display || glm::any(glm::lessThanEqual(zw(node.m_clip), { 0, 0 })))
return kEventResult::Available;
if (!should_skip_children(node, e))
{
// make a copy because any handler can change the children vector
auto children_copy = node.m_children;
for (auto it = children_copy.rbegin(); it != children_copy.rend(); ++it)
{
if ((*it)->on_event(e) == kEventResult::Consumed)
{
if (node.m_flood_events)
{
ret = kEventResult::Consumed;
}
else
{
handle_mouse_focus_transition(node, e, *it);
ret = kEventResult::Consumed;
break;
}
}
}
if (ret == kEventResult::Consumed)
{
if (e->m_cat == kEventCategory::MouseEvent)
update_mouse_inside(node, static_cast<MouseEvent*>(e));
return kEventResult::Consumed;
}
}
switch (e->m_cat)
{
case kEventCategory::MouseEvent:
{
if (node.m_mouse_ignore)
break;
MouseEvent* me = static_cast<MouseEvent*>(e);
bool inside = point_in_rect(me->m_pos, node.m_clip);
bool inside_old = node.m_mouse_inside;
node.m_mouse_inside = inside;
switch (e->m_type)
{
case kEventType::MouseScroll:
case kEventType::MouseDownL:
case kEventType::MouseDownR:
case kEventType::MouseUpL:
case kEventType::MouseUpR:
if ((inside || node.m_mouse_captured) && ((node.handle_event(e) == kEventResult::Consumed) || node.m_force_mouse_capture))
return kEventResult::Consumed;
break;
case kEventType::MouseMove:
if (inside_old == false && inside == true)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseEnter;
node.handle_event(&e2);
}
if (inside || node.m_mouse_captured)
{
ret = node.handle_event(e);
if (node.m_force_mouse_capture)
ret = kEventResult::Consumed;
}
if (inside_old == true && inside == false)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseLeave;
node.handle_event(&e2);
}
break;
default:
if (node.handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
break;
}
case kEventCategory::GestureEvent:
{
if (node.m_mouse_ignore)
break;
GestureEvent* ge = static_cast<GestureEvent*>(e);
bool inside = point_in_rect(ge->m_pos, node.m_clip);
node.m_mouse_inside = inside;
if ((inside || node.m_mouse_captured) && node.handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
default:
if (node.handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
return ret;
}
void legacy_ui_node_mouse_capture(Node& node)
{
if (!node.m_parent || !node.m_manager)
return;
auto root = node.m_manager->get_ref("main");
if (!root)
return;
auto& c = root->current_mouse_capture;
auto& s = root->m_capture_stack;
// already owner of capture
if (c.get() == &node || std::find_if(s.begin(), s.end(),
[&node](const auto& a) { return a.get() == &node; }) != s.end())
return;
if (c)
{
if (c->is_child_recursive(&node))
{
// save on stack
s.push_back(c);
}
else
{
// cancel previous owner
MouseEvent e;
e.m_type = kEventType::MouseCancel;
c->handle_event(&e);
// TODO: only delete nodes on a different tree,
// so preserve direct parents of this
// also clear the whole stack
//s.clear();
s.push_back(c);
}
}
// make current
c = node.shared_from_this();
node.m_mouse_captured = true;
}
void legacy_ui_node_mouse_release(Node& node)
{
if (!node.m_parent || !node.m_manager)
return;
auto root = node.m_manager->get_ref("main");
if (!root)
return;
auto& c = root->current_mouse_capture;
auto& s = root->m_capture_stack;
s.erase(std::remove_if(s.begin(), s.end(),
[&node](const auto& a) { return a.get() == &node; }), s.end());
if (c.get() == &node)
{
if (s.empty())
{
c = nullptr;
}
else
{
c = s.back();
s.pop_back();
}
}
node.m_mouse_captured = false;
}
void legacy_ui_node_key_capture(Node& node)
{
if (!node.m_parent || !node.m_manager)
return;
auto root = node.m_manager->get_ref("main");
if (!root)
return;
root->current_key_capture = node.shared_from_this();
node.m_key_captured = true;
}
void legacy_ui_node_key_release(Node& node)
{
if (!node.m_parent || !node.m_manager)
return;
auto root = node.m_manager->get_ref("main");
if (!root)
return;
if (root->current_key_capture.get() == &node)
root->current_key_capture = nullptr;
node.m_key_captured = false;
}
} // namespace pp::panopainter