editor: apply pending updates

This commit is contained in:
2026-04-29 18:49:07 +08:00
parent fd6dc4ee4f
commit 626fe236bc
13 changed files with 844 additions and 872 deletions

View File

@@ -287,6 +287,7 @@ void InspectorPanel::ResetPanelState() {
m_subjectKey.clear();
m_presentation = {};
m_gridFrame = {};
m_popupOverlay = {};
m_knownSectionIds.clear();
m_lastSceneSelectionStamp = 0u;
m_lastProjectSelectionStamp = 0u;
@@ -303,6 +304,8 @@ void InspectorPanel::ResetInteractionState() {
m_scrollVerticalOffset = 0.0f;
m_interactionState = {};
m_gridFrame = {};
m_popupOverlay = {};
ResetUIEditorMenuPopupInteractionState(m_popupInteractionState);
m_lastAppliedColorPickerRevision = 0u;
ResetAddComponentButtonState();
}
@@ -855,14 +858,12 @@ void InspectorPanel::Update(
RefreshPresentation(context, subjectChanged);
ApplyColorPickerToolValue(context);
RebuildScrollableLayout();
Widgets::UIEditorMenuPopupLayout popupLayout = {};
Widgets::UIEditorMenuPopupState popupState = {};
std::vector<Widgets::UIEditorMenuPopupItem> popupItems = {};
const bool popupOpen =
BuildPropertyGridPopupRuntime(popupLayout, popupState, popupItems);
RebuildPropertyGridPopupOverlay();
const bool popupOpen = m_popupOverlay.open;
const std::vector<UIRect> popupBounds =
popupOpen ? std::vector<UIRect>{ popupLayout.popupRect } : std::vector<UIRect>{};
popupOpen
? std::vector<UIRect>{ m_popupOverlay.layout.popupRect }
: std::vector<UIRect>{};
const std::vector<UIInputEvent> filteredEvents =
BuildUIEditorPanelInputEvents(
@@ -887,7 +888,9 @@ void InspectorPanel::Update(
popupBounds.empty() ? nullptr : &popupBounds);
const std::vector<UIInputEvent> contentEvents =
popupOpen
? BuildContentInputEventsExcludingPopup(filteredEvents, popupLayout.popupRect)
? BuildContentInputEventsExcludingPopup(
filteredEvents,
m_popupOverlay.layout.popupRect)
: filteredEvents;
TryClaimHostedPanelCommandFocus(
m_commandFocusService,
@@ -954,13 +957,34 @@ void InspectorPanel::Update(
}
}
if (popupOpen) {
HandlePropertyGridPopupOverlayInteraction(
context,
BuildPopupInputEvents(filteredEvents, popupLayout.popupRect));
RebuildScrollableLayout();
RebuildPropertyGridPopupOverlay();
if (m_popupOverlay.open) {
const UIEditorMenuPopupInteractionFrame popupFrame =
UpdateUIEditorMenuPopupInteraction(
m_popupInteractionState,
UIEditorMenuPopupInteractionRequest{
.layout = m_popupOverlay.layout,
.items = m_popupOverlay.items,
.preferredHighlightedItemId = {},
.closeOnFocusLost = false,
},
BuildPopupInputEvents(
filteredEvents,
m_popupOverlay.layout.popupRect));
m_popupOverlay.widgetState = popupFrame.popupState;
m_interactionState.propertyGridState.popupHighlightedIndex =
popupFrame.popupState.hoveredIndex;
if (popupFrame.result.itemActivated) {
ApplyPropertyGridPopupActivation(
context,
popupFrame.result.activatedIndex);
RebuildScrollableLayout();
RebuildPropertyGridPopupOverlay();
}
}
RebuildScrollableLayout();
UpdateAddComponentButton(context, contentEvents);
}
@@ -1068,14 +1092,7 @@ void InspectorPanel::Append(UIDrawList& drawList) const {
}
void InspectorPanel::AppendOverlay(UIDrawList& drawList) const {
if (!m_visible) {
return;
}
Widgets::UIEditorMenuPopupLayout popupLayout = {};
Widgets::UIEditorMenuPopupState popupState = {};
std::vector<Widgets::UIEditorMenuPopupItem> popupItems = {};
if (!BuildPropertyGridPopupRuntime(popupLayout, popupState, popupItems)) {
if (!m_visible || !m_popupOverlay.open) {
return;
}
@@ -1085,152 +1102,102 @@ void InspectorPanel::AppendOverlay(UIDrawList& drawList) const {
ResolveUIEditorMenuPopupPalette();
Widgets::AppendUIEditorMenuPopupBackground(
drawList,
popupLayout,
popupItems,
popupState,
m_popupOverlay.layout,
m_popupOverlay.items,
m_popupOverlay.widgetState,
popupPalette,
popupMetrics);
Widgets::AppendUIEditorMenuPopupForeground(
drawList,
popupLayout,
popupItems,
popupState,
m_popupOverlay.layout,
m_popupOverlay.items,
m_popupOverlay.widgetState,
popupPalette,
popupMetrics);
}
std::vector<UIRect> InspectorPanel::CollectInteractiveOverlayBounds() const {
Widgets::UIEditorMenuPopupLayout popupLayout = {};
Widgets::UIEditorMenuPopupState popupState = {};
std::vector<Widgets::UIEditorMenuPopupItem> popupItems = {};
if (!BuildPropertyGridPopupRuntime(popupLayout, popupState, popupItems) ||
popupLayout.popupRect.width <= 0.0f ||
popupLayout.popupRect.height <= 0.0f) {
if (!m_popupOverlay.open ||
m_popupOverlay.layout.popupRect.width <= 0.0f ||
m_popupOverlay.layout.popupRect.height <= 0.0f) {
return {};
}
return { popupLayout.popupRect };
return { m_popupOverlay.layout.popupRect };
}
bool InspectorPanel::BuildPropertyGridPopupRuntime(
Widgets::UIEditorMenuPopupLayout& popupLayout,
Widgets::UIEditorMenuPopupState& popupState,
std::vector<Widgets::UIEditorMenuPopupItem>& popupItems) const {
void InspectorPanel::RebuildPropertyGridPopupOverlay() {
m_popupOverlay = {};
if (!m_visible ||
m_gridFrame.layout.bounds.width <= 0.0f ||
m_gridFrame.layout.bounds.height <= 0.0f) {
return false;
ResetUIEditorMenuPopupInteractionState(m_popupInteractionState);
return;
}
return Widgets::BuildUIEditorPropertyGridPopupRuntime(
Widgets::UIEditorMenuPopupLayout popupLayout = {};
Widgets::UIEditorMenuPopupState popupState = {};
std::vector<Widgets::UIEditorMenuPopupItem> popupItems = {};
if (!Widgets::BuildUIEditorPropertyGridPopupRuntime(
m_gridFrame.layout,
m_presentation.sections,
m_interactionState.propertyGridState,
popupLayout,
popupState,
popupItems,
ResolveUIEditorMenuPopupMetrics());
ResolveUIEditorMenuPopupMetrics())) {
ResetUIEditorMenuPopupInteractionState(m_popupInteractionState);
return;
}
m_popupInteractionState.focused = popupState.focused;
const UIEditorMenuPopupInteractionFrame popupFrame =
UpdateUIEditorMenuPopupInteraction(
m_popupInteractionState,
UIEditorMenuPopupInteractionRequest{
.layout = popupLayout,
.items = popupItems,
.preferredHighlightedItemId = {},
.closeOnFocusLost = false,
},
{});
m_popupOverlay.open = true;
m_popupOverlay.layout = popupFrame.layout;
m_popupOverlay.widgetState = popupFrame.popupState;
m_popupOverlay.items = std::move(popupItems);
m_interactionState.propertyGridState.popupHighlightedIndex =
popupFrame.popupState.hoveredIndex;
}
bool InspectorPanel::HandlePropertyGridPopupOverlayInteraction(
bool InspectorPanel::ApplyPropertyGridPopupActivation(
InspectorPanelContext& context,
const std::vector<UIInputEvent>& inputEvents) {
if (inputEvents.empty()) {
std::size_t activatedIndex) {
const std::string popupFieldId = m_interactionState.propertyGridState.popupFieldId;
if (popupFieldId.empty()) {
return false;
}
Widgets::UIEditorMenuPopupLayout popupLayout = {};
Widgets::UIEditorMenuPopupState popupState = {};
std::vector<Widgets::UIEditorMenuPopupItem> popupItems = {};
if (!BuildPropertyGridPopupRuntime(popupLayout, popupState, popupItems)) {
m_interactionState.propertyGridState.popupFieldId.clear();
m_interactionState.propertyGridState.popupHighlightedIndex =
Widgets::UIEditorPropertyGridInvalidIndex;
ResetUIEditorMenuPopupInteractionState(m_popupInteractionState);
Widgets::UIEditorPropertyGridField* field =
FindMutableField(popupFieldId);
if (field == nullptr ||
field->kind != Widgets::UIEditorPropertyGridFieldKind::Enum ||
activatedIndex >= field->enumValue.options.size()) {
return false;
}
bool handled = false;
for (const UIInputEvent& event : inputEvents) {
const Widgets::UIEditorMenuPopupHitTarget hitTarget =
Widgets::HitTestUIEditorMenuPopup(
popupLayout,
popupItems,
event.position);
switch (event.type) {
case UIInputEventType::PointerMove:
case UIInputEventType::PointerEnter:
m_interactionState.propertyGridState.popupHighlightedIndex =
hitTarget.kind == Widgets::UIEditorMenuPopupHitTargetKind::Item &&
hitTarget.index < popupItems.size() &&
popupItems[hitTarget.index].enabled
? hitTarget.index
: Widgets::UIEditorMenuPopupInvalidIndex;
handled = true;
break;
case UIInputEventType::PointerButtonDown:
if (event.pointerButton != UIPointerButton::Left) {
break;
}
if (hitTarget.kind == Widgets::UIEditorMenuPopupHitTargetKind::Item &&
hitTarget.index < popupItems.size() &&
popupItems[hitTarget.index].enabled) {
m_interactionState.propertyGridState.focused = true;
m_interactionState.pressedPopupIndex = hitTarget.index;
handled = true;
} else if (hitTarget.kind ==
Widgets::UIEditorMenuPopupHitTargetKind::PopupSurface) {
m_interactionState.propertyGridState.focused = true;
handled = true;
}
break;
case UIInputEventType::PointerButtonUp:
if (event.pointerButton != UIPointerButton::Left) {
break;
}
if (m_interactionState.pressedPopupIndex !=
Widgets::UIEditorPropertyGridInvalidIndex &&
hitTarget.kind == Widgets::UIEditorMenuPopupHitTargetKind::Item &&
hitTarget.index == m_interactionState.pressedPopupIndex &&
hitTarget.index < popupItems.size() &&
popupItems[hitTarget.index].enabled) {
const std::string popupFieldId =
m_interactionState.propertyGridState.popupFieldId;
m_interactionState.propertyGridState.popupHighlightedIndex = hitTarget.index;
m_interactionState.propertyGridState.popupFieldId.clear();
m_interactionState.pressedPopupIndex =
Widgets::UIEditorPropertyGridInvalidIndex;
Widgets::UIEditorPropertyGridField* field =
FindMutableField(popupFieldId);
if (field != nullptr &&
field->kind == Widgets::UIEditorPropertyGridFieldKind::Enum &&
hitTarget.index < field->enumValue.options.size()) {
field->enumValue.selectedIndex = hitTarget.index;
if (ApplyChangedField(field->fieldId)) {
RefreshPresentation(context, false);
} else {
ForceResyncPresentation(context);
}
}
handled = true;
break;
}
if (hitTarget.kind != Widgets::UIEditorMenuPopupHitTargetKind::None) {
m_interactionState.pressedPopupIndex =
Widgets::UIEditorPropertyGridInvalidIndex;
handled = true;
}
break;
default:
break;
}
field->enumValue.selectedIndex = activatedIndex;
if (ApplyChangedField(field->fieldId)) {
RefreshPresentation(context, false);
} else {
ForceResyncPresentation(context);
}
return handled;
return true;
}
UIEditorHostCommandEvaluationResult InspectorPanel::EvaluateEditCommand(