[olympic/studio] Fix several crashes

This commit is contained in:
Gary Talent 2023-12-14 21:34:46 -06:00
parent 2167a46266
commit db961739ad
3 changed files with 51 additions and 36 deletions

View File

@ -53,7 +53,7 @@ static ox::Error runApp(
turbine::setConstantRefresh(*ctx, false); turbine::setConstantRefresh(*ctx, false);
studio::StudioContext studioCtx; studio::StudioContext studioCtx;
turbine::setApplicationData(*ctx, &studioCtx); turbine::setApplicationData(*ctx, &studioCtx);
StudioUI ui(ctx.get(), projectDataDir); StudioUI ui(*ctx, projectDataDir);
studioCtx.ui = &ui; studioCtx.ui = &ui;
StudioUIDrawer drawer(ui); StudioUIDrawer drawer(ui);
turbine::gl::addDrawer(*ctx, &drawer); turbine::gl::addDrawer(*ctx, &drawer);

View File

@ -15,7 +15,12 @@
namespace studio { namespace studio {
ox::Vector<const studio::Module*> modules; static ox::Vector<const studio::Module*> modules;
void registerModule(studio::Module const*mod) noexcept {
modules.emplace_back(mod);
}
struct StudioConfig { struct StudioConfig {
static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig"; static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig";
@ -33,23 +38,25 @@ oxModelBegin(StudioConfig)
oxModelFieldRename(show_project_explorer, showProjectExplorer) oxModelFieldRename(show_project_explorer, showProjectExplorer)
oxModelEnd() oxModelEnd()
StudioUI::StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept: StudioUI::StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcept:
m_ctx(*ctx), m_ctx(ctx),
m_projectDir(projectDir), m_projectDataDir(projectDataDir),
m_projectExplorer(ox::make_unique<ProjectExplorer>(m_ctx)), m_projectExplorer(ox::make_unique<ProjectExplorer>(m_ctx)),
m_aboutPopup(*ctx) { m_aboutPopup(m_ctx) {
m_projectExplorer->fileChosen.connect(this, &StudioUI::openFile); m_projectExplorer->fileChosen.connect(this, &StudioUI::openFile);
ImGui::GetIO().IniFilename = nullptr; ImGui::GetIO().IniFilename = nullptr;
loadModules(); loadModules();
// open project and files // open project and files
const auto [config, err] = studio::readConfig<StudioConfig>(keelCtx(*ctx)); auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_ctx));
m_showProjectExplorer = config.showProjectExplorer; m_showProjectExplorer = config.showProjectExplorer;
if (!err) { if (!err) {
oxIgnoreError(openProject(config.projectPath)); auto const openProjErr = openProject(config.projectPath);
for (const auto &f : config.openFiles) { if (!openProjErr) {
auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f); for (const auto &f: config.openFiles) {
if (openFileErr) { auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr)); if (openFileErr) {
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
}
} }
} }
} else { } else {
@ -83,7 +90,9 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
toggleProjectExplorer(); toggleProjectExplorer();
break; break;
case turbine::Key::Alpha_C: case turbine::Key::Alpha_C:
m_activeEditor->copy(); if (m_activeEditor && m_activeEditor->copyEnabled()) {
m_activeEditor->copy();
}
break; break;
case turbine::Key::Alpha_N: case turbine::Key::Alpha_N:
m_newMenu.open(); m_newMenu.open();
@ -98,10 +107,14 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
save(); save();
break; break;
case turbine::Key::Alpha_V: case turbine::Key::Alpha_V:
m_activeEditor->paste(); if (m_activeEditor && m_activeEditor->pasteEnabled()) {
m_activeEditor->paste();
}
break; break;
case turbine::Key::Alpha_X: case turbine::Key::Alpha_X:
m_activeEditor->cut(); if (m_activeEditor && m_activeEditor->cutEnabled()) {
m_activeEditor->cut();
}
break; break;
case turbine::Key::Alpha_Y: case turbine::Key::Alpha_Y:
redo(); redo();
@ -169,19 +182,19 @@ void StudioUI::drawMenu() noexcept {
if (ImGui::BeginMenu("Edit")) { if (ImGui::BeginMenu("Edit")) {
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr; auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
if (ImGui::MenuItem("Undo", "Ctrl+Z", false, undoStack && undoStack->canUndo())) { 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())) { if (ImGui::MenuItem("Redo", "Ctrl+Y", false, undoStack && undoStack->canRedo())) {
m_activeEditor->undoStack()->redo(); undoStack->redo();
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Copy", "Ctrl+C")) { if (ImGui::MenuItem("Copy", "Ctrl+C", false, m_activeEditor && m_activeEditor->copyEnabled())) {
m_activeEditor->copy(); m_activeEditor->copy();
} }
if (ImGui::MenuItem("Cut", "Ctrl+X")) { if (ImGui::MenuItem("Cut", "Ctrl+X", false, m_activeEditor && m_activeEditor->cutEnabled())) {
m_activeEditor->cut(); 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(); m_activeEditor->paste();
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -240,6 +253,9 @@ void StudioUI::drawTabs() noexcept {
} }
if (!open) { if (!open) {
e->close(); e->close();
if (m_activeEditor == (*it).get()) {
m_activeEditor = nullptr;
}
try { try {
oxThrowError(m_editors.erase(it).moveTo(&it)); oxThrowError(m_editors.erase(it).moveTo(&it));
} catch (const ox::Exception &ex) { } catch (const ox::Exception &ex) {
@ -305,7 +321,7 @@ ox::Error StudioUI::openProject(ox::CRStringView path) noexcept {
oxRequireM(fs, keel::loadRomFs(path)); oxRequireM(fs, keel::loadRomFs(path));
oxReturnError(keel::setRomFs(keelCtx(m_ctx), std::move(fs))); oxReturnError(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, path)); turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, path));
m_project = ox::make_unique<studio::Project>(keelCtx(m_ctx), ox::String(path), m_projectDir); m_project = ox::make_unique<studio::Project>(keelCtx(m_ctx), ox::String(path), m_projectDataDir);
auto sctx = applicationData<studio::StudioContext>(m_ctx); auto sctx = applicationData<studio::StudioContext>(m_ctx);
sctx->project = m_project.get(); sctx->project = m_project.get();
m_project->fileAdded.connect(m_projectExplorer.get(), &ProjectExplorer::refreshProjectTreeModel); 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 { 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)) { if (m_openFiles.contains(path)) {
for (auto &e : m_editors) { for (auto &e : m_editors) {
if (makeActiveTab && e->itemPath() == path) { if (makeActiveTab && e->itemPath() == path) {
@ -332,7 +351,7 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
break; break;
} }
} }
return OxError(0); return {};
} }
oxRequire(ext, studio::fileExt(path).to<ox::String>([](auto const&v) {return ox::String(v);})); oxRequire(ext, studio::fileExt(path).to<ox::String>([](auto const&v) {return ox::String(v);}));
// create Editor // create Editor
@ -372,18 +391,14 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
ox::Error StudioUI::closeFile(ox::CRStringView path) noexcept { ox::Error StudioUI::closeFile(ox::CRStringView path) noexcept {
if (!m_openFiles.contains(path)) { if (!m_openFiles.contains(path)) {
return OxError(0); return {};
} }
oxIgnoreError(m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path))); oxIgnoreError(m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path)));
// save to config // save to config
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
oxIgnoreError(config->openFiles.erase(std::remove(config->openFiles.begin(), config->openFiles.end(), path))); oxIgnoreError(config->openFiles.erase(std::remove(config->openFiles.begin(), config->openFiles.end(), path)));
}); });
return OxError(0); return {};
}
void registerModule(const studio::Module *mod) noexcept {
modules.emplace_back(mod);
} }
} }

