Merge commit 'c42adc290cd8a27d01bb6d9877032dd2c963a4b7'

This commit is contained in:
2025-02-01 22:55:46 -06:00
35 changed files with 537 additions and 78 deletions

View File

@ -47,17 +47,17 @@ void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept {
}
void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept {
if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) {
if (ImGui::MenuItem("Add Item")) {
addItem.emit(path);
}
if (ImGui::MenuItem("Add Directory")) {
addDir.emit(path);
}
if (ImGui::MenuItem("Delete")) {
if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) {
if (ImGui::MenuItem("Add Item")) {
addItem.emit(path);
}
if (ImGui::MenuItem("Add Directory")) {
addDir.emit(path);
}
if (path.len() && ImGui::MenuItem("Delete")) {
deleteItem.emit(path);
}
ImGui::EndPopup();
ImGui::EndPopup();
}
}

View File

@ -41,18 +41,35 @@ void RenameFile::draw(StudioContext &ctx) noexcept {
case Stage::Opening:
ImGui::OpenPopup(title().c_str());
m_open = true;
m_fileExists = false;
m_stage = Stage::Open;
[[fallthrough]];
case Stage::Open:
setSize({250, 0});
drawWindow(ctx.tctx, m_open, [this] {
drawWindow(ctx.tctx, m_open, [this, &ctx] {
if (ImGui::IsWindowAppearing()) {
ImGui::SetKeyboardFocusHere();
}
ig::InputText("Name", m_name);
ImGui::Text("%s%s", m_path.c_str(), m_name.c_str());
if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK) {
moveFile.emit(m_oldPath, m_path + m_name);
m_fileExists = !ig::InputText("Name", m_name) && m_fileExists;
auto const nameInputFocused = ImGui::IsItemFocused();
if (m_fileExists) {
ImGui::Text("File %s already exists.", m_name.c_str());
} else {
ImGui::Text("%s%s", m_path.c_str(), m_name.c_str());
}
bool b{};
auto const response = ig::PopupControlsOkCancel(b);
if (response == ig::PopupResponse::OK ||
(nameInputFocused && ImGui::IsKeyPressed(ImGuiKey_Enter))) {
auto const newPath = m_path + m_name;
if (!ctx.project->exists(newPath)) {
moveFile.emit(m_oldPath, newPath);
close();
} else {
m_open = true;
m_fileExists = true;
}
} else if (response == ig::PopupResponse::Cancel) {
close();
}
});

View File

@ -21,6 +21,7 @@ class RenameFile: public Popup {
ox::String m_oldPath;
ox::String m_path;
ox::IString<255> m_name;
bool m_fileExists{};
bool m_open{};
public:

View File

@ -349,10 +349,6 @@ void StudioUI::handleKeyInput() noexcept {
m_activeEditorUpdatePending = m_activeEditor;
}
}
if (ImGui::IsKeyPressed(ImGuiKey_0)) {
m_activeEditor = m_editors[10 < m_editors.size() ? 10 : range].get();
m_activeEditorUpdatePending = m_activeEditor;
}
}
}
}
@ -396,6 +392,18 @@ ox::Error StudioUI::handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR ne
return m_projectExplorer.refreshProjectTreeModel();
}
ox::Error StudioUI::handleDeleteFile(ox::StringViewCR path) noexcept {
for (size_t i{}; auto &e : m_editors) {
if (path == e->itemPath()) {
oxLogError(m_editors.erase(i).error);
oxLogError(closeFile(path));
break;
}
++i;
}
return m_projectExplorer.refreshProjectTreeModel();
}
ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
std::error_code ec;
std::filesystem::create_directories(toStdStringView(path), ec);
@ -416,7 +424,7 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
m_newDirDialog.newDir.connect(m_sctx.project, &Project::mkdir);
m_project->dirAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
m_project->fileDeleted.connect(this, &StudioUI::handleDeleteFile);
m_project->fileMoved.connect(this, &StudioUI::handleMoveFile);
m_openFiles.clear();
m_editors.clear();
@ -499,11 +507,15 @@ ox::Error StudioUI::queueFileMove(ox::StringParam src, ox::StringParam dst) noex
void StudioUI::procFileMoves() noexcept {
for (auto const &m : m_queuedMoves) {
oxLogError(m_project->moveItem(m.a, m.b));
if (!m_project->exists(m.b)) {
oxLogError(m_project->moveItem(m.a, m.b));
}
}
m_queuedMoves.clear();
for (auto const &m : m_queuedDirMoves) {
oxLogError(m_project->moveDir(m.a, m.b));
if (!m_project->exists(m.b)) {
oxLogError(m_project->moveDir(m.a, m.b));
}
}
m_queuedDirMoves.clear();
}

View File

@ -104,6 +104,8 @@ class StudioUI: public ox::SignalHandler {
ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept;
ox::Error handleDeleteFile(ox::StringViewCR path) noexcept;
ox::Error createOpenProject(ox::StringViewCR path) noexcept;
ox::Error openProjectPath(ox::StringParam path) noexcept;

View File

@ -88,7 +88,7 @@ FileTreeModel::FileTreeModel(
void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
auto const selected = m_explorer.selected(this) ? ImGuiTreeNodeFlags_Selected : 0;
if (!m_children.empty()) {
if (m_fileType == ox::FileType::Directory) {
auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected);
if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) {
m_explorer.setSelectedNode(this);
@ -104,7 +104,8 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
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);
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 {

View File

@ -64,13 +64,11 @@ PopupResponse PopupControlsOkCancel(
ImGui::Separator();
ImGui::SetCursorPosX(popupWidth - 118);
if (ImGui::Button(ok.c_str(), btnSz)) {
ImGui::CloseCurrentPopup();
popupOpen = false;
out = PopupResponse::OK;
}
ImGui::SameLine();
if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button(cancel.c_str(), btnSz)) {
ImGui::CloseCurrentPopup();
popupOpen = false;
out = PopupResponse::Cancel;
}

View File

@ -46,6 +46,13 @@ static ox::Result<ox::Vector<ox::String>> listAllRecursive(ox::FileSystem &fs, o
return std::move(out);
}
[[nodiscard]]
static constexpr bool isParentOf(ox::StringViewCR parent, ox::StringViewCR child) noexcept {
if (endsWith(child, "/")) {
return beginsWith(child, parent);
}
return beginsWith(sfmt("{}/", child), parent);
}
Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir):
m_kctx(ctx),
@ -99,6 +106,9 @@ ox::Error Project::moveItem(ox::StringViewCR src, ox::StringViewCR dest) noexcep
}
ox::Error Project::moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
if (isParentOf(src, dest)) {
return ox::Error{1, "cannot move parent to a child directory"};
}
OX_REQUIRE(files, listAllRecursive(m_fs, src));
OX_RETURN_ERROR(m_fs.move(src, dest));
fileMoved.emit(src, dest, ox::UUID{});