diff --git a/src/nostalgia/modules/gfx/include/nostalgia/gfx/tilesheet.hpp b/src/nostalgia/modules/gfx/include/nostalgia/gfx/tilesheet.hpp index 3a67adc2..30355112 100644 --- a/src/nostalgia/modules/gfx/include/nostalgia/gfx/tilesheet.hpp +++ b/src/nostalgia/modules/gfx/include/nostalgia/gfx/tilesheet.hpp @@ -289,7 +289,7 @@ constexpr ox::Error repair(TileSheetV4 &ts) noexcept { struct TileSheetV5 { - using SubSheetIdx = ox::Vector; + using SubSheetIdx = ox::Vector; struct SubSheet { static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet.SubSheet"; @@ -445,23 +445,25 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe [[nodiscard]] TileSheet::SubSheet const&getSubSheet( - TileSheet::SubSheetIdx const&idx, + ox::SpanView const&idx, std::size_t idxIt, TileSheet::SubSheet const&pSubsheet) noexcept; [[nodiscard]] TileSheet::SubSheet &getSubSheet( - TileSheet::SubSheetIdx const&idx, + ox::SpanView const&idx, std::size_t idxIt, TileSheet::SubSheet &pSubsheet) noexcept; [[nodiscard]] -TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, TileSheet::SubSheetIdx const&idx) noexcept; +TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, ox::SpanView const &idx) noexcept; [[nodiscard]] -TileSheet::SubSheet &getSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept; +TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView const &idx) noexcept; -ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept; +ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept; + +ox::Error insertSubSheet(TileSheet &ts, ox::SpanView const &idx, TileSheet::SubSheet ss) noexcept; ox::Error rmSubSheet( TileSheet &ts, diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/CMakeLists.txt b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/CMakeLists.txt index df125ef6..f8f42c87 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/CMakeLists.txt +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources( deletetilescommand.cpp drawcommand.cpp flipcommand.cpp + movesubsheetcommand.cpp inserttilescommand.cpp palettechangecommand.cpp rmsubsheetcommand.cpp diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/commands.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/commands.hpp index 5d8302eb..4cdebe6b 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/commands.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/commands.hpp @@ -15,9 +15,10 @@ enum class CommandId { AddSubSheet, RmSubSheet, DeleteTile, - FlipXCommand, - FlipYCommand, + FlipX, + FlipY, InsertTile, + MoveSubSheet, UpdateSubSheet, Cut, Paste, diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/flipcommand.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/flipcommand.cpp index 6acc1274..a3fd2ac8 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/flipcommand.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/flipcommand.cpp @@ -31,7 +31,7 @@ ox::Error FlipXCommand::undo() noexcept { } int FlipXCommand::commandId() const noexcept { - return static_cast(CommandId::FlipXCommand); + return static_cast(CommandId::FlipX); } TileSheet::SubSheetIdx const &FlipXCommand::subsheetIdx() const noexcept { @@ -62,7 +62,7 @@ ox::Error FlipYCommand::undo() noexcept { } int FlipYCommand::commandId() const noexcept { - return static_cast(CommandId::FlipYCommand); + return static_cast(CommandId::FlipY); } TileSheet::SubSheetIdx const &FlipYCommand::subsheetIdx() const noexcept { diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.cpp new file mode 100644 index 00000000..d251d93a --- /dev/null +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "movesubsheetcommand.hpp" + +namespace nostalgia::gfx { + +MoveSubSheetCommand::MoveSubSheetCommand( + TileSheet &img, + TileSheet::SubSheetIdx src, + TileSheet::SubSheetIdx dst) noexcept: + m_img{img}, + m_src{std::move(src)}, + m_dst{std::move(dst)} { +} + +ox::Error MoveSubSheetCommand::redo() noexcept { + m_active = &m_dst; + TileSheet::SubSheet ss = std::move(getSubSheet(m_img, m_src)); + OX_RETURN_ERROR(rmSubSheet(m_img, m_src)); + return insertSubSheet(m_img, m_dst, std::move(ss)); +} + +ox::Error MoveSubSheetCommand::undo() noexcept { + m_active = &m_src; + TileSheet::SubSheet ss = std::move(getSubSheet(m_img, m_dst)); + OX_RETURN_ERROR(rmSubSheet(m_img, m_dst)); + return insertSubSheet(m_img, m_src, std::move(ss)); +} + +int MoveSubSheetCommand::commandId() const noexcept { + return static_cast(CommandId::MoveSubSheet); +} + +TileSheet::SubSheetIdx const&MoveSubSheetCommand::subsheetIdx() const noexcept { + return *m_active; +} + +} diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.hpp new file mode 100644 index 00000000..06fc9dd9 --- /dev/null +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.hpp @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include "commands.hpp" + +namespace nostalgia::gfx { + +class MoveSubSheetCommand: public TileSheetCommand { + private: + TileSheet &m_img; + TileSheet::SubSheetIdx m_src; + TileSheet::SubSheetIdx m_dst; + TileSheet::SubSheetIdx *m_active = &m_dst; + + public: + MoveSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept; + + ox::Error redo() noexcept final; + + ox::Error undo() noexcept final; + + [[nodiscard]] + int commandId() const noexcept final; + + [[nodiscard]] + TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; + +}; + +} diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp index c45a6692..d9677cc9 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp @@ -15,6 +15,16 @@ namespace nostalgia::gfx { namespace ig = studio::ig; +struct SubSheetRef { + static constexpr auto TypeName = "nostalgia.gfx.studio.SubSheetRef"; + static constexpr auto TypeVersion = 1; + TileSheet::SubSheetIdx subsheet{}; +}; + +OX_MODEL_BEGIN(SubSheetRef) + OX_MODEL_FIELD(subsheet) +OX_MODEL_END() + struct TileSheetEditorConfig { static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetEditorConfig"; static constexpr auto TypeVersion = 1; @@ -309,6 +319,16 @@ void TileSheetEditorImGui::drawSubsheetSelector( | (rowSelected ? ImGuiTreeNodeFlags_Selected : 0); ImGui::TableNextColumn(); auto const open = ImGui::TreeNodeEx(lbl.c_str(), flags); + std::ignore = ig::dragDropSource([&subsheet, &path] { + ImGui::Text("%s", subsheet.name.c_str()); + return ig::setDragDropPayload(SubSheetRef{path}); + }); + if (ig::DragDropTarget const dragDropTarget; dragDropTarget) { + auto const [ref, err] = ig::getDragDropPayload(); + if (!err) { + oxLogError(m_model.moveSubSheet(ref.subsheet, path)); + } + } ImGui::SameLine(); if (ImGui::IsItemClicked()) { setActiveSubsheet(path); @@ -330,7 +350,7 @@ void TileSheetEditorImGui::drawSubsheetSelector( ImGui::Text("--"); } if (open) { - for (auto i = 0ul; auto &child : subsheet.subsheets) { + for (uint32_t i{}; auto &child : subsheet.subsheets) { path.push_back(i); ImGui::PushID(static_cast(i)); ig::IndentStackItem const indentStackItem{-indentReduce}; diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp index ea42f57f..d8e3cac8 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp @@ -58,6 +58,7 @@ class TileSheetEditorImGui: public studio::Editor { ox::Vec2 m_prevMouseDownPos; TileSheetTool m_tool = TileSheetTool::Draw; bool m_palPathFocused{}; + ox::Vector, 1> m_deferredCmds; public: TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path); diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp index 99ab1b70..788c5f3f 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp @@ -11,18 +11,19 @@ #include -#include "commands/commands.hpp" #include "commands/addsubsheetcommand.hpp" +#include "commands/commands.hpp" #include "commands/cutpastecommand.hpp" #include "commands/deletetilescommand.hpp" #include "commands/drawcommand.hpp" +#include "commands/flipcommand.hpp" #include "commands/inserttilescommand.hpp" #include "commands/palettechangecommand.hpp" #include "commands/rmsubsheetcommand.hpp" #include "commands/updatesubsheetcommand.hpp" #include "tilesheeteditormodel.hpp" -#include "commands/flipcommand.hpp" +#include "commands/movesubsheetcommand.hpp" namespace nostalgia::gfx { @@ -303,6 +304,10 @@ ox::Error TileSheetEditorModel::flipY() noexcept { return pushCommand(ox::make(m_img, m_activeSubsSheetIdx, a, b)); } +ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept { + return pushCommand(ox::make(m_img, std::move(src), std::move(dst))); +} + void TileSheetEditorModel::getFillPixels( TileSheet::SubSheet const&activeSubSheet, ox::Span pixels, diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp index 9af2ec86..c6f930e4 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp @@ -130,6 +130,8 @@ class TileSheetEditorModel: public ox::SignalHandler { ox::Error flipY() noexcept; + ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept; + private: void getFillPixels( TileSheet::SubSheet const&activeSubSheet, diff --git a/src/nostalgia/modules/gfx/src/tilesheet.cpp b/src/nostalgia/modules/gfx/src/tilesheet.cpp index 078da34a..fb4cc4e8 100644 --- a/src/nostalgia/modules/gfx/src/tilesheet.cpp +++ b/src/nostalgia/modules/gfx/src/tilesheet.cpp @@ -177,7 +177,7 @@ TileSheet::SubSheetIdx validateSubSheetIdx( pIdx.resize(pIdxIt); return std::move(pIdx); } else { - currentIdx = pSubsheet.subsheets.size() - 1; + currentIdx = static_cast(pSubsheet.subsheets.size() - 1); } } return validateSubSheetIdx(std::move(pIdx), pIdxIt + 1, pSubsheet.subsheets[currentIdx]); @@ -188,9 +188,9 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe } TileSheet::SubSheet const&getSubSheet( - TileSheet::SubSheetIdx const&idx, + ox::SpanView const &idx, std::size_t const idxIt, - TileSheet::SubSheet const&pSubsheet) noexcept { + TileSheet::SubSheet const &pSubsheet) noexcept { if (idxIt == idx.size()) { return pSubsheet; } @@ -202,7 +202,7 @@ TileSheet::SubSheet const&getSubSheet( } TileSheet::SubSheet &getSubSheet( - TileSheet::SubSheetIdx const&idx, + ox::SpanView const &idx, std::size_t const idxIt, TileSheet::SubSheet &pSubsheet) noexcept { if (idxIt == idx.size()) { @@ -211,11 +211,11 @@ TileSheet::SubSheet &getSubSheet( return getSubSheet(idx, idxIt + 1, pSubsheet.subsheets[idx[idxIt]]); } -TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, TileSheet::SubSheetIdx const&idx) noexcept { +TileSheet::SubSheet const&getSubSheet(TileSheet const &ts, ox::SpanView const &idx) noexcept { return gfx::getSubSheet(idx, 0, ts.subsheet); } -TileSheet::SubSheet &getSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept { +TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView const&idx) noexcept { return gfx::getSubSheet(idx, 0, ts.subsheet); } @@ -227,7 +227,20 @@ ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept parent.subsheets.emplace_back(++ts.idIt, "Subsheet 0", parent.columns, parent.rows); parent.subsheets.emplace_back(++ts.idIt, "Subsheet 1", 1, 1); } - return ox::Error(0); + return {}; +} + +ox::Error insertSubSheet(TileSheet &ts, ox::SpanView const&idx, TileSheet::SubSheet ss) noexcept { + if (idx.empty()) { + return ox::Error{1, "invalid insert idx"}; + } + auto &parent = getSubSheet(ts, {idx.data(), idx.size() - 1}); + auto const insertIdx = idx[idx.size() - 1]; + if (insertIdx > parent.subsheets.size()) { + return ox::Error{1, "invalid insert idx"}; + } + parent.subsheets.emplace(insertIdx, std::move(ss)); + return {}; } ox::Error rmSubSheet(