[olympic/studio] Fix several crashes
This commit is contained in:
		| @@ -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); | ||||
|   | ||||
| @@ -15,7 +15,12 @@ | ||||
|  | ||||
| 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 { | ||||
| 	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<ProjectExplorer>(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<ProjectExplorer>(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<StudioConfig>(keelCtx(*ctx)); | ||||
| 	auto const [config, err] = studio::readConfig<StudioConfig>(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<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); | ||||
| 	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<ox::String>([](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<StudioConfig>(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 {}; | ||||
| } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -24,27 +24,27 @@ class StudioUI: public ox::SignalHandler { | ||||
|  | ||||
| 	private: | ||||
| 		turbine::Context &m_ctx; | ||||
| 		ox::String m_projectDir; | ||||
| 		ox::UniquePtr<studio::Project> m_project; | ||||
| 		ox::String m_projectDataDir; | ||||
| 		ox::UPtr<studio::Project> m_project; | ||||
| 		studio::TaskRunner m_taskRunner; | ||||
| 		ox::Vector<ox::UniquePtr<studio::BaseEditor>> m_editors; | ||||
| 		ox::Vector<ox::UniquePtr<studio::Widget>> m_widgets; | ||||
| 		ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors; | ||||
| 		ox::Vector<ox::UPtr<studio::Widget>> m_widgets; | ||||
| 		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; | ||||
| 		studio::BaseEditor *m_activeEditorOnLastDraw = nullptr; | ||||
| 		studio::BaseEditor *m_activeEditor = nullptr; | ||||
| 		studio::BaseEditor *m_activeEditorUpdatePending = nullptr; | ||||
| 		NewMenu m_newMenu; | ||||
| 		AboutPopup m_aboutPopup; | ||||
| 		const ox::Array<studio::Popup*, 2> m_popups = { | ||||
| 		ox::Array<studio::Popup*, 2> 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; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user