[nostalgia/core/studio] Add copy/cut/paste support to TileSheet Editor

This commit is contained in:
2022-03-10 20:42:21 -06:00
parent a6983ce53b
commit 415c2574bb
3 changed files with 154 additions and 65 deletions
@@ -2,14 +2,26 @@
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/claw/read.hpp>
#include <ox/claw/write.hpp>
#include <nostalgia/core/clipboard.hpp>
#include <nostalgia/core/media.hpp>
#include <ox/std/buffer.hpp>
#include "tilesheeteditormodel.hpp"
namespace nostalgia::core {
void TileSheetClipboard::addPixel(const geo::Point &pt, uint16_t colorIdx) noexcept {
m_pixels.emplace_back(colorIdx, pt);
}
void TileSheetClipboard::clear() noexcept {
m_pixels.clear();
}
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
m_ctx = ctx;
m_path = path;
@@ -20,26 +32,59 @@ TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path)
}
void TileSheetEditorModel::cut() {
TileSheetClipboard cb;
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
auto pt = geo::Point(x, y);
const auto s = activeSubSheet();
const auto idx = s->idx(pt);
const auto c = s->getPixel(m_img.bpp, idx);
s->setPixel(m_img.bpp, idx, 0);
pt.x -= m_selectionBounds.x;
pt.y -= m_selectionBounds.y;
cb.addPixel(pt, c);
}
}
setClipboardObject(m_ctx, &cb);
}
void TileSheetEditorModel::copy() {
TileSheetClipboard cb;
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
auto pt = geo::Point(x, y);
const auto s = activeSubSheet();
const auto idx = s->idx(pt);
const auto c = s->getPixel(m_img.bpp, idx);
pt.x -= m_selectionBounds.x;
pt.y -= m_selectionBounds.y;
cb.addPixel(pt, c);
}
}
setClipboardObject(m_ctx, &cb);
}
void TileSheetEditorModel::paste() {
auto [cb, err] = getClipboardObject<TileSheetClipboard>(m_ctx);
if (err) {
oxLogError(err);
oxErrf("Could not read clipboard: {}", toStr(err));
return;
}
const auto pt = m_selectionOrigin == geo::Point(-1, -1) ? geo::Point(0, 0) : m_selectionOrigin;
pushCommand(new PasteCommand(&m_img, m_activeSubsSheetIdx, pt, cb));
}
void TileSheetEditorModel::drawCommand(const geo::Point &pt, std::size_t palIdx) noexcept {
auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
const auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx);
const auto idx = ptToIdx(pt, activeSubSheet.columns);
if (idx >= activeSubSheet.pixelCnt(m_img.bpp)) {
return;
}
if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idx);
} else {
if (activeSubSheet.getPixel(m_img.bpp, idx) != palIdx) {
pushCommand(new DrawCommand(&m_img, m_activeSubsSheetIdx, idx, palIdx));
}
} else if (activeSubSheet.getPixel(m_img.bpp, idx) != palIdx) {
pushCommand(new DrawCommand(&m_img, m_activeSubsSheetIdx, idx, palIdx));
}
}
@@ -67,12 +112,12 @@ void TileSheetEditorModel::setActiveSubsheet(const TileSheet::SubSheetIdx &idx)
void TileSheetEditorModel::select(const geo::Point &pt) noexcept {
if (!m_selectionOngoing) {
m_selectionPt1 = pt;
m_selectionOrigin = pt;
m_selectionOngoing = true;
}
if (m_selectionPt2 != pt) {
m_selectionPt2 = pt;
m_selectionBounds = {m_selectionPt1, m_selectionPt2};
m_selectionBounds = {pt, pt};
m_updated = true;
} else if (m_selectionBounds.pt2() != pt) {
m_selectionBounds = {m_selectionOrigin, pt};
m_updated = true;
}
}
@@ -83,9 +128,8 @@ void TileSheetEditorModel::completeSelection() noexcept {
void TileSheetEditorModel::clearSelection() noexcept {
m_updated = true;
m_selectionPt1 = {-1, -1};
m_selectionPt2 = {-1, -1};
m_selectionBounds = {m_selectionPt1, m_selectionPt2};
m_selectionOrigin = {-1, -1};
m_selectionBounds = {{-1, -1}, {-1, -1}};
}
bool TileSheetEditorModel::updated() const noexcept {
@@ -105,6 +149,7 @@ ox::Error TileSheetEditorModel::markUpdated(int cmdId) noexcept {
break;
}
case CommandId::Draw:
case CommandId::Paste:
case CommandId::UpdateSubSheet:
break;
}
@@ -116,19 +161,19 @@ void TileSheetEditorModel::ackUpdate() noexcept {
}
ox::Error TileSheetEditorModel::saveFile() noexcept {
auto sctx = applicationData<studio::StudioContext>(m_ctx);
const auto sctx = applicationData<studio::StudioContext>(m_ctx);
oxReturnError(sctx->project->writeObj(m_path, &m_img));
return m_ctx->assetManager.setAsset(m_path, m_img).error;
}
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
auto s = activeSubSheet();
auto pt = idxToPt(idx, s->columns);
const auto s = activeSubSheet();
const auto pt = idxToPt(idx, s->columns);
return m_selectionBounds.contains(pt);
}
void TileSheetEditorModel::getFillPixels(bool *pixels, const geo::Point &pt, int oldColor) const noexcept {
auto &activeSubSheet = *this->activeSubSheet();
const auto &activeSubSheet = *this->activeSubSheet();
const auto tileIdx = [activeSubSheet](const geo::Point &pt) noexcept {
return ptToIdx(pt, activeSubSheet.columns) / PixelsPerTile;
};