222 lines
8.1 KiB
C++
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
|