Squashed 'deps/nostalgia/' changes from 7e3e0461..be518387
be518387 [nostalgia/gfx/studio/tilesheet] Add flip x and flip y functionality 1207dade [studio] Add ability to move directories 109e1898 [studio] Add ability to drag files between directories a24bf7ff [studio] Fix config to update when open file name changes 046834c2 [studio,nostalgia] Update tab name when corresponding file's name changes f840240a [nostalgia/gfx/studio/tilesheeteditor] Rework system for tracking current palette path cfa91d3d [keel,studio] Add ability to rename files f7a7a66a [ox/event] Add Signal::connectionCnt 5145595d [ox/std] Fix HashMap collision handling f01d3033 [ox/std] Fix UPtr compare with nullptr 098c8cb8 [nostalgia/gfx/studio] Make move color commands affect all pages 04ad0f02 [studio] Add drag/drop functions that use model TypeName for name 695e7a45 [nostalgia/gfx/studio/paletteeditor] Change move color mechanism to use drag/drop 7d53028f [studio] Cleanup git-subtree-dir: deps/nostalgia git-subtree-split: be51838775cd37d8c0778378a5d944f8f261830c
This commit is contained in:
@@ -13,10 +13,12 @@ struct FileRef {
|
||||
static constexpr auto TypeName = "net.drinkingtea.studio.FileRef";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
ox::String path;
|
||||
bool isDir{};
|
||||
};
|
||||
|
||||
OX_MODEL_BEGIN(FileRef)
|
||||
OX_MODEL_FIELD(path)
|
||||
OX_MODEL_FIELD(isDir)
|
||||
OX_MODEL_END()
|
||||
|
||||
}
|
||||
|
@@ -119,7 +119,7 @@ class Editor: public studio::BaseEditor {
|
||||
ox::String m_itemName;
|
||||
|
||||
public:
|
||||
Editor(ox::StringParam itemPath) noexcept;
|
||||
Editor(StudioContext &ctx, ox::StringParam itemPath) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
ox::CStringView itemPath() const noexcept final;
|
||||
@@ -143,6 +143,9 @@ class Editor: public studio::BaseEditor {
|
||||
|
||||
private:
|
||||
ox::Error markUnsavedChanges(UndoCommand const*) noexcept;
|
||||
|
||||
ox::Error handleRename(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@@ -45,6 +45,10 @@ class FileExplorer: public ox::SignalHandler {
|
||||
|
||||
virtual void fileDeleted(ox::StringViewCR path) const noexcept;
|
||||
|
||||
virtual void fileMoved(ox::StringViewCR src, ox::StringViewCR dst) const noexcept;
|
||||
|
||||
virtual void dirMoved(ox::StringViewCR src, ox::StringViewCR dst) const noexcept;
|
||||
|
||||
void drawFileContextMenu(ox::CStringViewCR path) const noexcept;
|
||||
|
||||
void drawDirContextMenu(ox::CStringViewCR path) const noexcept;
|
||||
|
@@ -34,19 +34,37 @@ ox::Result<T> getDragDropPayload(ox::CStringViewCR name) noexcept {
|
||||
static_cast<size_t>(payload->DataSize)});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Result<T> getDragDropPayload() noexcept {
|
||||
auto const payload = ImGui::AcceptDragDropPayload(ox::ModelTypeName_v<T>);
|
||||
if (!payload) {
|
||||
return ox::Error(1, "No drag/drop payload");
|
||||
}
|
||||
return ox::readClaw<T>({
|
||||
reinterpret_cast<char const*>(payload->Data),
|
||||
static_cast<size_t>(payload->DataSize)});
|
||||
}
|
||||
|
||||
ox::Error setDragDropPayload(ox::CStringViewCR name, auto const&obj) noexcept {
|
||||
OX_REQUIRE(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||
ImGui::SetDragDropPayload(name.c_str(), buff.data(), buff.size());
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error setDragDropPayload(T const&obj) noexcept {
|
||||
OX_REQUIRE(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||
ImGui::SetDragDropPayload(ox::ModelTypeName_v<T>, buff.data(), buff.size());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
class DragDropSource {
|
||||
private:
|
||||
bool const m_active{};
|
||||
public:
|
||||
DragDropSource() noexcept:
|
||||
m_active(ImGui::BeginDragDropSource()) {
|
||||
DragDropSource(ImGuiDragDropFlags const flags = 0) noexcept:
|
||||
m_active(ImGui::BeginDragDropSource(flags)) {
|
||||
}
|
||||
~DragDropSource() noexcept {
|
||||
if (m_active) {
|
||||
@@ -58,14 +76,14 @@ class DragDropSource {
|
||||
}
|
||||
};
|
||||
|
||||
auto dragDropSource(auto const&cb) noexcept {
|
||||
auto dragDropSource(auto const&cb, ImGuiDragDropFlags const flags = 0) noexcept {
|
||||
if constexpr(ox::is_same_v<decltype(cb()), ox::Error>) {
|
||||
if (ig::DragDropSource const tgt; tgt) [[unlikely]] {
|
||||
if (ig::DragDropSource const tgt{flags}; tgt) [[unlikely]] {
|
||||
return cb();
|
||||
}
|
||||
return ox::Error{};
|
||||
} else {
|
||||
if (ig::DragDropSource const tgt; tgt) [[unlikely]] {
|
||||
if (ig::DragDropSource const tgt{flags}; tgt) [[unlikely]] {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@
|
||||
#include <ox/claw/write.hpp>
|
||||
#include <ox/event/signal.hpp>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/model/descwrite.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
|
||||
@@ -26,6 +25,7 @@ enum class ProjectEvent {
|
||||
FileRecognized,
|
||||
FileDeleted,
|
||||
FileUpdated,
|
||||
FileMoved,
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -49,7 +49,7 @@ constexpr ox::StringView parentDir(ox::StringView path) noexcept {
|
||||
class Project: public ox::SignalHandler {
|
||||
private:
|
||||
ox::SmallMap<ox::String, ox::Optional<ox::ClawFormat>> m_typeFmt;
|
||||
keel::Context &m_ctx;
|
||||
keel::Context &m_kctx;
|
||||
ox::String m_path;
|
||||
ox::String m_projectDataDir;
|
||||
ox::String m_typeDescPath;
|
||||
@@ -92,6 +92,10 @@ class Project: public ox::SignalHandler {
|
||||
|
||||
ox::Result<ox::FileStat> stat(ox::StringViewCR path) const noexcept;
|
||||
|
||||
ox::Error moveItem(ox::StringViewCR src, ox::StringViewCR dest) noexcept;
|
||||
|
||||
ox::Error moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept;
|
||||
|
||||
ox::Error deleteItem(ox::StringViewCR path) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -114,7 +118,7 @@ class Project: public ox::SignalHandler {
|
||||
|
||||
ox::Result<ox::Buffer> loadBuff(ox::StringViewCR path) const noexcept;
|
||||
|
||||
ox::Error lsProcDir(ox::Vector<ox::String> *paths, ox::StringViewCR path) const noexcept;
|
||||
ox::Error lsProcDir(ox::Vector<ox::String> &paths, ox::StringViewCR path) const noexcept;
|
||||
|
||||
ox::Result<ox::Vector<ox::String>> listFiles(ox::StringViewCR path = "") const noexcept;
|
||||
|
||||
@@ -128,7 +132,8 @@ class Project: public ox::SignalHandler {
|
||||
// file.
|
||||
ox::Signal<ox::Error(ox::StringViewCR)> fileRecognized;
|
||||
ox::Signal<ox::Error(ox::StringViewCR)> fileDeleted;
|
||||
ox::Signal<ox::Error(ox::StringView, ox::UUID)> fileUpdated;
|
||||
ox::Signal<ox::Error(ox::StringViewCR path, ox::UUID const&id)> fileUpdated;
|
||||
ox::Signal<ox::Error(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id)> fileMoved;
|
||||
|
||||
};
|
||||
|
||||
@@ -151,8 +156,8 @@ ox::Error Project::writeObj(ox::StringViewCR path, T const&obj, ox::ClawFormat f
|
||||
if (!descExists) {
|
||||
OX_RETURN_ERROR(writeTypeStore());
|
||||
}
|
||||
OX_RETURN_ERROR(keel::reloadAsset(m_ctx, path));
|
||||
OX_REQUIRE(uuid, pathToUuid(m_ctx, path));
|
||||
OX_RETURN_ERROR(keel::reloadAsset(m_kctx, path));
|
||||
OX_REQUIRE(uuid, pathToUuid(m_kctx, path));
|
||||
fileUpdated.emit(path, uuid);
|
||||
return {};
|
||||
}
|
||||
@@ -200,6 +205,9 @@ ox::Error Project::subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&s
|
||||
case ProjectEvent::FileUpdated:
|
||||
connect(this, &Project::fileUpdated, tgt, slot);
|
||||
break;
|
||||
case ProjectEvent::FileMoved:
|
||||
connect(this, &Project::fileMoved, tgt, slot);
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@@ -107,10 +107,11 @@ UndoStack *BaseEditor::undoStack() noexcept {
|
||||
}
|
||||
|
||||
|
||||
Editor::Editor(ox::StringParam itemPath) noexcept:
|
||||
Editor::Editor(StudioContext &ctx, ox::StringParam itemPath) noexcept:
|
||||
m_itemPath(std::move(itemPath)),
|
||||
m_itemName(m_itemPath.substr(std::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset() + 1)) {
|
||||
m_undoStack.changeTriggered.connect(this, &Editor::markUnsavedChanges);
|
||||
ctx.project->fileMoved.connect(this, &Editor::handleRename);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -136,4 +137,12 @@ ox::Error Editor::markUnsavedChanges(UndoCommand const*) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error Editor::handleRename(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&) noexcept {
|
||||
if (m_itemPath == oldPath) {
|
||||
m_itemPath = newPath;
|
||||
m_itemName = m_itemPath.substr(std::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset() + 1);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -41,6 +41,10 @@ void FileExplorer::fileOpened(ox::StringViewCR) const noexcept {}
|
||||
|
||||
void FileExplorer::fileDeleted(ox::StringViewCR) const noexcept {}
|
||||
|
||||
void FileExplorer::fileMoved(ox::StringViewCR, ox::StringViewCR) const noexcept {}
|
||||
|
||||
void FileExplorer::dirMoved(ox::StringViewCR, ox::StringViewCR) const noexcept {}
|
||||
|
||||
void FileExplorer::drawFileContextMenu(ox::CStringViewCR path) const noexcept {
|
||||
ig::IDStackItem const idStackItem{path};
|
||||
fileContextMenu(path);
|
||||
@@ -91,6 +95,23 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
||||
}
|
||||
ig::IDStackItem const idStackItem{m_name};
|
||||
m_explorer.drawDirContextMenu(m_fullPath);
|
||||
if (m_explorer.fileDraggable()) {
|
||||
std::ignore = ig::dragDropSource([this] {
|
||||
ImGui::Text("%s", m_name.c_str());
|
||||
return ig::setDragDropPayload("FileRef", FileRef{ox::String{m_fullPath}, true});
|
||||
});
|
||||
}
|
||||
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
||||
auto const [ref, err] = ig::getDragDropPayload<FileRef>("FileRef");
|
||||
if (!err) {
|
||||
auto const name = substr(ref.path, find(ref.path.rbegin(), ref.path.rend(), '/').offset() + 1);
|
||||
if (ref.isDir) {
|
||||
m_explorer.dirMoved(ref.path, sfmt("{}/{}", m_fullPath, name));
|
||||
} else {
|
||||
m_explorer.fileMoved(ref.path, sfmt("{}/{}", m_fullPath, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeOpen) {
|
||||
for (auto const&child : m_children) {
|
||||
child->draw(tctx);
|
||||
|
@@ -26,16 +26,37 @@ static void generateTypes(ox::TypeStore &ts) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
static ox::Result<ox::Vector<ox::String>> listAllRecursive(ox::FileSystem &fs, ox::StringViewCR path) {
|
||||
// there really isn't much recourse if this function fails, just log it and move on
|
||||
auto [out, outErr] = fs.ls(path);
|
||||
oxLogError(outErr);
|
||||
for (auto const &p : out) {
|
||||
auto const [stat, statErr] = fs.stat(path);
|
||||
if (statErr) {
|
||||
oxLogError(statErr);
|
||||
continue;
|
||||
}
|
||||
if (stat.fileType == ox::FileType::Directory) {
|
||||
OX_REQUIRE_M(l, listAllRecursive(fs, sfmt("{}/{}", path, p)));
|
||||
for (auto &c : l) {
|
||||
out.emplace_back(std::move(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::move(out);
|
||||
}
|
||||
|
||||
|
||||
Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir):
|
||||
m_ctx(ctx),
|
||||
m_kctx(ctx),
|
||||
m_path(std::move(path)),
|
||||
m_projectDataDir(projectDataDir),
|
||||
m_typeDescPath(ox::sfmt("/{}/type_descriptors", m_projectDataDir)),
|
||||
m_typeStore(*m_ctx.rom, ox::sfmt("/{}/type_descriptors", projectDataDir)),
|
||||
m_fs(*m_ctx.rom) {
|
||||
m_typeStore(*m_kctx.rom, ox::sfmt("/{}/type_descriptors", projectDataDir)),
|
||||
m_fs(*m_kctx.rom) {
|
||||
oxTracef("studio", "Project: {}", m_path);
|
||||
generateTypes(m_typeStore);
|
||||
if (ox::defines::Debug) {
|
||||
if constexpr(ox::defines::Debug) {
|
||||
OX_THROW_ERROR(writeTypeStore());
|
||||
}
|
||||
buildFileIndex();
|
||||
@@ -69,6 +90,29 @@ ox::Result<ox::FileStat> Project::stat(ox::StringViewCR path) const noexcept {
|
||||
return m_fs.stat(path);
|
||||
}
|
||||
|
||||
ox::Error Project::moveItem(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
|
||||
OX_RETURN_ERROR(m_fs.move(src, dest));
|
||||
OX_RETURN_ERROR(keel::updatePath(m_kctx, src, dest));
|
||||
OX_REQUIRE(uuid, keel::pathToUuid(m_kctx, dest));
|
||||
fileMoved.emit(src, dest, uuid);
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error Project::moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
|
||||
OX_REQUIRE(files, listAllRecursive(m_fs, src));
|
||||
OX_RETURN_ERROR(m_fs.move(src, dest));
|
||||
fileMoved.emit(src, dest, ox::UUID{});
|
||||
for (auto const &op : files) {
|
||||
auto const name =
|
||||
substr(op, ox::find(op.rbegin(), op.rend(), '/').offset() + 1);
|
||||
auto const np = sfmt("{}/{}", dest, name);
|
||||
OX_RETURN_ERROR(keel::updatePath(m_kctx, op, np));
|
||||
OX_REQUIRE(uuid, keel::pathToUuid(m_kctx, dest));
|
||||
fileMoved.emit(src, dest, uuid);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error Project::deleteItem(ox::StringViewCR path) noexcept {
|
||||
OX_REQUIRE(stat, m_fs.stat(path));
|
||||
if (stat.fileType == ox::FileType::Directory) {
|
||||
@@ -142,7 +186,7 @@ ox::Error Project::writeBuff(ox::StringViewCR path, ox::BufferView const&buff) n
|
||||
ox::Buffer outBuff;
|
||||
outBuff.reserve(buff.size() + HdrSz);
|
||||
ox::BufferWriter writer(&outBuff);
|
||||
auto const [uuid, err] = pathToUuid(m_ctx, path);
|
||||
auto const [uuid, err] = pathToUuid(m_kctx, path);
|
||||
if (!err) {
|
||||
OX_RETURN_ERROR(keel::writeUuidHeader(writer, uuid));
|
||||
}
|
||||
@@ -162,14 +206,14 @@ ox::Result<ox::Buffer> Project::loadBuff(ox::StringViewCR path) const noexcept {
|
||||
return m_fs.read(path);
|
||||
}
|
||||
|
||||
ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, ox::StringViewCR path) const noexcept {
|
||||
ox::Error Project::lsProcDir(ox::Vector<ox::String> &paths, ox::StringViewCR path) const noexcept {
|
||||
OX_REQUIRE(files, m_fs.ls(path));
|
||||
for (auto const&name : files) {
|
||||
auto fullPath = ox::sfmt("{}/{}", path, name);
|
||||
OX_REQUIRE(stat, m_fs.stat(ox::StringView(fullPath)));
|
||||
switch (stat.fileType) {
|
||||
case ox::FileType::NormalFile:
|
||||
paths->emplace_back(std::move(fullPath));
|
||||
paths.emplace_back(std::move(fullPath));
|
||||
break;
|
||||
case ox::FileType::Directory:
|
||||
OX_RETURN_ERROR(lsProcDir(paths, fullPath));
|
||||
@@ -183,7 +227,7 @@ ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, ox::StringViewCR pat
|
||||
|
||||
ox::Result<ox::Vector<ox::String>> Project::listFiles(ox::StringViewCR path) const noexcept {
|
||||
ox::Vector<ox::String> paths;
|
||||
OX_RETURN_ERROR(lsProcDir(&paths, path));
|
||||
OX_RETURN_ERROR(lsProcDir(paths, path));
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user