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 oldMousePos; // 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 oldMousePos 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 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
369 {
370 if( ( isHighContrast && activeLayers.count( layer ) )
371 || view->IsLayerVisible( layer ) )
372 {
373 if( item->ViewGetLOD( layer, view ) < view->GetScale() )
374 return true;
375 }
376 }
377
378 return false;
379 };
380
381 for( PAD* pad : board()->GetFirstFootprint()->Pads() )
382 {
383 if( checkVisibility( pad ) )
384 pads.push_back( pad );
385 }
386
387 Activate();
388 // Must be done after Activate() so that it gets set into the correct context
389 getViewControls()->ShowCursor( true );
391 // Set initial cursor
392 setCursor();
393
394 STATUS_TEXT_POPUP statusPopup( frame() );
395
396 // Callable lambda to construct the pad number string for the given value
397 const auto constructPadNumber =
398 [&]( int aValue )
399 {
400 return wxString::Format( wxT( "%s%d" ), params->m_prefix.value_or( "" ), aValue );
401 };
402
403 // Callable lambda to set the popup text for the given pad value
404 const auto setPopupTextForValue =
405 [&]( int aValue )
406 {
407 const wxString msg = _( "Click on pad %s\n"
408 "Press <esc> to cancel all; double-click to finish" );
409 statusPopup.SetText( wxString::Format( msg, constructPadNumber( aValue ) ) );
410 };
411
412 setPopupTextForValue( seqPadNum );
413 statusPopup.Popup();
414 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
415 canvas()->SetStatusPopup( statusPopup.GetPanel() );
416
417 while( TOOL_EVENT* evt = Wait() )
418 {
419 setCursor();
420
422 VECTOR2I cursorPos = grid.SnapToPad( mousePos, pads );
423 getViewControls()->ForceCursorPosition( true, cursorPos );
424
425 if( evt->IsCancelInteractive() )
426 {
428 commit.Revert();
429
430 frame()->PopTool( aEvent );
431 break;
432 }
433 else if( evt->IsActivate() )
434 {
435 commit.Push( _( "Renumber Pads" ) );
436
437 frame()->PopTool( aEvent );
438 break;
439 }
440 else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
441 {
442 selectedPads.clear();
443
444 // Be sure the old cursor mouse position was initialized:
445 if( isFirstPoint )
446 {
447 oldMousePos = mousePos;
448 isFirstPoint = false;
449 }
450
451 // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
452 // pads if the user moves cursor too fast. To solve it, create a line that approximates
453 // the mouse move and search pads that are on the line.
454 int distance = ( mousePos - oldMousePos ).EuclideanNorm();
455 // Search will be made every 0.1 mm:
456 int segments = distance / int( 0.1 * pcbIUScale.IU_PER_MM ) + 1;
457 const VECTOR2I line_step( ( mousePos - oldMousePos ) / segments );
458
459 collector.Empty();
460
461 for( int j = 0; j < segments; ++j )
462 {
463 VECTOR2I testpoint( mousePos.x - j * line_step.x, mousePos.y - j * line_step.y );
464 collector.Collect( board(), { PCB_PAD_T }, testpoint, guide );
465
466 for( int i = 0; i < collector.GetCount(); ++i )
467 {
468 PAD* pad = static_cast<PAD*>( collector[i] );
469
470 if( !pad->IsAperturePad() && checkVisibility( pad ) )
471 selectedPads.push_back( pad );
472 }
473 }
474
475 selectedPads.unique();
476
477 for( PAD* pad : selectedPads )
478 {
479 // If pad was not selected, then enumerate it
480 if( !pad->IsSelected() )
481 {
482 commit.Modify( pad );
483
484 // Rename pad and store the old name
485 int newval;
486
487 if( storedPadNumbers.size() > 0 )
488 {
489 newval = storedPadNumbers.front();
490 storedPadNumbers.pop_front();
491 }
492 else
493 {
494 newval = seqPadNum;
495 seqPadNum += params->m_step;
496 }
497
498 const wxString newNumber = constructPadNumber( newval );
499 oldNumbers[newNumber] = { newval, pad->GetNumber() };
500 pad->SetNumber( newNumber );
501 SetLastPadNumber( newNumber );
502 pad->SetSelected();
503 getView()->Update( pad );
504
505 // Ensure the popup text shows the correct next value
506 if( storedPadNumbers.size() > 0 )
507 newval = storedPadNumbers.front();
508 else
509 newval = seqPadNum;
510
511 setPopupTextForValue( newval );
512 }
513
514 // ... or restore the old name if it was enumerated and clicked again
515 else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
516 {
517 auto it = oldNumbers.find( pad->GetNumber() );
518 wxASSERT( it != oldNumbers.end() );
519
520 if( it != oldNumbers.end() )
521 {
522 storedPadNumbers.push_back( it->second.first );
523 pad->SetNumber( it->second.second );
524 SetLastPadNumber( it->second.second );
525 oldNumbers.erase( it );
526
527 const int newval = storedPadNumbers.front();
528 setPopupTextForValue( newval );
529 }
530
531 pad->ClearSelected();
532 getView()->Update( pad );
533 }
534 }
535 }
536 else if( evt->IsDblClick( BUT_LEFT ) )
537 {
538 commit.Push( _( "Renumber Pads" ) );
539 frame()->PopTool( aEvent );
540 break;
541 }
542 else if( evt->IsClick( BUT_RIGHT ) )
543 {
544 m_menu->ShowContextMenu( selection() );
545 }
546 else
547 {
548 evt->SetPassEvent();
549 }
550
551 // Prepare the next loop by updating the old cursor mouse position
552 // to this last mouse cursor position
553 oldMousePos = mousePos;
554 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
555 }
556
557 for( PAD* p : board()->GetFirstFootprint()->Pads() )
558 {
559 p->ClearSelected();
560 getView()->Update( p );
561 }
562
563 canvas()->SetStatusPopup( nullptr );
564 statusPopup.Hide();
565
566 canvas()->SetCurrentCursor( KICURSOR::ARROW );
568 return 0;
569}
570
571
572int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
573{
574 // When creating a new pad (in FP editor) we can use a new pad number
575 // or the last entered pad number
576 // neednewPadNumber = true to create a new pad number, false to use the last
577 // entered pad number
578 static bool neednewPadNumber;
579
581 return 0;
582
583 if( !board()->GetFirstFootprint() )
584 return 0;
585
586 struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
587 {
588 PAD_PLACER( PAD_TOOL* aPadTool, PCB_BASE_EDIT_FRAME* aFrame ) :
589 m_padTool( aPadTool ),
590 m_frame( aFrame ),
591 m_gridHelper( aPadTool->GetManager(), aFrame->GetMagneticItemsSettings() )
592 {
593 neednewPadNumber = true; // Use a new pad number when creatin a pad by default
594 }
595
596 virtual ~PAD_PLACER()
597 {
598 }
599
600 std::unique_ptr<BOARD_ITEM> CreateItem() override
601 {
602 // TODO(JE) padstacks
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 the footprint type and master pad type directly conflict then make some
609 // adjustments. Otherwise assume the user set what they wanted.
610 // Note also a HEATSINK pad (thermal via) is allowed in SMD footprint
611 if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
612 && master->GetAttribute() == PAD_ATTRIB::PTH )
613 {
614 if( pad->GetProperty() != PAD_PROP::HEATSINK )
615 {
616 pad->SetAttribute( PAD_ATTRIB::SMD );
617 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::ROUNDRECT );
618 pad->SetSizeX( 1.5 * pad->GetSizeY() );
619 pad->SetLayerSet( PAD::SMDMask() );
620 }
621 }
622 else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
623 && master->GetAttribute() == PAD_ATTRIB::SMD )
624 {
625 pad->SetAttribute( PAD_ATTRIB::PTH );
626 pad->SetShape( PADSTACK::ALL_LAYERS, PAD_SHAPE::CIRCLE );
627 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pad->GetSizeX(), pad->GetSizeX() ) );
628
629 // Gives an acceptable drill size: it cannot be 0, but from pad master
630 // it is currently 0, therefore change it:
631 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
632 int hole_size = pad->GetSizeX() / 2;
633 pad->SetDrillSize( VECTOR2I( hole_size, hole_size ) );
634
635 pad->SetLayerSet( PAD::PTHMask() );
636 }
637
638 if( pad->CanHaveNumber() )
639 {
640 wxString padNumber = m_padTool->GetLastPadNumber();
641
642 // Use the last entered pad number when recreating a pad without using the
643 // previously created pad, and a new number when creating a really new pad
644 if( neednewPadNumber )
645 padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
646
647 pad->SetNumber( padNumber );
648 m_padTool->SetLastPadNumber( padNumber );
649
650 // If a pad is recreated and the previously created was not placed, use
651 // the last entered pad number
652 neednewPadNumber = false;
653 }
654
655 return std::unique_ptr<BOARD_ITEM>( pad );
656 }
657
658 bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
659 {
660 PAD* pad = dynamic_cast<PAD*>( aItem );
661 // We are using this pad number.
662 // therefore use a new pad number for a newly created pad
663 neednewPadNumber = true;
664
665 if( pad )
666 {
667 m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
668 aCommit.Add( aItem );
669 return true;
670 }
671
672 return false;
673 }
674
675 void SnapItem( BOARD_ITEM *aItem ) override
676 {
677 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
678 m_gridHelper.SetUseGrid( !( m_modifiers & MD_CTRL ) );
679
680 if( !m_gridHelper.GetSnap() )
681 return;
682
683 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
684 PAD* pad = static_cast<PAD*>( aItem );
685 VECTOR2I position = m_padTool->getViewControls()->GetMousePosition();
686 KIGFX::VIEW_CONTROLS* viewControls = m_padTool->getViewControls();
687 std::vector<BOARD_ITEM*> ignored_items( 1, pad );
688
689 if( settings->pads == MAGNETIC_OPTIONS::NO_EFFECT )
690 {
691 PADS& pads = m_board->GetFirstFootprint()->Pads();
692 ignored_items.insert( ignored_items.end(), pads.begin(), pads.end() );
693 }
694
695 if( !settings->graphics )
696 {
697 DRAWINGS& graphics = m_board->GetFirstFootprint()->GraphicalItems();
698 ignored_items.insert( ignored_items.end(), graphics.begin(), graphics.end() );
699 }
700
701 VECTOR2I cursorPos = m_gridHelper.BestSnapAnchor( position, LSET::AllLayersMask(), GRID_CURRENT, ignored_items );
702 viewControls->ForceCursorPosition( true, cursorPos );
703 aItem->SetPosition( cursorPos );
704 }
705
706 PAD_TOOL* m_padTool;
707 PCB_BASE_EDIT_FRAME* m_frame;
708 PCB_GRID_HELPER m_gridHelper;
709 };
710
711 PAD_PLACER placer( this, frame() );
712
713 doInteractiveItemPlacement( aEvent, &placer, _( "Place pad" ),
715
716 return 0;
717}
718
719
720int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
721{
723 return 0;
724
725 Activate();
726
727 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
728 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
730
731 if( m_editPad != niluuid )
732 {
733 PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
734
735 if( pad )
736 {
737 BOARD_COMMIT commit( frame() );
738 commit.Modify( pad );
739
740 std::vector<PCB_SHAPE*> mergedShapes = RecombinePad( pad, false );
741
742 for( PCB_SHAPE* shape : mergedShapes )
743 commit.Remove( shape );
744
745 commit.Push( _( "Edit Pad" ) );
746 }
747
749 }
750 else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
751 {
752 PCB_LAYER_ID layer;
753 PAD* pad = static_cast<PAD*>( selection[0] );
754 BOARD_COMMIT commit( frame() );
755
756 commit.Modify( pad );
757 explodePad( pad, &layer, commit );
758 commit.Push( _( "Edit Pad" ) );
759
761 frame()->SetActiveLayer( layer );
762
763 settings->m_PadEditModePad = pad;
765 }
766
767 if( m_editPad == niluuid )
769
770 return 0;
771}
772
773
775{
776 PAD* flaggedPad = nullptr;
777 KIID flaggedPadId = niluuid;
778
779 for( FOOTPRINT* fp : board()->Footprints() )
780 {
781 for( PAD* pad : fp->Pads() )
782 {
783 if( pad->IsEntered() )
784 {
785 flaggedPad = pad;
786 flaggedPadId = pad->m_Uuid;
787 break;
788 }
789 }
790 }
791
792 if( flaggedPadId != m_editPad )
793 {
794 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
795 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
796
797 m_editPad = flaggedPadId;
798 settings->m_PadEditModePad = flaggedPad;
799
800 if( flaggedPad )
802 else
804 }
805
806 return 0;
807}
808
809
811{
812 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
813 WX_INFOBAR* infoBar = frame()->GetInfoBar();
814 wxString msg;
815
817 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
818 {
819 return dynamic_cast<PAD*>( aItem ) != nullptr;
820 } );
821
823
824 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::NORMAL )
825 {
826 opts.m_ContrastModeDisplay = HIGH_CONTRAST_MODE::DIMMED;
827 frame()->SetDisplayOptions( opts );
828 }
829
830 if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
831 {
832 msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
834 }
835 else
836 {
837 msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
839 }
840
841 infoBar->RemoveAllButtons();
842 infoBar->ShowMessage( msg, wxICON_INFORMATION );
843}
844
845
847{
848 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view()->GetPainter() );
849 PCB_RENDER_SETTINGS* settings = painter->GetSettings();
850 PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
851
852 settings->m_PadEditModePad = nullptr;
853
855 {
857 frame()->SetDisplayOptions( opts );
858 }
859
860 // Note: KIGFX::REPAINT isn't enough for things that go from invisible to visible as
861 // they won't be found in the view layer's itemset for re-painting.
863 [&]( KIGFX::VIEW_ITEM* aItem ) -> bool
864 {
865 return dynamic_cast<PAD*>( aItem ) != nullptr;
866 } );
867
868 // Refresh now (otherwise there's an uncomfortably long pause while the infoBar
869 // closes before refresh).
870 canvas()->ForceRefresh();
871
872 frame()->GetInfoBar()->Dismiss();
873}
874
875
876void PAD_TOOL::explodePad( PAD* aPad, PCB_LAYER_ID* aLayer, BOARD_COMMIT& aCommit )
877{
878 if( aPad->IsOnLayer( F_Cu ) )
879 *aLayer = F_Cu;
880 else if( aPad->IsOnLayer( B_Cu ) )
881 *aLayer = B_Cu;
882 else
883 *aLayer = aPad->GetLayerSet().UIOrder().front();
884
885 // TODO(JE) padstacks
886 if( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CUSTOM )
887 {
888 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( PADSTACK::ALL_LAYERS ) )
889 {
890 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( primitive->Duplicate() );
891
892 shape->SetParent( board()->GetFirstFootprint() );
893 shape->Rotate( VECTOR2I( 0, 0 ), aPad->GetOrientation() );
894 shape->Move( aPad->ShapePos( PADSTACK::ALL_LAYERS ) );
895 shape->SetLayer( *aLayer );
896
897 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::SEGMENT )
898 {
899 if( aPad->GetThermalSpokeWidth() )
900 shape->SetWidth( aPad->GetThermalSpokeWidth() );
901 else
903 }
904
905 aCommit.Add( shape );
906 }
907
908 // TODO(JE) padstacks
910 aPad->DeletePrimitivesList();
911 }
912
913 aPad->SetFlags( ENTERED );
914 m_editPad = aPad->m_Uuid;
915}
916
917
918std::vector<PCB_SHAPE*> PAD_TOOL::RecombinePad( PAD* aPad, bool aIsDryRun )
919{
920 int maxError = board()->GetDesignSettings().m_MaxError;
921
922 // Don't leave an object in the point editor that might no longer exist after recombining.
924
925 return aPad->Recombine( aIsDryRun, maxError );
926}
927
928
930{
934
937
940
942}
@ 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:298
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:895
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:132
void SetWidth(int aWidth)
Definition: eda_shape.h:121
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:180
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:185
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.
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: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:273
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:1669
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:419
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:217
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1639
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:1555
Definition: kiid.h:49
LSEQ UIOrder() const
Returns the copper, technical and user layers in the order shown in layer widget.
Definition: lset.cpp:809
static LSET AllLayersMask()
Definition: lset.cpp:711
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:774
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:876
~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:929
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:720
void ExitPadEditMode()
Definition: pad_tool.cpp:846
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:810
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:572
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:918
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:1983
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:1780
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:480
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:170
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:387
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