From a7030059a4d27a91bc3ebc50f422cca82f8b3431 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Wed, 4 Mar 2026 11:03:05 +0300 Subject: [PATCH] Grid modify tool and drag drop work with events --- src/DrawingProgram/DrawingProgram.cpp | 53 ++++----- src/DrawingProgram/DrawingProgram.hpp | 2 + src/DrawingProgram/Tools/GridModifyTool.cpp | 125 +++++++++++--------- src/DrawingProgram/Tools/GridModifyTool.hpp | 2 + src/InputManager.cpp | 24 +++- src/InputManager.hpp | 16 +-- src/MainProgram.cpp | 34 +++--- src/MainProgram.hpp | 2 + src/World.cpp | 10 ++ src/World.hpp | 2 + src/main.cpp | 10 +- 11 files changed, 166 insertions(+), 114 deletions(-) diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 2448529..f5821f2 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -52,6 +52,31 @@ void DrawingProgram::on_tab_out() { controls.middleClickHeld = false; } +void DrawingProgram::input_drop_file_callback(const InputManager::DropCallbackArgs& drop) { + if(world.main.toolbar.check_if_position_isnt_obstructed(drop.pos) && std::filesystem::is_regular_file(drop.data)) { + #ifdef __EMSCRIPTEN_ + add_file_to_canvas_by_path(drop.data, world.main.input.mouse.pos, true); + #else + add_file_to_canvas_by_path(drop.data, drop.pos, true); + #endif + } +} + +void DrawingProgram::input_drop_text_callback(const InputManager::DropCallbackArgs& drop) { + if(world.main.toolbar.check_if_position_isnt_obstructed(drop.pos) && is_valid_http_url(drop.data)) { + CanvasComponentContainer* newContainer = new CanvasComponentContainer(world.netObjMan, CanvasComponentType::IMAGE); + ImageCanvasComponent& img = static_cast(newContainer->get_comp()); + newContainer->coords = world.drawData.cam.c; + Vector2f imDim = Vector2f{100.0f, 100.0f}; + img.d.p1 = drop.pos - imDim; + img.d.p2 = drop.pos + imDim; + img.d.imageID = {0, 0}; + auto newObjInfo = layerMan.add_component_to_layer_being_edited(newContainer); + layerMan.add_undo_place_component(newObjInfo); + droppedDownloadingFiles.emplace_back(newObjInfo, world.main.window.size.cast(), FileDownloader::download_data_from_url(drop.data)); + } +} + void DrawingProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { auto buttonCallbacks = [&](const InputManager::MouseButtonCallbackArgs& b) { drawTool->input_mouse_button_on_canvas_callback(b); @@ -433,8 +458,6 @@ void DrawingProgram::update() { addFileInNextFrame = false; } - drag_drop_update(); - selection.update(); drawTool->tool_update(); @@ -527,32 +550,6 @@ void DrawingProgram::rebuild_cache() { drawCache.build({}); } -void DrawingProgram::drag_drop_update() { - if(controls.cursorHoveringOverCanvas && layerMan.is_a_layer_being_edited()) { - for(auto& droppedItem : world.main.input.droppedItems) { - if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) { -#ifdef __EMSCRIPTEN_ - add_file_to_canvas_by_path(droppedItem.dataPath.value(), world.main.input.mouse.pos, true); -#else - add_file_to_canvas_by_path(droppedItem.dataPath.value(), droppedItem.pos, true); -#endif - } - else if(droppedItem.dataText.has_value() && is_valid_http_url(droppedItem.dataText.value())) { - CanvasComponentContainer* newContainer = new CanvasComponentContainer(world.netObjMan, CanvasComponentType::IMAGE); - ImageCanvasComponent& img = static_cast(newContainer->get_comp()); - newContainer->coords = world.drawData.cam.c; - Vector2f imDim = Vector2f{100.0f, 100.0f}; - img.d.p1 = droppedItem.pos - imDim; - img.d.p2 = droppedItem.pos + imDim; - img.d.imageID = {0, 0}; - auto newObjInfo = layerMan.add_component_to_layer_being_edited(newContainer); - layerMan.add_undo_place_component(newObjInfo); - droppedDownloadingFiles.emplace_back(newObjInfo, world.main.window.size.cast(), FileDownloader::download_data_from_url(droppedItem.dataText.value())); - } - } - } -} - void DrawingProgram::update_downloading_dropped_files() { std::erase_if(droppedDownloadingFiles, [&](auto& downFile) { switch(downFile.downData->status) { diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index 335ba08..cb22434 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -58,6 +58,8 @@ class DrawingProgram { void send_transforms_for(const std::vector& objsToSendTransformsFor); void on_tab_out(); + void input_drop_text_callback(const InputManager::DropCallbackArgs& drop); + void input_drop_file_callback(const InputManager::DropCallbackArgs& drop); void input_key_callback(const InputManager::KeyCallbackArgs& key); void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); diff --git a/src/DrawingProgram/Tools/GridModifyTool.cpp b/src/DrawingProgram/Tools/GridModifyTool.cpp index bf959da..7c36775 100644 --- a/src/DrawingProgram/Tools/GridModifyTool.cpp +++ b/src/DrawingProgram/Tools/GridModifyTool.cpp @@ -36,6 +36,76 @@ DrawingProgramToolType GridModifyTool::get_type() { void GridModifyTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) { } +void GridModifyTool::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) { + if(button.button == InputManager::MouseButton::LEFT) { + switch(selectionMode) { + case 0: + if(button.down) { + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; + Vector2f gOffsetScreenPos = drawP.world.drawData.cam.c.to_space(g.offset); + Vector2f gSizeScreenPos = drawP.world.drawData.cam.c.to_space(g.offset + WorldVec{g.size, 0}); + if(SCollision::collide(SCollision::Circle(gOffsetScreenPos, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) + selectionMode = 1; + else if(SCollision::collide(SCollision::Circle(gSizeScreenPos, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) + selectionMode = 2; + else if(g.bounds.has_value()) { + const auto& b = g.bounds.value(); + Vector2f bMin = drawP.world.drawData.cam.c.to_space(b.min); + Vector2f bMax = drawP.world.drawData.cam.c.to_space(b.max); + if(SCollision::collide(SCollision::Circle(bMin, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) + selectionMode = 3; + else if(SCollision::collide(SCollision::Circle(bMax, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) + selectionMode = 4; + } + } + } + break; + case 1: + case 2: + case 3: + case 4: + if(!button.down) + selectionMode = 0; + break; + } + } +} + +void GridModifyTool::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { + NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); + if(gLock) { + WorldGrid& g = *gLock; + switch(selectionMode) { + case 0: + break; + case 1: + g.offset = drawP.world.get_mouse_world_pos(); + break; + case 2: + g.size = std::max(FixedPoint::abs(drawP.world.get_mouse_world_pos().x() - g.offset.x()), WorldScalar(1)); + break; + case 3: + if(g.bounds.has_value()) { + auto& b = g.bounds.value(); + b.min = cwise_vec_min(drawP.world.get_mouse_world_pos(), b.max); + } + else + selectionMode = 0; + break; + case 4: + if(g.bounds.has_value()) { + auto& b = g.bounds.value(); + b.max = cwise_vec_max(drawP.world.get_mouse_world_pos(), b.min); + } + else + selectionMode = 0; + break; + } + } +} + void GridModifyTool::gui_toolbox() { Toolbar& t = drawP.world.main.toolbar; t.gui.push_id("Grid modify tool"); @@ -93,60 +163,7 @@ bool GridModifyTool::right_click_popup_gui(Vector2f popupPos) { void GridModifyTool::tool_update() { NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); - if(gLock) { - WorldGrid& g = *gLock; - switch(selectionMode) { - case 0: - if(drawP.controls.leftClick) { - Vector2f gOffsetScreenPos = drawP.world.drawData.cam.c.to_space(g.offset); - Vector2f gSizeScreenPos = drawP.world.drawData.cam.c.to_space(g.offset + WorldVec{g.size, 0}); - if(SCollision::collide(SCollision::Circle(gOffsetScreenPos, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) - selectionMode = 1; - else if(SCollision::collide(SCollision::Circle(gSizeScreenPos, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) - selectionMode = 2; - else if(g.bounds.has_value()) { - const auto& b = g.bounds.value(); - Vector2f bMin = drawP.world.drawData.cam.c.to_space(b.min); - Vector2f bMax = drawP.world.drawData.cam.c.to_space(b.max); - if(SCollision::collide(SCollision::Circle(bMin, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) - selectionMode = 3; - else if(SCollision::collide(SCollision::Circle(bMax, drawP.drag_point_radius()), drawP.world.main.input.mouse.pos)) - selectionMode = 4; - } - } - break; - case 1: - if(drawP.controls.leftClickHeld) - g.offset = drawP.world.get_mouse_world_pos(); - else - selectionMode = 0; - break; - case 2: - if(drawP.controls.leftClickHeld) - g.size = std::max(FixedPoint::abs(drawP.world.get_mouse_world_pos().x() - g.offset.x()), WorldScalar(1)); - else - selectionMode = 0; - break; - case 3: - if(drawP.controls.leftClickHeld && g.bounds.has_value()) { - auto& b = g.bounds.value(); - b.min = cwise_vec_min(drawP.world.get_mouse_world_pos(), b.max); - } - else - selectionMode = 0; - break; - case 4: - if(drawP.controls.leftClickHeld && g.bounds.has_value()) { - auto& b = g.bounds.value(); - b.max = cwise_vec_max(drawP.world.get_mouse_world_pos(), b.min); - } - else - selectionMode = 0; - break; - } - drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, false); - } - else + if(!gLock) selectionMode = 0; } diff --git a/src/DrawingProgram/Tools/GridModifyTool.hpp b/src/DrawingProgram/Tools/GridModifyTool.hpp index e6364e9..18f6bc8 100644 --- a/src/DrawingProgram/Tools/GridModifyTool.hpp +++ b/src/DrawingProgram/Tools/GridModifyTool.hpp @@ -17,6 +17,8 @@ class GridModifyTool : public DrawingProgramToolBase { virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; virtual bool prevent_undo_or_redo() override; virtual void switch_tool(DrawingProgramToolType newTool) override; + virtual void input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) override; + virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; private: WorldGrid oldGrid; NetworkingObjects::NetObjWeakPtr grid; diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 170f9d7..5361fc0 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -368,6 +368,28 @@ uint32_t InputManager::make_generic_key_mod(SDL_Keymod m) { return toRet; } +void InputManager::backend_drop_file_event(const SDL_DropEvent& e) { + Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density}; + mouse.set_pos(mousePos); + + main.input_drop_file_callback({ + .pos = mousePos, + .source = e.source, + .data = e.data + }); +} + +void InputManager::backend_drop_text_event(const SDL_DropEvent& e) { + Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density}; + mouse.set_pos(mousePos); + + main.input_drop_text_callback({ + .pos = mousePos, + .source = e.source, + .data = e.data + }); +} + void InputManager::backend_mouse_button_up_update(const SDL_MouseButtonEvent& e) { Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density}; mouse.set_pos(mousePos); @@ -902,8 +924,6 @@ void InputManager::frame_reset(const Vector2i& windowSize) { mouse.rightClicks = 0; mouse.middleClicks = 0; - droppedItems.clear(); - cursorIcon = SystemCursorType::DEFAULT; for(auto& p : keys) { diff --git a/src/InputManager.hpp b/src/InputManager.hpp index 513f516..15cc826 100644 --- a/src/InputManager.hpp +++ b/src/InputManager.hpp @@ -122,12 +122,6 @@ struct InputManager { friend struct InputManager; } text; - struct DroppedItem { - Vector2f pos; - std::optional dataText; - std::optional dataPath; - }; - #ifdef __APPLE__ SDL_Keymod CTRL_MOD = SDL_KMOD_GUI; #else @@ -137,8 +131,6 @@ struct InputManager { int stopKeyInput = 0; std::optional lastPressedKeybind; - std::vector droppedItems; - void text_input_silence_everything(); enum KeyCodeEnum : unsigned { @@ -213,6 +205,8 @@ struct InputManager { void set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode); void set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode); + void backend_drop_file_event(const SDL_DropEvent& e); + void backend_drop_text_event(const SDL_DropEvent& e); void backend_mouse_button_up_update(const SDL_MouseButtonEvent& e); void backend_mouse_button_down_update(const SDL_MouseButtonEvent& e); void backend_mouse_motion_update(const SDL_MouseMotionEvent& e); @@ -297,6 +291,12 @@ struct InputManager { float value; }; + struct DropCallbackArgs { + Vector2f pos; + const char* source; + const char* data; + }; + MainProgram& main; }; diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index 0657ec5..d9c20f6 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -68,20 +68,6 @@ void MainProgram::update() { while(std::chrono::duration_cast>(std::chrono::steady_clock::now() - lastFrameTime).count() < 1.0 / fpsLimit); lastFrameTime = std::chrono::steady_clock::now(); - std::erase_if(input.droppedItems, [&](auto& droppedItem) { - if(droppedItem.dataPath.has_value() && std::filesystem::is_regular_file(droppedItem.dataPath.value())) { - const std::filesystem::path& droppedFilePath = droppedItem.dataPath.value(); - if(droppedFilePath.has_extension() && droppedFilePath.extension().string() == std::string("." + World::FILE_EXTENSION)) { - new_tab({ - .isClient = false, - .filePathSource = droppedFilePath - }, true); - return true; - } - } - return false; - }); - for(auto& s : setTabsToClose) std::erase(worlds, s.lock()); @@ -310,6 +296,26 @@ sk_sp MainProgram::create_native_surface(Vector2i resolution, bool is return surfaceToRet; } +void MainProgram::input_drop_file_callback(const InputManager::DropCallbackArgs& drop) { + if(std::filesystem::is_regular_file(drop.data)) { + std::filesystem::path droppedFilePath(drop.data); + if(droppedFilePath.has_extension() && droppedFilePath.extension().string() == std::string("." + World::FILE_EXTENSION)) { + new_tab({ + .isClient = false, + .filePathSource = droppedFilePath + }, true); + return; + } + } + if(world) + world->input_drop_file_callback(drop); +} + +void MainProgram::input_drop_text_callback(const InputManager::DropCallbackArgs& drop) { + if(world) + world->input_drop_text_callback(drop); +} + void MainProgram::input_key_callback(const InputManager::KeyCallbackArgs& key) { switch(key.key) { case InputManager::KEY_NOGUI: { diff --git a/src/MainProgram.hpp b/src/MainProgram.hpp index b470dc7..3a2bf02 100644 --- a/src/MainProgram.hpp +++ b/src/MainProgram.hpp @@ -120,6 +120,8 @@ class MainProgram { std::string displayName; + void input_drop_file_callback(const InputManager::DropCallbackArgs& drop); + void input_drop_text_callback(const InputManager::DropCallbackArgs& drop); void input_key_callback(const InputManager::KeyCallbackArgs& key); void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); diff --git a/src/World.cpp b/src/World.cpp index 7d47fdc..a7f2d41 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -247,6 +247,16 @@ void World::on_tab_out() { rMan.clear_display_cache(); } +void World::input_drop_file_callback(const InputManager::DropCallbackArgs& drop) { + if(!clientStillConnecting) + drawProg.input_drop_file_callback(drop); +} + +void World::input_drop_text_callback(const InputManager::DropCallbackArgs& drop) { + if(!clientStillConnecting) + drawProg.input_drop_text_callback(drop); +} + void World::input_key_callback(const InputManager::KeyCallbackArgs& key) { if(!clientStillConnecting) { switch(key.key) { diff --git a/src/World.hpp b/src/World.hpp index ed22aad..22b3dfd 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -101,6 +101,8 @@ class World { std::shared_ptr netServer; std::shared_ptr netClient; + void input_drop_file_callback(const InputManager::DropCallbackArgs& drop); + void input_drop_text_callback(const InputManager::DropCallbackArgs& drop); void input_key_callback(const InputManager::KeyCallbackArgs& key); void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); diff --git a/src/main.cpp b/src/main.cpp index 5f83628..795e76f 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -762,17 +762,11 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { break; case SDL_EVENT_DROP_FILE: mS.m->update_scale_and_density(); - mS.m->input.droppedItems.emplace_back(InputManager::DroppedItem{ - .pos = Vector2f{event->drop.x, event->drop.y} * mS.m->window.density, - .dataPath = std::u8string_view(reinterpret_cast(event->drop.data)) - }); + mS.m->input.backend_drop_file_event(event->drop); break; case SDL_EVENT_DROP_TEXT: mS.m->update_scale_and_density(); - mS.m->input.droppedItems.emplace_back(InputManager::DroppedItem{ - .pos = Vector2f{event->drop.x, event->drop.y} * mS.m->window.density, - .dataText = event->drop.data - }); + mS.m->input.backend_drop_text_event(event->drop); break; case SDL_EVENT_PEN_PROXIMITY_IN: { mS.m->input.pen.inProximity = true;