[nostalgia/core] Add Fill command to tilesheet editor and make ClipboardObject more efficient
This commit is contained in:
parent
ae80d22769
commit
7df978605f
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ox/claw/claw.hpp>
|
#include <ox/claw/claw.hpp>
|
||||||
|
#include <ox/std/memory.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
|
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
@ -15,32 +16,21 @@ ox::String getClipboardText(class Context *ctx) noexcept;
|
|||||||
|
|
||||||
void setClipboardText(class Context *ctx, const ox::String &text) noexcept;
|
void setClipboardText(class Context *ctx, const ox::String &text) noexcept;
|
||||||
|
|
||||||
void setClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] auto *obj) noexcept {
|
template<typename T>
|
||||||
|
void setClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] ox::UniquePtr<T> obj) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
auto [buff, err] = ox::writeClaw(obj);
|
ctx->clipboard = std::move(obj);
|
||||||
if (err) {
|
|
||||||
oxLogError(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx->clipboard = std::move(buff);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error getClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] auto *obj) noexcept {
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
return ox::readClaw<decltype(*obj)>(ctx->clipboard).moveTo(obj);
|
|
||||||
#else
|
|
||||||
return OxError(0);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> getClipboardObject([[maybe_unused]] class Context *ctx) noexcept {
|
ox::Result<T*> getClipboardObject([[maybe_unused]] class Context *ctx) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
return ox::readClaw<T>(ctx->clipboard);
|
if (ctx->clipboard && ctx->clipboard->typeMatch(T::TypeName, T::TypeVersion)) {
|
||||||
#else
|
return static_cast<T*>(ctx->clipboard.get());
|
||||||
return OxError(0);
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,25 @@ class Size;
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
class BaseClipboardObject {
|
||||||
|
public:
|
||||||
|
virtual ~BaseClipboardObject() = default;
|
||||||
|
|
||||||
|
virtual ox::String typeId() const noexcept = 0;
|
||||||
|
|
||||||
|
constexpr auto typeMatch(auto name, auto version) const noexcept {
|
||||||
|
auto inId = ox::sfmt("{};{}", name, version);
|
||||||
|
return typeId() == inId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ClipboardObject: public BaseClipboardObject {
|
||||||
|
ox::String typeId() const noexcept final {
|
||||||
|
return ox::sfmt("{};{}", T::TypeName, T::TypeVersion);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
class Drawer;
|
class Drawer;
|
||||||
|
|
||||||
@ -59,7 +78,7 @@ class Context {
|
|||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
AssetManager assetManager;
|
AssetManager assetManager;
|
||||||
int uninterruptedRefreshes = 0;
|
int uninterruptedRefreshes = 0;
|
||||||
ox::Buffer clipboard;
|
ox::UniquePtr<BaseClipboardObject> clipboard;
|
||||||
#endif
|
#endif
|
||||||
protected:
|
protected:
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
|
@ -56,7 +56,7 @@ void TileSheetEditorImGui::draw(core::Context*) noexcept {
|
|||||||
{
|
{
|
||||||
ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
|
ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
|
||||||
{
|
{
|
||||||
const auto btnSz = ImVec2(40, 14);
|
const auto btnSz = ImVec2(45, 14);
|
||||||
if (ImGui::Selectable("Draw", m_tool == Tool::Draw, 0, btnSz)) {
|
if (ImGui::Selectable("Draw", m_tool == Tool::Draw, 0, btnSz)) {
|
||||||
m_tool = Tool::Draw;
|
m_tool = Tool::Draw;
|
||||||
model()->clearSelection();
|
model()->clearSelection();
|
||||||
@ -65,6 +65,11 @@ void TileSheetEditorImGui::draw(core::Context*) noexcept {
|
|||||||
if (ImGui::Selectable("Select", m_tool == Tool::Select, 0, btnSz)) {
|
if (ImGui::Selectable("Select", m_tool == Tool::Select, 0, btnSz)) {
|
||||||
m_tool = Tool::Select;
|
m_tool = Tool::Select;
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Selectable("Fill", m_tool == Tool::Fill, 0, btnSz)) {
|
||||||
|
m_tool = Tool::Fill;
|
||||||
|
model()->clearSelection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
const auto ySize = paneSize.y - 36;
|
const auto ySize = paneSize.y - 36;
|
||||||
@ -212,10 +217,13 @@ void TileSheetEditorImGui::drawTileSheet(const geo::Vec2 &fbSize) noexcept {
|
|||||||
m_tileSheetEditor.clickDraw(fbSize, clickPos);
|
m_tileSheetEditor.clickDraw(fbSize, clickPos);
|
||||||
break;
|
break;
|
||||||
case Tool::Fill:
|
case Tool::Fill:
|
||||||
case Tool::None:
|
m_tileSheetEditor.clickFill(fbSize, clickPos);
|
||||||
|
break;
|
||||||
case Tool::Select:
|
case Tool::Select:
|
||||||
m_tileSheetEditor.clickSelect(fbSize, clickPos);
|
m_tileSheetEditor.clickSelect(fbSize, clickPos);
|
||||||
break;
|
break;
|
||||||
|
case Tool::None:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,320 @@
|
|||||||
#include <nostalgia/core/clipboard.hpp>
|
#include <nostalgia/core/clipboard.hpp>
|
||||||
#include <nostalgia/core/media.hpp>
|
#include <nostalgia/core/media.hpp>
|
||||||
#include <ox/std/buffer.hpp>
|
#include <ox/std/buffer.hpp>
|
||||||
|
#include <ox/std/memory.hpp>
|
||||||
|
|
||||||
#include "tilesheeteditormodel.hpp"
|
#include "tilesheeteditormodel.hpp"
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
void TileSheetClipboard::addPixel(const geo::Point &pt, uint16_t colorIdx) noexcept {
|
class TileSheetClipboard: public ClipboardObject<TileSheetClipboard> {
|
||||||
m_pixels.emplace_back(colorIdx, pt);
|
public:
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
|
||||||
|
oxModelFriend(TileSheetClipboard);
|
||||||
|
|
||||||
|
struct Pixel {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard.Pixel";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
uint16_t colorIdx = 0;
|
||||||
|
geo::Point pt;
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
ox::Vector<Pixel> m_pixels;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr void addPixel(const geo::Point &pt, uint16_t colorIdx) noexcept {
|
||||||
|
m_pixels.emplace_back(colorIdx, pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const ox::Vector<Pixel> &pixels() const noexcept {
|
||||||
|
return m_pixels;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetClipboard::Pixel)
|
||||||
|
oxModelField(colorIdx)
|
||||||
|
oxModelField(pt)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetClipboard)
|
||||||
|
oxModelFieldRename(pixels, m_pixels)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
|
||||||
|
// Command IDs to use with QUndoCommand::id()
|
||||||
|
enum class CommandId {
|
||||||
|
Draw = 1,
|
||||||
|
AddSubSheet = 2,
|
||||||
|
RmSubSheet = 3,
|
||||||
|
UpdateSubSheet = 4,
|
||||||
|
Paste = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool operator==(CommandId c, int i) noexcept {
|
||||||
|
return static_cast<int>(c) == i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetClipboard::clear() noexcept {
|
constexpr bool operator==(int i, CommandId c) noexcept {
|
||||||
m_pixels.clear();
|
return static_cast<int>(c) == i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DrawCommand: public studio::UndoCommand {
|
||||||
|
private:
|
||||||
|
struct Change {
|
||||||
|
uint32_t idx = 0;
|
||||||
|
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, const TileSheet::SubSheetIdx &subSheetIdx, std::size_t idx, int palIdx) noexcept {
|
||||||
|
m_img = img;
|
||||||
|
auto &subsheet = m_img->getSubSheet(subSheetIdx);
|
||||||
|
m_subSheetIdx = subSheetIdx;
|
||||||
|
m_changes.emplace_back(idx, subsheet.getPixel(m_img->bpp, idx));
|
||||||
|
m_palIdx = palIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr DrawCommand(TileSheet *img, const TileSheet::SubSheetIdx &subSheetIdx, ox::Vector<std::size_t> idxList, int palIdx) noexcept {
|
||||||
|
m_img = img;
|
||||||
|
auto &subsheet = m_img->getSubSheet(subSheetIdx);
|
||||||
|
m_subSheetIdx = subSheetIdx;
|
||||||
|
for (const auto idx : idxList) {
|
||||||
|
m_changes.emplace_back(idx, subsheet.getPixel(m_img->bpp, idx));
|
||||||
|
}
|
||||||
|
m_palIdx = palIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto append(std::size_t idx) noexcept {
|
||||||
|
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, subsheet.getPixel(m_img->bpp, idx));
|
||||||
|
subsheet.setPixel(m_img->bpp, idx, m_palIdx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto append(ox::Vector<std::size_t> idxList) noexcept {
|
||||||
|
auto out = false;
|
||||||
|
for (auto idx : idxList) {
|
||||||
|
out = append(idx) || out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void redo() noexcept final {
|
||||||
|
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||||
|
for (const auto &c : m_changes) {
|
||||||
|
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) {
|
||||||
|
subsheet.setPixel(m_img->bpp, c.idx, c.oldPalIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int commandId() const noexcept final {
|
||||||
|
return static_cast<int>(CommandId::Draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class PasteCommand: public studio::UndoCommand {
|
||||||
|
private:
|
||||||
|
struct Change {
|
||||||
|
uint32_t idx = 0;
|
||||||
|
uint16_t newPalIdx = 0;
|
||||||
|
uint16_t oldPalIdx = 0;
|
||||||
|
};
|
||||||
|
TileSheet *m_img = nullptr;
|
||||||
|
TileSheet::SubSheetIdx m_subSheetIdx;
|
||||||
|
ox::Vector<Change> m_changes;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr PasteCommand(TileSheet *img, const TileSheet::SubSheetIdx &subSheetIdx, const geo::Point &dstStart, const geo::Point &dstEnd, const TileSheetClipboard &cb) noexcept {
|
||||||
|
m_img = img;
|
||||||
|
m_subSheetIdx = subSheetIdx;
|
||||||
|
const auto &subsheet = m_img->getSubSheet(subSheetIdx);
|
||||||
|
for (const auto &p : cb.pixels()) {
|
||||||
|
const auto dstPt = p.pt + dstStart;
|
||||||
|
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
|
||||||
|
const auto idx = subsheet.idx(dstPt);
|
||||||
|
m_changes.emplace_back(idx, p.colorIdx, subsheet.getPixel(m_img->bpp, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void redo() noexcept final {
|
||||||
|
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||||
|
for (const auto &c : m_changes) {
|
||||||
|
subsheet.setPixel(m_img->bpp, c.idx, c.newPalIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void undo() noexcept final {
|
||||||
|
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
||||||
|
for (const auto &c : m_changes) {
|
||||||
|
subsheet.setPixel(m_img->bpp, c.idx, c.oldPalIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int commandId() const noexcept final {
|
||||||
|
return static_cast<int>(CommandId::Paste);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class UpdateSubSheetCommand: public studio::UndoCommand {
|
||||||
|
private:
|
||||||
|
TileSheet *m_img = nullptr;
|
||||||
|
TileSheet::SubSheetIdx m_idx;
|
||||||
|
TileSheet::SubSheet m_sheet;
|
||||||
|
ox::String m_newName;
|
||||||
|
int m_newCols = 0;
|
||||||
|
int m_newRows = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr UpdateSubSheetCommand(TileSheet *img, const TileSheet::SubSheetIdx &idx,
|
||||||
|
const ox::String &name, int cols, int rows) noexcept {
|
||||||
|
m_img = img;
|
||||||
|
m_idx = idx;
|
||||||
|
m_sheet = img->getSubSheet(idx);
|
||||||
|
m_newName = name;
|
||||||
|
m_newCols = cols;
|
||||||
|
m_newRows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
void redo() noexcept final {
|
||||||
|
auto &sheet = m_img->getSubSheet(m_idx);
|
||||||
|
sheet.name = m_newName;
|
||||||
|
sheet.columns = m_newCols;
|
||||||
|
sheet.rows = m_newRows;
|
||||||
|
oxLogError(sheet.setPixelCount(m_img->bpp, static_cast<std::size_t>(PixelsPerTile * m_newCols * m_newRows)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void undo() noexcept final {
|
||||||
|
auto &sheet = m_img->getSubSheet(m_idx);
|
||||||
|
sheet = m_sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int commandId() const noexcept final {
|
||||||
|
return static_cast<int>(CommandId::UpdateSubSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
|
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
|
||||||
m_ctx = ctx;
|
m_ctx = ctx;
|
||||||
@ -32,7 +333,7 @@ TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::cut() {
|
void TileSheetEditorModel::cut() {
|
||||||
TileSheetClipboard cb;
|
auto cb = ox::make_unique<TileSheetClipboard>();;
|
||||||
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||||
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||||
auto pt = geo::Point(x, y);
|
auto pt = geo::Point(x, y);
|
||||||
@ -42,14 +343,14 @@ void TileSheetEditorModel::cut() {
|
|||||||
s->setPixel(m_img.bpp, idx, 0);
|
s->setPixel(m_img.bpp, idx, 0);
|
||||||
pt.x -= m_selectionBounds.x;
|
pt.x -= m_selectionBounds.x;
|
||||||
pt.y -= m_selectionBounds.y;
|
pt.y -= m_selectionBounds.y;
|
||||||
cb.addPixel(pt, c);
|
cb->addPixel(pt, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setClipboardObject(m_ctx, &cb);
|
setClipboardObject(m_ctx, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::copy() {
|
void TileSheetEditorModel::copy() {
|
||||||
TileSheetClipboard cb;
|
auto cb = ox::make_unique<TileSheetClipboard>();;
|
||||||
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||||
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||||
auto pt = geo::Point(x, y);
|
auto pt = geo::Point(x, y);
|
||||||
@ -58,10 +359,10 @@ void TileSheetEditorModel::copy() {
|
|||||||
const auto c = s->getPixel(m_img.bpp, idx);
|
const auto c = s->getPixel(m_img.bpp, idx);
|
||||||
pt.x -= m_selectionBounds.x;
|
pt.x -= m_selectionBounds.x;
|
||||||
pt.y -= m_selectionBounds.y;
|
pt.y -= m_selectionBounds.y;
|
||||||
cb.addPixel(pt, c);
|
cb->addPixel(pt, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setClipboardObject(m_ctx, &cb);
|
setClipboardObject(m_ctx, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::paste() {
|
void TileSheetEditorModel::paste() {
|
||||||
@ -74,12 +375,12 @@ void TileSheetEditorModel::paste() {
|
|||||||
const auto s = activeSubSheet();
|
const auto s = activeSubSheet();
|
||||||
const auto pt1 = m_selectionOrigin == geo::Point(-1, -1) ? geo::Point(0, 0) : m_selectionOrigin;
|
const auto pt1 = m_selectionOrigin == geo::Point(-1, -1) ? geo::Point(0, 0) : m_selectionOrigin;
|
||||||
const auto pt2 = geo::Point(s->columns * TileWidth, s->rows * TileHeight);
|
const auto pt2 = geo::Point(s->columns * TileWidth, s->rows * TileHeight);
|
||||||
pushCommand(new PasteCommand(&m_img, m_activeSubsSheetIdx, pt1, pt2, cb));
|
pushCommand(new PasteCommand(&m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::drawCommand(const geo::Point &pt, std::size_t palIdx) noexcept {
|
void TileSheetEditorModel::drawCommand(const geo::Point &pt, std::size_t palIdx) noexcept {
|
||||||
const auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
|
const auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
|
||||||
const auto idx = ptToIdx(pt, activeSubSheet.columns);
|
const auto idx = activeSubSheet.idx(pt);
|
||||||
if (idx >= activeSubSheet.pixelCnt(m_img.bpp)) {
|
if (idx >= activeSubSheet.pixelCnt(m_img.bpp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -112,6 +413,31 @@ void TileSheetEditorModel::setActiveSubsheet(const TileSheet::SubSheetIdx &idx)
|
|||||||
this->activeSubsheetChanged.emit(m_activeSubsSheetIdx);
|
this->activeSubsheetChanged.emit(m_activeSubsSheetIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSheetEditorModel::fill(const geo::Point &pt, int palIdx) noexcept {
|
||||||
|
const auto s = m_img.getSubSheet(m_activeSubsSheetIdx);
|
||||||
|
// build idx list
|
||||||
|
ox::Array<bool, PixelsPerTile> updateMap = {};
|
||||||
|
const auto oldColor = s.getPixel(m_img.bpp, pt);
|
||||||
|
if (oldColor == palIdx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getFillPixels(updateMap.data(), pt, oldColor);
|
||||||
|
ox::Vector<std::size_t> idxList;
|
||||||
|
auto i = s.idx(pt) / PixelsPerTile * PixelsPerTile;
|
||||||
|
for (auto u : updateMap) {
|
||||||
|
if (u) {
|
||||||
|
idxList.emplace_back(i);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
// do updates to sheet
|
||||||
|
if (m_ongoingDrawCommand) {
|
||||||
|
m_updated = m_updated || m_ongoingDrawCommand->append(idxList);
|
||||||
|
} else if (s.getPixel(m_img.bpp, pt) != palIdx) {
|
||||||
|
pushCommand(new DrawCommand(&m_img, m_activeSubsSheetIdx, idxList, palIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::select(const geo::Point &pt) noexcept {
|
void TileSheetEditorModel::select(const geo::Point &pt) noexcept {
|
||||||
if (!m_selectionOngoing) {
|
if (!m_selectionOngoing) {
|
||||||
m_selectionOrigin = pt;
|
m_selectionOrigin = pt;
|
||||||
@ -193,16 +519,16 @@ void TileSheetEditorModel::getFillPixels(bool *pixels, const geo::Point &pt, int
|
|||||||
const auto tile = tileIdx(pt);
|
const auto tile = tileIdx(pt);
|
||||||
// mark pixels to update
|
// mark pixels to update
|
||||||
pixels[idx % PixelsPerTile] = true;
|
pixels[idx % PixelsPerTile] = true;
|
||||||
if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && activeSubSheet.pixels[leftIdx] == oldColor) {
|
if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && activeSubSheet.getPixel(m_img.bpp, leftIdx) == oldColor) {
|
||||||
getFillPixels(pixels, leftPt, oldColor);
|
getFillPixels(pixels, leftPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && activeSubSheet.pixels[rightIdx] == oldColor) {
|
if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && activeSubSheet.getPixel(m_img.bpp, rightIdx) == oldColor) {
|
||||||
getFillPixels(pixels, rightPt, oldColor);
|
getFillPixels(pixels, rightPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && activeSubSheet.pixels[topIdx] == oldColor) {
|
if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && activeSubSheet.getPixel(m_img.bpp, topIdx) == oldColor) {
|
||||||
getFillPixels(pixels, topPt, oldColor);
|
getFillPixels(pixels, topPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && activeSubSheet.pixels[bottomIdx] == oldColor) {
|
if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && activeSubSheet.getPixel(m_img.bpp, bottomIdx) == oldColor) {
|
||||||
getFillPixels(pixels, bottomPt, oldColor);
|
getFillPixels(pixels, bottomPt, oldColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,301 +15,6 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
class TileSheetClipboard {
|
|
||||||
public:
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
|
|
||||||
static constexpr auto TypeVersion = 1;
|
|
||||||
|
|
||||||
oxModelFriend(TileSheetClipboard);
|
|
||||||
|
|
||||||
struct Pixel {
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard.Pixel";
|
|
||||||
static constexpr auto TypeVersion = 1;
|
|
||||||
uint16_t colorIdx = 0;
|
|
||||||
geo::Point pt;
|
|
||||||
};
|
|
||||||
protected:
|
|
||||||
ox::Vector<Pixel> m_pixels;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void addPixel(const geo::Point &pt, uint16_t colorIdx) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
bool empty() const;
|
|
||||||
|
|
||||||
void pastePixels(const geo::Point &pt, ox::Vector<int> *tgt, int tgtColumns) const;
|
|
||||||
|
|
||||||
void clear() noexcept;
|
|
||||||
|
|
||||||
constexpr const ox::Vector<Pixel> &pixels() const noexcept {
|
|
||||||
return m_pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
oxModelBegin(TileSheetClipboard::Pixel)
|
|
||||||
oxModelField(colorIdx)
|
|
||||||
oxModelField(pt)
|
|
||||||
oxModelEnd()
|
|
||||||
|
|
||||||
oxModelBegin(TileSheetClipboard)
|
|
||||||
oxModelFieldRename(pixels, m_pixels)
|
|
||||||
oxModelEnd()
|
|
||||||
|
|
||||||
// Command IDs to use with QUndoCommand::id()
|
|
||||||
enum class CommandId {
|
|
||||||
Draw = 1,
|
|
||||||
AddSubSheet = 2,
|
|
||||||
RmSubSheet = 3,
|
|
||||||
UpdateSubSheet = 4,
|
|
||||||
Paste = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
uint32_t idx = 0;
|
|
||||||
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, const TileSheet::SubSheetIdx &subSheetIdx, std::size_t idx, int palIdx) noexcept {
|
|
||||||
m_img = img;
|
|
||||||
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 {
|
|
||||||
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, subsheet.getPixel(m_img->bpp, idx));
|
|
||||||
subsheet.setPixel(m_img->bpp, idx, m_palIdx);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void redo() noexcept final {
|
|
||||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
|
||||||
for (const auto &c : m_changes) {
|
|
||||||
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) {
|
|
||||||
subsheet.setPixel(m_img->bpp, c.idx, c.oldPalIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
int commandId() const noexcept final {
|
|
||||||
return static_cast<int>(CommandId::Draw);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PasteCommand: public studio::UndoCommand {
|
|
||||||
private:
|
|
||||||
struct Change {
|
|
||||||
uint32_t idx = 0;
|
|
||||||
uint16_t newPalIdx = 0;
|
|
||||||
uint16_t oldPalIdx = 0;
|
|
||||||
};
|
|
||||||
TileSheet *m_img = nullptr;
|
|
||||||
TileSheet::SubSheetIdx m_subSheetIdx;
|
|
||||||
ox::Vector<Change> m_changes;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr PasteCommand(TileSheet *img, const TileSheet::SubSheetIdx &subSheetIdx, const geo::Point &dstStart, const geo::Point &dstEnd, const TileSheetClipboard &cb) noexcept {
|
|
||||||
m_img = img;
|
|
||||||
m_subSheetIdx = subSheetIdx;
|
|
||||||
const auto &subsheet = m_img->getSubSheet(subSheetIdx);
|
|
||||||
for (const auto &p : cb.pixels()) {
|
|
||||||
const auto dstPt = p.pt + dstStart;
|
|
||||||
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
|
|
||||||
const auto idx = subsheet.idx(dstPt);
|
|
||||||
m_changes.emplace_back(idx, p.colorIdx, subsheet.getPixel(m_img->bpp, idx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void redo() noexcept final {
|
|
||||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
|
||||||
for (const auto &c : m_changes) {
|
|
||||||
subsheet.setPixel(m_img->bpp, c.idx, c.newPalIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void undo() noexcept final {
|
|
||||||
auto &subsheet = m_img->getSubSheet(m_subSheetIdx);
|
|
||||||
for (const auto &c : m_changes) {
|
|
||||||
subsheet.setPixel(m_img->bpp, c.idx, c.oldPalIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
int commandId() const noexcept final {
|
|
||||||
return static_cast<int>(CommandId::Paste);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
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 UpdateSubSheetCommand: public studio::UndoCommand {
|
|
||||||
private:
|
|
||||||
TileSheet *m_img = nullptr;
|
|
||||||
TileSheet::SubSheetIdx m_idx;
|
|
||||||
TileSheet::SubSheet m_sheet;
|
|
||||||
ox::String m_newName;
|
|
||||||
int m_newCols = 0;
|
|
||||||
int m_newRows = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr UpdateSubSheetCommand(TileSheet *img, const TileSheet::SubSheetIdx &idx,
|
|
||||||
const ox::String &name, int cols, int rows) noexcept {
|
|
||||||
m_img = img;
|
|
||||||
m_idx = idx;
|
|
||||||
m_sheet = img->getSubSheet(idx);
|
|
||||||
m_newName = name;
|
|
||||||
m_newCols = cols;
|
|
||||||
m_newRows = rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
void redo() noexcept final {
|
|
||||||
auto &sheet = m_img->getSubSheet(m_idx);
|
|
||||||
sheet.name = m_newName;
|
|
||||||
sheet.columns = m_newCols;
|
|
||||||
sheet.rows = m_newRows;
|
|
||||||
oxLogError(sheet.setPixelCount(m_img->bpp, static_cast<std::size_t>(PixelsPerTile * m_newCols * m_newRows)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void undo() noexcept final {
|
|
||||||
auto &sheet = m_img->getSubSheet(m_idx);
|
|
||||||
sheet = m_sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
int commandId() const noexcept final {
|
|
||||||
return static_cast<int>(CommandId::UpdateSubSheet);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class TileSheetEditorModel: public ox::SignalHandler {
|
class TileSheetEditorModel: public ox::SignalHandler {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -320,7 +25,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
TileSheet::SubSheetIdx m_activeSubsSheetIdx;
|
TileSheet::SubSheetIdx m_activeSubsSheetIdx;
|
||||||
AssetRef<Palette> m_pal;
|
AssetRef<Palette> m_pal;
|
||||||
studio::UndoStack m_undoStack;
|
studio::UndoStack m_undoStack;
|
||||||
DrawCommand *m_ongoingDrawCommand = nullptr;
|
class DrawCommand *m_ongoingDrawCommand = nullptr;
|
||||||
bool m_updated = false;
|
bool m_updated = false;
|
||||||
Context *m_ctx = nullptr;
|
Context *m_ctx = nullptr;
|
||||||
ox::String m_path;
|
ox::String m_path;
|
||||||
@ -374,6 +79,8 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
return m_activeSubsSheetIdx;
|
return m_activeSubsSheetIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fill(const geo::Point &pt, int palIdx) noexcept;
|
||||||
|
|
||||||
void select(const geo::Point &pt) noexcept;
|
void select(const geo::Point &pt) noexcept;
|
||||||
|
|
||||||
void completeSelection() noexcept;
|
void completeSelection() noexcept;
|
||||||
@ -394,8 +101,6 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
bool pixelSelected(std::size_t idx) const noexcept;
|
bool pixelSelected(std::size_t idx) const noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void saveItem();
|
|
||||||
|
|
||||||
void getFillPixels(bool *pixels, const geo::Point &pt, int oldColor) const noexcept;
|
void getFillPixels(bool *pixels, const geo::Point &pt, int oldColor) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -53,7 +53,6 @@ void TileSheetEditorView::scrollH(const geo::Vec2 &paneSz, float wheelh) noexcep
|
|||||||
void TileSheetEditorView::clickDraw(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
|
void TileSheetEditorView::clickDraw(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
|
||||||
const auto pt = clickPoint(paneSize, clickPos);
|
const auto pt = clickPoint(paneSize, clickPos);
|
||||||
m_model.drawCommand(pt, m_palIdx);
|
m_model.drawCommand(pt, m_palIdx);
|
||||||
m_model.clearSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorView::clickSelect(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
|
void TileSheetEditorView::clickSelect(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
|
||||||
@ -61,6 +60,11 @@ void TileSheetEditorView::clickSelect(const geo::Vec2 &paneSize, const geo::Vec2
|
|||||||
m_model.select(pt);
|
m_model.select(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSheetEditorView::clickFill(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
|
||||||
|
const auto pt = clickPoint(paneSize, clickPos);
|
||||||
|
m_model.fill(pt, m_palIdx);
|
||||||
|
}
|
||||||
|
|
||||||
void TileSheetEditorView::releaseMouseButton() noexcept {
|
void TileSheetEditorView::releaseMouseButton() noexcept {
|
||||||
m_model.endDrawCommand();
|
m_model.endDrawCommand();
|
||||||
m_model.completeSelection();
|
m_model.completeSelection();
|
||||||
|
@ -59,6 +59,8 @@ class TileSheetEditorView: public ox::SignalHandler {
|
|||||||
|
|
||||||
void clickSelect(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
|
void clickSelect(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
|
||||||
|
|
||||||
|
void clickFill(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
|
||||||
|
|
||||||
void releaseMouseButton() noexcept;
|
void releaseMouseButton() noexcept;
|
||||||
|
|
||||||
void scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept;
|
void scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept;
|
||||||
|
Loading…
Reference in New Issue
Block a user