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 {
70 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
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.get() );
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 // TODO(JE) padstacks
213 if( aPadShapeFilter && ( pad->GetShape( PADSTACK::ALL_LAYERS ) != aSrcPad.GetShape( PADSTACK::ALL_LAYERS ) ) )
214 continue;
215
216 EDA_ANGLE padAngle = pad->GetOrientation() - footprint->GetOrientation();
217
218 if( aPadOrientFilter && ( padAngle != srcPadAngle ) )
219 continue;
220
221 if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
222 continue;
223
224 if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
225 continue;
226
227 // Special-case for aperture pads
228 if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
229 {
230 if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
231 continue;
232 }
233
234 commit.Modify( pad );
235
236 // Apply source pad settings to this pad
237 pad->ImportSettingsFrom( aSrcPad );
238 }
239 }
240}
241
242
244{
246 const PCB_SELECTION& selection = selTool->GetSelection();
247
248 if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
249 {
250 PAD* srcPad = static_cast<PAD*>( selection[0] );
251
252 if( FOOTPRINT* footprint = srcPad->GetParentFootprint() )
253 {
254 frame()->SetMsgPanel( footprint );
255
257 int dialogRet = dlg.ShowModal();
258
259 if( dialogRet == wxID_CANCEL )
260 return 0;
261
262 const bool edit_Same_Modules = (dialogRet == 1);
263
264 BOARD_COMMIT commit( frame() );
265
266 doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules,
271
272 commit.Push( _( "Push Pad Settings" ) );
273
275 frame()->Refresh();
276 }
277 }
278
279 return 0;
280}
281
282
289static std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS>
291{
292 // Persistent settings for the pad enumeration dialog.
293 static SEQUENTIAL_PAD_ENUMERATION_PARAMS s_lastUsedParams;
294
295 DIALOG_ENUM_PADS settingsDlg( aFrame, s_lastUsedParams );
296
297 if( settingsDlg.ShowModal() != wxID_OK )
298 return std::nullopt;
299
300 return s_lastUsedParams;
301}
302
303
305{
307 return 0;
308
309 if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
310 return 0;
311
312 GENERAL_COLLECTOR collector;
313 GENERAL_COLLECTORS_GUIDE guide = frame()->GetCollectorsGuide();
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 {
542 m_menu->ShowContextMenu( selection() );
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 // TODO(JE) padstacks
599 PAD* pad = new PAD( m_board->GetFirstFootprint() );
600 PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
601
602 pad->ImportSettingsFrom( *master );
603
604 // If the footprint type and master pad type directly conflict then make some
605 // adjustments. Otherwise assume the user set what they wanted.
606 // Note also a HEATSINK pad (thermal via) is allowed in SMD footprint
607 if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
608 && master->GetAttribute() == PAD_ATTRIB::PTH )
609 {
610 if( pad->GetProperty() != PAD_PROP::HEATSINK )
611 {
612 pad->SetAttribute( PAD_ATTRIB::SMD );
613 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
614 pad->SetSizeX( 1.5 * pad->GetSizeY() );
615 pad->SetLayerSet( PAD::SMDMask() );
616 }
617 }
618 else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
619 && master->GetAttribute() == PAD_ATTRIB::SMD )
620 {
621 pad->SetAttribute( PAD_ATTRIB::PTH );
622 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
623 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pad->GetSizeX(), pad->GetSizeX() ) );
624
625 // Gives an acceptable drill size: it cannot be 0, but from pad master
626 // it is currently 0, therefore change it:
627 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
628 int hole_size = pad->GetSizeX() / 2;
629 pad->SetDrillSize( VECTOR2I( hole_size, hole_size ) );
630
631 pad->SetLayerSet( PAD::PTHMask() );
632 }
633
634 if( pad->CanHaveNumber() )
635 {
636 wxString padNumber = m_padTool->GetLastPadNumber();
637
638 // Use the last entered pad number when recreating a pad without using the
639 // previously created pad, and a new number when creating a really new pad
640 if( neednewPadNumber )
641 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
642
643 pad->SetNumber( padNumber );
644 m_padTool->SetLastPadNumber( padNumber );
645
646 // If a pad is recreated and the previously created was not placed, use
647 // the last entered pad number
648 neednewPadNumber = false;
649 }
650
651 return std::unique_ptr<BOARD_ITEM>( pad );
652 }
653
654 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
655 {
656 PAD* pad = dynamic_cast<PAD*>( aItem );
657 // We are using this pad number.
658 // therefore use a new pad number for a newly created pad
659 neednewPadNumber = true;
660
661 if( pad )
662 {
663 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
664 aCommit.Add( aItem );
665 return true;
666 }
667
668 return false;
669 }
670
671 PAD_TOOL* m_padTool;
672 };
673
674 PAD_PLACER placer( this );
675
676 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
678
679 return 0;
680}
681
682
683int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
684{
686 return 0;
687
688 Activate();
689
690 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
691 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
693
694 if( m_editPad != niluuid )
695 {
696 PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
697
698 if( pad )
699 {
700 BOARD_COMMIT commit( frame() );
701 commit.Modify( pad );
702
703 std::vector<PCB_SHAPE*> mergedShapes = RecombinePad( pad, false );
704
705 for( PCB_SHAPE* shape : mergedShapes )
706 commit.Remove( shape );
707
708 commit.Push( _( "Edit Pad" ) );
709 }
710
712 }
713 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
714 {
715 PCB_LAYER_ID layer;
716 PAD* pad = static_cast<PAD*>( selection[0] );
717 BOARD_COMMIT commit( frame() );
718
719 commit.Modify( pad );
720 explodePad( pad, &layer, commit );
721 commit.Push( _( "Edit Pad" ) );
722
724 frame()->SetActiveLayer( layer );
725
726 settings->m_PadEditModePad = pad;
728 }
729
730 if( m_editPad == niluuid )
732
733 return 0;
734}
735
736
738{
739 PAD* flaggedPad = nullptr;
740 KIID flaggedPadId = niluuid;
741
742 for( FOOTPRINT* fp : board()->Footprints() )
743 {
744 for( PAD* pad : fp->Pads() )
745 {
746 if( pad->IsEntered() )
747 {
748 flaggedPad = pad;
749 flaggedPadId = pad->m_Uuid;
750 break;
751 }
752 }
753 }
754
755 if( flaggedPadId != m_editPad )
756 {
757 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
758 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
759
760 m_editPad = flaggedPadId;
761 settings->m_PadEditModePad = flaggedPad;
762
763 if( flaggedPad )
765 else
767 }
768
769 return 0;
770}
771
772
774{
775 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
776 WX_INFOBAR* infoBar = frame()->GetInfoBar();
777 wxString msg;
778
780 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
781 {
782 return dynamic_cast<PAD*>( aItem ) != nullptr;
783 } );
784
786
787 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::NORMAL )
788 {
789 opts.m_ContrastModeDisplay = HIGH_CONTRAST_MODE::DIMMED;
790 frame()->SetDisplayOptions( opts );
791 }
792
793 if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
794 {
795 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
797 }
798 else
799 {
800 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
802 }
803
804 infoBar->RemoveAllButtons();
805 infoBar->ShowMessage( msg, wxICON_INFORMATION );
806}
807
808
810{
811 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
812 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
813 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
814
815 settings->m_PadEditModePad = nullptr;
816
818 {
820 frame()->SetDisplayOptions( opts );
821 }
822
823 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
824 // they won't be found in the view layer's itemset for re-painting.
826 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
827 {
828 return dynamic_cast<PAD*>( aItem ) != nullptr;
829 } );
830
831 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
832 // closes before refresh).
833 canvas()->ForceRefresh();
834
835 frame()->GetInfoBar()->Dismiss();
836}
837
838
839void PAD_TOOL::explodePad( PAD* aPad, PCB_LAYER_ID* aLayer, BOARD_COMMIT& aCommit )
840{
841 if( aPad->IsOnLayer( F_Cu ) )
842 *aLayer = F_Cu;
843 else if( aPad->IsOnLayer( B_Cu ) )
844 *aLayer = B_Cu;
845 else
846 *aLayer = aPad->GetLayerSet().UIOrder().front();
847
848 // TODO(JE) padstacks
849 if( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CUSTOM )
850 {
851 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( PADSTACK::ALL_LAYERS ) )
852 {
853 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate() );
854
855 shape->SetParent( board()->GetFirstFootprint() );
856 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
857 shape->Move( aPad->ShapePos( PADSTACK::ALL_LAYERS ) );
858 shape->SetLayer( *aLayer );
859
860 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
861 {
862 if( aPad->GetThermalSpokeWidth() )
863 shape->SetWidth( aPad->GetThermalSpokeWidth() );
864 else
866 }
867
868 aCommit.Add( shape );
869 }
870
871 // TODO(JE) padstacks
873 aPad->DeletePrimitivesList();
874 }
875
876 aPad->SetFlags( ENTERED );
877 m_editPad = aPad->m_Uuid;
878}
879
880
881std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun )
882{
883 int maxError = board()->GetDesignSettings().m_MaxError;
884
885 // Don't leave an object in the point editor that might no longer exist after recombining.
887
888 return aPad->Recombine( aIsDryRun, maxError );
889}
890
891
893{
897
900
903
905}
@ 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
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:448
const FOOTPRINTS & Footprints() const
Definition: board.h:331
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
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:484
Dialog for enumerating pads.
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:280
static const TOOL_EVENT UndoRedoPostEvent
Definition: actions.h:297
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:319
void SetIgnoreFPTextOnFront(bool ignore)
Definition: collectors.h:410
void SetIgnoreFPTextOnBack(bool ignore)
Definition: collectors.h:404
void SetIgnoreFPReferences(bool ignore)
Definition: collectors.h:452
void SetIgnoreFPValues(bool ignore)
Definition: collectors.h:446
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
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:482
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:173
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:178
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
Returns the copper, technical and user layers in the order shown in layer widget.
Definition: lset.cpp:799
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:138
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:737
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:839
~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:892
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:683
void ExitPadEditMode()
Definition: pad_tool.cpp:809
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:773
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:304
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:881
wxString m_lastPadNumber
Definition: pad_tool.h:97
int pushPadSettings(const TOOL_EVENT &aEvent)
Definition: pad_tool.cpp:243
Definition: pad.h:54
bool IsAperturePad() const
Definition: pad.h:449
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:439
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:367
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:765
PAD_ATTRIB GetAttribute() const
Definition: pad.h:442
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:267
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:184
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition: pad.cpp:1981
void DeletePrimitivesList(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Clear the basic shapes list.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:193
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition: pad.cpp:1778
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:410
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:274
int GetThermalSpokeWidth() const
Definition: pad.h:602
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:966
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:215
static TOOL_ACTION recombinePad
Definition: pcb_actions.h:484
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
Definition: pcb_actions.h:487
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
Definition: pcb_actions.h:507
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:501
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
Definition: pcb_actions.h:481
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:180
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION explodePad
Definition: pcb_actions.h:483
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
Definition: pcb_actions.h:504
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
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:636
bool IsProxyItem() const override
Definition: pcb_shape.h:114
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:326
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:543
T * frame() const
KIGFX::PCB_VIEW * view() 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.
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()
std::unique_ptr< 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
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:304
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:78
@ 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:65
@ 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:620
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:290
@ 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:691
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM
Definition: zones.h:34