From 23e3758ccadbbdbb1643c83d93b92266291943ce Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 9 Feb 2026 09:38:57 -0700 Subject: [PATCH] Step 88: drag-and-drop open --- PROGRESS.md | 3 +++ editor/CMakeLists.txt | 3 +++ editor/src/DragDropHandler.h | 24 ++++++++++++++++++ editor/src/main.cpp | 13 ++++++++++ editor/tests/step88_test.cpp | 49 ++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 editor/src/DragDropHandler.h create mode 100644 editor/tests/step88_test.cpp diff --git a/PROGRESS.md b/PROGRESS.md index 87c86cd..3df8d3d 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -185,6 +185,7 @@ All 38 steps implemented and passing. Each step has a corresponding test (`step1 - [x] Step 85: **IMPLEMENTED** — Filesystem tree with .gitignore filtering, recursive Explorer rendering (1/1 tests pass) - [x] Step 86: **IMPLEMENTED** — Multi-tab editing with BufferManager and per-buffer editor state (3/3 tests pass) - [x] Step 87: **IMPLEMENTED** — Welcome screen wired with recent files persistence and quick actions (2/2 tests pass) +- [x] Step 88: **IMPLEMENTED** — Drag-and-drop file/folder open via SDL_DROPFILE (2/2 tests pass) --- @@ -251,6 +252,7 @@ vcpkg's imgui 1.91.9 removed the `sdl2-binding` feature (only `sdl3-binding` exi **Step 85:** Compile and pass (1/1) **Step 86:** Compile and pass (3/3) **Step 87:** Compile and pass (2/2) +**Step 88:** Compile and pass (2/2) --- @@ -346,3 +348,4 @@ Sprint 4 in progress. Step 76 (LayoutManager) done. Next: Step 77 (custom code e | 2026-02-09 | Codex | Step 85: Filesystem tree with .gitignore filtering and Explorer rendering. 1/1 tests pass. | | 2026-02-09 | Codex | Step 86: Multi-tab editing wired via BufferManager with per-buffer state. 3/3 tests pass. | | 2026-02-09 | Codex | Step 87: Welcome screen wired with recent files persistence and quick actions. 2/2 tests pass. | +| 2026-02-09 | Codex | Step 88: Drag-and-drop open for files and folders. 2/2 tests pass. | diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index f4a0ad2..05664a8 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -496,6 +496,9 @@ target_include_directories(step86_test PRIVATE src) add_executable(step87_test tests/step87_test.cpp) target_include_directories(step87_test PRIVATE src) +add_executable(step88_test tests/step88_test.cpp) +target_include_directories(step88_test PRIVATE src) + find_package(SDL2 CONFIG REQUIRED) find_package(OpenGL REQUIRED) find_package(glad CONFIG REQUIRED) diff --git a/editor/src/DragDropHandler.h b/editor/src/DragDropHandler.h new file mode 100644 index 0000000..871296b --- /dev/null +++ b/editor/src/DragDropHandler.h @@ -0,0 +1,24 @@ +#pragma once +// Step 88: Drag-and-drop handler + +#include +#include +#include + +class DragDropHandler { +public: + using FileCallback = std::function; + using FolderCallback = std::function; + + static void handleDrop(const std::string& path, + const FileCallback& onFile, + const FolderCallback& onFolder) { + if (path.empty()) return; + std::filesystem::path p(path); + if (std::filesystem::is_directory(p)) { + if (onFolder) onFolder(path); + } else { + if (onFile) onFile(path); + } + } +}; diff --git a/editor/src/main.cpp b/editor/src/main.cpp index d736eb2..d221299 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -22,6 +22,7 @@ #include "FileDialog.h" #include "FileTree.h" #include "WelcomeScreen.h" +#include "DragDropHandler.h" #include "ast/Generator.h" #include @@ -624,6 +625,18 @@ int main(int, char**) { event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; + if (event.type == SDL_DROPFILE) { + char* droppedFile = event.drop.file; + if (droppedFile) { + DragDropHandler::handleDrop(droppedFile, + [&](const std::string& p) { state.doOpen(p); }, + [&](const std::string& p) { + state.workspaceRoot = p; + state.fileTreeDirty = true; + }); + SDL_free(droppedFile); + } + } // Handle keyboard shortcuts via KeybindingManager if (event.type == SDL_KEYDOWN && !io.WantTextInput) { diff --git a/editor/tests/step88_test.cpp b/editor/tests/step88_test.cpp new file mode 100644 index 0000000..787087e --- /dev/null +++ b/editor/tests/step88_test.cpp @@ -0,0 +1,49 @@ +// Step 88 TDD Test: Drag-and-drop handler +// +// Tests: +// 1. File drop invokes file callback +// 2. Folder drop invokes folder callback + +#include +#include +#include +#include +#include "DragDropHandler.h" + +int main() { + int passed = 0; + int failed = 0; + + std::filesystem::path root = std::filesystem::current_path() / "tmp_step88"; + std::filesystem::create_directories(root / "dir"); + std::filesystem::path file = root / "file.txt"; + std::ofstream f(file.string()); + f << "x"; + f.close(); + + bool fileCalled = false; + bool folderCalled = false; + + DragDropHandler::handleDrop(file.string(), + [&](const std::string& p){ fileCalled = (p == file.string()); }, + [&](const std::string& p){ folderCalled = (p == (root / "dir").string()); } + ); + assert(fileCalled); + std::cout << "Test 1 PASS: File drop" << std::endl; + ++passed; + + fileCalled = false; + folderCalled = false; + DragDropHandler::handleDrop((root / "dir").string(), + [&](const std::string& p){ fileCalled = (p == file.string()); }, + [&](const std::string& p){ folderCalled = (p == (root / "dir").string()); } + ); + assert(folderCalled); + std::cout << "Test 2 PASS: Folder drop" << std::endl; + ++passed; + + std::filesystem::remove_all(root); + + std::cout << "\n=== Step 88 Results: " << passed << " passed, " << failed << " failed ===" << std::endl; + return failed > 0 ? 1 : 0; +}