View File

@ -24,27 +24,27 @@ class StudioUI: public ox::SignalHandler {
private: private:
turbine::Context &m_ctx; turbine::Context &m_ctx;
ox::String m_projectDir; ox::String m_projectDataDir;
ox::UniquePtr<studio::Project> m_project; ox::UPtr<studio::Project> m_project;
studio::TaskRunner m_taskRunner; studio::TaskRunner m_taskRunner;
ox::Vector<ox::UniquePtr<studio::BaseEditor>> m_editors; ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors;
ox::Vector<ox::UniquePtr<studio::Widget>> m_widgets; ox::Vector<ox::UPtr<studio::Widget>> m_widgets;
ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers; ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
ox::UniquePtr<ProjectExplorer> m_projectExplorer; ox::UPtr<ProjectExplorer> m_projectExplorer;
ox::Vector<ox::String> m_openFiles; ox::Vector<ox::String> m_openFiles;
studio::BaseEditor *m_activeEditorOnLastDraw = nullptr; studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
studio::BaseEditor *m_activeEditor = nullptr; studio::BaseEditor *m_activeEditor = nullptr;
studio::BaseEditor *m_activeEditorUpdatePending = nullptr; studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
NewMenu m_newMenu; NewMenu m_newMenu;
AboutPopup m_aboutPopup; AboutPopup m_aboutPopup;
const ox::Array<studio::Popup*, 2> m_popups = { ox::Array<studio::Popup*, 2> const m_popups = {
&m_newMenu, &m_newMenu,
&m_aboutPopup &m_aboutPopup
}; };
bool m_showProjectExplorer = true; bool m_showProjectExplorer = true;
public: public:
explicit StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept; explicit StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcept;
void update() noexcept; void update() noexcept;