KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_track_via_properties.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) 2015 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <core/kicad_algo.h>
31#include <footprint.h>
32#include <pad.h>
33#include <pcb_track.h>
34#include <confirm.h>
35#include <kidialog.h>
37#include <board_commit.h>
38#include <magic_enum.hpp>
39#include <macros.h>
40#include <optional>
41
42
43bool DIALOG_TRACK_VIA_PROPERTIES::IPC4761_CONFIGURATION::operator==( const IPC4761_CONFIGURATION& aOther ) const
44{
45 return ( tent == aOther.tent ) && ( plug == aOther.plug ) && ( cover == aOther.cover )
46 && ( cap == aOther.cap ) && ( fill == aOther.fill );
47}
48
49
51 const PCB_SELECTION& aItems ) :
53 m_frame( aParent ),
54 m_items( aItems ),
57 m_trackEndX( aParent, m_TrackEndXLabel, m_TrackEndXCtrl, nullptr ),
61 m_viaX( aParent, m_ViaXLabel, m_ViaXCtrl, nullptr ),
74 m_tracks( false ),
75 m_vias( false ),
79 m_padstackDirty( false )
80{
82
83 wxASSERT( !m_items.Empty() );
84
86 m_legacyTeardropsWarning->Show( m_frame->GetBoard()->LegacyTeardrops() );
87
89
93
94 m_minTrackWidthHint->SetFont( KIUI::GetInfoFont( this ).Italic() );
95
96 // Configure display origin transforms
103
104 m_TrackLayerCtrl->SetLayersHotkeys( false );
105 m_TrackLayerCtrl->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
106 m_TrackLayerCtrl->SetBoardFrame( aParent );
107 m_TrackLayerCtrl->Resync();
108
109 m_ViaStartLayer->SetLayersHotkeys( false );
110 m_ViaStartLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
111 m_ViaStartLayer->SetBoardFrame( aParent );
112 m_ViaStartLayer->Resync();
113
114 m_ViaEndLayer->SetLayersHotkeys( false );
115 m_ViaEndLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
116 m_ViaEndLayer->SetBoardFrame( aParent );
117 m_ViaEndLayer->Resync();
118
119 m_backDrillFrontLayer->SetLayersHotkeys( false );
120 m_backDrillFrontLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
121 m_backDrillFrontLayer->SetBoardFrame( aParent );
122 m_backDrillFrontLayer->SetUndefinedLayerName( _( "None" ) );
123 m_backDrillFrontLayer->Resync();
124
125 m_ViaStartLayer11->SetLayersHotkeys( false );
126 m_ViaStartLayer11->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
127 m_ViaStartLayer11->SetBoardFrame( aParent );
128 m_ViaStartLayer11->SetUndefinedLayerName( _( "None" ) );
129 m_ViaStartLayer11->Resync();
130
131 wxFont infoFont = KIUI::GetSmallInfoFont( this );
132 m_techLayersLabel->SetFont( infoFont );
133
134 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged, this );
135 m_netSelector->Bind( FILTERED_ITEM_SELECTED, &DIALOG_TRACK_VIA_PROPERTIES::onNetSelector, this );
136
137 for( auto& preset : magic_enum::enum_values<IPC4761_PRESET>() )
138 {
139 if( preset >= IPC4761_PRESET::CUSTOM )
140 continue;
141
142 const auto& name_it = m_IPC4761Names.find( preset );
143
144 wxString name = _( "Unknown choice" );
145
146 if( name_it != m_IPC4761Names.end() )
147 name = name_it->second;
148
149 m_protectionFeatures->AppendString( name );
150 }
151
153}
154
155
161
162
164{
165 // Setting widgets states/values must be in TransferDataToWindow, not in CTor
166 // otherwise states/values are overwritten by the DIALOG_SHIM::TransferDataToWindow() config values
167 bool nets = false;
168 int net = 0;
169 bool hasLocked = false;
170 bool hasUnlocked = false;
172
173 // Start and end layers of vias
174 // if at least 2 vias do not have the same start or the same end layer
175 // the layers will be set as undefined
176 int selection_first_layer = -1;
177 int selection_last_layer = -1;
178
179 // The selection layer for tracks
180 int track_selection_layer = -1;
181
182 int backdrill_start_layer = UNDEFINED_LAYER;
183 int backdrill_end_layer = UNDEFINED_LAYER;
184 bool backdrill_start_layer_set = false;
185 bool backdrill_end_layer_set = false;
186 bool backdrill_start_layer_mixed = false;
187 bool backdrill_end_layer_mixed = false;
188
189 std::optional<PAD_DRILL_POST_MACHINING_MODE> primary_post_machining_value;
190 bool primary_post_machining_set = false;
191 bool primary_post_machining_mixed = false;
192
193 std::optional<PAD_DRILL_POST_MACHINING_MODE> secondary_post_machining_value;
194 bool secondary_post_machining_set = false;
195 bool secondary_post_machining_mixed = false;
196
197 m_padstackDirty = false;
198
199 auto getAnnularRingSelection =
200 []( const PCB_VIA* via ) -> int
201 {
202 switch( via->Padstack().UnconnectedLayerMode() )
203 {
204 default:
209 }
210 };
211
212 // Look for values that are common for every item that is selected
213 for( EDA_ITEM* item : m_items )
214 {
215 if( !nets )
216 {
217 net = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode();
218 nets = true;
219 }
220 else if( net != static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode() )
221 {
222 net = -1;
223 }
224
225 switch( item->Type() )
226 {
227 case PCB_TRACE_T:
228 case PCB_ARC_T:
229 {
230 const PCB_TRACK* t = static_cast<const PCB_TRACK*>( item );
231
232 if( !m_tracks ) // first track in the list
233 {
234 m_trackStartX.SetValue( t->GetStartX() );
235 m_trackStartY.SetValue( t->GetStartY() );
236 m_trackEndX.SetValue( t->GetEndX() );
237 m_trackEndY.SetValue( t->GetEndY() );
238 m_trackWidth.SetValue( t->GetWidth() );
239 track_selection_layer = t->GetLayer();
240 m_trackHasSolderMask->SetValue ( t->HasSolderMask() );
241
242 if( t->GetLocalSolderMaskMargin().has_value() )
243 m_trackMaskMargin.SetValue( t->GetLocalSolderMaskMargin().value() );
244 else
245 m_trackMaskMargin.SetValue( wxEmptyString );
246
247 m_tracks = true;
248 }
249 else // check if values are the same for every selected track
250 {
251 if( m_trackStartX.GetValue() != t->GetStartX() )
253
254 if( m_trackStartY.GetValue() != t->GetStartY() )
256
257 if( m_trackEndX.GetValue() != t->GetEndX() )
259
260 if( m_trackEndY.GetValue() != t->GetEndY() )
262
263 if( m_trackWidth.GetValue() != t->GetWidth() )
265
266 if( track_selection_layer != t->GetLayer() )
267 track_selection_layer = UNDEFINED_LAYER;
268
269 if( m_trackHasSolderMask->GetValue() != t->HasSolderMask() )
270 m_trackHasSolderMask->Set3StateValue( wxCHK_UNDETERMINED );
271
272 if( m_trackMaskMargin.GetValue() != t->GetLocalSolderMaskMargin() )
274 }
275
276 if( t->IsLocked() )
277 hasLocked = true;
278 else
279 hasUnlocked = true;
280
281 break;
282 }
283
284 case PCB_VIA_T:
285 {
286 PCB_VIA* v = static_cast<PCB_VIA*>( item );
287
288 if( !m_vias ) // first via in the list
289 {
290 m_viaX.SetValue( v->GetPosition().x );
291 m_viaY.SetValue( v->GetPosition().y );
292 m_viaStack = std::make_unique<PADSTACK>( v->Padstack() );
293 m_viaDiameter.SetValue( v->GetWidth( m_editLayer ) );
294 m_viaDrill.SetValue( v->GetDrillValue() );
295 m_vias = true;
296 viaType = v->GetViaType();
297 m_viaNotFree->SetValue( !v->GetIsFree() );
298 m_annularRingsCtrl->SetSelection( getAnnularRingSelection( v ) );
299
300 const PADSTACK::DRILL_PROPS& secondaryDrill = v->Padstack().SecondaryDrill();
301
302 primary_post_machining_value = v->Padstack().FrontPostMachining().mode;
303 primary_post_machining_set = true;
304
305 secondary_post_machining_value = v->Padstack().BackPostMachining().mode;
306 secondary_post_machining_set = true;
307
308 backdrill_start_layer = secondaryDrill.start;
309 backdrill_start_layer_set = true;
310
311 backdrill_end_layer = secondaryDrill.end;
312 backdrill_end_layer_set = true;
313
314 selection_first_layer = v->TopLayer();
315 selection_last_layer = v->BottomLayer();
316
317 m_cbTeardrops->SetValue( v->GetTeardropParams().m_Enabled );
321 m_teardropLenPercent.SetDoubleValue( v->GetTeardropParams().m_BestLengthRatio*100.0 );
322 m_teardropWidthPercent.SetDoubleValue( v->GetTeardropParams().m_BestWidthRatio*100.0 );
325
327
328 if( preset >= IPC4761_PRESET::CUSTOM )
330 else
331 m_protectionFeatures->SetSelection( static_cast<int>( preset ) );
332 }
333 else // check if values are the same for every selected via
334 {
335 if( m_viaX.GetValue() != v->GetPosition().x )
336 m_viaX.SetValue( INDETERMINATE_STATE );
337
338 if( m_viaY.GetValue() != v->GetPosition().y )
339 m_viaY.SetValue( INDETERMINATE_STATE );
340
341 if( m_viaDiameter.GetValue() != v->GetWidth( m_editLayer ) )
343
344 if( m_viaDrill.GetValue() != v->GetDrillValue() )
346
347 if( viaType != v->GetViaType() )
348 viaType = VIATYPE::NOT_DEFINED;
349
350 if( v->GetIsFree() != !m_viaNotFree->GetValue() )
351 m_viaNotFree->Set3StateValue( wxCHK_UNDETERMINED );
352
353 if( selection_first_layer != v->TopLayer() )
354 selection_first_layer = UNDEFINED_LAYER;
355
356 if( selection_last_layer != v->BottomLayer() )
357 selection_last_layer = UNDEFINED_LAYER;
358
359 if( m_annularRingsCtrl->GetSelection() != getAnnularRingSelection( v ) )
360 {
361 if( m_annularRingsCtrl->GetStrings().size() < 4 )
363
364 m_annularRingsCtrl->SetSelection( 3 );
365 }
366
367 if( m_cbTeardrops->GetValue() != v->GetTeardropParams().m_Enabled )
368 m_cbTeardrops->Set3StateValue( wxCHK_UNDETERMINED );
369
371 m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
372
373 if( m_teardropMaxLen.GetValue() != v->GetTeardropParams().m_TdMaxLen )
375
376 if( m_teardropMaxWidth.GetValue() != v->GetTeardropParams().m_TdMaxWidth )
378
379 if( m_teardropLenPercent.GetDoubleValue() != v->GetTeardropParams().m_BestLengthRatio *100.0 )
381
382 if( m_teardropWidthPercent.GetDoubleValue() != v->GetTeardropParams().m_BestWidthRatio *100.0 )
384
385 if( m_teardropHDPercent.GetDoubleValue() != v->GetTeardropParams().m_WidthtoSizeFilterRatio*100.0 )
387
388 if( static_cast<int>( getViaConfiguration( v ) ) != m_protectionFeatures->GetSelection() )
390
391 const PADSTACK::DRILL_PROPS& secondaryDrill = v->Padstack().SecondaryDrill();
392
393 if( primary_post_machining_set && primary_post_machining_value != v->Padstack().FrontPostMachining().mode )
394 primary_post_machining_mixed = true;
395
396 if( secondary_post_machining_set && secondary_post_machining_value != v->Padstack().BackPostMachining().mode )
397 secondary_post_machining_mixed = true;
398
399 if( backdrill_start_layer_set && backdrill_start_layer != secondaryDrill.start )
400 backdrill_start_layer_mixed = true;
401
402 if( backdrill_end_layer_set && backdrill_end_layer != secondaryDrill.end )
403 backdrill_end_layer_mixed = true;
404 }
405
406 if( v->IsLocked() )
407 hasLocked = true;
408 else
409 hasUnlocked = true;
410
411 break;
412 }
413
414 default:
415 {
416 UNIMPLEMENTED_FOR( item->GetClass() );
417 break;
418 }
419 }
420 }
421
422 if( m_tracks )
423 {
424 // Set the track layer selection state:
425 if( track_selection_layer == UNDEFINED_LAYER )
426 {
427 m_TrackLayerCtrl->SetUndefinedLayerName( INDETERMINATE_STATE );
428 m_TrackLayerCtrl->Resync();
429 }
430
431 m_TrackLayerCtrl->SetLayerSelection( track_selection_layer );
432 }
433
434 // Set the vias layers selections state:
435 if( m_vias )
436 {
437 if( selection_first_layer == UNDEFINED_LAYER )
438 {
439 m_ViaStartLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
440 m_ViaStartLayer->Resync();
441 }
442
443 m_ViaStartLayer->SetLayerSelection( selection_first_layer );
444
445 if( selection_last_layer == UNDEFINED_LAYER )
446 {
447 m_ViaEndLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
448 m_ViaEndLayer->Resync();
449 }
450
451 m_ViaEndLayer->SetLayerSelection( selection_last_layer );
452
453 if( backdrill_start_layer_mixed )
454 {
456 m_backDrillFrontLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
457 m_backDrillFrontLayer->Resync();
458 m_backDrillFrontLayer->SetLayerSelection( UNDEFINED_LAYER );
459 }
460 else
461 {
463
464 if( !backdrill_start_layer_set )
465 backdrill_start_layer = UNDEFINED_LAYER;
466
467 m_backDrillFrontLayer->SetUndefinedLayerName( _( "None" ) );
468 m_backDrillFrontLayer->Resync();
469 m_backDrillFrontLayer->SetLayerSelection( backdrill_start_layer );
470 }
471
472 if( backdrill_end_layer_mixed )
473 {
475 m_ViaStartLayer11->SetUndefinedLayerName( INDETERMINATE_STATE );
476 m_ViaStartLayer11->Resync();
477 m_ViaStartLayer11->SetLayerSelection( UNDEFINED_LAYER );
478 }
479 else
480 {
482
483 if( !backdrill_end_layer_set )
484 backdrill_end_layer = UNDEFINED_LAYER;
485
486 m_ViaStartLayer11->SetUndefinedLayerName( _( "None" ) );
487 m_ViaStartLayer11->Resync();
488 m_ViaStartLayer11->SetLayerSelection( backdrill_end_layer );
489 }
490
491 // Set Backdrill Choice
492 if( backdrill_start_layer_mixed || backdrill_end_layer_mixed )
493 {
494 m_backDrillChoice->SetSelection( wxNOT_FOUND );
495 }
496 else
497 {
498 if( backdrill_start_layer != UNDEFINED_LAYER )
499 m_backDrillChoice->SetSelection( 2 ); // Top
500 else if( backdrill_end_layer != UNDEFINED_LAYER )
501 m_backDrillChoice->SetSelection( 1 ); // Bottom
502 else
503 m_backDrillChoice->SetSelection( 0 ); // None
504 }
505
506 // Post Machining
507 if( primary_post_machining_mixed )
508 {
509 m_topPostMachine->SetSelection( wxNOT_FOUND );
510 }
511 else if( primary_post_machining_set && primary_post_machining_value.has_value() )
512 {
513 switch( primary_post_machining_value.value() )
514 {
515 case PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE: m_topPostMachine->SetSelection( 2 ); break;
516 case PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK: m_topPostMachine->SetSelection( 1 ); break;
517 default: m_topPostMachine->SetSelection( 0 ); break;
518 }
519 }
520 else
521 {
522 m_topPostMachine->SetSelection( 0 );
523 }
524
525 if( secondary_post_machining_mixed )
526 {
527 m_bottomPostMachine->SetSelection( wxNOT_FOUND );
528 }
529 else if( secondary_post_machining_set && secondary_post_machining_value.has_value() )
530 {
531 switch( secondary_post_machining_value.value() )
532 {
535 default: m_bottomPostMachine->SetSelection( 0 ); break;
536 }
537 }
538 else
539 {
540 m_bottomPostMachine->SetSelection( 0 );
541 }
542 }
543
544 m_netSelector->SetNetInfo( &m_frame->GetBoard()->GetNetInfo() );
545
546 if ( net >= 0 )
547 {
548 m_netSelector->SetSelectedNetcode( net );
549 }
550 else
551 {
552 m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
553 m_netSelector->SetIndeterminate();
554 }
555
556 wxASSERT( m_tracks || m_vias );
557
558 if( m_vias )
559 {
560 if( m_viaNotFree->GetValue() && !m_tracks )
561 {
562 // Disable net selector to re-inforce meaning of "Automatically update via nets",
563 // but not when tracks are also selected as then things get harder if you want to
564 // update all the nets to match.
565 m_netSelectorLabel->Disable();
566 m_netSelector->Disable();
567 }
568
569 int viaSelection = wxNOT_FOUND;
570
571 // 0 is the netclass place-holder
572 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
573 {
574 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
575 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
576 + wxT( " / " )
577 + m_frame->StringFromValue( viaDimension->m_Drill );
578 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
579
580 if( viaSelection == wxNOT_FOUND
581 && m_viaDiameter.GetValue() == viaDimension->m_Diameter
582 && m_viaDrill.GetValue() == viaDimension->m_Drill )
583 {
584 viaSelection = ii - 1;
585 }
586 }
587
588 m_predefinedViaSizesCtrl->SetSelection( viaSelection );
589 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
590
591 m_ViaTypeChoice->Enable();
592
593 switch( viaType )
594 {
595 case VIATYPE::THROUGH: m_ViaTypeChoice->SetSelection( 0 ); break;
596 case VIATYPE::MICROVIA: m_ViaTypeChoice->SetSelection( 1 ); break;
597 case VIATYPE::BLIND: m_ViaTypeChoice->SetSelection( 2 ); break;
598 case VIATYPE::BURIED: m_ViaTypeChoice->SetSelection( 3 ); break;
599 case VIATYPE::NOT_DEFINED: m_ViaTypeChoice->SetSelection( wxNOT_FOUND ); break;
600 }
601
602 m_ViaStartLayer->Enable( viaType != VIATYPE::THROUGH );
603 m_ViaEndLayer->Enable( viaType != VIATYPE::THROUGH );
604
605 m_annularRingsLabel->Show( getLayerDepth() > 1 );
606 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
607 m_annularRingsCtrl->Enable( true );
608
610 }
611 else
612 {
613 m_viaNotFree->Hide();
614 m_MainSizer->Hide( m_sbViaSizer, true );
615 }
616
617 if( m_tracks )
618 {
619 int widthSelection = wxNOT_FOUND;
620
621 // 0 is the netclass place-holder
622 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
623 {
624 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
625 wxString msg = m_frame->StringFromValue( width );
626 m_predefinedTrackWidthsCtrl->Append( msg );
627
628 if( widthSelection == wxNOT_FOUND && m_trackWidth.GetValue() == width )
629 widthSelection = ii - 1;
630 }
631
632 m_predefinedTrackWidthsCtrl->SetSelection( widthSelection );
633 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
634
635 wxCommandEvent event;
636 onTrackEdit( event );
637 }
638 else
639 {
640 m_MainSizer->Hide( m_sbTrackSizer, true );
641 }
642
643 if( hasLocked && hasUnlocked )
644 m_lockedCbox->Set3StateValue( wxCHK_UNDETERMINED );
645 else if( hasLocked )
646 m_lockedCbox->Set3StateValue( wxCHK_CHECKED );
647 else
648 m_lockedCbox->Set3StateValue( wxCHK_UNCHECKED );
649
650 if( m_tracks )
652 else if( m_netSelector->IsEnabled() )
654 else
656
657 wxCommandEvent dummyEvent;
658 onBackdrillChange( dummyEvent );
659 onTopPostMachineChange( dummyEvent );
660 onBottomPostMachineChange( dummyEvent );
661
662 // Now all widgets have the size fixed, call FinishDialogSettings
664
665 return true;
666}
667
668
670{
671 if( m_vias )
672 {
673 int viaSel = m_predefinedViaSizesCtrl->GetSelection();
674
676
677 // 0 is the netclass place-holder
678 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
679 {
680 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
681 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
682 + wxT( " / " )
683 + m_frame->StringFromValue( viaDimension->m_Drill );
684 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
685 }
686
687 m_predefinedViaSizesCtrl->SetSelection( viaSel );
688 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
689 }
690
691 if( m_tracks )
692 {
693 int trackSel = m_predefinedTrackWidthsCtrl->GetSelection();
694
696
697 // 0 is the netclass place-holder
698 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
699 {
700 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
701 wxString msg = m_frame->StringFromValue( width );
702 m_predefinedTrackWidthsCtrl->Append( msg );
703 }
704
705 m_predefinedTrackWidthsCtrl->SetSelection( trackSel );
706 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
707 }
708
709 aEvent.Skip();
710}
711
712
713bool DIALOG_TRACK_VIA_PROPERTIES::confirmShortingNets( int aNet, const std::set<int>& shortingNets )
714{
715 wxString msg;
716
717 if( shortingNets.size() == 1 )
718 {
719 msg.Printf( _( "Applying these changes will short net %s with %s." ),
720 m_netSelector->GetValue(),
721 m_frame->GetBoard()->FindNet( *shortingNets.begin() )->GetNetname() );
722 }
723 else
724 {
725 msg.Printf( _( "Applying these changes will short net %s with other nets." ),
726 m_netSelector->GetValue() );
727 }
728
729 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
730 dlg.SetOKCancelLabels( _( "Apply Anyway" ), _( "Cancel Changes" ) );
731 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
732
733 return dlg.ShowModal() == wxID_OK;
734}
735
736
737bool DIALOG_TRACK_VIA_PROPERTIES::confirmPadChange( const std::set<PAD*>& changingPads )
738{
739 wxString msg;
740
741 if( changingPads.size() == 1 )
742 {
743 PAD* pad = *changingPads.begin();
744 msg.Printf( _( "Changing the net will also update %s pad %s to %s." ),
745 pad->GetParentFootprint()->GetReference(),
746 pad->GetNumber(),
747 m_netSelector->GetValue() );
748 }
749 else if( changingPads.size() == 2 )
750 {
751 PAD* pad1 = *changingPads.begin();
752 PAD* pad2 = *( ++changingPads.begin() );
753 msg.Printf( _( "Changing the net will also update %s pad %s and %s pad %s to %s." ),
755 pad1->GetNumber(),
757 pad2->GetNumber(),
758 m_netSelector->GetValue() );
759 }
760 else
761 {
762 msg.Printf( _( "Changing the net will also update %lu connected pads to %s." ),
763 static_cast<unsigned long>( changingPads.size() ),
764 m_netSelector->GetValue() );
765 }
766
767 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
768 dlg.SetOKCancelLabels( _( "Change Nets" ), _( "Leave Nets Unchanged" ) );
769 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
770
771 return dlg.ShowModal() == wxID_OK;
772}
773
774
776{
777 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_frame->GetBoard()->GetConnectivity();
778 std::vector<PCB_TRACK*> selected_tracks;
779 std::set<PCB_TRACK*> connected_tracks;
780
781 for( EDA_ITEM* item : m_items )
782 {
783 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
784 selected_tracks.push_back( track );
785 }
786
787 for( PCB_TRACK* selected_track : selected_tracks )
788 {
789 for( BOARD_CONNECTED_ITEM* connected_item : connectivity->GetConnectedItems( selected_track ) )
790 {
791 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( connected_item ) )
792 connected_tracks.insert( track );
793 }
794 }
795
796 // Check for malformed data ONLY; design rules and constraints are the business of DRC.
797
798 if( m_vias )
799 {
800 // TODO: This needs to move into the via class, not the dialog
801
802 std::optional<int> viaDiameter;
803
804 if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate() )
805 viaDiameter = m_viaDiameter.GetValue();
806
807 std::optional<int> viaDrill;
808
809 if( m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate() )
810 viaDrill = m_viaDrill.GetValue();
811
812 std::optional<PCB_LAYER_ID> startLayer;
813
814 if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER )
815 startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
816
817 std::optional<PCB_LAYER_ID> endLayer;
818
819 if( m_ViaEndLayer->GetLayerSelection() != UNDEFINED_LAYER )
820 endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
821
822 std::optional<int> secondaryDrill;
823
824 // Calculate backdrill size (10% larger than drill)
825 if( viaDrill.has_value() )
826 {
827 secondaryDrill = viaDrill.value() * 1.1;
828 }
829 else if( !m_viaDrill.IsIndeterminate() )
830 {
831 secondaryDrill = m_viaDrill.GetIntValue() * 1.1;
832 }
833
834 std::optional<PCB_LAYER_ID> secondaryStartLayer;
835 std::optional<PCB_LAYER_ID> secondaryEndLayer;
836
837 int backdrillChoice = m_backDrillChoice->GetSelection();
838
839 if( backdrillChoice == 1 ) // Bottom
840 {
841 secondaryStartLayer = B_Cu;
842 if( m_ViaStartLayer11->GetLayerSelection() != UNDEFINED_LAYER )
843 secondaryEndLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer11->GetLayerSelection() );
844 }
845 else if( backdrillChoice == 2 ) // Top
846 {
847 secondaryStartLayer = F_Cu;
848 if( m_backDrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
849 secondaryEndLayer = static_cast<PCB_LAYER_ID>( m_backDrillFrontLayer->GetLayerSelection() );
850 }
851 // Choice 0 is None, so optional values remain empty
852
853 // Post Machining
854 std::optional<PADSTACK::POST_MACHINING_PROPS> frontPostMachining;
855 std::optional<PADSTACK::POST_MACHINING_PROPS> backPostMachining;
856
857 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
858 {
860 switch( m_topPostMachine->GetSelection() )
861 {
865 }
866
867 if( !m_topPostMachineSize1Binder.IsIndeterminate() )
868 props.size = m_topPostMachineSize1Binder.GetIntValue();
869
870 if( !m_topPostMachineSize2Binder.IsIndeterminate() )
871 {
873 props.angle = m_topPostMachineSize2Binder.GetIntValue();
874 else
875 props.depth = m_topPostMachineSize2Binder.GetIntValue();
876 }
877 frontPostMachining = props;
878 }
879
880 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
881 {
883 switch( m_bottomPostMachine->GetSelection() )
884 {
888 }
889
890 if( !m_bottomPostMachineSize1Binder.IsIndeterminate() )
891 props.size = m_bottomPostMachineSize1Binder.GetIntValue();
892
893 if( !m_bottomPostMachineSize2Binder.IsIndeterminate() )
894 {
896 props.angle = m_bottomPostMachineSize2Binder.GetIntValue();
897 else
898 props.depth = m_bottomPostMachineSize2Binder.GetIntValue();
899 }
900 backPostMachining = props;
901 }
902
903 // Tertiary drill not supported in new UI for now
904 std::optional<int> tertiaryDrill;
905 std::optional<PCB_LAYER_ID> tertiaryStartLayer;
906 std::optional<PCB_LAYER_ID> tertiaryEndLayer;
907
908 int copperLayerCount = m_frame->GetBoard() ? m_frame->GetBoard()->GetCopperLayerCount() : 0;
909
910 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
911 PCB_VIA::ValidateViaParameters( viaDiameter, viaDrill, startLayer, endLayer,
912 secondaryDrill, secondaryStartLayer,
913 secondaryEndLayer, tertiaryDrill, tertiaryStartLayer,
914 tertiaryEndLayer, copperLayerCount ) )
915 {
916 DisplayError( GetParent(), error->m_Message );
917
918 if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DRILL )
919 {
920 m_ViaDrillCtrl->SelectAll();
921 m_ViaDrillCtrl->SetFocus();
922 }
923 else if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DIAMETER )
924 {
925 m_ViaDiameterCtrl->SelectAll();
926 m_ViaDiameterCtrl->SetFocus();
927 }
928 // Other fields might not have direct focus targets in new UI or I'd need to map them
929 return false;
930 }
931
932 }
933
934 if( m_tracks )
935 {
936 if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) )
937 return false;
938 }
939
940 // If we survived that, then save the changes:
941 //
942 // We don't bother with updating the nets at this point as it will be useless (any connected
943 // pads will simply drive their existing nets back onto the track segments and vias).
944
945 BOARD_COMMIT commit( m_frame );
946 bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED;
947 bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED;
948
949 for( PCB_TRACK* track : selected_tracks )
950 {
951 commit.Modify( track );
952
953 switch( track->Type() )
954 {
955 case PCB_TRACE_T:
956 case PCB_ARC_T:
957 {
958 wxASSERT( m_tracks );
959
960 if( !m_trackStartX.IsIndeterminate() )
961 track->SetStartX( m_trackStartX.GetIntValue() );
962
963 if( !m_trackStartY.IsIndeterminate() )
964 track->SetStartY( m_trackStartY.GetIntValue() );
965
966 if( !m_trackEndX.IsIndeterminate() )
967 track->SetEndX( m_trackEndX.GetIntValue() );
968
969 if( !m_trackEndY.IsIndeterminate() )
970 track->SetEndY( m_trackEndY.GetIntValue() );
971
972 if( !m_trackWidth.IsIndeterminate() )
973 track->SetWidth( m_trackWidth.GetIntValue() );
974
975 int layer = m_TrackLayerCtrl->GetLayerSelection();
976
977 if( layer != UNDEFINED_LAYER )
978 track->SetLayer( (PCB_LAYER_ID) layer );
979
980 if ( m_trackHasSolderMask->Get3StateValue() != wxCHK_UNDETERMINED )
981 track->SetHasSolderMask( m_trackHasSolderMask->GetValue() );
982
983 if( !m_trackMaskMargin.IsIndeterminate() )
984 {
985 if( m_trackMaskMargin.IsNull() )
986 track->SetLocalSolderMaskMargin( {} );
987 else
988 track->SetLocalSolderMaskMargin( m_trackMaskMargin.GetIntValue() );
989 }
990
991 if( changeLock )
992 track->SetLocked( setLock );
993
994 break;
995 }
996
997 case PCB_VIA_T:
998 {
999 wxASSERT( m_vias );
1000 PCB_VIA* via = static_cast<PCB_VIA*>( track );
1001 bool updatePadstack = m_padstackDirty;
1002
1003 if( !m_viaX.IsIndeterminate() )
1004 via->SetPosition( VECTOR2I( m_viaX.GetIntValue(), via->GetPosition().y ) );
1005
1006 if( !m_viaY.IsIndeterminate() )
1007 via->SetPosition( VECTOR2I( via->GetPosition().x, m_viaY.GetIntValue() ) );
1008
1009 if( m_viaNotFree->Get3StateValue() != wxCHK_UNDETERMINED )
1010 via->SetIsFree( !m_viaNotFree->GetValue() );
1011
1012 if( !m_viaDiameter.IsIndeterminate() )
1013 {
1014 int newDiameter = m_viaDiameter.GetIntValue();
1015 const VECTOR2I& currentSize = via->Padstack().Size( m_editLayer );
1016
1017 if( currentSize.x != newDiameter || currentSize.y != newDiameter )
1018 {
1019 m_viaStack->SetSize( { newDiameter, newDiameter }, m_editLayer );
1020 updatePadstack = true;
1021 }
1022 }
1023
1024 // Backdrill
1025 int backdrillChoice = m_backDrillChoice->GetSelection();
1026 if( backdrillChoice != wxNOT_FOUND )
1027 {
1028 PADSTACK::DRILL_PROPS secondaryDrill;
1029 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1030
1031 // Calculate size (10% larger)
1032 int drillSize = via->GetDrillValue();
1033 if( !m_viaDrill.IsIndeterminate() )
1034 drillSize = m_viaDrill.GetIntValue();
1035
1036 secondaryDrill.size = VECTOR2I( drillSize * 1.1, drillSize * 1.1 );
1037
1038 if( backdrillChoice == 0 ) // None
1039 {
1040 secondaryDrill.start = UNDEFINED_LAYER;
1041 secondaryDrill.end = UNDEFINED_LAYER;
1042 secondaryDrill.size = { 0, 0 };
1043 secondaryDrill.shape = PAD_DRILL_SHAPE::UNDEFINED;
1044 }
1045 else if( backdrillChoice == 1 ) // Bottom
1046 {
1047 secondaryDrill.start = B_Cu;
1048 if( m_ViaStartLayer11->GetLayerSelection() != UNDEFINED_LAYER )
1049 secondaryDrill.end = static_cast<PCB_LAYER_ID>( m_ViaStartLayer11->GetLayerSelection() );
1050 else
1051 secondaryDrill.end = UNDEFINED_LAYER; // Or keep existing?
1052 }
1053 else if( backdrillChoice == 2 ) // Top
1054 {
1055 secondaryDrill.start = F_Cu;
1056 if( m_backDrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1057 secondaryDrill.end = static_cast<PCB_LAYER_ID>( m_backDrillFrontLayer->GetLayerSelection() );
1058 else
1059 secondaryDrill.end = UNDEFINED_LAYER;
1060 }
1061
1062 if( via->Padstack().SecondaryDrill() != secondaryDrill )
1063 {
1064 m_viaStack->SecondaryDrill() = secondaryDrill;
1065 updatePadstack = true;
1066 }
1067 }
1068
1069 // Post Machining
1070 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
1071 {
1073 switch( m_topPostMachine->GetSelection() )
1074 {
1075 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1076 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1078 }
1079
1080 if( !m_topPostMachineSize1Binder.IsIndeterminate() )
1081 props.size = m_topPostMachineSize1Binder.GetIntValue();
1082 else
1083 props.size = via->Padstack().FrontPostMachining().size;
1084
1085 if( !m_topPostMachineSize2Binder.IsIndeterminate() )
1086 {
1088 props.angle = m_topPostMachineSize2Binder.GetIntValue();
1089 else
1090 props.depth = m_topPostMachineSize2Binder.GetIntValue();
1091 }
1092 else
1093 {
1094 props.angle = via->Padstack().FrontPostMachining().angle;
1095 props.depth = via->Padstack().FrontPostMachining().depth;
1096 }
1097
1098 if( via->Padstack().FrontPostMachining() != props )
1099 {
1100 m_viaStack->FrontPostMachining() = props;
1101 updatePadstack = true;
1102 }
1103 }
1104
1105 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
1106 {
1108 switch( m_bottomPostMachine->GetSelection() )
1109 {
1110 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1111 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1113 }
1114
1115 if( !m_bottomPostMachineSize1Binder.IsIndeterminate() )
1116 props.size = m_bottomPostMachineSize1Binder.GetIntValue();
1117 else
1118 props.size = via->Padstack().BackPostMachining().size;
1119
1120 if( !m_bottomPostMachineSize2Binder.IsIndeterminate() )
1121 {
1123 props.angle = m_bottomPostMachineSize2Binder.GetIntValue();
1124 else
1125 props.depth = m_bottomPostMachineSize2Binder.GetIntValue();
1126 }
1127 else
1128 {
1129 props.angle = via->Padstack().BackPostMachining().angle;
1130 props.depth = via->Padstack().BackPostMachining().depth;
1131 }
1132
1133 if( via->Padstack().BackPostMachining() != props )
1134 {
1135 m_viaStack->BackPostMachining() = props;
1136 updatePadstack = true;
1137 }
1138 }
1139
1140 switch( m_ViaTypeChoice->GetSelection() )
1141 {
1142 case 0: via->SetViaType( VIATYPE::THROUGH ); break;
1143 case 1: via->SetViaType( VIATYPE::MICROVIA ); break;
1144 case 2: via->SetViaType( VIATYPE::BLIND ); break;
1145 case 3: via->SetViaType( VIATYPE::BURIED ); break;
1146 default: break;
1147 }
1148
1149 PCB_LAYER_ID startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
1150 PCB_LAYER_ID endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
1151
1152 if( startLayer != UNDEFINED_LAYER )
1153 {
1154 if( via->Padstack().Drill().start != startLayer )
1155 {
1156 m_viaStack->Drill().start = startLayer;
1157 updatePadstack = true;
1158 }
1159
1160 via->SetTopLayer( startLayer );
1161 }
1162
1163 if( endLayer != UNDEFINED_LAYER )
1164 {
1165 if( via->Padstack().Drill().end != endLayer )
1166 {
1167 m_viaStack->Drill().end = endLayer;
1168 updatePadstack = true;
1169 }
1170
1171 via->SetBottomLayer( endLayer );
1172 }
1173
1174 if( updatePadstack )
1175 {
1176 via->SetPadstack( *m_viaStack );
1177 via->SanitizeLayers();
1178 }
1179
1180 switch( m_annularRingsCtrl->GetSelection() )
1181 {
1182 case 0:
1183 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL );
1184 break;
1185 case 1:
1186 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
1187 break;
1188 case 2:
1189 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_ALL );
1190 break;
1191 case 3:
1192 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::START_END_ONLY );
1193 break;
1194 default:
1195 break;
1196 }
1197
1198
1199 if( !m_viaDrill.IsIndeterminate() )
1200 via->SetDrill( m_viaDrill.GetIntValue() );
1201
1202 TEARDROP_PARAMETERS* targetParams = &via->GetTeardropParams();
1203
1204 if( m_cbTeardrops->Get3StateValue() != wxCHK_UNDETERMINED )
1205 targetParams->m_Enabled = m_cbTeardrops->GetValue();
1206
1207 if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
1208 targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
1209
1210 if( !m_teardropMaxLen.IsIndeterminate() )
1211 targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
1212
1213 if( !m_teardropMaxWidth.IsIndeterminate() )
1214 targetParams->m_TdMaxWidth = m_teardropMaxWidth.GetIntValue();
1215
1216 if( !m_teardropLenPercent.IsIndeterminate() )
1217 targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
1218
1219 if( !m_teardropWidthPercent.IsIndeterminate() )
1220 targetParams->m_BestWidthRatio = m_teardropWidthPercent.GetDoubleValue() / 100.0;
1221
1222 if( !m_teardropHDPercent.IsIndeterminate() )
1223 targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
1224
1225 if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
1226 targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
1227
1228 if( changeLock )
1229 via->SetLocked( setLock );
1230
1231 setViaConfiguration( via, static_cast<IPC4761_PRESET>( m_protectionFeatures->GetSelection() ) );
1232 break;
1233 }
1234
1235 default:
1236 UNIMPLEMENTED_FOR( track->GetClass() );
1237 break;
1238 }
1239 }
1240
1241 std::set<int> shortingNets;
1242 int newNetCode = m_netSelector->GetSelectedNetcode();
1243 std::set<PAD*> changingPads;
1244
1245 // Do NOT use the connectivity code here. It will propagate through zones, and we haven't
1246 // refilled those yet so it's going to pick up a whole bunch of other nets any time the track
1247 // width was increased.
1248 auto collide =
1250 {
1251 for( PCB_LAYER_ID layer : LSET( a->GetLayerSet() & b->GetLayerSet() ) )
1252 {
1253 if( a->GetEffectiveShape( layer )->Collide( b->GetEffectiveShape( layer ).get() ) )
1254 return true;
1255 }
1256
1257 return false;
1258 };
1259
1260 for( PCB_TRACK* track : connected_tracks )
1261 {
1262 for( PCB_TRACK* other : m_frame->GetBoard()->Tracks() )
1263 {
1264 if( other->GetNetCode() == track->GetNetCode() || other->GetNetCode() == newNetCode )
1265 continue;
1266
1267 if( collide( track, other ) )
1268 shortingNets.insert( other->GetNetCode() );
1269 }
1270
1271 for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
1272 {
1273 for( PAD* pad : footprint->Pads() )
1274 {
1275 if( pad->GetNetCode() == newNetCode )
1276 continue;
1277
1278 if( collide( track, pad ) )
1279 {
1280 if( pad->GetNetCode() == track->GetNetCode() )
1281 changingPads.insert( pad );
1282 else
1283 shortingNets.insert( pad->GetNetCode() );
1284 }
1285 }
1286 }
1287 }
1288
1289 if( shortingNets.size() && !confirmShortingNets( newNetCode, shortingNets ) )
1290 {
1291 commit.Revert();
1292 return true;
1293 }
1294
1295 if( !m_netSelector->IsIndeterminate() )
1296 {
1297 if( changingPads.empty() || confirmPadChange( changingPads ) )
1298 {
1299 for( PCB_TRACK* track : selected_tracks )
1300 track->SetNetCode( newNetCode );
1301
1302 for( PAD* pad : changingPads )
1303 {
1304 commit.Modify( pad );
1305 pad->SetNetCode( newNetCode );
1306 }
1307 }
1308 }
1309
1310 commit.Push( _( "Edit Track/Via Properties" ) );
1311 return true;
1312}
1313
1314
1316{
1317 m_viaNotFree->SetValue( false );
1318}
1319
1320
1322{
1323 if( !m_tracks )
1324 {
1325 m_netSelectorLabel->Enable( !m_viaNotFree->GetValue() );
1326 m_netSelector->Enable( !m_viaNotFree->GetValue() );
1327 }
1328}
1329
1330
1332{
1333 m_TrackWidthCtrl->ChangeValue( m_predefinedTrackWidthsCtrl->GetStringSelection() );
1334 m_TrackWidthCtrl->SelectAll();
1335}
1336
1337
1338void DIALOG_TRACK_VIA_PROPERTIES::onWidthEdit( wxCommandEvent& aEvent )
1339{
1340 m_predefinedTrackWidthsCtrl->SetStringSelection( m_TrackWidthCtrl->GetValue() );
1341}
1342
1343
1344void DIALOG_TRACK_VIA_PROPERTIES::onViaSelect( wxCommandEvent& aEvent )
1345{
1346 VIA_DIMENSION* viaDimension = static_cast<VIA_DIMENSION*> ( aEvent.GetClientData() );
1347
1348 m_viaDiameter.ChangeValue( viaDimension->m_Diameter );
1349 m_viaDrill.ChangeValue( viaDimension->m_Drill );
1350}
1351
1352
1354{
1355 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onPadstackModeChanged" );
1356
1357 switch( m_cbPadstackMode->GetSelection() )
1358 {
1359 default:
1360 case 0: m_viaStack->SetMode( PADSTACK::MODE::NORMAL ); break;
1361 case 1: m_viaStack->SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1362 case 2: m_viaStack->SetMode( PADSTACK::MODE::CUSTOM ); break;
1363 }
1364
1365 m_padstackDirty = true;
1366
1368}
1369
1370
1372{
1373 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onEditLayerChanged" );
1374
1375 // Save data from the previous layer
1376 if( !m_viaDiameter.IsIndeterminate() )
1377 {
1378 int diameter = m_viaDiameter.GetValue();
1379 m_viaStack->SetSize( { diameter, diameter }, m_editLayer );
1380 }
1381
1382 switch( m_viaStack->Mode() )
1383 {
1384 default:
1387 break;
1388
1390 switch( m_cbEditLayer->GetSelection() )
1391 {
1392 default:
1393 case 0: m_editLayer = F_Cu; break;
1394 case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
1395 case 2: m_editLayer = B_Cu; break;
1396 }
1397 break;
1398
1400 {
1401 int layer = m_cbEditLayer->GetSelection();
1402
1403 if( layer < 0 )
1404 layer = 0;
1405
1406 if( m_editLayerCtrlMap.contains( layer ) )
1407 m_editLayer = m_editLayerCtrlMap.at( layer );
1408 else
1409 m_editLayer = F_Cu;
1410 }
1411 }
1412
1413 // Load controls with the current layer
1414 m_viaDiameter.SetValue( m_viaStack->Size( m_editLayer ).x );
1415}
1416
1417
1419{
1420 // NOTE: synchronize changes here with DIALOG_PAD_PROPERTIES::afterPadstackModeChanged
1421
1422 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in afterPadstackModeChanged" );
1423 m_cbEditLayer->Clear();
1424
1425 BOARD* board = m_frame->GetBoard();
1426
1427 switch( m_viaStack->Mode() )
1428 {
1430 m_cbPadstackMode->SetSelection( 0 );
1431 m_cbEditLayer->Append( _( "All layers" ) );
1432 m_cbEditLayer->Disable();
1435 break;
1436
1438 {
1439 m_cbPadstackMode->SetSelection( 1 );
1440 m_cbEditLayer->Enable();
1441
1442 std::vector choices = {
1443 board->GetLayerName( F_Cu ),
1444 _( "Inner Layers" ),
1445 board->GetLayerName( B_Cu )
1446 };
1447
1448 m_cbEditLayer->Append( choices );
1449
1451 { 0, F_Cu },
1453 { 2, B_Cu }
1454 };
1455
1456 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
1458
1459 break;
1460 }
1461
1463 {
1464 m_cbPadstackMode->SetSelection( 2 );
1465 m_cbEditLayer->Enable();
1466 LSET layers = LSET::AllCuMask() & board->GetEnabledLayers();
1467
1468 for( PCB_LAYER_ID layer : layers.UIOrder() )
1469 {
1470 int idx = m_cbEditLayer->Append( board->GetLayerName( layer ) );
1471 m_editLayerCtrlMap[idx] = layer;
1472 }
1473
1474 break;
1475 }
1476 }
1477
1478 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1479 {
1480 if( layer == m_editLayer )
1481 {
1482 m_cbEditLayer->SetSelection( idx );
1483 break;
1484 }
1485 }
1486}
1487
1488
1490{
1491 int viaType = m_ViaTypeChoice->GetSelection();
1492
1493 if( viaType <= 0 )
1494 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1495
1496 int startLayer = m_ViaStartLayer->GetLayerSelection();
1497 int endLayer = m_ViaEndLayer->GetLayerSelection();
1498
1499 if( startLayer < 0 || endLayer < 0 )
1500 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1501 else
1502 return m_frame->GetBoard()->LayerDepth( ToLAYER_ID( startLayer ), ToLAYER_ID( endLayer ) );
1503}
1504
1505
1506void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
1507{
1508 m_predefinedViaSizesCtrl->SetSelection( wxNOT_FOUND );
1509
1510 if( m_vias )
1511 {
1512 if( m_ViaTypeChoice->GetSelection() != 0 ) // check if selected type isn't through.
1513 {
1514 m_ViaStartLayer->Enable();
1515 m_ViaEndLayer->Enable();
1516 }
1517 else
1518 {
1519 m_ViaStartLayer->SetLayerSelection( F_Cu );
1520 m_ViaEndLayer->SetLayerSelection( B_Cu );
1521
1522 m_ViaStartLayer->Enable( false );
1523 m_ViaEndLayer->Enable( false );
1524 }
1525
1526 m_annularRingsLabel->Show( getLayerDepth() > 1 );
1527 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
1528 m_annularRingsCtrl->Enable( true );
1529 }
1530}
1531
1532
1533void DIALOG_TRACK_VIA_PROPERTIES::onTrackEdit( wxCommandEvent& aEvent )
1534{
1535 bool externalCuLayer = m_TrackLayerCtrl->GetLayerSelection() == F_Cu
1536 || m_TrackLayerCtrl->GetLayerSelection() == B_Cu;
1537
1538 m_techLayersLabel->Enable( externalCuLayer );
1539 m_trackHasSolderMask->Enable( externalCuLayer );
1540
1541 bool showMaskMargin = externalCuLayer && m_trackHasSolderMask->GetValue();
1542
1543 m_trackMaskMarginCtrl->Enable( showMaskMargin );
1544 m_trackMaskMarginLabel->Enable( showMaskMargin );
1545 m_trackMaskMarginUnit->Enable( showMaskMargin );
1546}
1547
1548
1550{
1551 event.Enable( !m_frame->GetBoard()->LegacyTeardrops() );
1552}
1553
1554
1556{
1557 int selection = m_backDrillChoice->GetSelection();
1558 // 0: None, 1: Bottom, 2: Top, 3: Both
1559
1560 bool enableTop = ( selection == 2 || selection == 3 );
1561 bool enableBottom = ( selection == 1 || selection == 3 );
1562
1563 m_backDrillFrontLayer->Enable( enableTop );
1564 m_backDrillFrontLayerLabel->Enable( enableTop );
1565
1566 m_ViaStartLayer11->Enable( enableBottom ); // Back layer selector
1567 m_backDrillBackLayer->Enable( enableBottom ); // Back layer label
1568}
1569
1570
1572{
1573 int selection = m_topPostMachine->GetSelection();
1574 // 0: None, 1: Countersink, 2: Counterbore
1575
1576 bool enable = ( selection != 0 );
1577 m_topPostMachineSize1Binder.Enable( enable );
1578 m_topPostMachineSize2Binder.Enable( enable );
1579 m_topPostMachineSize1Label->Enable( enable );
1580 m_topPostMachineSize2Label->Enable( enable );
1581
1582 if( selection == 1 ) // Countersink
1583 {
1584 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
1585 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
1586
1587 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
1588 {
1589 m_topPostMachineSize2Binder.SetValue( "82" );
1590 }
1591 }
1592 else if( selection == 2 ) // Counterbore
1593 {
1594 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
1595 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1596 }
1597}
1598
1599
1601{
1602 int selection = m_bottomPostMachine->GetSelection();
1603 // 0: None, 1: Countersink, 2: Counterbore
1604
1605 bool enable = ( selection != 0 );
1606 m_bottomPostMachineSize1Binder.Enable( enable );
1607 m_bottomPostMachineSize2Binder.Enable( enable );
1608 m_bottomPostMachineSize1Label->Enable( enable );
1609 m_bottomPostMachineSize2Label->Enable( enable );
1610
1611 if( selection == 1 ) // Countersink
1612 {
1613 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
1614 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
1615
1616 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
1617 {
1618 m_bottomPostMachineSize2Binder.SetValue( "82" );
1619 }
1620 }
1621 else if( selection == 2 ) // Counterbore
1622 {
1623 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
1624 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1625 }
1626}
1627
1628
const char * name
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
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 derived from BOARD_ITEM for items that can be connected and have a net,...
TEARDROP_PARAMETERS & GetTeardropParams()
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
bool IsLocked() const override
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:256
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:715
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:954
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:106
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:82
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool m_useCalculatedSize
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
DIALOG_TRACK_VIA_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Track & Via Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU)
void onWidthEdit(wxCommandEvent &aEvent) override
void onUnitsChanged(wxCommandEvent &aEvent)
void onNetSelector(wxCommandEvent &aEvent)
void afterPadstackModeChanged()
Get data from the PCB board and display it to dialog.
void onWidthSelect(wxCommandEvent &aEvent) override
bool confirmShortingNets(int aNet, const std::set< int > &shortingNets)
void onTeardropsUpdateUi(wxUpdateUIEvent &event) override
void onPadstackModeChanged(wxCommandEvent &aEvent) override
void onBackdrillChange(wxCommandEvent &aEvent) override
void onViaEdit(wxCommandEvent &aEvent) override
std::map< int, PCB_LAYER_ID > m_editLayerCtrlMap
PCB_LAYER_ID m_editLayer
The currently-shown copper layer of the edited via(s)
void onViaSelect(wxCommandEvent &aEvent) override
void onBottomPostMachineChange(wxCommandEvent &aEvent) override
void onEditLayerChanged(wxCommandEvent &aEvent) override
void onTopPostMachineChange(wxCommandEvent &aEvent) override
void onViaNotFreeClicked(wxCommandEvent &aEvent) override
DIALOG_TRACK_VIA_PROPERTIES(PCB_BASE_EDIT_FRAME *aParent, const PCB_SELECTION &aItems)
std::unique_ptr< PADSTACK > m_viaStack
Temporary padstack of the edited via(s)
bool confirmPadChange(const std::set< PAD * > &connectedPads)
void onTrackEdit(wxCommandEvent &aEvent) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const wxString & GetReference() const
Definition footprint.h:661
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
Definition kidialog.h:52
int ShowModal() override
Definition kidialog.cpp:93
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:726
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:610
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:157
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:344
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:171
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:173
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:172
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:338
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:347
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:180
Definition pad.h:55
const wxString & GetNumber() const
Definition pad.h:137
Common, abstract interface for edit frames.
bool HasSolderMask() const
Definition pcb_track.h:178
int GetStartY() const
Definition pcb_track.h:160
int GetEndX() const
Definition pcb_track.h:165
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:181
int GetEndY() const
Definition pcb_track.h:166
int GetStartX() const
Definition pcb_track.h:159
virtual int GetWidth() const
Definition pcb_track.h:148
bool GetIsFree() const
Check if the via is a free via (as opposed to one created on a track by the router).
Definition pcb_track.h:867
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:614
const PADSTACK & Padstack() const
Definition pcb_track.h:463
static std::optional< VIA_PARAMETER_ERROR > ValidateViaParameters(std::optional< int > aDiameter, std::optional< int > aPrimaryDrill, std::optional< PCB_LAYER_ID > aPrimaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aPrimaryEndLayer=std::nullopt, std::optional< int > aSecondaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryEndLayer=std::nullopt, std::optional< int > aTertiaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryEndLayer=std::nullopt, int aCopperLayerCount=0)
int GetWidth() const override
PCB_LAYER_ID TopLayer() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
VIATYPE GetViaType() const
Definition pcb_track.h:455
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:181
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
IPC4761_PRESET getViaConfiguration(const PCB_VIA *aVia)
const std::map< IPC4761_PRESET, wxString > m_IPC4761Names
void setViaConfiguration(PCB_VIA *aVia, const IPC4761_PRESET &aPreset)
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
#define _(s)
@ ALL_LAYERS
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:737
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:114
VIATYPE
Definition pcb_track.h:67
@ THROUGH
Definition pcb_track.h:68
@ NOT_DEFINED
Definition pcb_track.h:73
@ MICROVIA
Definition pcb_track.h:71
bool collide(T aObject, U aAnotherObject, int aLayer, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition shape_index.h:97
! The properties of a padstack drill. Drill position is always the pad position (origin).
Definition padstack.h:261
PCB_LAYER_ID start
Definition padstack.h:264
PCB_LAYER_ID end
Definition padstack.h:265
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:262
PAD_DRILL_SHAPE shape
Definition padstack.h:263
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:275
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
#define INDETERMINATE_ACTION
Definition ui_common.h:47
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695