diff --git a/src/CanvasComponents/BrushStrokeCanvasComponent.hpp b/src/CanvasComponents/BrushStrokeCanvasComponent.hpp index bceb305..d91e322 100644 --- a/src/CanvasComponents/BrushStrokeCanvasComponent.hpp +++ b/src/CanvasComponents/BrushStrokeCanvasComponent.hpp @@ -15,7 +15,7 @@ struct BrushStrokeCanvasComponentPoint { class BrushStrokeCanvasComponent : public CanvasComponent { public: - constexpr static float DRAW_MINIMUM_LIMIT = 0.3; + constexpr static float DRAW_MINIMUM_LIMIT = 0.7f; virtual CanvasComponentType get_type() const override; virtual void save(cereal::PortableBinaryOutputArchive& a) const override; diff --git a/src/DrawCamera.cpp b/src/DrawCamera.cpp index 670c330..756d7d5 100755 --- a/src/DrawCamera.cpp +++ b/src/DrawCamera.cpp @@ -110,10 +110,22 @@ void DrawCamera::update_main(World& w) { } } else { - if(w.main.input.key(InputManager::KEY_CAMERA_ROTATE_COUNTERCLOCKWISE).held && !w.main.input.text.is_accepting_input()) + if(w.main.input.key(InputManager::KEY_CAMERA_ROTATE_COUNTERCLOCKWISE).held && !w.main.input.text.is_accepting_input()) { c.rotate_about(c.from_space(w.main.window.size.cast() * 0.5f), -w.main.deltaTime); - if(w.main.input.key(InputManager::KEY_CAMERA_ROTATE_CLOCKWISE).held && !w.main.input.text.is_accepting_input()) + InputManager::MouseMotionCallbackArgs motion{ + .pos = w.main.input.mouse.pos, + .move = {0, 0} + }; + w.drawProg.drawTool->input_mouse_motion_callback(motion); + } + if(w.main.input.key(InputManager::KEY_CAMERA_ROTATE_CLOCKWISE).held && !w.main.input.text.is_accepting_input()) { c.rotate_about(c.from_space(w.main.window.size.cast() * 0.5f), w.main.deltaTime); + InputManager::MouseMotionCallbackArgs motion{ + .pos = w.main.input.mouse.pos, + .move = {0, 0} + }; + w.drawProg.drawTool->input_mouse_motion_callback(motion); + } } set_viewing_area(w.main.window.size.cast()); @@ -127,7 +139,7 @@ void DrawCamera::input_key_callback(const InputManager::KeyCallbackArgs& key) { void DrawCamera::input_mouse_button_on_canvas_callback(World& w, const InputManager::MouseButtonCallbackArgs& button) { if(!smoothMove.occurring) { - bool newIsAccurateZooming = (w.drawProg.controls.middleClickHeld && w.main.input.pen.isDown && w.main.input.pen.buttons[w.main.toolbar.tabletOptions.middleClickButton].held && w.main.toolbar.tabletOptions.zoomWhilePenDownAndButtonHeld) || // Hold middle click (pen button assigned to middle click) while pen is down + bool newIsAccurateZooming = (w.drawProg.controls.middleClickHeld && w.main.input.pen.isDown && w.main.toolbar.tabletOptions.zoomWhilePenDownAndButtonHeld) || // Hold middle click (pen button assigned to middle click) while pen is down (w.drawProg.controls.middleClickHeld && w.main.input.key(InputManager::KEY_GENERIC_LCTRL).held) || // Hold middle click/pen button while holding control (w.drawProg.controls.leftClickHeld && w.drawProg.drawTool->get_type() == DrawingProgramToolType::ZOOM); // Hold left click while on zoom tool if(newIsAccurateZooming && !isAccurateZooming) { diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 3506ad5..2448529 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -53,10 +53,14 @@ void DrawingProgram::on_tab_out() { } void DrawingProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { + auto buttonCallbacks = [&](const InputManager::MouseButtonCallbackArgs& b) { + drawTool->input_mouse_button_on_canvas_callback(b); + }; + bool isHoveringOverCanvas = world.main.toolbar.check_if_position_isnt_obstructed(button.pos); - if(isHoveringOverCanvas) { + if(isHoveringOverCanvas && button.down) { if(button.button == InputManager::MouseButton::RIGHT) { - if(button.down) { + if(!controls.middleClickHeld && !controls.leftClickHeld) { if(world.main.toolbar.rightClickPopupLocation) world.main.toolbar.rightClickPopupLocation = std::nullopt; else @@ -64,18 +68,35 @@ void DrawingProgram::input_mouse_button_callback(const InputManager::MouseButton } } else { - if(button.down) - world.main.toolbar.rightClickPopupLocation = std::nullopt; - if(button.button == InputManager::MouseButton::LEFT) - controls.leftClickHeld = button.down; - else if(button.button == InputManager::MouseButton::MIDDLE) - controls.middleClickHeld = button.down; - drawTool->input_mouse_button_on_canvas_callback(button); - world.drawData.cam.input_mouse_button_on_canvas_callback(world, button); + world.main.toolbar.rightClickPopupLocation = std::nullopt; + if(button.button == InputManager::MouseButton::LEFT && !controls.middleClickHeld) { + controls.leftClickHeld = true; + buttonCallbacks(button); + } + else if(button.button == InputManager::MouseButton::MIDDLE) { + if(controls.leftClickHeld) { + controls.leftClickHeld = false; + InputManager::MouseButtonCallbackArgs leftReleaseCallback; + leftReleaseCallback.clicks = 0; + leftReleaseCallback.down = false; + leftReleaseCallback.pos = button.pos; + leftReleaseCallback.button = InputManager::MouseButton::LEFT; + buttonCallbacks(leftReleaseCallback); + } + controls.middleClickHeld = true; + buttonCallbacks(button); + } } } - else if(!button.down && button.button != InputManager::MouseButton::RIGHT) { - drawTool->input_mouse_button_on_canvas_callback(button); + else if(!button.down) { + if(controls.leftClickHeld && button.button == InputManager::MouseButton::LEFT) { + controls.leftClickHeld = false; + buttonCallbacks(button); + } + else if(controls.middleClickHeld && button.button == InputManager::MouseButton::MIDDLE) { + controls.middleClickHeld = false; + buttonCallbacks(button); + } } if(toolToSwitchToAfterUpdate) { diff --git a/src/DrawingProgram/Tools/BrushTool.cpp b/src/DrawingProgram/Tools/BrushTool.cpp index 46cb474..2b821e3 100644 --- a/src/DrawingProgram/Tools/BrushTool.cpp +++ b/src/DrawingProgram/Tools/BrushTool.cpp @@ -31,6 +31,102 @@ void BrushTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) { objInfoBeingEdited = nullptr; } +void BrushTool::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) { + if(button.button == InputManager::MouseButton::LEFT) { + auto& toolConfig = drawP.world.main.toolConfig; + if(button.down && drawP.layerMan.is_a_layer_being_edited() && !objInfoBeingEdited) { + if(drawP.world.main.input.pen.isDown) { + penWidth = drawP.world.main.input.pen.pressure; + if(penWidth != 0.0f) { + float brushMinSize = drawP.world.main.toolbar.tabletOptions.brushMinimumSize; + penWidth = brushMinSize + penWidth * (1.0f - brushMinSize); + } + } + else + penWidth = 1.0f; + + 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); + return; + } + float width = relativeWidthResult.first.value() * penWidth; + + CanvasComponentContainer* newBrushStrokeContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponentType::BRUSHSTROKE); + BrushStrokeCanvasComponent& newBrushStroke = static_cast(newBrushStrokeContainer->get_comp()); + + BrushStrokeCanvasComponentPoint p; + p.pos = button.pos; + p.width = width; + prevPointUnaltered = p.pos; + newBrushStroke.d.points->emplace_back(p); + newBrushStroke.d.color = toolConfig.globalConf.foregroundColor; + newBrushStroke.d.hasRoundCaps = toolConfig.brush.hasRoundCaps; + newBrushStrokeContainer->coords = drawP.world.drawData.cam.c; + objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newBrushStrokeContainer); + addedTemporaryPoint = false; + } + else if(!button.down && objInfoBeingEdited) + commit_stroke(); + } +} + +void BrushTool::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { + if(objInfoBeingEdited) { + auto& toolConfig = drawP.world.main.toolConfig; + NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; + BrushStrokeCanvasComponent& brushStroke = static_cast(containerPtr->get_comp()); + auto& brushPoints = *brushStroke.d.points; + float width = toolConfig.get_relative_width_stroke_size(drawP, containerPtr->coords.inverseScale).first.value() * penWidth; + + BrushStrokeCanvasComponentPoint p; + p.pos = containerPtr->coords.from_cam_space_to_this(drawP.world, motion.pos); + p.width = width; + + if(!addedTemporaryPoint) { + if(extensive_point_checking(brushStroke, p.pos)) { + brushPoints.emplace_back(p); + addedTemporaryPoint = true; + } + else + brushPoints.back().width = std::max(brushPoints.back().width, p.width); + } + + if(addedTemporaryPoint) { + const BrushStrokeCanvasComponentPoint& prevP = brushPoints[brushPoints.size() - 2]; + float distToPrev = (p.pos - prevP.pos).norm(); + if(extensive_point_checking_back(brushStroke, p.pos)) { + brushPoints.back().pos = p.pos; + brushPoints.back().width = std::max(brushPoints.back().width, p.width); + brushPoints[brushPoints.size() - 2].width = std::max(brushPoints[brushPoints.size() - 2].width, p.width); + } + if((!drawingMinimumRelativeToSize && distToPrev >= 10.0) || (drawingMinimumRelativeToSize && distToPrev >= width * BrushStrokeCanvasComponent::DRAW_MINIMUM_LIMIT)) { + brushPoints.back() = p; + addedTemporaryPoint = false; + + if(midwayInterpolation) { + if(brushPoints.size() != 2) // Don't interpolate the first point + brushPoints[brushPoints.size() - 2].pos = (prevPointUnaltered + p.pos) * 0.5; + prevPointUnaltered = p.pos; + } + } + } + + containerPtr->send_comp_update(drawP, false); + containerPtr->commit_update(drawP); + } +} + +void BrushTool::input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis) { + if(axis.axis == SDL_PEN_AXIS_PRESSURE) { + penWidth = axis.value; + if(penWidth != 0.0f) { + float brushMinSize = drawP.world.main.toolbar.tabletOptions.brushMinimumSize; + penWidth = brushMinSize + penWidth * (1.0f - brushMinSize); + } + } +} + bool BrushTool::extensive_point_checking(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint) { auto& points = *brushStroke.d.points; if(points.size() >= 1 && (newPoint - points[points.size() - 1].pos).norm() < MINIMUM_DISTANCE_TO_NEXT_POINT) @@ -54,111 +150,8 @@ bool BrushTool::extensive_point_checking_back(const BrushStrokeCanvasComponent& } void BrushTool::tool_update() { - auto& toolConfig = drawP.world.main.toolConfig; - if(drawP.controls.cursorHoveringOverCanvas) drawP.world.main.input.hideCursor = true; - - if(!objInfoBeingEdited) - penSmoothingData.clear(); - - if(drawP.world.main.input.pen.isDown && drawP.controls.leftClickHeld && drawP.world.main.toolbar.tabletOptions.pressureAffectsBrushWidth) { - while(!penSmoothingData.empty() && (std::chrono::steady_clock::now() - penSmoothingData.front().t) > std::chrono::milliseconds(static_cast(drawP.world.main.toolbar.tabletOptions.smoothingSamplingTime * 1000.0f))) - penSmoothingData.pop_front(); - penSmoothingData.emplace_back( - drawP.world.main.input.pen.pressure, - std::chrono::steady_clock::now() - ); - float averagePressure = 0.0f; - for(auto& [width, t] : penSmoothingData) - averagePressure += width; - averagePressure /= penSmoothingData.size(); - penWidth = averagePressure; - if(penWidth != 0.0f) { - float brushMinSize = drawP.world.main.toolbar.tabletOptions.brushMinimumSize; - penWidth = brushMinSize + penWidth * (1.0f - brushMinSize); - } - } - else - penWidth = 1.0f; - - bool isPenDown = false; - if(drawP.world.main.input.pen.isDown && drawP.controls.leftClickHeld) - isPenDown = penWidth != 0.0; - else if(drawP.controls.leftClickHeld) - isPenDown = true; - - if(isPenDown) { - if(!objInfoBeingEdited) { - if(drawP.controls.leftClick && drawP.layerMan.is_a_layer_being_edited()) { - 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() * penWidth; - - CanvasComponentContainer* newBrushStrokeContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponentType::BRUSHSTROKE); - BrushStrokeCanvasComponent& newBrushStroke = static_cast(newBrushStrokeContainer->get_comp()); - - BrushStrokeCanvasComponentPoint p; - p.pos = drawP.world.main.input.mouse.pos; - p.width = width; - prevPointUnaltered = p.pos; - newBrushStroke.d.points->emplace_back(p); - newBrushStroke.d.color = toolConfig.globalConf.foregroundColor; - newBrushStroke.d.hasRoundCaps = toolConfig.brush.hasRoundCaps; - newBrushStrokeContainer->coords = drawP.world.drawData.cam.c; - objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newBrushStrokeContainer); - addedTemporaryPoint = false; - } - } - else { - NetworkingObjects::NetObjOwnerPtr& containerPtr = objInfoBeingEdited->obj; - BrushStrokeCanvasComponent& brushStroke = static_cast(containerPtr->get_comp()); - auto& brushPoints = *brushStroke.d.points; - float width = toolConfig.get_relative_width_stroke_size(drawP, containerPtr->coords.inverseScale).first.value() * penWidth; - - BrushStrokeCanvasComponentPoint p; - p.pos = containerPtr->coords.get_mouse_pos(drawP.world); - p.width = width; - - if(!addedTemporaryPoint) { - if(extensive_point_checking(brushStroke, p.pos)) { - brushPoints.emplace_back(p); - addedTemporaryPoint = true; - } - else - brushPoints.back().width = std::max(brushPoints.back().width, p.width); - } - - if(addedTemporaryPoint) { - const BrushStrokeCanvasComponentPoint& prevP = brushPoints[brushPoints.size() - 2]; - float distToPrev = (p.pos - prevP.pos).norm(); - if(extensive_point_checking_back(brushStroke, p.pos)) { - brushPoints.back().pos = p.pos; - brushPoints.back().width = std::max(brushPoints.back().width, p.width); - brushPoints[brushPoints.size() - 2].width = std::max(brushPoints[brushPoints.size() - 2].width, p.width); - } - if((!drawingMinimumRelativeToSize && distToPrev >= 10.0) || (drawingMinimumRelativeToSize && distToPrev >= width * BrushStrokeCanvasComponent::DRAW_MINIMUM_LIMIT)) { - brushPoints.back() = p; - addedTemporaryPoint = false; - - if(midwayInterpolation) { - if(brushPoints.size() != 2) // Don't interpolate the first point - brushPoints[brushPoints.size() - 2].pos = (prevPointUnaltered + p.pos) * 0.5; - prevPointUnaltered = p.pos; - } - } - } - - containerPtr->send_comp_update(drawP, false); - containerPtr->commit_update(drawP); - } - } - else if(objInfoBeingEdited) - commit_stroke(); } void BrushTool::commit_stroke() { diff --git a/src/DrawingProgram/Tools/BrushTool.hpp b/src/DrawingProgram/Tools/BrushTool.hpp index 00c70e6..0d04479 100644 --- a/src/DrawingProgram/Tools/BrushTool.hpp +++ b/src/DrawingProgram/Tools/BrushTool.hpp @@ -24,6 +24,9 @@ class BrushTool : 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; + virtual void input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis) override; private: bool extensive_point_checking_back(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint); bool extensive_point_checking(const BrushStrokeCanvasComponent& brushStroke, const Vector2f& newPoint); @@ -31,13 +34,9 @@ class BrushTool : public DrawingProgramToolBase { float penWidth = 1.0f; bool addedTemporaryPoint = false; - struct SmoothingPoint { - float val; - std::chrono::steady_clock::time_point t; - }; - std::deque penSmoothingData; CanvasComponentContainer::ObjInfo* objInfoBeingEdited = nullptr; + bool drawingMinimumRelativeToSize = true; bool midwayInterpolation = true; Vector2f prevPointUnaltered = {0, 0}; diff --git a/src/DrawingProgram/Tools/EllipseDrawTool.cpp b/src/DrawingProgram/Tools/EllipseDrawTool.cpp index d7181b0..297dc17 100644 --- a/src/DrawingProgram/Tools/EllipseDrawTool.cpp +++ b/src/DrawingProgram/Tools/EllipseDrawTool.cpp @@ -38,8 +38,7 @@ void EllipseDrawTool::input_mouse_button_on_canvas_callback(const InputManager:: 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(); diff --git a/src/World.cpp b/src/World.cpp index 0787f80..7d47fdc 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -267,8 +267,10 @@ void World::input_key_callback(const InputManager::KeyCallbackArgs& key) { } void World::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { - if(!clientStillConnecting) + if(!clientStillConnecting) { drawProg.input_mouse_button_callback(button); + drawData.cam.input_mouse_button_on_canvas_callback(*this, button); + } } void World::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { diff --git a/src/main.cpp b/src/main.cpp index 10a1eec..5f83628 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -790,9 +790,8 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { break; } case SDL_EVENT_PEN_AXIS: { - if(event->paxis.axis == SDL_PEN_AXIS_PRESSURE) - mS.m->input.pen.pressure = event->paxis.value; - //mS.m->input.mouse.set_pos({event->paxis.x, event->paxis.y}); + mS.m->update_scale_and_density(); + mS.m->input.backend_pen_axis_update(event->paxis); break; } case SDL_EVENT_PEN_DOWN: {