Files
UsdLayerManager/src/ui/LayerPanel.cpp
T
2026-06-03 09:00:11 +08:00

253 lines
9.0 KiB
C++

#include "LayerPanel.h"
#include "../utils/Logger.h"
#include "../core/commands/LayerCommands.h"
#include <imgui.h>
#include <memory>
namespace UsdLayerManager {
LayerPanel::LayerPanel()
: m_layerManager(nullptr)
, m_selectedLayerIndex(-1)
, m_showCreateDialog(false) {
m_newLayerPath[0] = '\0';
m_newLayerName[0] = '\0';
}
LayerPanel::~LayerPanel() {
}
void LayerPanel::SetLayerManager(LayerManager* manager) {
m_layerManager = manager;
}
void LayerPanel::Render() {
if (!m_layerManager) return;
// Header with buttons
ImGui::Text("Layers");
ImGui::SameLine(ImGui::GetWindowWidth() - 110);
if (ImGui::Button("Refresh")) {
m_layerManager->Refresh();
}
ImGui::SameLine();
if (ImGui::Button("Add Layer")) {
m_showCreateDialog = true;
m_newLayerPath[0] = '\0';
strcpy_s(m_newLayerName, "new_layer.usd");
}
ImGui::Separator();
// Create layer dialog
if (m_showCreateDialog) {
ShowCreateLayerDialog();
}
// Layer list
auto layers = m_layerManager->GetLayerStack();
if (layers.empty()) {
ImGui::TextDisabled("No layers loaded");
return;
}
// Layer table
if (ImGui::BeginTable("LayerTable", 4,
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) {
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 20.0f);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Muted", ImGuiTableColumnFlags_WidthFixed, 60.0f);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 80.0f);
ImGui::TableHeadersRow();
for (int i = 0; i < static_cast<int>(layers.size()); i++) {
const auto& layerInfo = layers[i];
ImGui::TableNextRow();
bool isSelected = (m_selectedLayerIndex == i);
// Selection column
ImGui::TableSetColumnIndex(0);
ImGui::PushID(i);
if (ImGui::Selectable("##select", isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap)) {
m_selectedLayerIndex = i;
}
ImGui::PopID();
// Name column
ImGui::TableSetColumnIndex(1);
ImVec4 textColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
if (layerInfo.isMuted) {
textColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
} else if (layerInfo.isRootLayer) {
textColor = ImVec4(0.5f, 1.0f, 0.5f, 1.0f);
} else if (layerInfo.isSessionLayer) {
textColor = ImVec4(0.5f, 0.7f, 1.0f, 1.0f);
}
ImGui::TextColored(textColor, "%s", layerInfo.displayName.c_str());
if (ImGui::IsItemHovered() && !layerInfo.realPath.empty()) {
ImGui::SetTooltip("%s\n%s", layerInfo.identifier.c_str(), layerInfo.realPath.c_str());
}
// Mute toggle
ImGui::TableSetColumnIndex(2);
bool muted = layerInfo.isMuted;
ImGui::PushID(("mute_" + std::to_string(i)).c_str());
if (ImGui::Checkbox("##muted", &muted)) {
if (muted) {
m_layerManager->MuteLayer(layerInfo.identifier);
} else {
m_layerManager->UnmuteLayer(layerInfo.identifier);
}
}
ImGui::PopID();
// Type column
ImGui::TableSetColumnIndex(3);
if (layerInfo.isRootLayer) {
ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.5f, 1.0f), "Root");
} else if (layerInfo.isSessionLayer) {
ImGui::TextColored(ImVec4(0.5f, 0.7f, 1.0f, 1.0f), "Session");
} else if (layerInfo.isAnonymous) {
ImGui::Text("Anonymous");
} else {
ImGui::Text("Sublayer");
}
// Context menu
RenderLayerContextMenu(i);
}
ImGui::EndTable();
}
}
void LayerPanel::RenderLayerContextMenu(int layerIndex) {
if (ImGui::BeginPopupContextItem(("layer_ctx_" + std::to_string(layerIndex)).c_str())) {
auto layers = m_layerManager->GetLayerStack();
if (layerIndex < 0 || layerIndex >= static_cast<int>(layers.size())) {
ImGui::EndPopup();
return;
}
const auto& info = layers[layerIndex];
if (ImGui::MenuItem(info.isMuted ? "Unmute" : "Mute")) {
if (info.isMuted) {
m_layerManager->UnmuteLayer(info.identifier);
} else {
m_layerManager->MuteLayer(info.identifier);
}
}
ImGui::Separator();
if (!info.isRootLayer && !info.isSessionLayer) {
if (ImGui::MenuItem("Move Up", nullptr, false, layerIndex > 0)) {
if (m_commandHistory) {
// Capture order before move.
auto layers = m_layerManager->GetLayerStack();
std::vector<std::string> before, after;
for (auto& l : layers)
if (!l.isRootLayer && !l.isSessionLayer)
before.push_back(l.identifier);
after = before;
// Find index within sublayer-only list.
int subIdx = -1;
for (int i = 0; i < static_cast<int>(before.size()); ++i)
if (before[i] == info.identifier) { subIdx = i; break; }
if (subIdx > 0) std::swap(after[subIdx], after[subIdx - 1]);
m_commandHistory->Push(std::make_unique<LayerReorderCommand>(
m_layerManager, before, after));
} else {
m_layerManager->MoveSublayerUp(layerIndex);
}
}
if (ImGui::MenuItem("Move Down", nullptr, false, layerIndex < static_cast<int>(layers.size()) - 1)) {
if (m_commandHistory) {
auto layersNow = m_layerManager->GetLayerStack();
std::vector<std::string> before, after;
for (auto& l : layersNow)
if (!l.isRootLayer && !l.isSessionLayer)
before.push_back(l.identifier);
after = before;
int subIdx = -1;
for (int i = 0; i < static_cast<int>(before.size()); ++i)
if (before[i] == info.identifier) { subIdx = i; break; }
if (subIdx >= 0 && subIdx + 1 < static_cast<int>(after.size()))
std::swap(after[subIdx], after[subIdx + 1]);
m_commandHistory->Push(std::make_unique<LayerReorderCommand>(
m_layerManager, before, after));
} else {
m_layerManager->MoveSublayerDown(layerIndex);
}
}
ImGui::Separator();
if (ImGui::MenuItem("Remove")) {
if (m_commandHistory) {
m_commandHistory->Push(std::make_unique<LayerRemoveCommand>(
m_layerManager, layerIndex));
} else {
m_layerManager->RemoveSublayer(layerIndex);
}
}
}
ImGui::EndPopup();
}
}
void LayerPanel::ShowCreateLayerDialog() {
ImGui::SetNextWindowSize(ImVec2(400, 150), ImGuiCond_Always);
ImGui::OpenPopup("Create New Layer");
if (ImGui::BeginPopupModal("Create New Layer", &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::SameLine();
if (ImGui::Button("Browse...")) {
// TODO: File save dialog
}
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<LayerCreateCommand>(
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