564 lines
22 KiB
C++
564 lines
22 KiB
C++
#include <XCEditor/Fields/UIEditorVector2FieldInteraction.h>
|
|
|
|
#include <XCEngine/Input/InputTypes.h>
|
|
|
|
#include <utility>
|
|
|
|
namespace XCEngine::UI::Editor {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::Input::KeyCode;
|
|
using ::XCEngine::UI::UIInputEvent;
|
|
using ::XCEngine::UI::UIInputEventType;
|
|
using ::XCEngine::UI::UIPointerButton;
|
|
using ::XCEngine::UI::Text::HandleKeyDown;
|
|
using ::XCEngine::UI::Text::InsertCharacter;
|
|
using ::XCEngine::UI::Editor::Widgets::BuildUIEditorVector2FieldLayout;
|
|
using ::XCEngine::UI::Editor::Widgets::FormatUIEditorVector2FieldComponentValue;
|
|
using ::XCEngine::UI::Editor::Widgets::HitTestUIEditorVector2Field;
|
|
using ::XCEngine::UI::Editor::Widgets::IsUIEditorVector2FieldPointInside;
|
|
using ::XCEngine::UI::Editor::Widgets::NormalizeUIEditorVector2FieldComponentValue;
|
|
using ::XCEngine::UI::Editor::Widgets::TryParseUIEditorVector2FieldComponentValue;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldHitTarget;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldHitTargetKind;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldInvalidComponentIndex;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldLayout;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldMetrics;
|
|
using ::XCEngine::UI::Editor::Widgets::UIEditorVector2FieldSpec;
|
|
|
|
bool ShouldUsePointerPosition(const UIInputEvent& event) {
|
|
switch (event.type) {
|
|
case UIInputEventType::PointerMove:
|
|
case UIInputEventType::PointerEnter:
|
|
case UIInputEventType::PointerButtonDown:
|
|
case UIInputEventType::PointerButtonUp:
|
|
case UIInputEventType::PointerWheel:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::size_t ResolveFallbackSelectedComponentIndex(
|
|
const UIEditorVector2FieldInteractionState& state) {
|
|
return state.vector2FieldState.selectedComponentIndex ==
|
|
UIEditorVector2FieldInvalidComponentIndex
|
|
? 0u
|
|
: state.vector2FieldState.selectedComponentIndex;
|
|
}
|
|
|
|
std::string BuildComponentEditFieldId(
|
|
const UIEditorVector2FieldSpec& spec,
|
|
std::size_t componentIndex) {
|
|
return spec.fieldId + "." + std::to_string(componentIndex);
|
|
}
|
|
|
|
bool IsPermittedCharacter(
|
|
const UIEditorVector2FieldSpec& spec,
|
|
std::uint32_t character) {
|
|
if (character >= static_cast<std::uint32_t>('0') &&
|
|
character <= static_cast<std::uint32_t>('9')) {
|
|
return true;
|
|
}
|
|
|
|
if (character == static_cast<std::uint32_t>('-') ||
|
|
character == static_cast<std::uint32_t>('+')) {
|
|
return true;
|
|
}
|
|
|
|
return !spec.integerMode && character == static_cast<std::uint32_t>('.');
|
|
}
|
|
|
|
void SyncDisplayTexts(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
const UIEditorVector2FieldSpec& spec) {
|
|
for (std::size_t componentIndex = 0u;
|
|
componentIndex < state.vector2FieldState.displayTexts.size();
|
|
++componentIndex) {
|
|
if (state.vector2FieldState.editing &&
|
|
state.vector2FieldState.selectedComponentIndex == componentIndex) {
|
|
continue;
|
|
}
|
|
|
|
state.vector2FieldState.displayTexts[componentIndex] =
|
|
FormatUIEditorVector2FieldComponentValue(spec, componentIndex);
|
|
}
|
|
}
|
|
|
|
void SyncHoverTarget(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
const UIEditorVector2FieldLayout& layout) {
|
|
if (!state.hasPointerPosition) {
|
|
state.vector2FieldState.hoveredTarget = UIEditorVector2FieldHitTargetKind::None;
|
|
state.vector2FieldState.hoveredComponentIndex = UIEditorVector2FieldInvalidComponentIndex;
|
|
return;
|
|
}
|
|
|
|
const UIEditorVector2FieldHitTarget hitTarget =
|
|
HitTestUIEditorVector2Field(layout, state.pointerPosition);
|
|
state.vector2FieldState.hoveredTarget = hitTarget.kind;
|
|
state.vector2FieldState.hoveredComponentIndex = hitTarget.componentIndex;
|
|
}
|
|
|
|
bool MoveSelection(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
int direction,
|
|
UIEditorVector2FieldInteractionResult& result) {
|
|
const std::size_t before = ResolveFallbackSelectedComponentIndex(state);
|
|
const std::size_t after =
|
|
direction < 0
|
|
? (before == 0u ? 0u : before - 1u)
|
|
: (before >= 1u ? 1u : before + 1u);
|
|
state.vector2FieldState.selectedComponentIndex = after;
|
|
result.selectionChanged = before != after;
|
|
result.selectedComponentIndex = after;
|
|
result.consumed = true;
|
|
return true;
|
|
}
|
|
|
|
bool SelectComponent(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
std::size_t componentIndex,
|
|
UIEditorVector2FieldInteractionResult& result) {
|
|
if (componentIndex >= 2u) {
|
|
return false;
|
|
}
|
|
|
|
const std::size_t before = ResolveFallbackSelectedComponentIndex(state);
|
|
state.vector2FieldState.selectedComponentIndex = componentIndex;
|
|
result.selectionChanged = before != componentIndex;
|
|
result.selectedComponentIndex = componentIndex;
|
|
return true;
|
|
}
|
|
|
|
bool BeginEdit(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
const UIEditorVector2FieldSpec& spec,
|
|
std::size_t componentIndex,
|
|
bool clearText) {
|
|
if (spec.readOnly || componentIndex >= spec.values.size()) {
|
|
return false;
|
|
}
|
|
|
|
const std::string baseline =
|
|
FormatUIEditorVector2FieldComponentValue(spec, componentIndex);
|
|
const std::string editFieldId =
|
|
BuildComponentEditFieldId(spec, componentIndex);
|
|
const bool changed = state.editModel.BeginEdit(editFieldId, baseline);
|
|
if (!changed &&
|
|
state.editModel.HasActiveEdit() &&
|
|
state.editModel.GetActiveFieldId() != editFieldId) {
|
|
return false;
|
|
}
|
|
if (!changed &&
|
|
state.vector2FieldState.editing &&
|
|
state.vector2FieldState.selectedComponentIndex == componentIndex) {
|
|
return false;
|
|
}
|
|
|
|
state.vector2FieldState.selectedComponentIndex = componentIndex;
|
|
state.vector2FieldState.editing = true;
|
|
state.textInputState.value = clearText ? std::string() : baseline;
|
|
state.textInputState.caret = state.textInputState.value.size();
|
|
state.editModel.UpdateStagedValue(state.textInputState.value);
|
|
state.vector2FieldState.displayTexts[componentIndex] = state.textInputState.value;
|
|
return true;
|
|
}
|
|
|
|
bool CommitEdit(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
UIEditorVector2FieldSpec& spec,
|
|
UIEditorVector2FieldInteractionResult& result) {
|
|
if (!state.vector2FieldState.editing ||
|
|
!state.editModel.HasActiveEdit() ||
|
|
state.vector2FieldState.selectedComponentIndex >= spec.values.size()) {
|
|
return false;
|
|
}
|
|
|
|
const std::size_t componentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
double parsedValue = spec.values[componentIndex];
|
|
if (!TryParseUIEditorVector2FieldComponentValue(
|
|
spec,
|
|
state.textInputState.value,
|
|
parsedValue)) {
|
|
result.consumed = true;
|
|
result.editCommitRejected = true;
|
|
return false;
|
|
}
|
|
|
|
result.valuesBefore = spec.values;
|
|
spec.values[componentIndex] = NormalizeUIEditorVector2FieldComponentValue(spec, parsedValue);
|
|
result.valuesAfter = spec.values;
|
|
result.valueChanged = result.valuesBefore != result.valuesAfter;
|
|
result.editCommitted = true;
|
|
result.consumed = true;
|
|
result.changedComponentIndex = componentIndex;
|
|
result.selectedComponentIndex = componentIndex;
|
|
result.committedText =
|
|
FormatUIEditorVector2FieldComponentValue(spec, componentIndex);
|
|
|
|
state.editModel.CommitEdit();
|
|
state.textInputState = {};
|
|
state.vector2FieldState.editing = false;
|
|
state.vector2FieldState.displayTexts[componentIndex] = result.committedText;
|
|
return true;
|
|
}
|
|
|
|
bool CancelEdit(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
const UIEditorVector2FieldSpec& spec,
|
|
UIEditorVector2FieldInteractionResult& result) {
|
|
if (!state.vector2FieldState.editing ||
|
|
!state.editModel.HasActiveEdit() ||
|
|
state.vector2FieldState.selectedComponentIndex >= spec.values.size()) {
|
|
return false;
|
|
}
|
|
|
|
const std::size_t componentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
state.editModel.CancelEdit();
|
|
state.textInputState = {};
|
|
state.vector2FieldState.editing = false;
|
|
state.vector2FieldState.displayTexts[componentIndex] =
|
|
FormatUIEditorVector2FieldComponentValue(spec, componentIndex);
|
|
result.consumed = true;
|
|
result.editCanceled = true;
|
|
result.valuesBefore = spec.values;
|
|
result.valuesAfter = spec.values;
|
|
result.selectedComponentIndex = componentIndex;
|
|
return true;
|
|
}
|
|
|
|
bool ApplyStep(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
UIEditorVector2FieldSpec& spec,
|
|
double direction,
|
|
bool snapToEdge,
|
|
UIEditorVector2FieldInteractionResult& result) {
|
|
if (spec.readOnly) {
|
|
return false;
|
|
}
|
|
|
|
const std::size_t componentIndex = ResolveFallbackSelectedComponentIndex(state);
|
|
state.vector2FieldState.selectedComponentIndex = componentIndex;
|
|
|
|
if (state.vector2FieldState.editing &&
|
|
!CommitEdit(state, spec, result)) {
|
|
return result.editCommitRejected;
|
|
}
|
|
|
|
result.valuesBefore = spec.values;
|
|
if (snapToEdge) {
|
|
spec.values[componentIndex] =
|
|
direction < 0.0
|
|
? NormalizeUIEditorVector2FieldComponentValue(spec, spec.minValue)
|
|
: NormalizeUIEditorVector2FieldComponentValue(spec, spec.maxValue);
|
|
} else {
|
|
const double step = spec.step == 0.0 ? 1.0 : spec.step;
|
|
spec.values[componentIndex] = NormalizeUIEditorVector2FieldComponentValue(
|
|
spec,
|
|
spec.values[componentIndex] + step * direction);
|
|
result.stepDelta = step * direction;
|
|
}
|
|
|
|
result.valuesAfter = spec.values;
|
|
result.stepApplied = true;
|
|
result.valueChanged = result.valuesBefore != result.valuesAfter || result.valueChanged;
|
|
result.changedComponentIndex = componentIndex;
|
|
result.selectedComponentIndex = componentIndex;
|
|
result.consumed = true;
|
|
state.vector2FieldState.displayTexts[componentIndex] =
|
|
FormatUIEditorVector2FieldComponentValue(spec, componentIndex);
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
UIEditorVector2FieldInteractionFrame UpdateUIEditorVector2FieldInteraction(
|
|
UIEditorVector2FieldInteractionState& state,
|
|
UIEditorVector2FieldSpec& spec,
|
|
const ::XCEngine::UI::UIRect& bounds,
|
|
const std::vector<UIInputEvent>& inputEvents,
|
|
const UIEditorVector2FieldMetrics& metrics) {
|
|
UIEditorVector2FieldLayout layout = BuildUIEditorVector2FieldLayout(bounds, spec, metrics);
|
|
SyncDisplayTexts(state, spec);
|
|
SyncHoverTarget(state, layout);
|
|
|
|
UIEditorVector2FieldInteractionResult interactionResult = {};
|
|
interactionResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
for (const UIInputEvent& event : inputEvents) {
|
|
if (ShouldUsePointerPosition(event)) {
|
|
state.pointerPosition = event.position;
|
|
state.hasPointerPosition = true;
|
|
} else if (event.type == UIInputEventType::PointerLeave) {
|
|
state.hasPointerPosition = false;
|
|
}
|
|
|
|
UIEditorVector2FieldInteractionResult eventResult = {};
|
|
eventResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
switch (event.type) {
|
|
case UIInputEventType::FocusGained:
|
|
eventResult.focusChanged = !state.vector2FieldState.focused;
|
|
state.vector2FieldState.focused = true;
|
|
if (state.vector2FieldState.selectedComponentIndex ==
|
|
UIEditorVector2FieldInvalidComponentIndex) {
|
|
state.vector2FieldState.selectedComponentIndex = 0u;
|
|
}
|
|
eventResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
break;
|
|
|
|
case UIInputEventType::FocusLost:
|
|
eventResult.focusChanged = state.vector2FieldState.focused;
|
|
state.vector2FieldState.focused = false;
|
|
state.vector2FieldState.activeTarget = UIEditorVector2FieldHitTargetKind::None;
|
|
state.vector2FieldState.activeComponentIndex = UIEditorVector2FieldInvalidComponentIndex;
|
|
state.hasPointerPosition = false;
|
|
if (state.vector2FieldState.editing) {
|
|
CommitEdit(state, spec, eventResult);
|
|
if (eventResult.editCommitRejected) {
|
|
CancelEdit(state, spec, eventResult);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UIInputEventType::PointerMove:
|
|
case UIInputEventType::PointerEnter:
|
|
case UIInputEventType::PointerLeave:
|
|
break;
|
|
|
|
case UIInputEventType::PointerButtonDown: {
|
|
const UIEditorVector2FieldHitTarget hitTarget =
|
|
state.hasPointerPosition
|
|
? HitTestUIEditorVector2Field(layout, state.pointerPosition)
|
|
: UIEditorVector2FieldHitTarget {};
|
|
eventResult.hitTarget = hitTarget;
|
|
|
|
if (event.pointerButton != UIPointerButton::Left) {
|
|
break;
|
|
}
|
|
|
|
const bool insideField =
|
|
state.hasPointerPosition &&
|
|
IsUIEditorVector2FieldPointInside(layout.bounds, state.pointerPosition);
|
|
if (insideField) {
|
|
eventResult.focusChanged = !state.vector2FieldState.focused;
|
|
state.vector2FieldState.focused = true;
|
|
state.vector2FieldState.activeTarget = hitTarget.kind == UIEditorVector2FieldHitTargetKind::None
|
|
? UIEditorVector2FieldHitTargetKind::Row
|
|
: hitTarget.kind;
|
|
state.vector2FieldState.activeComponentIndex = hitTarget.componentIndex;
|
|
if (hitTarget.kind == UIEditorVector2FieldHitTargetKind::Component) {
|
|
SelectComponent(state, hitTarget.componentIndex, eventResult);
|
|
} else if (state.vector2FieldState.selectedComponentIndex ==
|
|
UIEditorVector2FieldInvalidComponentIndex) {
|
|
state.vector2FieldState.selectedComponentIndex = 0u;
|
|
eventResult.selectedComponentIndex = 0u;
|
|
}
|
|
eventResult.consumed = true;
|
|
} else {
|
|
if (state.vector2FieldState.editing) {
|
|
CommitEdit(state, spec, eventResult);
|
|
if (!eventResult.editCommitRejected) {
|
|
eventResult.focusChanged = state.vector2FieldState.focused;
|
|
state.vector2FieldState.focused = false;
|
|
}
|
|
} else if (state.vector2FieldState.focused) {
|
|
eventResult.focusChanged = true;
|
|
state.vector2FieldState.focused = false;
|
|
}
|
|
state.vector2FieldState.activeTarget = UIEditorVector2FieldHitTargetKind::None;
|
|
state.vector2FieldState.activeComponentIndex = UIEditorVector2FieldInvalidComponentIndex;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case UIInputEventType::PointerButtonUp: {
|
|
const UIEditorVector2FieldHitTarget hitTarget =
|
|
state.hasPointerPosition
|
|
? HitTestUIEditorVector2Field(layout, state.pointerPosition)
|
|
: UIEditorVector2FieldHitTarget {};
|
|
eventResult.hitTarget = hitTarget;
|
|
|
|
if (event.pointerButton == UIPointerButton::Left) {
|
|
const UIEditorVector2FieldHitTargetKind activeTarget = state.vector2FieldState.activeTarget;
|
|
const std::size_t activeComponentIndex = state.vector2FieldState.activeComponentIndex;
|
|
state.vector2FieldState.activeTarget = UIEditorVector2FieldHitTargetKind::None;
|
|
state.vector2FieldState.activeComponentIndex = UIEditorVector2FieldInvalidComponentIndex;
|
|
|
|
if (activeTarget == UIEditorVector2FieldHitTargetKind::Component &&
|
|
hitTarget.kind == UIEditorVector2FieldHitTargetKind::Component &&
|
|
activeComponentIndex == hitTarget.componentIndex) {
|
|
SelectComponent(state, hitTarget.componentIndex, eventResult);
|
|
if (!state.vector2FieldState.editing) {
|
|
eventResult.editStarted =
|
|
BeginEdit(state, spec, hitTarget.componentIndex, false);
|
|
}
|
|
eventResult.consumed = true;
|
|
} else if (hitTarget.kind == UIEditorVector2FieldHitTargetKind::Row) {
|
|
eventResult.consumed = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case UIInputEventType::KeyDown:
|
|
if (!state.vector2FieldState.focused) {
|
|
break;
|
|
}
|
|
|
|
if (state.vector2FieldState.editing) {
|
|
if (event.keyCode == static_cast<std::int32_t>(KeyCode::Escape)) {
|
|
CancelEdit(state, spec, eventResult);
|
|
break;
|
|
}
|
|
|
|
if (event.keyCode == static_cast<std::int32_t>(KeyCode::Tab)) {
|
|
if (CommitEdit(state, spec, eventResult)) {
|
|
MoveSelection(
|
|
state,
|
|
event.modifiers.shift ? -1 : 1,
|
|
eventResult);
|
|
}
|
|
eventResult.consumed = true;
|
|
break;
|
|
}
|
|
|
|
const auto textResult =
|
|
HandleKeyDown(state.textInputState, event.keyCode, event.modifiers);
|
|
if (textResult.handled) {
|
|
state.editModel.UpdateStagedValue(state.textInputState.value);
|
|
state.vector2FieldState.displayTexts[state.vector2FieldState.selectedComponentIndex] =
|
|
state.textInputState.value;
|
|
eventResult.consumed = true;
|
|
eventResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
if (textResult.submitRequested) {
|
|
CommitEdit(state, spec, eventResult);
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
switch (static_cast<KeyCode>(event.keyCode)) {
|
|
case KeyCode::Left:
|
|
MoveSelection(state, -1, eventResult);
|
|
break;
|
|
|
|
case KeyCode::Right:
|
|
case KeyCode::Tab:
|
|
MoveSelection(
|
|
state,
|
|
static_cast<KeyCode>(event.keyCode) == KeyCode::Tab && event.modifiers.shift ? -1 : 1,
|
|
eventResult);
|
|
break;
|
|
|
|
case KeyCode::Up:
|
|
ApplyStep(state, spec, 1.0, false, eventResult);
|
|
break;
|
|
|
|
case KeyCode::Down:
|
|
ApplyStep(state, spec, -1.0, false, eventResult);
|
|
break;
|
|
|
|
case KeyCode::Home:
|
|
ApplyStep(state, spec, -1.0, true, eventResult);
|
|
break;
|
|
|
|
case KeyCode::End:
|
|
ApplyStep(state, spec, 1.0, true, eventResult);
|
|
break;
|
|
|
|
case KeyCode::Enter:
|
|
eventResult.selectedComponentIndex = ResolveFallbackSelectedComponentIndex(state);
|
|
eventResult.editStarted = BeginEdit(
|
|
state,
|
|
spec,
|
|
eventResult.selectedComponentIndex,
|
|
false);
|
|
eventResult.consumed = eventResult.editStarted;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UIInputEventType::Character:
|
|
if (!state.vector2FieldState.focused ||
|
|
spec.readOnly ||
|
|
event.modifiers.control ||
|
|
event.modifiers.alt ||
|
|
event.modifiers.super ||
|
|
!IsPermittedCharacter(spec, event.character)) {
|
|
break;
|
|
}
|
|
|
|
if (state.vector2FieldState.selectedComponentIndex ==
|
|
UIEditorVector2FieldInvalidComponentIndex) {
|
|
state.vector2FieldState.selectedComponentIndex = 0u;
|
|
}
|
|
eventResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
|
|
if (!state.vector2FieldState.editing) {
|
|
eventResult.editStarted = BeginEdit(
|
|
state,
|
|
spec,
|
|
state.vector2FieldState.selectedComponentIndex,
|
|
true);
|
|
}
|
|
|
|
if (InsertCharacter(state.textInputState, event.character)) {
|
|
state.editModel.UpdateStagedValue(state.textInputState.value);
|
|
state.vector2FieldState.displayTexts[state.vector2FieldState.selectedComponentIndex] =
|
|
state.textInputState.value;
|
|
eventResult.consumed = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
layout = BuildUIEditorVector2FieldLayout(bounds, spec, metrics);
|
|
SyncDisplayTexts(state, spec);
|
|
SyncHoverTarget(state, layout);
|
|
if (eventResult.hitTarget.kind == UIEditorVector2FieldHitTargetKind::None &&
|
|
state.hasPointerPosition) {
|
|
eventResult.hitTarget = HitTestUIEditorVector2Field(layout, state.pointerPosition);
|
|
}
|
|
if (eventResult.selectedComponentIndex == UIEditorVector2FieldInvalidComponentIndex) {
|
|
eventResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
}
|
|
|
|
if (eventResult.consumed ||
|
|
eventResult.focusChanged ||
|
|
eventResult.valueChanged ||
|
|
eventResult.stepApplied ||
|
|
eventResult.selectionChanged ||
|
|
eventResult.editStarted ||
|
|
eventResult.editCommitted ||
|
|
eventResult.editCommitRejected ||
|
|
eventResult.editCanceled ||
|
|
eventResult.hitTarget.kind != UIEditorVector2FieldHitTargetKind::None) {
|
|
interactionResult = std::move(eventResult);
|
|
}
|
|
}
|
|
|
|
layout = BuildUIEditorVector2FieldLayout(bounds, spec, metrics);
|
|
SyncDisplayTexts(state, spec);
|
|
SyncHoverTarget(state, layout);
|
|
if (interactionResult.hitTarget.kind == UIEditorVector2FieldHitTargetKind::None &&
|
|
state.hasPointerPosition) {
|
|
interactionResult.hitTarget = HitTestUIEditorVector2Field(layout, state.pointerPosition);
|
|
}
|
|
if (interactionResult.selectedComponentIndex == UIEditorVector2FieldInvalidComponentIndex) {
|
|
interactionResult.selectedComponentIndex = state.vector2FieldState.selectedComponentIndex;
|
|
}
|
|
|
|
return {
|
|
std::move(layout),
|
|
std::move(interactionResult)
|
|
};
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor
|