From a62764397cb95312d8c007d186b26eb5ff57a425 Mon Sep 17 00:00:00 2001 From: indigo Date: Tue, 16 Jun 2026 03:49:35 +0800 Subject: [PATCH] Scene Hierarchy ET switcher + Create Sublayer via Save dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add edit-target layer combo at top of Scene Hierarchy panel (always visible when stage loaded — session, root, sublayers); routes through LayerManager::SetEditTarget so StageEditor ET checkboxes stay in sync - Replace custom Create Sublayer modal with native SaveFile dialog; LayerManager::CreateNewSublayer creates the file on disk, inserts it at the top of the sublayer stack, and activates it as edit target Co-Authored-By: Claude Sonnet 4.6 --- src/core/LayerManager.cpp | 18 +++++++++++ src/core/LayerManager.h | 3 ++ src/ui/Application.cpp | 1 + src/ui/SceneHierarchyPanel.cpp | 57 ++++++++++++++++++++++++++++++++++ src/ui/SceneHierarchyPanel.h | 3 ++ src/ui/StageEditorPanel.cpp | 54 +++++--------------------------- src/ui/StageEditorPanel.h | 4 --- 7 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/core/LayerManager.cpp b/src/core/LayerManager.cpp index bdbd74f..e1491d0 100644 --- a/src/core/LayerManager.cpp +++ b/src/core/LayerManager.cpp @@ -157,6 +157,24 @@ bool LayerManager::SetEditTarget(const std::string& identifier) { return true; } +bool LayerManager::CreateNewSublayer(const std::string& absolutePath) { + if (!m_stage) return false; + SdfLayerHandle rootLayer = m_stage->GetRootLayer(); + if (!rootLayer) return false; + + auto newLayer = SdfLayer::CreateNew(absolutePath); + if (!newLayer) { + LOG_ERROR("Failed to create layer file: " + absolutePath); + return false; + } + newLayer->Save(); + + rootLayer->InsertSubLayerPath(absolutePath, 0); + m_stage->SetEditTarget(newLayer); + Refresh(); + return true; +} + bool LayerManager::IsLayerMuted(const std::string& layerIdentifier) const { if (m_stage) { return m_stage->IsLayerMuted(layerIdentifier); diff --git a/src/core/LayerManager.h b/src/core/LayerManager.h index c84e37a..9e585e8 100644 --- a/src/core/LayerManager.h +++ b/src/core/LayerManager.h @@ -44,6 +44,9 @@ public: // Edit target bool SetEditTarget(const std::string& identifier); + // Create a new USD file on disk, insert as sublayer, and activate as edit target. + bool CreateNewSublayer(const std::string& absolutePath); + // Muting void MuteLayer(const std::string& layerIdentifier); void UnmuteLayer(const std::string& layerIdentifier); diff --git a/src/ui/Application.cpp b/src/ui/Application.cpp index fb70f4e..1eff908 100644 --- a/src/ui/Application.cpp +++ b/src/ui/Application.cpp @@ -69,6 +69,7 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig m_sceneHierarchyPanel = std::make_unique(); m_sceneHierarchyPanel->SetPropertyManager(m_propertyManager.get()); m_sceneHierarchyPanel->SetCommandHistory(&m_commandHistory); + m_sceneHierarchyPanel->SetLayerManager(m_layerManager.get()); m_viewportPanel = std::make_unique(); m_viewportPanel->SetCommandHistory(&m_commandHistory); m_propertyPanel = std::make_unique(); diff --git a/src/ui/SceneHierarchyPanel.cpp b/src/ui/SceneHierarchyPanel.cpp index 3c119aa..fa48a0d 100644 --- a/src/ui/SceneHierarchyPanel.cpp +++ b/src/ui/SceneHierarchyPanel.cpp @@ -119,6 +119,63 @@ void SceneHierarchyPanel::Render() { return; } + // ── Edit-target layer switcher ──────────────────────────────────── + { + struct LayerEntry { SdfLayerHandle layer; std::string label; }; + std::vector layers; + + auto sessionLayer = m_stage->GetSessionLayer(); + if (sessionLayer) + layers.push_back({ sessionLayer, "Session" }); + + auto rootLayer = m_stage->GetRootLayer(); + if (rootLayer) { + std::string name = rootLayer->IsAnonymous() + ? "anonymous" + : std::filesystem::path(rootLayer->GetIdentifier()).filename().string(); + layers.push_back({ rootLayer, "Root: " + name }); + + for (const auto& subPath : rootLayer->GetSubLayerPaths()) { + auto sub = SdfLayer::FindOrOpenRelativeToLayer(rootLayer, subPath); + if (!sub) continue; + std::string subName = sub->IsAnonymous() + ? sub->GetIdentifier() + : std::filesystem::path(sub->GetIdentifier()).filename().string(); + layers.push_back({ SdfLayerHandle(sub), subName }); + } + } + + std::string currentLabel = "\xe2\x80\x94"; // em dash + auto etLayer = m_stage->GetEditTarget().GetLayer(); + if (etLayer) { + for (const auto& e : layers) { + if (e.layer && e.layer->GetIdentifier() == etLayer->GetIdentifier()) { + currentLabel = e.label; + break; + } + } + } + + ImGui::SetNextItemWidth(-1.0f); + if (ImGui::BeginCombo("##layerswitch", currentLabel.c_str(), + ImGuiComboFlags_HeightRegular)) { + for (const auto& e : layers) { + bool isCurrent = (e.layer && etLayer && + e.layer->GetIdentifier() == etLayer->GetIdentifier()); + if (ImGui::Selectable(e.label.c_str(), isCurrent)) { + if (m_layerManager) + m_layerManager->SetEditTarget(e.layer->GetIdentifier()); + else + m_stage->SetEditTarget(UsdEditTarget(e.layer)); + } + if (isCurrent) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + ImGui::Spacing(); + } + auto paths = m_propertyManager->GetPrimPaths(); if (paths.empty()) { ImGui::TextDisabled("No prims in stage"); diff --git a/src/ui/SceneHierarchyPanel.h b/src/ui/SceneHierarchyPanel.h index ef18069..d8d3834 100644 --- a/src/ui/SceneHierarchyPanel.h +++ b/src/ui/SceneHierarchyPanel.h @@ -2,6 +2,7 @@ #include "../core/PropertyManager.h" #include "../core/CommandHistory.h" +#include "../core/LayerManager.h" #include "IconManager.h" #include #include @@ -24,6 +25,7 @@ public: void SetPropertyManager(PropertyManager* manager); void SetCommandHistory(CommandHistory* history) { m_commandHistory = history; } + void SetLayerManager(LayerManager* lm) { m_layerManager = lm; } void SetStage(UsdStageRefPtr stage); void SetIconManager(IconManager* iconManager) { m_iconManager = iconManager; } void Render(); @@ -74,6 +76,7 @@ private: PropertyManager* m_propertyManager; CommandHistory* m_commandHistory = nullptr; + LayerManager* m_layerManager = nullptr; IconManager* m_iconManager = nullptr; UsdStageRefPtr m_stage; diff --git a/src/ui/StageEditorPanel.cpp b/src/ui/StageEditorPanel.cpp index 8711a33..9a2a5fe 100644 --- a/src/ui/StageEditorPanel.cpp +++ b/src/ui/StageEditorPanel.cpp @@ -7,10 +7,7 @@ namespace UsdLayerManager { -StageEditorPanel::StageEditorPanel() { - m_newLayerPath[0] = '\0'; - m_newLayerName[0] = '\0'; -} +StageEditorPanel::StageEditorPanel() {} StageEditorPanel::~StageEditorPanel() {} @@ -51,9 +48,12 @@ void StageEditorPanel::Render() { ImGui::SameLine(); if (iconBtn("##createNew", Icon::FilePlus, "+N")) { - m_showCreateDialog = true; - m_newLayerPath[0] = '\0'; - strcpy_s(m_newLayerName, "new_layer.usd"); + std::string path = FileDialog::SaveFile( + "USD Files (*.usd;*.usda;*.usdc)\0*.usd;*.usda;*.usdc\0All Files (*.*)\0*.*\0", + "Create New Sublayer", + "usd"); + if (!path.empty() && m_layerManager) + m_layerManager->CreateNewSublayer(path); } if (ImGui::IsItemHovered()) ImGui::SetTooltip("Create New Sublayer"); @@ -62,7 +62,6 @@ void StageEditorPanel::Render() { auto allLayers = m_layerManager->GetLayerStack(); if (allLayers.empty()) { ImGui::TextDisabled("No stage loaded"); - if (m_showCreateDialog) ShowCreateLayerDialog(); return; } @@ -82,7 +81,6 @@ void StageEditorPanel::Render() { RenderSublayerList(sublayers); - if (m_showCreateDialog) ShowCreateLayerDialog(); } // --------------------------------------------------------------------------- @@ -350,43 +348,5 @@ void StageEditorPanel::RenderSublayerContextMenu(int i, ImGui::EndPopup(); } -// --------------------------------------------------------------------------- -void StageEditorPanel::ShowCreateLayerDialog() { - ImGui::SetNextWindowSize(ImVec2(400, 150), ImGuiCond_Always); - ImGui::OpenPopup("Create Sublayer"); - - if (ImGui::BeginPopupModal("Create Sublayer", &m_showCreateDialog)) { - ImGui::Text("Layer Name:"); - ImGui::InputText("##name", m_newLayerName, sizeof(m_newLayerName)); - - ImGui::Spacing(); - ImGui::Text("Save Path:"); - ImGui::InputText("##path", m_newLayerPath, sizeof(m_newLayerPath)); - - ImGui::Spacing(); - - if (ImGui::Button("Create", ImVec2(120, 0))) { - std::string path; - if (m_newLayerPath[0] != '\0') - path = std::string(m_newLayerPath) + "/" + m_newLayerName; - else - path = m_newLayerName; - - if (!path.empty()) { - if (m_commandHistory) - m_commandHistory->Push(std::make_unique( - m_layerManager, "./" + path)); - else - m_layerManager->CreateSublayer("./" + path); - m_showCreateDialog = false; - } - } - ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(120, 0))) - m_showCreateDialog = false; - - ImGui::EndPopup(); - } -} } // namespace UsdLayerManager diff --git a/src/ui/StageEditorPanel.h b/src/ui/StageEditorPanel.h index 399b586..e90fbf1 100644 --- a/src/ui/StageEditorPanel.h +++ b/src/ui/StageEditorPanel.h @@ -23,15 +23,11 @@ private: void RenderFixedLayers(const std::vector& layers); void RenderSublayerList(const std::vector& sublayers); void RenderSublayerContextMenu(int i, const std::vector& sublayers); - void ShowCreateLayerDialog(); LayerManager* m_layerManager = nullptr; CommandHistory* m_commandHistory = nullptr; IconManager* m_iconManager = nullptr; int m_selectedIdx = -1; - bool m_showCreateDialog = false; - char m_newLayerPath[256]; - char m_newLayerName[128]; }; } // namespace UsdLayerManager