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 m_postMachineSectionLabel->SetFont( infoFont );
134
135 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged, this );
136 m_netSelector->Bind( FILTERED_ITEM_SELECTED, &DIALOG_TRACK_VIA_PROPERTIES::onNetSelector, this );
137
138 for( auto& preset : magic_enum::enum_values<IPC4761_PRESET>() )
139 {
140 if( preset >= IPC4761_PRESET::CUSTOM )
141 continue;
142
143 const auto& name_it = m_IPC4761Names.find( preset );
144
145 wxString name = _( "Unknown choice" );
146
147 if( name_it != m_IPC4761Names.end() )
148 name = name_it->second;
149
150 m_protectionFeatures->AppendString( name );
151 }
152
154}
155
156
162
163
165{
166 // Setting widgets states/values must be in TransferDataToWindow, not in CTor
167 // otherwise states/values are overwritten by the DIALOG_SHIM::TransferDataToWindow() config values
168 bool nets = false;
169 int net = 0;
170 bool hasLocked = false;
171 bool hasUnlocked = false;
173
174 // Start and end layers of vias
175 // if at least 2 vias do not have the same start or the same end layer
176 // the layers will be set as undefined
177 int selection_first_layer = -1;
178 int selection_last_layer = -1;
179
180 // The selection layer for tracks
181 int track_selection_layer = -1;
182
183 int backdrill_start_layer = UNDEFINED_LAYER;
184 int backdrill_end_layer = UNDEFINED_LAYER;
185 bool backdrill_start_layer_set = false;
186 bool backdrill_end_layer_set = false;
187 bool backdrill_start_layer_mixed = false;
188 bool backdrill_end_layer_mixed = false;
189
190 std::optional<PAD_DRILL_POST_MACHINING_MODE> primary_post_machining_value;
191 bool primary_post_machining_set = false;
192 bool primary_post_machining_mixed = false;
193
194 std::optional<PAD_DRILL_POST_MACHINING_MODE> secondary_post_machining_value;
195 bool secondary_post_machining_set = false;
196 bool secondary_post_machining_mixed = false;
197
198 m_padstackDirty = false;
199
200 auto getAnnularRingSelection =
201 []( const PCB_VIA* via ) -> int
202 {
203 switch( via->Padstack().UnconnectedLayerMode() )
204 {
205 default:
210 }
211 };
212
213 // Look for values that are common for every item that is selected
214 for( EDA_ITEM* item : m_items )
215 {
216 if( !nets )
217 {
218 net = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode();
219 nets = true;
220 }
221 else if( net != static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode() )
222 {
223 net = -1;
224 }
225
226 switch( item->Type() )
227 {
228 case PCB_TRACE_T:
229 case PCB_ARC_T:
230 {
231 const PCB_TRACK* t = static_cast<const PCB_TRACK*>( item );
232
233 if( !m_tracks ) // first track in the list
234 {
235 m_trackStartX.SetValue( t->GetStartX() );
236 m_trackStartY.SetValue( t->GetStartY() );
237 m_trackEndX.SetValue( t->GetEndX() );
238 m_trackEndY.SetValue( t->GetEndY() );
239 m_trackWidth.SetValue( t->GetWidth() );
240 track_selection_layer = t->GetLayer();
241 m_trackHasSolderMask->SetValue ( t->HasSolderMask() );
242
243 if( t->GetLocalSolderMaskMargin().has_value() )
244 m_trackMaskMargin.SetValue( t->GetLocalSolderMaskMargin().value() );
245 else
246 m_trackMaskMargin.SetValue( wxEmptyString );
247
248 m_tracks = true;
249 }
250 else // check if values are the same for every selected track
251 {
252 if( m_trackStartX.GetValue() != t->GetStartX() )
254
255 if( m_trackStartY.GetValue() != t->GetStartY() )
257
258 if( m_trackEndX.GetValue() != t->GetEndX() )
260
261 if( m_trackEndY.GetValue() != t->GetEndY() )
263
264 if( m_trackWidth.GetValue() != t->GetWidth() )
266
267 if( track_selection_layer != t->GetLayer() )
268 track_selection_layer = UNDEFINED_LAYER;
269
270 if( m_trackHasSolderMask->GetValue() != t->HasSolderMask() )
271 m_trackHasSolderMask->Set3StateValue( wxCHK_UNDETERMINED );
272
273 if( m_trackMaskMargin.GetValue() != t->GetLocalSolderMaskMargin() )
275 }
276
277 if( t->IsLocked() )
278 hasLocked = true;
279 else
280 hasUnlocked = true;
281
282 break;
283 }
284
285 case PCB_VIA_T:
286 {
287 PCB_VIA* v = static_cast<PCB_VIA*>( item );
288
289 if( !m_vias ) // first via in the list
290 {
291 m_viaX.SetValue( v->GetPosition().x );
292 m_viaY.SetValue( v->GetPosition().y );
293 m_viaStack = std::make_unique<PADSTACK>( v->Padstack() );
294 m_viaDiameter.SetValue( v->GetWidth( m_editLayer ) );
295 m_viaDrill.SetValue( v->GetDrillValue() );
296 m_vias = true;
297 viaType = v->GetViaType();
298 m_viaNotFree->SetValue( !v->GetIsFree() );
299 m_annularRingsCtrl->SetSelection( getAnnularRingSelection( v ) );
300
301 const PADSTACK::DRILL_PROPS& secondaryDrill = v->Padstack().SecondaryDrill();
302
303 primary_post_machining_value = v->Padstack().FrontPostMachining().mode;
304 primary_post_machining_set = true;
305
306 secondary_post_machining_value = v->Padstack().BackPostMachining().mode;
307 secondary_post_machining_set = true;
308
309 backdrill_start_layer = secondaryDrill.start;
310 backdrill_start_layer_set = true;
311
312 backdrill_end_layer = secondaryDrill.end;
313 backdrill_end_layer_set = true;
314
315 selection_first_layer = v->TopLayer();
316 selection_last_layer = v->BottomLayer();
317
318 m_cbTeardrops->SetValue( v->GetTeardropParams().m_Enabled );
322 m_teardropLenPercent.SetDoubleValue( v->GetTeardropParams().m_BestLengthRatio*100.0 );
323 m_teardropWidthPercent.SetDoubleValue( v->GetTeardropParams().m_BestWidthRatio*100.0 );
326
328
329 if( preset >= IPC4761_PRESET::CUSTOM )
331 else
332 m_protectionFeatures->SetSelection( static_cast<int>( preset ) );
333 }
334 else // check if values are the same for every selected via
335 {
336 if( m_viaX.GetValue() != v->GetPosition().x )
337 m_viaX.SetValue( INDETERMINATE_STATE );
338
339 if( m_viaY.GetValue() != v->GetPosition().y )
340 m_viaY.SetValue( INDETERMINATE_STATE );
341
342 if( m_viaDiameter.GetValue() != v->GetWidth( m_editLayer ) )
344
345 if( m_viaDrill.GetValue() != v->GetDrillValue() )
347
348 if( viaType != v->GetViaType() )
349 viaType = VIATYPE::NOT_DEFINED;
350
351 if( v->GetIsFree() != !m_viaNotFree->GetValue() )
352 m_viaNotFree->Set3StateValue( wxCHK_UNDETERMINED );
353
354 if( selection_first_layer != v->TopLayer() )
355 selection_first_layer = UNDEFINED_LAYER;
356
357 if( selection_last_layer != v->BottomLayer() )
358 selection_last_layer = UNDEFINED_LAYER;
359
360 if( m_annularRingsCtrl->GetSelection() != getAnnularRingSelection( v ) )
361 {
362 if( m_annularRingsCtrl->GetStrings().size() < 4 )
364
365 m_annularRingsCtrl->SetSelection( 3 );
366 }
367
368 if( m_cbTeardrops->GetValue() != v->GetTeardropParams().m_Enabled )
369 m_cbTeardrops->Set3StateValue( wxCHK_UNDETERMINED );
370
372 m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
373
374 if( m_teardropMaxLen.GetValue() != v->GetTeardropParams().m_TdMaxLen )
376
377 if( m_teardropMaxWidth.GetValue() != v->GetTeardropParams().m_TdMaxWidth )
379
380 if( m_teardropLenPercent.GetDoubleValue() != v->GetTeardropParams().m_BestLengthRatio *100.0 )
382
383 if( m_teardropWidthPercent.GetDoubleValue() != v->GetTeardropParams().m_BestWidthRatio *100.0 )
385
386 if( m_teardropHDPercent.GetDoubleValue() != v->GetTeardropParams().m_WidthtoSizeFilterRatio*100.0 )
388
389 if( static_cast<int>( getViaConfiguration( v ) ) != m_protectionFeatures->GetSelection() )
391
392 const PADSTACK::DRILL_PROPS& secondaryDrill = v->Padstack().SecondaryDrill();
393
394 if( primary_post_machining_set && primary_post_machining_value != v->Padstack().FrontPostMachining().mode )
395 primary_post_machining_mixed = true;
396
397 if( secondary_post_machining_set && secondary_post_machining_value != v->Padstack().BackPostMachining().mode )
398 secondary_post_machining_mixed = true;
399
400 if( backdrill_start_layer_set && backdrill_start_layer != secondaryDrill.start )
401 backdrill_start_layer_mixed = true;
402
403 if( backdrill_end_layer_set && backdrill_end_layer != secondaryDrill.end )
404 backdrill_end_layer_mixed = true;
405 }
406
407 if( v->IsLocked() )
408 hasLocked = true;
409 else
410 hasUnlocked = true;
411
412 break;
413 }
414
415 default:
416 {
417 UNIMPLEMENTED_FOR( item->GetClass() );
418 break;
419 }
420 }
421 }
422
423 if( m_tracks )
424 {
425 // Set the track layer selection state:
426 if( track_selection_layer == UNDEFINED_LAYER )
427 {
428 m_TrackLayerCtrl->SetUndefinedLayerName( INDETERMINATE_STATE );
429 m_TrackLayerCtrl->Resync();
430 }
431
432 m_TrackLayerCtrl->SetLayerSelection( track_selection_layer );
433 }
434
435 // Set the vias layers selections state:
436 if( m_vias )
437 {
438 if( selection_first_layer == UNDEFINED_LAYER )
439 {
440 m_ViaStartLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
441 m_ViaStartLayer->Resync();
442 }
443
444 m_ViaStartLayer->SetLayerSelection( selection_first_layer );
445
446 if( selection_last_layer == UNDEFINED_LAYER )
447 {
448 m_ViaEndLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
449 m_ViaEndLayer->Resync();
450 }
451
452 m_ViaEndLayer->SetLayerSelection( selection_last_layer );
453
454 if( backdrill_start_layer_mixed )
455 {
457 m_backDrillFrontLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
458 m_backDrillFrontLayer->Resync();
459 m_backDrillFrontLayer->SetLayerSelection( UNDEFINED_LAYER );
460 }
461 else
462 {
464
465 if( !backdrill_start_layer_set )
466 backdrill_start_layer = UNDEFINED_LAYER;
467
468 m_backDrillFrontLayer->SetUndefinedLayerName( _( "None" ) );
469 m_backDrillFrontLayer->Resync();
470 m_backDrillFrontLayer->SetLayerSelection( backdrill_start_layer );
471 }
472
473 if( backdrill_end_layer_mixed )
474 {
476 m_ViaStartLayer11->SetUndefinedLayerName( INDETERMINATE_STATE );
477 m_ViaStartLayer11->Resync();
478 m_ViaStartLayer11->SetLayerSelection( UNDEFINED_LAYER );
479 }
480 else
481 {
483
484 if( !backdrill_end_layer_set )
485 backdrill_end_layer = UNDEFINED_LAYER;
486
487 m_ViaStartLayer11->SetUndefinedLayerName( _( "None" ) );
488 m_ViaStartLayer11->Resync();
489 m_ViaStartLayer11->SetLayerSelection( backdrill_end_layer );
490 }
491
492 // Set Backdrill Choice
493 if( backdrill_start_layer_mixed || backdrill_end_layer_mixed )
494 {
495 m_backDrillChoice->SetSelection( wxNOT_FOUND );
496 }
497 else
498 {
499 if( backdrill_start_layer != UNDEFINED_LAYER )
500 m_backDrillChoice->SetSelection( 2 ); // Top
501 else if( backdrill_end_layer != UNDEFINED_LAYER )
502 m_backDrillChoice->SetSelection( 1 ); // Bottom
503 else
504 m_backDrillChoice->SetSelection( 0 ); // None
505 }
506
507 // Post Machining
508 if( primary_post_machining_mixed )
509 {
510 m_topPostMachine->SetSelection( wxNOT_FOUND );
511 }
512 else if( primary_post_machining_set && primary_post_machining_value.has_value() )
513 {
514 switch( primary_post_machining_value.value() )
515 {
516 case PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE: m_topPostMachine->SetSelection( 2 ); break;
517 case PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK: m_topPostMachine->SetSelection( 1 ); break;
518 default: m_topPostMachine->SetSelection( 0 ); break;
519 }
520 }
521 else
522 {
523 m_topPostMachine->SetSelection( 0 );
524 }
525
526 if( secondary_post_machining_mixed )
527 {
528 m_bottomPostMachine->SetSelection( wxNOT_FOUND );
529 }
530 else if( secondary_post_machining_set && secondary_post_machining_value.has_value() )
531 {
532 switch( secondary_post_machining_value.value() )
533 {
536 default: m_bottomPostMachine->SetSelection( 0 ); break;
537 }
538 }
539 else
540 {
541 m_bottomPostMachine->SetSelection( 0 );
542 }
543 }
544
545 m_netSelector->SetNetInfo( &m_frame->GetBoard()->GetNetInfo() );
546
547 if ( net >= 0 )
548 {
549 m_netSelector->SetSelectedNetcode( net );
550 }
551 else
552 {
553 m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
554 m_netSelector->SetIndeterminate();
555 }
556
557 wxASSERT( m_tracks || m_vias );
558
559 if( m_vias )
560 {
561 if( m_viaNotFree->GetValue() && !m_tracks )
562 {
563 // Disable net selector to re-inforce meaning of "Automatically update via nets",
564 // but not when tracks are also selected as then things get harder if you want to
565 // update all the nets to match.
566 m_netSelectorLabel->Disable();
567 m_netSelector->Disable();
568 }
569
570 int viaSelection = wxNOT_FOUND;
571
572 // 0 is the netclass place-holder
573 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
574 {
575 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
576 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
577 + wxT( " / " )
578 + m_frame->StringFromValue( viaDimension->m_Drill );
579 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
580
581 if( viaSelection == wxNOT_FOUND
582 && m_viaDiameter.GetValue() == viaDimension->m_Diameter
583 && m_viaDrill.GetValue() == viaDimension->m_Drill )
584 {
585 viaSelection = ii - 1;
586 }
587 }
588
589 m_predefinedViaSizesCtrl->SetSelection( viaSelection );
590 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
591
592 m_ViaTypeChoice->Enable();
593
594 switch( viaType )
595 {
596 case VIATYPE::THROUGH: m_ViaTypeChoice->SetSelection( 0 ); break;
597 case VIATYPE::MICROVIA: m_ViaTypeChoice->SetSelection( 1 ); break;
598 case VIATYPE::BLIND: m_ViaTypeChoice->SetSelection( 2 ); break;
599 case VIATYPE::BURIED: m_ViaTypeChoice->SetSelection( 3 ); break;
600 case VIATYPE::NOT_DEFINED: m_ViaTypeChoice->SetSelection( wxNOT_FOUND ); break;
601 }
602
603 m_ViaStartLayer->Enable( viaType != VIATYPE::THROUGH );
604 m_ViaEndLayer->Enable( viaType != VIATYPE::THROUGH );
605
606 m_annularRingsLabel->Show( getLayerDepth() > 1 );
607 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
608 m_annularRingsCtrl->Enable( true );
609
611 }
612 else
613 {
614 m_viaNotFree->Hide();
615 m_MainSizer->Hide( m_sbViaSizer, true );
616 }
617
618 if( m_tracks )
619 {
620 int widthSelection = wxNOT_FOUND;
621
622 // 0 is the netclass place-holder
623 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
624 {
625 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
626 wxString msg = m_frame->StringFromValue( width );
627 m_predefinedTrackWidthsCtrl->Append( msg );
628
629 if( widthSelection == wxNOT_FOUND && m_trackWidth.GetValue() == width )
630 widthSelection = ii - 1;
631 }
632
633 m_predefinedTrackWidthsCtrl->SetSelection( widthSelection );
634 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
635
636 wxCommandEvent event;
637 onTrackEdit( event );
638 }
639 else
640 {
641 m_MainSizer->Hide( m_sbTrackSizer, true );
642 }
643
644 if( hasLocked && hasUnlocked )
645 m_lockedCbox->Set3StateValue( wxCHK_UNDETERMINED );
646 else if( hasLocked )
647 m_lockedCbox->Set3StateValue( wxCHK_CHECKED );
648 else
649 m_lockedCbox->Set3StateValue( wxCHK_UNCHECKED );
650
651 if( m_tracks )
653 else if( m_netSelector->IsEnabled() )
655 else
657
658 wxCommandEvent dummyEvent;
659 onBackdrillChange( dummyEvent );
660 onTopPostMachineChange( dummyEvent );
661 onBottomPostMachineChange( dummyEvent );
662
663 // Now all widgets have the size fixed, call FinishDialogSettings
665
666 return true;
667}
668
669
671{
672 if( m_vias )
673 {
674 int viaSel = m_predefinedViaSizesCtrl->GetSelection();
675
677
678 // 0 is the netclass place-holder
679 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
680 {
681 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
682 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
683 + wxT( " / " )
684 + m_frame->StringFromValue( viaDimension->m_Drill );
685 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
686 }
687
688 m_predefinedViaSizesCtrl->SetSelection( viaSel );
689 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
690 }
691
692 if( m_tracks )
693 {
694 int trackSel = m_predefinedTrackWidthsCtrl->GetSelection();
695
697
698 // 0 is the netclass place-holder
699 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
700 {
701 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
702 wxString msg = m_frame->StringFromValue( width );
703 m_predefinedTrackWidthsCtrl->Append( msg );
704 }
705
706 m_predefinedTrackWidthsCtrl->SetSelection( trackSel );
707 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
708 }
709
710 aEvent.Skip();
711}
712
713
714bool DIALOG_TRACK_VIA_PROPERTIES::confirmShortingNets( int aNet, const std::set<int>& shortingNets )
715{
716 wxString msg;
717
718 if( shortingNets.size() == 1 )
719 {
720 msg.Printf( _( "Applying these changes will short net %s with %s." ),
721 m_netSelector->GetValue(),
722 m_frame->GetBoard()->FindNet( *shortingNets.begin() )->GetNetname() );
723 }
724 else
725 {
726 msg.Printf( _( "Applying these changes will short net %s with other nets." ),
727 m_netSelector->GetValue() );
728 }
729
730 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
731 dlg.SetOKCancelLabels( _( "Apply Anyway" ), _( "Cancel Changes" ) );
732 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
733
734 return dlg.ShowModal() == wxID_OK;
735}
736
737
738bool DIALOG_TRACK_VIA_PROPERTIES::confirmPadChange( const std::set<PAD*>& changingPads )
739{
740 wxString msg;
741
742 if( changingPads.size() == 1 )
743 {
744 PAD* pad = *changingPads.begin();
745 msg.Printf( _( "Changing the net will also update %s pad %s to %s." ),
746 pad->GetParentFootprint()->GetReference(),
747 pad->GetNumber(),
748 m_netSelector->GetValue() );
749 }
750 else if( changingPads.size() == 2 )
751 {
752 PAD* pad1 = *changingPads.begin();
753 PAD* pad2 = *( ++changingPads.begin() );
754 msg.Printf( _( "Changing the net will also update %s pad %s and %s pad %s to %s." ),
756 pad1->GetNumber(),
758 pad2->GetNumber(),
759 m_netSelector->GetValue() );
760 }
761 else
762 {
763 msg.Printf( _( "Changing the net will also update %lu connected pads to %s." ),
764 static_cast<unsigned long>( changingPads.size() ),
765 m_netSelector->GetValue() );
766 }
767
768 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
769 dlg.SetOKCancelLabels( _( "Change Nets" ), _( "Leave Nets Unchanged" ) );
770 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
771
772 return dlg.ShowModal() == wxID_OK;
773}
774
775
777{
778 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_frame->GetBoard()->GetConnectivity();
779 std::vector<PCB_TRACK*> selected_tracks;
780 std::set<PCB_TRACK*> connected_tracks;
781
782 for( EDA_ITEM* item : m_items )
783 {
784 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
785 selected_tracks.push_back( track );
786 }
787
788 for( PCB_TRACK* selected_track : selected_tracks )
789 {
790 for( BOARD_CONNECTED_ITEM* connected_item : connectivity->GetConnectedItems( selected_track ) )
791 {
792 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( connected_item ) )
793 connected_tracks.insert( track );
794 }
795 }
796
797 // Check for malformed data ONLY; design rules and constraints are the business of DRC.
798
799 if( m_vias )
800 {
801 // TODO: This needs to move into the via class, not the dialog
802
803 std::optional<int> viaDiameter;
804
805 if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate() )
806 viaDiameter = m_viaDiameter.GetValue();
807
808 std::optional<int> viaDrill;
809
810 if( m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate() )
811 viaDrill = m_viaDrill.GetValue();
812
813 std::optional<PCB_LAYER_ID> startLayer;
814
815 if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER )
816 startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
817
818 std::optional<PCB_LAYER_ID> endLayer;
819
820 if( m_ViaEndLayer->GetLayerSelection() != UNDEFINED_LAYER )
821 endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
822
823 std::optional<int> secondaryDrill;
824
825 // Calculate backdrill size (10% larger than drill)
826 if( viaDrill.has_value() )
827 {
828 secondaryDrill = viaDrill.value() * 1.1;
829 }
830 else if( !m_viaDrill.IsIndeterminate() )
831 {
832 secondaryDrill = m_viaDrill.GetIntValue() * 1.1;
833 }
834
835 std::optional<PCB_LAYER_ID> secondaryStartLayer;
836 std::optional<PCB_LAYER_ID> secondaryEndLayer;
837
838 int backdrillChoice = m_backDrillChoice->GetSelection();
839
840 if( backdrillChoice == 1 ) // Bottom
841 {
842 secondaryStartLayer = B_Cu;
843 if( m_ViaStartLayer11->GetLayerSelection() != UNDEFINED_LAYER )
844 secondaryEndLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer11->GetLayerSelection() );
845 }
846 else if( backdrillChoice == 2 ) // Top
847 {
848 secondaryStartLayer = F_Cu;
849 if( m_backDrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
850 secondaryEndLayer = static_cast<PCB_LAYER_ID>( m_backDrillFrontLayer->GetLayerSelection() );
851 }
852 // Choice 0 is None, so optional values remain empty
853
854 // Post Machining
855 std::optional<PADSTACK::POST_MACHINING_PROPS> frontPostMachining;
856 std::optional<PADSTACK::POST_MACHINING_PROPS> backPostMachining;
857
858 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
859 {
861 switch( m_topPostMachine->GetSelection() )
862 {
866 }
867
868 if( !m_topPostMachineSize1Binder.IsIndeterminate() )
869 props.size = m_topPostMachineSize1Binder.GetIntValue();
870
871 if( !m_topPostMachineSize2Binder.IsIndeterminate() )
872 {
874 props.angle = m_topPostMachineSize2Binder.GetIntValue();
875 else
876 props.depth = m_topPostMachineSize2Binder.GetIntValue();
877 }
878 frontPostMachining = props;
879 }
880
881 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
882 {
884 switch( m_bottomPostMachine->GetSelection() )
885 {
889 }
890
891 if( !m_bottomPostMachineSize1Binder.IsIndeterminate() )
892 props.size = m_bottomPostMachineSize1Binder.GetIntValue();
893
894 if( !m_bottomPostMachineSize2Binder.IsIndeterminate() )
895 {
897 props.angle = m_bottomPostMachineSize2Binder.GetIntValue();
898 else
899 props.depth = m_bottomPostMachineSize2Binder.GetIntValue();
900 }
901 backPostMachining = props;
902 }
903
904 // Tertiary drill not supported in new UI for now
905 std::optional<int> tertiaryDrill;
906 std::optional<PCB_LAYER_ID> tertiaryStartLayer;
907 std::optional<PCB_LAYER_ID> tertiaryEndLayer;
908
909 int copperLayerCount = m_frame->GetBoard() ? m_frame->GetBoard()->GetCopperLayerCount() : 0;
910
911 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
912 PCB_VIA::ValidateViaParameters( viaDiameter, viaDrill, startLayer, endLayer,
913 secondaryDrill, secondaryStartLayer,
914 secondaryEndLayer, tertiaryDrill, tertiaryStartLayer,
915 tertiaryEndLayer, copperLayerCount ) )
916 {
917 DisplayError( GetParent(), error->m_Message );
918
919 if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DRILL )
920 {
921 m_ViaDrillCtrl->SelectAll();
922 m_ViaDrillCtrl->SetFocus();
923 }
924 else if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DIAMETER )
925 {
926 m_ViaDiameterCtrl->SelectAll();
927 m_ViaDiameterCtrl->SetFocus();
928 }
929 // Other fields might not have direct focus targets in new UI or I'd need to map them
930 return false;
931 }
932
933 }
934
935 if( m_tracks )
936 {
937 if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) )
938 return false;
939 }
940
941 // If we survived that, then save the changes:
942 //
943 // We don't bother with updating the nets at this point as it will be useless (any connected
944 // pads will simply drive their existing nets back onto the track segments and vias).
945
946 BOARD_COMMIT commit( m_frame );
947 bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED;
948 bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED;
949
950 for( PCB_TRACK* track : selected_tracks )
951 {
952 commit.Modify( track );
953
954 switch( track->Type() )
955 {
956 case PCB_TRACE_T:
957 case PCB_ARC_T:
958 {
959 wxASSERT( m_tracks );
960
961 if( !m_trackStartX.IsIndeterminate() )
962 track->SetStartX( m_trackStartX.GetIntValue() );
963
964 if( !m_trackStartY.IsIndeterminate() )
965 track->SetStartY( m_trackStartY.GetIntValue() );
966
967 if( !m_trackEndX.IsIndeterminate() )
968 track->SetEndX( m_trackEndX.GetIntValue() );
969
970 if( !m_trackEndY.IsIndeterminate() )
971 track->SetEndY( m_trackEndY.GetIntValue() );
972
973 if( !m_trackWidth.IsIndeterminate() )
974 track->SetWidth( m_trackWidth.GetIntValue() );
975
976 int layer = m_TrackLayerCtrl->GetLayerSelection();
977
978 if( layer != UNDEFINED_LAYER )
979 track->SetLayer( (PCB_LAYER_ID) layer );
980
981 if ( m_trackHasSolderMask->Get3StateValue() != wxCHK_UNDETERMINED )
982 track->SetHasSolderMask( m_trackHasSolderMask->GetValue() );
983
984 if( !m_trackMaskMargin.IsIndeterminate() )
985 {
986 if( m_trackMaskMargin.IsNull() )
987 track->SetLocalSolderMaskMargin( {} );
988 else
989 track->SetLocalSolderMaskMargin( m_trackMaskMargin.GetIntValue() );
990 }
991
992 if( changeLock )
993 track->SetLocked( setLock );
994
995 break;
996 }
997
998 case PCB_VIA_T:
999 {
1000 wxASSERT( m_vias );
1001 PCB_VIA* via = static_cast<PCB_VIA*>( track );
1002 bool updatePadstack = m_padstackDirty;
1003
1004 if( !m_viaX.IsIndeterminate() )
1005 via->SetPosition( VECTOR2I( m_viaX.GetIntValue(), via->GetPosition().y ) );
1006
1007 if( !m_viaY.IsIndeterminate() )
1008 via->SetPosition( VECTOR2I( via->GetPosition().x, m_viaY.GetIntValue() ) );
1009
1010 if( m_viaNotFree->Get3StateValue() != wxCHK_UNDETERMINED )
1011 via->SetIsFree( !m_viaNotFree->GetValue() );
1012
1013 if( !m_viaDiameter.IsIndeterminate() )
1014 {
1015 int newDiameter = m_viaDiameter.GetIntValue();
1016 const VECTOR2I& currentSize = via->Padstack().Size( m_editLayer );
1017
1018 if( currentSize.x != newDiameter || currentSize.y != newDiameter )
1019 {
1020 m_viaStack->SetSize( { newDiameter, newDiameter }, m_editLayer );
1021 updatePadstack = true;
1022 }
1023 }
1024
1025 // Backdrill
1026 int backdrillChoice = m_backDrillChoice->GetSelection();
1027 if( backdrillChoice != wxNOT_FOUND )
1028 {
1029 PADSTACK::DRILL_PROPS secondaryDrill;
1030 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1031
1032 // Calculate size (10% larger)
1033 int drillSize = via->GetDrillValue();
1034 if( !m_viaDrill.IsIndeterminate() )
1035 drillSize = m_viaDrill.GetIntValue();
1036
1037 secondaryDrill.size = VECTOR2I( drillSize * 1.1, drillSize * 1.1 );
1038
1039 if( backdrillChoice == 0 ) // None
1040 {
1041 secondaryDrill.start = UNDEFINED_LAYER;
1042 secondaryDrill.end = UNDEFINED_LAYER;
1043 secondaryDrill.size = { 0, 0 };
1044 secondaryDrill.shape = PAD_DRILL_SHAPE::UNDEFINED;
1045 }
1046 else if( backdrillChoice == 1 ) // Bottom
1047 {
1048 secondaryDrill.start = B_Cu;
1049 if( m_ViaStartLayer11->GetLayerSelection() != UNDEFINED_LAYER )
1050 secondaryDrill.end = static_cast<PCB_LAYER_ID>( m_ViaStartLayer11->GetLayerSelection() );
1051 else
1052 secondaryDrill.end = UNDEFINED_LAYER; // Or keep existing?
1053 }
1054 else if( backdrillChoice == 2 ) // Top
1055 {
1056 secondaryDrill.start = F_Cu;
1057 if( m_backDrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1058 secondaryDrill.end = static_cast<PCB_LAYER_ID>( m_backDrillFrontLayer->GetLayerSelection() );
1059 else
1060 secondaryDrill.end = UNDEFINED_LAYER;
1061 }
1062
1063 if( via->Padstack().SecondaryDrill() != secondaryDrill )
1064 {
1065 m_viaStack->SecondaryDrill() = secondaryDrill;
1066 updatePadstack = true;
1067 }
1068 }
1069
1070 // Post Machining
1071 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
1072 {
1074 switch( m_topPostMachine->GetSelection() )
1075 {
1076 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1077 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1079 }
1080
1081 if( !m_topPostMachineSize1Binder.IsIndeterminate() )
1082 props.size = m_topPostMachineSize1Binder.GetIntValue();
1083 else
1084 props.size = via->Padstack().FrontPostMachining().size;
1085
1086 if( !m_topPostMachineSize2Binder.IsIndeterminate() )
1087 {
1089 props.angle = m_topPostMachineSize2Binder.GetIntValue();
1090 else
1091 props.depth = m_topPostMachineSize2Binder.GetIntValue();
1092 }
1093 else
1094 {
1095 props.angle = via->Padstack().FrontPostMachining().angle;
1096 props.depth = via->Padstack().FrontPostMachining().depth;
1097 }
1098
1099 if( via->Padstack().FrontPostMachining() != props )
1100 {
1101 m_viaStack->FrontPostMachining() = props;
1102 updatePadstack = true;
1103 }
1104 }
1105
1106 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
1107 {
1109 switch( m_bottomPostMachine->GetSelection() )
1110 {
1111 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1112 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1114 }
1115
1116 if( !m_bottomPostMachineSize1Binder.IsIndeterminate() )
1117 props.size = m_bottomPostMachineSize1Binder.GetIntValue();
1118 else
1119 props.size = via->Padstack().BackPostMachining().size;
1120
1121 if( !m_bottomPostMachineSize2Binder.IsIndeterminate() )
1122 {
1124 props.angle = m_bottomPostMachineSize2Binder.GetIntValue();
1125 else
1126 props.depth = m_bottomPostMachineSize2Binder.GetIntValue();
1127 }
1128 else
1129 {
1130 props.angle = via->Padstack().BackPostMachining().angle;
1131 props.depth = via->Padstack().BackPostMachining().depth;
1132 }
1133
1134 if( via->Padstack().BackPostMachining() != props )
1135 {
1136 m_viaStack->BackPostMachining() = props;
1137 updatePadstack = true;
1138 }
1139 }
1140
1141 switch( m_ViaTypeChoice->GetSelection() )
1142 {
1143 case 0: via->SetViaType( VIATYPE::THROUGH ); break;
1144 case 1: via->SetViaType( VIATYPE::MICROVIA ); break;
1145 case 2: via->SetViaType( VIATYPE::BLIND ); break;
1146 case 3: via->SetViaType( VIATYPE::BURIED ); break;
1147 default: break;
1148 }
1149
1150 PCB_LAYER_ID startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
1151 PCB_LAYER_ID endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
1152
1153 if( startLayer != UNDEFINED_LAYER )
1154 {
1155 if( via->Padstack().Drill().start != startLayer )
1156 {
1157 m_viaStack->Drill().start = startLayer;
1158 updatePadstack = true;
1159 }
1160
1161 via->SetTopLayer( startLayer );
1162 }
1163
1164 if( endLayer != UNDEFINED_LAYER )
1165 {
1166 if( via->Padstack().Drill().end != endLayer )
1167 {
1168 m_viaStack->Drill().end = endLayer;
1169 updatePadstack = true;
1170 }
1171
1172 via->SetBottomLayer( endLayer );
1173 }
1174
1175 if( updatePadstack )
1176 {
1177 via->SetPadstack( *m_viaStack );
1178 via->SanitizeLayers();
1179 }
1180
1181 switch( m_annularRingsCtrl->GetSelection() )
1182 {
1183 case 0:
1184 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL );
1185 break;
1186 case 1:
1187 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
1188 break;
1189 case 2:
1190 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_ALL );
1191 break;
1192 case 3:
1193 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::START_END_ONLY );
1194 break;
1195 default:
1196 break;
1197 }
1198
1199
1200 if( !m_viaDrill.IsIndeterminate() )
1201 via->SetDrill( m_viaDrill.GetIntValue() );
1202
1203 TEARDROP_PARAMETERS* targetParams = &via->GetTeardropParams();
1204
1205 if( m_cbTeardrops->Get3StateValue() != wxCHK_UNDETERMINED )
1206 targetParams->m_Enabled = m_cbTeardrops->GetValue();
1207
1208 if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
1209 targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
1210
1211 if( !m_teardropMaxLen.IsIndeterminate() )
1212 targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
1213
1214 if( !m_teardropMaxWidth.IsIndeterminate() )
1215 targetParams->m_TdMaxWidth = m_teardropMaxWidth.GetIntValue();
1216
1217 if( !m_teardropLenPercent.IsIndeterminate() )
1218 targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
1219
1220 if( !m_teardropWidthPercent.IsIndeterminate() )
1221 targetParams->m_BestWidthRatio = m_teardropWidthPercent.GetDoubleValue() / 100.0;
1222
1223 if( !m_teardropHDPercent.IsIndeterminate() )
1224 targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
1225
1226 if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
1227 targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
1228
1229 if( changeLock )
1230 via->SetLocked( setLock );
1231
1232 setViaConfiguration( via, static_cast<IPC4761_PRESET>( m_protectionFeatures->GetSelection() ) );
1233 break;
1234 }
1235
1236 default:
1237 UNIMPLEMENTED_FOR( track->GetClass() );
1238 break;
1239 }
1240 }
1241
1242 std::set<int> shortingNets;
1243 int newNetCode = m_netSelector->GetSelectedNetcode();
1244 std::set<PAD*> changingPads;
1245
1246 // Do NOT use the connectivity code here. It will propagate through zones, and we haven't
1247 // refilled those yet so it's going to pick up a whole bunch of other nets any time the track
1248 // width was increased.
1249 auto collide =
1251 {
1252 for( PCB_LAYER_ID layer : LSET( a->GetLayerSet() & b->GetLayerSet() ) )
1253 {
1254 if( a->GetEffectiveShape( layer )->Collide( b->GetEffectiveShape( layer ).get() ) )
1255 return true;
1256 }
1257
1258 return false;
1259 };
1260
1261 for( PCB_TRACK* track : connected_tracks )
1262 {
1263 for( PCB_TRACK* other : m_frame->GetBoard()->Tracks() )
1264 {
1265 if( other->GetNetCode() == track->GetNetCode() || other->GetNetCode() == newNetCode )
1266 continue;
1267
1268 if( collide( track, other ) )
1269 shortingNets.insert( other->GetNetCode() );
1270 }
1271
1272 for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
1273 {
1274 for( PAD* pad : footprint->Pads() )
1275 {
1276 if( pad->GetNetCode() == newNetCode )
1277 continue;
1278
1279 if( collide( track, pad ) )
1280 {
1281 if( pad->GetNetCode() == track->GetNetCode() )
1282 changingPads.insert( pad );
1283 else
1284 shortingNets.insert( pad->GetNetCode() );
1285 }
1286 }
1287 }
1288 }
1289
1290 if( shortingNets.size() && !confirmShortingNets( newNetCode, shortingNets ) )
1291 {
1292 commit.Revert();
1293 return true;
1294 }
1295
1296 if( !m_netSelector->IsIndeterminate() )
1297 {
1298 if( changingPads.empty() || confirmPadChange( changingPads ) )
1299 {
1300 for( PCB_TRACK* track : selected_tracks )
1301 track->SetNetCode( newNetCode );
1302
1303 for( PAD* pad : changingPads )
1304 {
1305 commit.Modify( pad );
1306 pad->SetNetCode( newNetCode );
1307 }
1308 }
1309 }
1310
1311 commit.Push( _( "Edit Track/Via Properties" ) );
1312 return true;
1313}
1314
1315
1317{
1318 m_viaNotFree->SetValue( false );
1319}
1320
1321
1323{
1324 if( !m_tracks )
1325 {
1326 m_netSelectorLabel->Enable( !m_viaNotFree->GetValue() );
1327 m_netSelector->Enable( !m_viaNotFree->GetValue() );
1328 }
1329}
1330
1331
1333{
1334 m_TrackWidthCtrl->ChangeValue( m_predefinedTrackWidthsCtrl->GetStringSelection() );
1335 m_TrackWidthCtrl->SelectAll();
1336}
1337
1338
1339void DIALOG_TRACK_VIA_PROPERTIES::onWidthEdit( wxCommandEvent& aEvent )
1340{
1341 m_predefinedTrackWidthsCtrl->SetStringSelection( m_TrackWidthCtrl->GetValue() );
1342}
1343
1344
1345void DIALOG_TRACK_VIA_PROPERTIES::onViaSelect( wxCommandEvent& aEvent )
1346{
1347 VIA_DIMENSION* viaDimension = static_cast<VIA_DIMENSION*> ( aEvent.GetClientData() );
1348
1349 m_viaDiameter.ChangeValue( viaDimension->m_Diameter );
1350 m_viaDrill.ChangeValue( viaDimension->m_Drill );
1351}
1352
1353
1355{
1356 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onPadstackModeChanged" );
1357
1358 switch( m_cbPadstackMode->GetSelection() )
1359 {
1360 default:
1361 case 0: m_viaStack->SetMode( PADSTACK::MODE::NORMAL ); break;
1362 case 1: m_viaStack->SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1363 case 2: m_viaStack->SetMode( PADSTACK::MODE::CUSTOM ); break;
1364 }
1365
1366 m_padstackDirty = true;
1367
1369}
1370
1371
1373{
1374 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onEditLayerChanged" );
1375
1376 // Save data from the previous layer
1377 if( !m_viaDiameter.IsIndeterminate() )
1378 {
1379 int diameter = m_viaDiameter.GetValue();
1380 m_viaStack->SetSize( { diameter, diameter }, m_editLayer );
1381 }
1382
1383 switch( m_viaStack->Mode() )
1384 {
1385 default:
1388 break;
1389
1391 switch( m_cbEditLayer->GetSelection() )
1392 {
1393 default:
1394 case 0: m_editLayer = F_Cu; break;
1395 case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
1396 case 2: m_editLayer = B_Cu; break;
1397 }
1398 break;
1399
1401 {
1402 int layer = m_cbEditLayer->GetSelection();
1403
1404 if( layer < 0 )
1405 layer = 0;
1406
1407 if( m_editLayerCtrlMap.contains( layer ) )
1408 m_editLayer = m_editLayerCtrlMap.at( layer );
1409 else
1410 m_editLayer = F_Cu;
1411 }
1412 }
1413
1414 // Load controls with the current layer
1415 m_viaDiameter.SetValue( m_viaStack->Size( m_editLayer ).x );
1416}
1417
1418
1420{
1421 // NOTE: synchronize changes here with DIALOG_PAD_PROPERTIES::afterPadstackModeChanged
1422
1423 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in afterPadstackModeChanged" );
1424 m_cbEditLayer->Clear();
1425
1426 BOARD* board = m_frame->GetBoard();
1427
1428 switch( m_viaStack->Mode() )
1429 {
1431 m_cbPadstackMode->SetSelection( 0 );
1432 m_cbEditLayer->Append( _( "All layers" ) );
1433 m_cbEditLayer->Disable();
1436 break;
1437
1439 {
1440 m_cbPadstackMode->SetSelection( 1 );
1441 m_cbEditLayer->Enable();
1442
1443 std::vector choices = {
1444 board->GetLayerName( F_Cu ),
1445 _( "Inner Layers" ),
1446 board->GetLayerName( B_Cu )
1447 };
1448
1449 m_cbEditLayer->Append( choices );
1450
1452 { 0, F_Cu },
1454 { 2, B_Cu }
1455 };
1456
1457 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
1459
1460 break;
1461 }
1462
1464 {
1465 m_cbPadstackMode->SetSelection( 2 );
1466 m_cbEditLayer->Enable();
1467 LSET layers = LSET::AllCuMask() & board->GetEnabledLayers();
1468
1469 for( PCB_LAYER_ID layer : layers.UIOrder() )
1470 {
1471 int idx = m_cbEditLayer->Append( board->GetLayerName( layer ) );
1472 m_editLayerCtrlMap[idx] = layer;
1473 }
1474
1475 break;
1476 }
1477 }
1478
1479 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1480 {
1481 if( layer == m_editLayer )
1482 {
1483 m_cbEditLayer->SetSelection( idx );
1484 break;
1485 }
1486 }
1487}
1488
1489
1491{
1492 int viaType = m_ViaTypeChoice->GetSelection();
1493
1494 if( viaType <= 0 )
1495 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1496
1497 int startLayer = m_ViaStartLayer->GetLayerSelection();
1498 int endLayer = m_ViaEndLayer->GetLayerSelection();
1499
1500 if( startLayer < 0 || endLayer < 0 )
1501 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1502 else
1503 return m_frame->GetBoard()->LayerDepth( ToLAYER_ID( startLayer ), ToLAYER_ID( endLayer ) );
1504}
1505
1506
1507void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
1508{
1509 m_predefinedViaSizesCtrl->SetSelection( wxNOT_FOUND );
1510
1511 if( m_vias )
1512 {
1513 if( m_ViaTypeChoice->GetSelection() != 0 ) // check if selected type isn't through.
1514 {
1515 m_ViaStartLayer->Enable();
1516 m_ViaEndLayer->Enable();
1517 }
1518 else
1519 {
1520 m_ViaStartLayer->SetLayerSelection( F_Cu );
1521 m_ViaEndLayer->SetLayerSelection( B_Cu );
1522
1523 m_ViaStartLayer->Enable( false );
1524 m_ViaEndLayer->Enable( false );
1525 }
1526
1527 m_annularRingsLabel->Show( getLayerDepth() > 1 );
1528 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
1529 m_annularRingsCtrl->Enable( true );
1530 }
1531}
1532
1533
1534void DIALOG_TRACK_VIA_PROPERTIES::onTrackEdit( wxCommandEvent& aEvent )
1535{
1536 bool externalCuLayer = m_TrackLayerCtrl->GetLayerSelection() == F_Cu
1537 || m_TrackLayerCtrl->GetLayerSelection() == B_Cu;
1538
1539 m_techLayersLabel->Enable( externalCuLayer );
1540 m_trackHasSolderMask->Enable( externalCuLayer );
1541
1542 bool showMaskMargin = externalCuLayer && m_trackHasSolderMask->GetValue();
1543
1544 m_trackMaskMarginCtrl->Enable( showMaskMargin );
1545 m_trackMaskMarginLabel->Enable( showMaskMargin );
1546 m_trackMaskMarginUnit->Enable( showMaskMargin );
1547}
1548
1549
1551{
1552 event.Enable( !m_frame->GetBoard()->LegacyTeardrops() );
1553}
1554
1555
1557{
1558 int selection = m_backDrillChoice->GetSelection();
1559 // 0: None, 1: Bottom, 2: Top, 3: Both
1560
1561 bool enableTop = ( selection == 2 || selection == 3 );
1562 bool enableBottom = ( selection == 1 || selection == 3 );
1563
1564 m_backDrillFrontLayer->Enable( enableTop );
1565 m_backDrillFrontLayerLabel->Enable( enableTop );
1566
1567 m_ViaStartLayer11->Enable( enableBottom ); // Back layer selector
1568 m_backDrillBackLayer->Enable( enableBottom ); // Back layer label
1569}
1570
1571
1573{
1574 int selection = m_topPostMachine->GetSelection();
1575 // 0: None, 1: Countersink, 2: Counterbore
1576
1577 bool enable = ( selection != 0 );
1578 m_topPostMachineSize1Binder.Enable( enable );
1579 m_topPostMachineSize2Binder.Enable( enable );
1580 m_topPostMachineSize1Label->Enable( enable );
1581 m_topPostMachineSize2Label->Enable( enable );
1582
1583 if( selection == 1 ) // Countersink
1584 {
1585 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
1586 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
1587
1588 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
1589 {
1590 m_topPostMachineSize2Binder.SetValue( "82" );
1591 }
1592 }
1593 else if( selection == 2 ) // Counterbore
1594 {
1595 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
1596 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1597 }
1598}
1599
1600
1602{
1603 int selection = m_bottomPostMachine->GetSelection();
1604 // 0: None, 1: Countersink, 2: Counterbore
1605
1606 bool enable = ( selection != 0 );
1607 m_bottomPostMachineSize1Binder.Enable( enable );
1608 m_bottomPostMachineSize2Binder.Enable( enable );
1609 m_bottomPostMachineSize1Label->Enable( enable );
1610 m_bottomPostMachineSize2Label->Enable( enable );
1611
1612 if( selection == 1 ) // Countersink
1613 {
1614 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
1615 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
1616
1617 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
1618 {
1619 m_bottomPostMachineSize2Binder.SetValue( "82" );
1620 }
1621 }
1622 else if( selection == 2 ) // Counterbore
1623 {
1624 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
1625 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1626 }
1627}
1628
1629
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,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
TEARDROP_PARAMETERS & GetTeardropParams()
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:257
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:728
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:967
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:99
const wxString & GetReference() const
Definition footprint.h:751
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:743
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:627
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
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:357
@ 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:351
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:360
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:754
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:266
PCB_LAYER_ID start
Definition padstack.h:269
PCB_LAYER_ID end
Definition padstack.h:270
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:267
PAD_DRILL_SHAPE shape
Definition padstack.h:268
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:281
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