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-2024 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_previousHighContrastMode( HIGH_CONTRAST_MODE::NORMAL ),
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
73 {
75 frame()->SetDisplayOptions( opts );
76 }
77
78 frame()->GetInfoBar()->Dismiss();
79
81 }
82}
83
84
86{
87 static const std::vector<KICAD_T> padTypes = { PCB_PAD_T };
88
90
91 if( selTool )
92 {
93 // Add context menu entries that are displayed when selection tool is active
94 CONDITIONAL_MENU& menu = selTool->GetToolMenu().GetMenu();
95
99
100 auto explodeCondition =
101 [&]( const SELECTION& aSel )
102 {
103 return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
104 };
105
106 auto recombineCondition =
107 [&]( const SELECTION& aSel )
108 {
109 return m_editPad != niluuid;
110 };
111
112 menu.AddSeparator( 400 );
113
115 {
117 menu.AddItem( PCB_ACTIONS::recombinePad, recombineCondition, 400 );
118 menu.AddItem( PCB_ACTIONS::explodePad, explodeCondition, 400 );
119 }
120
121 menu.AddItem( PCB_ACTIONS::copyPadSettings, singlePadSel, 400 );
122 menu.AddItem( PCB_ACTIONS::applyPadSettings, padSel, 400 );
123 menu.AddItem( PCB_ACTIONS::pushPadSettings, singlePadSel, 400 );
124 }
125
126 auto& ctxMenu = m_menu.GetMenu();
127
128 // cancel current tool goes in main context menu at the top if present
130 ctxMenu.AddSeparator( 1 );
131
138
139 // Finally, add the standard zoom/grid items
140 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
141
142 return true;
143}
144
145
147{
149 const PCB_SELECTION& selection = selTool->GetSelection();
150 const PAD* masterPad = frame()->GetDesignSettings().m_Pad_Master.get();
151
152 BOARD_COMMIT commit( frame() );
153
154 // for every selected pad, paste global settings
155 for( EDA_ITEM* item : selection )
156 {
157 if( item->Type() == PCB_PAD_T )
158 {
159 commit.Modify( item );
160 static_cast<PAD&>( *item ).ImportSettingsFrom( *masterPad );
161 }
162 }
163
164 commit.Push( _( "Paste Pad Properties" ) );
165
167 frame()->Refresh();
168
169 return 0;
170}
171
172
174{
176 const PCB_SELECTION& selection = selTool->GetSelection();
177
178 // can only copy from a single pad
179 if( selection.Size() == 1 )
180 {
181 EDA_ITEM* item = selection[0];
182
183 if( item->Type() == PCB_PAD_T )
184 {
185 const PAD& selPad = static_cast<const PAD&>( *item );
186 frame()->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( selPad );
187 }
188 }
189
190 return 0;
191}
192
193
194static void doPushPadProperties( BOARD& board, const PAD& aSrcPad, BOARD_COMMIT& commit,
195 bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter,
196 bool aPadLayerFilter, bool aPadTypeFilter )
197{
198 const FOOTPRINT* refFootprint = aSrcPad.GetParentFootprint();
199
200 EDA_ANGLE srcPadAngle = aSrcPad.GetOrientation() - refFootprint->GetOrientation();
201
202 for( FOOTPRINT* footprint : board.Footprints() )
203 {
204 if( !aSameFootprints && ( footprint != refFootprint ) )
205 continue;
206
207 if( footprint->GetFPID() != refFootprint->GetFPID() )
208 continue;
209
210 for( PAD* pad : footprint->Pads() )
211 {
212 if( aPadShapeFilter && ( pad->GetShape() != aSrcPad.GetShape() ) )
213 continue;
214
215 EDA_ANGLE padAngle = pad->GetOrientation() - footprint->GetOrientation();
216
217 if( aPadOrientFilter && ( padAngle != srcPadAngle ) )
218 continue;
219
220 if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
221 continue;
222
223 if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
224 continue;
225
226 // Special-case for aperture pads
227 if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
228 {
229 if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
230 continue;
231 }
232
233 commit.Modify( pad );
234
235 // Apply source pad settings to this pad
236 pad->ImportSettingsFrom( aSrcPad );
237 }
238 }
239}
240
241
243{
245 const PCB_SELECTION& selection = selTool->GetSelection();
246
247 if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
248 {
249 PAD* srcPad = static_cast<PAD*>( selection[0] );
250
251 if( FOOTPRINT* footprint = srcPad->GetParentFootprint() )
252 {
254
256 int dialogRet = dlg.ShowModal();
257
258 if( dialogRet == wxID_CANCEL )
259 return 0;
260
261 const bool edit_Same_Modules = (dialogRet == 1);
262
263 BOARD_COMMIT commit( frame() );
264
265 doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules,
270
271 commit.Push( _( "Push Pad Settings" ) );
272
274 frame()->Refresh();
275 }
276 }
277
278 return 0;
279}
280
281
288static std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS>
290{
291 // Persistent settings for the pad enumeration dialog.
292 static SEQUENTIAL_PAD_ENUMERATION_PARAMS s_lastUsedParams;
293
294 DIALOG_ENUM_PADS settingsDlg( aFrame, s_lastUsedParams );
295
296 if( settingsDlg.ShowModal() != wxID_OK )
297 return std::nullopt;
298
299 return s_lastUsedParams;
300}
301
302
304{
306 return 0;
307
308 if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
309 return 0;
310
311 GENERAL_COLLECTOR collector;
313 guide.SetIgnoreHiddenFPText( true );
314 guide.SetIgnoreFPTextOnBack( true );
315 guide.SetIgnoreFPTextOnFront( true );
316 guide.SetIgnoreFPValues( true );
317 guide.SetIgnoreFPReferences( true );
318
319 const std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS> params =
321
322 // Cancelled or otherwise failed to get any useful parameters
323 if( !params )
324 return 0;
325
326 int seqPadNum = params->m_start_number;
327
328 std::deque<int> storedPadNumbers;
329 std::map<wxString, std::pair<int, wxString>> oldNumbers;
330
332
333 frame()->PushTool( aEvent );
334
335 VECTOR2I oldCursorPos; // store the previous mouse cursor position, during mouse drag
336 std::list<PAD*> selectedPads;
337 BOARD_COMMIT commit( frame() );
338 bool isFirstPoint = true; // make sure oldCursorPos is initialized at least once
339 std::deque<PAD*> pads = board()->GetFirstFootprint()->Pads();
340 MAGNETIC_SETTINGS mag_settings;
341
342 mag_settings.graphics = false;
343 mag_settings.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
344 mag_settings.pads = MAGNETIC_OPTIONS::CAPTURE_ALWAYS;
345
346 PCB_GRID_HELPER grid( m_toolMgr, &mag_settings );
347
348 grid.SetSnap( true );
349 grid.SetUseGrid( false );
350
351 auto setCursor =
352 [&]()
353 {
354 canvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
355 };
356
358 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
359 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
360 bool isHighContrast = settings->GetHighContrast();
361
362 auto checkVisibility =
363 [&]( BOARD_ITEM* item )
364 {
365 if( !view->IsVisible( item ) )
366 return false;
367
368 bool onActiveLayer = !isHighContrast;
369 bool isLODVisible = false;
370
371 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
372 {
373 if( !onActiveLayer && activeLayers.count( layer ) )
374 onActiveLayer = true;
375
376 if( !isLODVisible && item->ViewGetLOD( layer, view ) < view->GetScale() )
377 isLODVisible = true;
378
379 if( onActiveLayer && isLODVisible )
380 return true;
381 }
382
383 return false;
384 };
385
386 Activate();
387 // Must be done after Activate() so that it gets set into the correct context
388 getViewControls()->ShowCursor( true );
390 // Set initial cursor
391 setCursor();
392
393 STATUS_TEXT_POPUP statusPopup( frame() );
394
395 // Callable lambda to construct the pad number string for the given value
396 const auto constructPadNumber =
397 [&]( int aValue )
398 {
399 return wxString::Format( wxT( "%s%d" ), params->m_prefix.value_or( "" ), aValue );
400 };
401
402 // Callable lambda to set the popup text for the given pad value
403 const auto setPopupTextForValue =
404 [&]( int aValue )
405 {
406 const wxString msg = _( "Click on pad %s\n"
407 "Press <esc> to cancel all; double-click to finish" );
408 statusPopup.SetText( wxString::Format( msg, constructPadNumber( aValue ) ) );
409 };
410
411 setPopupTextForValue( seqPadNum );
412 statusPopup.Popup();
413 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
414 canvas()->SetStatusPopup( statusPopup.GetPanel() );
415
416 while( TOOL_EVENT* evt = Wait() )
417 {
418 setCursor();
419
420 VECTOR2I cursorPos = grid.AlignToNearestPad( getViewControls()->GetMousePosition(), pads );
421 getViewControls()->ForceCursorPosition( true, cursorPos );
422
423 if( evt->IsCancelInteractive() )
424 {
426 commit.Revert();
427
428 frame()->PopTool( aEvent );
429 break;
430 }
431 else if( evt->IsActivate() )
432 {
433 commit.Push( _( "Renumber Pads" ) );
434
435 frame()->PopTool( aEvent );
436 break;
437 }
438 else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
439 {
440 selectedPads.clear();
441
442 // Be sure the old cursor mouse position was initialized:
443 if( isFirstPoint )
444 {
445 oldCursorPos = cursorPos;
446 isFirstPoint = false;
447 }
448
449 // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
450 // pads if the user moves cursor too fast. To solve it, create a line that approximates
451 // the mouse move and search pads that are on the line.
452 int distance = ( cursorPos - oldCursorPos ).EuclideanNorm();
453 // Search will be made every 0.1 mm:
454 int segments = distance / int( 0.1 * pcbIUScale.IU_PER_MM ) + 1;
455 const VECTOR2I line_step( ( cursorPos - oldCursorPos ) / segments );
456
457 collector.Empty();
458
459 for( int j = 0; j < segments; ++j )
460 {
461 VECTOR2I testpoint( cursorPos.x - j * line_step.x, cursorPos.y - j * line_step.y );
462 collector.Collect( board(), { PCB_PAD_T }, testpoint, guide );
463
464 for( int i = 0; i < collector.GetCount(); ++i )
465 {
466 PAD* pad = static_cast<PAD*>( collector[i] );
467
468 if( !pad->IsAperturePad() && checkVisibility( pad ) )
469 selectedPads.push_back( pad );
470 }
471 }
472
473 selectedPads.unique();
474
475 for( PAD* pad : selectedPads )
476 {
477 // If pad was not selected, then enumerate it
478 if( !pad->IsSelected() )
479 {
480 commit.Modify( pad );
481
482 // Rename pad and store the old name
483 int newval;
484
485 if( storedPadNumbers.size() > 0 )
486 {
487 newval = storedPadNumbers.front();
488 storedPadNumbers.pop_front();
489 }
490 else
491 {
492 newval = seqPadNum;
493 seqPadNum += params->m_step;
494 }
495
496 const wxString newNumber = constructPadNumber( newval );
497 oldNumbers[newNumber] = { newval, pad->GetNumber() };
498 pad->SetNumber( newNumber );
499 SetLastPadNumber( newNumber );
500 pad->SetSelected();
501 getView()->Update( pad );
502
503 // Ensure the popup text shows the correct next value
504 if( storedPadNumbers.size() > 0 )
505 newval = storedPadNumbers.front();
506 else
507 newval = seqPadNum;
508
509 setPopupTextForValue( newval );
510 }
511
512 // ... or restore the old name if it was enumerated and clicked again
513 else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
514 {
515 auto it = oldNumbers.find( pad->GetNumber() );
516 wxASSERT( it != oldNumbers.end() );
517
518 if( it != oldNumbers.end() )
519 {
520 storedPadNumbers.push_back( it->second.first );
521 pad->SetNumber( it->second.second );
522 SetLastPadNumber( it->second.second );
523 oldNumbers.erase( it );
524
525 const int newval = storedPadNumbers.front();
526 setPopupTextForValue( newval );
527 }
528
529 pad->ClearSelected();
530 getView()->Update( pad );
531 }
532 }
533 }
534 else if( evt->IsDblClick( BUT_LEFT ) )
535 {
536 commit.Push( _( "Renumber Pads" ) );
537 frame()->PopTool( aEvent );
538 break;
539 }
540 else if( evt->IsClick( BUT_RIGHT ) )
541 {
543 }
544 else
545 {
546 evt->SetPassEvent();
547 }
548
549 // Prepare the next loop by updating the old cursor mouse position
550 // to this last mouse cursor position
551 oldCursorPos = getViewControls()->GetCursorPosition();
552 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
553 }
554
555 for( PAD* p : board()->GetFirstFootprint()->Pads() )
556 {
557 p->ClearSelected();
558 getView()->Update( p );
559 }
560
561 canvas()->SetStatusPopup( nullptr );
562 statusPopup.Hide();
563
564 canvas()->SetCurrentCursor( KICURSOR::ARROW );
566 return 0;
567}
568
569
570int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
571{
572 // When creating a new pad (in FP editor) we can use a new pad number
573 // or the last entered pad number
574 // neednewPadNumber = true to create a new pad number, false to use the last
575 // entered pad number
576 static bool neednewPadNumber;
577
579 return 0;
580
581 if( !board()->GetFirstFootprint() )
582 return 0;
583
584 struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
585 {
586 PAD_PLACER( PAD_TOOL* aPadTool )
587 {
588 neednewPadNumber = true; // Use a new pad number when creatin a pad by default
589 m_padTool = aPadTool;
590 }
591
592 virtual ~PAD_PLACER()
593 {
594 }
595
596 std::unique_ptr<BOARD_ITEM> CreateItem() override
597 {
598 PAD* pad = new PAD( m_board->GetFirstFootprint() );
599 PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
600
601 pad->ImportSettingsFrom( *master );
602
603 // If the footprint type and master pad type directly conflict then make some
604 // adjustments. Otherwise assume the user set what they wanted.
605 // Note also a HEATSINK pad (thermal via) is allowed in SMD footprint
606 if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
607 && master->GetAttribute() == PAD_ATTRIB::PTH )
608 {
609 if( pad->GetProperty() != PAD_PROP::HEATSINK )
610 {
611 pad->SetAttribute( PAD_ATTRIB::SMD );
612 pad->SetShape( PAD_SHAPE::ROUNDRECT );
613 pad->SetSizeX( 1.5 * pad->GetSizeY() );
614 pad->SetLayerSet( PAD::SMDMask() );
615 }
616 }
617 else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
618 && master->GetAttribute() == PAD_ATTRIB::SMD )
619 {
620 pad->SetAttribute( PAD_ATTRIB::PTH );
621 pad->SetShape( PAD_SHAPE::CIRCLE );
622 pad->SetSize( VECTOR2I( pad->GetSizeX(), pad->GetSizeX() ) );
623
624 // Gives an acceptable drill size: it cannot be 0, but from pad master
625 // it is currently 0, therefore change it:
626 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
627 int hole_size = pad->GetSizeX() / 2;
628 pad->SetDrillSize( VECTOR2I( hole_size, hole_size ) );
629
630 pad->SetLayerSet( PAD::PTHMask() );
631 }
632
633 if( pad->CanHaveNumber() )
634 {
635 wxString padNumber = m_padTool->GetLastPadNumber();
636
637 // Use the last entered pad number when recreating a pad without using the
638 // previously created pad, and a new number when creating a really new pad
639 if( neednewPadNumber )
640 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
641
642 pad->SetNumber( padNumber );
643 m_padTool->SetLastPadNumber( padNumber );
644
645 // If a pad is recreated and the previously created was not placed, use
646 // the last entered pad number
647 neednewPadNumber = false;
648 }
649
650 return std::unique_ptr<BOARD_ITEM>( pad );
651 }
652
653 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
654 {
655 PAD* pad = dynamic_cast<PAD*>( aItem );
656 // We are using this pad number.
657 // therefore use a new pad number for a newly created pad
658 neednewPadNumber = true;
659
660 if( pad )
661 {
662 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
663 aCommit.Add( aItem );
664 return true;
665 }
666
667 return false;
668 }
669
670 PAD_TOOL* m_padTool;
671 };
672
673 PAD_PLACER placer( this );
674
675 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
677
678 return 0;
679}
680
681
682int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
683{
685 return 0;
686
687 Activate();
688
689 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
690 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
692
693 if( m_editPad != niluuid )
694 {
695 PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
696
697 if( pad )
698 {
699 BOARD_COMMIT commit( frame() );
700 commit.Modify( pad );
701
702 std::vector<PCB_SHAPE*> mergedShapes = RecombinePad( pad, false );
703
704 for( PCB_SHAPE* shape : mergedShapes )
705 commit.Remove( shape );
706
707 commit.Push( _( "Edit Pad" ) );
708 }
709
711 }
712 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
713 {
714 PCB_LAYER_ID layer;
715 PAD* pad = static_cast<PAD*>( selection[0] );
716 BOARD_COMMIT commit( frame() );
717
718 commit.Modify( pad );
719 explodePad( pad, &layer, commit );
720 commit.Push( _( "Edit Pad" ) );
721
723 frame()->SetActiveLayer( layer );
724
725 settings->m_PadEditModePad = pad;
727 }
728
729 if( m_editPad == niluuid )
731
732 return 0;
733}
734
735
737{
738 PAD* flaggedPad = nullptr;
739 KIID flaggedPadId = niluuid;
740
741 for( FOOTPRINT* fp : board()->Footprints() )
742 {
743 for( PAD* pad : fp->Pads() )
744 {
745 if( pad->IsEntered() )
746 {
747 flaggedPad = pad;
748 flaggedPadId = pad->m_Uuid;
749 break;
750 }
751 }
752 }
753
754 if( flaggedPadId != m_editPad )
755 {
756 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
757 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
758
759 m_editPad = flaggedPadId;
760 settings->m_PadEditModePad = flaggedPad;
761
762 if( flaggedPad )
764 else
766 }
767
768 return 0;
769}
770
771
773{
775 WX_INFOBAR* infoBar = frame()->GetInfoBar();
776 wxString msg;
777
779 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
780 {
781 return dynamic_cast<PAD*>( aItem ) != nullptr;
782 } );
783
785
786 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::NORMAL )
787 {
788 opts.m_ContrastModeDisplay = HIGH_CONTRAST_MODE::DIMMED;
789 frame()->SetDisplayOptions( opts );
790 }
791
792 if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
793 {
794 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
796 }
797 else
798 {
799 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
801 }
802
803 infoBar->RemoveAllButtons();
804 infoBar->ShowMessage( msg, wxICON_INFORMATION );
805}
806
807
809{
810 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
811 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
813
814 settings->m_PadEditModePad = nullptr;
815
817 {
819 frame()->SetDisplayOptions( opts );
820 }
821
822 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
823 // they won't be found in the view layer's itemset for re-painting.
825 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
826 {
827 return dynamic_cast<PAD*>( aItem ) != nullptr;
828 } );
829
830 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
831 // closes before refresh).
832 canvas()->ForceRefresh();
833
834 frame()->GetInfoBar()->Dismiss();
835}
836
837
838void PAD_TOOL::explodePad( PAD* aPad, PCB_LAYER_ID* aLayer, BOARD_COMMIT& aCommit )
839{
840 if( aPad->IsOnLayer( F_Cu ) )
841 *aLayer = F_Cu;
842 else if( aPad->IsOnLayer( B_Cu ) )
843 *aLayer = B_Cu;
844 else
845 *aLayer = aPad->GetLayerSet().UIOrder().front();
846
847 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
848 {
849 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
850 {
851 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate() );
852
853 shape->SetParent( board()->GetFirstFootprint() );
854 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
855 shape->Move( aPad->ShapePos() );
856 shape->SetLayer( *aLayer );
857
858 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
859 {
860 if( aPad->GetThermalSpokeWidth() )
861 shape->SetWidth( aPad->GetThermalSpokeWidth() );
862 else
864 }
865
866 aCommit.Add( shape );
867 }
868
869 aPad->SetShape( aPad->GetAnchorPadShape() );
870 aPad->DeletePrimitivesList();
871 }
872
873 aPad->SetFlags( ENTERED );
874 m_editPad = aPad->m_Uuid;
875}
876
877
878std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun )
879{
880 int maxError = board()->GetDesignSettings().m_MaxError;
881
882 // Don't leave an object in the point editor that might no longer exist after recombining.
884
885 return aPad->Recombine( aIsDryRun, maxError );
886}
887
888
890{
894
897
900
902}
@ NORMAL
Use all material properties from model file.
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
HIGH_CONTRAST_MODE
Determine how inactive layers should be displayed.
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
virtual void Revert() override
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:79
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:266
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:447
const FOOTPRINTS & Footprints() const
Definition: board.h:330
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:875
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:92
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
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:448
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:89
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
const KIID m_Uuid
Definition: eda_item.h:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
SHAPE_T GetShape() const
Definition: eda_shape.h:125
void SetWidth(int aWidth)
Definition: eda_shape.h:114
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:277
static const TOOL_EVENT UndoRedoPostEvent
Definition: actions.h:294
EDA_ANGLE GetOrientation() const
Definition: footprint.h:226
std::deque< PAD * > & Pads()
Definition: footprint.h:205
const LIB_ID & GetFPID() const
Definition: footprint.h:247
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:324
void SetIgnoreFPTextOnFront(bool ignore)
Definition: collectors.h:422
void SetIgnoreHiddenFPText(bool ignore)
Definition: collectors.h:410
void SetIgnoreFPTextOnBack(bool ignore)
Definition: collectors.h:416
void SetIgnoreFPReferences(bool ignore)
Definition: collectors.h:464
void SetIgnoreFPValues(bool ignore)
Definition: collectors.h:458
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:207
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:483
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:175
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:180
PCB specific render settings.
Definition: pcb_painter.h:78
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
bool GetHighContrast() const
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:84
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:277
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:1687
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1657
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:1573
Definition: kiid.h:49
LSEQ UIOrder() const
Definition: lset.cpp:866
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:736
HIGH_CONTRAST_MODE m_previousHighContrastMode
Definition: pad_tool.h:99
void explodePad(PAD *aPad, PCB_LAYER_ID *aLayer, BOARD_COMMIT &aCommit)
Definition: pad_tool.cpp:838
~PAD_TOOL()
React to model/view changes.
Definition: pad_tool.cpp:59
void setTransitions() override
< Bind handlers to corresponding TOOL_ACTIONs.
Definition: pad_tool.cpp:889
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:682
void ExitPadEditMode()
Definition: pad_tool.cpp:808
KIID m_editPad
Definition: pad_tool.h:100
int copyPadSettings(const TOOL_EVENT &aEvent)
Push pad settings from a pad to other pads on board or footprint.
Definition: pad_tool.cpp:173
void enterPadEditMode()
Definition: pad_tool.cpp:772
int pastePadProperties(const TOOL_EVENT &aEvent)
Copy pad settings from a pad to the board design settings.
Definition: pad_tool.cpp:146
int PlacePad(const TOOL_EVENT &aEvent)
Place a pad in footprint editor.
Definition: pad_tool.cpp:570
int EnumeratePads(const TOOL_EVENT &aEvent)
Tool for quick pad enumeration.
Definition: pad_tool.cpp:303
PAD_TOOL()
Definition: pad_tool.cpp:52
bool Init() override
Init() is called once upon a registration of the tool.
Definition: pad_tool.cpp:85
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:69
std::vector< PCB_SHAPE * > RecombinePad(PAD *aPad, bool aIsDryRun)
Recombine an exploded pad (or one produced with overlapping polygons in an older version).
Definition: pad_tool.cpp:878
wxString m_lastPadNumber
Definition: pad_tool.h:97
int pushPadSettings(const TOOL_EVENT &aEvent)
Definition: pad_tool.cpp:242
Definition: pad.h:54
bool IsAperturePad() const
Definition: pad.h:402
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:392
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:698
PAD_ATTRIB GetAttribute() const
Definition: pad.h:395
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:241
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:318
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition: pad.cpp:1867
VECTOR2I ShapePos() const
Definition: pad.cpp:851
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1646
PAD_SHAPE GetShape() const
Definition: pad.h:193
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:359
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:248
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:184
int GetThermalSpokeWidth() const
Definition: pad.h:555
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:206
static TOOL_ACTION recombinePad
Definition: pcb_actions.h:475
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
Definition: pcb_actions.h:478
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
Definition: pcb_actions.h:498
static TOOL_ACTION mirrorH
Mirroring of selected items.
Definition: pcb_actions.h:139
static TOOL_ACTION copyPadSettings
Copy the selected pad's settings to the board design settings.
Definition: pcb_actions.h:492
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
Definition: pcb_actions.h:472
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:176
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION explodePad
Definition: pcb_actions.h:474
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
Definition: pcb_actions.h:495
static TOOL_ACTION mirrorV
Definition: pcb_actions.h:140
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:136
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:132
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:133
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.
void SetDisplayOptions(const PCB_DISPLAY_OPTIONS &aOptions, bool aRefresh=true)
Updates the current display options from the given options struct.
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()
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:526
bool IsProxyItem() const override
Definition: pcb_shape.h:110
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:317
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:455
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:116
wxWindow * GetPanel()
Definition: status_popup.h:63
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:84
void SetText(const wxString &aText)
Display a text.
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.
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:218
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:150
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
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:304
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
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 bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define ENTERED
indicates a group has been entered
static const std::vector< KICAD_T > padTypes
Definition: edit_tool.cpp:76
@ FP_SMD
Definition: footprint.h:75
@ FP_THROUGH_HOLE
Definition: footprint.h:74
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:95
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:57
@ ALL
All except INITIAL_ADD.
Definition: view_item.h:58
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:611
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:194
static std::optional< SEQUENTIAL_PAD_ENUMERATION_PARAMS > GetSequentialPadNumberingParams(wxWindow *aFrame)
Prompts the user for parameters for sequential pad numbering.
Definition: pad_tool.cpp:289
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
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:76
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
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
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM
Definition: zones.h:34