Files
XCEngine/new_editor/src/Shell/UIEditorViewportInputBridge.cpp

222 lines
8.1 KiB
C++

#include <XCEditor/Shell/UIEditorViewportInputBridge.h>
#include <algorithm>
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<UIInputEvent>& 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<std::uint8_t>(~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