diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index 18565d4abc..ae67feea78 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -573,11 +573,15 @@ int DRAWING_TOOL::DrawBezier( const TOOL_EVENT& aEvent ) if( aEvent.HasPosition() ) startingPoint = aEvent.Position(); - bool cancelled = false; - while( !cancelled ) + DRAW_ONE_RESULT result = DRAW_ONE_RESULT::ACCEPTED; + while( result != DRAW_ONE_RESULT::CANCELLED ) { std::unique_ptr bezier = - drawOneBezier( aEvent, startingPoint, startingC1, cancelled ); + drawOneBezier( aEvent, startingPoint, startingC1, result ); + + // Anyting other than accepted means no chaining + startingPoint = std::nullopt; + startingC1 = std::nullopt; // If a bezier was created, add it and go again if( bezier ) @@ -586,18 +590,21 @@ int DRAWING_TOOL::DrawBezier( const TOOL_EVENT& aEvent ) commit.Add( bezier.release() ); commit.Push( _( "Draw Bezier" ) ); - startingPoint = bezierRef.GetEnd(); + // Don't chain if reset (or accepted and reset) + if( result == DRAW_ONE_RESULT::ACCEPTED ) + { + startingPoint = bezierRef.GetEnd(); - // Mirror the control point across the starting point to get - // a tangent control point - startingC1 = *startingPoint - ( bezierRef.GetBezierC2() - *startingPoint ); - } - else - { - // If the bezier was cancelled, we're done - // But if it was just reset, start again with a free starting point - startingPoint = std::nullopt; - startingC1 = std::nullopt; + // If the last bezier has a zero C2 control arm, allow the user to + // define a new C1 control arm for the next one. + if( bezierRef.GetEnd() != bezierRef.GetBezierC2() ) + { + // Mirror the control point across the end point to get + // a tangent control point + startingC1 = + bezierRef.GetEnd() - ( bezierRef.GetBezierC2() - bezierRef.GetEnd() ); + } + } } } @@ -2848,7 +2855,7 @@ static void updateBezierFromConstructionMgr( const KIGFX::PREVIEW::BEZIER_GEOM_M std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aTool, const OPT_VECTOR2I& aStartingPoint, const OPT_VECTOR2I& aStartingControl1Point, - bool& aCancelled ) + DRAW_ONE_RESULT& aResult ) { std::unique_ptr bezier = std::make_unique( m_frame->GetModel() ); bezier->SetShape( SHAPE_T::BEZIER ); @@ -2898,7 +2905,8 @@ std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo { return bezierManager.GetStep() > KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_START; }; - aCancelled = false; + + aResult = DRAW_ONE_RESULT::ACCEPTED; bool priming = false; m_toolMgr->PostAction( ACTIONS::refreshPreview ); @@ -2907,6 +2915,7 @@ std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo if( aStartingPoint ) { priming = true; + if( aStartingControl1Point ) { bezierManager.AddPoint( *aStartingPoint, true ); @@ -2946,13 +2955,13 @@ std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo // We've handled the cancel event. Don't cancel other tools evt->SetPassEvent( false ); m_frame->PopTool( aTool ); - aCancelled = true; + aResult = DRAW_ONE_RESULT::CANCELLED; } else { // We're not cancelling, but we're also not returning a finished bezier // So we'll be called again. - aCancelled = false; + aResult = DRAW_ONE_RESULT::RESET; } break; @@ -2967,18 +2976,18 @@ std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo { resetProgress(); // leave ourselves on the stack so we come back after the move - aCancelled = true; + aResult = DRAW_ONE_RESULT::CANCELLED; break; } else { resetProgress(); m_frame->PopTool( aTool ); - aCancelled = true; + aResult = DRAW_ONE_RESULT::CANCELLED; break; } } - else if( evt->IsClick( BUT_LEFT ) ) + else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) { if( !started() ) { @@ -3006,10 +3015,29 @@ std::unique_ptr DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo else priming = false; + const bool doubleClick = evt->IsDblClick( BUT_LEFT ); + + if( doubleClick ) + { + // Use the current point for all remaining points + while( bezierManager.GetStep() < KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) + { + bezierManager.AddPoint( cursorPos, true ); + } + } + if( bezierManager.GetStep() == KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) { preview.Add( bezier.get() ); } + + // Return to the caller for a reset + if( doubleClick ) + { + // Don't chain to this one + aResult = DRAW_ONE_RESULT::ACCEPTED_AND_RESET; + break; + } } else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) ) { diff --git a/pcbnew/tools/drawing_tool.h b/pcbnew/tools/drawing_tool.h index e93c8a79df..3fc7fb8e3d 100644 --- a/pcbnew/tools/drawing_tool.h +++ b/pcbnew/tools/drawing_tool.h @@ -240,6 +240,21 @@ public: void UpdateStatusBar() const; private: + enum class DRAW_ONE_RESULT + { + // The drawing was accepted "normally" + // E.g. for a poly-line, you might then begin a chained next segment + ACCEPTED, + // The drawing was cancelled with no shape accepted. + CANCELLED, + // The drawing was reset - no shape was accepted this time, + // but the tool remains active. + RESET, + // A shape was accepted, but the tool should reset for the + // next one (e.g. no chaining) + ACCEPTED_AND_RESET, + }; + /** * Start drawing a selected shape (i.e. PCB_SHAPE). * @@ -282,7 +297,8 @@ private: std::unique_ptr drawOneBezier( const TOOL_EVENT& aTool, const OPT_VECTOR2I& aStartingPoint, const OPT_VECTOR2I& aStartingControl1Point, - bool& aCancelled ); + DRAW_ONE_RESULT& aResult ); + /** * Draw a polygon, that is added as a zone or a keepout area.