KiCad PCB EDA Suite
edit_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013-2017 CERN
5 * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 * @author Tomasz Wlostowski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <advanced_config.h>
28#include <limits>
29#include <board.h>
31#include <footprint.h>
32#include <fp_shape.h>
33#include <fp_textbox.h>
34#include <pcb_group.h>
35#include <pcb_target.h>
36#include <pcb_text.h>
37#include <pcb_textbox.h>
38#include <collectors.h>
39#include <pcb_edit_frame.h>
41#include <kiway.h>
42#include <array_creator.h>
43#include <status_popup.h>
45#include <tool/tool_manager.h>
46#include <tools/pcb_actions.h>
48#include <tools/edit_tool.h>
52#include <tools/pad_tool.h>
53#include <view/view_controls.h>
56#include <core/kicad_algo.h>
57#include <bitmaps.h>
58#include <cassert>
59#include <functional>
60using namespace std::placeholders;
61#include "kicad_clipboard.h"
62#include <wx/hyperlink.h>
63#include <router/router_tool.h>
67#include <board_commit.h>
68#include <zone_filler.h>
69#include <pcb_bitmap.h>
70
71const unsigned int EDIT_TOOL::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
72
74 PCB_TOOL_BASE( "pcbnew.InteractiveEdit" ),
75 m_selectionTool( nullptr ),
76 m_dragging( false )
77{
78}
79
80
82{
83 m_dragging = false;
84
85 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( getEditFrame<PCB_BASE_EDIT_FRAME>() );
86
87 if( aReason != RUN )
88 m_commit.reset( new BOARD_COMMIT( this ) );
89}
90
91
93 CONDITIONAL_MENU( aTool )
94{
96 SetTitle( _( "Positioning Tools" ) );
97
102}
103
104
106{
107 // Find the selection tool, so they can cooperate
109
110 auto positioningToolsSubMenu = std::make_shared<POSITIONING_TOOLS_MENU>( this );
111 m_selectionTool->GetToolMenu().RegisterSubMenu( positioningToolsSubMenu );
112
113 auto propertiesCondition =
114 [&]( const SELECTION& aSel )
115 {
116 if( aSel.GetSize() == 0 )
117 {
119 {
122
123 if( ds && ds->HitTestDrawingSheetItems( getView(), cursor ) )
124 return true;
125 }
126
127 return false;
128 }
129
130 if( aSel.GetSize() == 1 )
131 return true;
132
133 for( EDA_ITEM* item : aSel )
134 {
135 if( !dynamic_cast<PCB_TRACK*>( item ) )
136 return false;
137 }
138
139 return true;
140 };
141
142 auto inFootprintEditor =
143 [ this ]( const SELECTION& aSelection )
144 {
145 return m_isFootprintEditor;
146 };
147
148 auto canMirror =
149 [ this ]( const SELECTION& aSelection )
150 {
152 && SELECTION_CONDITIONS::OnlyTypes( { PCB_PAD_T } )( aSelection ) )
153 {
154 return false;
155 }
156
158 };
159
160 auto singleFootprintCondition = SELECTION_CONDITIONS::OnlyTypes( { PCB_FOOTPRINT_T } )
162
163 auto noActiveToolCondition =
164 [ this ]( const SELECTION& aSelection )
165 {
166 return frame()->ToolStackIsEmpty();
167 };
168
169 auto notMovingCondition =
170 [ this ]( const SELECTION& aSelection )
171 {
175 };
176
177 auto noItemsCondition =
178 [ this ]( const SELECTION& aSelections ) -> bool
179 {
180 return frame()->GetBoard() && !frame()->GetBoard()->IsEmpty();
181 };
182
183 auto isSkippable =
184 [ this ]( const SELECTION& aSelection )
185 {
187 };
188
189 static std::vector<KICAD_T> connectedTypes = { PCB_TRACE_T,
190 PCB_ARC_T,
191 PCB_VIA_T,
192 PCB_PAD_T,
193 PCB_ZONE_T };
194
195 static std::vector<KICAD_T> unroutableTypes = { PCB_TRACE_T,
196 PCB_ARC_T,
197 PCB_VIA_T,
198 PCB_PAD_T,
200
201 static std::vector<KICAD_T> trackTypes = { PCB_TRACE_T,
202 PCB_ARC_T,
203 PCB_VIA_T };
204
205 static std::vector<KICAD_T> filletTypes = { PCB_SHAPE_LOCATE_POLY_T,
208
209
210 // Add context menu entries that are displayed when selection tool is active
212
214 && notMovingCondition );
216 && SELECTION_CONDITIONS::OnlyTypes( unroutableTypes )
217 && notMovingCondition
218 && !inFootprintEditor );
220 && notMovingCondition );
221 menu.AddItem( PCB_ACTIONS::skip, isSkippable );
223 && SELECTION_CONDITIONS::OnlyTypes( trackTypes ) );
234 menu.AddItem( PCB_ACTIONS::mirrorH, canMirror );
235 menu.AddItem( PCB_ACTIONS::mirrorV, canMirror );
239
240 menu.AddItem( PCB_ACTIONS::properties, propertiesCondition );
241
243 && !inFootprintEditor );
245
246 // Footprint actions
247 menu.AddSeparator();
248 menu.AddItem( PCB_ACTIONS::editFpInFpEditor, singleFootprintCondition );
249 menu.AddItem( PCB_ACTIONS::updateFootprint, singleFootprintCondition );
250 menu.AddItem( PCB_ACTIONS::changeFootprint, singleFootprintCondition );
251
252 // Add the submenu for the special positioning tools
253 menu.AddSeparator( 100 );
254 menu.AddMenu( positioningToolsSubMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
255
256 menu.AddSeparator( 150 );
259
260 // Selection tool handles the context menu for some other tools, such as the Picker.
261 // Don't add things like Paste when another tool is active.
262 menu.AddItem( ACTIONS::paste, noActiveToolCondition, 150 );
263 menu.AddItem( ACTIONS::pasteSpecial, noActiveToolCondition && !inFootprintEditor, 150 );
266
267 menu.AddSeparator( 150 );
268 menu.AddItem( ACTIONS::selectAll, noItemsCondition, 150 );
269
270 return true;
271}
272
273
275{
276 // GetAndPlace makes sense only in board editor, although it is also called
277 // in fpeditor, that shares the same EDIT_TOOL list
278 if( !getEditFrame<PCB_BASE_FRAME>()->IsType( FRAME_PCB_EDITOR ) )
279 return 0;
280
282 FOOTPRINT* fp = getEditFrame<PCB_BASE_FRAME>()->GetFootprintFromBoardByReference();
283
284 if( fp )
285 {
287 m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, (void*) fp );
288
289 selectionTool->GetSelection().SetReferencePoint( fp->GetPosition() );
291 }
292
293 return 0;
294}
295
296
297bool EDIT_TOOL::invokeInlineRouter( int aDragMode )
298{
300
301 if( !theRouter )
302 return false;
303
304 // don't allow switch from moving to dragging
305 if( m_dragging )
306 {
307 wxBell();
308 return false;
309 }
310
311 // make sure we don't accidentally invoke inline routing mode while the router is already
312 // active!
313 if( theRouter->IsToolActive() )
314 return false;
315
316 if( theRouter->CanInlineDrag( aDragMode ) )
317 {
319 static_cast<intptr_t>( aDragMode ) );
320 return true;
321 }
322
323 return false;
324}
325
326
328{
330
331 return router && router->RoutingInProgress();
332}
333
334
335int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
336{
337 if( !m_toolMgr->GetTool<ROUTER_TOOL>() )
338 return false; // don't drag when no router tool (i.e. fp editor)
339
341 return false; // don't drag when router is already active
342
343 int mode = PNS::DM_ANY;
344
345 if( aEvent.IsAction( &PCB_ACTIONS::dragFreeAngle ) )
346 mode |= PNS::DM_FREE_ANGLE;
347
349 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
350 {
351 sTool->FilterCollectorForFreePads( aCollector );
352 sTool->FilterCollectorForHierarchy( aCollector, true );
353
354 if( aCollector.GetCount() > 1 )
355 sTool->GuessSelectionCandidates( aCollector, aPt );
356
357 /*
358 * If we have a knee between two segments, or a via attached to two segments,
359 * then drop the selection to a single item.
360 */
361
362 std::vector<PCB_TRACK*> tracks;
363 std::vector<PCB_TRACK*> vias;
364
365 for( EDA_ITEM* item : aCollector )
366 {
367 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
368 {
369 if( track->Type() == PCB_VIA_T )
370 vias.push_back( track );
371 else
372 tracks.push_back( track );
373 }
374 }
375
376 auto connected = []( PCB_TRACK* track, const VECTOR2I& pt )
377 {
378 return track->GetStart() == pt || track->GetEnd() == pt;
379 };
380
381 if( tracks.size() == 2 && vias.size() == 0 )
382 {
383 if( connected( tracks[0], tracks[1]->GetStart() )
384 || connected( tracks[0], tracks[1]->GetEnd() ) )
385 {
386 aCollector.Remove( tracks[1] );
387 }
388 }
389 else if( tracks.size() == 2 && vias.size() == 1 )
390 {
391 if( connected( tracks[0], vias[0]->GetPosition() )
392 && connected( tracks[1], vias[0]->GetPosition() ) )
393 {
394 aCollector.Remove( tracks[0] );
395 aCollector.Remove( tracks[1] );
396 }
397 }
398 },
399 true /* prompt user regarding locked items */ );
400
401 if( selection.Empty() )
402 return 0;
403
404 if( selection.Size() == 1 && selection.Front()->Type() == PCB_ARC_T )
405 {
406 // TODO: This really should be done in PNS to ensure DRC is maintained, but for now
407 // it allows interactive editing of an arc track
408 return DragArcTrack( aEvent );
409 }
410 else
411 {
412 invokeInlineRouter( mode );
413 }
414
415 return 0;
416}
417
418
420{
422
423 if( selection.Size() != 1 || selection.Front()->Type() != PCB_ARC_T )
424 return 0;
425
426 PCB_ARC* theArc = static_cast<PCB_ARC*>( selection.Front() );
427 EDA_ANGLE maxTangentDeviation( ADVANCED_CFG::GetCfg().m_MaxTangentAngleDeviation, DEGREES_T );
428
429 if( theArc->GetAngle() + maxTangentDeviation >= ANGLE_180 )
430 {
431 wxString msg = wxString::Format( _( "Unable to resize arc tracks of %s or greater." ),
432 EDA_UNIT_UTILS::UI::MessageTextFromValue( ANGLE_180 - maxTangentDeviation ) );
433 frame()->ShowInfoBarError( msg );
434
435 return 0; // don't bother with > 180 degree arcs
436 }
437
439
440 Activate();
441 // Must be done after Activate() so that it gets set into the correct context
442 controls->ShowCursor( true );
443 controls->SetAutoPan( true );
444
445 bool restore_state = false;
446 VECTOR2I arcCenter = theArc->GetCenter();
447 SEG tanStart = SEG( arcCenter, theArc->GetStart() ).PerpendicularSeg( theArc->GetStart() );
448 SEG tanEnd = SEG( arcCenter, theArc->GetEnd() ).PerpendicularSeg( theArc->GetEnd() );
449
450 //Ensure the tangent segments are in the correct orientation
451 OPT_VECTOR2I tanIntersect = tanStart.IntersectLines( tanEnd );
452
453 if( !tanIntersect )
454 return 0;
455
456 tanStart.A = *tanIntersect;
457 tanStart.B = theArc->GetStart();
458 tanEnd.A = *tanIntersect;
459 tanEnd.B = theArc->GetEnd();
460
461 auto getUniqueTrackAtAnchorCollinear =
462 [&]( const VECTOR2I& aAnchor, const SEG& aCollinearSeg ) -> PCB_TRACK*
463 {
464 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
465
466 // Allow items at a distance within the width of the arc track
467 int allowedDeviation = theArc->GetWidth();
468
469 std::vector<BOARD_CONNECTED_ITEM*> itemsOnAnchor;
470
471 for( int i = 0; i < 3; i++ )
472 {
473 itemsOnAnchor = conn->GetConnectedItemsAtAnchor( theArc, aAnchor,
476 allowedDeviation );
477 allowedDeviation /= 2;
478
479 if( itemsOnAnchor.size() == 1 )
480 break;
481 }
482
483 PCB_TRACK* retval = nullptr;
484
485 if( itemsOnAnchor.size() == 1 && itemsOnAnchor.front()->Type() == PCB_TRACE_T )
486 {
487 retval = static_cast<PCB_TRACK*>( itemsOnAnchor.front() );
488 SEG trackSeg( retval->GetStart(), retval->GetEnd() );
489
490 // Allow deviations in colinearity as defined in ADVANCED_CFG
491 if( trackSeg.Angle( aCollinearSeg ) > maxTangentDeviation )
492 retval = nullptr;
493 }
494
495 if( !retval )
496 {
497 retval = new PCB_TRACK( theArc->GetParent() );
498 retval->SetStart( aAnchor );
499 retval->SetEnd( aAnchor );
500 retval->SetNet( theArc->GetNet() );
501 retval->SetLayer( theArc->GetLayer() );
502 retval->SetWidth( theArc->GetWidth() );
503 retval->SetLocked( theArc->IsLocked() );
504 retval->SetFlags( IS_NEW );
505 getView()->Add( retval );
506 }
507
508 return retval;
509 };
510
511 PCB_TRACK* trackOnStart = getUniqueTrackAtAnchorCollinear( theArc->GetStart(), tanStart);
512 PCB_TRACK* trackOnEnd = getUniqueTrackAtAnchorCollinear( theArc->GetEnd(), tanEnd );
513
514 // Make copies of items to be edited
515 PCB_ARC* theArcCopy = new PCB_ARC( *theArc );
516 PCB_TRACK* trackOnStartCopy = new PCB_TRACK( *trackOnStart );
517 PCB_TRACK* trackOnEndCopy = new PCB_TRACK( *trackOnEnd );
518
519 if( trackOnStart->GetLength() != 0 )
520 {
521 tanStart.A = trackOnStart->GetStart();
522 tanStart.B = trackOnStart->GetEnd();
523 }
524
525 if( trackOnEnd->GetLength() != 0 )
526 {
527 tanEnd.A = trackOnEnd->GetStart();
528 tanEnd.B = trackOnEnd->GetEnd();
529 }
530
531 // Recalculate intersection point
532 if( tanIntersect = tanStart.IntersectLines( tanEnd ); !tanIntersect )
533 return 0;
534
535 auto isTrackStartClosestToArcStart =
536 [&]( PCB_TRACK* aTrack ) -> bool
537 {
538 double trackStartToArcStart = GetLineLength( aTrack->GetStart(), theArc->GetStart() );
539 double trackEndToArcStart = GetLineLength( aTrack->GetEnd(), theArc->GetStart() );
540
541 return trackStartToArcStart < trackEndToArcStart;
542 };
543
544 bool isStartTrackOnStartPt = isTrackStartClosestToArcStart( trackOnStart );
545 bool isEndTrackOnStartPt = isTrackStartClosestToArcStart( trackOnEnd );
546
547 // Calculate constraints
548 //======================
549 // maxTanCircle is the circle with maximum radius that is tangent to the two adjacent straight
550 // tracks and whose tangent points are constrained within the original tracks and their
551 // projected intersection points.
552 //
553 // The cursor will be constrained first within the isosceles triangle formed by the segments
554 // cSegTanStart, cSegTanEnd and cSegChord. After that it will be constrained to be outside
555 // maxTanCircle.
556 //
557 //
558 // ____________ <-cSegTanStart
559 // / * . ' *
560 // cSegTanEnd-> / * . ' *
561 // /* . ' <-cSegChord *
562 // /. '
563 // /* *
564 //
565 // * c * <-maxTanCircle
566 //
567 // * *
568 //
569 // * *
570 // * *
571 // * *
572 //
573
574 auto getFurthestPointToTanInterstect =
575 [&]( VECTOR2I& aPointA, VECTOR2I& aPointB ) -> VECTOR2I
576 {
577 if( ( aPointA - *tanIntersect ).EuclideanNorm()
578 > ( aPointB - *tanIntersect ).EuclideanNorm() )
579 {
580 return aPointA;
581 }
582 else
583 {
584 return aPointB;
585 }
586 };
587
588 CIRCLE maxTanCircle;
589 VECTOR2I tanStartPoint = getFurthestPointToTanInterstect( tanStart.A, tanStart.B );
590 VECTOR2I tanEndPoint = getFurthestPointToTanInterstect( tanEnd.A, tanEnd.B );
591 VECTOR2I tempTangentPoint = tanEndPoint;
592
593 if( getFurthestPointToTanInterstect( tanStartPoint, tanEndPoint ) == tanEndPoint )
594 tempTangentPoint = tanStartPoint;
595
596 maxTanCircle.ConstructFromTanTanPt( tanStart, tanEnd, tempTangentPoint );
597 VECTOR2I maxTanPtStart = tanStart.LineProject( maxTanCircle.Center );
598 VECTOR2I maxTanPtEnd = tanEnd.LineProject( maxTanCircle.Center );
599
600 SEG cSegTanStart( maxTanPtStart, *tanIntersect );
601 SEG cSegTanEnd( maxTanPtEnd, *tanIntersect );
602 SEG cSegChord( maxTanPtStart, maxTanPtEnd );
603
604 int cSegTanStartSide = cSegTanStart.Side( theArc->GetMid() );
605 int cSegTanEndSide = cSegTanEnd.Side( theArc->GetMid() );
606 int cSegChordSide = cSegChord.Side( theArc->GetMid() );
607
608 bool eatFirstMouseUp = true;
609
610 // Start the tool loop
611 while( TOOL_EVENT* evt = Wait() )
612 {
614
615 // Constrain cursor within the isosceles triangle
616 if( cSegTanStartSide != cSegTanStart.Side( m_cursor )
617 || cSegTanEndSide != cSegTanEnd.Side( m_cursor )
618 || cSegChordSide != cSegChord.Side( m_cursor ) )
619 {
620 std::vector<VECTOR2I> possiblePoints;
621
622 possiblePoints.push_back( cSegTanEnd.NearestPoint( m_cursor ) );
623 possiblePoints.push_back( cSegChord.NearestPoint( m_cursor ) );
624
625 VECTOR2I closest = cSegTanStart.NearestPoint( m_cursor );
626
627 for( VECTOR2I candidate : possiblePoints )
628 {
629 if( ( candidate - m_cursor ).SquaredEuclideanNorm()
630 < ( closest - m_cursor ).SquaredEuclideanNorm() )
631 {
632 closest = candidate;
633 }
634 }
635
636 m_cursor = closest;
637 }
638
639 // Constrain cursor to be outside maxTanCircle
640 if( ( m_cursor - maxTanCircle.Center ).EuclideanNorm() < maxTanCircle.Radius )
641 m_cursor = maxTanCircle.NearestPoint( m_cursor );
642
644
645 // Calculate resulting object coordinates
646 CIRCLE circlehelper;
647 circlehelper.ConstructFromTanTanPt( cSegTanStart, cSegTanEnd, m_cursor );
648
649 VECTOR2I newCenter = circlehelper.Center;
650 VECTOR2I newStart = cSegTanStart.LineProject( newCenter );
651 VECTOR2I newEnd = cSegTanEnd.LineProject( newCenter );
652 VECTOR2I newMid = CalcArcMid( newStart, newEnd, newCenter );
653
654 // Update objects
655 theArc->SetStart( newStart );
656 theArc->SetEnd( newEnd );
657 theArc->SetMid( newMid );
658
659 if( isStartTrackOnStartPt )
660 trackOnStart->SetStart( newStart );
661 else
662 trackOnStart->SetEnd( newStart );
663
664 if( isEndTrackOnStartPt )
665 trackOnEnd->SetStart( newEnd );
666 else
667 trackOnEnd->SetEnd( newEnd );
668
669 // Update view
670 getView()->Update( trackOnStart );
671 getView()->Update( trackOnEnd );
672 getView()->Update( theArc );
673
674 // Handle events
675 if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
676 {
677 eatFirstMouseUp = false;
678 }
679 else if( evt->IsCancelInteractive() || evt->IsActivate() )
680 {
681 restore_state = true; // Canceling the tool means that items have to be restored
682 break; // Finish
683 }
684 else if( evt->IsAction( &ACTIONS::undo ) )
685 {
686 restore_state = true; // Perform undo locally
687 break; // Finish
688 }
689 else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT )
690 || evt->IsDblClick( BUT_LEFT ) )
691 {
692 // Eat mouse-up/-click events that leaked through from the lock dialog
693 if( eatFirstMouseUp && evt->Parameter<intptr_t>() != ACTIONS::CURSOR_CLICK )
694 {
695 eatFirstMouseUp = false;
696 continue;
697 }
698
699 break; // Finish
700 }
701 }
702
703 // Ensure we only do one commit operation on each object
704 auto processTrack =
705 [&]( PCB_TRACK* aTrack, PCB_TRACK* aTrackCopy, int aMaxLengthIU ) -> bool
706 {
707 if( aTrack->IsNew() )
708 {
709 getView()->Remove( aTrack );
710
711 if( aTrack->GetLength() <= aMaxLengthIU )
712 {
713 aTrack->SetParentGroup( nullptr );
714 delete aTrack;
715 aTrack = nullptr;
716
717 aTrackCopy->SetParentGroup( nullptr );
718 delete aTrackCopy;
719 aTrackCopy = nullptr;
720
721 return false;
722 }
723 else
724 {
725 m_commit->Add( aTrack );
726
727 aTrackCopy->SetParentGroup( nullptr );
728 delete aTrackCopy;
729 aTrackCopy = nullptr;
730
731 return true;
732 }
733 }
734 else if( aTrack->GetLength() <= aMaxLengthIU )
735 {
736 aTrack->SwapItemData( aTrackCopy ); //restore the original before notifying COMMIT
737 m_commit->Remove( aTrack );
738
739 aTrackCopy->SetParentGroup( nullptr );
740 delete aTrackCopy;
741 aTrackCopy = nullptr;
742
743 return false;
744 }
745 else
746 {
747 m_commit->Modified( aTrack, aTrackCopy );
748 }
749
750 return true;
751 };
752
753 // Amend the end points of the arc if we delete the joining tracks
754 VECTOR2I newStart = trackOnStart->GetStart();
755 VECTOR2I newEnd = trackOnEnd->GetStart();
756
757 if( isStartTrackOnStartPt )
758 newStart = trackOnStart->GetEnd();
759
760 if( isEndTrackOnStartPt )
761 newEnd = trackOnEnd->GetEnd();
762
763 int maxLengthIU =
764 KiROUND( ADVANCED_CFG::GetCfg().m_MaxTrackLengthToKeep * pcbIUScale.IU_PER_MM );
765
766 if( !processTrack( trackOnStart, trackOnStartCopy, maxLengthIU ) )
767 theArc->SetStart( newStart );
768
769 if( !processTrack( trackOnEnd, trackOnEndCopy, maxLengthIU ) )
770 theArc->SetEnd( newEnd );
771
772 processTrack( theArc, theArcCopy, 0 ); // only delete the arc if start and end points coincide
773
774 // Should we commit?
775 if( restore_state )
776 m_commit->Revert();
777 else
778 m_commit->Push( _( "Drag Arc Track" ) );
779
780 return 0;
781}
782
783
785{
787 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
788 {
789 // Iterate from the back so we don't have to worry about removals.
790 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
791 {
792 BOARD_ITEM* item = aCollector[ i ];
793
794 if( !dynamic_cast<PCB_TRACK*>( item ) )
795 aCollector.Remove( item );
796 }
797 },
798 true /* prompt user regarding locked items */ );
799
800 for( EDA_ITEM* item : selection )
801 {
802 if( item->Type() == PCB_VIA_T )
803 {
804 PCB_VIA* via = static_cast<PCB_VIA*>( item );
805
806 m_commit->Modify( via );
807
808 int new_width;
809 int new_drill;
810
811 if( via->GetViaType() == VIATYPE::MICROVIA )
812 {
813 NETCLASS* netClass = via->GetEffectiveNetClass();
814
815 new_width = netClass->GetuViaDiameter();
816 new_drill = netClass->GetuViaDrill();
817 }
818 else
819 {
820 new_width = board()->GetDesignSettings().GetCurrentViaSize();
821 new_drill = board()->GetDesignSettings().GetCurrentViaDrill();
822 }
823
824 via->SetDrill( new_drill );
825 via->SetWidth( new_width );
826 }
827 else if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
828 {
829 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
830
831 wxCHECK( track, 0 );
832
833 m_commit->Modify( track );
834
835 int new_width = board()->GetDesignSettings().GetCurrentTrackWidth();
836 track->SetWidth( new_width );
837 }
838 }
839
840 m_commit->Push( _( "Edit track width/via size" ) );
841
842 if( selection.IsHover() )
843 {
845
846 // Notify other tools of the changes -- This updates the visual ratsnest
848 }
849
850 return 0;
851}
852
853
855{
856 // Store last used fillet radius to allow pressing "enter" if repeat fillet is required
857 static long long filletRadiusIU = 0;
858
860 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
861 {
862 // Iterate from the back so we don't have to worry about removals.
863 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
864 {
865 BOARD_ITEM* item = aCollector[i];
866
867 if( !dynamic_cast<PCB_TRACK*>( item ) )
868 aCollector.Remove( item );
869 }
870 },
871 true /* prompt user regarding locked items */ );
872
873 if( selection.Size() < 2 )
874 {
875 frame()->ShowInfoBarMsg( _( "At least two straight track segments must be selected." ) );
876 return 0;
877 }
878
879 WX_UNIT_ENTRY_DIALOG dia( frame(), _( "Enter fillet radius:" ), _( "Fillet Tracks" ),
880 filletRadiusIU );
881
882 if( dia.ShowModal() == wxID_CANCEL )
883 return 0;
884
885 filletRadiusIU = dia.GetValue();
886
887 if( filletRadiusIU == 0 )
888 {
889 frame()->ShowInfoBarMsg( _( "A radius of zero was entered.\n"
890 "The fillet operation was not performed." ) );
891 return 0;
892 }
893
894 struct FILLET_OP
895 {
896 PCB_TRACK* t1;
897 PCB_TRACK* t2;
898 // Start point of track is modified after PCB_ARC is added, otherwise the end point:
899 bool t1Start = true;
900 bool t2Start = true;
901 };
902
903 std::vector<FILLET_OP> filletOperations;
904 bool operationPerformedOnAtLeastOne = false;
905 bool didOneAttemptFail = false;
906 std::set<PCB_TRACK*> processedTracks;
907
908 for( EDA_ITEM* item : selection )
909 {
910 PCB_TRACK* track = dyn_cast<PCB_TRACK*>( item );
911
912 if( !track || track->Type() != PCB_TRACE_T || track->GetLength() == 0 )
913 {
914 continue;
915 }
916
917 auto processFilletOp =
918 [&]( bool aStartPoint )
919 {
920 std::shared_ptr<CONNECTIVITY_DATA> c = board()->GetConnectivity();
921 VECTOR2I anchor = aStartPoint ? track->GetStart()
922 : track->GetEnd();
923 std::vector<BOARD_CONNECTED_ITEM*> itemsOnAnchor;
924
925 itemsOnAnchor = c->GetConnectedItemsAtAnchor( track, anchor,
928
929 if( itemsOnAnchor.size() > 0
930 && selection.Contains( itemsOnAnchor.at( 0 ) )
931 && itemsOnAnchor.at( 0 )->Type() == PCB_TRACE_T )
932 {
933 PCB_TRACK* trackOther = dyn_cast<PCB_TRACK*>( itemsOnAnchor.at( 0 ) );
934
935 // Make sure we don't fillet the same pair of tracks twice
936 if( processedTracks.find( trackOther ) == processedTracks.end() )
937 {
938 if( itemsOnAnchor.size() == 1 )
939 {
940 FILLET_OP filletOp;
941 filletOp.t1 = track;
942 filletOp.t2 = trackOther;
943 filletOp.t1Start = aStartPoint;
944 filletOp.t2Start = track->IsPointOnEnds( filletOp.t2->GetStart() );
945 filletOperations.push_back( filletOp );
946 }
947 else
948 {
949 // User requested to fillet these two tracks but not possible as
950 // there are other elements connected at that point
951 didOneAttemptFail = true;
952 }
953 }
954 }
955 };
956
957 processFilletOp( true ); // on the start point of track
958 processFilletOp( false ); // on the end point of track
959
960 processedTracks.insert( track );
961 }
962
963 std::vector<BOARD_ITEM*> itemsToAddToSelection;
964
965 for( FILLET_OP filletOp : filletOperations )
966 {
967 PCB_TRACK* track1 = filletOp.t1;
968 PCB_TRACK* track2 = filletOp.t2;
969
970 bool trackOnStart = track1->IsPointOnEnds( track2->GetStart() );
971 bool trackOnEnd = track1->IsPointOnEnds( track2->GetEnd() );
972
973 if( trackOnStart && trackOnEnd )
974 continue; // Ignore duplicate tracks
975
976 if( ( trackOnStart || trackOnEnd ) && track1->GetLayer() == track2->GetLayer() )
977 {
978 SEG t1Seg( track1->GetStart(), track1->GetEnd() );
979 SEG t2Seg( track2->GetStart(), track2->GetEnd() );
980
981 if( t1Seg.ApproxCollinear( t2Seg ) )
982 continue;
983
984 SHAPE_ARC sArc( t1Seg, t2Seg, filletRadiusIU );
985 VECTOR2I t1newPoint, t2newPoint;
986
987 auto setIfPointOnSeg =
988 []( VECTOR2I& aPointToSet, SEG aSegment, VECTOR2I aVecToTest )
989 {
990 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
991
992 // Find out if we are on the segment (minimum precision)
994 {
995 aPointToSet.x = aVecToTest.x;
996 aPointToSet.y = aVecToTest.y;
997 return true;
998 }
999
1000 return false;
1001 };
1002
1003 //Do not draw a fillet if the end points of the arc are not within the track segments
1004 if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP0() )
1005 && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP0() ) )
1006 {
1007 didOneAttemptFail = true;
1008 continue;
1009 }
1010
1011 if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP1() )
1012 && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP1() ) )
1013 {
1014 didOneAttemptFail = true;
1015 continue;
1016 }
1017
1018 PCB_ARC* tArc = new PCB_ARC( frame()->GetBoard(), &sArc );
1019 tArc->SetLayer( track1->GetLayer() );
1020 tArc->SetWidth( track1->GetWidth() );
1021 tArc->SetNet( track1->GetNet() );
1022 tArc->SetLocked( track1->IsLocked() );
1023 m_commit->Add( tArc );
1024 itemsToAddToSelection.push_back( tArc );
1025
1026 m_commit->Modify( track1 );
1027 m_commit->Modify( track2 );
1028
1029 if( filletOp.t1Start )
1030 track1->SetStart( t1newPoint );
1031 else
1032 track1->SetEnd( t1newPoint );
1033
1034 if( filletOp.t2Start )
1035 track2->SetStart( t2newPoint );
1036 else
1037 track2->SetEnd( t2newPoint );
1038
1039 operationPerformedOnAtLeastOne = true;
1040 }
1041 }
1042
1043 m_commit->Push( _( "Fillet Tracks" ) );
1044
1045 //select the newly created arcs
1046 for( BOARD_ITEM* item : itemsToAddToSelection )
1048
1049 if( !operationPerformedOnAtLeastOne )
1050 frame()->ShowInfoBarMsg( _( "Unable to fillet the selected track segments." ) );
1051 else if( didOneAttemptFail )
1052 frame()->ShowInfoBarMsg( _( "Some of the track segments could not be filleted." ) );
1053
1054 return 0;
1055}
1056
1057
1059{
1060 // Store last used fillet radius to allow pressing "enter" if repeat fillet is required
1061 static long long filletRadiusIU = 0;
1062
1064 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1065 {
1066
1067 std::vector<VECTOR2I> pts;
1068
1069 // Iterate from the back so we don't have to worry about removals.
1070 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1071 {
1072 BOARD_ITEM* item = aCollector[i];
1073
1074 // We've converted the polygon and rectangle to segments, so drop everything
1075 // that isn't a segment at this point
1076 if( !item->IsType( { PCB_SHAPE_LOCATE_SEGMENT_T,
1077 PCB_SHAPE_LOCATE_POLY_T,
1078 PCB_SHAPE_LOCATE_RECT_T } ) )
1079 {
1080 aCollector.Remove( item );
1081 }
1082 }
1083 },
1084 true /* prompt user regarding locked items */ );
1085
1086 std::set<PCB_SHAPE*> lines_to_add;
1087 std::vector<PCB_SHAPE*> items_to_remove;
1088
1089 for( EDA_ITEM* item : selection )
1090 {
1091 std::vector<VECTOR2I> pts;
1092 PCB_SHAPE *graphic = static_cast<PCB_SHAPE*>( item );
1093 PCB_LAYER_ID layer = graphic->GetLayer();
1094 int width = graphic->GetWidth();
1095
1096 if( graphic->GetShape() == SHAPE_T::RECT )
1097 {
1098 items_to_remove.push_back( graphic );
1099 VECTOR2I start( graphic->GetStart() );
1100 VECTOR2I end( graphic->GetEnd() );
1101 pts.emplace_back( start );
1102 pts.emplace_back( VECTOR2I( end.x, start.y ) );
1103 pts.emplace_back( end );
1104 pts.emplace_back( VECTOR2I( start.x, end.y ) );
1105 }
1106
1107 if( graphic->GetShape() == SHAPE_T::POLY )
1108 {
1109 items_to_remove.push_back( graphic );
1110
1111 for( int jj = 0; jj < graphic->GetPolyShape().VertexCount(); ++jj )
1112 pts.emplace_back( graphic->GetPolyShape().CVertex( jj ) );
1113 }
1114
1115 for( size_t jj = 1; jj < pts.size(); ++jj )
1116 {
1117 PCB_SHAPE *line;
1118
1119 if( m_isFootprintEditor )
1120 line = new FP_SHAPE( static_cast<FOOTPRINT*>( frame()->GetModel() ), SHAPE_T::SEGMENT );
1121 else
1122 line = new PCB_SHAPE( frame()->GetModel(), SHAPE_T::SEGMENT );
1123
1124 line->SetStart( pts[jj - 1] );
1125 line->SetEnd( pts[jj] );
1126 line->SetWidth( width );
1127 line->SetLayer( layer );
1128 lines_to_add.insert( line );
1129 }
1130
1131 if( pts.size() > 1 )
1132 {
1133 PCB_SHAPE *line;
1134
1135 if( m_isFootprintEditor )
1136 line = new FP_SHAPE( static_cast<FOOTPRINT*>( frame()->GetModel() ), SHAPE_T::SEGMENT );
1137 else
1138 line = new PCB_SHAPE( frame()->GetModel(), SHAPE_T::SEGMENT );
1139
1140 line->SetStart( pts.back() );
1141 line->SetEnd( pts.front() );
1142 line->SetWidth( width );
1143 line->SetLayer( layer );
1144 lines_to_add.insert( line );
1145 }
1146 }
1147
1148 for( PCB_SHAPE* item : lines_to_add )
1149 selection.Add( item );
1150
1151 for( PCB_SHAPE* item : items_to_remove )
1152 selection.Remove( item );
1153
1154 if( selection.CountType( PCB_SHAPE_LOCATE_SEGMENT_T ) < 2 )
1155 {
1156 frame()->ShowInfoBarMsg( _( "A shape with least two lines must be selected." ) );
1157 return 0;
1158 }
1159
1160 WX_UNIT_ENTRY_DIALOG dia( frame(), _( "Enter fillet radius:" ), _( "Fillet Lines" ),
1161 filletRadiusIU );
1162
1163 if( dia.ShowModal() == wxID_CANCEL )
1164 return 0;
1165
1166 filletRadiusIU = dia.GetValue();
1167
1168 if( filletRadiusIU == 0 )
1169 {
1170 frame()->ShowInfoBarMsg( _( "A radius of zero was entered.\n"
1171 "The fillet operation was not performed." ) );
1172 return 0;
1173 }
1174
1175 bool operationPerformedOnAtLeastOne = false;
1176 bool didOneAttemptFail = false;
1177 std::vector<BOARD_ITEM*> itemsToAddToSelection;
1178
1179 // Only modify one parent in FP editor
1180 if( m_isFootprintEditor )
1181 m_commit->Modify( selection.Front() );
1182
1183 alg::for_all_pairs( selection.begin(), selection.end(), [&]( EDA_ITEM* a, EDA_ITEM* b )
1184 {
1185 PCB_SHAPE* line_a = static_cast<PCB_SHAPE*>( a );
1186 PCB_SHAPE* line_b = static_cast<PCB_SHAPE*>( b );
1187
1188 if( line_a->GetLength() == 0.0 || line_b->GetLength() == 0 )
1189 return;
1190
1191 SEG seg_a( line_a->GetStart(), line_a->GetEnd() );
1192 SEG seg_b( line_b->GetStart(), line_b->GetEnd() );
1193 VECTOR2I* a_pt;
1194 VECTOR2I* b_pt;
1195
1196 if (seg_a.A == seg_b.A)
1197 {
1198 a_pt = &seg_a.A;
1199 b_pt = &seg_b.A;
1200 }
1201 else if (seg_a.A == seg_b.B)
1202 {
1203 a_pt = &seg_a.A;
1204 b_pt = &seg_b.B;
1205 }
1206 else if (seg_a.B == seg_b.A)
1207 {
1208 a_pt = &seg_a.B;
1209 b_pt = &seg_b.A;
1210 }
1211 else if (seg_a.B == seg_b.B)
1212 {
1213 a_pt = &seg_a.B;
1214 b_pt = &seg_b.B;
1215 }
1216 else
1217 return;
1218
1219
1220 SHAPE_ARC sArc( seg_a, seg_b, filletRadiusIU );
1221 VECTOR2I t1newPoint, t2newPoint;
1222
1223 auto setIfPointOnSeg =
1224 []( VECTOR2I& aPointToSet, SEG aSegment, VECTOR2I aVecToTest )
1225 {
1226 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
1227
1228 // Find out if we are on the segment (minimum precision)
1230 {
1231 aPointToSet.x = aVecToTest.x;
1232 aPointToSet.y = aVecToTest.y;
1233 return true;
1234 }
1235
1236 return false;
1237 };
1238
1239 //Do not draw a fillet if the end points of the arc are not within the track segments
1240 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.GetP0() )
1241 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.GetP0() ) )
1242 {
1243 didOneAttemptFail = true;
1244 return;
1245 }
1246
1247 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.GetP1() )
1248 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.GetP1() ) )
1249 {
1250 didOneAttemptFail = true;
1251 return;
1252 }
1253
1254 PCB_SHAPE* tArc;
1255
1256 if( m_isFootprintEditor )
1257 tArc = new FP_SHAPE( static_cast<FOOTPRINT*>( frame()->GetModel() ), SHAPE_T::ARC );
1258 else
1259 tArc = new PCB_SHAPE( frame()->GetBoard(), SHAPE_T::ARC );
1260
1261 tArc->SetArcGeometry( sArc.GetP0(), sArc.GetArcMid(), sArc.GetP1() );
1262 tArc->SetWidth( line_a->GetWidth() );
1263 tArc->SetLayer( line_a->GetLayer() );
1264 tArc->SetLocked( line_a->IsLocked() );
1265
1266 if( lines_to_add.count( line_a ) )
1267 {
1268 lines_to_add.erase( line_a );
1269 itemsToAddToSelection.push_back( line_a );
1270 }
1271 else if( !m_isFootprintEditor )
1272 {
1273 m_commit->Modify( line_a );
1274 }
1275
1276 if( lines_to_add.count( line_b ) )
1277 {
1278 lines_to_add.erase( line_b );
1279 itemsToAddToSelection.push_back( line_b );
1280 }
1281 else if( !m_isFootprintEditor )
1282 {
1283 m_commit->Modify( line_b );
1284 }
1285
1286 itemsToAddToSelection.push_back( tArc );
1287 *a_pt = t1newPoint;
1288 *b_pt = t2newPoint;
1289 line_a->SetStart( seg_a.A );
1290 line_a->SetEnd( seg_a.B );
1291 line_b->SetStart( seg_b.A );
1292 line_b->SetEnd( seg_b.B );
1293
1294 if( m_isFootprintEditor )
1295 {
1296 static_cast<FP_SHAPE*>( line_a )->SetLocalCoord();
1297 static_cast<FP_SHAPE*>( line_b )->SetLocalCoord();
1298 static_cast<FP_SHAPE*>( tArc )->SetLocalCoord();
1299 }
1300
1301 operationPerformedOnAtLeastOne = true;
1302
1303 } );
1304
1305 for( auto item : items_to_remove )
1306 {
1307 m_commit->Remove( item );
1308 m_selectionTool->RemoveItemFromSel( item, true );
1309 }
1310
1311 //select the newly created arcs
1312 for( BOARD_ITEM* item : itemsToAddToSelection )
1313 {
1314 m_commit->Add( item );
1315 m_selectionTool->AddItemToSel( item, true );
1316 }
1317
1318 if( !items_to_remove.empty() )
1319 m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
1320
1321 if( !itemsToAddToSelection.empty() )
1322 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1323
1324 // Notify other tools of the changes
1325 m_toolMgr->ProcessEvent( EVENTS::SelectedItemsModified );
1326
1327 m_commit->Push( _( "Fillet Lines" ) );
1328
1329 if( !operationPerformedOnAtLeastOne )
1330 frame()->ShowInfoBarMsg( _( "Unable to fillet the selected lines." ) );
1331 else if( didOneAttemptFail )
1332 frame()->ShowInfoBarMsg( _( "Some of the lines could not be filleted." ) );
1333
1334 return 0;
1335}
1336
1337
1339{
1340 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1342 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1343 {
1344 } );
1345
1346 // Tracks & vias are treated in a special way:
1348 {
1350 dlg.ShowQuasiModal(); // QuasiModal required for NET_SELECTOR
1351 }
1352 else if( selection.Size() == 1 )
1353 {
1354 // Display properties dialog
1355 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
1356
1357 // Do not handle undo buffer, it is done by the properties dialogs
1358 editFrame->OnEditItemRequest( item );
1359
1360 // Notify other tools of the changes
1362 }
1363 else if( selection.Size() == 0 && getView()->IsLayerVisible( LAYER_DRAWINGSHEET ) )
1364 {
1365 DS_PROXY_VIEW_ITEM* ds = editFrame->GetCanvas()->GetDrawingSheet();
1366 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( false );
1367
1368 if( ds && ds->HitTestDrawingSheetItems( getView(), cursorPos ) )
1370 else
1372 }
1373
1374 if( selection.IsHover() )
1375 {
1377 }
1378 else
1379 {
1380 // Check for items becoming invisible and drop them from the selection.
1381
1382 PCB_SELECTION selCopy = selection;
1383 LSET visible = editFrame->GetBoard()->GetVisibleLayers();
1384
1385 for( EDA_ITEM* eda_item : selCopy )
1386 {
1387 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( eda_item );
1388
1389 if( !( item->GetLayerSet() & visible ).any() )
1391 }
1392 }
1393
1394 return 0;
1395}
1396
1397
1398int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
1399{
1400 if( isRouterActive() )
1401 {
1402 wxBell();
1403 return 0;
1404 }
1405
1406 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1407
1408 // Be sure that there is at least one item that we can modify. If nothing was selected before,
1409 // try looking for the stuff under mouse cursor (i.e. KiCad old-style hover selection)
1411 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1412 {
1413 sTool->FilterCollectorForHierarchy( aCollector, true );
1414 sTool->FilterCollectorForMarkers( aCollector );
1415 },
1416 // Prompt user regarding locked items if in board editor and in free-pad-mode (if
1417 // we're not in free-pad mode we delay this until the second RequestSelection()).
1419
1420 if( selection.Empty() )
1421 return 0;
1422
1423 std::optional<VECTOR2I> oldRefPt;
1424 bool is_hover = selection.IsHover(); // N.B. This must be saved before the second
1425 // call to RequestSelection() below
1426
1428 oldRefPt = selection.GetReferencePoint();
1429
1430 // Now filter out pads if not in free pads mode. We cannot do this in the first
1431 // RequestSelection() as we need the reference point when a pad is the selection front.
1433 {
1435 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1436 {
1437 sTool->FilterCollectorForMarkers( aCollector );
1438 sTool->FilterCollectorForHierarchy( aCollector, true );
1439 sTool->FilterCollectorForFreePads( aCollector );
1440 },
1441 true /* prompt user regarding locked items */ );
1442 }
1443
1444 // Did we filter everything out? If so, don't try to operate further
1445 if( selection.Empty() )
1446 return 0;
1447
1449
1451 EDA_ANGLE rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent );
1452
1453 // Calculate view bounding box
1454 BOX2I viewBBox = selection.Front()->ViewBBox();
1455
1456 for( EDA_ITEM* item : selection )
1457 viewBBox.Merge( item->ViewBBox() );
1458
1459 // Check if the view bounding box will go out of bounds
1460 VECTOR2D rotPos = viewBBox.GetPosition();
1461 VECTOR2D rotEnd = viewBBox.GetEnd();
1462
1463 RotatePoint( &rotPos.x, &rotPos.y, refPt.x, refPt.y, rotateAngle );
1464 RotatePoint( &rotEnd.x, &rotEnd.y, refPt.x, refPt.y, rotateAngle );
1465
1466 typedef std::numeric_limits<int> coord_limits;
1467
1468 int max = coord_limits::max() - COORDS_PADDING;
1469 int min = -max;
1470
1471 bool outOfBounds = rotPos.x < min || rotPos.x > max || rotPos.y < min || rotPos.y > max
1472 || rotEnd.x < min || rotEnd.x > max || rotEnd.y < min || rotEnd.y > max;
1473
1474 if( !outOfBounds )
1475 {
1476 // When editing footprints, all items have the same parent
1477 if( IsFootprintEditor() )
1478 m_commit->Modify( selection.Front() );
1479
1480 for( EDA_ITEM* item : selection )
1481 {
1482 if( !item->IsNew() && !IsFootprintEditor() )
1483 {
1484 m_commit->Modify( item );
1485
1486 // If rotating a group, record position of all the descendants for undo
1487 if( item->Type() == PCB_GROUP_T )
1488 {
1489 static_cast<PCB_GROUP*>( item )->RunOnDescendants( [&]( BOARD_ITEM* bItem )
1490 {
1491 m_commit->Modify( bItem );
1492 });
1493 }
1494 }
1495
1496 static_cast<BOARD_ITEM*>( item )->Rotate( refPt, rotateAngle );
1497 }
1498
1499 if( !m_dragging )
1500 m_commit->Push( _( "Rotate" ) );
1501
1502 if( is_hover && !m_dragging )
1504
1506
1507 if( m_dragging )
1509 }
1510
1511 // Restore the old reference so any mouse dragging that occurs doesn't make the selection jump
1512 // to this now invalid reference
1513 if( oldRefPt )
1514 selection.SetReferencePoint( *oldRefPt );
1515 else
1517
1518 return 0;
1519}
1520
1521
1525static VECTOR2I mirrorPointX( const VECTOR2I& aPoint, const VECTOR2I& aMirrorPoint )
1526{
1527 VECTOR2I mirrored = aPoint;
1528
1529 mirrored.x -= aMirrorPoint.x;
1530 mirrored.x = -mirrored.x;
1531 mirrored.x += aMirrorPoint.x;
1532
1533 return mirrored;
1534}
1535
1536
1540static VECTOR2I mirrorPointY( const VECTOR2I& aPoint, const VECTOR2I& aMirrorPoint )
1541{
1542 VECTOR2I mirrored = aPoint;
1543
1544 mirrored.y -= aMirrorPoint.y;
1545 mirrored.y = -mirrored.y;
1546 mirrored.y += aMirrorPoint.y;
1547
1548 return mirrored;
1549}
1550
1551
1555static void mirrorPadX( PAD& aPad, const VECTOR2I& aMirrorPoint )
1556{
1557 if( aPad.GetShape() == PAD_SHAPE::CUSTOM )
1558 aPad.FlipPrimitives( true ); // mirror primitives left to right
1559
1560 VECTOR2I tmpPt = mirrorPointX( aPad.GetPosition(), aMirrorPoint );
1561 aPad.SetPosition( tmpPt );
1562
1563 aPad.SetX0( aPad.GetPosition().x );
1564
1565 tmpPt = aPad.GetOffset();
1566 tmpPt.x = -tmpPt.x;
1567 aPad.SetOffset( tmpPt );
1568
1569 auto tmpz = aPad.GetDelta();
1570 tmpz.x = -tmpz.x;
1571 aPad.SetDelta( tmpz );
1572
1573 aPad.SetOrientation( -aPad.GetOrientation() );
1574}
1575
1576
1580static void mirrorPadY( PAD& aPad, const VECTOR2I& aMirrorPoint )
1581{
1582 if( aPad.GetShape() == PAD_SHAPE::CUSTOM )
1583 aPad.FlipPrimitives( false ); // mirror primitives top to bottom
1584
1585 VECTOR2I tmpPt = mirrorPointY( aPad.GetPosition(), aMirrorPoint );
1586 aPad.SetPosition( tmpPt );
1587
1588 aPad.SetY0( aPad.GetPosition().y );
1589
1590 tmpPt = aPad.GetOffset();
1591 tmpPt.y = -tmpPt.y;
1592 aPad.SetOffset( tmpPt );
1593
1594 auto tmpz = aPad.GetDelta();
1595 tmpz.y = -tmpz.y;
1596 aPad.SetDelta( tmpz );
1597
1598 aPad.SetOrientation( -aPad.GetOrientation() );
1599}
1600
1601
1602const std::vector<KICAD_T> EDIT_TOOL::MirrorableItems = {
1606 PCB_TEXT_T,
1610 PCB_ZONE_T,
1611 PCB_PAD_T,
1613 PCB_ARC_T,
1614 PCB_VIA_T,
1615};
1616
1617int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
1618{
1619 if( isRouterActive() )
1620 {
1621 wxBell();
1622 return 0;
1623 }
1624
1626 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1627 {
1628 sTool->FilterCollectorForMarkers( aCollector );
1629 sTool->FilterCollectorForHierarchy( aCollector, true );
1630 sTool->FilterCollectorForFreePads( aCollector );
1631 },
1632 !m_dragging /* prompt user regarding locked items */ );
1633
1634 if( selection.Empty() )
1635 return 0;
1636
1638 VECTOR2I mirrorPoint = selection.GetReferencePoint();
1639
1640 // When editing footprints, all items have the same parent
1641 if( IsFootprintEditor() )
1642 m_commit->Modify( selection.Front() );
1643
1644 // Set the mirroring options.
1645 // Unfortunately, the mirror function do not have the same parameter for all items
1646 // So we need these 2 parameters to avoid mistakes
1647 bool mirrorLeftRight = true;
1648 bool mirrorAroundXaxis = false;
1649
1650 if( aEvent.IsAction( &PCB_ACTIONS::mirrorV ) )
1651 {
1652 mirrorLeftRight = false;
1653 mirrorAroundXaxis = true;
1654 }
1655
1656 for( EDA_ITEM* item : selection )
1657 {
1658 if( !item->IsType( MirrorableItems ) )
1659 continue;
1660
1661 if( !item->IsNew() && !IsFootprintEditor() )
1662 m_commit->Modify( item );
1663
1664 // modify each object as necessary
1665 switch( item->Type() )
1666 {
1667 case PCB_FP_SHAPE_T:
1668 case PCB_SHAPE_T:
1669 static_cast<PCB_SHAPE*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1670 break;
1671
1672 case PCB_FP_ZONE_T:
1673 case PCB_ZONE_T:
1674 static_cast<FP_ZONE*>( item )->Mirror( mirrorPoint, mirrorLeftRight );
1675 break;
1676
1677 case PCB_FP_TEXT_T:
1678 static_cast<FP_TEXT*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1679 break;
1680
1681 case PCB_TEXT_T:
1682 static_cast<PCB_TEXT*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1683 break;
1684
1685 case PCB_FP_TEXTBOX_T:
1686 static_cast<FP_TEXTBOX*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1687 break;
1688
1689 case PCB_TEXTBOX_T:
1690 static_cast<PCB_TEXTBOX*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1691 break;
1692
1693 case PCB_PAD_T:
1694 if( mirrorLeftRight )
1695 mirrorPadX( *static_cast<PAD*>( item ), mirrorPoint );
1696 else
1697 mirrorPadY( *static_cast<PAD*>( item ), mirrorPoint );
1698
1699 break;
1700
1701 case PCB_TRACE_T:
1702 case PCB_ARC_T:
1703 case PCB_VIA_T:
1704 static_cast<PCB_TRACK*>( item )->Mirror( mirrorPoint, mirrorAroundXaxis );
1705 break;
1706
1707 default:
1708 // it's likely the commit object is wrong if you get here
1709 // Unsure if PCB_GROUP_T needs special attention here.
1710 assert( false );
1711 break;
1712 }
1713 }
1714
1715 if( !m_dragging )
1716 m_commit->Push( _( "Mirror" ) );
1717
1718 if( selection.IsHover() && !m_dragging )
1720
1722
1723 if( m_dragging )
1725
1726 return 0;
1727}
1728
1729
1730int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
1731{
1732 if( isRouterActive() )
1733 {
1734 wxBell();
1735 return 0;
1736 }
1737
1739 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1740 {
1741 sTool->FilterCollectorForMarkers( aCollector );
1742 sTool->FilterCollectorForHierarchy( aCollector, true );
1743 sTool->FilterCollectorForFreePads( aCollector );
1744 },
1745 !m_dragging /* prompt user regarding locked items */ );
1746
1747 if( selection.Empty() )
1748 return 0;
1749
1750 std::optional<VECTOR2I> oldRefPt;
1751
1753 oldRefPt = selection.GetReferencePoint();
1754
1756
1757 // Flip around the anchor for footprints, and the bounding box center for board items
1758 VECTOR2I refPt = IsFootprintEditor() ? VECTOR2I( 0, 0 ) : selection.GetCenter();
1759
1760 // If only one item selected, flip around the selection or item anchor point (instead
1761 // of the bounding box center) to avoid moving the item anchor
1762 if( selection.GetSize() == 1 )
1763 {
1765 refPt = selection.GetReferencePoint();
1766 else
1767 refPt = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) )->GetPosition();
1768 }
1769
1770 bool leftRight = frame()->GetPcbNewSettings()->m_FlipLeftRight;
1771
1772 // When editing footprints, all items have the same parent
1773 if( IsFootprintEditor() )
1774 m_commit->Modify( selection.Front() );
1775
1776 for( EDA_ITEM* item : selection )
1777 {
1778 if( !item->IsNew() && !IsFootprintEditor() )
1779 m_commit->Modify( item );
1780
1781 if( item->Type() == PCB_GROUP_T )
1782 {
1783 static_cast<PCB_GROUP*>( item )->RunOnDescendants( [&]( BOARD_ITEM* bItem )
1784 {
1785 m_commit->Modify( bItem );
1786 });
1787 }
1788
1789 static_cast<BOARD_ITEM*>( item )->Flip( refPt, leftRight );
1790 }
1791
1792 if( !m_dragging )
1793 m_commit->Push( _( "Change Side / Flip" ) );
1794
1795 if( selection.IsHover() && !m_dragging )
1797
1799
1800 if( m_dragging )
1802
1803 // Restore the old reference so any mouse dragging that occurs doesn't make the selection jump
1804 // to this now invalid reference
1805 if( oldRefPt )
1806 selection.SetReferencePoint( *oldRefPt );
1807 else
1809
1810 return 0;
1811}
1812
1813
1814void EDIT_TOOL::DeleteItems( const PCB_SELECTION& aItems, bool aIsCut )
1815{
1816 // As we are about to remove items, they have to be removed from the selection first
1818
1819 for( EDA_ITEM* item : aItems )
1820 {
1821 PCB_GROUP* parentGroup = static_cast<BOARD_ITEM*>( item )->GetParentGroup();
1822
1823 if( parentGroup )
1824 {
1825 m_commit->Modify( parentGroup );
1826 parentGroup->RemoveItem( static_cast<BOARD_ITEM*>( item ) );
1827 }
1828
1829 switch( item->Type() )
1830 {
1831 case PCB_FP_TEXT_T:
1832 {
1833 FP_TEXT* text = static_cast<FP_TEXT*>( item );
1834 FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1835
1836 switch( text->GetType() )
1837 {
1840 m_commit->Modify( parent );
1841 text->SetVisible( false );
1842 getView()->Update( text );
1843 break;
1845 m_commit->Modify( parent );
1846 getView()->Remove( text );
1847 parent->Remove( text );
1848 break;
1849 default:
1850 wxFAIL; // Shouldn't get here
1851 break;
1852 }
1853
1854 break;
1855 }
1856
1857 case PCB_FP_TEXTBOX_T:
1858 {
1859 FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
1860 FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1861
1862 m_commit->Modify( parent );
1863 getView()->Remove( textbox );
1864 parent->Remove( textbox );
1865 break;
1866 }
1867
1868 case PCB_BITMAP_T:
1869 if( IsFootprintEditor() )
1870 {
1871 PCB_BITMAP* fp_bitmap = static_cast<PCB_BITMAP*>( item );
1872 FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1873
1874 m_commit->Modify( parent );
1875 getView()->Remove( fp_bitmap );
1876 parent->Remove( fp_bitmap );
1877 }
1878 else
1879 m_commit->Remove( item );
1880
1881 break;
1882
1883 case PCB_PAD_T:
1884 if( IsFootprintEditor() || frame()->GetPcbNewSettings()->m_AllowFreePads )
1885 {
1886 PAD* pad = static_cast<PAD*>( item );
1887 FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1888
1889 m_commit->Modify( parent );
1890 getView()->Remove( pad );
1891 parent->Remove( pad );
1892 }
1893
1894 break;
1895
1896 case PCB_FP_ZONE_T:
1897 {
1898 FP_ZONE* zone = static_cast<FP_ZONE*>( item );
1899 FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1900
1901 m_commit->Modify( parent );
1902 getView()->Remove( zone );
1903 parent->Remove( zone );
1904 break;
1905 }
1906
1907 case PCB_ZONE_T:
1908 // We process the zones special so that cutouts can be deleted when the delete tool
1909 // is called from inside a cutout when the zone is selected.
1910 {
1911 // Only interact with cutouts when deleting and a single item is selected
1912 if( !aIsCut && aItems.GetSize() == 1 )
1913 {
1915 ZONE* zone = static_cast<ZONE*>( item );
1916
1917 int outlineIdx, holeIdx;
1918
1919 if( zone->HitTestCutout( curPos, &outlineIdx, &holeIdx ) )
1920 {
1921 // Remove the cutout
1922 m_commit->Modify( zone );
1923 zone->RemoveCutout( outlineIdx, holeIdx );
1924 zone->UnFill();
1925
1926 // TODO Refill zone when KiCad supports auto re-fill
1927
1928 // Update the display
1929 zone->HatchBorder();
1930 canvas()->Refresh();
1931
1932 // Restore the selection on the original zone
1934
1935 break;
1936 }
1937 }
1938
1939 // Remove the entire zone otherwise
1940 m_commit->Remove( item );
1941 break;
1942 }
1943
1944 case PCB_GROUP_T:
1945 {
1946 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
1947
1948 auto removeItem =
1949 [&]( BOARD_ITEM* bItem )
1950 {
1951 if( bItem->GetParent() && bItem->GetParent()->Type() == PCB_FOOTPRINT_T )
1952 {
1953 // Silently ignore delete of Reference or Value if they happen to be
1954 // in group.
1955 if( bItem->Type() == PCB_FP_TEXT_T )
1956 {
1957 FP_TEXT* textItem = static_cast<FP_TEXT*>( bItem );
1958
1959 if( textItem->GetType() != FP_TEXT::TEXT_is_DIVERS )
1960 return;
1961 }
1962 else if( bItem->Type() == PCB_PAD_T )
1963 {
1964 if( !IsFootprintEditor()
1966 {
1967 return;
1968 }
1969 }
1970
1971 m_commit->Modify( bItem->GetParent() );
1972 getView()->Remove( bItem );
1973 bItem->GetParent()->Remove( bItem );
1974 }
1975 else
1976 {
1977 m_commit->Remove( bItem );
1978 }
1979 };
1980
1981 removeItem( group );
1982
1983 group->RunOnDescendants( [&]( BOARD_ITEM* aDescendant )
1984 {
1985 removeItem( aDescendant );
1986 });
1987 break;
1988 }
1989
1990 default:
1991 m_commit->Remove( item );
1992 break;
1993 }
1994 }
1995
1996 // If the entered group has been emptied then leave it.
1997 PCB_GROUP* enteredGroup = m_selectionTool->GetEnteredGroup();
1998
1999 if( enteredGroup && enteredGroup->GetItems().empty() )
2001
2002 if( aIsCut )
2003 m_commit->Push( _( "Cut" ) );
2004 else
2005 m_commit->Push( _( "Delete" ) );
2006}
2007
2008
2009int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
2010{
2011 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2012
2013 if( isRouterActive() )
2014 {
2016 return 0;
2017 }
2018
2019 editFrame->PushTool( aEvent );
2020
2021 std::vector<BOARD_ITEM*> lockedItems;
2022 Activate();
2023
2024 // get a copy instead of reference (as we're going to clear the selection before removing items)
2025 PCB_SELECTION selectionCopy;
2028
2029 // If we are in a "Cut" operation, then the copied selection exists already and we want to
2030 // delete exactly that; no more, no fewer. Any filtering for locked items must be done in
2031 // the copyToClipboard() routine.
2032 if( isCut )
2033 {
2034 selectionCopy = m_selectionTool->GetSelection();
2035 }
2036 else
2037 {
2038 // When not in free-pad mode we normally auto-promote selected pads to their parent
2039 // footprints. But this is probably a little too dangerous for a destructive operation,
2040 // so we just do the promotion but not the deletion (allowing for a second delete to do
2041 // it if that's what the user wanted).
2042 selectionCopy = m_selectionTool->RequestSelection(
2043 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2044 {
2045 } );
2046
2047 size_t beforeFPCount = selectionCopy.CountType( PCB_FOOTPRINT_T );
2048
2050 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2051 {
2052 sTool->FilterCollectorForFreePads( aCollector );
2053 } );
2054
2055 if( !selectionCopy.IsHover()
2056 && m_selectionTool->GetSelection().CountType( PCB_FOOTPRINT_T ) > beforeFPCount )
2057 {
2058 wxBell();
2059 canvas()->Refresh();
2060 editFrame->PopTool( aEvent );
2061 return 0;
2062 }
2063
2064 // In "alternative" mode, we expand selected track items to their full connection.
2065 if( isAlt && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
2066 {
2068 }
2069
2070 // Finally run RequestSelection() one more time to find out what user wants to do about
2071 // locked objects.
2072 selectionCopy = m_selectionTool->RequestSelection(
2073 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2074 {
2075 sTool->FilterCollectorForFreePads( aCollector );
2076 },
2077 true /* prompt user regarding locked items */ );
2078 }
2079
2080 DeleteItems( selectionCopy, isCut );
2081
2082 editFrame->PopTool( aEvent );
2083 return 0;
2084}
2085
2086
2088{
2089 if( isRouterActive() )
2090 {
2091 wxBell();
2092 return 0;
2093 }
2094
2096 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2097 {
2098 sTool->FilterCollectorForMarkers( aCollector );
2099 sTool->FilterCollectorForHierarchy( aCollector, true );
2100 },
2101 true /* prompt user regarding locked items */ );
2102
2103 if( selection.Empty() )
2104 return 0;
2105
2106 VECTOR2I translation;
2107 EDA_ANGLE rotation;
2110
2111 // TODO: Implement a visible bounding border at the edge
2112 BOX2I sel_box = selection.GetBoundingBox();
2113
2114 DIALOG_MOVE_EXACT dialog( frame(), translation, rotation, rotationAnchor, sel_box );
2115 int ret = dialog.ShowModal();
2116
2117 if( ret == wxID_OK )
2118 {
2119 EDA_ANGLE angle = rotation;
2121 VECTOR2I selCenter( rp.x, rp.y );
2122
2123 // Make sure the rotation is from the right reference point
2124 selCenter += translation;
2125
2126 if( !frame()->GetPcbNewSettings()->m_Display.m_DisplayInvertYAxis )
2127 rotation = -rotation;
2128
2129 // When editing footprints, all items have the same parent
2130 if( IsFootprintEditor() )
2131 m_commit->Modify( selection.Front() );
2132
2133 for( EDA_ITEM* selItem : selection )
2134 {
2135 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selItem );
2136
2137 if( !item->IsNew() && !IsFootprintEditor() )
2138 {
2139 m_commit->Modify( item );
2140
2141 if( item->Type() == PCB_GROUP_T )
2142 {
2143 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
2144
2145 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
2146 {
2147 m_commit->Modify( bItem );
2148 });
2149 }
2150 }
2151
2152 if( !item->GetParent() || !item->GetParent()->IsSelected() )
2153 item->Move( translation );
2154
2155 switch( rotationAnchor )
2156 {
2158 item->Rotate( item->GetPosition(), angle );
2159 break;
2161 item->Rotate( selCenter, angle );
2162 break;
2164 item->Rotate( frame()->GetScreen()->m_LocalOrigin, angle );
2165 break;
2168 break;
2169 }
2170
2171 if( !m_dragging )
2172 getView()->Update( item );
2173 }
2174
2175 m_commit->Push( _( "Move exact" ) );
2176
2177 if( selection.IsHover() )
2179
2181
2182 if( m_dragging )
2184 }
2185
2186 return 0;
2187}
2188
2189
2191{
2192 if( isRouterActive() )
2193 {
2194 wxBell();
2195 return 0;
2196 }
2197
2198 bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement );
2199
2200 // Be sure that there is at least one item that we can modify
2202 []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2203 {
2204 sTool->FilterCollectorForMarkers( aCollector );
2205 sTool->FilterCollectorForHierarchy( aCollector, true );
2206 } );
2207
2208 if( selection.Empty() )
2209 return 0;
2210
2211 // we have a selection to work on now, so start the tool process
2212 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2213
2214 // If the selection was given a hover, we do not keep the selection after completion
2215 bool is_hover = selection.IsHover();
2216
2217 std::vector<BOARD_ITEM*> new_items;
2218 new_items.reserve( selection.Size() );
2219
2220 // Each selected item is duplicated and pushed to new_items list
2221 // Old selection is cleared, and new items are then selected.
2222 for( EDA_ITEM* item : selection )
2223 {
2224 BOARD_ITEM* dupe_item = nullptr;
2225 BOARD_ITEM* orig_item = static_cast<BOARD_ITEM*>( item );
2226
2228 {
2229 FOOTPRINT* parentFootprint = editFrame->GetBoard()->GetFirstFootprint();
2230 dupe_item = parentFootprint->DuplicateItem( orig_item );
2231
2232 if( increment && dupe_item->Type() == PCB_PAD_T
2233 && static_cast<PAD*>( dupe_item )->CanHaveNumber() )
2234 {
2235 PAD_TOOL* padTool = m_toolMgr->GetTool<PAD_TOOL>();
2236 wxString padNumber = padTool->GetLastPadNumber();
2237 padNumber = parentFootprint->GetNextPadNumber( padNumber );
2238 padTool->SetLastPadNumber( padNumber );
2239 static_cast<PAD*>( dupe_item )->SetNumber( padNumber );
2240 }
2241 }
2242 else if( orig_item->GetParent() && orig_item->GetParent()->Type() == PCB_FOOTPRINT_T )
2243 {
2244 FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( orig_item->GetParent() );
2245
2246 m_commit->Modify( parentFootprint );
2247 dupe_item = parentFootprint->DuplicateItem( orig_item, true /* add to parent */ );
2248 }
2249 else
2250 {
2251 switch( orig_item->Type() )
2252 {
2253 case PCB_FOOTPRINT_T:
2254 case PCB_TEXT_T:
2255 case PCB_TEXTBOX_T:
2256 case PCB_BITMAP_T:
2257 case PCB_SHAPE_T:
2258 case PCB_TRACE_T:
2259 case PCB_ARC_T:
2260 case PCB_VIA_T:
2261 case PCB_ZONE_T:
2262 case PCB_TARGET_T:
2263 case PCB_DIM_ALIGNED_T:
2264 case PCB_DIM_CENTER_T:
2265 case PCB_DIM_RADIAL_T:
2267 case PCB_DIM_LEADER_T:
2268 dupe_item = orig_item->Duplicate();
2269 break;
2270
2271 case PCB_GROUP_T:
2272 dupe_item = static_cast<PCB_GROUP*>( orig_item )->DeepDuplicate();
2273 break;
2274
2275 default:
2276 wxASSERT_MSG( false, wxString::Format( wxT( "Unhandled item type %d" ),
2277 orig_item->Type() ) );
2278 break;
2279 }
2280 }
2281
2282 if( dupe_item )
2283 {
2284 if( dupe_item->Type() == PCB_GROUP_T )
2285 {
2286 static_cast<PCB_GROUP*>( dupe_item )->RunOnDescendants(
2287 [&]( BOARD_ITEM* bItem )
2288 {
2289 m_commit->Add( bItem );
2290 });
2291 }
2292
2293 // Clear the selection flag here, otherwise the PCB_SELECTION_TOOL
2294 // will not properly select it later on
2295 dupe_item->ClearSelected();
2296
2297 new_items.push_back( dupe_item );
2298 m_commit->Add( dupe_item );
2299 }
2300 }
2301
2302 // Clear the old selection first
2304
2305 // Select the new items
2306 m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &new_items );
2307
2308 // record the new items as added
2309 if( !selection.Empty() )
2310 {
2311 editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ),
2312 (int) new_items.size() ) );
2313
2314 // TODO(ISM): This line can't be used to activate the tool until we allow multiple
2315 // activations.
2316 // m_toolMgr->RunAction( PCB_ACTIONS::move, true );
2317 // Instead we have to create the event and call the tool's function
2318 // directly
2319
2320 // If items were duplicated, pick them up
2321 // this works well for "dropping" copies around and pushes the commit
2323 Move( evt );
2324
2325 // Deslect the duplicated item if we originally started as a hover selection
2326 if( is_hover )
2328 }
2329
2330 return 0;
2331}
2332
2333
2335{
2336 if( isRouterActive() )
2337 {
2338 wxBell();
2339 return 0;
2340 }
2341
2342 // Be sure that there is at least one item that we can modify
2344 []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2345 {
2346 sTool->FilterCollectorForMarkers( aCollector );
2347 sTool->FilterCollectorForHierarchy( aCollector, true );
2348 } );
2349
2350 if( selection.Empty() )
2351 return 0;
2352
2353 // we have a selection to work on now, so start the tool process
2354 PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
2355 ARRAY_CREATOR array_creator( *editFrame, m_isFootprintEditor, selection, m_toolMgr );
2356 array_creator.Invoke();
2357
2358 return 0;
2359}
2360
2361
2363 PCB_SELECTION_TOOL* sTool )
2364{
2365 for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
2366 {
2367 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( aCollector[i] );
2368
2369 if( item->Type() != PCB_PAD_T )
2370 aCollector.Remove( i );
2371 }
2372}
2373
2374
2376 PCB_SELECTION_TOOL* sTool )
2377{
2378 for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
2379 {
2380 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( aCollector[i] );
2381
2382 if( item->Type() != PCB_FOOTPRINT_T )
2383 aCollector.Remove( i );
2384 }
2385}
2386
2387
2389{
2390 if( m_dragging && aSelection.HasReferencePoint() )
2391 return false;
2392
2393 // Can't modify an empty group
2394 if( aSelection.Empty() )
2395 return false;
2396
2397 // When there is only one item selected, the reference point is its position...
2398 if( aSelection.Size() == 1 )
2399 {
2400 auto item = static_cast<BOARD_ITEM*>( aSelection.Front() );
2401 auto pos = item->GetPosition();
2402 aSelection.SetReferencePoint( VECTOR2I( pos.x, pos.y ) );
2403 }
2404 // ...otherwise modify items with regard to the grid-snapped center position
2405 else
2406 {
2407 PCB_GRID_HELPER grid( m_toolMgr, frame()->GetMagneticItemsSettings() );
2408 aSelection.SetReferencePoint( grid.BestSnapAnchor( aSelection.GetCenter(), nullptr ) );
2409 }
2410
2411 return true;
2412}
2413
2414
2415bool EDIT_TOOL::pickReferencePoint( const wxString& aTooltip, const wxString& aSuccessMessage,
2416 const wxString& aCanceledMessage, VECTOR2I& aReferencePoint )
2417{
2419 std::optional<VECTOR2I> pickedPoint;
2420 bool done = false;
2421
2422 m_statusPopup->SetText( aTooltip );
2423
2425 picker->SetSnapping( true );
2426
2427 picker->SetClickHandler(
2428 [&]( const VECTOR2D& aPoint ) -> bool
2429 {
2430 pickedPoint = aPoint;
2431
2432 if( !aSuccessMessage.empty() )
2433 {
2434 m_statusPopup->SetText( aSuccessMessage );
2435 m_statusPopup->Expire( 800 );
2436 }
2437 else
2438 {
2439 m_statusPopup->Hide();
2440 }
2441
2442 return false; // we don't need any more points
2443 } );
2444
2445 picker->SetMotionHandler(
2446 [&]( const VECTOR2D& aPos )
2447 {
2448 m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
2449 } );
2450
2451 picker->SetCancelHandler(
2452 [&]()
2453 {
2454 if( !aCanceledMessage.empty() )
2455 {
2456 m_statusPopup->SetText( aCanceledMessage );
2457 m_statusPopup->Expire( 800 );
2458 }
2459 else
2460 {
2461 m_statusPopup->Hide();
2462 }
2463 } );
2464
2465 picker->SetFinalizeHandler(
2466 [&]( const int& aFinalState )
2467 {
2468 done = true;
2469 } );
2470
2471 m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
2472 m_statusPopup->Popup();
2473 canvas()->SetStatusPopup( m_statusPopup->GetPanel() );
2474
2476
2477 while( !done )
2478 {
2479 // Pass events unless we receive a null event, then we must shut down
2480 if( TOOL_EVENT* evt = Wait() )
2481 evt->SetPassEvent();
2482 else
2483 break;
2484 }
2485
2486 // Ensure statusPopup is hidden after use and before deleting it:
2487 canvas()->SetStatusPopup( nullptr );
2488 m_statusPopup->Hide();
2489
2490 if( pickedPoint )
2491 aReferencePoint = *pickedPoint;
2492
2493 return pickedPoint.has_value();
2494}
2495
2496
2498{
2499 CLIPBOARD_IO io;
2501 getEditFrame<PCB_BASE_EDIT_FRAME>()->GetMagneticItemsSettings() );
2502 TOOL_EVENT selectReferencePoint( aEvent.Category(), aEvent.Action(),
2503 "pcbnew.InteractiveEdit.selectReferencePoint",
2505
2506 frame()->PushTool( selectReferencePoint );
2507 Activate();
2508
2510 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2511 {
2512 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
2513 {
2514 BOARD_ITEM* item = aCollector[i];
2515
2516 // We can't copy both a footprint and its text in the same operation, so if
2517 // both are selected, remove the text
2518 if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
2519 aCollector.Remove( item );
2520 }
2521 },
2522
2523 // Prompt user regarding locked items.
2524 aEvent.IsAction( &ACTIONS::cut ) && !m_isFootprintEditor );
2525
2526 if( !selection.Empty() )
2527 {
2528 std::vector<BOARD_ITEM*> items;
2529
2530 for( EDA_ITEM* item : selection )
2531 items.push_back( static_cast<BOARD_ITEM*>( item ) );
2532
2533 VECTOR2I refPoint;
2534
2536 {
2537 if( !pickReferencePoint( _( "Select reference point for the copy..." ),
2538 _( "Selection copied" ),
2539 _( "Copy canceled" ),
2540 refPoint ) )
2541 {
2542 frame()->PopTool( selectReferencePoint );
2543 return 0;
2544 }
2545 }
2546 else
2547 {
2548 refPoint = grid.BestDragOrigin( getViewControls()->GetCursorPosition(), items );
2549 }
2550
2551 selection.SetReferencePoint( refPoint );
2552
2553 io.SetBoard( board() );
2555 frame()->SetStatusText( _( "Selection copied" ) );
2556 }
2557
2558 frame()->PopTool( selectReferencePoint );
2559
2560 if( selection.IsHover() )
2562
2563 return 0;
2564}
2565
2566
2568{
2569 if( !copyToClipboard( aEvent ) )
2570 {
2571 // N.B. Setting the CUT flag prevents lock filtering as we only want to delete the items
2572 // that were copied to the clipboard, no more, no fewer. Filtering for locked item, if
2573 // any will be done in the copyToClipboard() routine
2574 TOOL_EVENT evt = aEvent;
2576 Remove( evt );
2577 }
2578
2579 return 0;
2580}
2581
2582
2584{
2588}
2589
2590
2592{
2594 Go( &EDIT_TOOL::Move, PCB_ACTIONS::move.MakeEvent() );
2600 Go( &EDIT_TOOL::Flip, PCB_ACTIONS::flip.MakeEvent() );
2601 Go( &EDIT_TOOL::Remove, ACTIONS::doDelete.MakeEvent() );
2609 Go( &EDIT_TOOL::Mirror, PCB_ACTIONS::mirrorH.MakeEvent() );
2610 Go( &EDIT_TOOL::Mirror, PCB_ACTIONS::mirrorV.MakeEvent() );
2611 Go( &EDIT_TOOL::Swap, PCB_ACTIONS::swap.MakeEvent() );
2616
2619 Go( &EDIT_TOOL::cutToClipboard, ACTIONS::cut.MakeEvent() );
2620}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
@ special_tools
static TOOL_ACTION paste
Definition: actions.h:69
static TOOL_ACTION pickerSubTool
Definition: actions.h:159
static TOOL_ACTION copy
Definition: actions.h:68
static TOOL_ACTION pasteSpecial
Definition: actions.h:70
static TOOL_ACTION pageSettings
Definition: actions.h:56
@ CURSOR_CLICK
Definition: actions.h:191
static TOOL_ACTION undo
Definition: actions.h:65
static TOOL_ACTION duplicate
Definition: actions.h:72
static TOOL_ACTION doDelete
Definition: actions.h:73
REMOVE_FLAGS
Definition: actions.h:195
static TOOL_ACTION cut
Definition: actions.h:67
static TOOL_ACTION selectAll
Definition: actions.h:71
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
VECTOR2D m_LocalOrigin
Relative Screen cursor coordinate (on grid) in user units.
Definition: base_screen.h:90
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.
const VECTOR2I & GetAuxOrigin()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
void SetParentGroup(PCB_GROUP *aGroup)
Definition: board_item.h:71
void SwapItemData(BOARD_ITEM *aImage)
Swap data between aItem and aImage.
Definition: board_item.cpp:166
virtual void SetLocked(bool aLocked)
Definition: board_item.h:254
virtual void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle)
Rotate this object.
Definition: board_item.cpp:250
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:184
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:266
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:185
virtual bool IsLocked() const
Definition: board_item.cpp:71
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:163
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:583
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:162
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:397
bool IsEmpty() const
Definition: board.h:355
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:686
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:424
const Vec & GetPosition() const
Definition: box2.h:184
const Vec GetEnd() const
Definition: box2.h:185
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
Represent basic circle geometry with utility geometry functions.
Definition: circle.h:33
VECTOR2I Center
Public to make access simpler.
Definition: circle.h:116
int Radius
Public to make access simpler.
Definition: circle.h:115
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...
Definition: circle.cpp:51
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute the point on the circumference of the circle that is the closest to aP.
Definition: circle.cpp:197
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
void SetBoard(BOARD *aBoard)
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
int ShowQuasiModal()
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
Update the board display after modifying it by a python script (note: it is automatically called by a...
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:249
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:139
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearSelected()
Definition: eda_item.h:118
bool IsSelected() const
Definition: eda_item.h:106
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:254
bool IsNew() const
Definition: eda_item.h:103
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:247
SHAPE_T GetShape() const
Definition: eda_shape.h:113
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:124
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
int GetWidth() const
Definition: eda_shape.h:109
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:149
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
Definition: eda_shape.cpp:555
void SetWidth(int aWidth)
Definition: eda_shape.h:108
bool isRouterActive() const
Definition: edit_tool.cpp:327
int Drag(const TOOL_EVENT &aEvent)
Invoke the PNS router to drag tracks or do an offline resizing of an arc track if a single arc track ...
Definition: edit_tool.cpp:335
int Flip(const TOOL_EVENT &aEvent)
Rotate currently selected items.
Definition: edit_tool.cpp:1730
int Duplicate(const TOOL_EVENT &aEvent)
Duplicate the current selection and starts a move action.
Definition: edit_tool.cpp:2190
int FilletLines(const TOOL_EVENT &aEvent)
Fillet (i.e.
Definition: edit_tool.cpp:1058
int Swap(const TOOL_EVENT &aEvent)
Swap currently selected items' positions.
int PackAndMoveFootprints(const TOOL_EVENT &aEvent)
Try to fit selected footprints inside a minimal area and start movement.
int Mirror(const TOOL_EVENT &aEvent)
Mirror the current selection.
Definition: edit_tool.cpp:1617
int CreateArray(const TOOL_EVENT &aEvent)
Create an array of the selected items, invoking the array editor dialog to set the options.
Definition: edit_tool.cpp:2334
bool pickReferencePoint(const wxString &aTooltip, const wxString &aSuccessMessage, const wxString &aCanceledMessage, VECTOR2I &aReferencePoint)
Rebuilds the ratsnest for operations that require it outside the commit rebuild.
Definition: edit_tool.cpp:2415
bool Init() override
Init() is called once upon a registration of the tool.
Definition: edit_tool.cpp:105
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: edit_tool.cpp:81
void DeleteItems(const PCB_SELECTION &aItems, bool aIsCut)
Definition: edit_tool.cpp:1814
bool m_dragging
Definition: edit_tool.h:211
int MoveExact(const TOOL_EVENT &aEvent)
Invoke a dialog box to allow moving of the item by an exact amount.
Definition: edit_tool.cpp:2087
int Move(const TOOL_EVENT &aEvent)
Main loop in which events are handled.
static const unsigned int COORDS_PADDING
Definition: edit_tool.h:216
std::unique_ptr< BOARD_COMMIT > m_commit
Definition: edit_tool.h:210
bool updateModificationPoint(PCB_SELECTION &aSelection)
Definition: edit_tool.cpp:2388
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
Definition: edit_tool.h:214
int DragArcTrack(const TOOL_EVENT &aTrack)
Drag-resize an arc (and change end points of connected straight segments).
Definition: edit_tool.cpp:419
int copyToClipboard(const TOOL_EVENT &aEvent)
Send the current selection to the clipboard by formatting it as a fake pcb see #AppendBoardFromClipbo...
Definition: edit_tool.cpp:2497
int Remove(const TOOL_EVENT &aEvent)
Delete currently selected items.
Definition: edit_tool.cpp:2009
int cutToClipboard(const TOOL_EVENT &aEvent)
Cut the current selection to the clipboard by formatting it as a fake pcb see #AppendBoardFromClipboa...
Definition: edit_tool.cpp:2567
static const std::vector< KICAD_T > MirrorableItems
Definition: edit_tool.h:114
static void PadFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type PCB_PAD_T.
Definition: edit_tool.cpp:2362
VECTOR2I m_cursor
Definition: edit_tool.h:212
bool invokeInlineRouter(int aDragMode)
Definition: edit_tool.cpp:297
void rebuildConnectivity()
Definition: edit_tool.cpp:2583
void setTransitions() override
< Set up handlers for various events.
Definition: edit_tool.cpp:2591
int ChangeTrackWidth(const TOOL_EVENT &aEvent)
Definition: edit_tool.cpp:784
int GetAndPlace(const TOOL_EVENT &aEvent)
Definition: edit_tool.cpp:274
int FilletTracks(const TOOL_EVENT &aEvent)
Fillet (i.e.
Definition: edit_tool.cpp:854
PCB_SELECTION_TOOL * m_selectionTool
Definition: edit_tool.h:209
int Properties(const TOOL_EVENT &aEvent)
Display properties window for the selected object.
Definition: edit_tool.cpp:1338
static void FootprintFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type #PCB_MODULE_T.
Definition: edit_tool.cpp:2375
int Rotate(const TOOL_EVENT &aEvent)
Rotate currently selected items.
Definition: edit_tool.cpp:1398
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
Definition: actions.h:210
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:207
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:627
BOARD_ITEM * DuplicateItem(const BOARD_ITEM *aItem, bool aAddToFootprint=false)
Duplicate a given item within the footprint, optionally adding it to the board.
Definition: footprint.cpp:1870
wxString GetNextPadNumber(const wxString &aLastPadName) const
Return the next available pad number in the footprint.
Definition: footprint.cpp:1982
@ TEXT_is_REFERENCE
Definition: fp_text.h:49
@ TEXT_is_DIVERS
Definition: fp_text.h:51
@ TEXT_is_VALUE
Definition: fp_text.h:50
TEXT_TYPE GetType() const
Definition: fp_text.h:120
A specialization of ZONE for use in footprints.
Definition: zone.h:910
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
Definition: collectors.h:270
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.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:349
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...
Definition: view.cpp:1591
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:410
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:47
int GetuViaDrill() const
Definition: netclass.h:92
int GetuViaDiameter() const
Definition: netclass.h:88
Tool relating to pads and pad settings.
Definition: pad_tool.h:37
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:66
wxString GetLastPadNumber() const
Definition: pad_tool.h:65
Definition: pad.h:59
void SetX0(int x)
Definition: pad.h:254
void FlipPrimitives(bool aFlipLeftRight)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
Definition: pad.cpp:776
VECTOR2I GetPosition() const override
Definition: pad.h:202
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:273
void SetY0(int y)
Definition: pad.h:253
const VECTOR2I & GetOffset() const
Definition: pad.h:274
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:263
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:196
const VECTOR2I & GetDelta() const
Definition: pad.h:264
PAD_SHAPE GetShape() const
Definition: pad.h:194
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:370
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:709
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:166
static TOOL_ACTION duplicateIncrement
Activation of the duplication tool with incrementing (e.g. pad number)
Definition: pcb_actions.h:155
static TOOL_ACTION routerUndoLastSegment
Definition: pcb_actions.h:222
static TOOL_ACTION changeTrackWidth
Update selected tracks & vias to the current track & via dimensions.
Definition: pcb_actions.h:142
static TOOL_ACTION unrouteSelected
Removes all tracks from the selected items to the first pad.
Definition: pcb_actions.h:83
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:129
static TOOL_ACTION updateFootprint
Definition: pcb_actions.h:364
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:164
static TOOL_ACTION getAndPlace
Find an item and start moving.
Definition: pcb_actions.h:514
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:149
static TOOL_ACTION editFpInFpEditor
Definition: pcb_actions.h:386
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION moveWithReference
move with a reference point
Definition: pcb_actions.h:116
static TOOL_ACTION swap
Swapping of selected items.
Definition: pcb_actions.h:133
static TOOL_ACTION moveExact
Activation of the exact move tool.
Definition: pcb_actions.h:152
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:80
static TOOL_ACTION assignNetClass
Definition: pcb_actions.h:340
static TOOL_ACTION packAndMoveFootprints
Pack and start moving selected footprints.
Definition: pcb_actions.h:136
static TOOL_ACTION copyWithReference
copy command with manual reference point selection
Definition: pcb_actions.h:119
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:167
static TOOL_ACTION inspectClearance
Definition: pcb_actions.h:492
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:508
static TOOL_ACTION deleteFull
Definition: pcb_actions.h:159
static TOOL_ACTION moveIndividually
move items one-by-one
Definition: pcb_actions.h:113
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:62
static TOOL_ACTION filletTracks
Fillet (i.e. adds an arc tangent to) all selected straight tracks by a user defined radius.
Definition: pcb_actions.h:145
static TOOL_ACTION footprintProperties
Definition: pcb_actions.h:420
static TOOL_ACTION filletLines
Definition: pcb_actions.h:146
static TOOL_ACTION changeFootprint
Definition: pcb_actions.h:366
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:242
static TOOL_ACTION positionRelative
Activation of the position relative tool.
Definition: pcb_actions.h:269
static TOOL_ACTION skip
Definition: pcb_actions.h:139
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:110
static TOOL_ACTION mirrorV
Definition: pcb_actions.h:130
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:126
static TOOL_ACTION createArray
Tool for creating an array of objects.
Definition: pcb_actions.h:435
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:122
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:123
void SetMid(const VECTOR2I &aMid)
Definition: pcb_track.h:311
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1152
const VECTOR2I & GetMid() const
Definition: pcb_track.h:312
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:321
Common, abstract interface for edit frames.
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
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.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
Object to handle a bitmap image that can be inserted in a PCB.
Definition: pcb_bitmap.h:42
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).
Definition: pcb_group.h:51
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
bool RemoveItem(BOARD_ITEM *aItem)
Remove item from group.
Definition: pcb_group.cpp:95
Generic tool for picking an item.
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
PCB_GROUP * GetEnteredGroup()
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
int ClearSelection(const TOOL_EVENT &aEvent)
PCB_SELECTION & GetSelection()
void ExitGroup(bool aSelectGroup=false)
Leave the currently-entered group.
bool IsFootprintEditor() const
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
void SetWidth(int aWidth)
Definition: pcb_track.h:106
virtual double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
Definition: pcb_track.cpp:315
int GetWidth() const
Definition: pcb_track.h:107
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:109
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:112
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point,...
Definition: pcb_track.cpp:237
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:82
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:71
void SetSnapping(bool aSnap)
Definition: picker_tool.h:64
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:91
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:102
POSITIONING_TOOLS_MENU(TOOL_INTERACTIVE *aTool)
Definition: edit_tool.cpp:92
bool RoutingInProgress()
Returns whether routing is currently active.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:261
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:210
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
Definition: seg.cpp:382
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition: seg.cpp:302
SEG PerpendicularSeg(const VECTOR2I &aP) const
Compute a segment perpendicular to this one, passing through point aP.
Definition: seg.cpp:199
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
EDA_ANGLE Angle(const SEG &aOther) const
Determine the smallest angle between two segments.
Definition: seg.cpp:97
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 bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
VECTOR2I GetReferencePoint() const
Definition: selection.h:252
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition: selection.cpp:93
bool IsHover() const
Definition: selection.h:83
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
Definition: selection.cpp:144
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
void ClearReferencePoint()
Definition: selection.h:265
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:260
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
bool HasReferencePoint() const
Definition: selection.h:247
size_t CountType(KICAD_T aType) const
Definition: selection.cpp:156
bool Contains(EDA_ITEM *aItem) const
Definition: selection.cpp:84
virtual BOX2I GetBoundingBox() const
Definition: selection.cpp:133
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
Definition: shape.h:128
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
bool IsCurrentTool(const TOOL_ACTION &aAction) const
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.cpp:72
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool IsToolActive() const
Definition: tool_base.cpp:31
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
Generic, UI-independent tool event.
Definition: tool_event.h:156
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
TOOL_ACTIONS Action() const
These give a tool a method of informing the TOOL_MANAGER that a particular event should be passed on ...
Definition: tool_event.h:233
void SetParameter(T aParam)
Set a non-standard parameter assigned to the event.
Definition: tool_event.h:460
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:230
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
An extension of WX_TEXT_ENTRY_DIALOG that uses UNIT_BINDER to request a dimension (e....
long long GetValue()
Returns the value in internal units.
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
bool UnFill()
Removes the zone filling.
Definition: zone.cpp:209
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.
Definition: zone.cpp:496
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:855
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition: zone.cpp:714
ROTATION_ANCHOR
@ ROTATE_AROUND_USER_ORIGIN
@ ROTATE_AROUND_SEL_CENTER
@ ROTATE_AROUND_AUX_ORIGIN
@ ROTATE_AROUND_ITEM_ANCHOR
#define _(s)
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:427
@ DEGREES_T
Definition: eda_angle.h:31
#define IS_NEW
New item, just created.
static VECTOR2I mirrorPointY(const VECTOR2I &aPoint, const VECTOR2I &aMirrorPoint)
Mirror a point about the vertical axis passing through another point.
Definition: edit_tool.cpp:1540
static void mirrorPadX(PAD &aPad, const VECTOR2I &aMirrorPoint)
Mirror a pad in the vertical axis passing through a point (mirror left to right).
Definition: edit_tool.cpp:1555
static VECTOR2I mirrorPointX(const VECTOR2I &aPoint, const VECTOR2I &aMirrorPoint)
Mirror a point about the vertical axis passing through another point.
Definition: edit_tool.cpp:1525
static void mirrorPadY(PAD &aPad, const VECTOR2I &aMirrorPoint)
Mirror a pad in the vertical axis passing through a point (mirror left to right).
Definition: edit_tool.cpp:1580
static std::vector< KICAD_T > connectedTypes
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ LAYER_DRAWINGSHEET
drawingsheet frame and titleblock
Definition: layer_ids.h:217
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition: layer_ids.h:382
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
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.
Definition: eda_units.cpp:326
static ROUTER * theRouter
Definition: pns_router.cpp:58
@ DM_ANY
Definition: pns_router.h:77
@ DM_FREE_ANGLE
Definition: pns_router.h:75
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Function GetModel creates an S3DMODEL representation of aNode (raw data, no transforms)
Definition: ifsg_api.cpp:338
EDA_ANGLE GetEventRotationAngle(const PCB_BASE_EDIT_FRAME &aFrame, const TOOL_EVENT &aEvent)
Function getEventRotationAngle()
void for_all_pairs(_InputIterator __first, _InputIterator __last, _Function __f)
Apply a function to every possible pair of elements of a sequence.
Definition: kicad_algo.h:83
BOARD * GetBoard()
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
const double IU_PER_MM
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition: tool_action.h:45
@ BUT_LEFT
Definition: tool_event.h:127
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.
Definition: trigo.cpp:163
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:188
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:110
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:91
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:112
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:111
@ PCB_SHAPE_LOCATE_SEGMENT_T
Definition: typeinfo.h:131
@ PCB_SHAPE_LOCATE_RECT_T
Definition: typeinfo.h:132
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:106
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_BITMAP_T
class PCB_BITMAP, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_SHAPE_LOCATE_POLY_T
Definition: typeinfo.h:135
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618