#include "InputRouter.h" #include "HitTest.h" namespace UI { InputRouter::InputRouter() = default; InputRouter::InputRouter(Widget* root) { SetRootWidget(root); } bool InputRouter::IsAlive(const WidgetReference& reference) { return reference.pointer && !reference.lifetime.expired(); } void InputRouter::SetReference(WidgetReference& reference, Widget* widget) { reference.pointer = widget; reference.lifetime = widget ? widget->GetLifetimeToken() : std::weak_ptr(); } void InputRouter::ClearReference(WidgetReference& reference) { reference.pointer = nullptr; reference.lifetime.reset(); } void InputRouter::SetRootWidget(Widget* root) { SetReference(rootWidget, root); ClearReference(hoveredWidget); ClearReference(activeWidget); ClearReference(focusedWidget); ancestorConsumedPointer = false; } Widget* InputRouter::GetRootWidget() const { return IsAlive(rootWidget) ? rootWidget.pointer : nullptr; } Widget* InputRouter::GetHoveredWidget() const { return IsAlive(hoveredWidget) ? hoveredWidget.pointer : nullptr; } Widget* InputRouter::GetActiveWidget() const { return IsAlive(activeWidget) ? activeWidget.pointer : nullptr; } Widget* InputRouter::GetFocusedWidget() const { return IsAlive(focusedWidget) ? focusedWidget.pointer : nullptr; } void InputRouter::SetFocusedWidget(Widget* widget) { if (IsAlive(focusedWidget) && focusedWidget.pointer == widget) { return; } if (IsAlive(focusedWidget)) { focusedWidget.pointer->SetFocused(false); } ClearReference(focusedWidget); SetReference(focusedWidget, widget); if (IsAlive(focusedWidget) && focusedWidget.pointer->IsFocusable()) { focusedWidget.pointer->SetFocused(true); } } bool InputRouter::ProcessPointerStream(const std::shared_ptr& stream) { if (!IsAlive(rootWidget)) { return false; } const auto event = stream->PeekLatestInput(); Point pointerPos{event.scaledX, event.scaledY}; Widget* hitWidget = HitTest::Perform(rootWidget.pointer, pointerPos); if (!IsAlive(hoveredWidget) || hitWidget != hoveredWidget.pointer) { if (IsAlive(hoveredWidget)) { hoveredWidget.pointer->SetHovered(false); } SetReference(hoveredWidget, hitWidget); if (IsAlive(hoveredWidget)) { hoveredWidget.pointer->SetHovered(true); } } if (event.actDirection == PointerDirection::Down) { SetReference(activeWidget, hitWidget); ancestorConsumedPointer = false; if (hitWidget && hitWidget->IsFocusable()) { SetFocusedWidget(hitWidget); } if (IsAlive(activeWidget)) { for (Widget* ancestor = activeWidget.pointer->GetParent(); ancestor; ancestor = ancestor->GetParent()) { if (ancestor->WantsPointerCapture(stream)) { SetReference(activeWidget, ancestor); break; } } if (!IsAlive(activeWidget)) { return false; } activeWidget.pointer->SetPressed(true); bool handled = activeWidget.pointer->OnPointerStream(stream) || activeWidget.pointer != hitWidget; if (!IsAlive(activeWidget)) { ClearReference(activeWidget); } return handled; } } else if (event.actDirection == PointerDirection::Up) { bool handled = false; if (IsAlive(activeWidget)) { handled |= activeWidget.pointer->WantsPointerCapture(stream); if (!IsAlive(activeWidget)) { ClearReference(activeWidget); ancestorConsumedPointer = false; return handled; } for (Widget* ancestor = activeWidget.pointer->GetParent(); ancestor; ancestor = ancestor->GetParent()) { handled |= ancestor->WantsPointerCapture(stream); } if (!ancestorConsumedPointer) { handled |= activeWidget.pointer->OnPointerStream(stream); } if (IsAlive(activeWidget)) { activeWidget.pointer->SetPressed(false); } ClearReference(activeWidget); ancestorConsumedPointer = false; } else if (hitWidget) { ClearReference(activeWidget); handled = hitWidget->OnPointerStream(stream); } return handled; } else { if (IsAlive(activeWidget)) { if (activeWidget.pointer->WantsPointerCapture(stream)) { ancestorConsumedPointer = true; if (!IsAlive(activeWidget)) { ClearReference(activeWidget); } return true; } if (!IsAlive(activeWidget)) { ClearReference(activeWidget); return false; } for (Widget* ancestor = activeWidget.pointer->GetParent(); ancestor; ancestor = ancestor->GetParent()) { if (ancestor->WantsPointerCapture(stream)) { ancestorConsumedPointer = true; return true; } } bool handled = activeWidget.pointer->OnPointerStream(stream); if (!IsAlive(activeWidget)) { ClearReference(activeWidget); } return handled; } if (hitWidget) { ClearReference(activeWidget); return hitWidget->OnPointerStream(stream); } } return false; } void InputRouter::ProcessPointerHover(Point scaledPoint) { if (!IsAlive(rootWidget)) { return; } Widget* hitWidget = HitTest::Perform(rootWidget.pointer, scaledPoint); if (IsAlive(hoveredWidget) && hitWidget == hoveredWidget.pointer) { return; } if (IsAlive(hoveredWidget)) { hoveredWidget.pointer->SetHovered(false); } SetReference(hoveredWidget, hitWidget); if (IsAlive(hoveredWidget)) { hoveredWidget.pointer->SetHovered(true); } } }