Squashed 'deps/nostalgia/' changes from a3d6a58c..d68e6493
d68e6493 [nostalgia/core/studio/tilesheeteditor] Add support for dragging palette to palette selector 1cbc5762 [studio] Complete drag/drop support for files 500b9356 [studio] Make new dir window OK on Enter key 800ca851 [ox/std] Fix possible error that occurs with appending on boundary of small string size cc466a9f [studio] Add support for adding and deleting directories 9d115584 [nostalgia] Rename player from 'nostalgia' to 'Nostalgia' a2139c09 [studio] Cleanup unused member a3e5f27a [ox/std] Fix Mac build 643f95ec [studio] Add confirmation dialog for file deletion, move deletion to Project 69241476 [studio] Add ability to add file through dir context menu 6e2b4fa7 [nostalgia] Cleanup player run in Makefile 4e5c7499 [studio] Add support for deleting files 66229de7 [ox/fs] FileSystem fixes with removing files 7eb37c53 [nostalgia/core/studio/paletteeditor] Fix adding page if there is no existing page 7a21b207 [nostalgia/core] Replace ContextDeleter with safeDelete(Context*) 894be237 [ox/std] Drop ox:: qualifier from safeDelete function for pointee 92e9d9cb [keel,studio] Add support for New Item templates b29b9a9b [ox/std] Add UAnyPtr 721f8442 [nostalgia/core/studio/tilesheeteditor] Fix subsheet and palette scrolling git-subtree-dir: deps/nostalgia git-subtree-split: d68e64931b37d7d8bbaff7b43bf131c7acf2aa97
This commit is contained in:
22
src/olympic/studio/modlib/include/studio/dragdrop.hpp
Normal file
22
src/olympic/studio/modlib/include/studio/dragdrop.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/model/def.hpp>
|
||||
|
||||
namespace studio {
|
||||
|
||||
struct FileRef {
|
||||
static constexpr auto TypeName = "net.drinkingtea.studio.FileRef";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
ox::String path;
|
||||
};
|
||||
|
||||
OX_MODEL_BEGIN(FileRef)
|
||||
OX_MODEL_FIELD(path)
|
||||
OX_MODEL_END()
|
||||
|
||||
}
|
@@ -63,6 +63,7 @@ auto dragDropSource(auto const&cb) noexcept {
|
||||
if (ig::DragDropSource const tgt; tgt) [[unlikely]] {
|
||||
return cb();
|
||||
}
|
||||
return ox::Error{};
|
||||
} else {
|
||||
if (ig::DragDropSource const tgt; tgt) [[unlikely]] {
|
||||
cb();
|
||||
@@ -175,9 +176,16 @@ enum class PopupResponse {
|
||||
Cancel,
|
||||
};
|
||||
|
||||
PopupResponse PopupControlsOkCancel(float popupWidth, bool &popupOpen);
|
||||
PopupResponse PopupControlsOkCancel(
|
||||
float popupWidth,
|
||||
bool &popupOpen,
|
||||
ox::CStringViewCR ok = "OK",
|
||||
ox::CStringViewCR cancel = "Cancel");
|
||||
|
||||
PopupResponse PopupControlsOkCancel(bool &popupOpen);
|
||||
PopupResponse PopupControlsOkCancel(
|
||||
bool &popupOpen,
|
||||
ox::CStringViewCR ok = "OK",
|
||||
ox::CStringViewCR cancel = "Cancel");
|
||||
|
||||
[[nodiscard]]
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const&sz = {285, 0});
|
||||
@@ -214,7 +222,8 @@ bool ListBox(
|
||||
ox::CStringViewCR name,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
size_t strCnt,
|
||||
size_t &selIdx) noexcept;
|
||||
size_t &selIdx,
|
||||
ImVec2 const&sz = {0, 0}) noexcept;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@@ -4,7 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/claw/claw.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ox/model/typenamecatcher.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
#include <turbine/context.hpp>
|
||||
@@ -13,75 +15,249 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
class ItemMaker {
|
||||
class ItemTemplate {
|
||||
private:
|
||||
ox::String const m_name{"Default"};
|
||||
|
||||
public:
|
||||
ox::String const typeName;
|
||||
ox::String const parentDir;
|
||||
ox::String const fileExt;
|
||||
constexpr explicit ItemMaker(
|
||||
explicit ItemTemplate() noexcept = default;
|
||||
|
||||
explicit ItemTemplate(ox::StringParam name) noexcept: m_name{std::move(name)} {}
|
||||
|
||||
virtual ~ItemTemplate() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr ox::String const&name() const noexcept {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
constexpr bool operator<=>(ItemTemplate const&other) const noexcept {
|
||||
return m_name != other.name() ? (m_name < other.name() ? -1 : 1) : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::CStringView displayName() const noexcept {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ox::CStringView typeName() const noexcept = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual int typeVersion() const noexcept = 0;
|
||||
|
||||
virtual ox::Result<ox::UAnyPtr> getItem(
|
||||
keel::Context &ctx, ox::StringViewCR name, int version) noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ItemTemplateT: public ItemTemplate {
|
||||
private:
|
||||
T const m_item;
|
||||
|
||||
public:
|
||||
constexpr ItemTemplateT() noexcept = default;
|
||||
|
||||
explicit ItemTemplateT(ox::StringParam name, T item) noexcept:
|
||||
ItemTemplate{std::move(name)}, m_item{std::move(item)} {}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::CStringView typeName() const noexcept final {
|
||||
return ox::ModelTypeName_v<T>;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int typeVersion() const noexcept final {
|
||||
return ox::ModelTypeVersion_v<T>;
|
||||
}
|
||||
|
||||
ox::Result<ox::UAnyPtr> getItem(
|
||||
keel::Context &kctx, ox::StringViewCR name, int const version) noexcept final {
|
||||
if (ox::ModelTypeVersion_v<T> != version || ox::ModelTypeName_v<T> != name) {
|
||||
OX_REQUIRE_M(item, keel::convert(kctx, m_item, name, version));
|
||||
auto out = ox::Result<ox::UAnyPtr>{item->moveToCopy()};
|
||||
ox::safeDelete(item.release());
|
||||
return out;
|
||||
}
|
||||
return ox::UAnyPtr{new T{m_item}};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ItemMaker {
|
||||
private:
|
||||
ox::Vector<ox::UPtr<ItemTemplate>> m_templates;
|
||||
ox::String const m_parentDir;
|
||||
ox::String const m_fileExt;
|
||||
ox::String const m_typeDisplayName;
|
||||
|
||||
public:
|
||||
constexpr ItemMaker(
|
||||
ox::StringParam pName,
|
||||
ox::StringParam pParentDir,
|
||||
ox::StringParam pFileExt) noexcept:
|
||||
typeName{std::move(pName)},
|
||||
parentDir{std::move(pParentDir)},
|
||||
fileExt{std::move(pFileExt)} {
|
||||
m_parentDir{std::move(pParentDir)},
|
||||
m_fileExt{std::move(pFileExt)},
|
||||
m_typeDisplayName{std::move(pName)} {
|
||||
}
|
||||
|
||||
virtual ~ItemMaker() noexcept = default;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ox::String itemPath(ox::StringView pName) const noexcept {
|
||||
return ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
|
||||
ox::String const&typeDisplayName() const noexcept {
|
||||
return m_typeDisplayName;
|
||||
}
|
||||
|
||||
bool installTemplate(ox::UPtr<ItemTemplate> &tmpl) {
|
||||
if (typeName() == tmpl->typeName() &&
|
||||
typeVersion() <= tmpl->typeVersion()) {
|
||||
m_templates.emplace_back(std::move(tmpl));
|
||||
// begin() + 1 because 'Default' should always be first
|
||||
std::sort(m_templates.begin() + 1, m_templates.end());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool installTemplate(ox::UPtr<ItemTemplate> &&tmpl) {
|
||||
return installTemplate(tmpl);
|
||||
}
|
||||
|
||||
constexpr ox::Vector<ox::UPtr<ItemTemplate>> const&itemTemplates() const noexcept {
|
||||
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]]
|
||||
ox::String itemPath(ox::StringViewCR pName) const noexcept {
|
||||
return ox::sfmt("/{}/{}.{}", m_parentDir, pName, m_fileExt);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ox::StringView typeName() const noexcept = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual int typeVersion() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns path of the file created.
|
||||
* @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 pTemplateIdx
|
||||
* @return path of file or error in Result
|
||||
*/
|
||||
virtual ox::Result<ox::String> write(StudioContext &ctx, ox::StringView pName) const noexcept = 0;
|
||||
ox::Error write(
|
||||
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>
|
||||
class ItemMakerT: public ItemMaker {
|
||||
class ItemMakerT final: public ItemMaker {
|
||||
private:
|
||||
T const m_item;
|
||||
ox::ClawFormat const m_fmt;
|
||||
|
||||
public:
|
||||
constexpr ItemMakerT(
|
||||
ox::StringParam pDisplayName,
|
||||
ox::StringParam pParentDir,
|
||||
ox::StringParam fileExt,
|
||||
ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
m_fmt(pFmt) {
|
||||
ox::ClawFormat const pFmt = ox::ClawFormat::Metal) noexcept:
|
||||
ItemMaker(
|
||||
std::move(pDisplayName),
|
||||
std::move(pParentDir),
|
||||
std::move(fileExt)),
|
||||
m_fmt{pFmt} {
|
||||
installTemplate(ox::make_unique<ItemTemplateT<T>>());
|
||||
}
|
||||
|
||||
constexpr ItemMakerT(
|
||||
ox::StringParam pDisplayName,
|
||||
ox::StringParam pParentDir,
|
||||
ox::StringParam fileExt,
|
||||
T pItem,
|
||||
ox::ClawFormat pFmt) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
m_item(std::move(pItem)),
|
||||
m_fmt(pFmt) {
|
||||
T const&pItem,
|
||||
ox::ClawFormat const pFmt) noexcept:
|
||||
ItemMaker(
|
||||
std::move(pDisplayName),
|
||||
std::move(pParentDir),
|
||||
std::move(fileExt)),
|
||||
m_fmt{pFmt} {
|
||||
installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
|
||||
}
|
||||
|
||||
constexpr ItemMakerT(
|
||||
ox::StringParam pDisplayName,
|
||||
ox::StringParam pParentDir,
|
||||
ox::StringParam fileExt,
|
||||
T &&pItem,
|
||||
ox::ClawFormat pFmt) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
m_item(std::move(pItem)),
|
||||
m_fmt(pFmt) {
|
||||
ox::ClawFormat const pFmt) noexcept:
|
||||
ItemMaker(
|
||||
std::move(pDisplayName),
|
||||
std::move(pParentDir),
|
||||
std::move(fileExt)),
|
||||
m_fmt{pFmt} {
|
||||
installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
|
||||
}
|
||||
ox::Result<ox::String> write(studio::StudioContext &sctx, ox::StringView const pName) const noexcept override {
|
||||
auto const path = itemPath(pName);
|
||||
createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
|
||||
OX_RETURN_ERROR(sctx.project->writeObj(path, m_item, m_fmt));
|
||||
return path;
|
||||
|
||||
ox::StringView typeName() const noexcept override {
|
||||
return ox::ModelTypeName_v<T>;
|
||||
}
|
||||
|
||||
int typeVersion() const noexcept override {
|
||||
return ox::ModelTypeVersion_v<T>;
|
||||
}
|
||||
|
||||
ox::Error writeItem(
|
||||
StudioContext &ctx,
|
||||
ox::StringViewCR pPath,
|
||||
size_t const pTemplateIdx) const noexcept override {
|
||||
createUuidMapping(keelCtx(ctx.tctx), pPath, ox::UUID::generate().unwrap());
|
||||
auto const&templates = itemTemplates();
|
||||
auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0;
|
||||
OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem(
|
||||
keelCtx(ctx), typeName(), typeVersion()));
|
||||
auto item = tmpl.template get<T>();
|
||||
OX_RETURN_ERROR(ctx.project->writeObj(pPath, *item, m_fmt));
|
||||
tmpl.free();
|
||||
return {};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -31,6 +31,8 @@ class Module {
|
||||
|
||||
virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::StudioContext&) const;
|
||||
|
||||
virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(studio::StudioContext&) const;
|
||||
|
||||
};
|
||||
|
||||
template<typename Editor>
|
||||
|
@@ -47,7 +47,7 @@ class Popup {
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents);
|
||||
void drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents);
|
||||
|
||||
};
|
||||
|
||||
|
@@ -19,6 +19,7 @@ namespace studio {
|
||||
|
||||
enum class ProjectEvent {
|
||||
None,
|
||||
DirAdded,
|
||||
FileAdded,
|
||||
// FileRecognized is triggered for all matching files upon a new
|
||||
// subscription to a section of the project and upon the addition of a file.
|
||||
@@ -45,7 +46,7 @@ constexpr ox::StringView parentDir(ox::StringView path) noexcept {
|
||||
return substr(path, 0, extStart);
|
||||
}
|
||||
|
||||
class Project {
|
||||
class Project: public ox::SignalHandler {
|
||||
private:
|
||||
ox::SmallMap<ox::String, ox::Optional<ox::ClawFormat>> m_typeFmt;
|
||||
keel::Context &m_ctx;
|
||||
@@ -91,6 +92,8 @@ class Project {
|
||||
|
||||
ox::Result<ox::FileStat> stat(ox::StringViewCR path) const noexcept;
|
||||
|
||||
ox::Error deleteItem(ox::StringViewCR path) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool exists(ox::StringViewCR path) const noexcept;
|
||||
|
||||
@@ -118,6 +121,7 @@ class Project {
|
||||
// signals
|
||||
public:
|
||||
ox::Signal<ox::Error(ProjectEvent, ox::StringViewCR)> fileEvent;
|
||||
ox::Signal<ox::Error(ox::StringViewCR)> dirAdded;
|
||||
ox::Signal<ox::Error(ox::StringViewCR)> fileAdded;
|
||||
// FileRecognized is triggered for all matching files upon a new
|
||||
// subscription to a section of the project and upon the addition of a
|
||||
@@ -175,6 +179,9 @@ ox::Error Project::subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&s
|
||||
switch (e) {
|
||||
case ProjectEvent::None:
|
||||
break;
|
||||
case ProjectEvent::DirAdded:
|
||||
connect(this, &Project::dirAdded, tgt, slot);
|
||||
break;
|
||||
case ProjectEvent::FileAdded:
|
||||
connect(this, &Project::fileAdded, tgt, slot);
|
||||
break;
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <studio/configio.hpp>
|
||||
#include <studio/context.hpp>
|
||||
#include <studio/dragdrop.hpp>
|
||||
#include <studio/editor.hpp>
|
||||
#include <studio/filedialog.hpp>
|
||||
#include <studio/imguiutil.hpp>
|
||||
|
@@ -54,18 +54,22 @@ bool PushButton(ox::CStringViewCR lbl, ImVec2 const&btnSz) noexcept {
|
||||
return ImGui::Button(lbl.c_str(), btnSz);
|
||||
}
|
||||
|
||||
PopupResponse PopupControlsOkCancel(float popupWidth, bool &popupOpen) {
|
||||
PopupResponse PopupControlsOkCancel(
|
||||
float popupWidth,
|
||||
bool &popupOpen,
|
||||
ox::CStringViewCR ok,
|
||||
ox::CStringViewCR cancel) {
|
||||
auto out = PopupResponse::None;
|
||||
constexpr auto btnSz = ImVec2{50, BtnSz.y};
|
||||
ImGui::Separator();
|
||||
ImGui::SetCursorPosX(popupWidth - 118);
|
||||
if (ImGui::Button("OK", btnSz)) {
|
||||
if (ImGui::Button(ok.c_str(), btnSz)) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
popupOpen = false;
|
||||
out = PopupResponse::OK;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button("Cancel", btnSz)) {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button(cancel.c_str(), btnSz)) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
popupOpen = false;
|
||||
out = PopupResponse::Cancel;
|
||||
@@ -73,8 +77,11 @@ PopupResponse PopupControlsOkCancel(float popupWidth, bool &popupOpen) {
|
||||
return out;
|
||||
}
|
||||
|
||||
PopupResponse PopupControlsOkCancel(bool &popupOpen) {
|
||||
return PopupControlsOkCancel(ImGui::GetContentRegionAvail().x + 17, popupOpen);
|
||||
PopupResponse PopupControlsOkCancel(
|
||||
bool &popupOpen,
|
||||
ox::CStringViewCR ok,
|
||||
ox::CStringViewCR cancel) {
|
||||
return PopupControlsOkCancel(ImGui::GetContentRegionAvail().x + 17, popupOpen, ok, cancel);
|
||||
}
|
||||
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const&sz) {
|
||||
@@ -136,11 +143,12 @@ bool FileComboBox(
|
||||
bool ListBox(
|
||||
ox::CStringViewCR name,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
size_t strCnt,
|
||||
size_t &selIdx) noexcept {
|
||||
size_t const strCnt,
|
||||
size_t &selIdx,
|
||||
ImVec2 const&sz) noexcept {
|
||||
auto out = false;
|
||||
if (ImGui::BeginListBox(name.c_str())) {
|
||||
for (auto i = 0u; i < strCnt; ++i) {
|
||||
if (ImGui::BeginListBox(name.c_str(), sz)) {
|
||||
for (size_t i = 0; i < strCnt; ++i) {
|
||||
auto str = f(i);
|
||||
ig::IDStackItem const idStackItem2(static_cast<int>(i));
|
||||
if (ImGui::Selectable(str.c_str(), selIdx == i)) {
|
||||
@@ -161,6 +169,12 @@ bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const&list, size_t
|
||||
}, list.size(), selIdx);
|
||||
}
|
||||
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::CStringView> const&list, size_t &selIdx) noexcept {
|
||||
return ListBox(name, [list](size_t i) -> ox::CStringView {
|
||||
return list[i];
|
||||
}, list.size(), selIdx);
|
||||
}
|
||||
|
||||
|
||||
FilePicker::FilePicker(
|
||||
StudioContext &sctx,
|
||||
|
@@ -6,11 +6,15 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
ox::Vector<EditorMaker> Module::editors(studio::StudioContext&) const {
|
||||
ox::Vector<EditorMaker> Module::editors(StudioContext&) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(studio::StudioContext&) const {
|
||||
ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(StudioContext&) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Vector<ox::UPtr<ItemTemplate>> Module::itemTemplates(StudioContext&) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@@ -7,11 +7,11 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
void Popup::drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents) {
|
||||
void Popup::drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents) {
|
||||
studio::ig::centerNextWindow(ctx);
|
||||
ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
|
||||
constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
if (ImGui::BeginPopupModal(m_title.c_str(), open, modalFlags)) {
|
||||
if (ImGui::BeginPopupModal(m_title.c_str(), &open, modalFlags)) {
|
||||
drawContents();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
@@ -59,16 +59,41 @@ ox::Error Project::mkdir(ox::StringViewCR path) const noexcept {
|
||||
auto const [stat, err] = m_fs.stat(path);
|
||||
if (err) {
|
||||
OX_RETURN_ERROR(m_fs.mkdir(path, true));
|
||||
fileUpdated.emit(path, {});
|
||||
dirAdded.emit(path);
|
||||
}
|
||||
return stat.fileType == ox::FileType::Directory ?
|
||||
ox::Error{} : ox::Error(1, "path exists as normal file");
|
||||
ox::Error{} : ox::Error{1, "path exists as normal file"};
|
||||
}
|
||||
|
||||
ox::Result<ox::FileStat> Project::stat(ox::StringViewCR path) const noexcept {
|
||||
return m_fs.stat(path);
|
||||
}
|
||||
|
||||
ox::Error Project::deleteItem(ox::StringViewCR path) noexcept {
|
||||
OX_REQUIRE(stat, m_fs.stat(path));
|
||||
if (stat.fileType == ox::FileType::Directory) {
|
||||
bool partialRemoval{};
|
||||
OX_REQUIRE(members, m_fs.ls(path));
|
||||
for (auto const&p : members) {
|
||||
partialRemoval = m_fs.remove(ox::sfmt("{}/{}", path, p)) || partialRemoval;
|
||||
}
|
||||
if (partialRemoval) {
|
||||
return ox::Error{1, "failed to remove one or more directory members"};
|
||||
}
|
||||
auto const err = m_fs.remove(path);
|
||||
if (!err) {
|
||||
fileDeleted.emit(path);
|
||||
}
|
||||
return err;
|
||||
} else {
|
||||
auto const err = m_fs.remove(path);
|
||||
if (!err) {
|
||||
fileDeleted.emit(path);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bool Project::exists(ox::StringViewCR path) const noexcept {
|
||||
return m_fs.stat(path).error == 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user