[studio] Add ability to add file through dir context menu
All checks were successful
Build / build (push) Successful in 3m15s
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.
This commit is contained in:
parent
6e2b4fa7b4
commit
6924147686
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user