Extract node events, transform mode, and preview pass shells
This commit is contained in:
309
src/legacy_ui_node_event.cpp
Normal file
309
src/legacy_ui_node_event.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user