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, PCB_BASE_EDIT_FRAME* aFrame ) :
587 m_padTool( aPadTool ),
588 m_frame( aFrame ),
589 m_gridHelper( aPadTool->GetManager(), aFrame->GetMagneticItemsSettings() )
590 {
591 neednewPadNumber = true; // Use a new pad number when creatin a pad by default
592 }
593
594 virtual ~PAD_PLACER()
595 {
596 }
597
598 std::unique_ptr<BOARD_ITEM> CreateItem() override
599 {
600 // TODO(JE) padstacks
601 PAD* pad = new PAD( m_board->GetFirstFootprint() );
602 PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
603
604 pad->ImportSettingsFrom( *master );
605
606 // If the footprint type and master pad type directly conflict then make some
607 // adjustments. Otherwise assume the user set what they wanted.
608 // Note also a HEATSINK pad (thermal via) is allowed in SMD footprint
609 if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
610 && master->GetAttribute() == PAD_ATTRIB::PTH )
611 {
612 if( pad->GetProperty() != PAD_PROP::HEATSINK )
613 {
614 pad->SetAttribute( PAD_ATTRIB::SMD );
615 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
616 pad->SetSizeX( 1.5 * pad->GetSizeY() );
617 pad->SetLayerSet( PAD::SMDMask() );
618 }
619 }
620 else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
621 && master->GetAttribute() == PAD_ATTRIB::SMD )
622 {
623 pad->SetAttribute( PAD_ATTRIB::PTH );
624 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
625 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pad->GetSizeX(), pad->GetSizeX() ) );
626
627 // Gives an acceptable drill size: it cannot be 0, but from pad master
628 // it is currently 0, therefore change it:
629 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
630 int hole_size = pad->GetSizeX() / 2;
631 pad->SetDrillSize( VECTOR2I( hole_size, hole_size ) );
632
633 pad->SetLayerSet( PAD::PTHMask() );
634 }
635
636 if( pad->CanHaveNumber() )
637 {
638 wxString padNumber = m_padTool->GetLastPadNumber();
639
640 // Use the last entered pad number when recreating a pad without using the
641 // previously created pad, and a new number when creating a really new pad
642 if( neednewPadNumber )
643 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
644
645 pad->SetNumber( padNumber );
646 m_padTool->SetLastPadNumber( padNumber );
647
648 // If a pad is recreated and the previously created was not placed, use
649 // the last entered pad number
650 neednewPadNumber = false;
651 }
652
653 return std::unique_ptr<BOARD_ITEM>( pad );
654 }
655
656 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
657 {
658 PAD* pad = dynamic_cast<PAD*>( aItem );
659 // We are using this pad number.
660 // therefore use a new pad number for a newly created pad
661 neednewPadNumber = true;
662
663 if( pad )
664 {
665 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
666 aCommit.Add( aItem );
667 return true;
668 }
669
670 return false;
671 }
672
673 void SnapItem( BOARD_ITEM *aItem ) override
674 {
675 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
676 m_gridHelper.SetUseGrid( !( m_modifiers & MD_CTRL ) );
677
678 if( !m_gridHelper.GetSnap() )
679 return;
680
681 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
682 PAD* pad = static_cast<PAD*>( aItem );
683 VECTOR2I position = m_padTool->getViewControls()->GetMousePosition();
684 KIGFX::VIEW_CONTROLS* viewControls = m_padTool->getViewControls();
685 std::vector<BOARD_ITEM*> ignored_items( 1, pad );
686
687 if( settings->pads == MAGNETIC_OPTIONS::NO_EFFECT )
688 {
689 PADS& pads = m_board->GetFirstFootprint()->Pads();
690 ignored_items.insert( ignored_items.end(), pads.begin(), pads.end() );
691 }
692
693 if( !settings->graphics )
694 {
695 DRAWINGS& graphics = m_board->GetFirstFootprint()->GraphicalItems();
696 ignored_items.insert( ignored_items.end(), graphics.begin(), graphics.end() );
697 }
698
699 VECTOR2I cursorPos = m_gridHelper.BestSnapAnchor( position, LSET::AllLayersMask(), GRID_CURRENT, ignored_items );
700 viewControls->ForceCursorPosition( true, cursorPos );
701 aItem->SetPosition( cursorPos );
702 }
703
704 PAD_TOOL* m_padTool;
705 PCB_BASE_EDIT_FRAME* m_frame;
706 PCB_GRID_HELPER m_gridHelper;
707 };
708
709 PAD_PLACER placer( this, frame() );
710
711 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
713
714 return 0;
715}
716
717
718int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
719{
721 return 0;
722
723 Activate();
724
725 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
726 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
728
729 if( m_editPad != niluuid )
730 {
731 PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
732
733 if( pad )
734 {
735 BOARD_COMMIT commit( frame() );
736 commit.Modify( pad );
737
738 std::vector<PCB_SHAPE*> mergedShapes = RecombinePad( pad, false );
739
740 for( PCB_SHAPE* shape : mergedShapes )
741 commit.Remove( shape );
742
743 commit.Push( _( "Edit Pad" ) );
744 }
745
747 }
748 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
749 {
750 PCB_LAYER_ID layer;
751 PAD* pad = static_cast<PAD*>( selection[0] );
752 BOARD_COMMIT commit( frame() );
753
754 commit.Modify( pad );
755 explodePad( pad, &layer, commit );
756 commit.Push( _( "Edit Pad" ) );
757
759 frame()->SetActiveLayer( layer );
760
761 settings->m_PadEditModePad = pad;
763 }
764
765 if( m_editPad == niluuid )
767
768 return 0;
769}
770
771
773{
774 PAD* flaggedPad = nullptr;
775 KIID flaggedPadId = niluuid;
776
777 for( FOOTPRINT* fp : board()->Footprints() )
778 {
779 for( PAD* pad : fp->Pads() )
780 {
781 if( pad->IsEntered() )
782 {
783 flaggedPad = pad;
784 flaggedPadId = pad->m_Uuid;
785 break;
786 }
787 }
788 }
789
790 if( flaggedPadId != m_editPad )
791 {
792 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
793 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
794
795 m_editPad = flaggedPadId;
796 settings->m_PadEditModePad = flaggedPad;
797
798 if( flaggedPad )
800 else
802 }
803
804 return 0;
805}
806
807
809{
810 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
811 WX_INFOBAR* infoBar = frame()->GetInfoBar();
812 wxString msg;
813
815 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
816 {
817 return dynamic_cast<PAD*>( aItem ) != nullptr;
818 } );
819
821
822 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::NORMAL )
823 {
824 opts.m_ContrastModeDisplay = HIGH_CONTRAST_MODE::DIMMED;
825 frame()->SetDisplayOptions( opts );
826 }
827
828 if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
829 {
830 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
832 }
833 else
834 {
835 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
837 }
838
839 infoBar->RemoveAllButtons();
840 infoBar->ShowMessage( msg, wxICON_INFORMATION );
841}
842
843
845{
846 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
847 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
848 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
849
850 settings->m_PadEditModePad = nullptr;
851
853 {
855 frame()->SetDisplayOptions( opts );
856 }
857
858 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
859 // they won't be found in the view layer's itemset for re-painting.
861 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
862 {
863 return dynamic_cast<PAD*>( aItem ) != nullptr;
864 } );
865
866 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
867 // closes before refresh).
868 canvas()->ForceRefresh();
869
870 frame()->GetInfoBar()->Dismiss();
871}
872
873
874void PAD_TOOL::explodePad( PAD* aPad, PCB_LAYER_ID* aLayer, BOARD_COMMIT& aCommit )
875{
876 if( aPad->IsOnLayer( F_Cu ) )
877 *aLayer = F_Cu;
878 else if( aPad->IsOnLayer( B_Cu ) )
879 *aLayer = B_Cu;
880 else
881 *aLayer = aPad->GetLayerSet().UIOrder().front();
882
883 // TODO(JE) padstacks
884 if( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CUSTOM )
885 {
886 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( PADSTACK::ALL_LAYERS ) )
887 {
888 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate() );
889
890 shape->SetParent( board()->GetFirstFootprint() );
891 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
892 shape->Move( aPad->ShapePos( PADSTACK::ALL_LAYERS ) );
893 shape->SetLayer( *aLayer );
894
895 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
896 {
897 if( aPad->GetThermalSpokeWidth() )
898 shape->SetWidth( aPad->GetThermalSpokeWidth() );
899 else
901 }
902
903 aCommit.Add( shape );
904 }
905
906 // TODO(JE) padstacks
908 aPad->DeletePrimitivesList();
909 }
910
911 aPad->SetFlags( ENTERED );
912 m_editPad = aPad->m_Uuid;
913}
914
915
916std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun )
917{
918 int maxError = board()->GetDesignSettings().m_MaxError;
919
920 // Don't leave an object in the point editor that might no longer exist after recombining.
922
923 return aPad->Recombine( aIsDryRun, maxError );
924}
925
926
928{
932
935
938
940}
@ 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:79
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:892
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:475
Dialog for enumerating pads.
int ShowModal() override
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
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:244
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:299
static const TOOL_EVENT UndoRedoPostEvent
Definition: actions.h:316
EDA_ANGLE GetOrientation() const
Definition: footprint.h:227
std::deque< PAD * > & Pads()
Definition: footprint.h:206
const LIB_ID & GetFPID() const
Definition: footprint.h:248
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
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
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 LSET AllLayersMask()
Definition: lset.cpp:701
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
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:772
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:874
~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:927
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:718
void ExitPadEditMode()
Definition: pad_tool.cpp:844
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:808
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:916
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:269
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:1980
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:1777
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:276
int GetThermalSpokeWidth() const
Definition: pad.h:602
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:973
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:215
static TOOL_ACTION recombinePad
Definition: pcb_actions.h:487
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
Definition: pcb_actions.h:490
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
Definition: pcb_actions.h:510
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:504
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
Definition: pcb_actions.h:484
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:486
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
Definition: pcb_actions.h:507
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
Common, abstract interface for edit frames.
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
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.
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:146
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:79
@ FP_SMD
Definition: footprint.h:76
@ FP_THROUGH_HOLE
Definition: footprint.h:75
@ GRID_CURRENT
Definition: grid_helper.h:44
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.
@ MD_CTRL
Definition: tool_event.h:143
@ MD_SHIFT
Definition: tool_event.h:142
@ 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