From 275e9dbff1ab27cdc94e5a26586a9fb11b143633 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Fri, 29 Jul 2022 21:38:18 -0500 Subject: [PATCH] [nostalgia] Add NewMenu for creating new files --- src/nostalgia/core/assetmanager.hpp | 7 +- src/nostalgia/core/gfx.hpp | 44 +++---- src/nostalgia/core/media.hpp | 4 +- src/nostalgia/core/studio/module.cpp | 8 ++ src/nostalgia/core/studio/module.hpp | 1 + .../core/studio/tilesheeteditor-imgui.cpp | 63 ++++----- .../core/studio/tilesheeteditormodel.cpp | 18 ++- .../core/studio/tilesheeteditormodel.hpp | 12 +- .../core/studio/tilesheeteditorview.hpp | 4 +- src/nostalgia/core/studio/tilesheetpixels.cpp | 10 +- src/nostalgia/core/typestore.hpp | 3 +- src/nostalgia/studio/CMakeLists.txt | 2 + src/nostalgia/studio/aboutpopup.cpp | 57 +++++++++ src/nostalgia/studio/aboutpopup.hpp | 39 ++++++ src/nostalgia/studio/lib/CMakeLists.txt | 4 + src/nostalgia/studio/lib/editor.cpp | 6 +- src/nostalgia/studio/lib/imguiuitl.hpp | 13 ++ src/nostalgia/studio/lib/imguiutil.cpp | 19 +++ src/nostalgia/studio/lib/itemmaker.hpp | 54 ++++++++ src/nostalgia/studio/lib/module.cpp | 4 + src/nostalgia/studio/lib/module.hpp | 5 + src/nostalgia/studio/lib/popup.cpp | 9 ++ src/nostalgia/studio/lib/popup.hpp | 62 +++++++++ src/nostalgia/studio/lib/project.cpp | 19 ++- src/nostalgia/studio/lib/project.hpp | 18 +-- src/nostalgia/studio/newmenu.cpp | 121 ++++++++++++++++++ src/nostalgia/studio/newmenu.hpp | 81 ++++++++++++ src/nostalgia/studio/projectexplorer.hpp | 1 + src/nostalgia/studio/studio.hpp | 3 + src/nostalgia/studio/studioapp.cpp | 47 ++++--- src/nostalgia/studio/studioapp.hpp | 12 +- 31 files changed, 630 insertions(+), 120 deletions(-) create mode 100644 src/nostalgia/studio/aboutpopup.cpp create mode 100644 src/nostalgia/studio/aboutpopup.hpp create mode 100644 src/nostalgia/studio/lib/imguiuitl.hpp create mode 100644 src/nostalgia/studio/lib/imguiutil.cpp create mode 100644 src/nostalgia/studio/lib/itemmaker.hpp create mode 100644 src/nostalgia/studio/lib/popup.cpp create mode 100644 src/nostalgia/studio/lib/popup.hpp create mode 100644 src/nostalgia/studio/newmenu.cpp create mode 100644 src/nostalgia/studio/newmenu.hpp diff --git a/src/nostalgia/core/assetmanager.hpp b/src/nostalgia/core/assetmanager.hpp index 59c3cbc3..fa55ac07 100644 --- a/src/nostalgia/core/assetmanager.hpp +++ b/src/nostalgia/core/assetmanager.hpp @@ -41,7 +41,7 @@ class AssetContainer { AssetContainer& operator=(AssetContainer&&) = delete; constexpr T *get() noexcept { - return &m_obj; + return &m_obj; } constexpr const T *get() const noexcept { @@ -92,7 +92,10 @@ class AssetRef: public ox::SignalHandler { } constexpr const T *get() const noexcept { - return m_ctr->get(); + if (m_ctr) { + return m_ctr->get(); + } + return nullptr; } constexpr const T &operator*() const & noexcept { diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index f13df49c..dd082365 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -61,10 +61,10 @@ struct TileSheet { static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet"; static constexpr auto TypeVersion = 1; ox::String name; - int columns = 1; - int rows = 1; + int columns = 0; + int rows = 0; ox::Vector subsheets; - ox::Vector pixels = {}; + ox::Vector pixels; constexpr SubSheet() noexcept = default; constexpr SubSheet(const SubSheet &other) noexcept { @@ -84,8 +84,8 @@ struct TileSheet { other.columns = 0; other.rows = 0; } - constexpr SubSheet(const char *pName, int pColumns, int pRows) noexcept: - name(pName), columns(pColumns), rows(pRows), pixels(static_cast(columns * rows * PixelsPerTile)) { + constexpr SubSheet(const char *pName, int pColumns, int pRows, int bpp) noexcept: + name(pName), columns(pColumns), rows(pRows), pixels(static_cast(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { } constexpr SubSheet(const char *pName, int pColumns, int pRows, ox::Vector pPixels) noexcept: name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) { @@ -267,27 +267,27 @@ struct TileSheet { static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet"; static constexpr auto TypeVersion = 2; - int8_t bpp = 0; + int8_t bpp = 4; ox::FileAddress defaultPalette; - SubSheet subsheet; + SubSheet subsheet{"Root", 1, 1, bpp}; constexpr TileSheet() noexcept = default; - inline TileSheet(const TileSheet &other) noexcept { - bpp = other.bpp; - defaultPalette = other.defaultPalette; - subsheet = other.subsheet; + inline TileSheet(const TileSheet &other) noexcept: + bpp(other.bpp), + defaultPalette(other.defaultPalette), + subsheet(other.subsheet) { } - inline TileSheet(TileSheet &&other) noexcept { - bpp = other.bpp; - defaultPalette = std::move(other.defaultPalette); - subsheet = std::move(other.subsheet); + inline TileSheet(TileSheet &&other) noexcept: + bpp(std::move(other.bpp)), + defaultPalette(std::move(other.defaultPalette)), + subsheet(std::move(other.subsheet)) { } inline auto &operator=(const TileSheet &other) noexcept { - bpp = other.bpp; - defaultPalette = other.defaultPalette; - subsheet = other.subsheet; - return *this; + if (this != &other) { + bpp = other.bpp; + defaultPalette = other.defaultPalette; + subsheet = other.subsheet; } return *this; } inline auto &operator=(TileSheet &&other) noexcept { bpp = other.bpp; @@ -359,10 +359,10 @@ struct TileSheet { constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept { auto &parent = getSubSheet(idx); if (parent.subsheets.size() < 2) { - parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1); + parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1, bpp); } else { - parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows); - parent.subsheets.emplace_back("Subsheet 1", 1, 1); + parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp); + parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp); } return OxError(0); } diff --git a/src/nostalgia/core/media.hpp b/src/nostalgia/core/media.hpp index 825a013f..19f9bffa 100644 --- a/src/nostalgia/core/media.hpp +++ b/src/nostalgia/core/media.hpp @@ -48,9 +48,9 @@ ox::Result> readObj(Context *ctx, const ox::FileAddress &file, bool } template -ox::Error writeObj(Context *ctx, const ox::FileAddress &file, T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { +ox::Error writeObj(Context *ctx, const ox::FileAddress &file, const T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { oxRequire(objBuff, ox::writeClaw(&obj, fmt)); - return ctx->rom-write(file, objBuff); + return ctx->rom->write(file, objBuff.data(), objBuff.size()); } ox::Result> loadRomFs(const char *path) noexcept; diff --git a/src/nostalgia/core/studio/module.cpp b/src/nostalgia/core/studio/module.cpp index 51951206..0f687088 100644 --- a/src/nostalgia/core/studio/module.cpp +++ b/src/nostalgia/core/studio/module.cpp @@ -2,6 +2,7 @@ * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ +#include "ox/std/memory.hpp" #include "paletteeditor-imgui.hpp" #include "tilesheeteditor-imgui.hpp" @@ -30,4 +31,11 @@ ox::Vector Module::editors(core::Context *ctx) noexcept { }; } +ox::Vector> Module::itemMakers(core::Context*) noexcept { + ox::Vector> out; + out.emplace_back(new studio::ItemMakerT("Tile Sheet", "TileSheets", "ng")); + out.emplace_back(new studio::ItemMakerT("Palette", "Palettes", "npal")); + return out; +} + } diff --git a/src/nostalgia/core/studio/module.hpp b/src/nostalgia/core/studio/module.hpp index dd7088fb..d0eed570 100644 --- a/src/nostalgia/core/studio/module.hpp +++ b/src/nostalgia/core/studio/module.hpp @@ -11,6 +11,7 @@ namespace nostalgia::core { class Module: public studio::Module { public: ox::Vector editors(core::Context *ctx) noexcept override; + ox::Vector> itemMakers(core::Context*) noexcept override; }; } diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp index a5fae3a5..17fdbd36 100644 --- a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp @@ -87,13 +87,16 @@ void TileSheetEditorImGui::keyStateChanged(core::Key key, bool down) { if (!down) { return; } - const auto colorCnt = model()->pal().colors.size(); - if (key >= core::Key::Num_1 && key <= core::Key::Num_0 + colorCnt) { - auto idx = ox::min(static_cast(key - core::Key::Num_1), colorCnt - 1); - m_tileSheetEditor.setPalIdx(idx); - } else if (key == core::Key::Num_0 && colorCnt >= 10) { - auto idx = ox::min(static_cast(key - core::Key::Num_1 + 9), colorCnt - 1); - m_tileSheetEditor.setPalIdx(idx); + auto pal = model()->pal(); + if (pal) { + const auto colorCnt = pal->colors.size(); + if (key >= core::Key::Num_1 && key <= core::Key::Num_0 + colorCnt) { + auto idx = ox::min(static_cast(key - core::Key::Num_1), colorCnt - 1); + m_tileSheetEditor.setPalIdx(idx); + } else if (key == core::Key::Num_0 && colorCnt >= 10) { + auto idx = ox::min(static_cast(key - core::Key::Num_1 + 9), colorCnt - 1); + m_tileSheetEditor.setPalIdx(idx); + } } } @@ -184,10 +187,10 @@ void TileSheetEditorImGui::drawSubsheetSelector(TileSheet::SubSheet *subsheet, T auto lbl = ox::sfmt("{}##{}", subsheet->name, pathStr); const auto rowSelected = *path == model()->activeSubSheetIdx(); const auto flags = ImGuiTreeNodeFlags_SpanFullWidth - | ImGuiTreeNodeFlags_OpenOnArrow - | ImGuiTreeNodeFlags_DefaultOpen - | (subsheet->subsheets.size() ? 0 : ImGuiTreeNodeFlags_Leaf) - | (rowSelected ? ImGuiTreeNodeFlags_Selected : 0); + | ImGuiTreeNodeFlags_OpenOnArrow + | ImGuiTreeNodeFlags_DefaultOpen + | (subsheet->subsheets.size() ? 0 : ImGuiTreeNodeFlags_Leaf) + | (rowSelected ? ImGuiTreeNodeFlags_Selected : 0); ImGui::TableNextColumn(); const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags); Str newName = subsheet->name.c_str(); @@ -255,7 +258,7 @@ void TileSheetEditorImGui::exportSubhseetToPng() noexcept { const auto &img = model()->img(); const auto &s = *model()->activeSubSheet(); const auto &pal = model()->pal(); - err = toPngFile(path, s, pal, img.bpp); + err = toPngFile(path, s, *pal, img.bpp); if (err) { oxErrorf("Tilesheet export failed: {}", toStr(err)); } @@ -353,24 +356,26 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept { ImGui::TableSetupColumn("", 0, 0.22); ImGui::TableSetupColumn("Color16", 0, 3); ImGui::TableHeadersRow(); - for (auto i = 0u; auto c: m_tileSheetEditor.pal().colors) { - ImGui::PushID(static_cast(i)); - // Column: color idx - ImGui::TableNextColumn(); - const auto label = ox::BString<8>() + (i + 1); - const auto rowSelected = i == m_tileSheetEditor.palIdx(); - if (ImGui::Selectable(label.c_str(), rowSelected, ImGuiSelectableFlags_SpanAllColumns)) { - m_tileSheetEditor.setPalIdx(i); + if (auto pal = m_tileSheetEditor.pal()) { + for (auto i = 0u; auto c: pal->colors) { + ImGui::PushID(static_cast(i)); + // Column: color idx + ImGui::TableNextColumn(); + const auto label = ox::BString<8>() + (i + 1); + const auto rowSelected = i == m_tileSheetEditor.palIdx(); + if (ImGui::Selectable(label.c_str(), rowSelected, ImGuiSelectableFlags_SpanAllColumns)) { + m_tileSheetEditor.setPalIdx(i); + } + // Column: color RGB + ImGui::TableNextColumn(); + auto ic = ImGui::GetColorU32(ImVec4(redf(c), greenf(c), bluef(c), 1)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ic); + ImGui::TableNextColumn(); + ImGui::Text("(%02d, %02d, %02d)", red16(c), green16(c), blue16(c)); + ImGui::TableNextRow(); + ImGui::PopID(); + ++i; } - // Column: color RGB - ImGui::TableNextColumn(); - auto ic = ImGui::GetColorU32(ImVec4(redf(c), greenf(c), bluef(c), 1)); - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ic); - ImGui::TableNextColumn(); - ImGui::Text("(%02d, %02d, %02d)", red16(c), green16(c), blue16(c)); - ImGui::TableNextRow(); - ImGui::PopID(); - ++i; } ImGui::EndTable(); } diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.cpp b/src/nostalgia/core/studio/tilesheeteditormodel.cpp index f74e8a0e..5a39f81b 100644 --- a/src/nostalgia/core/studio/tilesheeteditormodel.cpp +++ b/src/nostalgia/core/studio/tilesheeteditormodel.cpp @@ -15,6 +15,10 @@ namespace nostalgia::core { +const Palette TileSheetEditorModel::s_defaultPalette = { + .colors = ox::Vector(128), +}; + class TileSheetClipboard: public ClipboardObject { public: static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard"; @@ -252,12 +256,12 @@ class AddSubSheetCommand: public TileSheetCommand { 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); + parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i).c_str(), 1, 1, m_img->bpp); } 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); + parent.subsheets.emplace_back("Subsheet 1", 1, 1, m_img->bpp); } } @@ -531,12 +535,14 @@ class PaletteChangeCommand: public TileSheetCommand { }; -TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) { +TileSheetEditorModel::TileSheetEditorModel(Context *ctx, ox::String path) { m_ctx = ctx; - m_path = path; - oxRequireT(img, readObj(ctx, path.c_str())); + m_path = std::move(path); + oxRequireT(img, readObj(ctx, m_path.c_str())); m_img = *img; - oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); + if (m_img.defaultPalette) { + oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); + } m_pal.updated.connect(this, &TileSheetEditorModel::markUpdated); m_undoStack.changeTriggered.connect(this, &TileSheetEditorModel::markUpdatedCmdId); } diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.hpp b/src/nostalgia/core/studio/tilesheeteditormodel.hpp index 2c37e911..12246f33 100644 --- a/src/nostalgia/core/studio/tilesheeteditormodel.hpp +++ b/src/nostalgia/core/studio/tilesheeteditormodel.hpp @@ -20,6 +20,7 @@ class TileSheetEditorModel: public ox::SignalHandler { ox::Signal activeSubsheetChanged; private: + static const Palette s_defaultPalette; TileSheet m_img; TileSheet::SubSheetIdx m_activeSubsSheetIdx; AssetRef m_pal; @@ -33,7 +34,7 @@ class TileSheetEditorModel: public ox::SignalHandler { geo::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}}; public: - TileSheetEditorModel(Context *ctx, const ox::String &path); + TileSheetEditorModel(Context *ctx, ox::String path); ~TileSheetEditorModel() override = default; @@ -50,7 +51,7 @@ class TileSheetEditorModel: public ox::SignalHandler { constexpr TileSheet &img() noexcept; [[nodiscard]] - constexpr const Palette &pal() const noexcept; + constexpr const Palette *pal() const noexcept; [[nodiscard]] const ox::FileAddress &palPath() const noexcept; @@ -142,8 +143,11 @@ constexpr TileSheet &TileSheetEditorModel::img() noexcept { return m_img; } -constexpr const Palette &TileSheetEditorModel::pal() const noexcept { - return *m_pal; +constexpr const Palette *TileSheetEditorModel::pal() const noexcept { + if (m_pal) { + return m_pal.get(); + } + return &s_defaultPalette; } constexpr studio::UndoStack *TileSheetEditorModel::undoStack() noexcept { diff --git a/src/nostalgia/core/studio/tilesheeteditorview.hpp b/src/nostalgia/core/studio/tilesheeteditorview.hpp index 7a82ee9f..4364c5d2 100644 --- a/src/nostalgia/core/studio/tilesheeteditorview.hpp +++ b/src/nostalgia/core/studio/tilesheeteditorview.hpp @@ -80,7 +80,7 @@ class TileSheetEditorView: public ox::SignalHandler { constexpr TileSheet &img() noexcept; [[nodiscard]] - constexpr const Palette &pal() const noexcept; + constexpr const Palette *pal() const noexcept; [[nodiscard]] constexpr auto *model() noexcept { @@ -125,7 +125,7 @@ constexpr TileSheet &TileSheetEditorView::img() noexcept { return m_model.img(); } -constexpr const Palette &TileSheetEditorView::pal() const noexcept { +constexpr const Palette *TileSheetEditorView::pal() const noexcept { return m_model.pal(); } diff --git a/src/nostalgia/core/studio/tilesheetpixels.cpp b/src/nostalgia/core/studio/tilesheetpixels.cpp index 6c224296..9bc0675b 100644 --- a/src/nostalgia/core/studio/tilesheetpixels.cpp +++ b/src/nostalgia/core/studio/tilesheetpixels.cpp @@ -85,7 +85,7 @@ void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned v void TileSheetPixels::setBufferObjects(const geo::Vec2 &paneSize) noexcept { // set buffer lengths const auto subSheet = m_model->activeSubSheet(); - const auto &pal = m_model->pal(); + const auto pal = m_model->pal(); const auto width = subSheet->columns * TileWidth; const auto height = subSheet->rows * TileHeight; const auto pixels = static_cast(width * height); @@ -93,12 +93,18 @@ void TileSheetPixels::setBufferObjects(const geo::Vec2 &paneSize) noexcept { m_bufferSet.elements.resize(pixels * VertexEboLength); // set pixels subSheet->walkPixels(m_model->img().bpp, [&](std::size_t i, uint8_t p) { - auto color = pal.colors[p]; + auto color = pal->colors[p]; const auto pt = idxToPt(static_cast(i), subSheet->columns); const auto fx = static_cast(pt.x); const auto fy = static_cast(pt.y); const auto vbo = &m_bufferSet.vertices[i * VertexVboLength]; const auto ebo = &m_bufferSet.elements[i * VertexEboLength]; + if (i * VertexVboLength + VertexVboLength > m_bufferSet.vertices.size()) { + return; + } + if (i * VertexEboLength + VertexEboLength > m_bufferSet.elements.size()) { + return; + } if (m_model->pixelSelected(i)) { const auto r = red16(color) / 2; const auto g = (green16(color) + 20) / 2; diff --git a/src/nostalgia/core/typestore.hpp b/src/nostalgia/core/typestore.hpp index 70956b82..1b9e519d 100644 --- a/src/nostalgia/core/typestore.hpp +++ b/src/nostalgia/core/typestore.hpp @@ -5,10 +5,9 @@ #pragma once #include +#include #include -#include "context.hpp" - namespace nostalgia::core { class TypeStore: public ox::TypeStore { diff --git a/src/nostalgia/studio/CMakeLists.txt b/src/nostalgia/studio/CMakeLists.txt index 5be9b0e9..4174cb78 100644 --- a/src/nostalgia/studio/CMakeLists.txt +++ b/src/nostalgia/studio/CMakeLists.txt @@ -2,8 +2,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable( nostalgia-studio MACOSX_BUNDLE + aboutpopup.cpp filedialogmanager.cpp main.cpp + newmenu.cpp projectexplorer.cpp projecttreemodel.cpp studioapp.cpp diff --git a/src/nostalgia/studio/aboutpopup.cpp b/src/nostalgia/studio/aboutpopup.cpp new file mode 100644 index 00000000..e265ed71 --- /dev/null +++ b/src/nostalgia/studio/aboutpopup.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "lib/imguiuitl.hpp" +#include "aboutpopup.hpp" + +namespace nostalgia { + +void AboutPopup::open() noexcept { + m_stage = Stage::Opening; +} + +void AboutPopup::close() noexcept { + m_stage = Stage::Closed; +} + +bool AboutPopup::isOpen() const noexcept { + return m_stage == Stage::Open; +} + +void AboutPopup::draw(core::Context *ctx) noexcept { + switch (m_stage) { + case Stage::Closed: + break; + case Stage::Opening: + ImGui::OpenPopup("About"); + m_stage = Stage::Open; + [[fallthrough]]; + case Stage::Open: { + constexpr auto modalFlags = + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + ImGui::SetNextWindowSize(ImVec2(215, 90)); + studio::ig::centerNextWindow(ctx); + auto open = true; + if (ImGui::BeginPopupModal("About", &open, modalFlags)) { + ImGui::Text("Nostalgia Studio - dev build"); + ImGui::NewLine(); + ImGui::Dummy(ImVec2(148.0f, 0.0f)); + ImGui::SameLine(); + if (ImGui::Button("Close")) { + ImGui::CloseCurrentPopup(); + open = false; + } + ImGui::EndPopup(); + } + if (!open) { + m_stage = Stage::Closed; + } + break; + } + } +} + +} diff --git a/src/nostalgia/studio/aboutpopup.hpp b/src/nostalgia/studio/aboutpopup.hpp new file mode 100644 index 00000000..e4ce5e19 --- /dev/null +++ b/src/nostalgia/studio/aboutpopup.hpp @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +#include + +#include "lib/popup.hpp" + +namespace nostalgia { + + class AboutPopup: public studio::Popup { + public: + enum class Stage { + Closed, + Opening, + Open, + }; + + private: + Stage m_stage = Stage::Closed; + + public: + void open() noexcept override; + + void close() noexcept override; + + [[nodiscard]] + bool isOpen() const noexcept override; + + void draw(core::Context *ctx) noexcept override; + +}; + +} diff --git a/src/nostalgia/studio/lib/CMakeLists.txt b/src/nostalgia/studio/lib/CMakeLists.txt index c474c477..4e002ab6 100644 --- a/src/nostalgia/studio/lib/CMakeLists.txt +++ b/src/nostalgia/studio/lib/CMakeLists.txt @@ -2,7 +2,9 @@ add_library( NostalgiaStudio configio.cpp editor.cpp + imguiutil.cpp module.cpp + popup.cpp project.cpp task.cpp undostack.cpp @@ -43,7 +45,9 @@ install( context.hpp editor.hpp filedialog.hpp + itemmaker.hpp module.hpp + popup.hpp project.hpp task.hpp undostack.hpp diff --git a/src/nostalgia/studio/lib/editor.cpp b/src/nostalgia/studio/lib/editor.cpp index 3742fa55..f61a3784 100644 --- a/src/nostalgia/studio/lib/editor.cpp +++ b/src/nostalgia/studio/lib/editor.cpp @@ -36,7 +36,11 @@ void BaseEditor::save() noexcept { if (!err) { setUnsavedChanges(false); } else { - oxErrorf("Could not save file {}: {}", itemName(), toStr(err)); + if constexpr(ox::defines::Debug) { + oxErrorf("Could not save file {}: {} ({}:{})", itemName(), toStr(err), err.file, err.line); + } else { + oxErrorf("Could not save file {}: {}", itemName(), toStr(err)); + } } } diff --git a/src/nostalgia/studio/lib/imguiuitl.hpp b/src/nostalgia/studio/lib/imguiuitl.hpp new file mode 100644 index 00000000..cfe8b55a --- /dev/null +++ b/src/nostalgia/studio/lib/imguiuitl.hpp @@ -0,0 +1,13 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include + +namespace nostalgia::studio::ig { + +void centerNextWindow(core::Context *ctx) noexcept; + +} \ No newline at end of file diff --git a/src/nostalgia/studio/lib/imguiutil.cpp b/src/nostalgia/studio/lib/imguiutil.cpp new file mode 100644 index 00000000..5f2c9110 --- /dev/null +++ b/src/nostalgia/studio/lib/imguiutil.cpp @@ -0,0 +1,19 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include + +namespace nostalgia::studio::ig { + +void centerNextWindow(core::Context *ctx) noexcept { + const auto sz = core::getScreenSize(ctx); + const auto screenW = static_cast(sz.width); + const auto screenH = static_cast(sz.height); + const auto mod = ImGui::GetWindowDpiScale() * 2; + ImGui::SetNextWindowPos(ImVec2(screenW / mod, screenH / mod), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); +} + +} diff --git a/src/nostalgia/studio/lib/itemmaker.hpp b/src/nostalgia/studio/lib/itemmaker.hpp new file mode 100644 index 00000000..05af6cdb --- /dev/null +++ b/src/nostalgia/studio/lib/itemmaker.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include + +namespace nostalgia::studio { + +class ItemMaker { + public: + const ox::String name; + const ox::String parentDir; + const ox::String fileExt; + constexpr explicit ItemMaker(ox::String pName, ox::String pParentDir, ox::String pFileExt) noexcept: + name(std::move(pName)), + parentDir(std::move(pParentDir)), + fileExt(std::move(pFileExt)) { + } + virtual ~ItemMaker() noexcept = default; + virtual ox::Error write(core::Context *ctx, const char *pName) const noexcept = 0; +}; + +template +class ItemMakerT: public ItemMaker { + private: + const T item; + const ox::ClawFormat fmt; + public: + constexpr explicit ItemMakerT(ox::String pDisplayName, ox::String pParentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept: + ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)), + fmt(pFmt) { + } + constexpr ItemMakerT(ox::String pDisplayName, ox::String pParentDir, ox::String fileExt, const T &pItem, ox::ClawFormat pFmt) noexcept: + ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)), + item(pItem), + fmt(pFmt) { + } + constexpr ItemMakerT(ox::String pDisplayName, ox::String pParentDir, T &&pItem, ox::ClawFormat pFmt) noexcept: + ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)), + item(std::forward(pItem)), + fmt(pFmt) { + } + ox::Error write(core::Context *ctx, const char *pName) const noexcept override { + const auto path = ox::sfmt("{}/{}.{}", parentDir, pName, fileExt); + auto sctx = core::applicationData(ctx); + return sctx->project->writeObj(path, &item, fmt); + } +}; + +} diff --git a/src/nostalgia/studio/lib/module.cpp b/src/nostalgia/studio/lib/module.cpp index 4946735d..0bab0e62 100644 --- a/src/nostalgia/studio/lib/module.cpp +++ b/src/nostalgia/studio/lib/module.cpp @@ -10,4 +10,8 @@ ox::Vector Module::editors(core::Context*) { return {}; } +ox::Vector> Module::itemMakers(core::Context*) { + return {}; +} + } diff --git a/src/nostalgia/studio/lib/module.hpp b/src/nostalgia/studio/lib/module.hpp index 3cd4376c..da22a027 100644 --- a/src/nostalgia/studio/lib/module.hpp +++ b/src/nostalgia/studio/lib/module.hpp @@ -9,10 +9,13 @@ #include #include +#include #include namespace nostalgia::studio { +class ItemMaker; + struct EditorMaker { using Func = std::function(const ox::String&)>; ox::Vector fileTypes; @@ -25,6 +28,8 @@ class Module { virtual ox::Vector editors(core::Context *ctx); + virtual ox::Vector> itemMakers(core::Context*); + }; } diff --git a/src/nostalgia/studio/lib/popup.cpp b/src/nostalgia/studio/lib/popup.cpp new file mode 100644 index 00000000..9aea2842 --- /dev/null +++ b/src/nostalgia/studio/lib/popup.cpp @@ -0,0 +1,9 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "popup.hpp" + +namespace nostalgia::studio { + +} \ No newline at end of file diff --git a/src/nostalgia/studio/lib/popup.hpp b/src/nostalgia/studio/lib/popup.hpp new file mode 100644 index 00000000..0648531a --- /dev/null +++ b/src/nostalgia/studio/lib/popup.hpp @@ -0,0 +1,62 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +#include +#include + +#include "imguiuitl.hpp" + +namespace nostalgia::studio { + + +class Popup { + private: + geo::Vec2 m_size; + ox::String m_title; + public: + // emits path parameter + ox::Signal finished; + + virtual ~Popup() noexcept = default; + + virtual void open() noexcept = 0; + + virtual void close() noexcept = 0; + + [[nodiscard]] + virtual bool isOpen() const noexcept = 0; + + virtual void draw(core::Context *ctx) noexcept = 0; + + protected: + constexpr void setSize(geo::Size sz) noexcept { + m_size = {static_cast(sz.width), static_cast(sz.height)}; + } + + constexpr void setTitle(ox::String title) noexcept { + m_title = std::move(title); + } + + constexpr const ox::String &title() const noexcept { + return m_title; + } + + void drawWindow(core::Context *ctx, bool *open, auto drawContents) { + studio::ig::centerNextWindow(ctx); + ImGui::SetNextWindowSize(static_cast(m_size)); + constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + if (ImGui::BeginPopupModal(m_title.c_str(), open, modalFlags)) { + drawContents(); + } + } + +}; + + +} \ No newline at end of file diff --git a/src/nostalgia/studio/lib/project.cpp b/src/nostalgia/studio/lib/project.cpp index 7bd320b3..916fe99d 100644 --- a/src/nostalgia/studio/lib/project.cpp +++ b/src/nostalgia/studio/lib/project.cpp @@ -11,16 +11,8 @@ namespace nostalgia::studio { -ox::String filePathToName(const ox::String &path, const ox::String &prefix, const ox::String &suffix) noexcept { - const auto begin = prefix.len(); - const auto end = path.len() - (suffix.len() + prefix.len()); - return path.substr(begin, end); -} - - -Project::Project(ox::FileSystem *fs, const ox::String &path) noexcept: m_typeStore(fs), m_fs(fs) { - oxTracef("nostalgia::studio", "Project: {}", path); - m_path = path; +Project::Project(ox::FileSystem *fs, ox::String path) noexcept: m_path(std::move(path)), m_typeStore(fs), m_fs(fs) { + oxTracef("nostalgia::studio", "Project: {}", m_path); buildFileIndex(); } @@ -71,8 +63,13 @@ void Project::buildFileIndex() noexcept { } ox::Error Project::writeBuff(const ox::String &path, const ox::Buffer &buff) const noexcept { + const auto newFile = m_fs->stat(path.c_str()).error != 0; oxReturnError(m_fs->write(path.c_str(), buff.data(), buff.size())); - fileUpdated.emit(path); + if (newFile) { + fileAdded.emit(path); + } else { + fileUpdated.emit(path); + } return OxError(0); } diff --git a/src/nostalgia/studio/lib/project.hpp b/src/nostalgia/studio/lib/project.hpp index 0a041ff6..cce928f6 100644 --- a/src/nostalgia/studio/lib/project.hpp +++ b/src/nostalgia/studio/lib/project.hpp @@ -37,9 +37,6 @@ constexpr ox::Result fileExt(const ox::String &path) noexcept { return path.substr(extStart + 1); } -[[nodiscard]] -ox::String filePathToName(const ox::String &path, const ox::String &prefix, const ox::String &suffix) noexcept; - class NOSTALGIASTUDIO_EXPORT Project { private: ox::String m_path; @@ -48,7 +45,7 @@ class NOSTALGIASTUDIO_EXPORT Project { ox::HashMap> m_fileExtFileMap; public: - explicit Project(ox::FileSystem *fs, const ox::String &path) noexcept; + explicit Project(ox::FileSystem *fs, ox::String path) noexcept; ox::Error create() noexcept; @@ -60,7 +57,7 @@ class NOSTALGIASTUDIO_EXPORT Project { /** * Writes a MetalClaw object to the project at the given path. */ - ox::Error writeObj(const ox::String &path, auto *obj) const noexcept; + ox::Error writeObj(const ox::String &path, auto *obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) const noexcept; template ox::Result> loadObj(const ox::String &path) const noexcept; @@ -100,9 +97,9 @@ class NOSTALGIASTUDIO_EXPORT Project { }; -ox::Error Project::writeObj(const ox::String &path, auto *obj) const noexcept { +ox::Error Project::writeObj(const ox::String &path, auto *obj, ox::ClawFormat fmt) const noexcept { // write MetalClaw - oxRequireM(buff, ox::writeClaw(obj, ox::ClawFormat::Metal)); + oxRequireM(buff, ox::writeClaw(obj, fmt)); // write to FS oxReturnError(writeBuff(path, buff)); // write type descriptor @@ -110,15 +107,12 @@ ox::Error Project::writeObj(const ox::String &path, auto *obj) const noexcept { // write out type store static constexpr auto descPath = "/.nostalgia/type_descriptors"; oxReturnError(mkdir(descPath)); - for (const auto t : m_typeStore.typeList()) { - if (t->typeName.beginsWith("B:")) { - continue; - } + for (const auto &t : m_typeStore.typeList()) { oxRequireM(typeOut, ox::writeClaw(t, ox::ClawFormat::Organic)); // replace garbage last character with new line typeOut.back().value = '\n'; // write to FS - const auto typePath = ox::sfmt("{}/{}", descPath, t->typeName); + const auto typePath = ox::sfmt("{}/{};{}", descPath, t->typeName, t->typeVersion); oxReturnError(writeBuff(typePath, typeOut)); } fileUpdated.emit(path); diff --git a/src/nostalgia/studio/newmenu.cpp b/src/nostalgia/studio/newmenu.cpp new file mode 100644 index 00000000..e4d8771d --- /dev/null +++ b/src/nostalgia/studio/newmenu.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "lib/context.hpp" +#include "lib/imguiuitl.hpp" + +#include "newmenu.hpp" + +namespace nostalgia { + +NewMenu::NewMenu() noexcept { + setTitle("New Item"); + setSize({225, 110}); +} + +void NewMenu::open() noexcept { + m_stage = Stage::Opening; + m_selectedType = 0; +} + +void NewMenu::close() noexcept { + m_stage = Stage::Closed; + m_open = false; +} + +bool NewMenu::isOpen() const noexcept { + return m_open; +} + +void NewMenu::draw(core::Context *ctx) noexcept { + switch (m_stage) { + case Stage::Opening: + ImGui::OpenPopup(title().c_str()); + m_stage = Stage::NewItemType; + m_open = true; + [[fallthrough]]; + case Stage::NewItemType: + drawNewItemType(ctx); + break; + case Stage::NewItemName: + drawNewItemName(ctx); + break; + case Stage::Closed: + m_open = false; + break; + } +} + +void NewMenu::addItemMaker(ox::UniquePtr im) noexcept { + m_types.emplace_back(std::move(im)); +} + +void NewMenu::drawNewItemType(core::Context *ctx) noexcept { + drawWindow(ctx, &m_open, [this] { + auto items = ox_malloca(m_types.size() * sizeof(const char*), const char*, nullptr); + for (auto i = 0u; const auto &im : m_types) { + items[i] = im->name.c_str(); + ++i; + } + ImGui::ListBox("Item Type", &m_selectedType, items.get(), m_types.size()); + drawFirstPageButtons(); + ImGui::EndPopup(); + }); +} + +void NewMenu::drawNewItemName(core::Context *ctx) noexcept { + drawWindow(ctx, &m_open, [this, ctx] { + const auto typeIdx = static_cast(m_selectedType); + if (typeIdx < m_types.size()) { + ImGui::InputText("Name", m_itemName.data(), m_itemName.cap()); + } + drawLastPageButtons(ctx); + ImGui::EndPopup(); + }); +} + +void NewMenu::drawFirstPageButtons() noexcept { + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 80); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20); + if (ImGui::Button("Next")) { + m_stage = Stage::NewItemName; + } + ImGui::SameLine(); + if (ImGui::Button("Quit")) { + ImGui::CloseCurrentPopup(); + m_stage = Stage::Closed; + } +} + +void NewMenu::drawLastPageButtons(core::Context *ctx) noexcept { + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 138); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20); + if (ImGui::Button("Back")) { + m_stage = Stage::NewItemType; + } + ImGui::SameLine(); + if (ImGui::Button("Finish")) { + finish(ctx); + } + ImGui::SameLine(); + if (ImGui::Button("Quit")) { + ImGui::CloseCurrentPopup(); + m_stage = Stage::Closed; + } +} + +void NewMenu::finish(core::Context *ctx) noexcept { + const auto err = m_types[static_cast(m_selectedType)]->write(ctx, m_itemName.c_str()); + if (err) { + oxDebugf("NewMenu::finish() error: {}", toStr(err)); + oxLogError(err); + return; + } + finished.emit(""); + m_stage = Stage::Closed; +} + +} diff --git a/src/nostalgia/studio/newmenu.hpp b/src/nostalgia/studio/newmenu.hpp new file mode 100644 index 00000000..2f4c13e6 --- /dev/null +++ b/src/nostalgia/studio/newmenu.hpp @@ -0,0 +1,81 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include + +#include + +#include "lib/itemmaker.hpp" +#include "lib/popup.hpp" + +namespace nostalgia { + +class NewMenu: public studio::Popup { + public: + enum class Stage { + Closed, + Opening, + NewItemType, + NewItemName, + }; + + // emits path parameter + ox::Signal finished; + + private: + Stage m_stage = Stage::Closed; + ox::String m_typeName; + ox::BString<255> m_itemName; + ox::Vector> m_types; + int m_selectedType = 0; + bool m_open = false; + + public: + NewMenu() noexcept; + + void open() noexcept override; + + void close() noexcept override; + + [[nodiscard]] + bool isOpen() const noexcept override; + + void draw(core::Context *ctx) noexcept override; + + template + void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept; + + template + void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept; + + void addItemMaker(ox::UniquePtr im) noexcept; + + private: + void drawNewItemType(core::Context *ctx) noexcept; + + void drawNewItemName(core::Context *ctx) noexcept; + + void drawFirstPageButtons() noexcept; + + void drawLastPageButtons(core::Context *ctx) noexcept; + + void finish(core::Context *ctx) noexcept; + +}; + +template +void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt) noexcept { + m_types.emplace_back(new studio::ItemMakerT(std::move(displayName), std::move(parentDir), std::move(fileExt), std::move(itemTempl), pFmt)); +} + +template +void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt) noexcept { + m_types.emplace_back(new studio::ItemMakerT(std::move(displayName), std::move(parentDir), std::move(fileExt), pFmt)); +} + +} diff --git a/src/nostalgia/studio/projectexplorer.hpp b/src/nostalgia/studio/projectexplorer.hpp index 3bdbf39f..ff45029e 100644 --- a/src/nostalgia/studio/projectexplorer.hpp +++ b/src/nostalgia/studio/projectexplorer.hpp @@ -25,6 +25,7 @@ class ProjectExplorer: public studio::Widget { ox::Error refreshProjectTreeModel(const ox::String& = {}) noexcept; + [[nodiscard]] constexpr ox::FileSystem *romFs() noexcept { return m_ctx->rom.get(); } diff --git a/src/nostalgia/studio/studio.hpp b/src/nostalgia/studio/studio.hpp index d0e89860..67f34958 100644 --- a/src/nostalgia/studio/studio.hpp +++ b/src/nostalgia/studio/studio.hpp @@ -7,7 +7,10 @@ #include "lib/context.hpp" #include "lib/editor.hpp" #include "lib/filedialog.hpp" +#include "lib/imguiuitl.hpp" #include "lib/module.hpp" +#include "lib/itemmaker.hpp" +#include "lib/popup.hpp" #include "lib/project.hpp" #include "lib/task.hpp" #include "lib/undostack.hpp" diff --git a/src/nostalgia/studio/studioapp.cpp b/src/nostalgia/studio/studioapp.cpp index d516c8ba..e123ccfb 100644 --- a/src/nostalgia/studio/studioapp.cpp +++ b/src/nostalgia/studio/studioapp.cpp @@ -46,10 +46,10 @@ StudioUI::StudioUI(core::Context *ctx) noexcept { } } } else { - if (toStr(err)) { - oxErrf("Could not open studio config file: {}\n", toStr(err)); + if constexpr(!ox::defines::Debug) { + oxErrf("Could not open studio config file: {}: {}\n", err.errCode, toStr(err)); } else { - oxErrf("Could not open studio config file: {} ({}:{})\n", err.errCode, err.file, err.line); + oxErrf("Could not open studio config file: {}: {} ({}:{})\n", err.errCode, toStr(err), err.file, err.line); } } } @@ -60,6 +60,14 @@ void StudioUI::update() noexcept { void StudioUI::handleKeyEvent(core::Key key, bool down) noexcept { const auto ctrlDown = core::buttonDown(m_ctx, core::Key::Mod_Ctrl); + for (auto p : m_popups) { + if (p->isOpen()) { + if (key == core::Key::Escape) { + p->close(); + } + return; + } + } if (down && ctrlDown) { switch (key) { case core::Key::Num_1: @@ -68,6 +76,9 @@ void StudioUI::handleKeyEvent(core::Key key, bool down) noexcept { case core::Key::Alpha_C: m_activeEditor->copy(); break; + case core::Key::Alpha_N: + m_newMenu.open(); + break; case core::Key::Alpha_O: m_taskRunner.add(new FileDialogManager(this, &StudioUI::openProject)); break; @@ -109,16 +120,16 @@ void StudioUI::draw() noexcept { for (auto &w : m_widgets) { w->draw(m_ctx); } - if (m_aboutEnabled) { - ImGui::OpenPopup("About"); + for (auto p : m_popups) { + p->draw(m_ctx); } - drawAboutPopup(); } void StudioUI::drawMenu() noexcept { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("New...", "Ctrl+N")) { + m_newMenu.open(); } if (ImGui::MenuItem("Open Project...", "Ctrl+O")) { m_taskRunner.add(new FileDialogManager(this, &StudioUI::openProject)); @@ -159,7 +170,7 @@ void StudioUI::drawMenu() noexcept { } if (ImGui::BeginMenu("Help")) { if (ImGui::MenuItem("About")) { - m_aboutEnabled = true; + m_aboutPopup.open(); } ImGui::EndMenu(); } @@ -221,19 +232,6 @@ void StudioUI::drawTabs() noexcept { } } -void StudioUI::drawAboutPopup() noexcept { - constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; - if (ImGui::BeginPopupModal("About", &m_aboutEnabled, modalFlags)) { - ImGui::Text("Nostalgia Studio - dev build"); - ImGui::SetNextWindowPos(ImVec2(0.5f, 0.5f), ImGuiCond_Always, ImVec2(0.5f,0.5f)); - if (ImGui::Button("Close")) { - ImGui::CloseCurrentPopup(); - m_aboutEnabled = false; - } - ImGui::EndPopup(); - } -} - void StudioUI::loadEditorMaker(const studio::EditorMaker &editorMaker) noexcept { for (const auto &ext : editorMaker.fileTypes) { m_editorMakers[ext] = editorMaker.make; @@ -244,6 +242,9 @@ void StudioUI::loadModule(studio::Module *module) noexcept { for (auto &editorMaker : module->editors(m_ctx)) { loadEditorMaker(editorMaker); } + for (auto &im : module->itemMakers(m_ctx)) { + m_newMenu.addItemMaker(std::move(im)); + } } void StudioUI::loadModules() noexcept { @@ -320,7 +321,11 @@ ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab } auto [editor, err] = m_editorMakers[ext](path); if (err) { - oxErrorf("Could not open Editor: {} ({}:{})", err.msg, err.file, err.line); + if constexpr(!ox::defines::Debug) { + oxErrf("Could not open Editor: {}\n", toStr(err)); + } else { + oxErrf("Could not open Editor: {} ({}:{})\n", err.errCode, err.file, err.line); + } return err; } editor->closed.connect(this, &StudioUI::closeFile); diff --git a/src/nostalgia/studio/studioapp.hpp b/src/nostalgia/studio/studioapp.hpp index ce24a84a..0321a1f8 100644 --- a/src/nostalgia/studio/studioapp.hpp +++ b/src/nostalgia/studio/studioapp.hpp @@ -12,6 +12,8 @@ #include "lib/module.hpp" #include "lib/project.hpp" #include "lib/task.hpp" +#include "aboutpopup.hpp" +#include "newmenu.hpp" #include "projectexplorer.hpp" #include "projecttreemodel.hpp" @@ -31,8 +33,12 @@ class StudioUI: public ox::SignalHandler { ox::Vector m_openFiles; studio::BaseEditor *m_activeEditor = nullptr; studio::BaseEditor *m_activeEditorUpdatePending = nullptr; - bool m_saveEnabled = false; - bool m_aboutEnabled = false; + NewMenu m_newMenu; + AboutPopup m_aboutPopup; + const ox::Array m_popups = { + &m_newMenu, + &m_aboutPopup + }; bool m_showProjectExplorer = true; public: @@ -57,8 +63,6 @@ class StudioUI: public ox::SignalHandler { void drawTabs() noexcept; - void drawAboutPopup() noexcept; - void loadEditorMaker(const studio::EditorMaker &editorMaker) noexcept; void loadModule(studio::Module *module) noexcept;