diff --git a/src/olympic/studio/applib/src/main.cpp b/src/olympic/studio/applib/src/main.cpp index dd3ce105..26931254 100644 --- a/src/olympic/studio/applib/src/main.cpp +++ b/src/olympic/studio/applib/src/main.cpp @@ -53,7 +53,7 @@ static ox::Error runApp( turbine::setConstantRefresh(*ctx, false); studio::StudioContext studioCtx; turbine::setApplicationData(*ctx, &studioCtx); - StudioUI ui(ctx.get(), projectDataDir); + StudioUI ui(*ctx, projectDataDir); studioCtx.ui = &ui; StudioUIDrawer drawer(ui); turbine::gl::addDrawer(*ctx, &drawer); diff --git a/src/olympic/studio/applib/src/studioapp.cpp b/src/olympic/studio/applib/src/studioapp.cpp index e37ade3c..6cc75a10 100644 --- a/src/olympic/studio/applib/src/studioapp.cpp +++ b/src/olympic/studio/applib/src/studioapp.cpp @@ -15,7 +15,12 @@ namespace studio { -ox::Vector modules; +static ox::Vector modules; + +void registerModule(studio::Module const*mod) noexcept { + modules.emplace_back(mod); +} + struct StudioConfig { static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig"; @@ -33,23 +38,25 @@ oxModelBegin(StudioConfig) oxModelFieldRename(show_project_explorer, showProjectExplorer) oxModelEnd() -StudioUI::StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept: - m_ctx(*ctx), - m_projectDir(projectDir), - m_projectExplorer(ox::make_unique(m_ctx)), - m_aboutPopup(*ctx) { +StudioUI::StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcept: + m_ctx(ctx), + m_projectDataDir(projectDataDir), + m_projectExplorer(ox::make_unique(m_ctx)), + m_aboutPopup(m_ctx) { m_projectExplorer->fileChosen.connect(this, &StudioUI::openFile); ImGui::GetIO().IniFilename = nullptr; loadModules(); // open project and files - const auto [config, err] = studio::readConfig(keelCtx(*ctx)); + auto const [config, err] = studio::readConfig(keelCtx(m_ctx)); m_showProjectExplorer = config.showProjectExplorer; if (!err) { - oxIgnoreError(openProject(config.projectPath)); - for (const auto &f : config.openFiles) { - auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f); - if (openFileErr) { - oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr)); + auto const openProjErr = openProject(config.projectPath); + if (!openProjErr) { + for (const auto &f: config.openFiles) { + auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f); + if (openFileErr) { + oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr)); + } } } } else { @@ -83,7 +90,9 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept { toggleProjectExplorer(); break; case turbine::Key::Alpha_C: - m_activeEditor->copy(); + if (m_activeEditor && m_activeEditor->copyEnabled()) { + m_activeEditor->copy(); + } break; case turbine::Key::Alpha_N: m_newMenu.open(); @@ -98,10 +107,14 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept { save(); break; case turbine::Key::Alpha_V: - m_activeEditor->paste(); + if (m_activeEditor && m_activeEditor->pasteEnabled()) { + m_activeEditor->paste(); + } break; case turbine::Key::Alpha_X: - m_activeEditor->cut(); + if (m_activeEditor && m_activeEditor->cutEnabled()) { + m_activeEditor->cut(); + } break; case turbine::Key::Alpha_Y: redo(); @@ -169,19 +182,19 @@ void StudioUI::drawMenu() noexcept { if (ImGui::BeginMenu("Edit")) { auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr; if (ImGui::MenuItem("Undo", "Ctrl+Z", false, undoStack && undoStack->canUndo())) { - m_activeEditor->undoStack()->undo(); + undoStack->undo(); } if (ImGui::MenuItem("Redo", "Ctrl+Y", false, undoStack && undoStack->canRedo())) { - m_activeEditor->undoStack()->redo(); + undoStack->redo(); } ImGui::Separator(); - if (ImGui::MenuItem("Copy", "Ctrl+C")) { + if (ImGui::MenuItem("Copy", "Ctrl+C", false, m_activeEditor && m_activeEditor->copyEnabled())) { m_activeEditor->copy(); } - if (ImGui::MenuItem("Cut", "Ctrl+X")) { + if (ImGui::MenuItem("Cut", "Ctrl+X", false, m_activeEditor && m_activeEditor->cutEnabled())) { m_activeEditor->cut(); } - if (ImGui::MenuItem("Paste", "Ctrl+V")) { + if (ImGui::MenuItem("Paste", "Ctrl+V", false, m_activeEditor && m_activeEditor->pasteEnabled()) && m_activeEditor) { m_activeEditor->paste(); } ImGui::EndMenu(); @@ -240,6 +253,9 @@ void StudioUI::drawTabs() noexcept { } if (!open) { e->close(); + if (m_activeEditor == (*it).get()) { + m_activeEditor = nullptr; + } try { oxThrowError(m_editors.erase(it).moveTo(&it)); } catch (const ox::Exception &ex) { @@ -305,7 +321,7 @@ ox::Error StudioUI::openProject(ox::CRStringView path) noexcept { oxRequireM(fs, keel::loadRomFs(path)); oxReturnError(keel::setRomFs(keelCtx(m_ctx), std::move(fs))); turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, path)); - m_project = ox::make_unique(keelCtx(m_ctx), ox::String(path), m_projectDir); + m_project = ox::make_unique(keelCtx(m_ctx), ox::String(path), m_projectDataDir); auto sctx = applicationData(m_ctx); sctx->project = m_project.get(); m_project->fileAdded.connect(m_projectExplorer.get(), &ProjectExplorer::refreshProjectTreeModel); @@ -324,6 +340,9 @@ ox::Error StudioUI::openFile(ox::CRStringView path) noexcept { } ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept { + if (!m_project) { + return OxError(1, "No project open to open a file from"); + } if (m_openFiles.contains(path)) { for (auto &e : m_editors) { if (makeActiveTab && e->itemPath() == path) { @@ -332,7 +351,7 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab) break; } } - return OxError(0); + return {}; } oxRequire(ext, studio::fileExt(path).to([](auto const&v) {return ox::String(v);})); // create Editor @@ -372,18 +391,14 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab) ox::Error StudioUI::closeFile(ox::CRStringView path) noexcept { if (!m_openFiles.contains(path)) { - return OxError(0); + return {}; } oxIgnoreError(m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path))); // save to config studio::editConfig(keelCtx(m_ctx), [&](StudioConfig *config) { oxIgnoreError(config->openFiles.erase(std::remove(config->openFiles.begin(), config->openFiles.end(), path))); }); - return OxError(0); -} - -void registerModule(const studio::Module *mod) noexcept { - modules.emplace_back(mod); + return {}; } } diff --git a/src/olympic/studio/applib/src/studioapp.hpp b/src/olympic/studio/applib/src/studioapp.hpp index b1bcf21a..049af42e 100644 --- a/src/olympic/studio/applib/src/studioapp.hpp +++ b/src/olympic/studio/applib/src/studioapp.hpp @@ -24,27 +24,27 @@ class StudioUI: public ox::SignalHandler { private: turbine::Context &m_ctx; - ox::String m_projectDir; - ox::UniquePtr m_project; + ox::String m_projectDataDir; + ox::UPtr m_project; studio::TaskRunner m_taskRunner; - ox::Vector> m_editors; - ox::Vector> m_widgets; + ox::Vector> m_editors; + ox::Vector> m_widgets; ox::HashMap m_editorMakers; - ox::UniquePtr m_projectExplorer; + ox::UPtr m_projectExplorer; ox::Vector m_openFiles; studio::BaseEditor *m_activeEditorOnLastDraw = nullptr; studio::BaseEditor *m_activeEditor = nullptr; studio::BaseEditor *m_activeEditorUpdatePending = nullptr; NewMenu m_newMenu; AboutPopup m_aboutPopup; - const ox::Array m_popups = { + ox::Array const m_popups = { &m_newMenu, &m_aboutPopup }; bool m_showProjectExplorer = true; public: - explicit StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept; + explicit StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcept; void update() noexcept;