/* * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include #include #include #include #include #include namespace nostalgia::core { class TileSheetEditorModel: public ox::SignalHandler { public: ox::Signal activeSubsheetChanged; private: static const Palette s_defaultPalette; TileSheet m_img; TileSheet::SubSheetIdx m_activeSubsSheetIdx; keel::AssetRef m_pal; studio::UndoStack m_undoStack; class DrawCommand *m_ongoingDrawCommand = nullptr; bool m_updated = false; turbine::Context *m_ctx = nullptr; ox::String m_path; bool m_selectionOngoing = false; ox::Point m_selectionOrigin = {-1, -1}; ox::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}}; public: TileSheetEditorModel(turbine::Context *ctx, ox::String path); ~TileSheetEditorModel() override = default; void cut(); void copy(); void paste(); [[nodiscard]] constexpr const TileSheet &img() const noexcept; [[nodiscard]] constexpr TileSheet &img() noexcept; [[nodiscard]] constexpr const Palette *pal() const noexcept; [[nodiscard]] ox::StringView palPath() const noexcept; ox::Error setPalette(const ox::String &path) noexcept; void drawCommand(const ox::Point &pt, std::size_t palIdx) noexcept; void endDrawCommand() noexcept; void addSubsheet(const TileSheet::SubSheetIdx &parentIdx) noexcept; void rmSubsheet(const TileSheet::SubSheetIdx &idx) noexcept; void insertTiles(const TileSheet::SubSheetIdx &idx, std::size_t tileIdx, std::size_t tileCnt) noexcept; void deleteTiles(const TileSheet::SubSheetIdx &idx, std::size_t tileIdx, std::size_t tileCnt) noexcept; ox::Error updateSubsheet(const TileSheet::SubSheetIdx &idx, const ox::String &name, int cols, int rows) noexcept; void setActiveSubsheet(const TileSheet::SubSheetIdx&) noexcept; [[nodiscard]] constexpr const TileSheet::SubSheet *activeSubSheet() const noexcept { auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx); return &activeSubSheet; } [[nodiscard]] constexpr TileSheet::SubSheet *activeSubSheet() noexcept { auto &activeSubSheet = m_img.getSubSheet(m_activeSubsSheetIdx); return &activeSubSheet; } [[nodiscard]] constexpr const TileSheet::SubSheetIdx &activeSubSheetIdx() const noexcept { return m_activeSubsSheetIdx; } void fill(const ox::Point &pt, int palIdx) noexcept; void select(const ox::Point &pt) noexcept; void completeSelection() noexcept; void clearSelection() noexcept; [[nodiscard]] bool updated() const noexcept; ox::Error markUpdatedCmdId(const studio::UndoCommand *cmd) noexcept; ox::Error markUpdated() noexcept; void ackUpdate() noexcept; ox::Error saveFile() noexcept; [[nodiscard]] constexpr studio::UndoStack *undoStack() noexcept; bool pixelSelected(std::size_t idx) const noexcept; protected: void getFillPixels(bool *pixels, const ox::Point &pt, int oldColor) const noexcept; private: void pushCommand(studio::UndoCommand *cmd) noexcept; void setPalette(); void saveState(); void restoreState(); [[nodiscard]] ox::String paletteName(const ox::String &palettePath) const; [[nodiscard]] ox::String palettePath(const ox::String &palettePath) const; }; constexpr const TileSheet &TileSheetEditorModel::img() const noexcept { return m_img; } constexpr TileSheet &TileSheetEditorModel::img() noexcept { return m_img; } constexpr const Palette *TileSheetEditorModel::pal() const noexcept { if (m_pal) { return m_pal.get(); } return &s_defaultPalette; } constexpr studio::UndoStack *TileSheetEditorModel::undoStack() noexcept { return &m_undoStack; } }