Compare commits

...

2 Commits

Author SHA1 Message Date
6924147686 [studio] Add ability to add file through dir context menu
All checks were successful
Build / build (push) Successful in 3m15s
Also, fix dir context menu to work when dir is closed, and fix it not to
override last file in the directory.
2025-01-18 23:45:04 -06:00
6e2b4fa7b4 [nostalgia] Cleanup player run in Makefile 2025-01-18 23:33:55 -06:00
9 changed files with 95 additions and 18 deletions

View File

@ -5,9 +5,11 @@ BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) ifeq ($(BC_VAR_OS),darwin)
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME}.app/Contents/MacOS/${BC_VAR_PROJECT_NAME}
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else else
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME}
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=mgba-qt MGBA=mgba-qt
endif endif
@ -16,9 +18,12 @@ endif
pkg-gba: build pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME}
.PHONY: run .PHONY: run
run: build run: build-player
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project ${PROJECT_PLAYER} sample_project
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build
${NOSTALGIA_STUDIO} ${NOSTALGIA_STUDIO}

View File

@ -22,6 +22,12 @@ void NewMenu::open() noexcept {
m_selectedType = 0; m_selectedType = 0;
m_itemName = ""; m_itemName = "";
m_typeName = ""; m_typeName = "";
m_path = "";
}
void NewMenu::openPath(ox::StringParam path) noexcept {
open();
m_path = std::move(path);
} }
void NewMenu::close() noexcept { void NewMenu::close() noexcept {
@ -158,14 +164,14 @@ void NewMenu::finish(StudioContext &sctx) noexcept {
oxLogError(ox::Error{1, "New file error: no file name"}); oxLogError(ox::Error{1, "New file error: no file name"});
return; return;
} }
auto const&im = *m_types[static_cast<std::size_t>(m_selectedType)]; auto const&im = *m_types[m_selectedType];
if (sctx.project->exists(im.itemPath(m_itemName))) { auto const path = m_path.len() ?
im.itemPath(m_itemName, m_path) : im.itemPath(m_itemName);
if (sctx.project->exists(path)) {
oxLogError(ox::Error{1, "New file error: file already exists"}); oxLogError(ox::Error{1, "New file error: file already exists"});
return; return;
} }
auto const [path, err] = if (auto const err = im.write(sctx, path, m_selectedTemplate)) {
im.write(sctx, m_itemName, m_selectedTemplate);
if (err) {
oxLogError(err); oxLogError(err);
return; return;
} }

View File

@ -30,6 +30,7 @@ class NewMenu final: public Popup {
Stage m_stage = Stage::Closed; Stage m_stage = Stage::Closed;
ox::String m_typeName; ox::String m_typeName;
ox::IString<255> m_itemName; ox::IString<255> m_itemName;
ox::String m_path;
ox::Vector<ox::UPtr<studio::ItemMaker>> m_types; ox::Vector<ox::UPtr<studio::ItemMaker>> m_types;
size_t m_selectedType = 0; size_t m_selectedType = 0;
size_t m_selectedTemplate = 0; size_t m_selectedTemplate = 0;
@ -38,6 +39,8 @@ class NewMenu final: public Popup {
public: public:
NewMenu() noexcept; NewMenu() noexcept;
void openPath(ox::StringParam path) noexcept;
void open() noexcept override; void open() noexcept override;
void close() noexcept override; void close() noexcept override;

View File

@ -19,7 +19,8 @@ class ProjectExplorer: public Widget {
public: public:
// slots // slots
ox::Signal<ox::Error(ox::StringView const&)> fileChosen; ox::Signal<ox::Error(ox::StringViewCR)> fileChosen;
ox::Signal<ox::Error(ox::StringViewCR)> addItem;
explicit ProjectExplorer(turbine::Context &ctx) noexcept; explicit ProjectExplorer(turbine::Context &ctx) noexcept;

View File

@ -4,6 +4,8 @@
#include <imgui.h> #include <imgui.h>
#include <studio/imguiutil.hpp>
#include "projectexplorer.hpp" #include "projectexplorer.hpp"
#include "projecttreemodel.hpp" #include "projecttreemodel.hpp"
@ -30,10 +32,14 @@ bool ProjectTreeModel::draw(turbine::Context &ctx) const noexcept {
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
if (!m_children.empty()) { if (!m_children.empty()) {
if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) { if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) {
drawDirContextMenu();
for (auto const&child : m_children) { for (auto const&child : m_children) {
updated = child->draw(ctx) || updated; updated = child->draw(ctx) || updated;
} }
ImGui::TreePop(); ImGui::TreePop();
} else {
ig::IDStackItem const idStackItem{m_name};
drawDirContextMenu();
} }
} else { } else {
auto const path = fullPath(); auto const path = fullPath();
@ -58,6 +64,15 @@ void ProjectTreeModel::setChildren(ox::Vector<ox::UPtr<ProjectTreeModel>> childr
m_children = std::move(children); m_children = std::move(children);
} }
void ProjectTreeModel::drawDirContextMenu() const noexcept {
if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) {
if (ImGui::MenuItem("Add Item")) {
m_explorer.addItem.emit(fullPath());
}
ImGui::EndPopup();
}
}
ox::BasicString<255> ProjectTreeModel::fullPath() const noexcept { ox::BasicString<255> ProjectTreeModel::fullPath() const noexcept {
if (m_parent) { if (m_parent) {
return m_parent->fullPath() + "/" + ox::StringView(m_name); return m_parent->fullPath() + "/" + ox::StringView(m_name);

View File

@ -31,6 +31,8 @@ class ProjectTreeModel {
void setChildren(ox::Vector<ox::UPtr<ProjectTreeModel>> children) noexcept; void setChildren(ox::Vector<ox::UPtr<ProjectTreeModel>> children) noexcept;
private: private:
void drawDirContextMenu() const noexcept;
[[nodiscard]] [[nodiscard]]
ox::BasicString<255> fullPath() const noexcept; ox::BasicString<255> fullPath() const noexcept;

View File

@ -52,6 +52,7 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
m_aboutPopup(m_tctx) { m_aboutPopup(m_tctx) {
turbine::setApplicationData(m_tctx, &m_sctx); turbine::setApplicationData(m_tctx, &m_sctx);
m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile); m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
m_projectExplorer.addItem.connect(this, &StudioUI::addFile);
m_newProject.finished.connect(this, &StudioUI::createOpenProject); m_newProject.finished.connect(this, &StudioUI::createOpenProject);
m_newMenu.finished.connect(this, &StudioUI::openFile); m_newMenu.finished.connect(this, &StudioUI::openFile);
ImGui::GetIO().IniFilename = nullptr; ImGui::GetIO().IniFilename = nullptr;
@ -342,6 +343,11 @@ void StudioUI::handleKeyInput() noexcept {
} }
} }
ox::Error StudioUI::addFile(ox::StringViewCR path) noexcept {
m_newMenu.openPath(path);
return {};
}
ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept { ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
std::error_code ec; std::error_code ec;
std::filesystem::create_directories(toStdStringView(path), ec); std::filesystem::create_directories(toStdStringView(path), ec);

View File

@ -83,6 +83,8 @@ class StudioUI: public ox::SignalHandler {
void handleKeyInput() noexcept; void handleKeyInput() noexcept;
ox::Error addFile(ox::StringViewCR path) noexcept;
ox::Error createOpenProject(ox::StringViewCR path) noexcept; ox::Error createOpenProject(ox::StringViewCR path) noexcept;
ox::Error openProjectPath(ox::StringParam path) noexcept; ox::Error openProjectPath(ox::StringParam path) noexcept;

View File

@ -128,6 +128,16 @@ class ItemMaker {
return m_templates; return m_templates;
} }
[[nodiscard]]
ox::String const&defaultPath() const noexcept {
return m_parentDir;
}
[[nodiscard]]
ox::String itemPath(ox::StringViewCR pName, ox::StringViewCR pPath) const noexcept {
return ox::sfmt("/{}/{}.{}", pPath, pName, m_fileExt);
}
[[nodiscard]] [[nodiscard]]
ox::String itemPath(ox::StringViewCR pName) const noexcept { ox::String itemPath(ox::StringViewCR pName) const noexcept {
return ox::sfmt("/{}/{}.{}", m_parentDir, pName, m_fileExt); return ox::sfmt("/{}/{}.{}", m_parentDir, pName, m_fileExt);
@ -142,12 +152,40 @@ class ItemMaker {
/** /**
* Returns path of the file created. * Returns path of the file created.
* @param ctx * @param ctx
* @param pPath
* @param pTemplateIdx
* @return path of file or error in Result
*/
ox::Error write(
StudioContext &ctx,
ox::StringViewCR pPath,
size_t pTemplateIdx) const noexcept {
return writeItem(ctx, pPath, pTemplateIdx);
}
/**
* Returns path of the file created.
* @param ctx
* @param pPath
* @param pName * @param pName
* @param pTemplateIdx * @param pTemplateIdx
* @return path of file or error in Result * @return path of file or error in Result
*/ */
virtual ox::Result<ox::String> write( ox::Error write(
StudioContext &ctx, ox::StringViewCR pName, size_t pTemplateIdx) const noexcept = 0; StudioContext &ctx,
ox::StringViewCR pPath,
ox::StringViewCR pName,
size_t pTemplateIdx) const noexcept {
auto const path = itemPath(pName, pPath);
return writeItem(ctx, path, pTemplateIdx);
}
protected:
virtual ox::Error writeItem(
StudioContext &ctx,
ox::StringViewCR pPath,
size_t pTemplateIdx) const noexcept = 0;
}; };
template<typename T> template<typename T>
@ -205,20 +243,19 @@ class ItemMakerT final: public ItemMaker {
return ox::ModelTypeVersion_v<T>; return ox::ModelTypeVersion_v<T>;
} }
ox::Result<ox::String> write( ox::Error writeItem(
StudioContext &sctx, StudioContext &ctx,
ox::StringViewCR pName, ox::StringViewCR pPath,
size_t const pTemplateIdx) const noexcept override { size_t const pTemplateIdx) const noexcept override {
auto const path = itemPath(pName); createUuidMapping(keelCtx(ctx.tctx), pPath, ox::UUID::generate().unwrap());
createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
auto const&templates = itemTemplates(); auto const&templates = itemTemplates();
auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0; auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0;
OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem( OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem(
keelCtx(sctx), typeName(), typeVersion())); keelCtx(ctx), typeName(), typeVersion()));
auto item = tmpl.template get<T>(); auto item = tmpl.template get<T>();
OX_RETURN_ERROR(sctx.project->writeObj(path, *item, m_fmt)); OX_RETURN_ERROR(ctx.project->writeObj(pPath, *item, m_fmt));
tmpl.free(); tmpl.free();
return path; return {};
} }
}; };