From 6ebdc0bb5fdf8f92daf2e0b6f07611367df213b5 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Sun, 1 Feb 2026 13:11:24 -0500 Subject: [PATCH] sch: keep labels on line when dragging sheets/pins This is not a perfect fix, but the more invasive fix probably needs to wait until after v10 is released. Fixes: https://gitlab.com/kicad/code/kicad/-/issues/20321 --- eeschema/tools/sch_move_tool.cpp | 76 +++++++++++++++++++++++++++----- eeschema/tools/sch_move_tool.h | 2 + 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp index 13ea57d741..a593561d1c 100644 --- a/eeschema/tools/sch_move_tool.cpp +++ b/eeschema/tools/sch_move_tool.cpp @@ -22,6 +22,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include @@ -1508,6 +1509,62 @@ void SCH_MOVE_TOOL::performItemMove( SCH_SELECTION& aSelection, const VECTOR2I& lineEnd.first->SetEndPoint( pin->GetPosition() ); } } + + // Needed to keep labels attached to a line when dragging a sheet/wire combo with a label + // on the line. The label moves by splitDelta for each part of the split move, but the + // line endpoints may not follow splitDelta due to orthogonal drag or sheet pin constraints, + // which can put the label off the line. + for( const auto& [label, info] : m_specialCaseLabels ) + { + if( !label || !info.attachedLine ) + continue; + + VECTOR2I start = info.attachedLine->GetStartPoint(); + VECTOR2I end = info.attachedLine->GetEndPoint(); + VECTOR2I deltaStart = start - info.originalLineStart; + VECTOR2I deltaEnd = end - info.originalLineEnd; + + // TODO: this could be improved by positioning the label based on the new line geometry, + // including line angle changes, grid snapping, and line length changes when orthogonal + // bends are involved. + // + // For now, special casing the equal delta case and using splitDelta should work in most + // cases as the user would expect. + if( deltaStart == deltaEnd ) + { + label->SetPosition( info.originalLabelPos + deltaStart ); + } + else + { + label->Move( splitDelta ); + + // If the line shrank while dragging, keep the label on the line, + // otherwise the label can drift off the end of the line, and change connectivity + if( !info.attachedLine->HitTest( label->GetPosition(), 1 ) && info.attachedLine->IsOrthogonal() ) + { + VECTOR2I pos = label->GetPosition(); + + if( start.x == end.x ) + { + int minY = std::min( start.y, end.y ); + int maxY = std::max( start.y, end.y ); + pos.x = start.x; + pos.y = std::clamp( pos.y, minY, maxY ); + } + else if( start.y == end.y ) + { + int minX = std::min( start.x, end.x ); + int maxX = std::max( start.x, end.x ); + pos.y = start.y; + pos.x = std::clamp( pos.x, minX, maxX ); + } + + label->SetPosition( pos ); + } + } + + updateItem( label, false ); + } } if( aSelection.HasReferencePoint() ) @@ -2227,8 +2284,8 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec break; } - // Since only one end is going to move, the movement vector of any labels attached to - // it is scaled by the proportion of the line length the label is from the moving end. + // When only one end moves, keep attached labels tracking the moving end so they stay + // connected to the line. for( SCH_ITEM* item : items.Overlapping( line->GetBoundingBox() ) ) { SCH_LABEL_BASE* label = dynamic_cast( item ); @@ -2247,6 +2304,8 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec SPECIAL_CASE_LABEL_INFO info; info.attachedLine = line; info.originalLabelPos = label->GetPosition(); + info.originalLineStart = line->GetStartPoint(); + info.originalLineEnd = line->GetEndPoint(); m_specialCaseLabels[label] = info; } } @@ -2336,6 +2395,8 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec SPECIAL_CASE_LABEL_INFO info; info.attachedLine = line; info.originalLabelPos = label->GetPosition(); + info.originalLineStart = line->GetStartPoint(); + info.originalLineEnd = line->GetEndPoint(); m_specialCaseLabels[label] = info; } } @@ -2460,17 +2521,8 @@ void SCH_MOVE_TOOL::moveItem( EDA_ITEM* aItem, const VECTOR2I& aDelta ) case SCH_HIER_LABEL_T: { SCH_LABEL_BASE* label = static_cast( aItem ); - - if( m_specialCaseLabels.count( label ) ) - { - SPECIAL_CASE_LABEL_INFO info = m_specialCaseLabels[ label ]; - SEG currentLine( info.attachedLine->GetStartPoint(), info.attachedLine->GetEndPoint() ); - label->SetPosition( currentLine.NearestPoint( info.originalLabelPos ) ); - } - else - { + if( !m_specialCaseLabels.count( label ) ) label->Move( aDelta ); - } break; } diff --git a/eeschema/tools/sch_move_tool.h b/eeschema/tools/sch_move_tool.h index 61b42ec2df..bed54b7617 100644 --- a/eeschema/tools/sch_move_tool.h +++ b/eeschema/tools/sch_move_tool.h @@ -50,6 +50,8 @@ struct SPECIAL_CASE_LABEL_INFO { SCH_LINE* attachedLine; VECTOR2I originalLabelPos; + VECTOR2I originalLineStart; + VECTOR2I originalLineEnd; };