diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp index f394c8b..e1c23a3 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp @@ -74,7 +74,7 @@ constexpr ox::Point fbPtToTileAddr( } WorldEditorImGui::WorldEditorImGui(studio::Context &sctx, ox::StringParam path): - Editor(sctx, std::move(path)), + Editor{sctx, std::move(path)}, m_sctx{sctx}, m_objSetPicker{"Object Set Chooser", keelCtx(m_sctx), FileExt_jwob}, m_doc{*keel::readObj(keelCtx(m_sctx), itemPath()).unwrapThrow()} { @@ -88,6 +88,7 @@ WorldEditorImGui::WorldEditorImGui(studio::Context &sctx, ox::StringParam path): keelCtx(m_sctx), itemPath(), [this](WorldEditorConfig const&config) { m_view.setAnimate(config.animateBg); }); + undoStack()->changeTriggered.connect(this, &WorldEditorImGui::handleUndoStackChange); } void WorldEditorImGui::draw(studio::Context&) noexcept { @@ -187,23 +188,57 @@ ox::Error WorldEditorImGui::saveItem() noexcept { return m_sctx.project->writeObj(itemPath(), m_doc, ox::ClawFormat::Organic); } -void WorldEditorImGui::drawObjSetSelector() noexcept { - ig::IDStackItem const idStackItem("ObjSetSelector"); +void WorldEditorImGui::drawObjSelector() noexcept { + ig::IDStackItem const idStackItem("ObjSelector"); if (ig::PushButton("+", SqrBtnSize)) { m_objSetPicker.open(); } ImGui::SameLine(); + ImGui::BeginDisabled(m_objMgr.selectedObjSet.len() == 0); if (ig::PushButton("-", SqrBtnSize)) { rmObjSet(); } - ig::ListBox("Object Sets", [this](size_t i) -> ox::CStringView { - auto const&uuidUrl = m_doc.objSets[i].path; - auto [setName, err] = uuidUrlToPath(keelCtx(m_sctx), uuidUrl); - if (err) { - setName = uuidUrl; + ImGui::EndDisabled(); + ImGui::BeginChild("ObjTree"); + { + for (auto const&[uuidUrl, setId, set] : m_objSets) { + auto flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + auto [setName, err] = uuidUrlToPath(keelCtx(m_sctx), uuidUrl); + auto const uuid = substr(uuidUrl, 7); + if (err) { + setName = uuidUrl; + } + if (uuid == m_objMgr.selectedObjSet) { + flags |= ImGuiTreeNodeFlags_Selected; + } + if (ImGui::TreeNodeEx(setName.c_str(), flags)) { + if (ImGui::IsItemClicked()) { + m_objMgr.selectedObjSet = uuid; + } + for (auto const&obj : set->objects) { + if (ImGui::TreeNodeEx(obj.name.c_str(), ImGuiTreeNodeFlags_Leaf)) { + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + studio::navigateTo(m_sctx, setName, obj.name); + } + ImGui::TreePop(); + } + ig::dragDropSource([&] { + std::ignore = ig::setDragDropPayload("WorldTile", WorldTileDragDrop{ + .setId = setId, + .objId = obj.id, + }); + ImGui::Text("%s", obj.name.c_str()); + }); + } + ImGui::TreePop(); + } else { + if (ImGui::IsItemClicked()) { + m_objMgr.selectedObjSet = uuid; + } + } } - return setName; - }, m_doc.objSets.size(), m_palMgr.selectedIdx); + } + ImGui::EndChild(); if (ig::DragDropTarget const d; d) { auto const [fr, err] = ig::getDragDropPayload("FileRef"); if (!err && endsWith(fr.path, FileExt_jwob)) { @@ -212,35 +247,6 @@ void WorldEditorImGui::drawObjSetSelector() noexcept { } } -void WorldEditorImGui::drawObjSelector() noexcept { - ig::IDStackItem const idStackItem("ObjSelector"); - for (auto const&[uuidUrl, setId, set] : m_objSets) { - constexpr auto flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - auto [setName, err] = uuidUrlToPath(keelCtx(m_sctx), uuidUrl); - if (err) { - setName = uuidUrl; - } - if (ImGui::TreeNodeEx(setName.c_str(), flags)) { - for (auto const&obj : set->objects) { - if (ImGui::TreeNodeEx(obj.name.c_str(), ImGuiTreeNodeFlags_Leaf)) { - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { - studio::navigateTo(m_sctx, setName, obj.name); - } - ImGui::TreePop(); - } - ig::dragDropSource([&] { - std::ignore = ig::setDragDropPayload("WorldTile", WorldTileDragDrop{ - .setId = setId, - .objId = obj.id, - }); - ImGui::Text("%s", obj.name.c_str()); - }); - } - ImGui::TreePop(); - } - } -} - void WorldEditorImGui::drawPropEditor() noexcept { if (m_sizeEditor.show) { constexpr auto popupSz = ImVec2{285, 0}; @@ -285,7 +291,6 @@ void WorldEditorImGui::drawMenu() noexcept { void WorldEditorImGui::drawResources() noexcept { ig::IDStackItem const idStackItem("Resources"); - drawObjSetSelector(); drawObjSelector(); } @@ -399,7 +404,13 @@ ox::Error WorldEditorImGui::addObjSet(ox::StringViewCR path) noexcept { } void WorldEditorImGui::rmObjSet() noexcept { - std::ignore = pushCommand(m_doc, m_palMgr.selectedIdx); + auto const idx = ox::find_if( + m_doc.objSets.begin(), m_doc.objSets.end(), [this](ObjectSetEntry const &e) { + return substr(e.path, 7) == m_objMgr.selectedObjSet; + }); + if (idx != m_doc.objSets.end()) { + std::ignore = pushCommand(m_doc, idx.offset()); + } } ox::Error WorldEditorImGui::handleDepUpdate(ox::StringViewCR, ox::UUID const&uuid) noexcept { @@ -458,4 +469,14 @@ ox::Error WorldEditorImGui::addDependency(ox::FileAddress const&fileAddr) noexce return {}; } +ox::Error WorldEditorImGui::handleUndoStackChange(studio::UndoCommand const*cmd) noexcept { + if (dynamic_cast(cmd)) { + return loadObjectSets(); + } + if (dynamic_cast(cmd)) { + return loadObjectSets(); + } + return {}; +} + } diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp index 7f1db39..ee35259 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp @@ -40,8 +40,8 @@ class WorldEditorImGui: public studio::Editor { WorldStaticLoader m_loader{keelCtx(m_sctx), m_worldStatic, m_doc}; WorldEditorView m_view{m_sctx, m_worldStatic}; struct { - size_t selectedIdx{}; - } m_palMgr; + ox::UUIDStr selectedObjSet; + } m_objMgr; struct { bool show{}; int columns{}; @@ -67,8 +67,6 @@ class WorldEditorImGui: public studio::Editor { ox::Error saveItem() noexcept final; private: - void drawObjSetSelector() noexcept; - void drawObjSelector() noexcept; void drawPropEditor() noexcept; @@ -101,6 +99,8 @@ class WorldEditorImGui: public studio::Editor { ox::Error addDependency(ox::FileAddress const&fileAddr) noexcept; + ox::Error handleUndoStackChange(studio::UndoCommand const*) noexcept; + [[nodiscard]] constexpr bool popupOpen() const noexcept { return m_sizeEditor.show;