Compare commits
9 Commits
f189469926
...
b968ec8a91
Author | SHA1 | Date | |
---|---|---|---|
b968ec8a91 | |||
ec45ffb794 | |||
97dc027498 | |||
a138f60fea | |||
791d19504e | |||
78eb8fca28 | |||
0b8051b6cc | |||
5a426829f2 | |||
9d2fe0e814 |
17
deps/ox/src/ox/preloader/preloader.hpp
vendored
17
deps/ox/src/ox/preloader/preloader.hpp
vendored
@ -94,7 +94,7 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
|
||||
}
|
||||
|
||||
template<typename U, bool force>
|
||||
constexpr ox::Error field(CRStringView, const ox::UnionView<U, force> val) noexcept;
|
||||
constexpr ox::Error field(CRStringView, ox::UnionView<U, force> val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error field(CRStringView, const T *val) noexcept;
|
||||
@ -135,6 +135,9 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
|
||||
constexpr ox::Error fieldArray(CRStringView name, ox::ModelValueArray const*val) noexcept;
|
||||
|
||||
constexpr bool unionCheckAndIt() noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr size_t calcPadding(size_t align) const noexcept;
|
||||
};
|
||||
|
||||
template<typename PlatSpec>
|
||||
@ -265,7 +268,7 @@ template<typename PlatSpec>
|
||||
constexpr ox::Result<std::size_t> Preloader<PlatSpec>::startAlloc(size_t sz, size_t align) noexcept {
|
||||
m_allocStack.emplace_back(static_cast<typename PlatSpec::PtrType>(m_writer.tellp()));
|
||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||
const auto padding = m_writer.tellp() % align;
|
||||
auto const padding = calcPadding(align);
|
||||
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
||||
a += padding;
|
||||
oxReturnError(m_writer.seekp(a));
|
||||
@ -278,7 +281,7 @@ constexpr ox::Result<std::size_t> Preloader<PlatSpec>::startAlloc(
|
||||
std::size_t sz, size_t align, std::size_t restore) noexcept {
|
||||
m_allocStack.emplace_back(restore, ox::ios_base::beg);
|
||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||
const auto padding = m_writer.tellp() % align;
|
||||
auto const padding = calcPadding(align);
|
||||
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
||||
a += padding;
|
||||
oxReturnError(m_writer.seekp(a));
|
||||
@ -358,7 +361,7 @@ constexpr ox::Error Preloader<PlatSpec>::fieldVector(
|
||||
const auto sz = sizeOf<PlatSpec>(&(*val)[0]) * val->size();
|
||||
const auto align = alignOf<PlatSpec>((*val)[0]);
|
||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||
const auto padding = m_writer.tellp() % align;
|
||||
auto const padding = calcPadding(align);
|
||||
oxRequireM(p, ox::allocate(m_writer, sz + padding));
|
||||
p += padding;
|
||||
oxReturnError(m_writer.seekp(p));
|
||||
@ -394,6 +397,12 @@ constexpr bool Preloader<PlatSpec>::unionCheckAndIt() noexcept {
|
||||
return u.checkAndIterate();
|
||||
}
|
||||
|
||||
template<typename PlatSpec>
|
||||
constexpr size_t Preloader<PlatSpec>::calcPadding(size_t align) const noexcept {
|
||||
auto const excess = m_writer.tellp() % align;
|
||||
return (align * (excess != 0)) - excess;
|
||||
}
|
||||
|
||||
template<typename PlatSpec, typename T>
|
||||
constexpr ox::Error preload(Preloader<PlatSpec> *pl, ox::CommonPtrWith<T> auto *obj) noexcept {
|
||||
oxReturnError(model(pl->interface(), obj));
|
||||
|
@ -105,6 +105,10 @@ void TileSheetEditorImGui::paste() {
|
||||
m_model.paste();
|
||||
}
|
||||
|
||||
bool TileSheetEditorImGui::acceptsClipboardPayload() const noexcept {
|
||||
return m_model.acceptsClipboardPayload();
|
||||
}
|
||||
|
||||
void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
||||
if (!down) {
|
||||
return;
|
||||
@ -118,18 +122,18 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
||||
if (!popupOpen) {
|
||||
auto const colorCnt = pal.pages[m_model.palettePage()].size();
|
||||
if (key == turbine::Key::Alpha_D) {
|
||||
m_tool = Tool::Draw;
|
||||
m_tool = TileSheetTool::Draw;
|
||||
setCopyEnabled(false);
|
||||
setCutEnabled(false);
|
||||
setPasteEnabled(false);
|
||||
m_model.clearSelection();
|
||||
} else if (key == turbine::Key::Alpha_S) {
|
||||
m_tool = Tool::Select;
|
||||
m_tool = TileSheetTool::Select;
|
||||
setCopyEnabled(true);
|
||||
setCutEnabled(true);
|
||||
setPasteEnabled(true);
|
||||
} else if (key == turbine::Key::Alpha_F) {
|
||||
m_tool = Tool::Fill;
|
||||
m_tool = TileSheetTool::Fill;
|
||||
setCopyEnabled(false);
|
||||
setCutEnabled(false);
|
||||
setPasteEnabled(false);
|
||||
@ -173,17 +177,17 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
||||
ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
|
||||
{
|
||||
auto const btnSz = ImVec2(45, 14);
|
||||
if (ImGui::Selectable("Select", m_tool == Tool::Select, 0, btnSz)) {
|
||||
m_tool = Tool::Select;
|
||||
if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
|
||||
m_tool = TileSheetTool::Select;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Selectable("Draw", m_tool == Tool::Draw, 0, btnSz)) {
|
||||
m_tool = Tool::Draw;
|
||||
if (ImGui::Selectable("Draw", m_tool == TileSheetTool::Draw, 0, btnSz)) {
|
||||
m_tool = TileSheetTool::Draw;
|
||||
m_model.clearSelection();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Selectable("Fill", m_tool == Tool::Fill, 0, btnSz)) {
|
||||
m_tool = Tool::Fill;
|
||||
if (ImGui::Selectable("Fill", m_tool == TileSheetTool::Fill, 0, btnSz)) {
|
||||
m_tool = TileSheetTool::Fill;
|
||||
m_model.clearSelection();
|
||||
}
|
||||
}
|
||||
@ -370,16 +374,16 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
|
||||
if (io.MouseDown[0] && m_prevMouseDownPos != mousePos) {
|
||||
m_prevMouseDownPos = mousePos;
|
||||
switch (m_tool) {
|
||||
case Tool::Draw:
|
||||
case TileSheetTool::Draw:
|
||||
m_view.clickDraw(fbSize, clickPos(winPos, mousePos));
|
||||
break;
|
||||
case Tool::Fill:
|
||||
case TileSheetTool::Fill:
|
||||
m_view.clickFill(fbSize, clickPos(winPos, mousePos));
|
||||
break;
|
||||
case Tool::Select:
|
||||
case TileSheetTool::Select:
|
||||
m_view.clickSelect(fbSize, clickPos(winPos, mousePos));
|
||||
break;
|
||||
case Tool::None:
|
||||
case TileSheetTool::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -396,7 +400,7 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
|
||||
}
|
||||
if (io.MouseReleased[0]) {
|
||||
m_prevMouseDownPos = {-1, -1};
|
||||
m_view.releaseMouseButton();
|
||||
m_view.releaseMouseButton(m_tool);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,6 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
enum class Tool {
|
||||
None,
|
||||
Draw,
|
||||
Fill,
|
||||
Select,
|
||||
};
|
||||
|
||||
class TileSheetEditorImGui: public studio::Editor {
|
||||
|
||||
private:
|
||||
@ -71,7 +64,7 @@ class TileSheetEditorImGui: public studio::Editor {
|
||||
TileSheetEditorModel &m_model;
|
||||
float m_palViewWidth = 300;
|
||||
ox::Vec2 m_prevMouseDownPos;
|
||||
Tool m_tool = Tool::Draw;
|
||||
TileSheetTool m_tool = TileSheetTool::Draw;
|
||||
|
||||
public:
|
||||
TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRStringView path);
|
||||
@ -86,6 +79,9 @@ class TileSheetEditorImGui: public studio::Editor {
|
||||
|
||||
void paste() override;
|
||||
|
||||
[[nodiscard]]
|
||||
bool acceptsClipboardPayload() const noexcept override;
|
||||
|
||||
void keyStateChanged(turbine::Key key, bool down) override;
|
||||
|
||||
void draw(studio::StudioContext&) noexcept override;
|
||||
|
@ -55,55 +55,63 @@ TileSheetEditorModel::TileSheetEditorModel(studio::StudioContext &sctx, ox::Stri
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::cut() {
|
||||
if (!m_selection) {
|
||||
return;
|
||||
}
|
||||
TileSheetClipboard blankCb;
|
||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||
const auto &s = activeSubSheet();
|
||||
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||
auto pt = ox::Point(x, y);
|
||||
const auto idx = core::idx(s, pt);
|
||||
const auto c = getPixel(s, m_img.bpp, idx);
|
||||
pt.x -= m_selectionBounds.x;
|
||||
pt.y -= m_selectionBounds.y;
|
||||
cb->addPixel(pt, c);
|
||||
blankCb.addPixel(pt, 0);
|
||||
}
|
||||
}
|
||||
const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
|
||||
const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
|
||||
auto const&s = activeSubSheet();
|
||||
iterateSelectionRows(*m_selection, [&](int x, int y) {
|
||||
auto pt = ox::Point{x, y};
|
||||
auto const idx = core::idx(s, pt);
|
||||
auto const c = getPixel(s, m_img.bpp, idx);
|
||||
pt -= m_selection->a;
|
||||
cb->addPixel(pt, c);
|
||||
blankCb.addPixel(pt, 0);
|
||||
});
|
||||
auto const pt1 = m_selection->a;
|
||||
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
|
||||
turbine::setClipboardObject(m_tctx, std::move(cb));
|
||||
pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::copy() {
|
||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||
auto pt = ox::Point(x, y);
|
||||
const auto &s = activeSubSheet();
|
||||
const auto idx = core::idx(s, pt);
|
||||
const auto c = getPixel(s, m_img.bpp, idx);
|
||||
pt.x -= m_selectionBounds.x;
|
||||
pt.y -= m_selectionBounds.y;
|
||||
cb->addPixel(pt, c);
|
||||
}
|
||||
if (!m_selection) {
|
||||
return;
|
||||
}
|
||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||
iterateSelectionRows(*m_selection, [&](int x, int y) {
|
||||
auto pt = ox::Point{x, y};
|
||||
const auto&s = activeSubSheet();
|
||||
const auto idx = core::idx(s, pt);
|
||||
const auto c = getPixel(s, m_img.bpp, idx);
|
||||
pt -= m_selection->a;
|
||||
cb->addPixel(pt, c);
|
||||
});
|
||||
turbine::setClipboardObject(m_tctx, std::move(cb));
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::paste() {
|
||||
if (!m_selection) {
|
||||
return;
|
||||
}
|
||||
auto [cb, err] = turbine::getClipboardObject<TileSheetClipboard>(m_tctx);
|
||||
if (err) {
|
||||
oxLogError(err);
|
||||
oxErrf("Could not read clipboard: {}", toStr(err));
|
||||
return;
|
||||
}
|
||||
const auto &s = activeSubSheet();
|
||||
const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
|
||||
const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
|
||||
auto const&s = activeSubSheet();
|
||||
auto const pt1 = m_selection->a;
|
||||
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
|
||||
pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
||||
}
|
||||
|
||||
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
|
||||
auto const cb = getClipboardObject<TileSheetClipboard>(m_tctx);
|
||||
return cb.ok();
|
||||
}
|
||||
|
||||
ox::StringView TileSheetEditorModel::palPath() const noexcept {
|
||||
auto [path, err] = m_img.defaultPalette.getPath();
|
||||
if (err) {
|
||||
@ -206,30 +214,26 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int palIdx) noexcept {
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::select(ox::Point const&pt) noexcept {
|
||||
if (!m_selectionOngoing) {
|
||||
m_selectionOrigin = pt;
|
||||
m_selectionOngoing = true;
|
||||
m_selectionBounds = {pt, pt};
|
||||
m_updated = true;
|
||||
} else if (m_selectionBounds.pt2() != pt) {
|
||||
m_selectionBounds = {m_selectionOrigin, pt};
|
||||
if (m_selTracker.updateCursorPoint(pt)) {
|
||||
m_selection.emplace(m_selTracker.selection());
|
||||
m_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::completeSelection() noexcept {
|
||||
m_selectionOngoing = false;
|
||||
auto &s = activeSubSheet();
|
||||
auto pt = m_selectionBounds.pt2();
|
||||
pt.x = ox::min(s.columns * TileWidth, pt.x);
|
||||
pt.y = ox::min(s.rows * TileHeight, pt.y);
|
||||
m_selectionBounds.setPt2(pt);
|
||||
if (m_selTracker.selectionOngoing()) {
|
||||
m_selTracker.finishSelection();
|
||||
m_selection.emplace(m_selTracker.selection());
|
||||
auto&pt = m_selection->b;
|
||||
auto&s = activeSubSheet();
|
||||
pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
|
||||
pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::clearSelection() noexcept {
|
||||
m_updated = true;
|
||||
m_selectionOrigin = {-1, -1};
|
||||
m_selectionBounds = {{-1, -1}, {-1, -1}};
|
||||
m_selection.reset();
|
||||
}
|
||||
|
||||
bool TileSheetEditorModel::updated() const noexcept {
|
||||
@ -266,9 +270,9 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
|
||||
}
|
||||
|
||||
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
|
||||
const auto &s = activeSubSheet();
|
||||
const auto pt = idxToPt(static_cast<int>(idx), s.columns);
|
||||
return m_selectionBounds.contains(pt);
|
||||
auto const&s = activeSubSheet();
|
||||
auto const pt = idxToPt(static_cast<int>(idx), s.columns);
|
||||
return m_selection && m_selection->contains(pt);
|
||||
}
|
||||
|
||||
void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
|
||||
|
@ -33,10 +33,9 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
size_t m_palettePage{};
|
||||
studio::UndoStack &m_undoStack;
|
||||
class DrawCommand *m_ongoingDrawCommand = nullptr;
|
||||
studio::SelectionTracker m_selTracker;
|
||||
ox::Optional<studio::Selection> m_selection;
|
||||
bool m_updated = false;
|
||||
bool m_selectionOngoing = false;
|
||||
ox::Point m_selectionOrigin = {-1, -1};
|
||||
ox::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}};
|
||||
|
||||
public:
|
||||
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
|
||||
@ -49,6 +48,9 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
|
||||
void paste();
|
||||
|
||||
[[nodiscard]]
|
||||
bool acceptsClipboardPayload() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr TileSheet const&img() const noexcept;
|
||||
|
||||
|
@ -84,9 +84,18 @@ void TileSheetEditorView::clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clic
|
||||
m_model.fill(pt, static_cast<int>(m_palIdx));
|
||||
}
|
||||
|
||||
void TileSheetEditorView::releaseMouseButton() noexcept {
|
||||
m_model.endDrawCommand();
|
||||
m_model.completeSelection();
|
||||
void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept {
|
||||
switch (tool) {
|
||||
case TileSheetTool::Draw:
|
||||
m_model.endDrawCommand();
|
||||
break;
|
||||
case TileSheetTool::Select:
|
||||
m_model.completeSelection();
|
||||
break;
|
||||
case TileSheetTool::Fill:
|
||||
case TileSheetTool::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept {
|
||||
|
@ -18,7 +18,8 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
enum class TileSheetTool: int {
|
||||
enum class TileSheetTool {
|
||||
None,
|
||||
Select,
|
||||
Draw,
|
||||
Fill,
|
||||
@ -33,6 +34,8 @@ constexpr auto toString(TileSheetTool t) noexcept {
|
||||
return "Draw";
|
||||
case TileSheetTool::Fill:
|
||||
return "Fill";
|
||||
case TileSheetTool::None:
|
||||
return "None";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@ -66,7 +69,7 @@ class TileSheetEditorView: public ox::SignalHandler {
|
||||
|
||||
void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept;
|
||||
|
||||
void releaseMouseButton() noexcept;
|
||||
void releaseMouseButton(TileSheetTool tool) noexcept;
|
||||
|
||||
void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept;
|
||||
|
||||
|
@ -86,19 +86,21 @@ ox::Error preloadObj(
|
||||
ox::TypeStore &ts,
|
||||
ox::FileSystem &romFs,
|
||||
ox::Preloader<PlatSpec> &pl,
|
||||
ox::CRStringView path) noexcept {
|
||||
ox::StringView const path) noexcept {
|
||||
// load file
|
||||
oxRequireM(buff, romFs.read(path));
|
||||
oxRequireM(obj, keel::readAsset(ts, buff));
|
||||
if (obj.type()->preloadable) {
|
||||
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
|
||||
// preload
|
||||
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj)));
|
||||
auto const size = ox::sizeOf<GbaPlatSpec>(&obj);
|
||||
auto const alignment = ox::alignOf<GbaPlatSpec>(obj);
|
||||
oxRequire(a, pl.startAlloc(size, alignment));
|
||||
auto const err = ox::preload<GbaPlatSpec, ox::ModelObject>(&pl, &obj);
|
||||
oxReturnError(pl.endAlloc());
|
||||
oxReturnError(err);
|
||||
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};
|
||||
keel::PreloadPtr const p{.preloadAddr = a};
|
||||
oxReturnError(ox::writeMC(p).moveTo(buff));
|
||||
oxOutf("preloaded {} as a {} @ {} to {}\n", path, obj.type()->typeName, a, a + size);
|
||||
} else {
|
||||
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
||||
oxReturnError(ox::writeMC(obj).moveTo(buff));
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include <keel/keel.hpp>
|
||||
|
||||
static ox::Error writeFileBuff(ox::StringView path, ox::Buffer const&buff) noexcept {
|
||||
static ox::Error writeFileBuff(ox::StringView path, ox::BufferView const buff) noexcept {
|
||||
try {
|
||||
std::ofstream f(std::string(toStdStringView(path)), std::ios::binary);
|
||||
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
||||
@ -39,10 +39,10 @@ static ox::Result<ox::Buffer> readFileBuff(ox::StringView path) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
static ox::Error generateTypes(ox::TypeStore *ts) noexcept {
|
||||
static ox::Error generateTypes(ox::TypeStore &ts) noexcept {
|
||||
for (auto const mod : keel::modules()) {
|
||||
for (auto gen : mod->types()) {
|
||||
oxReturnError(gen(*ts));
|
||||
oxReturnError(gen(ts));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
@ -54,7 +54,7 @@ static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::Strin
|
||||
ox::FileSystem32 dst(dstBuff);
|
||||
oxRequire(ctx, keel::init(ox::make_unique<ox::PassThroughFS>(argSrc), "keel-pack"));
|
||||
keel::TypeStore ts(*ctx->rom, ox::sfmt("{}/type_descriptors", projectDataDir));
|
||||
oxReturnError(generateTypes(&ts));
|
||||
oxReturnError(generateTypes(ts));
|
||||
oxReturnError(keel::pack(*ctx, ts, dst));
|
||||
oxRequireM(pl, keel::GbaPreloader::make());
|
||||
oxReturnError(preload(ts, dst, *pl));
|
||||
@ -62,14 +62,13 @@ static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::Strin
|
||||
// resize buffer
|
||||
oxRequire(dstSize, dst.size());
|
||||
dstBuff.resize(dstSize);
|
||||
|
||||
// concatenate ROM segments
|
||||
oxRequireM(romBuff, readFileBuff(argRomBin));
|
||||
oxReturnError(appendBinary(romBuff, dstBuff, *pl));
|
||||
|
||||
oxOutf("Input exe size: {} bytes\n", romBuff.size());
|
||||
oxOutf("Dest FS size: {} bytes\n", dstSize);
|
||||
oxOutf("Preload buff size: {} bytes\n", pl->buff().size());
|
||||
oxOutf("ROM buff size: {} bytes\n", romBuff.size());
|
||||
|
||||
oxReturnError(appendBinary(romBuff, dstBuff, *pl));
|
||||
oxOutf("Final ROM buff size: {} bytes\n", romBuff.size());
|
||||
oxReturnError(writeFileBuff(argRomBin, romBuff));
|
||||
return {};
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ static ox::Error pathToInode(
|
||||
}
|
||||
oxRequire(s, dest.stat(path));
|
||||
oxReturnError(o.at("type").unwrap()->set(static_cast<int8_t>(ox::FileAddressType::Inode)));
|
||||
oxOutf("path to inode: {} => {}\n", path, s.inode);
|
||||
oxOutf("\tpath to inode: {} => {}\n", path, s.inode);
|
||||
return data.set(2, s.inode);
|
||||
}
|
||||
|
||||
@ -97,6 +97,7 @@ static ox::Error doTransformations(
|
||||
oxReturnError(keel::performPackTransforms(ctx, buff));
|
||||
// transform FileAddresses
|
||||
oxRequireM(obj, keel::readAsset(ts, buff));
|
||||
oxOutf("transforming {}\n", filePath);
|
||||
oxReturnError(transformFileAddressesObj(ctx, dest, obj));
|
||||
oxReturnError(ox::writeClaw(obj).moveTo(buff));
|
||||
// write file to dest
|
||||
@ -143,16 +144,15 @@ static ox::Error copy(
|
||||
if (beginsWith(name, ".")) {
|
||||
continue;
|
||||
}
|
||||
oxOutf("reading {}\n", currentFile);
|
||||
oxRequire(stat, src.stat(currentFile));
|
||||
if (stat.fileType == ox::FileType::Directory) {
|
||||
oxReturnError(dest.mkdir(currentFile, true));
|
||||
oxReturnError(copy(src, dest, currentFile + '/'));
|
||||
} else {
|
||||
// load file
|
||||
oxOutf("copying file: {}\n", currentFile);
|
||||
oxRequireM(buff, src.read(currentFile));
|
||||
// write file to dest
|
||||
oxOutf("writing {}\n", currentFile);
|
||||
oxReturnError(dest.write(currentFile, buff));
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ void StudioUI::drawMenu() noexcept {
|
||||
if (ImGui::MenuItem("Cut", "Ctrl+X", false, m_activeEditor && m_activeEditor->cutEnabled())) {
|
||||
m_activeEditor->cut();
|
||||
}
|
||||
if (ImGui::MenuItem("Paste", "Ctrl+V", false, m_activeEditor && m_activeEditor->pasteEnabled()) && m_activeEditor) {
|
||||
if (ImGui::MenuItem("Paste", "Ctrl+V", false, m_activeEditor && m_activeEditor->pasteEnabled())) {
|
||||
m_activeEditor->paste();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -22,4 +22,9 @@ struct StudioContext {
|
||||
ui(pUi), tctx(pTctx) {}
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
inline keel::Context &keelCtx(StudioContext &ctx) noexcept {
|
||||
return keelCtx(ctx.tctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ class BaseEditor: public Widget {
|
||||
|
||||
virtual void paste();
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool acceptsClipboardPayload() const noexcept;
|
||||
|
||||
virtual void exportFile();
|
||||
|
||||
virtual void keyStateChanged(turbine::Key key, bool down);
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <ox/std/math.hpp>
|
||||
#include <ox/std/point.hpp>
|
||||
#include <ox/std/size.hpp>
|
||||
#include <ox/std/typetraits.hpp>
|
||||
|
||||
namespace studio {
|
||||
@ -13,6 +14,15 @@ struct Selection {
|
||||
ox::Point a, b;
|
||||
constexpr Selection() noexcept = default;
|
||||
constexpr Selection(ox::Point const&pA, ox::Point const&pB) noexcept: a(pA), b(pB) {}
|
||||
[[nodiscard]]
|
||||
constexpr ox::Size size() const noexcept {
|
||||
return {b.x - a.x, b.y - a.y};
|
||||
}
|
||||
[[nodiscard]]
|
||||
constexpr bool contains(ox::Point const&pt) const noexcept {
|
||||
return a.x <= pt.x && a.y <= pt.y
|
||||
&& b.x >= pt.x && b.y >= pt.y;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
|
||||
@ -31,6 +41,22 @@ constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr auto iterateSelectionRows(studio::Selection const&sel, auto const&cb) {
|
||||
constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
|
||||
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
|
||||
for (auto x = sel.a.x; x <= sel.b.x; ++x) {
|
||||
if constexpr(retErr) {
|
||||
oxReturnError(cb(x, y));
|
||||
} else {
|
||||
cb(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr(retErr) {
|
||||
return ox::Error{};
|
||||
}
|
||||
};
|
||||
|
||||
class SelectionTracker {
|
||||
private:
|
||||
bool m_selectionOngoing{};
|
||||
@ -48,14 +74,23 @@ class SelectionTracker {
|
||||
m_selectionOngoing = true;
|
||||
}
|
||||
|
||||
constexpr void updateCursorPoint(ox::Point cursor, bool allowStart = true) noexcept {
|
||||
/**
|
||||
*
|
||||
* @param cursor
|
||||
* @param allowStart
|
||||
* @return true if changed, false otherwise
|
||||
*/
|
||||
constexpr bool updateCursorPoint(ox::Point cursor, bool allowStart = true) noexcept {
|
||||
auto changed = false;
|
||||
if (!m_selectionOngoing && allowStart) {
|
||||
m_pointA = cursor;
|
||||
m_selectionOngoing = true;
|
||||
}
|
||||
if (m_selectionOngoing) {
|
||||
m_pointB = cursor;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
constexpr void updateCursorPoint(ox::Vec2 cursor, bool allowStart = true) noexcept {
|
||||
|
@ -23,6 +23,10 @@ void BaseEditor::copy() {
|
||||
void BaseEditor::paste() {
|
||||
}
|
||||
|
||||
bool BaseEditor::acceptsClipboardPayload() const noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
void BaseEditor::exportFile() {
|
||||
}
|
||||
|
||||
@ -95,7 +99,7 @@ void BaseEditor::setPasteEnabled(bool v) {
|
||||
}
|
||||
|
||||
bool BaseEditor::pasteEnabled() const noexcept {
|
||||
return m_pasteEnabled;
|
||||
return m_pasteEnabled && acceptsClipboardPayload();
|
||||
}
|
||||
|
||||
ox::Error BaseEditor::saveItem() noexcept {
|
||||
|
@ -29,7 +29,7 @@ template<typename T>
|
||||
class ClipboardObject: public BaseClipboardObject {
|
||||
[[nodiscard]]
|
||||
ox::String typeId() const noexcept final {
|
||||
return ox::buildTypeId(T::TypeName, T::TypeVersion);
|
||||
return ox::String(ox::ModelTypeId_v<T>);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user