KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pad_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) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
25#include "pad_tool.h"
26#include "pcb_painter.h"
27#include <kiplatform/ui.h>
28#include <macros.h>
30#include <view/view_controls.h>
31#include <tool/tool_manager.h>
33#include <board_item.h>
34#include <footprint.h>
35#include <pcb_shape.h>
36#include <pad.h>
37#include <pcbnew_settings.h>
38#include <board_commit.h>
40#include <tools/pcb_actions.h>
44#include <tools/edit_tool.h>
46#include <widgets/wx_infobar.h>
47
48
50
51
53 PCB_TOOL_BASE( "pcbnew.PadTool" ),
54 m_wasHighContrast( false ),
55 m_editPad( niluuid )
56{}
57
58
60{}
61
62
64{
65 if( aReason == MODEL_RELOAD )
66 m_lastPadNumber = wxT( "1" );
67
68 if( board() && board()->GetItem( m_editPad ) == DELETED_BOARD_ITEM::GetInstance() )
69 {
71 bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
72
73 if( m_wasHighContrast != highContrast )
75
76 frame()->GetInfoBar()->Dismiss();
77
79 }
80}
81
82
84{
86
87 if( selTool )
88 {
89 // Add context menu entries that are displayed when selection tool is active
90 CONDITIONAL_MENU& menu = selTool->GetToolMenu().GetMenu();
91
95
96 auto explodeCondition =
97 [&]( const SELECTION& aSel )
98 {
99 return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
100 };
101
102 auto recombineCondition =
103 [&]( const SELECTION& aSel )
104 {
105 return m_editPad != niluuid;
106 };
107
108 menu.AddSeparator( 400 );
109
111 {
113 menu.AddItem( PCB_ACTIONS::recombinePad, recombineCondition, 400 );
114 menu.AddItem( PCB_ACTIONS::explodePad, explodeCondition, 400 );
115 }
116
117 menu.AddItem( PCB_ACTIONS::copyPadSettings, singlePadSel, 400 );
118 menu.AddItem( PCB_ACTIONS::applyPadSettings, padSel, 400 );
119 menu.AddItem( PCB_ACTIONS::pushPadSettings, singlePadSel, 400 );
120 }
121
122 auto& ctxMenu = m_menu.GetMenu();
123
124 // cancel current tool goes in main context menu at the top if present
126 ctxMenu.AddSeparator( 1 );
127
134
135 // Finally, add the standard zoom/grid items
136 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
137
138 return true;
139}
140
141
143{
145 const PCB_SELECTION& selection = selTool->GetSelection();
146 const PAD* masterPad = frame()->GetDesignSettings().m_Pad_Master.get();
147
148 BOARD_COMMIT commit( frame() );
149
150 // for every selected pad, paste global settings
151 for( EDA_ITEM* item : selection )
152 {
153 if( item->Type() == PCB_PAD_T )
154 {
155 commit.Modify( item );
156 static_cast<PAD&>( *item ).ImportSettingsFrom( *masterPad );
157 }
158 }
159
160 commit.Push( _( "Paste Pad Properties" ) );
161
163 frame()->Refresh();
164
165 return 0;
166}
167
168
170{
172 const PCB_SELECTION& selection = selTool->GetSelection();
173
174 // can only copy from a single pad
175 if( selection.Size() == 1 )
176 {
177 EDA_ITEM* item = selection[0];
178
179 if( item->Type() == PCB_PAD_T )
180 {
181 const PAD& selPad = static_cast<const PAD&>( *item );
182 frame()->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( selPad );
183 }
184 }
185
186 return 0;
187}
188
189
190static void doPushPadProperties( BOARD& board, const PAD& aSrcPad, BOARD_COMMIT& commit,
191 bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter,
192 bool aPadLayerFilter, bool aPadTypeFilter )
193{
194 const FOOTPRINT* refFootprint = aSrcPad.GetParentFootprint();
195
196 EDA_ANGLE srcPadAngle = aSrcPad.GetOrientation() - refFootprint->GetOrientation();
197
198 for( FOOTPRINT* footprint : board.Footprints() )
199 {
200 if( !aSameFootprints && ( footprint != refFootprint ) )
201 continue;
202
203 if( footprint->GetFPID() != refFootprint->GetFPID() )
204 continue;
205
206 for( PAD* pad : footprint->Pads() )
207 {
208 if( aPadShapeFilter && ( pad->GetShape() != aSrcPad.GetShape() ) )
209 continue;
210
211 EDA_ANGLE padAngle = pad->GetOrientation() - footprint->GetOrientation();
212
213 if( aPadOrientFilter && ( padAngle != srcPadAngle ) )
214 continue;
215
216 if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
217 continue;
218
219 if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
220 continue;
221
222 // Special-case for aperture pads
223 if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
224 {
225 if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
226 continue;
227 }
228
229 commit.Modify( pad );
230
231 // Apply source pad settings to this pad
232 pad->ImportSettingsFrom( aSrcPad );
233 }
234 }
235}
236
237
239{
241 const PCB_SELECTION& selection = selTool->GetSelection();
242
243 if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
244 {
245 PAD* srcPad = static_cast<PAD*>( selection[0] );
246
247 if( FOOTPRINT* footprint = srcPad->GetParentFootprint() )
248 {
250
252 int dialogRet = dlg.ShowModal();
253
254 if( dialogRet == wxID_CANCEL )
255 return 0;
256
257 const bool edit_Same_Modules = (dialogRet == 1);
258
259 BOARD_COMMIT commit( frame() );
260
261 doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules,
266
267 commit.Push( _( "Push Pad Settings" ) );
268
270 frame()->Refresh();
271 }
272 }
273
274 return 0;
275}
276
277
284static std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS>
286{
287 // Persistent settings for the pad enumeration dialog.
288 static SEQUENTIAL_PAD_ENUMERATION_PARAMS s_lastUsedParams;
289
290 DIALOG_ENUM_PADS settingsDlg( aFrame, s_lastUsedParams );
291
292 if( settingsDlg.ShowModal() != wxID_OK )
293 return std::nullopt;
294
295 return s_lastUsedParams;
296}
297
298
300{
302 return 0;
303
304 if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
305 return 0;
306
307 GENERAL_COLLECTOR collector;
309 guide.SetIgnoreMTextsMarkedNoShow( true );
310 guide.SetIgnoreMTextsOnBack( true );
311 guide.SetIgnoreMTextsOnFront( true );
312 guide.SetIgnoreModulesVals( true );
313 guide.SetIgnoreModulesRefs( true );
314
315 const std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS> params =
317
318 // Cancelled or otherwise failed to get any useful parameters
319 if( !params )
320 return 0;
321
322 int seqPadNum = params->m_start_number;
323
324 std::deque<int> storedPadNumbers;
325 std::map<wxString, std::pair<int, wxString>> oldNumbers;
326
328
329 frame()->PushTool( aEvent );
330
331 VECTOR2I oldCursorPos; // store the previous mouse cursor position, during mouse drag
332 std::list<PAD*> selectedPads;
333 BOARD_COMMIT commit( frame() );
334 bool isFirstPoint = true; // make sure oldCursorPos is initialized at least once
335 PADS pads = board()->GetFirstFootprint()->Pads();
336
337 MAGNETIC_SETTINGS mag_settings;
338 mag_settings.graphics = false;
339 mag_settings.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
340 mag_settings.pads = MAGNETIC_OPTIONS::CAPTURE_ALWAYS;
341 PCB_GRID_HELPER grid( m_toolMgr, &mag_settings );
342
343 grid.SetSnap( true );
344 grid.SetUseGrid( false );
345
346 auto setCursor =
347 [&]()
348 {
349 canvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
350 };
351
352 Activate();
353 // Must be done after Activate() so that it gets set into the correct context
354 getViewControls()->ShowCursor( true );
356 // Set initial cursor
357 setCursor();
358
359 STATUS_TEXT_POPUP statusPopup( frame() );
360
361 // Callable lambda to construct the pad number string for the given value
362 const auto constructPadNumber = [&]( int aValue )
363 {
364 return wxString::Format( wxT( "%s%d" ), params->m_prefix.value_or( "" ), aValue );
365 };
366
367 // Callable lambda to set the popup text for the given pad value
368 const auto setPopupTextForValue = [&]( int aValue )
369 {
370 const wxString msg =
371 _( "Click on pad %s\nPress <esc> to cancel all; double-click to finish" );
372 statusPopup.SetText( wxString::Format( msg, constructPadNumber( aValue ) ) );
373 };
374
375 setPopupTextForValue( seqPadNum );
376 statusPopup.Popup();
377 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
378 canvas()->SetStatusPopup( statusPopup.GetPanel() );
379
380 while( TOOL_EVENT* evt = Wait() )
381 {
382 setCursor();
383
384 VECTOR2I cursorPos = grid.AlignToNearestPad( getViewControls()->GetMousePosition(), pads );
385 getViewControls()->ForceCursorPosition( true, cursorPos );
386
387 if( evt->IsCancelInteractive() )
388 {
390 commit.Revert();
391
392 frame()->PopTool( aEvent );
393 break;
394 }
395 else if( evt->IsActivate() )
396 {
397 commit.Push( _( "Renumber pads" ) );
398
399 frame()->PopTool( aEvent );
400 break;
401 }
402 else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
403 {
404 selectedPads.clear();
405
406 // Be sure the old cursor mouse position was initialized:
407 if( isFirstPoint )
408 {
409 oldCursorPos = cursorPos;
410 isFirstPoint = false;
411 }
412
413 // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
414 // pads if the user moves cursor too fast. To solve it, create a line that approximates
415 // the mouse move and search pads that are on the line.
416 int distance = ( cursorPos - oldCursorPos ).EuclideanNorm();
417 // Search will be made every 0.1 mm:
418 int segments = distance / int( 0.1 * pcbIUScale.IU_PER_MM ) + 1;
419 const VECTOR2I line_step( ( cursorPos - oldCursorPos ) / segments );
420
421 collector.Empty();
422
423 for( int j = 0; j < segments; ++j )
424 {
425 VECTOR2I testpoint( cursorPos.x - j * line_step.x, cursorPos.y - j * line_step.y );
426 collector.Collect( board(), { PCB_PAD_T }, testpoint, guide );
427
428 for( int i = 0; i < collector.GetCount(); ++i )
429 selectedPads.push_back( static_cast<PAD*>( collector[i] ) );
430 }
431
432 selectedPads.unique();
433
434 for( PAD* pad : selectedPads )
435 {
436 // If pad was not selected, then enumerate it
437 if( !pad->IsSelected() )
438 {
439 commit.Modify( pad );
440
441 // Rename pad and store the old name
442 int newval;
443
444 if( storedPadNumbers.size() > 0 )
445 {
446 newval = storedPadNumbers.front();
447 storedPadNumbers.pop_front();
448 }
449 else
450 {
451 newval = seqPadNum;
452 seqPadNum += params->m_step;
453 }
454
455 const wxString newNumber = constructPadNumber( newval );
456 oldNumbers[newNumber] = { newval, pad->GetNumber() };
457 pad->SetNumber( newNumber );
458 SetLastPadNumber( newNumber );
459 pad->SetSelected();
460 getView()->Update( pad );
461
462 // Ensure the popup text shows the correct next value
463 if( storedPadNumbers.size() > 0 )
464 newval = storedPadNumbers.front();
465 else
466 newval = seqPadNum;
467
468 setPopupTextForValue( newval );
469 }
470
471 // ... or restore the old name if it was enumerated and clicked again
472 else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
473 {
474 auto it = oldNumbers.find( pad->GetNumber() );
475 wxASSERT( it != oldNumbers.end() );
476
477 if( it != oldNumbers.end() )
478 {
479 storedPadNumbers.push_back( it->second.first );
480 pad->SetNumber( it->second.second );
481 SetLastPadNumber( it->second.second );
482 oldNumbers.erase( it );
483
484 const int newval = storedPadNumbers.front();
485 setPopupTextForValue( newval );
486 }
487
488 pad->ClearSelected();
489 getView()->Update( pad );
490 }
491 }
492 }
493 else if( evt->IsDblClick( BUT_LEFT ) )
494 {
495 commit.Push( _( "Renumber pads" ) );
496 frame()->PopTool( aEvent );
497 break;
498 }
499 else if( evt->IsClick( BUT_RIGHT ) )
500 {
502 }
503 else
504 {
505 evt->SetPassEvent();
506 }
507
508 // Prepare the next loop by updating the old cursor mouse position
509 // to this last mouse cursor position
510 oldCursorPos = getViewControls()->GetCursorPosition();
511 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
512 }
513
514 for( PAD* p : board()->GetFirstFootprint()->Pads() )
515 {
516 p->ClearSelected();
517 getView()->Update( p );
518 }
519
520 canvas()->SetStatusPopup( nullptr );
521 statusPopup.Hide();
522
523 canvas()->SetCurrentCursor( KICURSOR::ARROW );
525 return 0;
526}
527
528
529int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
530{
532 return 0;
533
534 if( !board()->GetFirstFootprint() )
535 return 0;
536
537 struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
538 {
539 PAD_PLACER( PAD_TOOL* aPadTool )
540 {
541 m_padTool = aPadTool;
542 }
543
544 virtual ~PAD_PLACER()
545 {
546 }
547
548 std::unique_ptr<BOARD_ITEM> CreateItem() override
549 {
550 PAD* pad = new PAD( m_board->GetFirstFootprint() );
551 PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
552
553 pad->ImportSettingsFrom( *master );
554
555 // If the footprint type and master pad type directly conflict then make some
556 // adjustments. Otherwise assume the user set what they wanted.
557 if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
558 && master->GetAttribute() == PAD_ATTRIB::PTH )
559 {
560 pad->SetAttribute( PAD_ATTRIB::SMD );
561 pad->SetShape( PAD_SHAPE::ROUNDRECT );
562 pad->SetSizeX( 1.5 * pad->GetSizeY() );
563 pad->SetLayerSet( PAD::SMDMask() );
564 }
565 else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
566 && master->GetAttribute() == PAD_ATTRIB::SMD )
567 {
568 pad->SetAttribute( PAD_ATTRIB::PTH );
569 pad->SetShape( PAD_SHAPE::CIRCLE );
570 pad->SetSize( VECTOR2I( pad->GetSizeX(), pad->GetSizeX() ) );
571 pad->SetLayerSet( PAD::PTHMask() );
572 }
573
574 if( pad->CanHaveNumber() )
575 {
576 wxString padNumber = m_padTool->GetLastPadNumber();
577 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
578 pad->SetNumber( padNumber );
579 m_padTool->SetLastPadNumber( padNumber );
580 }
581
582 return std::unique_ptr<BOARD_ITEM>( pad );
583 }
584
585 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
586 {
587 PAD* pad = dynamic_cast<PAD*>( aItem );
588
589 if( pad )
590 {
591 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
592 aCommit.Add( aItem );
593 return true;
594 }
595
596 return false;
597 }
598
599 PAD_TOOL* m_padTool;
600 };
601
602 PAD_PLACER placer( this );
603
604 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
606
607 return 0;
608}
609
610
611int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
612{
614 return 0;
615
616 Activate();
617
619 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
620 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
622
623 if( m_editPad != niluuid )
624 {
625 PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
626
627 if( pad )
628 {
629 BOARD_COMMIT commit( frame() );
630 RecombinePad( pad, false, commit );
631 commit.Push( _( "Recombine pad" ) );
632 }
633
635 }
636 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
637 {
638 PAD* pad = static_cast<PAD*>( selection[0] );
639 PCB_LAYER_ID layer = explodePad( pad );
640
641 m_editPad = pad->m_Uuid;
642
643 m_wasHighContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
644 frame()->SetActiveLayer( layer );
645
646 settings->m_PadEditModePad = pad;
648 }
649
650 if( m_editPad == niluuid )
651 {
652 settings->m_PadEditModePad = nullptr;
654 }
655
656 return 0;
657}
658
659
661{
662 PAD* flaggedPad = nullptr;
663 KIID flaggedPadId = niluuid;
664
665 for( FOOTPRINT* fp : board()->Footprints() )
666 {
667 for( PAD* pad : fp->Pads() )
668 {
669 if( pad->IsEntered() )
670 {
671 flaggedPad = pad;
672 flaggedPadId = pad->m_Uuid;
673 break;
674 }
675 }
676 }
677
678 if( flaggedPadId != m_editPad )
679 {
680 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
681 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
682
683 m_editPad = flaggedPadId;
684 settings->m_PadEditModePad = flaggedPad;
685
686 if( flaggedPad )
688 else
690 }
691
692 return 0;
693}
694
695
697{
699 bool highContrast = opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL;
700 WX_INFOBAR* infoBar = frame()->GetInfoBar();
701 wxString msg;
702
704 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
705 {
706 return dynamic_cast<PAD*>( aItem ) != nullptr;
707 } );
708
709 if( !highContrast )
711
713 {
714 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
716 }
717 else
718 {
719 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
721 }
722
723 infoBar->RemoveAllButtons();
724 infoBar->ShowMessage( msg, wxICON_INFORMATION );
725}
726
727
729{
731 bool highContrast = opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL;
732
733 if( m_wasHighContrast != highContrast )
735
736 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
737 // they won't be found in the view layer's itemset for re-painting.
739 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
740 {
741 return dynamic_cast<PAD*>( aItem ) != nullptr;
742 } );
743
744 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
745 // closes before refresh).
746 canvas()->ForceRefresh();
747
748 frame()->GetInfoBar()->Dismiss();
749}
750
751
753{
754 PCB_LAYER_ID layer;
755 BOARD_COMMIT commit( frame() );
756
757 if( aPad->IsOnLayer( F_Cu ) )
758 layer = F_Cu;
759 else if( aPad->IsOnLayer( B_Cu ) )
760 layer = B_Cu;
761 else
762 layer = *aPad->GetLayerSet().UIOrder();
763
764 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
765 {
766 commit.Modify( aPad );
767
768 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
769 {
770 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate() );
771
772 shape->SetParent( board()->GetFirstFootprint() );
773 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
774 shape->Move( aPad->ShapePos() );
775 shape->SetLayer( layer );
776
777 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
778 {
779 if( aPad->GetThermalSpokeWidth() )
780 shape->SetWidth( aPad->GetThermalSpokeWidth() );
781 else
783 }
784
785 commit.Add( shape );
786 }
787
788 aPad->SetShape( aPad->GetAnchorPadShape() );
789 aPad->DeletePrimitivesList();
790 }
791
792 aPad->SetFlags( ENTERED );
793 m_editPad = aPad->m_Uuid;
794
795 commit.Push( _("Edit pad shapes") );
797 return layer;
798}
799
800
801std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun, BOARD_COMMIT& aCommit )
802{
803 int maxError = board()->GetDesignSettings().m_MaxError;
805
806 // Don't leave an object in the point editor that might no longer exist after recombining.
808
809 for( BOARD_ITEM* item : footprint->GraphicalItems() )
810 item->ClearFlags( SKIP_STRUCT );
811
812 auto findNext =
813 [&]( PCB_LAYER_ID aLayer ) -> PCB_SHAPE*
814 {
815 SHAPE_POLY_SET padPoly;
816 aPad->TransformShapeToPolygon( padPoly, aLayer, 0, maxError, ERROR_INSIDE );
817
818 for( BOARD_ITEM* item : footprint->GraphicalItems() )
819 {
820 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
821
822 if( !shape || ( shape->GetFlags() & SKIP_STRUCT ) )
823 continue;
824
825 if( shape->GetLayer() != aLayer )
826 continue;
827
828 if( shape->IsProxyItem() ) // Pad number (and net name) box
829 return shape;
830
831 SHAPE_POLY_SET drawPoly;
832 shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
833 drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
834
835 if( !drawPoly.IsEmpty() )
836 return shape;
837 }
838
839 return nullptr;
840 };
841
842 auto findMatching =
843 [&]( PCB_SHAPE* aShape ) -> std::vector<PCB_SHAPE*>
844 {
845 std::vector<PCB_SHAPE*> matching;
846
847 for( BOARD_ITEM* item : footprint->GraphicalItems() )
848 {
849 PCB_SHAPE* other = dynamic_cast<PCB_SHAPE*>( item );
850
851 if( !other || ( other->GetFlags() & SKIP_STRUCT ) )
852 continue;
853
854 if( aPad->GetLayerSet().test( other->GetLayer() )
855 && aShape->Compare( other ) == 0 )
856 {
857 matching.push_back( other );
858 }
859 }
860
861 return matching;
862 };
863
864 PCB_LAYER_ID layer;
865 std::vector<PCB_SHAPE*> mergedShapes;
866
867 if( aPad->IsOnLayer( F_Cu ) )
868 layer = F_Cu;
869 else if( aPad->IsOnLayer( B_Cu ) )
870 layer = B_Cu;
871 else
872 layer = *aPad->GetLayerSet().UIOrder();
873
874 // If there are intersecting items to combine, we need to first make sure the pad is a
875 // custom-shape pad.
876 if( !aIsDryRun && findNext( layer ) && aPad->GetShape() != PAD_SHAPE::CUSTOM )
877 {
878 aCommit.Modify( aPad );
879
880 if( aPad->GetShape() == PAD_SHAPE::CIRCLE || aPad->GetShape() == PAD_SHAPE::RECTANGLE )
881 {
882 // Use the existing pad as an anchor
883 aPad->SetAnchorPadShape( aPad->GetShape() );
884 aPad->SetShape( PAD_SHAPE::CUSTOM );
885 }
886 else
887 {
888 // Create a new circular anchor and convert existing pad to a polygon primitive
889 SHAPE_POLY_SET existingOutline;
890 aPad->TransformShapeToPolygon( existingOutline, layer, 0, maxError, ERROR_INSIDE );
891
892 int minExtent = std::min( aPad->GetSize().x, aPad->GetSize().y );
893 aPad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
894 aPad->SetSize( VECTOR2I( minExtent, minExtent ) );
895 aPad->SetShape( PAD_SHAPE::CUSTOM );
896
897 PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
898 shape->SetFilled( true );
899 shape->SetStroke( STROKE_PARAMS( 0, PLOT_DASH_TYPE::SOLID ) );
900 shape->SetPolyShape( existingOutline );
901 shape->Rotate( VECTOR2I( 0, 0 ), - aPad->GetOrientation() );
902 shape->Move( - aPad->ShapePos() );
903 aPad->AddPrimitive( shape );
904 }
905 }
906
907 while( PCB_SHAPE* fpShape = findNext( layer ) )
908 {
909 fpShape->SetFlags( SKIP_STRUCT );
910
911 mergedShapes.push_back( fpShape );
912
913 if( !aIsDryRun )
914 {
915 PCB_SHAPE* primitive = static_cast<PCB_SHAPE*>( fpShape->Duplicate() );
916
917 primitive->SetParent( nullptr );
918 primitive->Move( - aPad->ShapePos() );
919 primitive->Rotate( VECTOR2I( 0, 0 ), - aPad->GetOrientation() );
920
921 aPad->AddPrimitive( primitive );
922
923 aCommit.Remove( fpShape );
924 }
925
926 // See if there are other shapes that match and mark them for delete. (KiCad won't
927 // produce these, but old footprints from other vendors have them.)
928 for( PCB_SHAPE* other : findMatching( fpShape ) )
929 {
930 other->SetFlags( SKIP_STRUCT );
931 mergedShapes.push_back( other );
932
933 if( !aIsDryRun )
934 aCommit.Remove( other );
935 }
936 }
937
938 for( BOARD_ITEM* item : footprint->GraphicalItems() )
939 item->ClearFlags( SKIP_STRUCT );
940
941 if( !aIsDryRun )
942 aPad->ClearFlags( ENTERED );
943
944 return mergedShapes;
945}
946
947
949{
953
956
959
961}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION highContrastMode
Definition: actions.h:107
virtual void Revert() override
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
std::unique_ptr< PAD > m_Pad_Master
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:247
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:271
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:406
FOOTPRINTS & Footprints()
Definition: board.h:313
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:731
void Empty()
Clear the list.
Definition: collector.h:89
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition: commit.h:90
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:78
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.
static DELETED_BOARD_ITEM * GetInstance()
Definition: board_item.h:400
Dialog for enumerating pads.
WX_INFOBAR * GetInfoBar()
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void ForceRefresh()
Force a redraw.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
const KIID m_Uuid
Definition: eda_item.h:482
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:126
void SetFilled(bool aFlag)
Definition: eda_shape.h:96
SHAPE_T GetShape() const
Definition: eda_shape.h:117
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:264
void SetWidth(int aWidth)
Definition: eda_shape.h:109
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:236
static const TOOL_EVENT UndoRedoPostEvent
Definition: actions.h:253
EDA_ANGLE GetOrientation() const
Definition: footprint.h:209
PADS & Pads()
Definition: footprint.h:188
const LIB_ID & GetFPID() const
Definition: footprint.h:230
DRAWINGS & GraphicalItems()
Definition: footprint.h:191
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:321
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:406
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:460
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:454
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:418
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:412
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:472
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:163
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
Definition: pcb_painter.h:168
PCB specific render settings.
Definition: pcb_painter.h:76
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.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:77
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:1608
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition: view.cpp:1511
Definition: kiid.h:49
LSEQ UIOrder() const
Definition: lset.cpp:922
Tool relating to pads and pad settings.
Definition: pad_tool.h:37
void Reset(RESET_REASON aReason) override
Basic initialization.
Definition: pad_tool.cpp:63
int OnUndoRedo(const TOOL_EVENT &aEvent)
Definition: pad_tool.cpp:660
~PAD_TOOL()
React to model/view changes.
Definition: pad_tool.cpp:59
bool m_wasHighContrast
Definition: pad_tool.h:100
void setTransitions() override
< Bind handlers to corresponding TOOL_ACTIONs.
Definition: pad_tool.cpp:948
void exitPadEditMode()
Definition: pad_tool.cpp:728
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:611
KIID m_editPad
Definition: pad_tool.h:101
int copyPadSettings(const TOOL_EVENT &aEvent)
Push pad settings from a pad to other pads on board or footprint.
Definition: pad_tool.cpp:169
void enterPadEditMode()
Definition: pad_tool.cpp:696
int pastePadProperties(const TOOL_EVENT &aEvent)
Copy pad settings from a pad to the board design settings.
Definition: pad_tool.cpp:142
int PlacePad(const TOOL_EVENT &aEvent)
Place a pad in footprint editor.
Definition: pad_tool.cpp:529
int EnumeratePads(const TOOL_EVENT &aEvent)
Tool for quick pad enumeration.
Definition: pad_tool.cpp:299
PAD_TOOL()
Definition: pad_tool.cpp:52
PCB_LAYER_ID explodePad(PAD *aPad)
Definition: pad_tool.cpp:752
bool Init() override
Init() is called once upon a registration of the tool.
Definition: pad_tool.cpp:83
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:68
wxString m_lastPadNumber
Definition: pad_tool.h:98
std::vector< PCB_SHAPE * > RecombinePad(PAD *aPad, bool aIsDryRun, BOARD_COMMIT &aCommit)
Recombine an exploded pad (or one produced with overlapping polygons in an older version).
Definition: pad_tool.cpp:801
int pushPadSettings(const TOOL_EVENT &aEvent)
Definition: pad_tool.cpp:238
Definition: pad.h:58
bool IsAperturePad() const
Definition: pad.h:379
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:369
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:602
PAD_ATTRIB GetAttribute() const
Definition: pad.h:372
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:194
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1578
void DeletePrimitivesList()
Clear the basic shapes list.
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:300
VECTOR2I ShapePos() const
Definition: pad.cpp:756
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1469
PAD_SHAPE GetShape() const
Definition: pad.h:189
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:341
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:201
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:180
int GetThermalSpokeWidth() const
Definition: pad.h:503
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:228
void AddPrimitive(PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:242
const VECTOR2I & GetSize() const
Definition: pad.h:243
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:202
static TOOL_ACTION recombinePad
Definition: pcb_actions.h:452
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
Definition: pcb_actions.h:455
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
Definition: pcb_actions.h:475
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:138
static TOOL_ACTION copyPadSettings
Copy the selected pad's settings to the board design settings.
Definition: pcb_actions.h:469
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
Definition: pcb_actions.h:449
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:164
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION explodePad
Definition: pcb_actions.h:451
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
Definition: pcb_actions.h:472
static TOOL_ACTION mirrorV
Definition: pcb_actions.h:139
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:135
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:131
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:132
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
EDA_ITEM * GetItem(const KIID &aId) const override
Fetch an item by KIID.
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
virtual void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:306
bool IsProxyItem() const override
Definition: pcb_shape.h:107
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:97
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:568
virtual void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:235
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:83
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:67
KIGFX::PCB_VIEW * view() const
PCB_BASE_EDIT_FRAME * frame() const
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
@ IPO_FLIP
Handle flip action in the loop by calling the item's flip method.
@ IPO_ROTATE
Handle the rotate action in the loop by calling the item's rotate method.
@ IPO_SINGLE_CLICK
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
@ IPO_REPEAT
Allow repeat placement of the item.
bool m_isFootprintEditor
void doInteractiveItemPlacement(const TOOL_EVENT &aTool, INTERACTIVE_PLACER_BASE *aPlacer, const wxString &aCommitMessage, int aOptions=IPO_ROTATE|IPO_FLIP|IPO_REPEAT)
Helper function for performing a common interactive idiom: wait for a left click, place an item there...
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
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 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 Size() const
Returns the number of selected parts.
Definition: selection.h:115
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
wxWindow * GetPanel()
Definition: status_popup.h:62
virtual void Popup(wxWindow *aFocus=nullptr)
virtual void Move(const wxPoint &aWhere)
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:83
void SetText(const wxString &aText)
Display a text.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
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.
int GetHotKey() const
Return the hotkey keycode which initiates the action.
Definition: tool_action.h:263
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:216
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:167
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_MENU m_menu
The functions below are not yet implemented - their interface may change.
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).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:145
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:75
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:301
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:187
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:154
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const std::vector< PCB_SHAPE * > &aList, unsigned aLimit)
Searches for a PCB_SHAPE matching a given end point or start point in a list.
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define ENTERED
indicates a group has been entered
#define SKIP_STRUCT
flag indicating that the structure should be ignored
@ FP_SMD
Definition: footprint.h:73
@ FP_THROUGH_HOLE
Definition: footprint.h:72
@ ERROR_INSIDE
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
KIID niluuid(0)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:96
@ F_Cu
Definition: layer_ids.h:65
This file contains miscellaneous commonly used macros and functions.
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:52
@ ALL
All except INITIAL_ADD.
Definition: view_item.h:53
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: gtk/ui.cpp:584
@ CONN
Like smd, does not appear on the solder paste layer (default)
static void doPushPadProperties(BOARD &board, const PAD &aSrcPad, BOARD_COMMIT &commit, bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter, bool aPadLayerFilter, bool aPadTypeFilter)
Definition: pad_tool.cpp:190
static std::optional< SEQUENTIAL_PAD_ENUMERATION_PARAMS > GetSequentialPadNumberingParams(wxWindow *aFrame)
Prompts the user for parameters for sequential pad numbering.
Definition: pad_tool.cpp:285
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.
const double IU_PER_MM
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
Parameters for sequential pad numbering.
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM
Definition: zones.h:34