diff --git a/src/DrawingProgram/Tools/EraserTool.cpp b/src/DrawingProgram/Tools/EraserTool.cpp index 374ba6e..72bac0b 100644 --- a/src/DrawingProgram/Tools/EraserTool.cpp +++ b/src/DrawingProgram/Tools/EraserTool.cpp @@ -31,64 +31,78 @@ bool EraserTool::right_click_popup_gui(Vector2f popupPos) { return true; } +void EraserTool::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) { + if(button.button == InputManager::MouseButton::LEFT) { + if(button.down && !isErasing) { + isErasing = true; + erase_between_points(button.pos, button.pos); + } + else if(!button.down && isErasing) + switch_tool(get_type()); + } +} + +void EraserTool::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { + if(isErasing) + erase_between_points(motion.pos, motion.pos - motion.move); +} + +void EraserTool::erase_between_points(const Vector2f& start, const Vector2f& end) { + auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale); + if(!relativeWidthResult.first.has_value()) { + drawP.world.main.toolConfig.print_relative_width_fail_message(relativeWidthResult.second); + isErasing = false; + return; + } + float width = relativeWidthResult.first.value() * 0.5f; + + SCollision::ColliderCollection cC; + SCollision::generate_wide_line(cC, start, end, width * 2.0f, true); + auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); + + drawP.drawCache.traverse_bvh_run_function(cCWorld.bounds, [&](const auto& bvhNode) { + if(bvhNode && + SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) && + SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) && + SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) && + SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) { + drawP.drawCache.invalidate_cache_at_aabb(bvhNode->bounds); + drawP.drawCache.traverse_bvh_run_function_starting_at_node_no_collision_check(bvhNode, [&](const auto& bvhNodeChild) { + drawP.drawCache.node_loop_erase_if_components(bvhNodeChild, [&](auto c) { + if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) { + erasedComponents.emplace(c); + return true; + } + return false; + }); + return true; + }); + return false; + } + drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto c) { + if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { + erasedComponents.emplace(c); + drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); + return true; + } + return false; + }); + return true; + }); +} + void EraserTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) { erasedComponents.erase(erasedComp); } void EraserTool::switch_tool(DrawingProgramToolType newTool) { drawP.layerMan.erase_component_container(erasedComponents); + isErasing = false; } void EraserTool::tool_update() { if(drawP.controls.cursorHoveringOverCanvas) drawP.world.main.input.hideCursor = true; - - if(drawP.controls.leftClickHeld) { - auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale); - if(!relativeWidthResult.first.has_value()) { - if(drawP.controls.leftClick) - drawP.world.main.toolConfig.print_relative_width_fail_message(relativeWidthResult.second); - return; - } - float width = relativeWidthResult.first.value() * 0.5f; - - const Vector2f& prevMousePos = drawP.controls.leftClick ? drawP.world.main.input.mouse.pos : drawP.world.main.input.mouse.lastPos; - SCollision::ColliderCollection cC; - SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, width * 2.0f, true); - auto cCWorld = drawP.world.drawData.cam.c.collider_to_world, SCollision::ColliderCollection>(cC); - - drawP.drawCache.traverse_bvh_run_function(cCWorld.bounds, [&](const auto& bvhNode) { - if(bvhNode && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.max)) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.top_right())) && - SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.bottom_left()))) { - drawP.drawCache.invalidate_cache_at_aabb(bvhNode->bounds); - drawP.drawCache.traverse_bvh_run_function_starting_at_node_no_collision_check(bvhNode, [&](const auto& bvhNodeChild) { - drawP.drawCache.node_loop_erase_if_components(bvhNodeChild, [&](auto c) { - if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) { - erasedComponents.emplace(c); - return true; - } - return false; - }); - return true; - }); - return false; - } - drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto c) { - if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { - erasedComponents.emplace(c); - drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); - return true; - } - return false; - }); - return true; - }); - } - else - switch_tool(get_type()); } bool EraserTool::prevent_undo_or_redo() { @@ -97,6 +111,10 @@ bool EraserTool::prevent_undo_or_redo() { void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) { if(drawData.main->world->drawProg.controls.cursorHoveringOverCanvas) { + if(!lastPosOpt.has_value()) + lastPosOpt = drawData.main->input.mouse.pos; + auto& lastPos = lastPosOpt.value(); + auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale); if(relativeWidthResult.first.has_value()) { float width = relativeWidthResult.first.value() * 0.5f; @@ -109,9 +127,13 @@ void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) { linePaint.setStrokeCap(SkPaint::kRound_Cap); linePaint.setStrokeWidth(width * 2.0f); SkPathBuilder erasePath; - erasePath.moveTo(convert_vec2(drawData.main->input.mouse.lastPos)); + erasePath.moveTo(convert_vec2(lastPos)); erasePath.lineTo(convert_vec2(drawData.main->input.mouse.pos)); canvas->drawPath(erasePath.detach(), linePaint); } + + lastPos = drawData.main->input.mouse.pos; } + else + lastPosOpt = std::nullopt; } diff --git a/src/DrawingProgram/Tools/EraserTool.hpp b/src/DrawingProgram/Tools/EraserTool.hpp index 54995ec..2f683f7 100644 --- a/src/DrawingProgram/Tools/EraserTool.hpp +++ b/src/DrawingProgram/Tools/EraserTool.hpp @@ -17,6 +17,12 @@ class EraserTool : public DrawingProgramToolBase { virtual void switch_tool(DrawingProgramToolType newTool) override; virtual void draw(SkCanvas* canvas, const DrawData& drawData) override; virtual bool prevent_undo_or_redo() 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; std::unordered_set erasedComponents; // Pointers will be erased from this set if theyre erased in the main list (done by callback) + private: + void erase_between_points(const Vector2f& start, const Vector2f& end); + std::optional lastPosOpt; + bool isErasing = false; }; diff --git a/src/DrawingProgram/Tools/LineDrawTool.cpp b/src/DrawingProgram/Tools/LineDrawTool.cpp index 9c2cadd..fcc8954 100644 --- a/src/DrawingProgram/Tools/LineDrawTool.cpp +++ b/src/DrawingProgram/Tools/LineDrawTool.cpp @@ -32,8 +32,7 @@ void LineDrawTool::input_mouse_button_on_canvas_callback(const InputManager::Mou if(button.down && drawP.layerMan.is_a_layer_being_edited() && !objInfoBeingEdited) { auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale); if(!relativeWidthResult.first.has_value()) { - if(drawP.controls.leftClick) - drawP.world.main.toolConfig.print_relative_width_fail_message(relativeWidthResult.second); + drawP.world.main.toolConfig.print_relative_width_fail_message(relativeWidthResult.second); return; } float width = relativeWidthResult.first.value();