#include #include namespace XCEngine::UI::Editor { namespace { using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIInputEventType; using ::XCEngine::UI::UIPoint; using ::XCEngine::UI::UIPointerButton; using ::XCEngine::UI::UIRect; bool ContainsPoint(const UIRect& rect, const UIPoint& point) { return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height; } UIPoint ToLocalPoint(const UIRect& rect, const UIPoint& point) { return UIPoint(point.x - rect.x, point.y - rect.y); } std::uint8_t ButtonMask(UIPointerButton button) { switch (button) { case UIPointerButton::Left: return 1u << 0u; case UIPointerButton::Right: return 1u << 1u; case UIPointerButton::Middle: return 1u << 2u; case UIPointerButton::X1: return 1u << 3u; case UIPointerButton::X2: return 1u << 4u; case UIPointerButton::None: default: return 0u; } } bool AnyPointerButtonsDown(const UIEditorViewportInputBridgeState& state) { return state.pointerButtonsDownMask != 0u; } void ClearCapture(UIEditorViewportInputBridgeState& state) { state.captured = false; state.captureButton = UIPointerButton::None; } void ClearInputState(UIEditorViewportInputBridgeState& state) { state.pressedKeys.clear(); state.pointerButtonsDownMask = 0u; ClearCapture(state); state.hovered = false; } void UpdatePointerPosition( UIEditorViewportInputBridgeState& state, UIEditorViewportInputBridgeFrame& frame, const UIRect& inputRect, const UIPoint& screenPosition, const ::XCEngine::UI::UIInputModifiers& modifiers) { if (state.hasPointerPosition) { frame.pointerDelta.x += screenPosition.x - state.lastScreenPointerPosition.x; frame.pointerDelta.y += screenPosition.y - state.lastScreenPointerPosition.y; frame.pointerMoved = frame.pointerMoved || screenPosition.x != state.lastScreenPointerPosition.x || screenPosition.y != state.lastScreenPointerPosition.y; } state.lastScreenPointerPosition = screenPosition; state.lastLocalPointerPosition = ToLocalPoint(inputRect, screenPosition); state.hasPointerPosition = true; state.modifiers = modifiers; frame.screenPointerPosition = state.lastScreenPointerPosition; frame.localPointerPosition = state.lastLocalPointerPosition; frame.modifiers = state.modifiers; } } // namespace bool IsUIEditorViewportInputBridgeKeyDown( const UIEditorViewportInputBridgeState& state, std::int32_t keyCode) { return state.pressedKeys.contains(keyCode); } bool IsUIEditorViewportInputBridgePointerButtonDown( const UIEditorViewportInputBridgeState& state, UIPointerButton button) { const std::uint8_t mask = ButtonMask(button); return mask != 0u && (state.pointerButtonsDownMask & mask) != 0u; } UIEditorViewportInputBridgeFrame UpdateUIEditorViewportInputBridge( UIEditorViewportInputBridgeState& state, const UIRect& inputRect, const std::vector& events, const UIEditorViewportInputBridgeConfig& config) { UIEditorViewportInputBridgeFrame frame = {}; frame.screenPointerPosition = state.lastScreenPointerPosition; frame.localPointerPosition = state.lastLocalPointerPosition; frame.modifiers = state.modifiers; for (const UIInputEvent& event : events) { const bool inside = ContainsPoint(inputRect, event.position); switch (event.type) { case UIInputEventType::PointerEnter: case UIInputEventType::PointerMove: UpdatePointerPosition(state, frame, inputRect, event.position, event.modifiers); state.hovered = inside; break; case UIInputEventType::PointerLeave: state.hovered = false; state.lastScreenPointerPosition = event.position; state.lastLocalPointerPosition = ToLocalPoint(inputRect, event.position); frame.screenPointerPosition = state.lastScreenPointerPosition; frame.localPointerPosition = state.lastLocalPointerPosition; frame.modifiers = state.modifiers; break; case UIInputEventType::PointerButtonDown: UpdatePointerPosition(state, frame, inputRect, event.position, event.modifiers); state.hovered = inside; state.pointerButtonsDownMask |= ButtonMask(event.pointerButton); frame.changedPointerButton = event.pointerButton; if (inside) { frame.pointerPressedInside = true; if (config.focusOnPointerDownInside && !state.focused) { state.focused = true; frame.focusGained = true; } if (config.capturePointerOnPointerDownInside && !state.captured) { state.captured = true; state.captureButton = event.pointerButton; frame.captureStarted = true; } } else if (config.clearFocusOnPointerDownOutside) { if (state.focused) { state.focused = false; frame.focusLost = true; } if (state.captured) { ClearCapture(state); frame.captureEnded = true; } } break; case UIInputEventType::PointerButtonUp: UpdatePointerPosition(state, frame, inputRect, event.position, event.modifiers); state.hovered = inside; state.pointerButtonsDownMask &= static_cast(~ButtonMask(event.pointerButton)); frame.changedPointerButton = event.pointerButton; if (inside) { frame.pointerReleasedInside = true; } if (state.captured && state.captureButton == event.pointerButton && !AnyPointerButtonsDown(state)) { ClearCapture(state); frame.captureEnded = true; } break; case UIInputEventType::PointerWheel: UpdatePointerPosition(state, frame, inputRect, event.position, event.modifiers); state.hovered = inside; if (inside || state.captured) { frame.wheelDelta += event.wheelDelta; } break; case UIInputEventType::KeyDown: state.modifiers = event.modifiers; frame.modifiers = state.modifiers; if (state.focused) { state.pressedKeys.insert(event.keyCode); frame.pressedKeyCodes.push_back(event.keyCode); } break; case UIInputEventType::KeyUp: state.modifiers = event.modifiers; frame.modifiers = state.modifiers; if (state.focused) { state.pressedKeys.erase(event.keyCode); frame.releasedKeyCodes.push_back(event.keyCode); } break; case UIInputEventType::Character: if (state.focused) { frame.characters.push_back(event.character); } break; case UIInputEventType::FocusLost: if (state.focused) { frame.focusLost = true; } if (state.captured) { frame.captureEnded = true; } state.focused = false; ClearInputState(state); break; case UIInputEventType::FocusGained: state.modifiers = event.modifiers; frame.modifiers = state.modifiers; break; case UIInputEventType::None: default: break; } } frame.pointerInside = ContainsPoint(inputRect, state.lastScreenPointerPosition); frame.hovered = state.hovered; frame.focused = state.focused; frame.captured = state.captured; frame.screenPointerPosition = state.lastScreenPointerPosition; frame.localPointerPosition = state.lastLocalPointerPosition; frame.modifiers = state.modifiers; return frame; } } // namespace XCEngine::UI::Editor