65using namespace std::placeholders;
67#include <wx/hyperlink.h>
80 m_selectionTool( nullptr ),
90 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( getEditFrame<PCB_BASE_EDIT_FRAME>() );
96 auto menu = std::make_shared<CONDITIONAL_MENU>( aTool );
99 menu->SetTitle(
_(
"Positioning Tools" ) );
101 auto notMovingCondition = [](
const SELECTION& aSelection )
103 return aSelection.Empty() || !aSelection.Front()->IsMoving();
118 auto menu = std::make_shared<CONDITIONAL_MENU>( aTool );
120 menu->SetTitle(
_(
"Shape Modification" ) );
135 auto hasCornerCondition =
143 auto hasMidpointCondition =
185 auto propertiesCondition =
188 if( aSel.GetSize() == 0 )
202 if( aSel.GetSize() == 1 )
214 auto inFootprintEditor =
235 auto multipleFootprintsCondition =
238 bool foundFirst =
false;
254 auto noActiveToolCondition =
260 auto notMovingCondition =
263 return aSelection.Empty() || !aSelection.Front()->IsMoving();
266 auto noItemsCondition =
267 [ this ](
const SELECTION& aSelections ) ->
bool
284 static std::vector<KICAD_T> unroutableTypes = {
PCB_TRACE_T,
290 static std::vector<KICAD_T> trackTypes = {
PCB_TRACE_T,
299 && notMovingCondition );
302 && notMovingCondition
303 && !inFootprintEditor );
305 && notMovingCondition );
327 && !inFootprintEditor );
371 FOOTPRINT* fp = getEditFrame<PCB_BASE_FRAME>()->GetFootprintFromBoardByReference();
462 std::vector<PCB_TRACK*> tracks;
463 std::vector<PCB_TRACK*> vias;
467 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
469 if( track->Type() == PCB_VIA_T )
470 vias.push_back( track );
472 tracks.push_back( track );
481 if( tracks.size() == 2 && vias.size() == 0 )
483 if( connected( tracks[0], tracks[1]->GetStart() )
484 || connected( tracks[0], tracks[1]->GetEnd() ) )
486 aCollector.
Remove( tracks[1] );
489 else if( tracks.size() == 2 && vias.size() == 1 )
491 if( connected( tracks[0], vias[0]->GetPosition() )
492 && connected( tracks[1], vias[0]->GetPosition() ) )
494 aCollector.
Remove( tracks[0] );
495 aCollector.
Remove( tracks[1] );
501 if( selection.Empty() )
504 if( selection.Size() == 1 && selection.Front()->Type() ==
PCB_ARC_T )
508 return DragArcTrack( aEvent );
512 invokeInlineRouter( mode );
531 wxString msg = wxString::Format(
_(
"Unable to resize arc tracks of %s or greater." ),
546 bool restore_state =
false;
560 tanStart.
A = *tanIntersect;
562 tanEnd.
A = *tanIntersect;
565 std::set<PCB_TRACK*> addedTracks;
567 auto getUniqueTrackAtAnchorCollinear =
573 int allowedDeviation = theArc->
GetWidth();
575 std::vector<BOARD_CONNECTED_ITEM*> itemsOnAnchor;
577 for(
int i = 0; i < 3; i++ )
579 itemsOnAnchor = conn->GetConnectedItemsAtAnchor( theArc, aAnchor,
583 allowedDeviation /= 2;
585 if( itemsOnAnchor.size() == 1 )
591 if( itemsOnAnchor.size() == 1 && itemsOnAnchor.front()->Type() ==
PCB_TRACE_T )
593 track =
static_cast<PCB_TRACK*
>( itemsOnAnchor.front() );
599 if( trackSeg.
Angle( aCollinearSeg ) > maxTangentDeviation )
614 addedTracks.insert( track );
620 PCB_TRACK* trackOnStart = getUniqueTrackAtAnchorCollinear( theArc->
GetStart(), tanStart);
621 PCB_TRACK* trackOnEnd = getUniqueTrackAtAnchorCollinear( theArc->
GetEnd(), tanEnd );
626 tanStart.
B = trackOnStart->
GetEnd();
632 tanEnd.
B = trackOnEnd->
GetEnd();
636 if( tanIntersect = tanStart.
IntersectLines( tanEnd ); !tanIntersect )
639 auto isTrackStartClosestToArcStart =
645 return trackStartToArcStart < trackEndToArcStart;
648 bool isStartTrackOnStartPt = isTrackStartClosestToArcStart( trackOnStart );
649 bool isEndTrackOnStartPt = isTrackStartClosestToArcStart( trackOnEnd );
678 auto getFurthestPointToTanInterstect =
681 if( ( aPointA - *tanIntersect ).EuclideanNorm()
693 VECTOR2I tanStartPoint = getFurthestPointToTanInterstect( tanStart.
A, tanStart.
B );
694 VECTOR2I tanEndPoint = getFurthestPointToTanInterstect( tanEnd.
A, tanEnd.
B );
695 VECTOR2I tempTangentPoint = tanEndPoint;
697 if( getFurthestPointToTanInterstect( tanStartPoint, tanEndPoint ) == tanEndPoint )
698 tempTangentPoint = tanStartPoint;
704 SEG cSegTanStart( maxTanPtStart, *tanIntersect );
705 SEG cSegTanEnd( maxTanPtEnd, *tanIntersect );
706 SEG cSegChord( maxTanPtStart, maxTanPtEnd );
708 int cSegTanStartSide = cSegTanStart.
Side( theArc->
GetMid() );
709 int cSegTanEndSide = cSegTanEnd.
Side( theArc->
GetMid() );
710 int cSegChordSide = cSegChord.
Side( theArc->
GetMid() );
712 bool eatFirstMouseUp =
true;
724 std::vector<VECTOR2I> possiblePoints;
731 for(
const VECTOR2I& candidate : possiblePoints )
733 if( ( candidate -
m_cursor ).SquaredEuclideanNorm()
734 < ( closest -
m_cursor ).SquaredEuclideanNorm() )
763 if( isStartTrackOnStartPt )
766 trackOnStart->
SetEnd( newStart );
768 if( isEndTrackOnStartPt )
771 trackOnEnd->
SetEnd( newEnd );
779 if( evt->IsMotion() || evt->IsDrag(
BUT_LEFT ) )
781 eatFirstMouseUp =
false;
783 else if( evt->IsCancelInteractive() || evt->IsActivate() )
785 restore_state =
true;
790 restore_state =
true;
799 eatFirstMouseUp =
false;
811 if( isStartTrackOnStartPt )
812 newStart = trackOnStart->
GetEnd();
814 if( isEndTrackOnStartPt )
815 newEnd = trackOnEnd->
GetEnd();
820 if( trackOnStart->
GetLength() <= maxLengthIU )
822 if( addedTracks.count( trackOnStart ) )
825 addedTracks.erase( trackOnStart );
830 commit.
Remove( trackOnStart );
836 if( trackOnEnd->
GetLength() <= maxLengthIU )
838 if( addedTracks.count( trackOnEnd ) )
841 addedTracks.erase( trackOnEnd );
846 commit.
Remove( trackOnEnd );
865 commit.
Push(
_(
"Drag Arc Track" ) );
877 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
879 BOARD_ITEM* item = aCollector[ i ];
881 if( !dynamic_cast<PCB_TRACK*>( item ) )
882 aCollector.Remove( item );
900 if(
via->GetViaType() == VIATYPE::MICROVIA )
913 via->SetDrill( new_drill );
914 via->SetWidth( new_width );
929 commit.
Push(
_(
"Edit track width/via size" ) );
946 static int filletRadius = 0;
952 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
954 BOARD_ITEM* item = aCollector[i];
956 if( !dynamic_cast<PCB_TRACK*>( item ) )
957 aCollector.Remove( item );
962 if( selection.
Size() < 2 )
971 if( dlg.ShowModal() == wxID_CANCEL )
976 if( filletRadius == 0 )
979 "The fillet operation was not performed." ) );
992 std::vector<FILLET_OP> filletOperations;
993 bool operationPerformedOnAtLeastOne =
false;
994 bool didOneAttemptFail =
false;
995 std::set<PCB_TRACK*> processedTracks;
997 auto processFilletOp =
998 [&](
PCB_TRACK* aTrack,
bool aStartPoint )
1002 std::vector<BOARD_CONNECTED_ITEM*> itemsOnAnchor;
1004 itemsOnAnchor = c->GetConnectedItemsAtAnchor( aTrack,
anchor,
1008 if( itemsOnAnchor.size() > 0
1009 && selection.
Contains( itemsOnAnchor.at( 0 ) )
1015 if( processedTracks.find( trackOther ) == processedTracks.end() )
1017 if( itemsOnAnchor.size() == 1 )
1020 filletOp.t1 = aTrack;
1021 filletOp.t2 = trackOther;
1022 filletOp.t1Start = aStartPoint;
1023 filletOp.t2Start = aTrack->
IsPointOnEnds( filletOp.t2->GetStart() );
1024 filletOperations.push_back( filletOp );
1030 didOneAttemptFail =
true;
1044 processFilletOp( track,
true );
1045 processFilletOp( track,
false );
1047 processedTracks.insert( track );
1053 std::vector<BOARD_ITEM*> itemsToAddToSelection;
1055 for( FILLET_OP filletOp : filletOperations )
1063 if( trackOnStart && trackOnEnd )
1066 if( ( trackOnStart || trackOnEnd ) && track1->
GetLayer() == track2->
GetLayer() )
1074 SHAPE_ARC sArc( t1Seg, t2Seg, filletRadius );
1077 auto setIfPointOnSeg =
1080 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
1085 aPointToSet.
x = aVecToTest.x;
1086 aPointToSet.
y = aVecToTest.y;
1094 if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.
GetP0() )
1095 && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.
GetP0() ) )
1097 didOneAttemptFail =
true;
1101 if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.
GetP1() )
1102 && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.
GetP1() ) )
1104 didOneAttemptFail =
true;
1114 itemsToAddToSelection.push_back( tArc );
1119 if( filletOp.t1Start )
1122 track1->
SetEnd( t1newPoint );
1124 if( filletOp.t2Start )
1127 track2->
SetEnd( t2newPoint );
1129 operationPerformedOnAtLeastOne =
true;
1133 commit.
Push(
_(
"Fillet Tracks" ) );
1136 for(
BOARD_ITEM* item : itemsToAddToSelection )
1139 if( !operationPerformedOnAtLeastOne )
1141 else if( didOneAttemptFail )
1158 static int filletRadius = 0;
1163 if( dlg.ShowModal() == wxID_CANCEL )
1164 return std::nullopt;
1168 if( filletRadius == 0 )
1170 aErrorMsg =
_(
"A radius of zero was entered.\n"
1171 "The fillet operation was not performed." );
1172 return std::nullopt;
1175 return filletRadius;
1187 wxString& aErrorMsg )
1192 static CHAMFER_PARAMS params{ default_setback, default_setback };
1195 params.m_chamfer_setback_a );
1197 if( dlg.ShowModal() == wxID_CANCEL )
1198 return std::nullopt;
1200 params.m_chamfer_setback_a = dlg.
GetValue();
1203 params.m_chamfer_setback_b = params.m_chamfer_setback_a;
1206 if( params.m_chamfer_setback_a == 0 )
1208 aErrorMsg =
_(
"A setback of zero was entered.\n"
1209 "The chamfer operation was not performed." );
1210 return std::nullopt;
1221 std::vector<VECTOR2I> pts;
1224 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
1226 BOARD_ITEM* item = aCollector[i];
1230 if( !item->IsType( { PCB_SHAPE_LOCATE_SEGMENT_T,
1231 PCB_SHAPE_LOCATE_POLY_T,
1232 PCB_SHAPE_LOCATE_RECT_T } ) )
1234 aCollector.
Remove( item );
1240 std::set<PCB_SHAPE*> lines_to_add;
1241 std::vector<PCB_SHAPE*> items_to_remove;
1245 std::vector<VECTOR2I> pts;
1252 items_to_remove.push_back( graphic );
1255 pts.emplace_back( start );
1256 pts.emplace_back(
VECTOR2I( end.x, start.y ) );
1257 pts.emplace_back( end );
1258 pts.emplace_back(
VECTOR2I( start.x, end.y ) );
1263 items_to_remove.push_back( graphic );
1265 for(
int jj = 0; jj < graphic->
GetPolyShape().VertexCount(); ++jj )
1269 for(
size_t jj = 1; jj < pts.size(); ++jj )
1277 lines_to_add.insert( line );
1280 if( pts.size() > 1 )
1285 line->
SetEnd( pts.front() );
1288 lines_to_add.insert( line );
1293 selection.Add( item );
1295 for(
PCB_SHAPE* item : items_to_remove )
1296 selection.Remove( item );
1300 frame()->ShowInfoBarMsg(
_(
"A shape with least two lines must be selected." ) );
1308 std::vector<PCB_SHAPE*> items_to_select_on_success;
1311 std::vector<PCB_SHAPE*> items_to_deselect_on_success;
1316 const auto item_modification_handler = [&](
PCB_SHAPE& aItem )
1322 items_to_select_on_success.push_back( &aItem );
1326 bool any_items_created = !lines_to_add.empty();
1327 const auto item_creation_handler = [&]( std::unique_ptr<PCB_SHAPE> aItem )
1329 any_items_created =
true;
1330 items_to_select_on_success.push_back( aItem.get() );
1331 commit.
Add( aItem.release() );
1334 bool any_items_removed = !items_to_remove.empty();
1335 const auto item_removal_handler = [&](
PCB_SHAPE& aItem )
1337 any_items_removed =
true;
1338 items_to_deselect_on_success.push_back( &aItem );
1344 item_creation_handler, item_modification_handler, item_removal_handler );
1347 std::unique_ptr<PAIRWISE_LINE_ROUTINE> pairwise_line_routine;
1348 wxString error_message;
1352 const std::optional<int> filletRadiusIU =
GetFilletParams( *frame(), error_message );
1354 if( filletRadiusIU.has_value() )
1356 pairwise_line_routine = std::make_unique<LINE_FILLET_ROUTINE>(
1357 frame()->
GetModel(), change_handler, *filletRadiusIU );
1362 const std::optional<CHAMFER_PARAMS> chamfer_params =
1365 if( chamfer_params.has_value() )
1367 pairwise_line_routine = std::make_unique<LINE_CHAMFER_ROUTINE>(
1368 frame()->
GetModel(), change_handler, *chamfer_params );
1375 error_message =
_(
"Exactly two lines must be selected to extend them." );
1379 pairwise_line_routine =
1380 std::make_unique<LINE_EXTENSION_ROUTINE>( frame()->
GetModel(), change_handler );
1384 if( !pairwise_line_routine )
1387 if( !error_message.empty() )
1388 frame()->ShowInfoBarMsg( error_message );
1397 PCB_SHAPE* line_a = static_cast<PCB_SHAPE*>( a );
1398 PCB_SHAPE* line_b = static_cast<PCB_SHAPE*>( b );
1400 pairwise_line_routine->ProcessLinePair( *line_a, *line_b );
1408 m_selectionTool->AddItemToSel( item,
true );
1413 for(
PCB_SHAPE* item : items_to_remove )
1415 commit.Remove( item );
1416 m_selectionTool->RemoveItemFromSel( item,
true );
1420 for(
PCB_SHAPE* item : items_to_select_on_success )
1421 m_selectionTool->AddItemToSel( item,
true );
1424 for(
PCB_SHAPE* item : items_to_deselect_on_success )
1425 m_selectionTool->RemoveItemFromSel( item,
true );
1427 if( any_items_removed )
1430 if( any_items_created )
1436 commit.Push( pairwise_line_routine->GetCommitDescription() );
1438 if (
const std::optional<wxString> msg = pairwise_line_routine->GetStatusMessage()) {
1439 frame()->ShowInfoBarMsg( *msg );
1451 std::vector<VECTOR2I> pts;
1454 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
1456 BOARD_ITEM* item = aCollector[i];
1460 if( !item->IsType( { PCB_SHAPE_LOCATE_SEGMENT_T, PCB_SHAPE_LOCATE_ARC_T,
1461 PCB_SHAPE_LOCATE_BEZIER_T } ) )
1463 aCollector.
Remove( item );
1475 if( dlg.ShowModal() == wxID_CANCEL )
1478 s_toleranceValue = dlg.GetValue();
1480 if( s_toleranceValue <= 0 )
1485 std::vector<PCB_SHAPE*> shapeList;
1486 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1492 shapeList.push_back( shape );
1499 std::vector<PCB_SHAPE*> items_to_select;
1501 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1505 commit.Add( shape );
1506 items_to_select.push_back( shape );
1509 commit.Push(
_(
"Heal shapes" ) );
1512 for(
PCB_SHAPE* item : items_to_select )
1513 m_selectionTool->AddItemToSel( item,
true );
1515 if( items_to_select.size() > 0 )
1531 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
1533 BOARD_ITEM* item = aCollector[i];
1535 if( !item->IsType( {
1536 PCB_SHAPE_LOCATE_POLY_T,
1537 PCB_SHAPE_LOCATE_RECT_T,
1540 aCollector.
Remove( item );
1546 const EDA_ITEM*
const last_item = selection.GetLastAddedItem();
1549 std::vector<PCB_SHAPE*> items_to_process;
1552 items_to_process.push_back(
static_cast<PCB_SHAPE*
>( item ) );
1557 if( item == last_item )
1559 std::swap( items_to_process.back(), items_to_process.front() );
1566 const auto item_modification_handler = [&](
PCB_SHAPE& aItem )
1571 std::vector<PCB_SHAPE*> items_to_select_on_success;
1572 const auto item_creation_handler = [&]( std::unique_ptr<PCB_SHAPE> aItem )
1574 items_to_select_on_success.push_back( aItem.get() );
1575 commit.
Add( aItem.release() );
1578 const auto item_removal_handler = [&](
PCB_SHAPE& aItem )
1585 item_creation_handler, item_modification_handler, item_removal_handler );
1588 std::unique_ptr<POLYGON_BOOLEAN_ROUTINE> boolean_routine;
1592 std::make_unique<POLYGON_MERGE_ROUTINE>( frame()->
GetModel(), change_handler );
1597 std::make_unique<POLYGON_SUBTRACT_ROUTINE>( frame()->
GetModel(), change_handler );
1602 std::make_unique<POLYGON_INTERSECT_ROUTINE>( frame()->
GetModel(), change_handler );
1606 wxASSERT_MSG(
false,
"Could not find a polygon routine for this action" );
1611 for(
PCB_SHAPE* shape : items_to_process )
1613 boolean_routine->ProcessShape( *shape );
1617 for(
PCB_SHAPE* item : items_to_select_on_success )
1619 m_selectionTool->AddItemToSel( item,
true );
1625 commit.Push( boolean_routine->GetCommitDescription() );
1627 if(
const std::optional<wxString> msg = boolean_routine->GetStatusMessage() )
1629 frame()->ShowInfoBarMsg( *msg );
1650 else if( selection.
Size() == 1 )
1684 for(
EDA_ITEM* eda_item : selCopy )
1688 if( !( item->GetLayerSet() & visible ).any() )
1711 commit = &localCommit;
1725 if( selection.
Empty() )
1728 std::optional<VECTOR2I> oldRefPt;
1729 bool is_hover = selection.
IsHover();
1750 if( selection.
Empty() )
1753 if( selection.
Size() == 1 )
1766 if(
frame()->GetCanvas()->GetView()->GetGAL()->IsFlippedX() )
1767 rotateAngle = -rotateAngle;
1773 viewBBox.
Merge( item->ViewBBox() );
1782 typedef std::numeric_limits<int> coord_limits;
1787 bool outOfBounds = rotPos.
x < min || rotPos.
x > max || rotPos.
y < min || rotPos.
y > max
1788 || rotEnd.
x < min || rotEnd.
x > max || rotEnd.
y < min || rotEnd.
y > max;
1794 if( !item->IsNew() && !item->IsMoving() )
1799 board_item->Rotate( refPt, rotateAngle );
1800 board_item->Normalize();
1804 if( !localCommit.
Empty() )
1805 localCommit.
Push(
_(
"Rotate" ) );
1834 mirrored.
x -= aMirrorPoint.
x;
1835 mirrored.
x = -mirrored.
x;
1836 mirrored.
x += aMirrorPoint.
x;
1849 mirrored.
y -= aMirrorPoint.
y;
1850 mirrored.
y = -mirrored.
y;
1851 mirrored.
y += aMirrorPoint.
y;
1927 commit = &localCommit;
1938 if( selection.
Empty() )
1947 bool mirrorLeftRight =
true;
1948 bool mirrorAroundXaxis =
false;
1952 mirrorLeftRight =
false;
1953 mirrorAroundXaxis =
true;
1961 if( !item->IsNew() && !item->IsMoving() )
1965 switch( item->Type() )
1968 static_cast<PCB_SHAPE*
>( item )->
Mirror( mirrorPoint, mirrorAroundXaxis );
1972 static_cast<ZONE*
>( item )->
Mirror( mirrorPoint, mirrorLeftRight );
1977 static_cast<PCB_TEXT*
>( item )->
Mirror( mirrorPoint, mirrorAroundXaxis );
1985 if( mirrorLeftRight )
1995 static_cast<PCB_TRACK*
>( item )->
Mirror( mirrorPoint, mirrorAroundXaxis );
2006 if( !localCommit.
Empty() )
2007 localCommit.
Push(
_(
"Mirror" ) );
2033 commit = &localCommit;
2044 if( selection.
Empty() )
2047 std::optional<VECTOR2I> oldRefPt;
2059 if( selection.
GetSize() == 1 )
2068 if( !boardItem->IsNew() && !boardItem->IsMoving() )
2069 commit->
Modify( boardItem );
2071 boardItem->Flip( refPt, leftRight );
2072 boardItem->Normalize();
2076 if( !localCommit.
Empty() )
2077 localCommit.
Push(
_(
"Change Side / Flip" ) );
2108 wxCHECK2( board_item,
continue );
2114 commit.
Modify( parentGroup );
2115 parentGroup->RemoveItem( board_item );
2118 switch( item->Type() )
2121 wxASSERT( parentFP );
2122 commit.
Modify( parentFP );
2123 static_cast<PCB_TEXT*
>( board_item )->SetVisible(
false );
2138 commit.
Remove( board_item );
2144 commit.
Modify( parentFP );
2146 parentFP->
Remove( board_item );
2155 if( !aIsCut && aItems.
GetSize() == 1 )
2158 ZONE* zone =
static_cast<ZONE*
>( board_item );
2160 int outlineIdx, holeIdx;
2183 commit.
Remove( board_item );
2187 if( aItems.
Size() == 1 )
2196 commit.
Remove( board_item );
2202 wxASSERT_MSG( parentFP ==
nullptr, wxT(
"Try to delete an item living in a footrprint" ) );
2203 commit.
Remove( board_item );
2211 if( enteredGroup && enteredGroup->
GetItems().empty() )
2215 commit.
Push(
_(
"Cut" ) );
2217 commit.
Push(
_(
"Delete" ) );
2227 std::vector<BOARD_ITEM*> lockedItems;
2310 if( selection.
Empty() )
2322 int ret = dialog.ShowModal();
2324 if( ret == wxID_OK )
2332 selCenter += translation;
2334 if( !
frame()->GetPcbNewSettings()->m_Display.m_DisplayInvertYAxis )
2335 rotation = -rotation;
2341 wxCHECK2( boardItem,
continue );
2343 if( !boardItem->
IsNew() )
2344 commit.
Modify( boardItem );
2347 boardItem->
Move( translation );
2349 switch( rotationAnchor )
2357 boardItem->
Rotate(
frame()->GetScreen()->m_LocalOrigin, angle );
2360 boardItem->
Rotate(
board()->GetDesignSettings().GetAuxOrigin(), angle );
2368 commit.
Push(
_(
"Move exact" ) );
2370 if( selection.IsHover() )
2402 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
2404 BOARD_ITEM* item = aCollector[i];
2406 if( item->Type() == PCB_GENERATOR_T )
2411 aCollector.Remove( item );
2416 if( selection.Empty() )
2424 bool is_hover = selection.IsHover();
2426 std::vector<BOARD_ITEM*> new_items;
2427 new_items.reserve( selection.Size() );
2436 wxCHECK2( orig_item,
continue );
2438 if( m_isFootprintEditor )
2450 static_cast<PAD*
>( dupe_item )->SetNumber( padNumber );
2460 switch( orig_item->
Type() )
2482 dupe_item =
static_cast<PCB_GROUP*
>( orig_item )->DeepDuplicate();
2486 wxASSERT_MSG(
false, wxString::Format( wxT(
"Unhandled item type %d" ),
2487 orig_item->
Type() ) );
2498 new_items.push_back( dupe_item );
2499 commit.Add( dupe_item );
2507 EDA_ITEMS nItems( new_items.begin(), new_items.end() );
2511 if( !selection.Empty() )
2513 editFrame->
DisplayToolMsg( wxString::Format(
_(
"Duplicated %d item(s)" ),
2514 (
int) new_items.size() ) );
2517 if( doMoveSelection( aEvent, &commit ) )
2518 commit.Push(
_(
"Duplicate" ) );
2547 if( selection.
Empty() )
2562 for(
int i = aCollector.
GetCount() - 1; i >= 0; i-- )
2564 if( aCollector[i]->Type() !=
PCB_PAD_T )
2573 for(
int i = aCollector.
GetCount() - 1; i >= 0; i-- )
2587 if( aSelection.
Empty() )
2591 if( aSelection.
Size() == 1 )
2608 const wxString& aCanceledMessage,
VECTOR2I& aReferencePoint )
2611 std::optional<VECTOR2I> pickedPoint;
2620 [&](
const VECTOR2D& aPoint ) ->
bool
2622 pickedPoint = aPoint;
2624 if( !aSuccessMessage.empty() )
2646 if( !aCanceledMessage.empty() )
2658 [&](
const int& aFinalState )
2673 evt->SetPassEvent();
2683 aReferencePoint = *pickedPoint;
2685 return pickedPoint.has_value();
2693 getEditFrame<PCB_BASE_EDIT_FRAME>()->GetMagneticItemsSettings() );
2695 "pcbnew.InteractiveEdit.selectReferencePoint",
2696 TOOL_ACTION_SCOPE::AS_GLOBAL );
2704 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
2706 BOARD_ITEM* item = aCollector[i];
2710 if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
2711 && aCollector.HasItem( item->GetParentFootprint() ) )
2713 aCollector.Remove( item );
2719 aEvent.IsAction( &
ACTIONS::cut ) && !m_isFootprintEditor );
2721 if( !selection.Empty() )
2723 std::vector<BOARD_ITEM*> items;
2728 items.push_back( boardItem );
2735 if( !pickReferencePoint(
_(
"Select reference point for the copy..." ),
2736 _(
"Selection copied" ),
2737 _(
"Copy canceled" ),
2740 frame()->PopTool( selectReferencePoint );
2746 refPoint =
grid.BestDragOrigin( getViewControls()->GetCursorPosition(), items );
2749 selection.SetReferencePoint( refPoint );
2751 io.SetBoard( board() );
2752 io.SaveSelection( selection, m_isFootprintEditor );
2753 frame()->SetStatusText(
_(
"Selection copied" ) );
2756 frame()->PopTool( selectReferencePoint );
2758 if( selection.IsHover() )
2759 m_selectionTool->ClearSelection();
constexpr EDA_IU_SCALE pcbIUScale
static TOOL_ACTION pickerSubTool
static TOOL_ACTION unselectAll
static TOOL_ACTION pasteSpecial
static TOOL_ACTION pageSettings
static TOOL_ACTION duplicate
static TOOL_ACTION doDelete
static TOOL_ACTION cursorClick
static TOOL_ACTION selectAll
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
virtual void Revert() override
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
int GetCurrentViaSize() const
int GetCurrentTrackWidth() const
int GetCurrentViaDrill() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLocked(bool aLocked)
PCB_GROUP * GetParentGroup() const
virtual void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle)
Rotate this object.
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
FOOTPRINT * GetParentFootprint() const
virtual bool IsLocked() const
BOARD_ITEM_CONTAINER * GetParent() const
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
const Vec & GetPosition() const
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Represent basic circle geometry with utility geometry functions.
VECTOR2I Center
Public to make access simpler.
int Radius
Public to make access simpler.
CIRCLE & ConstructFromTanTanPt(const SEG &aLineA, const SEG &aLineB, const VECTOR2I &aP)
Construct this circle such that it is tangent to the given segments and passes through the given poin...
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute the point on the circumference of the circle that is the closest to aP.
int GetCount() const
Return the number of objects in the list.
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
bool Empty() const
Returns status of an item.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
bool HitTestDrawingSheetItems(KIGFX::VIEW *aView, const VECTOR2I &aPosition)
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
void DisplayToolMsg(const wxString &msg) override
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
virtual VECTOR2I GetPosition() const
void SetFlags(EDA_ITEM_FLAGS aMask)
KICAD_T Type() const
Returns the type of object.
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
SHAPE_POLY_SET & GetPolyShape()
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
void SetEnd(const VECTOR2I &aEnd)
void SetWidth(int aWidth)
static const TOOL_EVENT SelectedEvent
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
static const TOOL_EVENT UnselectedEvent
Used when the right click button is pressed, or when the select tool is in effect.
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
A handler that is based on a set of callbacks provided by the user of the ITEM_MODIFICATION_ROUTINE.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
LSET is a set of PCB_LAYER_IDs.
A collection of nets and the parameters used to route or test these nets.
int GetuViaDiameter() const
bool CanHaveNumber() const
Indicates whether or not the pad can have a number.
void FlipPrimitives(bool aFlipLeftRight)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
VECTOR2I GetPosition() const override
void SetOffset(const VECTOR2I &aOffset)
const VECTOR2I & GetOffset() const
void SetDelta(const VECTOR2I &aSize)
void SetPosition(const VECTOR2I &aPos) override
const VECTOR2I & GetDelta() const
PAD_SHAPE GetShape() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
static TOOL_ACTION drag45Degree
static TOOL_ACTION duplicateIncrement
Activation of the duplication tool with incrementing (e.g. pad number)
static TOOL_ACTION changeTrackWidth
Update selected tracks & vias to the current track & via dimensions.
static TOOL_ACTION unrouteSelected
Removes all tracks from the selected items to the first pad.
static TOOL_ACTION mirrorH
Mirroring of selected items.
static TOOL_ACTION updateFootprint
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
static TOOL_ACTION pointEditorMoveMidpoint
static TOOL_ACTION getAndPlace
Find an item and start moving.
static TOOL_ACTION properties
Activation of the edit tool.
static TOOL_ACTION editFpInFpEditor
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION moveWithReference
move with a reference point
static TOOL_ACTION swap
Swapping of selected items.
static TOOL_ACTION moveExact
Activation of the exact move tool.
static TOOL_ACTION intersectPolygons
Intersection of multiple polygons.
static TOOL_ACTION pointEditorMoveCorner
static TOOL_ACTION genRemove
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
static TOOL_ACTION assignNetClass
static TOOL_ACTION packAndMoveFootprints
Pack and start moving selected footprints.
static TOOL_ACTION copyWithReference
copy command with manual reference point selection
static TOOL_ACTION healShapes
Connect selected shapes, possibly extending or cutting them, or adding extra geometry.
static TOOL_ACTION dragFreeAngle
static TOOL_ACTION inspectClearance
static TOOL_ACTION updateLocalRatsnest
static TOOL_ACTION updateFootprints
static TOOL_ACTION deleteFull
static TOOL_ACTION moveIndividually
move items one-by-one
static TOOL_ACTION changeFootprints
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
static TOOL_ACTION chamferLines
Chamfer (i.e. adds a straight line) all selected straight lines by a user defined setback.
static TOOL_ACTION filletTracks
Fillet (i.e. adds an arc tangent to) all selected straight tracks by a user defined radius.
static TOOL_ACTION footprintProperties
static TOOL_ACTION filletLines
Fillet (i.e. adds an arc tangent to) all selected straight lines by a user defined radius.
static TOOL_ACTION changeFootprint
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
static TOOL_ACTION positionRelative
Activation of the position relative tool.
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION mirrorV
static TOOL_ACTION mergePolygons
Merge multiple polygons into a single polygon.
static TOOL_ACTION subtractPolygons
Subtract polygons from other polygons.
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
static TOOL_ACTION flip
Flipping of selected objects.
static TOOL_ACTION createArray
Tool for creating an array of objects.
static TOOL_ACTION extendLines
Extend selected lines to meet at a point.
static TOOL_ACTION rotateCw
Rotation of selected objects.
static TOOL_ACTION rotateCcw
virtual double GetLength() const override
Return the length of the arc track.
void SetMid(const VECTOR2I &aMid)
EDA_ANGLE GetAngle() const
const VECTOR2I & GetMid() const
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Common, abstract interface for edit frames.
virtual void OnEditItemRequest(BOARD_ITEM *aItem)
Install the corresponding dialog editor for the given item.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
PCBNEW_SETTINGS * GetPcbNewSettings() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
DS_PROXY_VIEW_ITEM * GetDrawingSheet() const
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
A set of BOARD_ITEMs (i.e., without duplicates).
std::unordered_set< BOARD_ITEM * > & GetItems()
Tool that displays edit points allowing to modify items by dragging the points.
int GetWidth() const override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetWidth(int aWidth)
virtual double GetLength() const
Get the length of the track using the hypotenuse calculation.
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
SEG PerpendicularSeg(const VECTOR2I &aP) const
Compute a segment perpendicular to this one, passing through point aP.
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
EDA_ANGLE Angle(const SEG &aOther) const
Determine the smallest angle between two segments.
static SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
static SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
VECTOR2I GetReferencePoint() const
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
virtual unsigned int GetSize() const override
Return the number of stored items.
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
int Size() const
Returns the number of selected parts.
void ClearReferencePoint()
void SetReferencePoint(const VECTOR2I &aP)
bool Empty() const
Checks if there is anything selected.
bool HasReferencePoint() const
size_t CountType(KICAD_T aType) const
bool Contains(EDA_ITEM *aItem) const
virtual BOX2I GetBoundingBox() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
An extension of WX_TEXT_ENTRY_DIALOG that uses UNIT_BINDER to request a dimension (e....
int GetValue()
Returns the value in internal units.
Handle a list of polygons defining a copper zone.
bool UnFill()
Removes the zone filling.
bool HitTestCutout(const VECTOR2I &aRefPos, int *aOutlineIdx=nullptr, int *aHoleIdx=nullptr) const
Test if the given point is contained within a cutout of the zone.
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
@ ROTATE_AROUND_USER_ORIGIN
@ ROTATE_AROUND_SEL_CENTER
@ ROTATE_AROUND_AUX_ORIGIN
@ ROTATE_AROUND_ITEM_ANCHOR
static constexpr EDA_ANGLE & ANGLE_180
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
#define IS_NEW
New item, just created.
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, std::vector< std::unique_ptr< PCB_SHAPE > > &aNewShapes, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
@ LAYER_DRAWINGSHEET
drawingsheet frame and titleblock
@ LAYER_SCHEMATIC_DRAWINGSHEET
PCB_LAYER_ID
A quick note on layer IDs:
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Function GetModel creates an S3DMODEL representation of aNode (raw data, no transforms)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
void for_all_pairs(_InputIterator __first, _InputIterator __last, _Function __f)
Apply a function to every possible pair of elements of a sequence.
Class to handle a set of BOARD_ITEMs.
std::optional< VECTOR2I > OPT_VECTOR2I
Parameters that define a simple chamfer operation.
constexpr int mmToIU(double mm) const
const VECTOR2I CalcArcMid(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aMinArcAngle=true)
Return the middle point of an arc, half-way between aStart and aEnd.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
double EuclideanNorm(const VECTOR2I &vector)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_SHAPE_LOCATE_SEGMENT_T
@ PCB_SHAPE_LOCATE_RECT_T
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_SHAPE_LOCATE_BEZIER_T
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_SHAPE_LOCATE_POLY_T
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".