feat(editor): improve scene edit save workflow
This commit is contained in:
parent
db78bed499
commit
f9083c4aec
@ -196,23 +196,38 @@ std::unordered_map<ImGuiID, MetaCoreEditorStateSnapshot>& MetaCoreGetComponentIn
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
std::vector<ImGuiID>& MetaCoreGetPendingComponentInspectorEditCommits() {
|
||||
static std::vector<ImGuiID> pendingCommits;
|
||||
return pendingCommits;
|
||||
}
|
||||
|
||||
void MetaCoreTrackComponentInspectorEdit(MetaCoreEditorContext& editorContext, const char* commandLabel, bool allowMerge) {
|
||||
auto& snapshots = MetaCoreGetComponentInspectorEditSnapshots();
|
||||
auto& pendingCommits = MetaCoreGetPendingComponentInspectorEditCommits();
|
||||
if (!pendingCommits.empty()) {
|
||||
const MetaCoreEditorStateSnapshot afterSnapshot = editorContext.CaptureStateSnapshot();
|
||||
for (const ImGuiID pendingItemId : pendingCommits) {
|
||||
const auto iterator = snapshots.find(pendingItemId);
|
||||
if (iterator != snapshots.end()) {
|
||||
(void)editorContext.CommitStateTransition(commandLabel, iterator->second, afterSnapshot, allowMerge);
|
||||
snapshots.erase(iterator);
|
||||
}
|
||||
}
|
||||
pendingCommits.clear();
|
||||
}
|
||||
|
||||
const ImGuiID itemId = ImGui::GetItemID();
|
||||
if (itemId == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& snapshots = MetaCoreGetComponentInspectorEditSnapshots();
|
||||
if (ImGui::IsItemActivated()) {
|
||||
snapshots[itemId] = editorContext.CaptureStateSnapshot();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
const auto iterator = snapshots.find(itemId);
|
||||
if (iterator != snapshots.end()) {
|
||||
const MetaCoreEditorStateSnapshot afterSnapshot = editorContext.CaptureStateSnapshot();
|
||||
(void)editorContext.CommitStateTransition(commandLabel, iterator->second, afterSnapshot, allowMerge);
|
||||
snapshots.erase(iterator);
|
||||
if (std::find(pendingCommits.begin(), pendingCommits.end(), itemId) == pendingCommits.end()) {
|
||||
pendingCommits.push_back(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2360,11 +2375,16 @@ std::optional<TValue> MetaCoreGetSharedSelectedValue(
|
||||
|
||||
template <typename TAccessor, typename TValue>
|
||||
void MetaCoreApplyValueToSelectedObjects(MetaCoreEditorContext& editorContext, TAccessor&& accessor, const TValue& value) {
|
||||
bool anyTarget = false;
|
||||
MetaCoreForEachSelectedGameObject(editorContext, [&](MetaCoreGameObject& selectedObject) {
|
||||
if (auto* targetValue = accessor(selectedObject); targetValue != nullptr) {
|
||||
*targetValue = value;
|
||||
anyTarget = true;
|
||||
}
|
||||
});
|
||||
if (anyTarget) {
|
||||
editorContext.GetScene().IncrementRevision();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -870,6 +871,11 @@ std::unordered_map<ImGuiID, MetaCoreEditorStateSnapshot>& MetaCoreGetInspectorEd
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
std::vector<ImGuiID>& MetaCoreGetPendingInspectorEditCommits() {
|
||||
static std::vector<ImGuiID> pendingCommits;
|
||||
return pendingCommits;
|
||||
}
|
||||
|
||||
void MetaCoreTrackInspectorEdit(MetaCoreEditorContext& editorContext, const char* commandLabel, bool allowMerge);
|
||||
|
||||
template <typename TAccessor>
|
||||
@ -2093,22 +2099,32 @@ struct MetaCoreTextureAssetChoicesCache {
|
||||
}
|
||||
|
||||
void MetaCoreTrackInspectorEdit(MetaCoreEditorContext& editorContext, const char* commandLabel, bool allowMerge) {
|
||||
auto& snapshots = MetaCoreGetInspectorEditSnapshots();
|
||||
auto& pendingCommits = MetaCoreGetPendingInspectorEditCommits();
|
||||
if (!pendingCommits.empty()) {
|
||||
const MetaCoreEditorStateSnapshot afterSnapshot = editorContext.CaptureStateSnapshot();
|
||||
for (const ImGuiID pendingItemId : pendingCommits) {
|
||||
const auto iterator = snapshots.find(pendingItemId);
|
||||
if (iterator != snapshots.end()) {
|
||||
(void)editorContext.CommitStateTransition(commandLabel, iterator->second, afterSnapshot, allowMerge);
|
||||
snapshots.erase(iterator);
|
||||
}
|
||||
}
|
||||
pendingCommits.clear();
|
||||
}
|
||||
|
||||
const ImGuiID itemId = ImGui::GetItemID();
|
||||
if (itemId == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& snapshots = MetaCoreGetInspectorEditSnapshots();
|
||||
if (ImGui::IsItemActivated()) {
|
||||
snapshots[itemId] = editorContext.CaptureStateSnapshot();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
const auto iterator = snapshots.find(itemId);
|
||||
if (iterator != snapshots.end()) {
|
||||
const MetaCoreEditorStateSnapshot afterSnapshot = editorContext.CaptureStateSnapshot();
|
||||
(void)editorContext.CommitStateTransition(commandLabel, iterator->second, afterSnapshot, allowMerge);
|
||||
snapshots.erase(iterator);
|
||||
if (std::find(pendingCommits.begin(), pendingCommits.end(), itemId) == pendingCommits.end()) {
|
||||
pendingCommits.push_back(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5219,7 +5235,7 @@ public:
|
||||
editorContext.ClearSelection();
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
if (item.Type == "scene" && scenePersistenceService) (void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
if (item.Type == "scene" && scenePersistenceService) RequestOpenScene(editorContext, *scenePersistenceService, item.Path);
|
||||
else if (item.Type == "model") (void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
else if (item.Type == "prefab") (void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
}
|
||||
@ -5260,7 +5276,7 @@ public:
|
||||
} else {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
if (item.Type == "scene" && scenePersistenceService) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
RequestOpenScene(editorContext, *scenePersistenceService, item.Path);
|
||||
} else if (item.Type == "model") {
|
||||
(void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
} else if (item.Type == "prefab") {
|
||||
@ -5556,7 +5572,7 @@ public:
|
||||
editorContext.ClearSelection();
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
if (item.Type == "scene" && scenePersistenceService) (void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
if (item.Type == "scene" && scenePersistenceService) RequestOpenScene(editorContext, *scenePersistenceService, item.Path);
|
||||
else if (item.Type == "model") (void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
else if (item.Type == "prefab") (void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
}
|
||||
@ -5597,7 +5613,7 @@ public:
|
||||
} else {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
if (item.Type == "scene" && scenePersistenceService) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
RequestOpenScene(editorContext, *scenePersistenceService, item.Path);
|
||||
} else if (item.Type == "model") {
|
||||
(void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
} else if (item.Type == "prefab") {
|
||||
@ -5777,7 +5793,74 @@ public:
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
DrawPendingOpenScenePopup(editorContext, scenePersistenceService);
|
||||
}
|
||||
|
||||
private:
|
||||
void RequestOpenScene(
|
||||
MetaCoreEditorContext& editorContext,
|
||||
MetaCoreIScenePersistenceService& scenePersistenceService,
|
||||
const std::filesystem::path& scenePath
|
||||
) {
|
||||
if (!scenePersistenceService.IsSceneDirty()) {
|
||||
(void)scenePersistenceService.LoadScene(editorContext, scenePath);
|
||||
return;
|
||||
}
|
||||
|
||||
PendingOpenScenePath_ = scenePath;
|
||||
OpenPendingScenePopup_ = true;
|
||||
}
|
||||
|
||||
void DrawPendingOpenScenePopup(
|
||||
MetaCoreEditorContext& editorContext,
|
||||
const std::shared_ptr<MetaCoreIScenePersistenceService>& scenePersistenceService
|
||||
) {
|
||||
if (scenePersistenceService == nullptr) {
|
||||
PendingOpenScenePath_.clear();
|
||||
OpenPendingScenePopup_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPendingScenePopup_) {
|
||||
ImGui::OpenPopup("Unsaved Scene Changes");
|
||||
OpenPendingScenePopup_ = false;
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("Unsaved Scene Changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
const std::string currentScene = scenePersistenceService->HasOpenScene()
|
||||
? scenePersistenceService->GetCurrentSceneDisplayName()
|
||||
: std::string("Untitled");
|
||||
ImGui::Text("Save changes to %s before opening another scene?", currentScene.c_str());
|
||||
ImGui::TextDisabled("Next scene: %s", PendingOpenScenePath_.generic_string().c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("Save and Open", ImVec2(130, 0))) {
|
||||
if (scenePersistenceService->SaveCurrentScene(editorContext)) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, PendingOpenScenePath_);
|
||||
PendingOpenScenePath_.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
} else {
|
||||
editorContext.AddConsoleMessage(MetaCoreLogLevel::Error, "Scene", "保存失败,已取消切换场景");
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Don't Save", ImVec2(110, 0))) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, PendingOpenScenePath_);
|
||||
PendingOpenScenePath_.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", ImVec2(90, 0))) {
|
||||
PendingOpenScenePath_.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path PendingOpenScenePath_{};
|
||||
bool OpenPendingScenePopup_ = false;
|
||||
};
|
||||
|
||||
class MetaCoreConsolePanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
@ -7475,6 +7558,9 @@ private:
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 4));
|
||||
|
||||
ImGuiID editedItemId = 0;
|
||||
bool editedItemDeactivated = false;
|
||||
|
||||
auto drawComponent = [&](const char* compLabel, float& val, const ImVec4& color) {
|
||||
ImGui::TextColored(color, "%s", compLabel);
|
||||
ImGui::SameLine();
|
||||
@ -7487,7 +7573,15 @@ private:
|
||||
else if (compLabel[0] == 'Y') { displayValues.x *= ratio; displayValues.z *= ratio; }
|
||||
else if (compLabel[0] == 'Z') { displayValues.x *= ratio; displayValues.y *= ratio; }
|
||||
}
|
||||
MetaCoreTrackInspectorEdit(editorContext, "修改检查器属性", true);
|
||||
}
|
||||
|
||||
const ImGuiID itemId = ImGui::GetItemID();
|
||||
if (itemId != 0 && ImGui::IsItemActivated()) {
|
||||
MetaCoreGetInspectorEditSnapshots()[itemId] = editorContext.CaptureStateSnapshot();
|
||||
}
|
||||
if (itemId != 0 && ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
editedItemId = itemId;
|
||||
editedItemDeactivated = true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -7508,16 +7602,30 @@ private:
|
||||
values = displayValues;
|
||||
}
|
||||
|
||||
if (editedItemDeactivated && editedItemId != 0) {
|
||||
auto& snapshots = MetaCoreGetInspectorEditSnapshots();
|
||||
const auto iterator = snapshots.find(editedItemId);
|
||||
if (iterator != snapshots.end()) {
|
||||
const MetaCoreEditorStateSnapshot afterSnapshot = editorContext.CaptureStateSnapshot();
|
||||
(void)editorContext.CommitStateTransition("修改检查器属性", iterator->second, afterSnapshot, true);
|
||||
snapshots.erase(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextItem("TransformContext")) {
|
||||
if (ImGui::MenuItem("Reset")) {
|
||||
MetaCoreApplyValueToSelectedObjects(
|
||||
editorContext,
|
||||
[&](MetaCoreGameObject& selectedObject) -> glm::vec3* {
|
||||
return getTargetValue(selectedObject);
|
||||
},
|
||||
glm::vec3(resetValue)
|
||||
);
|
||||
values = glm::vec3(resetValue);
|
||||
const glm::vec3 resetVec(resetValue);
|
||||
(void)editorContext.ExecuteSnapshotCommand("重置 Transform 字段", [&]() {
|
||||
MetaCoreApplyValueToSelectedObjects(
|
||||
editorContext,
|
||||
[&](MetaCoreGameObject& selectedObject) -> glm::vec3* {
|
||||
return getTargetValue(selectedObject);
|
||||
},
|
||||
resetVec
|
||||
);
|
||||
return true;
|
||||
});
|
||||
values = resetVec;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
@ -1494,6 +1494,34 @@ void MetaCoreEditorApp::DrawEditorStatusBar() {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
const auto scenePersistenceService = ModuleRegistry_.ResolveService<MetaCoreIScenePersistenceService>();
|
||||
std::string sceneStatus = "No Scene";
|
||||
ImVec4 sceneStatusColor(0.55F, 0.55F, 0.55F, 1.00F);
|
||||
if (scenePersistenceService != nullptr && scenePersistenceService->HasOpenScene()) {
|
||||
const bool sceneDirty = scenePersistenceService->IsSceneDirty();
|
||||
sceneStatus = scenePersistenceService->GetCurrentSceneDisplayName();
|
||||
sceneStatus += sceneDirty ? " * Unsaved" : " Saved";
|
||||
sceneStatusColor = sceneDirty
|
||||
? ImVec4(0.890F, 0.710F, 0.300F, 1.00F)
|
||||
: ImVec4(0.55F, 0.70F, 0.55F, 1.00F);
|
||||
}
|
||||
|
||||
const float sceneStatusWidth = std::min(300.0F, std::max(120.0F, leftZoneW * 0.32F));
|
||||
const float sceneStatusX = std::max(0.0F, leftZoneW - sceneStatusWidth - 140.0F);
|
||||
if (sceneStatusX > ImGui::GetCursorPosX()) {
|
||||
ImGui::SameLine(sceneStatusX);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, sceneStatusColor);
|
||||
ImGui::TextUnformatted(sceneStatus.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::IsItemHovered() && scenePersistenceService != nullptr && scenePersistenceService->HasOpenScene()) {
|
||||
ImGui::SetTooltip(
|
||||
"%s\n%s",
|
||||
scenePersistenceService->GetCurrentScenePath().generic_string().c_str(),
|
||||
scenePersistenceService->IsSceneDirty() ? "Unsaved changes" : "Scene saved"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Engine status (right zone)
|
||||
float statusX = leftZoneW + 8.0F;
|
||||
ImGui::SameLine(statusX);
|
||||
|
||||
@ -566,6 +566,7 @@ void MetaCoreSceneInteractionService::HandleGizmoManipulation(MetaCoreEditorCont
|
||||
}
|
||||
|
||||
MetaCoreApplyMatrixToTransform(newLocalMatrix, selectedObject.GetComponent<MetaCoreTransformComponent>());
|
||||
editorContext.GetScene().IncrementRevision();
|
||||
}
|
||||
|
||||
HandleGizmoEndUse(editorContext, gizmoUsing);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user