253 lines
9.0 KiB
C++
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
|