[nostalgia] Add basic support for subsheets
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
@@ -15,13 +16,19 @@ namespace nostalgia::core {
|
||||
|
||||
// Command IDs to use with QUndoCommand::id()
|
||||
enum class CommandId {
|
||||
UpdatePixel = 1,
|
||||
ModPixel = 2,
|
||||
UpdateDimension = 3,
|
||||
InsertTile = 4,
|
||||
ClipboardPaste = 5,
|
||||
Draw = 1,
|
||||
AddSubSheet = 2,
|
||||
RmSubSheet = 3,
|
||||
};
|
||||
|
||||
constexpr bool operator==(CommandId c, int i) noexcept {
|
||||
return static_cast<int>(c) == i;
|
||||
}
|
||||
|
||||
constexpr bool operator==(int i, CommandId c) noexcept {
|
||||
return static_cast<int>(c) == i;
|
||||
}
|
||||
|
||||
struct DrawCommand: public studio::UndoCommand {
|
||||
private:
|
||||
struct Change {
|
||||
@@ -29,25 +36,29 @@ struct DrawCommand: public studio::UndoCommand {
|
||||
uint16_t oldPalIdx = 0;
|
||||
};
|
||||
TileSheet *m_img = nullptr;
|
||||
TileSheet::SubSheetIdx m_subSheetIdx;
|
||||
ox::Vector<Change, 8> m_changes;
|
||||
int m_palIdx = 0;
|
||||
|
||||
public:
|
||||
constexpr DrawCommand(TileSheet *img, std::size_t idx, int palIdx) noexcept {
|
||||
constexpr DrawCommand(TileSheet *img, const TileSheet::SubSheetIdx &subSheetIdx, std::size_t idx, int palIdx) noexcept {
|
||||
m_img = img;
|
||||
m_changes.emplace_back(idx, m_img->getPixel(idx));
|
||||
auto &subsheet = m_img->getSubSheet(subSheetIdx);
|
||||
m_subSheetIdx = subSheetIdx;
|
||||
m_changes.emplace_back(idx, subsheet.getPixel(m_img->bpp, idx));
|
||||
m_palIdx = palIdx;
|
||||
}
|
||||
|
||||
constexpr auto append(std::size_t idx) noexcept {
|
||||
if (m_changes.back().value.idx != idx && m_img->getPixel(idx) != m_palIdx) {
|
||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||
if (m_changes.back().value.idx != idx && subsheet.getPixel(m_img->bpp, idx) != m_palIdx) {
|
||||
// duplicate entries are bad
|
||||
auto existing = std::find_if(m_changes.cbegin(), m_changes.cend(), [idx](const auto &c) {
|
||||
return c.idx == idx;
|
||||
});
|
||||
if (existing == m_changes.cend()) {
|
||||
m_changes.emplace_back(idx, m_img->getPixel(idx));
|
||||
m_img->setPixel(idx, m_palIdx);
|
||||
m_changes.emplace_back(idx, subsheet.getPixel(m_img->bpp, idx));
|
||||
subsheet.setPixel(m_img->bpp, idx, m_palIdx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -55,17 +66,118 @@ struct DrawCommand: public studio::UndoCommand {
|
||||
}
|
||||
|
||||
void redo() noexcept final {
|
||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||
for (const auto &c : m_changes) {
|
||||
m_img->setPixel(c.idx, m_palIdx);
|
||||
subsheet.setPixel(m_img->bpp, c.idx, m_palIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void undo() noexcept final {
|
||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||
for (const auto &c : m_changes) {
|
||||
m_img->setPixel(c.idx, c.oldPalIdx);
|
||||
subsheet.setPixel(m_img->bpp, c.idx, c.oldPalIdx);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int commandId() const noexcept final {
|
||||
return static_cast<int>(CommandId::Draw);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct AddSubSheetCommand: public studio::UndoCommand {
|
||||
private:
|
||||
TileSheet *m_img = nullptr;
|
||||
TileSheet::SubSheetIdx m_parentIdx;
|
||||
ox::Vector<TileSheet::SubSheetIdx, 2> m_addedSheets;
|
||||
|
||||
public:
|
||||
constexpr AddSubSheetCommand(TileSheet *img, const TileSheet::SubSheetIdx &parentIdx) noexcept {
|
||||
m_img = img;
|
||||
m_parentIdx = parentIdx;
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
if (parent.subsheets.size()) {
|
||||
auto idx = m_parentIdx;
|
||||
idx.emplace_back(parent.subsheets.size());
|
||||
m_addedSheets.push_back(idx);
|
||||
} else {
|
||||
auto idx = m_parentIdx;
|
||||
idx.emplace_back(0);
|
||||
m_addedSheets.push_back(idx);
|
||||
idx.back().value = 1;
|
||||
m_addedSheets.push_back(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void redo() noexcept final {
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
if (m_addedSheets.size() < 2) {
|
||||
auto i = parent.subsheets.size();
|
||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i).c_str(), 1, 1);
|
||||
} else {
|
||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
|
||||
parent.rows = 0;
|
||||
parent.columns = 0;
|
||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void undo() noexcept final {
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
if (parent.subsheets.size() == 2) {
|
||||
auto s = parent.subsheets[0];
|
||||
parent.rows = s.rows;
|
||||
parent.columns = s.columns;
|
||||
parent.pixels = std::move(s.pixels);
|
||||
parent.subsheets.clear();
|
||||
} else {
|
||||
for (auto idx = m_addedSheets.rbegin(); idx != m_addedSheets.rend(); ++idx) {
|
||||
oxLogError(m_img->rmSubSheet(*idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int commandId() const noexcept final {
|
||||
return static_cast<int>(CommandId::AddSubSheet);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct RmSubSheetCommand: public studio::UndoCommand {
|
||||
private:
|
||||
TileSheet *m_img = nullptr;
|
||||
TileSheet::SubSheetIdx m_idx;
|
||||
TileSheet::SubSheetIdx m_parentIdx;
|
||||
TileSheet::SubSheet m_sheet;
|
||||
|
||||
public:
|
||||
constexpr RmSubSheetCommand(TileSheet *img, const TileSheet::SubSheetIdx &idx) noexcept {
|
||||
m_img = img;
|
||||
m_idx = idx;
|
||||
m_parentIdx = idx;
|
||||
m_parentIdx.pop_back();
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
m_sheet = parent.subsheets[idx.back().value];
|
||||
}
|
||||
|
||||
void redo() noexcept final {
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
oxLogError(parent.subsheets.erase(m_idx.back().value).error);
|
||||
}
|
||||
|
||||
void undo() noexcept final {
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
auto i = m_idx.back().value;
|
||||
parent.subsheets.insert(i, m_sheet);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int commandId() const noexcept final {
|
||||
return static_cast<int>(CommandId::RmSubSheet);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct TileSheetClipboard {
|
||||
@@ -109,8 +221,12 @@ oxModelEnd()
|
||||
|
||||
class TileSheetEditorModel: public ox::SignalHandler {
|
||||
|
||||
public:
|
||||
ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged;
|
||||
|
||||
private:
|
||||
TileSheet m_img;
|
||||
TileSheet::SubSheetIdx m_activeSubsSheetIdx;
|
||||
AssetRef<Palette> m_pal;
|
||||
studio::UndoStack m_undoStack;
|
||||
DrawCommand *m_ongoingDrawCommand = nullptr;
|
||||
@@ -142,18 +258,36 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
|
||||
void endDrawCommand() noexcept;
|
||||
|
||||
void addSubsheet(const TileSheet::SubSheetIdx &parentIdx) noexcept;
|
||||
|
||||
void rmSubsheet(const TileSheet::SubSheetIdx &idx) noexcept;
|
||||
|
||||
void setActiveSubsheet(const TileSheet::SubSheetIdx&) noexcept;
|
||||
|
||||
constexpr const TileSheet::SubSheet *activeSubSheet() const noexcept {
|
||||
auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
|
||||
return &activeSubSheet;
|
||||
}
|
||||
|
||||
constexpr TileSheet::SubSheet *activeSubSheet() noexcept {
|
||||
auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
|
||||
return &activeSubSheet;
|
||||
}
|
||||
|
||||
constexpr const TileSheet::SubSheetIdx &activeSubSheetIdx() const noexcept {
|
||||
return m_activeSubsSheetIdx;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool updated() const noexcept;
|
||||
|
||||
ox::Error markUpdated() noexcept;
|
||||
ox::Error markUpdated(int) noexcept;
|
||||
|
||||
void ackUpdate() noexcept;
|
||||
|
||||
ox::Error saveFile() noexcept;
|
||||
|
||||
constexpr studio::UndoStack *undoStack() noexcept {
|
||||
return &m_undoStack;
|
||||
}
|
||||
constexpr studio::UndoStack *undoStack() noexcept;
|
||||
|
||||
protected:
|
||||
void saveItem();
|
||||
@@ -189,4 +323,8 @@ constexpr const Palette &TileSheetEditorModel::pal() const noexcept {
|
||||
return *m_pal;
|
||||
}
|
||||
|
||||
}
|
||||
constexpr studio::UndoStack *TileSheetEditorModel::undoStack() noexcept {
|
||||
return &m_undoStack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user