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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
20
21#include "pad_tool.h"
22#include "pcb_painter.h"
23#include <kiplatform/ui.h>
24#include <macros.h>
26#include <view/view_controls.h>
27#include <tool/tool_manager.h>
29#include <board_item.h>
30#include <collectors.h>
31#include <footprint.h>
32#include <pcb_shape.h>
33#include <pad.h>
34#include <pcbnew_settings.h>
35#include <board_commit.h>
38#include <tools/pcb_actions.h>
42#include <tools/edit_tool.h>
44#include <widgets/wx_infobar.h>
45
46
48
49
55
56
58{
59 if( aReason == MODEL_RELOAD )
60 m_lastPadNumber = wxT( "1" );
61
62 if( board() && board()->ResolveItem( m_editPad ) == DELETED_BOARD_ITEM::GetInstance() )
63 {
64 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
65
67 {
69 frame()->SetDisplayOptions( opts );
70 }
71
72 frame()->GetInfoBar()->Dismiss();
73
75 }
76}
77
78
80{
81 static const std::vector<KICAD_T> padTypes = { PCB_PAD_T };
82
83 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
84
85 if( selTool )
86 {
87 // Add context menu entries that are displayed when selection tool is active
88 CONDITIONAL_MENU& menu = selTool->GetToolMenu().GetMenu();
89
93
94 auto explodeCondition =
95 [this]( const SELECTION& aSel )
96 {
97 return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
98 };
99
100 auto recombineCondition =
101 [this]( const SELECTION& aSel )
102 {
103 return m_editPad != niluuid;
104 };
105
106 menu.AddSeparator( 400 );
107
109 {
112 menu.AddItem( PCB_ACTIONS::recombinePad, recombineCondition, 400 );
113 menu.AddItem( PCB_ACTIONS::explodePad, explodeCondition, 400 );
114 }
115
116 menu.AddItem( PCB_ACTIONS::copyPadSettings, singlePadSel, 400 );
117 menu.AddItem( PCB_ACTIONS::applyPadSettings, padSel, 400 );
118 menu.AddItem( PCB_ACTIONS::pushPadSettings, singlePadSel, 400 );
119 }
120
121 auto& ctxMenu = m_menu->GetMenu();
122
123 // cancel current tool goes in main context menu at the top if present
125 ctxMenu.AddSeparator( 1 );
126
133
134 // Finally, add the standard zoom/grid items
135 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( *m_menu.get() );
136
137 return true;
138}
139
140
142{
143 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
144 const PCB_SELECTION& selection = selTool->GetSelection();
145 const PAD* masterPad = frame()->GetDesignSettings().m_Pad_Master.get();
146
147 BOARD_COMMIT commit( frame() );
148
149 // for every selected pad, paste global settings
150 for( EDA_ITEM* item : selection )
151 {
152 if( item->Type() == PCB_PAD_T )
153 {
154 commit.Modify( item );
155 static_cast<PAD&>( *item ).ImportSettingsFrom( *masterPad );
156 }
157 }
158
159 commit.Push( _( "Paste Pad Properties" ) );
160
162 frame()->Refresh();
163
164 return 0;
165}
166
167
169{
170 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
171 const PCB_SELECTION& selection = selTool->GetSelection();
172
173 // can only copy from a single pad
174 if( selection.Size() == 1 )
175 {
176 EDA_ITEM* item = selection[0];
177
178 if( item->Type() == PCB_PAD_T )
179 {
180 const PAD& selPad = static_cast<const PAD&>( *item );
181 frame()->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( selPad );
182 }
183 }
184
185 return 0;
186}
187
188
189static void doPushPadProperties( BOARD& board, const PAD& aSrcPad, BOARD_COMMIT& commit,
190 bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter,
191 bool aPadLayerFilter, bool aPadTypeFilter )
192{
193 const FOOTPRINT* refFootprint = aSrcPad.GetParentFootprint();
194
195 EDA_ANGLE srcPadAngle = aSrcPad.GetOrientation() - refFootprint->GetOrientation();
196
197 for( FOOTPRINT* footprint : board.Footprints() )
198 {
199 if( !aSameFootprints && ( footprint != refFootprint ) )
200 continue;
201
202 if( footprint->GetFPID() != refFootprint->GetFPID() )
203 continue;
204
205 for( PAD* pad : footprint->Pads() )
206 {
207 if( aPadShapeFilter )
208 {
209 bool shapesMatch = true;
210
211 // Compare in both directions to catch all potentialy unique layer defintions
212 pad->Padstack().ForEachUniqueLayer(
213 [&]( PCB_LAYER_ID aLayer )
214 {
215 if( pad->GetShape( aLayer ) != aSrcPad.GetShape( aLayer ) )
216 shapesMatch = false;
217 } );
218
220 [&]( PCB_LAYER_ID aLayer )
221 {
222 if( aSrcPad.GetShape( aLayer ) != pad->GetShape( aLayer ) )
223 shapesMatch = false;
224 } );
225
226 if( !shapesMatch )
227 continue;
228 }
229
230 EDA_ANGLE padAngle = pad->GetOrientation() - footprint->GetOrientation();
231
232 if( aPadOrientFilter && ( padAngle != srcPadAngle ) )
233 continue;
234
235 if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
236 continue;
237
238 if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
239 continue;
240
241 // Special-case for aperture pads
242 if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
243 {
244 if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
245 continue;
246 }
247
248 commit.Modify( pad );
249
250 // Apply source pad settings to this pad
251 pad->ImportSettingsFrom( aSrcPad );
252 }
253 }
254}
255
256
258{
259 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
260 const PCB_SELECTION& selection = selTool->GetSelection();
261
262 if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
263 {
264 PAD* srcPad = static_cast<PAD*>( selection[0] );
265
266 if( FOOTPRINT* footprint = srcPad->GetParentFootprint() )
267 {
268 frame()->SetMsgPanel( footprint );
269
271 int dialogRet = dlg.ShowModal();
272
273 if( dialogRet == wxID_CANCEL )
274 return 0;
275
276 const bool edit_Same_Modules = (dialogRet == 1);
277
278 BOARD_COMMIT commit( frame() );
279
280 doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules, dlg.GetPadShapeFilter(),
282
283 commit.Push( _( "Push Pad Settings" ) );
284
286 frame()->Refresh();
287 }
288 }
289
290 return 0;
291}
292
293
300static std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS> GetSequentialPadNumberingParams( wxWindow* aFrame )
301{
302 // Persistent settings for the pad enumeration dialog.
303 static SEQUENTIAL_PAD_ENUMERATION_PARAMS s_lastUsedParams;
304
305 DIALOG_ENUM_PADS settingsDlg( aFrame, s_lastUsedParams );
306
307 if( settingsDlg.ShowModal() != wxID_OK )
308 return std::nullopt;
309
310 return s_lastUsedParams;
311}
312
313
315{
317 return 0;
318
319 if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
320 return 0;
321
322 GENERAL_COLLECTOR collector;
323 GENERAL_COLLECTORS_GUIDE guide = frame()->GetCollectorsGuide();
324 guide.SetIgnoreFPTextOnBack( true );
325 guide.SetIgnoreFPTextOnFront( true );
326 guide.SetIgnoreFPValues( true );
327 guide.SetIgnoreFPReferences( true );
328
329 const std::optional<SEQUENTIAL_PAD_ENUMERATION_PARAMS> params = GetSequentialPadNumberingParams( frame() );
330
331 // Cancelled or otherwise failed to get any useful parameters
332 if( !params )
333 return 0;
334
335 int seqPadNum = params->m_start_number;
336
337 std::deque<int> storedPadNumbers;
338 std::map<wxString, std::pair<int, wxString>> oldNumbers;
339
341
342 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
343
344 VECTOR2I oldMousePos; // store the previous mouse cursor position, during mouse drag
345 std::list<PAD*> selectedPads;
346 BOARD_COMMIT commit( frame() );
347 bool isFirstPoint = true; // make sure oldMousePos is initialized at least once
348 std::deque<PAD*> pads = board()->GetFirstFootprint()->Pads();
349 MAGNETIC_SETTINGS mag_settings;
350
351 mag_settings.graphics = false;
352 mag_settings.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
354
355 PCB_GRID_HELPER grid( m_toolMgr, &mag_settings );
356
357 grid.SetSnap( true );
358 grid.SetUseGrid( false );
359
360 auto setCursor =
361 [&]()
362 {
364 };
365
366 KIGFX::VIEW* view = m_toolMgr->GetView();
367 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
368 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
369 bool isHighContrast = settings->GetHighContrast();
370
371 view->SyncLayerVisibilityCache(); // Required for ViewGetLOD() calls.
372
373 auto checkVisibility =
374 [&]( BOARD_ITEM* item )
375 {
376 if( !view->IsVisible( item ) )
377 return false;
378
379 for( PCB_LAYER_ID layer : item->GetLayerSet() )
380 {
381 if( ( isHighContrast && activeLayers.count( layer ) ) || view->IsLayerVisible( layer ) )
382 {
383 if( item->ViewGetLOD( layer, view ) < view->GetScale() )
384 return true;
385 }
386 }
387
388 return false;
389 };
390
391 for( PAD* pad : board()->GetFirstFootprint()->Pads() )
392 {
393 if( checkVisibility( pad ) )
394 pads.push_back( pad );
395 }
396
397 Activate();
398 // Must be done after Activate() so that it gets set into the correct context
399 getViewControls()->ShowCursor( true );
401 // Set initial cursor
402 setCursor();
403
404 STATUS_TEXT_POPUP statusPopup( frame() );
405
406 // Callable lambda to construct the pad number string for the given value
407 const auto constructPadNumber =
408 [&]( int aValue )
409 {
410 return wxString::Format( wxT( "%s%d" ), params->m_prefix.value_or( "" ), aValue );
411 };
412
413 // Callable lambda to set the popup text for the given pad value
414 const auto setPopupTextForValue =
415 [&]( int aValue )
416 {
417 const wxString msg = _( "Click on pad %s\n"
418 "Press <esc> to cancel all; double-click to finish" );
419 statusPopup.SetText( wxString::Format( msg, constructPadNumber( aValue ) ) );
420 };
421
422 setPopupTextForValue( seqPadNum );
423 statusPopup.Popup();
424 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
425 canvas()->SetStatusPopup( statusPopup.GetPanel() );
426
427 while( TOOL_EVENT* evt = Wait() )
428 {
429 setCursor();
430
432 VECTOR2I cursorPos = grid.SnapToPad( mousePos, pads );
433 getViewControls()->ForceCursorPosition( true, cursorPos );
434
435 if( evt->IsCancelInteractive() )
436 {
438 commit.Revert();
439 break;
440 }
441 else if( evt->IsActivate() )
442 {
443 commit.Push( _( "Renumber Pads" ) );
444 break;
445 }
446 else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
447 {
448 selectedPads.clear();
449
450 // Be sure the old cursor mouse position was initialized:
451 if( isFirstPoint )
452 {
453 oldMousePos = mousePos;
454 isFirstPoint = false;
455 }
456
457 // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
458 // pads if the user moves cursor too fast. To solve it, create a line that approximates
459 // the mouse move and search pads that are on the line.
460 int distance = ( mousePos - oldMousePos ).EuclideanNorm();
461 // Search will be made every 0.1 mm:
462 int segments = distance / int( 0.1 * pcbIUScale.IU_PER_MM ) + 1;
463 const VECTOR2I line_step( ( mousePos - oldMousePos ) / segments );
464
465 collector.Empty();
466
467 for( int j = 0; j < segments; ++j )
468 {
469 VECTOR2I testpoint( mousePos.x - j * line_step.x, mousePos.y - j * line_step.y );
470 collector.Collect( board(), { PCB_PAD_T }, testpoint, guide );
471
472 for( int i = 0; i < collector.GetCount(); ++i )
473 {
474 PAD* pad = static_cast<PAD*>( collector[i] );
475
476 if( pad->CanHaveNumber() && checkVisibility( pad ) )
477 selectedPads.push_back( pad );
478 }
479 }
480
481 selectedPads.unique();
482
483 for( PAD* pad : selectedPads )
484 {
485 // If pad was not selected, then enumerate it
486 if( !pad->IsSelected() )
487 {
488 commit.Modify( pad );
489
490 // Rename pad and store the old name
491 int newval;
492
493 if( storedPadNumbers.size() > 0 )
494 {
495 newval = storedPadNumbers.front();
496 storedPadNumbers.pop_front();
497 }
498 else
499 {
500 newval = seqPadNum;
501 seqPadNum += params->m_step;
502 }
503
504 const wxString newNumber = constructPadNumber( newval );
505 oldNumbers[newNumber] = { newval, pad->GetNumber() };
506 pad->SetNumber( newNumber );
507 SetLastPadNumber( newNumber );
508 pad->SetSelected();
509 getView()->Update( pad );
510
511 // Ensure the popup text shows the correct next value
512 if( storedPadNumbers.size() > 0 )
513 newval = storedPadNumbers.front();
514 else
515 newval = seqPadNum;
516
517 setPopupTextForValue( newval );
518 }
519
520 // ... or restore the old name if it was enumerated and clicked again
521 else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
522 {
523 auto it = oldNumbers.find( pad->GetNumber() );
524 wxASSERT( it != oldNumbers.end() );
525
526 if( it != oldNumbers.end() )
527 {
528 storedPadNumbers.push_back( it->second.first );
529 pad->SetNumber( it->second.second );
530 SetLastPadNumber( it->second.second );
531 oldNumbers.erase( it );
532
533 const int newval = storedPadNumbers.front();
534 setPopupTextForValue( newval );
535 }
536
537 pad->ClearSelected();
538 getView()->Update( pad );
539 }
540 }
541 }
542 else if( evt->IsDblClick( BUT_LEFT ) )
543 {
544 commit.Push( _( "Renumber Pads" ) );
545 break;
546 }
547 else if( evt->IsClick( BUT_RIGHT ) )
548 {
549 m_menu->ShowContextMenu( selection() );
550 }
551 else
552 {
553 evt->SetPassEvent();
554 }
555
556 // Prepare the next loop by updating the old cursor mouse position
557 // to this last mouse cursor position
558 oldMousePos = mousePos;
559 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
560 }
561
562 for( PAD* p : board()->GetFirstFootprint()->Pads() )
563 {
564 p->ClearSelected();
565 getView()->Update( p );
566 }
567
568 canvas()->SetStatusPopup( nullptr );
569 statusPopup.Hide();
570
573 return 0;
574}
575
576
577int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
578{
579 // When creating a new pad (in FP editor) we can use a new pad number or the last entered pad number
580 // neednewPadNumber = true to create a new pad number, false to use the last entered pad number
581 static bool neednewPadNumber;
582
584 return 0;
585
586 if( !board()->GetFirstFootprint() )
587 return 0;
588
589 struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
590 {
591 PAD_PLACER( PAD_TOOL* aPadTool, PCB_BASE_EDIT_FRAME* aFrame ) :
592 m_padTool( aPadTool ),
593 m_frame( aFrame ),
594 m_gridHelper( aPadTool->GetManager(), aFrame->GetMagneticItemsSettings() )
595 {
596 neednewPadNumber = true; // Use a new pad number when creatin a pad by default
597 }
598
599 virtual ~PAD_PLACER() = default;
600
601 std::unique_ptr<BOARD_ITEM> CreateItem() override
602 {
603 PAD* pad = new PAD( m_board->GetFirstFootprint() );
604 PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
605
606 pad->ImportSettingsFrom( *master );
607
608 if( pad->CanHaveNumber() )
609 {
610 wxString padNumber = m_padTool->GetLastPadNumber();
611
612 // Use the last entered pad number when recreating a pad without using the
613 // previously created pad, and a new number when creating a really new pad
614 if( neednewPadNumber )
615 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
616
617 pad->SetNumber( padNumber );
618 m_padTool->SetLastPadNumber( padNumber );
619
620 // If a pad is recreated and the previously created was not placed, use
621 // the last entered pad number
622 neednewPadNumber = false;
623 }
624
625 return std::unique_ptr<BOARD_ITEM>( pad );
626 }
627
628 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
629 {
630 PAD* pad = dynamic_cast<PAD*>( aItem );
631 // We are using this pad number.
632 // therefore use a new pad number for a newly created pad
633 neednewPadNumber = true;
634
635 if( pad )
636 {
637 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
638 aCommit.Add( aItem );
639 return true;
640 }
641
642 return false;
643 }
644
645 void SnapItem( BOARD_ITEM *aItem ) override
646 {
647 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
648 m_gridHelper.SetUseGrid( !( m_modifiers & MD_CTRL ) );
649
650 if( !m_gridHelper.GetSnap() )
651 return;
652
653 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
654 PAD* pad = static_cast<PAD*>( aItem );
655 VECTOR2I position = m_padTool->getViewControls()->GetMousePosition();
656 KIGFX::VIEW_CONTROLS* viewControls = m_padTool->getViewControls();
657 std::vector<BOARD_ITEM*> ignored_items( 1, pad );
658
659 if( settings->pads == MAGNETIC_OPTIONS::NO_EFFECT )
660 {
661 PADS& pads = m_board->GetFirstFootprint()->Pads();
662 ignored_items.insert( ignored_items.end(), pads.begin(), pads.end() );
663 }
664
665 if( !settings->graphics )
666 {
667 DRAWINGS& graphics = m_board->GetFirstFootprint()->GraphicalItems();
668 ignored_items.insert( ignored_items.end(), graphics.begin(), graphics.end() );
669 }
670
671 VECTOR2I cursorPos = m_gridHelper.ResolveSnap( position, LSET::AllLayersMask(),
672 GRID_CURRENT, ignored_items ).position;
673 viewControls->ForceCursorPosition( true, cursorPos );
674 aItem->SetPosition( cursorPos );
675 }
676
677 PAD_TOOL* m_padTool;
678 PCB_BASE_EDIT_FRAME* m_frame;
679 PCB_GRID_HELPER m_gridHelper;
680 };
681
682 PAD_PLACER placer( this, frame() );
683
684 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
686
687 return 0;
688}
689
690
691int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
692{
694 return 0;
695
696 Activate();
697
698 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
699 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
700 PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
701
702 if( m_editPad != niluuid )
703 {
704 if( PAD* pad = dynamic_cast<PAD*>( frame()->ResolveItem( m_editPad ) ) )
705 {
706 BOARD_COMMIT commit( frame() );
707 commit.Modify( pad );
708
709 std::vector<PCB_SHAPE*> mergedShapes = RecombinePad( pad, false );
710
711 for( PCB_SHAPE* shape : mergedShapes )
712 commit.Remove( shape );
713
714 commit.Push( _( "Edit Pad" ) );
715 }
716
718 }
719 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
720 {
721 PAD* pad = static_cast<PAD*>( selection[0] );
722 BOARD_COMMIT commit( frame() );
723
724 commit.Modify( pad );
725 explodePad( pad, commit );
726 commit.Push( _( "Edit Pad" ) );
727
729 frame()->SetActiveLayer( pad->GetPrincipalLayer() );
730
731 settings->m_PadEditModePad = pad;
733 }
734
735 if( m_editPad == niluuid )
737
738 return 0;
739}
740
741
743{
744 PAD* flaggedPad = nullptr;
745 KIID flaggedPadId = niluuid;
746
747 for( FOOTPRINT* fp : board()->Footprints() )
748 {
749 for( PAD* pad : fp->Pads() )
750 {
751 if( pad->IsEntered() )
752 {
753 flaggedPad = pad;
754 flaggedPadId = pad->m_Uuid;
755 break;
756 }
757 }
758 }
759
760 if( flaggedPadId != m_editPad )
761 {
762 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
763 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
764
765 m_editPad = flaggedPadId;
766 settings->m_PadEditModePad = flaggedPad;
767
768 if( flaggedPad )
770 else
772 }
773
774 return 0;
775}
776
777
779{
780 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
781 WX_INFOBAR* infoBar = frame()->GetInfoBar();
782 wxString msg;
783
785 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
786 {
787 return dynamic_cast<PAD*>( aItem ) != nullptr;
788 } );
789
791
793 {
795 frame()->SetDisplayOptions( opts );
796 }
797
798 if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
799 {
800 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
802 }
803 else
804 {
805 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
807 }
808
809 infoBar->RemoveAllButtons();
810 infoBar->ShowMessage( msg, wxICON_INFORMATION );
811}
812
813
815{
816 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
817 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
818 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
819
820 settings->m_PadEditModePad = nullptr;
821
823 {
825 frame()->SetDisplayOptions( opts );
826 }
827
828 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
829 // they won't be found in the view layer's itemset for re-painting.
831 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
832 {
833 return dynamic_cast<PAD*>( aItem ) != nullptr;
834 } );
835
836 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
837 // closes before refresh).
838 canvas()->ForceRefresh();
839
840 frame()->GetInfoBar()->Dismiss();
841}
842
843
844void PAD_TOOL::explodePad( PAD* aPad, BOARD_COMMIT& aCommit )
845{
846 auto explodePrimitives =
847 [&]( PCB_LAYER_ID padstackStorageLayer, PCB_LAYER_ID targetBoardLayer )
848 {
849 if( aPad->GetShape( padstackStorageLayer ) == PAD_SHAPE::CUSTOM )
850 {
851 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( padstackStorageLayer ) )
852 {
853 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate( true, &aCommit ) );
854
855 shape->SetParent( board()->GetFirstFootprint() );
856 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
857 shape->Move( aPad->ShapePos( padstackStorageLayer ) );
858 shape->SetLayer( targetBoardLayer );
859
860 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
861 {
862 if( aPad->GetLocalThermalSpokeWidthOverride().has_value() )
863 shape->SetWidth( aPad->GetLocalThermalSpokeWidthOverride().value() );
864 else
866 }
867
868 aCommit.Add( shape );
869 }
870
871 aPad->SetShape( padstackStorageLayer, aPad->GetAnchorPadShape( padstackStorageLayer ) );
872 aPad->DeletePrimitivesList( padstackStorageLayer );
873 }
874 };
875
876 if( aPad->Padstack().Mode() == PADSTACK::MODE::NORMAL )
877 {
878 explodePrimitives( PADSTACK::ALL_LAYERS, aPad->GetPrincipalLayer() );
879 }
880 else
881 {
883 [&]( PCB_LAYER_ID layer )
884 {
885 explodePrimitives( layer, layer );
886 } );
887 }
888
889 aPad->SetFlags( ENTERED );
890 m_editPad = aPad->m_Uuid;
891}
892
893
894std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun )
895{
896 int maxError = board()->GetDesignSettings().m_MaxError;
897
898 // Don't leave an object in the point editor that might no longer exist after recombining.
900
901 return aPad->Recombine( aIsDryRun, maxError );
902}
903
904
905int PAD_TOOL::PadTable( const TOOL_EVENT& aEvent )
906{
908 return 0;
909
911
912 if( !footprint )
913 return 0;
914
916 dlg.ShowQuasiModal();
917
918 return 0;
919}
920
921
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
HIGH_CONTRAST_MODE
Determine how inactive layers should be displayed.
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
@ DIMMED
Inactive layers are dimmed (old high-contrast mode)
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
FOOTPRINT * GetParentFootprint() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:704
const FOOTPRINTS & Footprints() const
Definition board.h:463
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
void Empty()
Clear the list.
Definition collector.h:87
int GetCount() const
Return the number of objects in the list.
Definition collector.h:79
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:86
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
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:609
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:98
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:349
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
SHAPE_T GetShape() const
Definition eda_shape.h:175
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:350
static const TOOL_EVENT UndoRedoPostEvent
Definition actions.h:367
EDA_ANGLE GetOrientation() const
Definition footprint.h:438
std::deque< PAD * > & Pads()
Definition footprint.h:404
const LIB_ID & GetFPID() const
Definition footprint.h:473
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:320
void SetIgnoreFPTextOnFront(bool ignore)
Definition collectors.h:412
void SetIgnoreFPTextOnBack(bool ignore)
Definition collectors.h:406
void SetIgnoreFPReferences(bool ignore)
Definition collectors.h:454
void SetIgnoreFPValues(bool ignore)
Definition collectors.h:448
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:203
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.
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:84
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.
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.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:82
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
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:1852
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
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:1719
Definition kiid.h:46
static const LSET & AllLayersMask()
Definition lset.cpp:637
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
MODE Mode() const
Definition padstack.h:344
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
void Reset(RESET_REASON aReason) override
Basic initialization.
Definition pad_tool.cpp:57
int OnUndoRedo(const TOOL_EVENT &aEvent)
Definition pad_tool.cpp:742
HIGH_CONTRAST_MODE m_previousHighContrastMode
Definition pad_tool.h:93
void setTransitions() override
< Bind handlers to corresponding TOOL_ACTIONs.
Definition pad_tool.cpp:922
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition pad_tool.cpp:691
void ExitPadEditMode()
Definition pad_tool.cpp:814
KIID m_editPad
Definition pad_tool.h:94
int copyPadSettings(const TOOL_EVENT &aEvent)
Push pad settings from a pad to other pads on board or footprint.
Definition pad_tool.cpp:168
void enterPadEditMode()
Definition pad_tool.cpp:778
int pastePadProperties(const TOOL_EVENT &aEvent)
< Apply pad settings from board design settings to a pad.
Definition pad_tool.cpp:141
int PlacePad(const TOOL_EVENT &aEvent)
Place a pad in footprint editor.
Definition pad_tool.cpp:577
int EnumeratePads(const TOOL_EVENT &aEvent)
Tool for quick pad enumeration.
Definition pad_tool.cpp:314
PAD_TOOL()
React to model/view changes.
Definition pad_tool.cpp:50
void explodePad(PAD *aPad, BOARD_COMMIT &aCommit)
Definition pad_tool.cpp:844
int PadTable(const TOOL_EVENT &aEvent)
Definition pad_tool.cpp:905
bool Init() override
Init() is called once upon a registration of the tool.
Definition pad_tool.cpp:79
void SetLastPadNumber(const wxString &aPadNumber)
Definition pad_tool.h:62
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:894
bool InPadEditMode()
Definition pad_tool.h:58
wxString m_lastPadNumber
Definition pad_tool.h:91
int pushPadSettings(const TOOL_EVENT &aEvent)
Definition pad_tool.cpp:257
Definition pad.h:61
bool IsAperturePad() const
Definition pad.h:565
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:555
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:373
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:196
std::vector< PCB_SHAPE * > Recombine(bool aIsDryRun, int aMaxError)
Recombines the pad with other graphical shapes in the footprint.
Definition pad.cpp:3116
PCB_LAYER_ID GetPrincipalLayer() const
Definition pad.cpp:655
void DeletePrimitivesList(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Clear the basic shapes list.
Definition pad.cpp:3696
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
void ImportSettingsFrom(const PAD &aMasterPad)
Import the pad settings from aMasterPad.
Definition pad.cpp:2913
const PADSTACK & Padstack() const
Definition pad.h:329
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1747
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:736
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1855
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:219
static TOOL_ACTION recombinePad
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
static TOOL_ACTION mirrorH
Mirroring of selected items.
static TOOL_ACTION copyPadSettings
Copy the selected pad's settings to the board design settings.
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
static TOOL_ACTION padTable
static TOOL_ACTION properties
Activation of the edit tool.
static TOOL_ACTION explodePad
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
static TOOL_ACTION mirrorV
static TOOL_ACTION flip
Flipping of selected objects.
static TOOL_ACTION rotateCw
Rotation of selected objects.
static TOOL_ACTION rotateCcw
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.
void SetWidth(int aWidth) override
bool IsProxyItem() const override
Definition pcb_shape.h:153
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
T * frame() const
KIGFX::PCB_VIEW * view() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
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.
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.
wxWindow * GetPanel()
virtual void Popup(wxWindow *aFocus=nullptr)
virtual void Move(const wxPoint &aWhere)
Extension of STATUS_POPUP for displaying a single line text.
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:142
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
T * getModel() const
Return the model object if it matches the requested type.
Definition tool_base.h:195
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
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.
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:40
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.
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
@ ARROW
Definition cursors.h:42
@ BULLSEYE
Definition cursors.h:54
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define ENTERED
indicates a group has been entered
@ SEGMENT
Definition eda_shape.h:56
static const std::vector< KICAD_T > padTypes
@ GRID_CURRENT
Definition grid_helper.h:57
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
NORMAL
Follows standard pretty-printing rules.
KIID niluuid(0)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
This file contains miscellaneous commonly used macros and functions.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ ALL
All except INITIAL_ADD.
Definition view_item.h:55
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:839
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:189
static std::optional< SEQUENTIAL_PAD_ENUMERATION_PARAMS > GetSequentialPadNumberingParams(wxWindow *aFrame)
Prompts the user for parameters for sequential pad numbering.
Definition pad_tool.cpp:300
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
std::deque< PAD * > PADS
std::deque< BOARD_ITEM * > DRAWINGS
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.
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
Parameters for sequential pad numbering.
@ MD_CTRL
Definition tool_event.h:140
@ MD_SHIFT
Definition tool_event.h:139
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM
Definition zones.h:29