From 055165974e4bd568aa922feb7c1ae3949fb4f166 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 15:41:40 -0600 Subject: [PATCH 01/21] [nostalgia/sample_project] Update test assets --- sample_project/Palettes/Dirt.npal | 29 +++++++++++++++++++++- sample_project/Palettes/Logo.npal | 37 ++++++++++++++++++++++++++++- sample_project/TileSheets/Logo.nts | Bin 265 -> 3740 bytes 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/sample_project/Palettes/Dirt.npal b/sample_project/Palettes/Dirt.npal index ffb649e5..a53b907e 100644 --- a/sample_project/Palettes/Dirt.npal +++ b/sample_project/Palettes/Dirt.npal @@ -1 +1,28 @@ -K1;0f75977f-1c52-45f8-9793-52ea2dc200a0;M2;net.drinkingtea.nostalgia.core.Palette;1;ûÿ³Ö +K1;0f75977f-1c52-45f8-9793-52ea2dc200a0;O1;net.drinkingtea.nostalgia.gfx.Palette;5;{ + "colorNames" : + [ + "Color 1", + "Color 2" + ], + "pages" : + [ + { + "colors" : + [ + { + "a" : 1, + "b" : 31, + "g" : 31, + "r" : 31 + }, + { + "a" : 1, + "b" : 22, + "g" : 22, + "r" : 22 + } + ], + "name" : "Page 1" + } + ] +} \ No newline at end of file diff --git a/sample_project/Palettes/Logo.npal b/sample_project/Palettes/Logo.npal index 6e2cb29f..3e70d034 100644 --- a/sample_project/Palettes/Logo.npal +++ b/sample_project/Palettes/Logo.npal @@ -1 +1,36 @@ -K1;c79f21e2-f74f-4ad9-90ed-32b0ef7da6ed;M2;net.drinkingtea.nostalgia.core.Palette;1;PÛ{³ÖCˆ +K1;c79f21e2-f74f-4ad9-90ed-32b0ef7da6ed;O1;net.drinkingtea.nostalgia.gfx.Palette;5;{ + "colorNames" : + [ + "Color 1", + "Color 2", + "Color 3", + "Color 4" + ], + "pages" : + [ + { + "colors" : + [ + { + "b" : 5 + }, + { + "b" : 22, + "g" : 22, + "r" : 22 + }, + { + "b" : 27, + "g" : 27, + "r" : 27 + }, + { + "b" : 20, + "g" : 8, + "r" : 8 + } + ], + "name" : "Page 1" + } + ] +} \ No newline at end of file diff --git a/sample_project/TileSheets/Logo.nts b/sample_project/TileSheets/Logo.nts index 7c6be746a7ea7a433524f8121849b2ed45783d9b..824bbd02b76ce96dc96994aed0289aa8e8f82c33 100644 GIT binary patch literal 3740 zcmeHK!A^rf5Iw_JG@M-ul!BBmFdj7O&3IVYrEa9qlqEJX{dZaRG6@~B)i&0ILpP5% zZ{7@#UiRKkZX9sDl;lwoEV77E&(G2aKdrcQ*-lg+qFPH%-KuUR zE!Tp&>tgS|h>}0Qb1u_m`ej>Aw%t0j)hxW}FyjSnOZiAkE+tpA)3$=G=JPyGiooXq zDdMmoA!P|kJkH1>$UI)ej7FR}%0jR^sTu?I(6m{jMk&I!x@ne^*JZn@8pSL+iE2>T z?{P&pdg@bMOJ!#{Te0V5FYlgSyPxGLemajN(1&=0pAtK70^>PjRgBlWVO5Mj?;A~S z*O0)e-+Izx2|!-sOP?nHAGpJ*daM`n7>2Vj4dlo5uxf&}vx!n`uuU)rs5hAfHL!Qw zA6B6Q@o?K~!1^uVCPN0R o!UUiOVyGE+)?H8!eK2g|iS_<5-(9@k`ditq{?u1E+d9~XZ{Cb<-v9sr delta 171 zcmbOu+sQORgUQ!uqL#FHa(+>&UPxw6YH&tsYKgV6H9rRv6JyxK3hjDvj-dSf5;nF* z76yg}1_lO&P$0q3(9zNHYyQvw0*1!M9UUAD|Nrwd7z;BpC@3&7DZl^|lM)m#DKIH0 a0TB!XC4iD3QK)K|1eiu>Qc_|DDgywqtRT+- From 285918374286fb465845eb0fb4ecc730c113ccb2 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 20:46:15 -0600 Subject: [PATCH 02/21] [nostalgia/gfx/studio/tilesheet] Add the ability to move subsheets --- .../gfx/include/nostalgia/gfx/tilesheet.hpp | 14 ++++--- .../tilesheeteditor/commands/CMakeLists.txt | 1 + .../tilesheeteditor/commands/commands.hpp | 5 ++- .../tilesheeteditor/commands/flipcommand.cpp | 4 +- .../commands/movesubsheetcommand.cpp | 40 +++++++++++++++++++ .../commands/movesubsheetcommand.hpp | 33 +++++++++++++++ .../tilesheeteditor/tilesheeteditor-imgui.cpp | 22 +++++++++- .../tilesheeteditor/tilesheeteditor-imgui.hpp | 1 + .../tilesheeteditor/tilesheeteditormodel.cpp | 9 ++++- .../tilesheeteditor/tilesheeteditormodel.hpp | 2 + src/nostalgia/modules/gfx/src/tilesheet.cpp | 27 +++++++++---- 11 files changed, 138 insertions(+), 20 deletions(-) create mode 100644 src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.cpp create mode 100644 src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/movesubsheetcommand.hpp 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( From cd63afacfe6ef8cedc4de1a3ae013216f43b620d Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 20:53:47 -0600 Subject: [PATCH 03/21] [studio] Remove Ctrl-0 tab shortcut --- src/olympic/studio/applib/src/studioapp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/olympic/studio/applib/src/studioapp.cpp b/src/olympic/studio/applib/src/studioapp.cpp index 64c6ba89..3b45c2d1 100644 --- a/src/olympic/studio/applib/src/studioapp.cpp +++ b/src/olympic/studio/applib/src/studioapp.cpp @@ -349,10 +349,6 @@ void StudioUI::handleKeyInput() noexcept { m_activeEditorUpdatePending = m_activeEditor; } } - if (ImGui::IsKeyPressed(ImGuiKey_0)) { - m_activeEditor = m_editors[10 < m_editors.size() ? 10 : range].get(); - m_activeEditorUpdatePending = m_activeEditor; - } } } } From 6298ac3a215e28a35a6e99266190ad9222564ff0 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 20:58:22 -0600 Subject: [PATCH 04/21] [nostalgia] Update release notes --- release-notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release-notes.md b/release-notes.md index 57449ad4..7c31d920 100644 --- a/release-notes.md +++ b/release-notes.md @@ -4,6 +4,8 @@ * Add PaletteV5 to accommodate namespace change. * Add TileSheetV5. TileSheetV5 retains the bpp field for the sake of CompactTileSheet, but always store it pixel as 8 bpp for itself. +* Add ability to move subsheets in the subsheet tree. +* Add Flip X and Flip Y button for TileSheet Editor. * Replace file picker combo boxes with a browse button and file picker, and support for dragging files from the project explorer. * Add ability to create directories. From a22aafaf96460bb8984fbd0bef34544077667150 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 22:12:57 -0600 Subject: [PATCH 05/21] [nostalgia/gfx/studio/palette] Add ability to reorder Palette pages --- .../src/studio/paletteeditor/CMakeLists.txt | 1 + .../paletteeditor/commands/commands.hpp | 1 + .../commands/movepagecommand.cpp | 40 +++++++++++++++++++ .../commands/movepagecommand.hpp | 35 ++++++++++++++++ .../paletteeditor/paletteeditor-imgui.cpp | 22 ++++++++++ 5 files changed, 99 insertions(+) create mode 100644 src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp create mode 100644 src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt b/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt index cdaf9d3e..9ec397bf 100644 --- a/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources( commands/applycolorallpagescommand.cpp commands/duplicatepagecommand.cpp commands/movecolorcommand.cpp + commands/movepagecommand.cpp commands/removecolorcommand.cpp commands/removepagecommand.cpp commands/renamepagecommand.cpp diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/commands.hpp b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/commands.hpp index 7ca6ee69..666a0f20 100644 --- a/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/commands.hpp +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/commands.hpp @@ -12,6 +12,7 @@ enum class PaletteEditorCommandId { AddPage, DuplicatePage, RemovePage, + MovePage, AddColor, RemoveColor, UpdateColorInfo, diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp new file mode 100644 index 00000000..86a9c80d --- /dev/null +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "commands.hpp" + +#include "movepagecommand.hpp" + +namespace nostalgia::gfx { + +MovePageCommand::MovePageCommand( + Palette &pal, + size_t const srcIdx, + size_t const dstIdx) noexcept: + m_pal(pal), + m_srcIdx(srcIdx), + m_dstIdx(dstIdx) {} + +int MovePageCommand::commandId() const noexcept { + return static_cast(PaletteEditorCommandId::MovePage); +} + +ox::Error MovePageCommand::redo() noexcept { + movePage(m_srcIdx, m_dstIdx); + return {}; +} + +ox::Error MovePageCommand::undo() noexcept { + movePage(m_dstIdx, m_srcIdx); + return {}; +} + +void MovePageCommand::movePage( + size_t const srcIdx, size_t const dstIdx) noexcept { + auto page = std::move(m_pal.pages[srcIdx]); + std::ignore = m_pal.pages.erase(srcIdx); + m_pal.pages.emplace(dstIdx, std::move(page)); +} + +} diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp new file mode 100644 index 00000000..0b42161d --- /dev/null +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp @@ -0,0 +1,35 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include + +namespace nostalgia::gfx { + +class MovePageCommand: public studio::UndoCommand { + private: + Palette &m_pal; + std::size_t const m_srcIdx = 0; + std::size_t const m_dstIdx = 0; + + public: + MovePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept; + + ~MovePageCommand() noexcept override = default; + + [[nodiscard]] + int commandId() const noexcept override; + + ox::Error redo() noexcept override; + + ox::Error undo() noexcept override; + + private: + void movePage(size_t srcIdx, size_t dstIdx) noexcept; +}; + +} diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/paletteeditor-imgui.cpp b/src/nostalgia/modules/gfx/src/studio/paletteeditor/paletteeditor-imgui.cpp index 28d1275a..8a433078 100644 --- a/src/nostalgia/modules/gfx/src/studio/paletteeditor/paletteeditor-imgui.cpp +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/paletteeditor-imgui.cpp @@ -11,6 +11,7 @@ #include "commands/applycolorallpagescommand.hpp" #include "commands/duplicatepagecommand.hpp" #include "commands/movecolorcommand.hpp" +#include "commands/movepagecommand.hpp" #include "commands/removecolorcommand.hpp" #include "commands/removepagecommand.hpp" #include "commands/renamepagecommand.hpp" @@ -19,6 +20,7 @@ #include "paletteeditor-imgui.hpp" + namespace nostalgia::gfx { namespace ig = studio::ig; @@ -33,6 +35,16 @@ OX_MODEL_BEGIN(ColorDragDrop) OX_MODEL_FIELD(i) OX_MODEL_END() +struct PageDragDrop { + static constexpr auto TypeName = "nostalgia.gfx.PageDragDrop"; + static constexpr auto TypeVersion = 1; + uint32_t page{}; +}; + +OX_MODEL_BEGIN(PageDragDrop) + OX_MODEL_FIELD(page) +OX_MODEL_END() + void PaletteEditorImGui::PageRenameDialog::draw(turbine::Context &tctx) noexcept { if (!m_show) { return; @@ -235,6 +247,16 @@ void PaletteEditorImGui::drawPagesEditor() noexcept { if (ImGui::Selectable("##PageRow", i == m_page, ImGuiSelectableFlags_SpanAllColumns)) { m_page = i; } + std::ignore = ig::dragDropSource([this, i] { + ImGui::Text("%s", m_pal.pages[i].name.c_str()); + return ig::setDragDropPayload(PageDragDrop{i}); + }, ImGuiDragDropFlags_SourceAllowNullID); + if (ig::DragDropTarget const d; d) { + auto const [src, err] = ig::getDragDropPayload(); + if (!err) { + std::ignore = pushCommand(m_pal, src.page, i); + } + } } } ImGui::EndTable(); From c6b58f7c63a593698b56708ddcdd336aac543d4c Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 22:16:04 -0600 Subject: [PATCH 06/21] [nostalgia] Update release notes --- release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release-notes.md b/release-notes.md index 7c31d920..e9c37a9c 100644 --- a/release-notes.md +++ b/release-notes.md @@ -14,3 +14,4 @@ * Ctrl- keyboard shortcuts for jumping between tabs. * Fix Palette Editor to ignore keyboard input when popups are open. * Palette Editor move color mechanism now uses drag and drop. +* Add ability to reorder Palette pages. From 6c858e0c4e950101280724164d80279c0f656c21 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 22:29:14 -0600 Subject: [PATCH 07/21] [nostalgia/gfx/studio/tilesheet] UI cleanup --- .../src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp | 7 ++++--- .../src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) 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 d9677cc9..ba6838ab 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp @@ -214,7 +214,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept { ImGui::BeginChild("Controls", {s_palViewWidth - 8, paneSize.y}, true); { auto const controlsSize = ImGui::GetContentRegionAvail(); - ImGui::BeginChild("ToolBox", {s_palViewWidth - 24, 30}, true); + ImGui::BeginChild("ToolBox", {168, 32}, true); { auto const btnSz = ImVec2{45, 14}; if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) { @@ -232,9 +232,10 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept { } } ImGui::EndChild(); - ImGui::BeginChild("OperationsBox", {s_palViewWidth - 24, ig::BtnSz.y + 17}, true); + ImGui::SameLine(); + ImGui::BeginChild("OperationsBox", {0, 32}, true); { - auto constexpr btnSz = ImVec2{55, ig::BtnSz.y}; + auto constexpr btnSz = ImVec2{55, 16}; if (ig::PushButton("Flip X", btnSz)) { oxLogError(m_model.flipX()); } 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 d8e3cac8..f338408d 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp @@ -45,7 +45,7 @@ class TileSheetEditorImGui: public studio::Editor { [[nodiscard]] constexpr bool isOpen() const noexcept { return m_show; } }; - static constexpr float s_palViewWidth = 300; + static constexpr float s_palViewWidth = 335; studio::StudioContext &m_sctx; turbine::Context &m_tctx; ox::Vector m_paletteList; From 12f6b22c8ba4560e70fd5a3a0aa2acace75cf79d Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 23:35:03 -0600 Subject: [PATCH 08/21] [nostalgia/gfx/studio/palette] Cleanup --- .../gfx/src/studio/paletteeditor/CMakeLists.txt | 17 ++--------------- .../paletteeditor/commands/CMakeLists.txt | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) create mode 100644 src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt b/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt index 9ec397bf..25e3a79c 100644 --- a/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/CMakeLists.txt @@ -1,19 +1,6 @@ -target_sources( - NostalgiaCore-Studio PRIVATE - commands/addcolorcommand.cpp - commands/addpagecommand.cpp - commands/applycolorallpagescommand.cpp - commands/duplicatepagecommand.cpp - commands/movecolorcommand.cpp - commands/movepagecommand.cpp - commands/removecolorcommand.cpp - commands/removepagecommand.cpp - commands/renamepagecommand.cpp - commands/updatecolorcommand.cpp - commands/updatecolorinfocommand.cpp -) - target_sources( NostalgiaCore-Studio-ImGui PRIVATE paletteeditor-imgui.cpp ) + +add_subdirectory(commands) \ No newline at end of file diff --git a/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt new file mode 100644 index 00000000..42c4cd54 --- /dev/null +++ b/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt @@ -0,0 +1,15 @@ + +target_sources( + NostalgiaCore-Studio PRIVATE + addcolorcommand.cpp + addpagecommand.cpp + applycolorallpagescommand.cpp + duplicatepagecommand.cpp + movecolorcommand.cpp + movepagecommand.cpp + removecolorcommand.cpp + removepagecommand.cpp + renamepagecommand.cpp + updatecolorcommand.cpp + updatecolorinfocommand.cpp +) From e132f2fd1bb7d7359c9f0f14ec9cceb8be339d02 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 26 Jan 2025 23:59:13 -0600 Subject: [PATCH 09/21] [studio] Make file move do nothing if the file already exists --- src/olympic/studio/applib/src/studioapp.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/olympic/studio/applib/src/studioapp.cpp b/src/olympic/studio/applib/src/studioapp.cpp index 3b45c2d1..fa50bc6d 100644 --- a/src/olympic/studio/applib/src/studioapp.cpp +++ b/src/olympic/studio/applib/src/studioapp.cpp @@ -495,11 +495,15 @@ ox::Error StudioUI::queueFileMove(ox::StringParam src, ox::StringParam dst) noex void StudioUI::procFileMoves() noexcept { for (auto const &m : m_queuedMoves) { - oxLogError(m_project->moveItem(m.a, m.b)); + if (!m_project->exists(m.b)) { + oxLogError(m_project->moveItem(m.a, m.b)); + } } m_queuedMoves.clear(); for (auto const &m : m_queuedDirMoves) { - oxLogError(m_project->moveDir(m.a, m.b)); + if (!m_project->exists(m.b)) { + oxLogError(m_project->moveDir(m.a, m.b)); + } } m_queuedDirMoves.clear(); } From 8eb1ac215b79c979965a845885efafab36f2e968 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 00:10:25 -0600 Subject: [PATCH 10/21] [studio] Fix not to try moving a parent directory to its child --- src/olympic/studio/modlib/src/project.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/olympic/studio/modlib/src/project.cpp b/src/olympic/studio/modlib/src/project.cpp index 1aa311a0..609c1d12 100644 --- a/src/olympic/studio/modlib/src/project.cpp +++ b/src/olympic/studio/modlib/src/project.cpp @@ -46,6 +46,10 @@ static ox::Result> listAllRecursive(ox::FileSystem &fs, o return std::move(out); } +[[nodiscard]] +static constexpr bool isParentOf(ox::StringViewCR parent, ox::StringViewCR child) noexcept { + return beginsWith(child, parent); +} Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir): m_kctx(ctx), @@ -99,6 +103,9 @@ ox::Error Project::moveItem(ox::StringViewCR src, ox::StringViewCR dest) noexcep } ox::Error Project::moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept { + if (isParentOf(src, dest)) { + return ox::Error{1, "cannot move parent to a child directory"}; + } OX_REQUIRE(files, listAllRecursive(m_fs, src)); OX_RETURN_ERROR(m_fs.move(src, dest)); fileMoved.emit(src, dest, ox::UUID{}); From 13f0bf57e46657c9b7ebe595f64f35e968a6e087 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 00:30:27 -0600 Subject: [PATCH 11/21] [studio] Make deleting a file close tabs associated with it --- src/olympic/studio/applib/src/studioapp.cpp | 14 +++++++++++++- src/olympic/studio/applib/src/studioapp.hpp | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/olympic/studio/applib/src/studioapp.cpp b/src/olympic/studio/applib/src/studioapp.cpp index fa50bc6d..3cbe35a9 100644 --- a/src/olympic/studio/applib/src/studioapp.cpp +++ b/src/olympic/studio/applib/src/studioapp.cpp @@ -392,6 +392,18 @@ ox::Error StudioUI::handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR ne return m_projectExplorer.refreshProjectTreeModel(); } +ox::Error StudioUI::handleDeleteFile(ox::StringViewCR path) noexcept { + for (size_t i{}; auto &e : m_editors) { + if (path == e->itemPath()) { + oxLogError(m_editors.erase(i).error); + oxLogError(closeFile(path)); + break; + } + ++i; + } + return m_projectExplorer.refreshProjectTreeModel(); +} + ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept { std::error_code ec; std::filesystem::create_directories(toStdStringView(path), ec); @@ -412,7 +424,7 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept { m_newDirDialog.newDir.connect(m_sctx.project, &Project::mkdir); m_project->dirAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel); m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel); - m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel); + m_project->fileDeleted.connect(this, &StudioUI::handleDeleteFile); m_project->fileMoved.connect(this, &StudioUI::handleMoveFile); m_openFiles.clear(); m_editors.clear(); diff --git a/src/olympic/studio/applib/src/studioapp.hpp b/src/olympic/studio/applib/src/studioapp.hpp index c2e6eb32..6dfc730f 100644 --- a/src/olympic/studio/applib/src/studioapp.hpp +++ b/src/olympic/studio/applib/src/studioapp.hpp @@ -104,6 +104,8 @@ class StudioUI: public ox::SignalHandler { ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept; + ox::Error handleDeleteFile(ox::StringViewCR path) noexcept; + ox::Error createOpenProject(ox::StringViewCR path) noexcept; ox::Error openProjectPath(ox::StringParam path) noexcept; From 2286238abc3f3176b4b052afce2331552d891859 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 00:33:14 -0600 Subject: [PATCH 12/21] [studio] Make rename file accept input upon pressing Enter if text input is focused --- src/olympic/studio/applib/src/renamefile.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/olympic/studio/applib/src/renamefile.cpp b/src/olympic/studio/applib/src/renamefile.cpp index b4c633c7..24053fc4 100644 --- a/src/olympic/studio/applib/src/renamefile.cpp +++ b/src/olympic/studio/applib/src/renamefile.cpp @@ -50,8 +50,10 @@ void RenameFile::draw(StudioContext &ctx) noexcept { ImGui::SetKeyboardFocusHere(); } ig::InputText("Name", m_name); + auto const nameInputFocused = ImGui::IsItemFocused(); ImGui::Text("%s%s", m_path.c_str(), m_name.c_str()); - if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK) { + if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK || + (nameInputFocused && ImGui::IsKeyPressed(ImGuiKey_Enter))) { moveFile.emit(m_oldPath, m_path + m_name); close(); } From 95256a9a0dc2d103281055636b099bf1eb317b69 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 00:54:58 -0600 Subject: [PATCH 13/21] [studio] Make rename file give error message if the file already exists --- src/olympic/studio/applib/src/renamefile.cpp | 25 ++++++++++++++++---- src/olympic/studio/applib/src/renamefile.hpp | 1 + src/olympic/studio/modlib/src/imguiutil.cpp | 2 -- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/olympic/studio/applib/src/renamefile.cpp b/src/olympic/studio/applib/src/renamefile.cpp index 24053fc4..73a2ff19 100644 --- a/src/olympic/studio/applib/src/renamefile.cpp +++ b/src/olympic/studio/applib/src/renamefile.cpp @@ -41,20 +41,35 @@ void RenameFile::draw(StudioContext &ctx) noexcept { case Stage::Opening: ImGui::OpenPopup(title().c_str()); m_open = true; + m_fileExists = false; m_stage = Stage::Open; [[fallthrough]]; case Stage::Open: setSize({250, 0}); - drawWindow(ctx.tctx, m_open, [this] { + drawWindow(ctx.tctx, m_open, [this, &ctx] { if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } - ig::InputText("Name", m_name); + m_fileExists = !ig::InputText("Name", m_name) && m_fileExists; auto const nameInputFocused = ImGui::IsItemFocused(); - ImGui::Text("%s%s", m_path.c_str(), m_name.c_str()); - if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK || + if (m_fileExists) { + ImGui::Text("File %s already exists.", m_name.c_str()); + } else { + ImGui::Text("%s%s", m_path.c_str(), m_name.c_str()); + } + bool b{}; + auto const response = ig::PopupControlsOkCancel(b); + if (response == ig::PopupResponse::OK || (nameInputFocused && ImGui::IsKeyPressed(ImGuiKey_Enter))) { - moveFile.emit(m_oldPath, m_path + m_name); + auto const newPath = m_path + m_name; + if (!ctx.project->exists(newPath)) { + moveFile.emit(m_oldPath, newPath); + close(); + } else { + m_open = true; + m_fileExists = true; + } + } else if (response == ig::PopupResponse::Cancel) { close(); } }); diff --git a/src/olympic/studio/applib/src/renamefile.hpp b/src/olympic/studio/applib/src/renamefile.hpp index 2af0326d..4625118f 100644 --- a/src/olympic/studio/applib/src/renamefile.hpp +++ b/src/olympic/studio/applib/src/renamefile.hpp @@ -21,6 +21,7 @@ class RenameFile: public Popup { ox::String m_oldPath; ox::String m_path; ox::IString<255> m_name; + bool m_fileExists{}; bool m_open{}; public: diff --git a/src/olympic/studio/modlib/src/imguiutil.cpp b/src/olympic/studio/modlib/src/imguiutil.cpp index d3af2aaf..12549785 100644 --- a/src/olympic/studio/modlib/src/imguiutil.cpp +++ b/src/olympic/studio/modlib/src/imguiutil.cpp @@ -64,13 +64,11 @@ PopupResponse PopupControlsOkCancel( ImGui::Separator(); ImGui::SetCursorPosX(popupWidth - 118); if (ImGui::Button(ok.c_str(), btnSz)) { - ImGui::CloseCurrentPopup(); popupOpen = false; out = PopupResponse::OK; } ImGui::SameLine(); if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button(cancel.c_str(), btnSz)) { - ImGui::CloseCurrentPopup(); popupOpen = false; out = PopupResponse::Cancel; } From eaa9a2415eb58bd88c1e6401dcd9f0038e15463d Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 21:59:57 -0600 Subject: [PATCH 14/21] [keel] Make reloadAsset check if file is loaded --- src/olympic/keel/include/keel/assetmanager.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/olympic/keel/include/keel/assetmanager.hpp b/src/olympic/keel/include/keel/assetmanager.hpp index 364f26f2..0730e62e 100644 --- a/src/olympic/keel/include/keel/assetmanager.hpp +++ b/src/olympic/keel/include/keel/assetmanager.hpp @@ -295,7 +295,9 @@ class AssetManager { } ox::Error reloadAsset(ox::StringViewCR assetId) noexcept { - m_fileUpdated[assetId]->emit(assetId); + if (m_fileUpdated.contains(assetId)) { + m_fileUpdated[assetId]->emit(assetId); + } return {}; } From 56b9cb6ebf8ba831ff8dcd67eb9238c9ec4c6b77 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Mon, 27 Jan 2025 23:31:58 -0600 Subject: [PATCH 15/21] [studio] Fix file explorer to treat empty directories as directories --- src/olympic/studio/modlib/src/filetreemodel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/olympic/studio/modlib/src/filetreemodel.cpp b/src/olympic/studio/modlib/src/filetreemodel.cpp index d7d347a0..9a364b25 100644 --- a/src/olympic/studio/modlib/src/filetreemodel.cpp +++ b/src/olympic/studio/modlib/src/filetreemodel.cpp @@ -88,7 +88,7 @@ FileTreeModel::FileTreeModel( void FileTreeModel::draw(turbine::Context &tctx) const noexcept { constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; auto const selected = m_explorer.selected(this) ? ImGuiTreeNodeFlags_Selected : 0; - if (!m_children.empty()) { + if (m_fileType == ox::FileType::Directory) { auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected); if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) { m_explorer.setSelectedNode(this); @@ -104,7 +104,8 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept { if (ig::DragDropTarget const dragDropTarget; dragDropTarget) { auto const [ref, err] = ig::getDragDropPayload("FileRef"); if (!err) { - auto const name = substr(ref.path, find(ref.path.rbegin(), ref.path.rend(), '/').offset() + 1); + auto const name = substr( + ref.path, find(ref.path.rbegin(), ref.path.rend(), '/').offset() + 1); if (ref.isDir) { m_explorer.dirMoved(ref.path, sfmt("{}/{}", m_fullPath, name)); } else { From e22b658a67b88317cb866f80a514c5b2cfaf14f4 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 28 Jan 2025 01:04:17 -0600 Subject: [PATCH 16/21] [studio] Fix isParentOf check in Project to ensure child dir path ends with / --- src/olympic/studio/modlib/src/project.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/olympic/studio/modlib/src/project.cpp b/src/olympic/studio/modlib/src/project.cpp index 609c1d12..dbf34dbb 100644 --- a/src/olympic/studio/modlib/src/project.cpp +++ b/src/olympic/studio/modlib/src/project.cpp @@ -48,7 +48,10 @@ static ox::Result> listAllRecursive(ox::FileSystem &fs, o [[nodiscard]] static constexpr bool isParentOf(ox::StringViewCR parent, ox::StringViewCR child) noexcept { - return beginsWith(child, parent); + if (endsWith(child, "/")) { + return beginsWith(child, parent); + } + return beginsWith(sfmt("{}/", child), parent); } Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir): From 0570f762369e32a3e67b4e15e635a2c902be17cc Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 28 Jan 2025 01:18:44 -0600 Subject: [PATCH 17/21] [ox/fs] Fix PassThroughFS::stripSlash --- deps/ox/src/ox/fs/filesystem/passthroughfs.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deps/ox/src/ox/fs/filesystem/passthroughfs.cpp b/deps/ox/src/ox/fs/filesystem/passthroughfs.cpp index 4cc7aa90..365d5bb7 100644 --- a/deps/ox/src/ox/fs/filesystem/passthroughfs.cpp +++ b/deps/ox/src/ox/fs/filesystem/passthroughfs.cpp @@ -185,8 +185,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n } std::string_view PassThroughFS::stripSlash(StringView path) noexcept { - const auto pathLen = ox::strlen(path); - for (auto i = 0u; i < pathLen && path[0] == '/'; i++) { + for (auto i = 0u; i < path.len() && path[0] == '/'; i++) { path = substr(path, 1); } return {path.data(), path.bytes()}; From 5dce9dd3773e5cde7cc98ea6ba26426f01e79b7d Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 28 Jan 2025 01:27:51 -0600 Subject: [PATCH 18/21] [studio] Suppress context menu for root dir in ProjectExplorer --- .../studio/applib/src/projectexplorer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/olympic/studio/applib/src/projectexplorer.cpp b/src/olympic/studio/applib/src/projectexplorer.cpp index f0edd82a..8a092f80 100644 --- a/src/olympic/studio/applib/src/projectexplorer.cpp +++ b/src/olympic/studio/applib/src/projectexplorer.cpp @@ -47,17 +47,17 @@ void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept { } void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept { - if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) { - if (ImGui::MenuItem("Add Item")) { - addItem.emit(path); - } - if (ImGui::MenuItem("Add Directory")) { - addDir.emit(path); - } + if (path.len() && ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) { + if (ImGui::MenuItem("Add Item")) { + addItem.emit(path); + } + if (ImGui::MenuItem("Add Directory")) { + addDir.emit(path); + } if (ImGui::MenuItem("Delete")) { deleteItem.emit(path); } - ImGui::EndPopup(); + ImGui::EndPopup(); } } From b5954f15c5d2a86f51a212af3fab6876fe83ccea Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Wed, 29 Jan 2025 18:47:48 -0600 Subject: [PATCH 19/21] [studio] Restore context menu for root dir, but exclude Delete --- src/olympic/studio/applib/src/projectexplorer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/olympic/studio/applib/src/projectexplorer.cpp b/src/olympic/studio/applib/src/projectexplorer.cpp index 8a092f80..20ba0dfa 100644 --- a/src/olympic/studio/applib/src/projectexplorer.cpp +++ b/src/olympic/studio/applib/src/projectexplorer.cpp @@ -47,14 +47,14 @@ void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept { } void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept { - if (path.len() && ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) { + if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) { if (ImGui::MenuItem("Add Item")) { addItem.emit(path); } if (ImGui::MenuItem("Add Directory")) { addDir.emit(path); } - if (ImGui::MenuItem("Delete")) { + if (path.len() && ImGui::MenuItem("Delete")) { deleteItem.emit(path); } ImGui::EndPopup(); From 5351e9aa0a6b7c83612163ee3416927ac881c2ca Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 1 Feb 2025 14:14:09 -0600 Subject: [PATCH 20/21] [nostalgia/core/studio/tilesheet] Add line drawing tool --- .../tilesheeteditor/commands/drawcommand.cpp | 82 ++++++++++++++++++- .../tilesheeteditor/commands/drawcommand.hpp | 8 +- .../tilesheeteditor/tilesheeteditor-imgui.cpp | 20 ++++- .../tilesheeteditor/tilesheeteditormodel.cpp | 26 +++++- .../tilesheeteditor/tilesheeteditormodel.hpp | 4 + .../tilesheeteditor/tilesheeteditorview.cpp | 9 +- .../tilesheeteditor/tilesheeteditorview.hpp | 7 +- 7 files changed, 144 insertions(+), 12 deletions(-) diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp index b359e70a..8f6c46ef 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp @@ -2,10 +2,64 @@ * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. */ +#include +#include + #include "drawcommand.hpp" namespace nostalgia::gfx { +constexpr void iterateLine(ox::Point const &a, ox::Point const &b, auto const &f) noexcept { + auto const rise = b.y - a.y; + auto const run = b.x - a.x; + auto const slope = static_cast(rise) / static_cast(run); + auto y = static_cast(a.y); + auto const w = abs(run); + if (rise > 0) { + if (run > 0) { + auto constexpr xmod = 1; + for (int32_t i = 0; i < w; ++i) { + auto const climb = static_cast(ceil(y + slope - y)); + f(a.x + i * xmod, static_cast(y), climb * xmod); + y += slope * xmod; + } + } else if (run < 0) { + auto constexpr xmod = -1; + for (int32_t i = 0; i < w; ++i) { + auto const climb = static_cast(floor(y + slope - y)); + f(a.x + i * xmod, static_cast(y), climb * xmod); + y += slope * xmod; + } + } else { + f(a.x, a.y, rise); + } + } else if (rise < 0) { + if (run > 0) { + auto constexpr xmod = 1; + for (int32_t i = 0; i < w; ++i) { + auto const climb = static_cast(floor(y + slope - y)); + f(a.x + i * xmod, static_cast(y), climb * xmod); + y += slope * xmod; + } + } else if (run < 0) { + auto constexpr xmod = -1; + for (int32_t i = 0; i < w; ++i) { + auto const climb = static_cast(ceil(y + slope - y)); + f(a.x + i * xmod, static_cast(y), climb * xmod); + y += slope * xmod; + } + } else { + f(a.x, a.y, rise - 1); + } + } else { + auto const xmod = run > 0 ? 1 : -1; + for (int32_t i = 0; i < w; ++i) { + f(a.x + i * xmod, static_cast(y), 1); + } + } +} + + DrawCommand::DrawCommand( TileSheet &img, TileSheet::SubSheetIdx subSheetIdx, @@ -21,7 +75,7 @@ DrawCommand::DrawCommand( DrawCommand::DrawCommand( TileSheet &img, TileSheet::SubSheetIdx subSheetIdx, - ox::Vector const&idxList, + ox::SpanView const&idxList, int palIdx) noexcept: m_img(img), m_subSheetIdx(std::move(subSheetIdx)), @@ -32,11 +86,12 @@ DrawCommand::DrawCommand( } } -bool DrawCommand::append(std::size_t idx) noexcept { +bool DrawCommand::append(std::size_t const idx) noexcept { auto &subsheet = getSubSheet(m_img, m_subSheetIdx); if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) { // duplicate entries are bad - auto existing = ox::find_if(m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) { + auto existing = find_if( + m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) { return c.idx == idx; }); if (existing == m_changes.cend()) { @@ -48,7 +103,7 @@ bool DrawCommand::append(std::size_t idx) noexcept { return false; } -bool DrawCommand::append(ox::Vector const&idxList) noexcept { +bool DrawCommand::append(ox::SpanView const&idxList) noexcept { auto out = false; for (auto idx : idxList) { out = append(idx) || out; @@ -56,6 +111,25 @@ bool DrawCommand::append(ox::Vector const&idxList) noexcept { return out; } +void DrawCommand::lineUpdate(ox::Point a, ox::Point b) noexcept { + std::ignore = undo(); + m_changes.clear(); + auto &ss = getSubSheet(m_img, m_subSheetIdx); + if (a.x < b.x) { ++b.x; } + if (a.y < b.y) { ++b.y; } + if (a.x > b.x) { --b.x; } + iterateLine(a, b, [this, &ss](int32_t const x, int32_t const y, int32_t const h) { + int const mod = h < 0 ? -1 : 1; + for (int32_t i{}; i < abs(h); ++i) { + auto const idx = ptToIdx(x, y + i * mod, ss.columns * TileWidth); + if (idx < ss.pixels.size()) { + m_changes.emplace_back(static_cast(idx), getPixel(ss, idx)); + } + } + }); + std::ignore = redo(); +} + ox::Error DrawCommand::redo() noexcept { auto &subsheet = getSubSheet(m_img, m_subSheetIdx); for (auto const&c : m_changes) { diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.hpp index 21cf845a..a9945e72 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.hpp @@ -33,12 +33,14 @@ class DrawCommand: public TileSheetCommand { DrawCommand( TileSheet &img, TileSheet::SubSheetIdx subSheetIdx, - ox::Vector const&idxList, + ox::SpanView const&idxList, int palIdx) noexcept; bool append(std::size_t idx) noexcept; - bool append(ox::Vector const&idxList) noexcept; + bool append(ox::SpanView const&idxList) noexcept; + + void lineUpdate(ox::Point a, ox::Point b) noexcept; ox::Error redo() noexcept final; @@ -52,4 +54,4 @@ class DrawCommand: public TileSheetCommand { }; -} \ No newline at end of file +} 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 ba6838ab..fe4bece9 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp @@ -152,6 +152,12 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key const key, bool const do setCutEnabled(false); setPasteEnabled(false); m_model.clearSelection(); + } else if (key == turbine::Key::Alpha_E) { + m_tool = TileSheetTool::Line; + setCopyEnabled(false); + setCutEnabled(false); + setPasteEnabled(false); + m_model.clearSelection(); } else if (key == turbine::Key::Alpha_S) { m_tool = TileSheetTool::Select; setCopyEnabled(true); @@ -214,7 +220,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept { ImGui::BeginChild("Controls", {s_palViewWidth - 8, paneSize.y}, true); { auto const controlsSize = ImGui::GetContentRegionAvail(); - ImGui::BeginChild("ToolBox", {168, 32}, true); + ImGui::BeginChild("ToolBox", {0, 32}, true); { auto const btnSz = ImVec2{45, 14}; if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) { @@ -230,9 +236,16 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept { m_tool = TileSheetTool::Fill; m_model.clearSelection(); } + ImGui::SameLine(); + if (ImGui::Selectable("Line", m_tool == TileSheetTool::Line, 0, btnSz)) { + m_tool = TileSheetTool::Line; + m_model.clearSelection(); + } + //ImGui::SameLine(); + //size_t i{}; + //ig::ComboBox("##Operations", ox::Array{"Operations"}, i); } ImGui::EndChild(); - ImGui::SameLine(); ImGui::BeginChild("OperationsBox", {0, 32}, true); { auto constexpr btnSz = ImVec2{55, 16}; @@ -448,6 +461,9 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept { case TileSheetTool::Fill: m_view.clickFill(fbSize, clickPos(winPos, mousePos)); break; + case TileSheetTool::Line: + m_view.clickLine(fbSize, clickPos(winPos, mousePos)); + break; case TileSheetTool::Select: m_view.clickSelect(fbSize, clickPos(winPos, mousePos)); break; diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp index 788c5f3f..954ef891 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.cpp @@ -140,11 +140,15 @@ size_t TileSheetEditorModel::palettePage() const noexcept { return m_palettePage; } -void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const palIdx) noexcept { +void TileSheetEditorModel::drawCommand(ox::Point const &pt, std::size_t const palIdx) noexcept { + if (m_lastDrawUpdatePt == pt) { + return; + } auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx); if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { return; } + m_lastDrawUpdatePt = pt; auto const idx = gfx::idx(activeSubSheet, pt); if (m_ongoingDrawCommand) { m_updated = m_updated || m_ongoingDrawCommand->append(idx); @@ -154,6 +158,26 @@ void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const pal } } +void TileSheetEditorModel::drawLineCommand(ox::Point const &pt, std::size_t const palIdx) noexcept { + if (m_lastDrawUpdatePt == pt) { + return; + } + auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx); + if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { + return; + } + m_lastDrawUpdatePt = pt; + auto const idx = gfx::idx(activeSubSheet, pt); + if (m_ongoingDrawCommand) { + m_ongoingDrawCommand->lineUpdate(m_lineStartPt, pt); + m_updated = true; + } else if (getPixel(activeSubSheet, idx) != palIdx) { + std::ignore = pushCommand(ox::make( + m_img, m_activeSubsSheetIdx, idx, static_cast(palIdx))); + m_lineStartPt = pt; + } +} + void TileSheetEditorModel::endDrawCommand() noexcept { m_ongoingDrawCommand = nullptr; } diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp index c6f930e4..95cab4f4 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditormodel.hpp @@ -34,6 +34,8 @@ class TileSheetEditorModel: public ox::SignalHandler { class DrawCommand *m_ongoingDrawCommand = nullptr; studio::SelectionTracker m_selTracker; ox::Optional m_selection; + ox::Point m_lineStartPt; + ox::Point m_lastDrawUpdatePt; bool m_updated = false; public: @@ -71,6 +73,8 @@ class TileSheetEditorModel: public ox::SignalHandler { void drawCommand(ox::Point const&pt, std::size_t palIdx) noexcept; + void drawLineCommand(ox::Point const&pt, std::size_t palIdx) noexcept; + void endDrawCommand() noexcept; void addSubsheet(TileSheet::SubSheetIdx const&parentIdx) noexcept; diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.cpp index 03fdaee6..0776a9a8 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.cpp @@ -11,7 +11,8 @@ namespace nostalgia::gfx { -TileSheetEditorView::TileSheetEditorView(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack): +TileSheetEditorView::TileSheetEditorView( + studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack): m_model(sctx, path, undoStack), m_pixelsDrawer(m_model) { glBindVertexArray(0); @@ -76,6 +77,11 @@ void TileSheetEditorView::clickDraw(ox::Vec2 const&paneSize, ox::Vec2 const&clic m_model.drawCommand(pt, m_palIdx); } +void TileSheetEditorView::clickLine(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { + auto const pt = clickPoint(paneSize, clickPos); + m_model.drawLineCommand(pt, m_palIdx); +} + void TileSheetEditorView::clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { auto const pt = clickPoint(paneSize, clickPos); m_model.select(pt); @@ -90,6 +96,7 @@ void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept { switch (tool) { case TileSheetTool::Draw: case TileSheetTool::Fill: + case TileSheetTool::Line: m_model.endDrawCommand(); break; case TileSheetTool::Select: diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.hpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.hpp index a3198151..b0dbab27 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.hpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/tilesheeteditorview.hpp @@ -23,6 +23,7 @@ enum class TileSheetTool { Select, Draw, Fill, + Line, }; [[nodiscard]] @@ -34,6 +35,8 @@ constexpr auto toString(TileSheetTool t) noexcept { return "Draw"; case TileSheetTool::Fill: return "Fill"; + case TileSheetTool::Line: + return "Line"; case TileSheetTool::None: return "None"; } @@ -53,7 +56,7 @@ class TileSheetEditorView: public ox::SignalHandler { std::size_t m_palIdx = 0; public: - TileSheetEditorView(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack); + TileSheetEditorView(studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack); ~TileSheetEditorView() override = default; @@ -65,6 +68,8 @@ class TileSheetEditorView: public ox::SignalHandler { void clickDraw(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; + void clickLine(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; + void clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; From 804d78e116ca07a13f0a3bd053875657fb6dfbcd Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 1 Feb 2025 15:14:24 -0600 Subject: [PATCH 21/21] [nostalgia/gfx/studio] Cleanup --- .../gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp index 8f6c46ef..b84b0f6a 100644 --- a/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp +++ b/src/nostalgia/modules/gfx/src/studio/tilesheeteditor/commands/drawcommand.cpp @@ -3,7 +3,6 @@ */ #include -#include #include "drawcommand.hpp" @@ -120,7 +119,8 @@ void DrawCommand::lineUpdate(ox::Point a, ox::Point b) noexcept { if (a.x > b.x) { --b.x; } iterateLine(a, b, [this, &ss](int32_t const x, int32_t const y, int32_t const h) { int const mod = h < 0 ? -1 : 1; - for (int32_t i{}; i < abs(h); ++i) { + auto const range = h * mod; + for (int32_t i{}; i < range; ++i) { auto const idx = ptToIdx(x, y + i * mod, ss.columns * TileWidth); if (idx < ss.pixels.size()) { m_changes.emplace_back(static_cast(idx), getPixel(ss, idx));