#include #include namespace XCEngine::UI::Editor { namespace { using ::XCEngine::Input::KeyCode; using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIInputEventType; using ::XCEngine::UI::UIPointerButton; using Widgets::BuildUIEditorObjectFieldLayout; using Widgets::HitTestUIEditorObjectField; using Widgets::UIEditorObjectFieldHitTargetKind; bool ShouldUsePointerPosition(const UIInputEvent& event) { switch (event.type) { case UIInputEventType::PointerMove: case UIInputEventType::PointerEnter: case UIInputEventType::PointerButtonDown: case UIInputEventType::PointerButtonUp: return true; default: return false; } } bool CanActivate(const Widgets::UIEditorObjectFieldSpec& spec) { return !spec.readOnly; } bool CanClear(const Widgets::UIEditorObjectFieldSpec& spec) { return !spec.readOnly && spec.hasValue && spec.showClearButton; } } // namespace UIEditorObjectFieldInteractionFrame UpdateUIEditorObjectFieldInteraction( UIEditorObjectFieldInteractionState& state, const Widgets::UIEditorObjectFieldSpec& spec, const ::XCEngine::UI::UIRect& bounds, const std::vector& inputEvents, const Widgets::UIEditorObjectFieldMetrics& metrics) { Widgets::UIEditorObjectFieldLayout layout = BuildUIEditorObjectFieldLayout(bounds, spec, metrics); if (state.hasPointerPosition) { state.fieldState.hoveredTarget = HitTestUIEditorObjectField(layout, state.pointerPosition).kind; } else { state.fieldState.hoveredTarget = UIEditorObjectFieldHitTargetKind::None; } UIEditorObjectFieldInteractionResult interactionResult = {}; for (const UIInputEvent& event : inputEvents) { if (ShouldUsePointerPosition(event)) { state.pointerPosition = event.position; state.hasPointerPosition = true; } else if (event.type == UIInputEventType::PointerLeave) { state.hasPointerPosition = false; } UIEditorObjectFieldInteractionResult eventResult = {}; switch (event.type) { case UIInputEventType::FocusGained: eventResult.focusChanged = !state.fieldState.focused; state.fieldState.focused = true; break; case UIInputEventType::FocusLost: eventResult.focusChanged = state.fieldState.focused; state.fieldState.focused = false; state.fieldState.activeTarget = UIEditorObjectFieldHitTargetKind::None; state.hasPointerPosition = false; state.fieldState.hoveredTarget = UIEditorObjectFieldHitTargetKind::None; break; case UIInputEventType::PointerMove: case UIInputEventType::PointerEnter: case UIInputEventType::PointerLeave: break; case UIInputEventType::PointerButtonDown: eventResult.hitTarget = state.hasPointerPosition ? HitTestUIEditorObjectField(layout, state.pointerPosition) : Widgets::UIEditorObjectFieldHitTarget {}; if (event.pointerButton == UIPointerButton::Left && eventResult.hitTarget.kind != UIEditorObjectFieldHitTargetKind::None) { eventResult.focusChanged = !state.fieldState.focused; state.fieldState.focused = true; state.fieldState.activeTarget = eventResult.hitTarget.kind; eventResult.consumed = true; } else if (event.pointerButton == UIPointerButton::Left) { eventResult.focusChanged = state.fieldState.focused; state.fieldState.focused = false; state.fieldState.activeTarget = UIEditorObjectFieldHitTargetKind::None; } break; case UIInputEventType::PointerButtonUp: eventResult.hitTarget = state.hasPointerPosition ? HitTestUIEditorObjectField(layout, state.pointerPosition) : Widgets::UIEditorObjectFieldHitTarget {}; if (event.pointerButton == UIPointerButton::Left) { const UIEditorObjectFieldHitTargetKind activeTarget = state.fieldState.activeTarget; state.fieldState.activeTarget = UIEditorObjectFieldHitTargetKind::None; if (eventResult.hitTarget.kind == activeTarget) { if ((activeTarget == UIEditorObjectFieldHitTargetKind::ValueBox || activeTarget == UIEditorObjectFieldHitTargetKind::PickerButton) && CanActivate(spec)) { eventResult.activateRequested = true; eventResult.consumed = true; } else if (activeTarget == UIEditorObjectFieldHitTargetKind::ClearButton && CanClear(spec)) { eventResult.clearRequested = true; eventResult.consumed = true; } else if (activeTarget == UIEditorObjectFieldHitTargetKind::Row) { eventResult.consumed = true; } } } break; case UIInputEventType::KeyDown: if (!state.fieldState.focused) { break; } if ((static_cast(event.keyCode) == KeyCode::Enter || static_cast(event.keyCode) == KeyCode::Space) && CanActivate(spec)) { eventResult.activateRequested = true; eventResult.consumed = true; } else if ((static_cast(event.keyCode) == KeyCode::Delete || static_cast(event.keyCode) == KeyCode::Backspace) && CanClear(spec)) { eventResult.clearRequested = true; eventResult.consumed = true; } break; default: break; } layout = BuildUIEditorObjectFieldLayout(bounds, spec, metrics); if (state.hasPointerPosition) { state.fieldState.hoveredTarget = HitTestUIEditorObjectField(layout, state.pointerPosition).kind; } else { state.fieldState.hoveredTarget = UIEditorObjectFieldHitTargetKind::None; } if (eventResult.consumed || eventResult.focusChanged || eventResult.activateRequested || eventResult.clearRequested || eventResult.hitTarget.kind != UIEditorObjectFieldHitTargetKind::None) { interactionResult = eventResult; } } layout = BuildUIEditorObjectFieldLayout(bounds, spec, metrics); if (state.hasPointerPosition) { state.fieldState.hoveredTarget = HitTestUIEditorObjectField(layout, state.pointerPosition).kind; if (interactionResult.hitTarget.kind == UIEditorObjectFieldHitTargetKind::None) { interactionResult.hitTarget = HitTestUIEditorObjectField(layout, state.pointerPosition); } } else { state.fieldState.hoveredTarget = UIEditorObjectFieldHitTargetKind::None; } return { layout, interactionResult }; } } // namespace XCEngine::UI::Editor