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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <core/kicad_algo.h>
27#include <footprint.h>
28#include <pad.h>
29#include <padstack.h>
30#include <pcb_track.h>
31#include <confirm.h>
32#include <kidialog.h>
34#include <board_commit.h>
35#include <magic_enum.hpp>
36#include <macros.h>
37#include <optional>
38
39
40bool DIALOG_TRACK_VIA_PROPERTIES::IPC4761_CONFIGURATION::operator==( const IPC4761_CONFIGURATION& aOther ) const
41{
42 return ( tent == aOther.tent ) && ( plug == aOther.plug ) && ( cover == aOther.cover )
43 && ( cap == aOther.cap ) && ( fill == aOther.fill );
44}
45
46
49 m_frame( aParent ),
50 m_items( aItems ),
53 m_trackEndX( aParent, m_TrackEndXLabel, m_TrackEndXCtrl, nullptr ),
57 m_viaX( aParent, m_ViaXLabel, m_ViaXCtrl, nullptr ),
76 m_tracks( false ),
77 m_vias( false ),
79 m_padstackDirty( false )
80{
81 commonInit( aParent );
82}
83
84
86 PCB_VIA* aStandaloneVia ) :
88 m_frame( aParent ),
92 m_trackEndX( aParent, m_TrackEndXLabel, m_TrackEndXCtrl, nullptr ),
96 m_viaX( aParent, m_ViaXLabel, m_ViaXCtrl, nullptr ),
115 m_tracks( false ),
116 m_vias( false ),
117 m_editLayer( F_Cu ),
118 m_padstackDirty( false )
119{
120 wxASSERT( aStandaloneVia );
121
122 m_standalone = true;
123 m_viaStandaloneSelection.Add( aStandaloneVia );
124
125 commonInit( aParent );
126}
127
128
130{
131 m_useCalculatedSize = true;
132
133 wxASSERT( !m_items.Empty() );
134
136 m_legacyTeardropsWarning->Show( m_frame->GetBoard()->LegacyTeardrops() );
137
139
143
144 m_minTrackWidthHint->SetFont( KIUI::GetInfoFont( this ).Italic() );
145
146 // Configure display origin transforms
153
154 m_TrackLayerCtrl->SetLayersHotkeys( false );
155 m_TrackLayerCtrl->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
156 m_TrackLayerCtrl->SetBoardFrame( aParent );
157 m_TrackLayerCtrl->Resync();
158
159 m_ViaStartLayer->SetLayersHotkeys( false );
160 m_ViaStartLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
161 m_ViaStartLayer->SetBoardFrame( aParent );
162 m_ViaStartLayer->Resync();
163
164 m_ViaEndLayer->SetLayersHotkeys( false );
165 m_ViaEndLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
166 m_ViaEndLayer->SetBoardFrame( aParent );
167 m_ViaEndLayer->Resync();
168
169 m_backdrillFrontLayer->SetLayersHotkeys( false );
170 m_backdrillFrontLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
171 m_backdrillFrontLayer->SetBoardFrame( aParent );
172 m_backdrillFrontLayer->SetUndefinedLayerName( _( "None" ) );
173 m_backdrillFrontLayer->Resync();
174
175 m_backdrillBackLayer->SetLayersHotkeys( false );
176 m_backdrillBackLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
177 m_backdrillBackLayer->SetBoardFrame( aParent );
178 m_backdrillBackLayer->SetUndefinedLayerName( _( "None" ) );
179 m_backdrillBackLayer->Resync();
180
181 wxFont infoFont = KIUI::GetSmallInfoFont( this );
182 m_techLayersLabel->SetFont( infoFont );
183 m_postMachineSectionLabel->SetFont( infoFont );
184
185 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged, this );
186 m_netSelector->Bind( FILTERED_ITEM_SELECTED, &DIALOG_TRACK_VIA_PROPERTIES::onNetSelector, this );
187
188 for( auto& preset : magic_enum::enum_values<IPC4761_PRESET>() )
189 {
190 if( preset >= IPC4761_PRESET::CUSTOM )
191 continue;
192
193 const auto& name_it = m_IPC4761Names.find( preset );
194
195 wxString name = _( "Unknown choice" );
196
197 if( name_it != m_IPC4761Names.end() )
198 name = name_it->second;
199
200 m_protectionFeatures->AppendString( name );
201 }
202
204}
205
206
212
213
215{
216 // Setting widgets states/values must be in TransferDataToWindow, not in CTor
217 // otherwise states/values are overwritten by the DIALOG_SHIM::TransferDataToWindow() config values
218 bool nets = false;
219 int net = 0;
220 bool hasLocked = false;
221 bool hasUnlocked = false;
223
224 // Start and end layers of vias
225 // if at least 2 vias do not have the same start or the same end layer
226 // the layers will be set as undefined
227 int selection_first_layer = -1;
228 int selection_last_layer = -1;
229
230 // The selection layer for tracks
231 int track_selection_layer = -1;
232
233 // Drill information for vias
234 int secondary_drill_end_layer = UNDEFINED_LAYER;
235 bool secondary_drill_end_layer_mixed = false;
236 int secondary_drill_size = 0;
237 bool secondary_drill_size_mixed = false;
238
239 int tertiary_drill_end_layer = UNDEFINED_LAYER;
240 bool tertiary_drill_end_layer_mixed = false;
241 int tertiary_drill_size = 0;
242 bool tertiary_drill_size_mixed = false;
243
245 bool backdrill_dir_mixed = false;
246
247 std::optional<PAD_DRILL_POST_MACHINING_MODE> primary_post_machining_value;
248 bool primary_post_machining_set = false;
249 bool primary_post_machining_mixed = false;
250 int primary_post_machining_size = 0;
251 bool primary_post_machining_size_mixed = false;
252 int primary_post_machining_depth = 0;
253 bool primary_post_machining_depth_mixed = false;
254 int primary_post_machining_angle = 0;
255 bool primary_post_machining_angle_mixed = false;
256
257 std::optional<PAD_DRILL_POST_MACHINING_MODE> secondary_post_machining_value;
258 bool secondary_post_machining_set = false;
259 bool secondary_post_machining_mixed = false;
260 int secondary_post_machining_size = 0;
261 bool secondary_post_machining_size_mixed = false;
262 int secondary_post_machining_depth = 0;
263 bool secondary_post_machining_depth_mixed = false;
264 int secondary_post_machining_angle = 0;
265 bool secondary_post_machining_angle_mixed = false;
266
267 m_padstackDirty = false;
268
269 const int annularRingChoices = static_cast<int>( m_annularRingsCtrl->GetCount() );
270
271 auto getAnnularRingSelection =
272 []( const PCB_VIA* via ) -> int
273 {
274 switch( via->Padstack().UnconnectedLayerMode() )
275 {
276 default:
281 }
282 };
283
284 auto getBackdrillDrills = []( const PCB_VIA* via, PADSTACK::DRILL_PROPS& aTop, PADSTACK::DRILL_PROPS& aBottom )
285 {
286 const PADSTACK::DRILL_PROPS& sec = via->Padstack().SecondaryDrill();
287 const PADSTACK::DRILL_PROPS& ter = via->Padstack().TertiaryDrill();
288
289 aTop = PADSTACK::DRILL_PROPS();
290 aBottom = PADSTACK::DRILL_PROPS();
291
292 if( sec.start == F_Cu )
293 aTop = sec;
294 else if( ter.start == F_Cu )
295 aTop = ter;
296
297 if( sec.start == B_Cu )
298 aBottom = sec;
299 else if( ter.start == B_Cu )
300 aBottom = ter;
301 };
302
303 // Look for values that are common for every item that is selected
304 for( EDA_ITEM* item : m_items )
305 {
306 if( !nets )
307 {
308 net = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode();
309 nets = true;
310 }
311 else if( net != static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode() )
312 {
313 net = -1;
314 }
315
316 switch( item->Type() )
317 {
318 case PCB_TRACE_T:
319 case PCB_ARC_T:
320 {
321 const PCB_TRACK* t = static_cast<const PCB_TRACK*>( item );
322
323 if( !m_tracks ) // first track in the list
324 {
325 m_trackStartX.SetValue( t->GetStartX() );
326 m_trackStartY.SetValue( t->GetStartY() );
327 m_trackEndX.SetValue( t->GetEndX() );
328 m_trackEndY.SetValue( t->GetEndY() );
329 m_trackWidth.SetValue( t->GetWidth() );
330 track_selection_layer = t->GetLayer();
331 m_trackHasSolderMask->SetValue ( t->HasSolderMask() );
332
333 if( t->GetLocalSolderMaskMargin().has_value() )
334 m_trackMaskMargin.SetValue( t->GetLocalSolderMaskMargin().value() );
335 else
336 m_trackMaskMargin.SetValue( wxEmptyString );
337
338 m_tracks = true;
339 }
340 else // check if values are the same for every selected track
341 {
342 if( m_trackStartX.GetValue() != t->GetStartX() )
344
345 if( m_trackStartY.GetValue() != t->GetStartY() )
347
348 if( m_trackEndX.GetValue() != t->GetEndX() )
350
351 if( m_trackEndY.GetValue() != t->GetEndY() )
353
354 if( m_trackWidth.GetValue() != t->GetWidth() )
356
357 if( track_selection_layer != t->GetLayer() )
358 track_selection_layer = UNDEFINED_LAYER;
359
360 if( m_trackHasSolderMask->GetValue() != t->HasSolderMask() )
361 m_trackHasSolderMask->Set3StateValue( wxCHK_UNDETERMINED );
362
363 if( m_trackMaskMargin.GetValue() != t->GetLocalSolderMaskMargin() )
365 }
366
367 if( t->IsLocked() )
368 hasLocked = true;
369 else
370 hasUnlocked = true;
371
372 break;
373 }
374
375 case PCB_VIA_T:
376 {
377 PCB_VIA* v = static_cast<PCB_VIA*>( item );
378
379 if( !m_vias ) // first via in the list
380 {
381 m_viaX.SetValue( v->GetPosition().x );
382 m_viaY.SetValue( v->GetPosition().y );
383 m_viaStack = std::make_unique<PADSTACK>( v->Padstack() );
384 m_viaDiameter.SetValue( v->GetWidth( m_editLayer ) );
385 m_viaDrill.SetValue( v->GetDrillValue() );
386 m_vias = true;
387 viaType = v->GetViaType();
388 m_viaNotFree->SetValue( !v->GetIsFree() );
389 m_annularRingsCtrl->SetSelection( getAnnularRingSelection( v ) );
390
391 primary_post_machining_value = v->Padstack().FrontPostMachining().mode;
392 primary_post_machining_set = true;
393 primary_post_machining_size = v->Padstack().FrontPostMachining().size;
394 primary_post_machining_depth = v->Padstack().FrontPostMachining().depth;
395 primary_post_machining_angle = v->Padstack().FrontPostMachining().angle;
396
397 secondary_post_machining_value = v->Padstack().BackPostMachining().mode;
398 secondary_post_machining_set = true;
399 secondary_post_machining_size = v->Padstack().BackPostMachining().size;
400 secondary_post_machining_depth = v->Padstack().BackPostMachining().depth;
401 secondary_post_machining_angle = v->Padstack().BackPostMachining().angle;
402
403 PADSTACK::DRILL_PROPS topDrill;
404 PADSTACK::DRILL_PROPS bottomDrill;
405 getBackdrillDrills( v, topDrill, bottomDrill );
406
407 // secondary_* holds the top (front) backdrill, tertiary_* the bottom (back) one
408 secondary_drill_end_layer = topDrill.end;
409 tertiary_drill_end_layer = bottomDrill.end;
410
411 secondary_drill_size = topDrill.size.x;
412 tertiary_drill_size = bottomDrill.size.x;
413
414 bool top = topDrill.end != UNDEFINED_LAYER && topDrill.size.x > 0;
415 bool bottom = bottomDrill.end != UNDEFINED_LAYER && bottomDrill.size.x > 0;
416
417 if( top && bottom )
418 backdrill_dir = BACKDRILL_MODE::BACKDRILL_BOTH;
419 else if( bottom )
420 backdrill_dir = BACKDRILL_MODE::BACKDRILL_BOTTOM;
421 else if( top )
422 backdrill_dir = BACKDRILL_MODE::BACKDRILL_TOP;
423 else
424 backdrill_dir = BACKDRILL_MODE::NO_BACKDRILL;
425
426 selection_first_layer = v->TopLayer();
427 selection_last_layer = v->BottomLayer();
428
429 m_cbTeardrops->SetValue( v->GetTeardropParams().m_Enabled );
433 m_teardropLenPercent.SetDoubleValue( v->GetTeardropParams().m_BestLengthRatio*100.0 );
434 m_teardropWidthPercent.SetDoubleValue( v->GetTeardropParams().m_BestWidthRatio*100.0 );
437
439
440 if( preset >= IPC4761_PRESET::CUSTOM )
442 else
443 m_protectionFeatures->SetSelection( static_cast<int>( preset ) );
444 }
445 else // check if values are the same for every selected via
446 {
447 if( m_viaX.GetValue() != v->GetPosition().x )
448 m_viaX.SetValue( INDETERMINATE_STATE );
449
450 if( m_viaY.GetValue() != v->GetPosition().y )
451 m_viaY.SetValue( INDETERMINATE_STATE );
452
453 if( m_viaDiameter.GetValue() != v->GetWidth( m_editLayer ) )
455
456 if( m_viaDrill.GetValue() != v->GetDrillValue() )
458
459 if( viaType != v->GetViaType() )
460 viaType = VIATYPE::NOT_DEFINED;
461
462 if( v->GetIsFree() != !m_viaNotFree->GetValue() )
463 m_viaNotFree->Set3StateValue( wxCHK_UNDETERMINED );
464
465 if( selection_first_layer != v->TopLayer() )
466 selection_first_layer = UNDEFINED_LAYER;
467
468 if( selection_last_layer != v->BottomLayer() )
469 selection_last_layer = UNDEFINED_LAYER;
470
471 if( m_annularRingsCtrl->GetSelection() != getAnnularRingSelection( v ) )
472 {
473 if( m_annularRingsCtrl->GetSelection() != annularRingChoices )
475
476 m_annularRingsCtrl->SetSelection( annularRingChoices );
477 }
478
479 if( m_cbTeardrops->GetValue() != v->GetTeardropParams().m_Enabled )
480 m_cbTeardrops->Set3StateValue( wxCHK_UNDETERMINED );
481
483 m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
484
485 if( m_teardropMaxLen.GetValue() != v->GetTeardropParams().m_TdMaxLen )
487
488 if( m_teardropMaxWidth.GetValue() != v->GetTeardropParams().m_TdMaxWidth )
490
491 if( m_teardropLenPercent.GetDoubleValue() != v->GetTeardropParams().m_BestLengthRatio *100.0 )
493
494 if( m_teardropWidthPercent.GetDoubleValue() != v->GetTeardropParams().m_BestWidthRatio *100.0 )
496
497 if( m_teardropHDPercent.GetDoubleValue() != v->GetTeardropParams().m_WidthtoSizeFilterRatio*100.0 )
499
500 if( static_cast<int>( getViaConfiguration( v ) ) != m_protectionFeatures->GetSelection() )
502
503 if( primary_post_machining_set )
504 {
505 if( primary_post_machining_value != v->Padstack().FrontPostMachining().mode )
506 primary_post_machining_mixed = true;
507
508 if( primary_post_machining_size != v->Padstack().FrontPostMachining().size )
509 primary_post_machining_size_mixed = true;
510
511 if( primary_post_machining_depth != v->Padstack().FrontPostMachining().depth )
512 primary_post_machining_depth_mixed = true;
513
514 if( primary_post_machining_angle != v->Padstack().FrontPostMachining().angle )
515 primary_post_machining_angle_mixed = true;
516 }
517
518 if( secondary_post_machining_set )
519 {
520 if( secondary_post_machining_value != v->Padstack().BackPostMachining().mode )
521 secondary_post_machining_mixed = true;
522
523 if( secondary_post_machining_size != v->Padstack().BackPostMachining().size )
524 secondary_post_machining_size_mixed = true;
525
526 if( secondary_post_machining_depth != v->Padstack().BackPostMachining().depth )
527 secondary_post_machining_depth_mixed = true;
528
529 if( secondary_post_machining_angle != v->Padstack().BackPostMachining().angle )
530 secondary_post_machining_angle_mixed = true;
531 }
532
533 PADSTACK::DRILL_PROPS topDrill;
534 PADSTACK::DRILL_PROPS bottomDrill;
535 getBackdrillDrills( v, topDrill, bottomDrill );
536
537 bool top = topDrill.end != UNDEFINED_LAYER && topDrill.size.x > 0;
538 bool bottom = bottomDrill.end != UNDEFINED_LAYER && bottomDrill.size.x > 0;
539
541
542 if( top && bottom )
543 new_backdrill_dir = BACKDRILL_MODE::BACKDRILL_BOTH;
544 else if( bottom )
545 new_backdrill_dir = BACKDRILL_MODE::BACKDRILL_BOTTOM;
546 else if( top )
547 new_backdrill_dir = BACKDRILL_MODE::BACKDRILL_TOP;
548 else
549 new_backdrill_dir = BACKDRILL_MODE::NO_BACKDRILL;
550
551 if( secondary_drill_end_layer != topDrill.end )
552 secondary_drill_end_layer_mixed = true;
553
554 if( tertiary_drill_end_layer != bottomDrill.end )
555 tertiary_drill_end_layer_mixed = true;
556
557 if( backdrill_dir != new_backdrill_dir )
558 backdrill_dir_mixed = true;
559
560 if( bottomDrill.size.x != tertiary_drill_size )
561 tertiary_drill_size_mixed = true;
562
563 if( topDrill.size.x != secondary_drill_size )
564 secondary_drill_size_mixed = true;
565 }
566
567 if( v->IsLocked() )
568 hasLocked = true;
569 else
570 hasUnlocked = true;
571
572 break;
573 }
574
575 default:
576 {
577 UNIMPLEMENTED_FOR( item->GetClass() );
578 break;
579 }
580 }
581 }
582
583 if( m_tracks )
584 {
585 // Set the track layer selection state:
586 if( track_selection_layer == UNDEFINED_LAYER )
587 {
588 m_TrackLayerCtrl->SetUndefinedLayerName( INDETERMINATE_STATE );
589 m_TrackLayerCtrl->Resync();
590 }
591
592 m_TrackLayerCtrl->SetLayerSelection( track_selection_layer );
593 }
594
595 // Set the vias layers selections state:
596 if( m_vias )
597 {
598 if( selection_first_layer == UNDEFINED_LAYER )
599 {
600 m_ViaStartLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
601 m_ViaStartLayer->Resync();
602 }
603
604 m_ViaStartLayer->SetLayerSelection( selection_first_layer );
605
606 if( selection_last_layer == UNDEFINED_LAYER )
607 {
608 m_ViaEndLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
609 m_ViaEndLayer->Resync();
610 }
611
612 m_ViaEndLayer->SetLayerSelection( selection_last_layer );
613
614 // Set backdrill controls
615
616 // Backdrill direction selector
617 if( backdrill_dir_mixed )
618 {
619 m_backdrillChoice->SetSelection( wxNOT_FOUND );
620
621 if( tertiary_drill_size_mixed )
623 else
624 m_backdrillBackSize.SetValue( tertiary_drill_size );
625
626 if( secondary_drill_size_mixed )
628 else
629 m_backdrillFrontSize.SetValue( secondary_drill_size );
630 }
631 else
632 {
633 m_backdrillChoice->SetSelection( static_cast<int>( backdrill_dir ) );
634
635 if( backdrill_dir == BACKDRILL_MODE::BACKDRILL_BOTTOM || backdrill_dir == BACKDRILL_MODE::BACKDRILL_BOTH )
636 {
637 if( tertiary_drill_size_mixed )
639 else
640 m_backdrillBackSize.SetValue( tertiary_drill_size );
641 }
642 else
643 {
644 m_backdrillBackSize.SetValue( wxEmptyString );
645 }
646
647 if( backdrill_dir == BACKDRILL_MODE::BACKDRILL_TOP || backdrill_dir == BACKDRILL_MODE::BACKDRILL_BOTH )
648 {
649 if( secondary_drill_size_mixed )
651 else
652 m_backdrillFrontSize.SetValue( secondary_drill_size );
653 }
654 else
655 {
656 m_backdrillFrontSize.SetValue( wxEmptyString );
657 }
658
659 }
660
661 // Top backdrill control
662 if( secondary_drill_end_layer_mixed )
663 {
664 m_backdrillFrontLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
665 m_backdrillFrontLayer->Resync();
666 m_backdrillFrontLayer->SetLayerSelection( UNDEFINED_LAYER );
667 }
668 else
669 {
670 m_backdrillFrontLayer->SetUndefinedLayerName( _( "None" ) );
671 m_backdrillFrontLayer->Resync();
672 m_backdrillFrontLayer->SetLayerSelection( secondary_drill_end_layer );
673 }
674
675 // Bottom backdrill control
676 if( tertiary_drill_end_layer_mixed )
677 {
678 m_backdrillBackLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
679 m_backdrillBackLayer->Resync();
680 m_backdrillBackLayer->SetLayerSelection( UNDEFINED_LAYER );
681 }
682 else
683 {
684 m_backdrillBackLayer->SetUndefinedLayerName( _( "None" ) );
685 m_backdrillBackLayer->Resync();
686 m_backdrillBackLayer->SetLayerSelection( tertiary_drill_end_layer );
687 }
688
689 // Post Machining
690 if( primary_post_machining_mixed )
691 {
692 m_topPostMachine->SetSelection( wxNOT_FOUND );
694 m_topPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
696 }
697 else if( primary_post_machining_set && primary_post_machining_value.has_value() )
698 {
699 switch( primary_post_machining_value.value() )
700 {
702 m_topPostMachine->SetSelection( 2 );
703
704 if( primary_post_machining_size_mixed )
706 else
707 m_topPostMachineSize1.SetValue( primary_post_machining_size );
708
709 m_topPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
710
711 if( primary_post_machining_depth_mixed )
713 else
714 m_topPostMachineSize2.SetValue( primary_post_machining_depth );
715
716 break;
717
719 m_topPostMachine->SetSelection( 1 );
720
721 if( primary_post_machining_size_mixed )
723 else
724 m_topPostMachineSize1.SetValue( primary_post_machining_size );
725
727
728 if( primary_post_machining_angle_mixed )
730 else
731 m_topPostMachineSize2.SetDoubleValue( primary_post_machining_angle / 10.0 );
732
733 break;
734
735 default:
736 m_topPostMachine->SetSelection( 0 );
737 m_topPostMachineSize1.SetValue( wxEmptyString );
738 m_topPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
739 m_topPostMachineSize2.SetValue( wxEmptyString );
740 break;
741 }
742 }
743 else
744 {
745 m_topPostMachine->SetSelection( 0 );
746 m_topPostMachineSize1.SetValue( wxEmptyString );
747 m_topPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
748 m_topPostMachineSize2.SetValue( wxEmptyString );
749 }
750
751 if( secondary_post_machining_mixed )
752 {
753 m_bottomPostMachine->SetSelection( wxNOT_FOUND );
755 m_bottomPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
757 }
758 else if( secondary_post_machining_set && secondary_post_machining_value.has_value() )
759 {
760 switch( secondary_post_machining_value.value() )
761 {
763 m_bottomPostMachine->SetSelection( 2 );
764
765 if( secondary_post_machining_size_mixed )
767 else
768 m_bottomPostMachineSize1.SetValue( secondary_post_machining_size );
769
770 m_bottomPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
771
772 if( secondary_post_machining_depth_mixed )
774 else
775 m_bottomPostMachineSize2.SetValue( secondary_post_machining_depth );
776
777 break;
778
780 m_bottomPostMachine->SetSelection( 1 );
781
782 if( secondary_post_machining_size_mixed )
784 else
785 m_bottomPostMachineSize1.SetValue( secondary_post_machining_size );
786
788
789 if( secondary_post_machining_angle_mixed )
791 else
792 m_bottomPostMachineSize2.SetDoubleValue( secondary_post_machining_angle / 10.0 );
793
794 break;
795
796 default:
797 m_bottomPostMachine->SetSelection( 0 );
798 m_bottomPostMachineSize1.SetValue( wxEmptyString );
799 m_bottomPostMachineSize2.SetValue( wxEmptyString );
800 m_bottomPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
801 break;
802 }
803 }
804 else
805 {
806 m_bottomPostMachine->SetSelection( 0 );
807 m_bottomPostMachineSize1.SetValue( wxEmptyString );
808 m_bottomPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
809 m_bottomPostMachineSize2.SetValue( wxEmptyString );
810 }
811 }
812
813 m_netSelector->SetNetInfo( &m_frame->GetBoard()->GetNetInfo() );
814
815 if ( net >= 0 )
816 {
817 m_netSelector->SetSelectedNetcode( net );
818 }
819 else
820 {
821 m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
822 m_netSelector->SetIndeterminate();
823 }
824
825 wxASSERT( m_tracks || m_vias );
826
827 if( m_vias )
828 {
829 if( m_viaNotFree->GetValue() && !m_tracks )
830 {
831 // Disable net selector to re-inforce meaning of "Automatically update via nets",
832 // but not when tracks are also selected as then things get harder if you want to
833 // update all the nets to match.
834 m_netSelectorLabel->Disable();
835 m_netSelector->Disable();
836 }
837
838 int viaSelection = wxNOT_FOUND;
839
840 // 0 is the netclass place-holder
841 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
842 {
843 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
844 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
845 + wxT( " / " )
846 + m_frame->StringFromValue( viaDimension->m_Drill );
847 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
848
849 if( viaSelection == wxNOT_FOUND
850 && m_viaDiameter.GetValue() == viaDimension->m_Diameter
851 && m_viaDrill.GetValue() == viaDimension->m_Drill )
852 {
853 viaSelection = ii - 1;
854 }
855 }
856
857 m_predefinedViaSizesCtrl->SetSelection( viaSelection );
858 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
859
860 m_ViaTypeChoice->Enable();
861
862 switch( viaType )
863 {
864 case VIATYPE::THROUGH: m_ViaTypeChoice->SetSelection( 0 ); break;
865 case VIATYPE::MICROVIA: m_ViaTypeChoice->SetSelection( 1 ); break;
866 case VIATYPE::BLIND: m_ViaTypeChoice->SetSelection( 2 ); break;
867 case VIATYPE::BURIED: m_ViaTypeChoice->SetSelection( 3 ); break;
868 case VIATYPE::NOT_DEFINED: m_ViaTypeChoice->SetSelection( wxNOT_FOUND ); break;
869 }
870
871 m_ViaStartLayer->Enable( viaType != VIATYPE::THROUGH );
872 m_ViaEndLayer->Enable( viaType != VIATYPE::THROUGH );
873
874 m_annularRingsLabel->Show( getLayerDepth() > 1 );
875 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
876 m_annularRingsCtrl->Enable( true );
877
879 }
880 else
881 {
882 m_viaNotFree->Hide();
883 m_MainSizer->Hide( m_sbViaSizer, true );
884 }
885
886 if( m_tracks )
887 {
888 int widthSelection = wxNOT_FOUND;
889
890 // 0 is the netclass place-holder
891 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
892 {
893 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
894 wxString msg = m_frame->StringFromValue( width );
895 m_predefinedTrackWidthsCtrl->Append( msg );
896
897 if( widthSelection == wxNOT_FOUND && m_trackWidth.GetValue() == width )
898 widthSelection = ii - 1;
899 }
900
901 m_predefinedTrackWidthsCtrl->SetSelection( widthSelection );
902 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
903
904 wxCommandEvent event;
905 onTrackEdit( event );
906 }
907 else
908 {
909 m_MainSizer->Hide( m_sbTrackSizer, true );
910 }
911
912 if( hasLocked && hasUnlocked )
913 m_lockedCbox->Set3StateValue( wxCHK_UNDETERMINED );
914 else if( hasLocked )
915 m_lockedCbox->Set3StateValue( wxCHK_CHECKED );
916 else
917 m_lockedCbox->Set3StateValue( wxCHK_UNCHECKED );
918
919 if( m_tracks )
921 else if( m_netSelector->IsEnabled() )
923 else
925
926 wxCommandEvent dummyEvent;
927 onBackdrillChange( dummyEvent );
928 onTopPostMachineChange( dummyEvent );
929 onBottomPostMachineChange( dummyEvent );
930
931 // Now all widgets have the size fixed, call FinishDialogSettings
933
934 return true;
935}
936
937
939{
940 if( m_vias )
941 {
942 int viaSel = m_predefinedViaSizesCtrl->GetSelection();
943
945
946 // 0 is the netclass place-holder
947 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
948 {
949 VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
950 wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
951 + wxT( " / " )
952 + m_frame->StringFromValue( viaDimension->m_Drill );
953 m_predefinedViaSizesCtrl->Append( msg, viaDimension );
954 }
955
956 m_predefinedViaSizesCtrl->SetSelection( viaSel );
957 m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
958 }
959
960 if( m_tracks )
961 {
962 int trackSel = m_predefinedTrackWidthsCtrl->GetSelection();
963
965
966 // 0 is the netclass place-holder
967 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
968 {
969 int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
970 wxString msg = m_frame->StringFromValue( width );
971 m_predefinedTrackWidthsCtrl->Append( msg );
972 }
973
974 m_predefinedTrackWidthsCtrl->SetSelection( trackSel );
975 m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
976 }
977
978 aEvent.Skip();
979}
980
981
982bool DIALOG_TRACK_VIA_PROPERTIES::confirmShortingNets( int aNet, const std::set<int>& shortingNets )
983{
984 wxString msg;
985
986 if( shortingNets.size() == 1 )
987 {
988 msg.Printf( _( "Applying these changes will short net %s with %s." ),
989 m_netSelector->GetValue(),
990 m_frame->GetBoard()->FindNet( *shortingNets.begin() )->GetNetname() );
991 }
992 else
993 {
994 msg.Printf( _( "Applying these changes will short net %s with other nets." ),
995 m_netSelector->GetValue() );
996 }
997
998 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
999 dlg.SetOKCancelLabels( _( "Apply Anyway" ), _( "Cancel Changes" ) );
1000 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1001
1002 return dlg.ShowModal() == wxID_OK;
1003}
1004
1005
1006bool DIALOG_TRACK_VIA_PROPERTIES::confirmPadChange( const std::set<PAD*>& changingPads )
1007{
1008 wxString msg;
1009
1010 if( changingPads.size() == 1 )
1011 {
1012 PAD* pad = *changingPads.begin();
1013 msg.Printf( _( "Changing the net will also update %s pad %s to %s." ),
1014 pad->GetParentFootprint()->GetReference(),
1015 pad->GetNumber(),
1016 m_netSelector->GetValue() );
1017 }
1018 else if( changingPads.size() == 2 )
1019 {
1020 PAD* pad1 = *changingPads.begin();
1021 PAD* pad2 = *( ++changingPads.begin() );
1022 msg.Printf( _( "Changing the net will also update %s pad %s and %s pad %s to %s." ),
1024 pad1->GetNumber(),
1026 pad2->GetNumber(),
1027 m_netSelector->GetValue() );
1028 }
1029 else
1030 {
1031 msg.Printf( _( "Changing the net will also update %lu connected pads to %s." ),
1032 static_cast<unsigned long>( changingPads.size() ),
1033 m_netSelector->GetValue() );
1034 }
1035
1036 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1037 dlg.SetOKCancelLabels( _( "Change Nets" ), _( "Leave Nets Unchanged" ) );
1038 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1039
1040 return dlg.ShowModal() == wxID_OK;
1041}
1042
1043
1045{
1046 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_frame->GetBoard()->GetConnectivity();
1047 std::vector<PCB_TRACK*> selected_tracks;
1048 std::set<PCB_TRACK*> connected_tracks;
1049
1050 for( EDA_ITEM* item : m_items )
1051 {
1052 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
1053 selected_tracks.push_back( track );
1054 }
1055
1056 for( PCB_TRACK* selected_track : selected_tracks )
1057 {
1058 connected_tracks.insert( selected_track );
1059
1060 // Exclude zones so we only follow direct copper, via, and pad connections. Zone
1061 // propagation would pull in unrelated same-net tracks and rewrite their net below.
1062 for( BOARD_CONNECTED_ITEM* connected_item :
1063 connectivity->GetConnectedItems( selected_track, EXCLUDE_ZONES ) )
1064 {
1065 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( connected_item ) )
1066 connected_tracks.insert( track );
1067 }
1068 }
1069
1070 // Check for malformed data ONLY; design rules and constraints are the business of DRC.
1071
1072 if( m_vias )
1073 {
1074 // Marshal UI values into optionals; the malformed-data checks themselves live on
1075 // PCB_VIA::ValidateViaParameters so they can be reused and unit tested.
1076
1077 std::optional<int> viaDiameter;
1078
1079 if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate() )
1080 viaDiameter = m_viaDiameter.GetValue();
1081
1082 std::optional<int> viaDrill;
1083
1084 if( m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate() )
1085 viaDrill = m_viaDrill.GetValue();
1086
1087 std::optional<PCB_LAYER_ID> startLayer;
1088
1089 if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER )
1090 startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
1091
1092 std::optional<PCB_LAYER_ID> endLayer;
1093
1094 if( m_ViaEndLayer->GetLayerSelection() != UNDEFINED_LAYER )
1095 endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
1096
1097 std::optional<int> secondaryDrill;
1098 std::optional<int> tertiaryDrill;
1099 std::optional<PCB_LAYER_ID> secondaryStartLayer;
1100 std::optional<PCB_LAYER_ID> secondaryEndLayer;
1101 std::optional<PCB_LAYER_ID> tertiaryStartLayer;
1102 std::optional<PCB_LAYER_ID> tertiaryEndLayer;
1103
1104 if( m_backdrillChoice->GetSelection() != wxNOT_FOUND )
1105 {
1106 switch( static_cast<BACKDRILL_MODE>( m_backdrillChoice->GetSelection() ) )
1107 {
1109 break;
1110
1112 if( m_backdrillBackSize.IsIndeterminate() || m_backdrillBackSize.IsNull() )
1113 tertiaryDrill = m_viaStack->TertiaryDrill().size.x;
1114 else
1115 tertiaryDrill = m_backdrillBackSize.GetIntValue();
1116
1117 tertiaryStartLayer = B_Cu;
1118
1119 if( m_backdrillBackLayer->GetLayerSelection() != UNDEFINED_LAYER )
1120 tertiaryEndLayer = ToLAYER_ID( m_backdrillBackLayer->GetLayerSelection() );
1121
1122 if( !m_backdrillBackSize.IsIndeterminate() )
1123 tertiaryDrill = m_backdrillBackSize.GetIntValue();
1124
1125 break;
1126
1128 if( m_backdrillFrontSize.IsIndeterminate() || m_backdrillFrontSize.IsNull() )
1129 secondaryDrill = m_viaStack->SecondaryDrill().size.x;
1130 else
1131 secondaryDrill = m_backdrillFrontSize.GetIntValue();
1132
1133 secondaryStartLayer = F_Cu;
1134
1135 if( m_backdrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1136 secondaryEndLayer = ToLAYER_ID( m_backdrillFrontLayer->GetLayerSelection() );
1137
1138 if( !m_backdrillFrontSize.IsIndeterminate() )
1139 secondaryDrill = m_backdrillFrontSize.GetIntValue();
1140
1141 break;
1142
1144 if( m_backdrillFrontSize.IsIndeterminate() || m_backdrillFrontSize.IsNull() )
1145 secondaryDrill = m_viaStack->SecondaryDrill().size.x;
1146 else
1147 secondaryDrill = m_backdrillFrontSize.GetIntValue();
1148
1149 secondaryStartLayer = F_Cu;
1150
1151 if( m_backdrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1152 secondaryEndLayer = ToLAYER_ID( m_backdrillFrontLayer->GetLayerSelection() );
1153
1154 if( !m_backdrillFrontSize.IsIndeterminate() )
1155 secondaryDrill = m_backdrillFrontSize.GetIntValue();
1156
1157 if( m_backdrillBackSize.IsIndeterminate() || m_backdrillBackSize.IsNull() )
1158 tertiaryDrill = m_viaStack->TertiaryDrill().size.x;
1159 else
1160 tertiaryDrill = m_backdrillBackSize.GetIntValue();
1161
1162 tertiaryStartLayer = B_Cu;
1163
1164 if( m_backdrillBackLayer->GetLayerSelection() != UNDEFINED_LAYER )
1165 tertiaryEndLayer = ToLAYER_ID( m_backdrillBackLayer->GetLayerSelection() );
1166
1167 if( !m_backdrillBackSize.IsIndeterminate() )
1168 tertiaryDrill = m_backdrillBackSize.GetIntValue();
1169
1170 break;
1171 }
1172 }
1173
1174 // Post Machining
1175 std::optional<PADSTACK::POST_MACHINING_PROPS> frontPostMachining;
1176 std::optional<PADSTACK::POST_MACHINING_PROPS> backPostMachining;
1177
1178 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
1179 {
1181
1182 switch( m_topPostMachine->GetSelection() )
1183 {
1184 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1185 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1187 }
1188
1189 if( !m_topPostMachineSize1.IsIndeterminate() )
1190 props.size = m_topPostMachineSize1.GetIntValue();
1191
1192 if( !m_topPostMachineSize2.IsIndeterminate() )
1193 {
1195 props.angle = KiROUND( m_topPostMachineSize2.GetDoubleValue() * 10.0 );
1196 else
1197 props.depth = m_topPostMachineSize2.GetIntValue();
1198 }
1199
1200 frontPostMachining = props;
1201 }
1202
1203 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
1204 {
1206
1207 switch( m_bottomPostMachine->GetSelection() )
1208 {
1209 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1210 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1212 }
1213
1214 if( !m_bottomPostMachineSize1.IsIndeterminate() )
1215 props.size = m_bottomPostMachineSize1.GetIntValue();
1216
1217 if( !m_bottomPostMachineSize2.IsIndeterminate() )
1218 {
1220 props.angle = KiROUND( m_bottomPostMachineSize2.GetDoubleValue() * 10.0 );
1221 else
1222 props.depth = m_bottomPostMachineSize2.GetIntValue();
1223 }
1224
1225 backPostMachining = props;
1226 }
1227
1228 int copperLayerCount = m_frame->GetBoard() ? m_frame->GetBoard()->GetCopperLayerCount() : 0;
1229
1230 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
1231 PCB_VIA::ValidateViaParameters( viaDiameter, viaDrill, startLayer, endLayer,
1232 secondaryDrill, secondaryStartLayer,
1233 secondaryEndLayer, tertiaryDrill, tertiaryStartLayer,
1234 tertiaryEndLayer, copperLayerCount ) )
1235 {
1236 DisplayError( GetParent(), error->m_Message );
1237
1238 if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DRILL )
1239 {
1240 m_ViaDrillCtrl->SelectAll();
1241 m_ViaDrillCtrl->SetFocus();
1242 }
1243 else if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DIAMETER )
1244 {
1245 m_ViaDiameterCtrl->SelectAll();
1246 m_ViaDiameterCtrl->SetFocus();
1247 }
1248
1249 // Other fields might not have direct focus targets in new UI or I'd need to map them
1250 return false;
1251 }
1252
1253 }
1254
1255 if( m_tracks )
1256 {
1257 if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) )
1258 return false;
1259 }
1260
1261 // If we survived that, then save the changes:
1262 //
1263 // We don't bother with updating the nets at this point as it will be useless (any connected
1264 // pads will simply drive their existing nets back onto the track segments and vias).
1265
1266 BOARD_COMMIT commit( m_frame );
1267 bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED;
1268 bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED;
1269
1270 for( PCB_TRACK* track : selected_tracks )
1271 {
1272
1273 if( !m_standalone )
1274 commit.Modify( track );
1275
1276 switch( track->Type() )
1277 {
1278 case PCB_TRACE_T:
1279 case PCB_ARC_T:
1280 {
1281 wxASSERT( m_tracks );
1282
1283 if( !m_trackStartX.IsIndeterminate() )
1284 track->SetStartX( m_trackStartX.GetIntValue() );
1285
1286 if( !m_trackStartY.IsIndeterminate() )
1287 track->SetStartY( m_trackStartY.GetIntValue() );
1288
1289 if( !m_trackEndX.IsIndeterminate() )
1290 track->SetEndX( m_trackEndX.GetIntValue() );
1291
1292 if( !m_trackEndY.IsIndeterminate() )
1293 track->SetEndY( m_trackEndY.GetIntValue() );
1294
1295 if( !m_trackWidth.IsIndeterminate() )
1296 track->SetWidth( m_trackWidth.GetIntValue() );
1297
1298 int layer = m_TrackLayerCtrl->GetLayerSelection();
1299
1300 if( layer != UNDEFINED_LAYER )
1301 track->SetLayer( (PCB_LAYER_ID) layer );
1302
1303 if ( m_trackHasSolderMask->Get3StateValue() != wxCHK_UNDETERMINED )
1304 track->SetHasSolderMask( m_trackHasSolderMask->GetValue() );
1305
1306 if( !m_trackMaskMargin.IsIndeterminate() )
1307 {
1308 if( m_trackMaskMargin.IsNull() )
1309 track->SetLocalSolderMaskMargin( {} );
1310 else
1311 track->SetLocalSolderMaskMargin( m_trackMaskMargin.GetIntValue() );
1312 }
1313
1314 if( changeLock )
1315 track->SetLocked( setLock );
1316
1317 break;
1318 }
1319
1320 case PCB_VIA_T:
1321 {
1322 wxASSERT( m_vias );
1323 PCB_VIA* via = static_cast<PCB_VIA*>( track );
1324 bool updatePadstack = m_padstackDirty;
1325
1326 // Edit each via's own padstack. Only a mode change replaces it wholesale.
1327 PADSTACK viaStack = m_padstackDirty ? *m_viaStack : via->Padstack();
1328
1329 if( !m_viaX.IsIndeterminate() )
1330 via->SetPosition( VECTOR2I( m_viaX.GetIntValue(), via->GetPosition().y ) );
1331
1332 if( !m_viaY.IsIndeterminate() )
1333 via->SetPosition( VECTOR2I( via->GetPosition().x, m_viaY.GetIntValue() ) );
1334
1335 if( m_viaNotFree->Get3StateValue() != wxCHK_UNDETERMINED )
1336 via->SetIsFree( !m_viaNotFree->GetValue() );
1337
1338 if( !m_viaDiameter.IsIndeterminate() )
1339 {
1340 int newDiameter = m_viaDiameter.GetIntValue();
1341 const VECTOR2I& currentSize = via->Padstack().Size( m_editLayer );
1342
1343 if( currentSize.x != newDiameter || currentSize.y != newDiameter )
1344 {
1345 viaStack.SetSize( { newDiameter, newDiameter }, m_editLayer );
1346 updatePadstack = true;
1347 }
1348 }
1349
1350 // Backdrill
1351 PADSTACK::DRILL_PROPS tertiaryDrill;
1352 PADSTACK::DRILL_PROPS secondaryDrill;
1353
1354 secondaryDrill.start = UNDEFINED_LAYER;
1355 secondaryDrill.end = UNDEFINED_LAYER;
1356 secondaryDrill.size = {0, 0};
1357 secondaryDrill.shape = PAD_DRILL_SHAPE::UNDEFINED;
1358
1359 tertiaryDrill.start = UNDEFINED_LAYER;
1360 tertiaryDrill.end = UNDEFINED_LAYER;
1361 tertiaryDrill.size = {0, 0};
1362 tertiaryDrill.shape = PAD_DRILL_SHAPE::UNDEFINED;
1363
1364 if( m_backdrillChoice->GetSelection() != wxNOT_FOUND )
1365 {
1366 switch( static_cast<BACKDRILL_MODE>( m_backdrillChoice->GetSelection() ) )
1367 {
1369 break;
1370
1372 if( m_backdrillBackSize.IsIndeterminate() || m_backdrillBackSize.IsNull() )
1373 {
1374 tertiaryDrill.size = viaStack.TertiaryDrill().size;
1375 }
1376 else
1377 {
1378 tertiaryDrill.size = VECTOR2I( m_backdrillBackSize.GetIntValue(),
1379 m_backdrillBackSize.GetIntValue() );
1380 }
1381
1382 tertiaryDrill.start = B_Cu;
1383 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1384
1385 if( m_backdrillBackLayer->GetLayerSelection() != UNDEFINED_LAYER )
1386 tertiaryDrill.end = ToLAYER_ID( m_backdrillBackLayer->GetLayerSelection() );
1387
1388 break;
1389
1391 if( m_backdrillFrontSize.IsIndeterminate() || m_backdrillFrontSize.IsNull() )
1392 {
1393 secondaryDrill.size = viaStack.SecondaryDrill().size;
1394 }
1395 else
1396 {
1397 secondaryDrill.size = VECTOR2I( m_backdrillFrontSize.GetIntValue(),
1398 m_backdrillFrontSize.GetIntValue() );
1399 }
1400
1401 secondaryDrill.start = F_Cu;
1402 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1403
1404 if( m_backdrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1405 secondaryDrill.end = ToLAYER_ID( m_backdrillFrontLayer->GetLayerSelection() );
1406
1407 break;
1408
1410 if( m_backdrillFrontSize.IsIndeterminate() || m_backdrillFrontSize.IsNull() )
1411 {
1412 secondaryDrill.size = viaStack.SecondaryDrill().size;
1413 }
1414 else
1415 {
1416 secondaryDrill.size = VECTOR2I( m_backdrillFrontSize.GetIntValue(),
1417 m_backdrillFrontSize.GetIntValue() );
1418 }
1419
1420 secondaryDrill.start = F_Cu;
1421 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1422
1423 if( m_backdrillFrontLayer->GetLayerSelection() != UNDEFINED_LAYER )
1424 secondaryDrill.end = ToLAYER_ID( m_backdrillFrontLayer->GetLayerSelection() );
1425
1426 if( m_backdrillBackSize.IsIndeterminate() || m_backdrillBackSize.IsNull() )
1427 {
1428 tertiaryDrill.size = viaStack.TertiaryDrill().size;
1429 }
1430 else
1431 {
1432 tertiaryDrill.size = VECTOR2I( m_backdrillBackSize.GetIntValue(),
1433 m_backdrillBackSize.GetIntValue() );
1434 }
1435
1436 tertiaryDrill.start = B_Cu;
1437 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
1438
1439 if( m_backdrillBackLayer->GetLayerSelection() != UNDEFINED_LAYER )
1440 tertiaryDrill.end = ToLAYER_ID( m_backdrillBackLayer->GetLayerSelection() );
1441
1442 break;
1443 }
1444
1445 if( via->Padstack().SecondaryDrill() != secondaryDrill )
1446 {
1447 viaStack.SecondaryDrill() = secondaryDrill;
1448 updatePadstack = true;
1449 }
1450
1451 if( via->Padstack().TertiaryDrill() != tertiaryDrill )
1452 {
1453 viaStack.TertiaryDrill() = tertiaryDrill;
1454 updatePadstack = true;
1455 }
1456 }
1457 else
1458 {
1459 if( !m_backdrillFrontSize.IsIndeterminate() && !m_backdrillFrontSize.IsNull() )
1460 {
1461 int frontSize = m_backdrillFrontSize.GetIntValue();
1462
1463 if( viaStack.SecondaryDrill().size != VECTOR2I( frontSize, frontSize ) )
1464 {
1465 viaStack.SecondaryDrill().size = VECTOR2I( frontSize, frontSize );
1466 updatePadstack = true;
1467 }
1468 }
1469
1470 if( !m_backdrillBackSize.IsIndeterminate() && !m_backdrillBackSize.IsNull() )
1471 {
1472 int backSize = m_backdrillBackSize.GetIntValue();
1473
1474 if( viaStack.TertiaryDrill().size != VECTOR2I( backSize, backSize ) )
1475 {
1476 viaStack.TertiaryDrill().size = VECTOR2I( backSize, backSize );
1477 updatePadstack = true;
1478 }
1479 }
1480 }
1481
1482 // Post Machining
1483 if( m_topPostMachine->GetSelection() != wxNOT_FOUND )
1484 {
1486
1487 switch( m_topPostMachine->GetSelection() )
1488 {
1489 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1490 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1492 }
1493
1494 if( !m_topPostMachineSize1.IsIndeterminate() )
1495 props.size = m_topPostMachineSize1.GetIntValue();
1496 else
1497 props.size = via->Padstack().FrontPostMachining().size;
1498
1499 if( !m_topPostMachineSize2.IsIndeterminate() )
1500 {
1502 props.angle = KiROUND( m_topPostMachineSize2.GetDoubleValue() * 10.0 );
1503 else
1504 props.depth = m_topPostMachineSize2.GetIntValue();
1505 }
1506 else
1507 {
1508 props.angle = via->Padstack().FrontPostMachining().angle;
1509 props.depth = via->Padstack().FrontPostMachining().depth;
1510 }
1511
1512 if( via->Padstack().FrontPostMachining() != props )
1513 {
1514 viaStack.FrontPostMachining() = props;
1515 updatePadstack = true;
1516 }
1517 }
1518
1519 if( m_bottomPostMachine->GetSelection() != wxNOT_FOUND )
1520 {
1522
1523 switch( m_bottomPostMachine->GetSelection() )
1524 {
1525 case 1: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
1526 case 2: props.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
1528 }
1529
1530 if( !m_bottomPostMachineSize1.IsIndeterminate() )
1531 props.size = m_bottomPostMachineSize1.GetIntValue();
1532 else
1533 props.size = via->Padstack().BackPostMachining().size;
1534
1535 if( !m_bottomPostMachineSize2.IsIndeterminate() )
1536 {
1538 props.angle = KiROUND( m_bottomPostMachineSize2.GetDoubleValue() * 10.0 );
1539 else
1540 props.depth = m_bottomPostMachineSize2.GetIntValue();
1541 }
1542 else
1543 {
1544 props.angle = via->Padstack().BackPostMachining().angle;
1545 props.depth = via->Padstack().BackPostMachining().depth;
1546 }
1547
1548 if( via->Padstack().BackPostMachining() != props )
1549 {
1550 viaStack.BackPostMachining() = props;
1551 updatePadstack = true;
1552 }
1553 }
1554
1555 switch( m_ViaTypeChoice->GetSelection() )
1556 {
1557 case 0: via->SetViaType( VIATYPE::THROUGH ); break;
1558 case 1: via->SetViaType( VIATYPE::MICROVIA ); break;
1559 case 2: via->SetViaType( VIATYPE::BLIND ); break;
1560 case 3: via->SetViaType( VIATYPE::BURIED ); break;
1561 default: break;
1562 }
1563
1564 PCB_LAYER_ID startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
1565 PCB_LAYER_ID endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
1566
1567 if( startLayer != UNDEFINED_LAYER )
1568 {
1569 if( via->Padstack().Drill().start != startLayer )
1570 {
1571 viaStack.Drill().start = startLayer;
1572 updatePadstack = true;
1573 }
1574
1575 via->SetTopLayer( startLayer );
1576 }
1577
1578 if( endLayer != UNDEFINED_LAYER )
1579 {
1580 if( via->Padstack().Drill().end != endLayer )
1581 {
1582 viaStack.Drill().end = endLayer;
1583 updatePadstack = true;
1584 }
1585
1586 via->SetBottomLayer( endLayer );
1587 }
1588
1589 if( updatePadstack )
1590 {
1591 via->SetPadstack( viaStack );
1592 via->SanitizeLayers();
1593 }
1594
1595 switch( m_annularRingsCtrl->GetSelection() )
1596 {
1597 case 0:
1598 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL );
1599 break;
1600 case 1:
1601 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
1602 break;
1603 case 2:
1604 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::REMOVE_ALL );
1605 break;
1606 case 3:
1607 via->Padstack().SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE::START_END_ONLY );
1608 break;
1609 default:
1610 break;
1611 }
1612
1613
1614 if( !m_viaDrill.IsIndeterminate() )
1615 via->SetDrill( m_viaDrill.GetIntValue() );
1616
1617 TEARDROP_PARAMETERS* targetParams = &via->GetTeardropParams();
1618
1619 if( m_cbTeardrops->Get3StateValue() != wxCHK_UNDETERMINED )
1620 targetParams->m_Enabled = m_cbTeardrops->GetValue();
1621
1622 if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
1623 targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
1624
1625 if( !m_teardropMaxLen.IsIndeterminate() )
1626 targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
1627
1628 if( !m_teardropMaxWidth.IsIndeterminate() )
1629 targetParams->m_TdMaxWidth = m_teardropMaxWidth.GetIntValue();
1630
1631 if( !m_teardropLenPercent.IsIndeterminate() )
1632 targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
1633
1634 if( !m_teardropWidthPercent.IsIndeterminate() )
1635 targetParams->m_BestWidthRatio = m_teardropWidthPercent.GetDoubleValue() / 100.0;
1636
1637 if( !m_teardropHDPercent.IsIndeterminate() )
1638 targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
1639
1640 if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
1641 targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
1642
1643 if( changeLock )
1644 via->SetLocked( setLock );
1645
1646 setViaConfiguration( via, static_cast<IPC4761_PRESET>( m_protectionFeatures->GetSelection() ) );
1647 break;
1648 }
1649
1650 default:
1651 UNIMPLEMENTED_FOR( track->GetClass() );
1652 break;
1653 }
1654 }
1655
1656 std::set<int> shortingNets;
1657 int newNetCode = m_netSelector->GetSelectedNetcode();
1658 std::set<PAD*> changingPads;
1659
1660 // Do NOT use the connectivity code here. It will propagate through zones, and we haven't
1661 // refilled those yet so it's going to pick up a whole bunch of other nets any time the track
1662 // width was increased.
1663 auto collide =
1665 {
1666 for( PCB_LAYER_ID layer : LSET( a->GetLayerSet() & b->GetLayerSet() ) )
1667 {
1668 if( a->GetEffectiveShape( layer )->Collide( b->GetEffectiveShape( layer ).get() ) )
1669 return true;
1670 }
1671
1672 return false;
1673 };
1674
1675 for( PCB_TRACK* track : connected_tracks )
1676 {
1677 for( PCB_TRACK* other : m_frame->GetBoard()->Tracks() )
1678 {
1679 if( other->GetNetCode() == track->GetNetCode() || other->GetNetCode() == newNetCode )
1680 continue;
1681
1682 if( collide( track, other ) )
1683 shortingNets.insert( other->GetNetCode() );
1684 }
1685
1686 for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
1687 {
1688 for( PAD* pad : footprint->Pads() )
1689 {
1690 if( pad->GetNetCode() == newNetCode )
1691 continue;
1692
1693 if( collide( track, pad ) )
1694 {
1695 if( pad->GetNetCode() == track->GetNetCode() )
1696 changingPads.insert( pad );
1697 else
1698 shortingNets.insert( pad->GetNetCode() );
1699 }
1700 }
1701 }
1702 }
1703
1704 if( shortingNets.size() && !confirmShortingNets( newNetCode, shortingNets ) )
1705 {
1706 commit.Revert();
1707 return true;
1708 }
1709
1710 if( !m_netSelector->IsIndeterminate() )
1711 {
1712 if( changingPads.empty() || confirmPadChange( changingPads ) )
1713 {
1714 for( PCB_TRACK* track : connected_tracks )
1715 {
1716 if( !alg::contains( selected_tracks, track ) )
1717 commit.Modify( track );
1718
1719 track->SetNetCode( newNetCode );
1720 }
1721
1722 for( PAD* pad : changingPads )
1723 {
1724 commit.Modify( pad );
1725 pad->SetNetCode( newNetCode );
1726 }
1727 }
1728 }
1729
1730 if( !m_standalone )
1731 commit.Push( _( "Edit Track/Via Properties" ) );
1732
1733 return true;
1734}
1735
1736
1738{
1739 m_viaNotFree->SetValue( false );
1740}
1741
1742
1744{
1745 if( !m_tracks )
1746 {
1747 m_netSelectorLabel->Enable( !m_viaNotFree->GetValue() );
1748 m_netSelector->Enable( !m_viaNotFree->GetValue() );
1749 }
1750}
1751
1752
1754{
1755 m_TrackWidthCtrl->ChangeValue( m_predefinedTrackWidthsCtrl->GetStringSelection() );
1756 m_TrackWidthCtrl->SelectAll();
1757}
1758
1759
1760void DIALOG_TRACK_VIA_PROPERTIES::onWidthEdit( wxCommandEvent& aEvent )
1761{
1762 m_predefinedTrackWidthsCtrl->SetStringSelection( m_TrackWidthCtrl->GetValue() );
1763}
1764
1765
1766void DIALOG_TRACK_VIA_PROPERTIES::onViaSelect( wxCommandEvent& aEvent )
1767{
1768 VIA_DIMENSION* viaDimension = static_cast<VIA_DIMENSION*> ( aEvent.GetClientData() );
1769
1770 m_viaDiameter.ChangeValue( viaDimension->m_Diameter );
1771 m_viaDrill.ChangeValue( viaDimension->m_Drill );
1772}
1773
1774
1776{
1777 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onPadstackModeChanged" );
1778
1779 switch( m_cbPadstackMode->GetSelection() )
1780 {
1781 default:
1782 case 0: m_viaStack->SetMode( PADSTACK::MODE::NORMAL ); break;
1783 case 1: m_viaStack->SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1784 case 2: m_viaStack->SetMode( PADSTACK::MODE::CUSTOM ); break;
1785 }
1786
1787 m_padstackDirty = true;
1788
1790}
1791
1792
1794{
1795 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onEditLayerChanged" );
1796
1797 // Save data from the previous layer
1798 if( !m_viaDiameter.IsIndeterminate() )
1799 {
1800 int diameter = m_viaDiameter.GetIntValue();
1801 const VECTOR2I& currentSize = m_viaStack->Size( m_editLayer );
1802
1803 if( currentSize.x != diameter || currentSize.y != diameter )
1804 {
1805 m_viaStack->SetSize( { diameter, diameter }, m_editLayer );
1806 m_padstackDirty = true;
1807 }
1808 }
1809
1810 switch( m_viaStack->Mode() )
1811 {
1812 default:
1815 break;
1816
1818 switch( m_cbEditLayer->GetSelection() )
1819 {
1820 default:
1821 case 0: m_editLayer = F_Cu; break;
1822 case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
1823 case 2: m_editLayer = B_Cu; break;
1824 }
1825 break;
1826
1828 {
1829 int layer = m_cbEditLayer->GetSelection();
1830
1831 if( layer < 0 )
1832 layer = 0;
1833
1834 if( m_editLayerCtrlMap.contains( layer ) )
1835 m_editLayer = m_editLayerCtrlMap.at( layer );
1836 else
1837 m_editLayer = F_Cu;
1838 }
1839 }
1840
1841 // Load controls with the current layer
1842 m_viaDiameter.SetValue( m_viaStack->Size( m_editLayer ).x );
1843}
1844
1845
1847{
1848 // NOTE: synchronize changes here with DIALOG_PAD_PROPERTIES::afterPadstackModeChanged
1849
1850 wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in afterPadstackModeChanged" );
1851 m_cbEditLayer->Clear();
1852
1853 BOARD* board = m_frame->GetBoard();
1854
1855 switch( m_viaStack->Mode() )
1856 {
1858 m_cbPadstackMode->SetSelection( 0 );
1859 m_cbEditLayer->Append( _( "All layers" ) );
1860 m_cbEditLayer->Disable();
1863 break;
1864
1866 {
1867 m_cbPadstackMode->SetSelection( 1 );
1868 m_cbEditLayer->Enable();
1869
1870 std::vector choices = {
1871 board->GetLayerName( F_Cu ),
1872 _( "Inner Layers" ),
1873 board->GetLayerName( B_Cu )
1874 };
1875
1876 m_cbEditLayer->Append( choices );
1877
1879 { 0, F_Cu },
1881 { 2, B_Cu }
1882 };
1883
1884 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
1886
1887 break;
1888 }
1889
1891 {
1892 m_cbPadstackMode->SetSelection( 2 );
1893 m_cbEditLayer->Enable();
1894 LSET layers = LSET::AllCuMask() & board->GetEnabledLayers();
1895
1896 for( PCB_LAYER_ID layer : layers.UIOrder() )
1897 {
1898 int idx = m_cbEditLayer->Append( board->GetLayerName( layer ) );
1899 m_editLayerCtrlMap[idx] = layer;
1900 }
1901
1902 break;
1903 }
1904 }
1905
1906 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1907 {
1908 if( layer == m_editLayer )
1909 {
1910 m_cbEditLayer->SetSelection( idx );
1911 break;
1912 }
1913 }
1914}
1915
1916
1918{
1919 int viaType = m_ViaTypeChoice->GetSelection();
1920
1921 if( viaType <= 0 )
1922 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1923
1924 int startLayer = m_ViaStartLayer->GetLayerSelection();
1925 int endLayer = m_ViaEndLayer->GetLayerSelection();
1926
1927 if( startLayer < 0 || endLayer < 0 )
1928 return m_frame->GetBoard()->GetCopperLayerCount() - 1;
1929 else
1930 return m_frame->GetBoard()->LayerDepth( ToLAYER_ID( startLayer ), ToLAYER_ID( endLayer ) );
1931}
1932
1933
1934void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
1935{
1936 m_predefinedViaSizesCtrl->SetSelection( wxNOT_FOUND );
1937
1938 if( m_vias )
1939 {
1940 if( m_ViaTypeChoice->GetSelection() != 0 ) // check if selected type isn't through.
1941 {
1942 m_ViaStartLayer->Enable();
1943 m_ViaEndLayer->Enable();
1944 }
1945 else
1946 {
1947 m_ViaStartLayer->SetLayerSelection( F_Cu );
1948 m_ViaEndLayer->SetLayerSelection( B_Cu );
1949
1950 m_ViaStartLayer->Enable( false );
1951 m_ViaEndLayer->Enable( false );
1952 }
1953
1954 m_annularRingsLabel->Show( getLayerDepth() > 1 );
1955 m_annularRingsCtrl->Show( getLayerDepth() > 1 );
1956 m_annularRingsCtrl->Enable( true );
1957 }
1958}
1959
1960
1961void DIALOG_TRACK_VIA_PROPERTIES::onTrackEdit( wxCommandEvent& aEvent )
1962{
1963 bool externalCuLayer = m_TrackLayerCtrl->GetLayerSelection() == F_Cu
1964 || m_TrackLayerCtrl->GetLayerSelection() == B_Cu;
1965
1966 m_techLayersLabel->Enable( externalCuLayer );
1967 m_trackHasSolderMask->Enable( externalCuLayer );
1968
1969 bool showMaskMargin = externalCuLayer && m_trackHasSolderMask->GetValue();
1970
1971 m_trackMaskMarginCtrl->Enable( showMaskMargin );
1972 m_trackMaskMarginLabel->Enable( showMaskMargin );
1973 m_trackMaskMarginUnit->Enable( showMaskMargin );
1974}
1975
1976
1978{
1979 event.Enable( !m_frame->GetBoard()->LegacyTeardrops() );
1980}
1981
1982
1984{
1985 int selection = m_backdrillChoice->GetSelection();
1986 // 0: None, 1: Bottom, 2: Top, 3: Both
1987
1988 bool enableTop = ( selection == 2 || selection == 3 );
1989 bool enableBottom = ( selection == 1 || selection == 3 );
1990
1991 m_backdrillFrontSize.Enable( enableTop );
1992 m_backdrillFrontLayer->Enable( enableTop );
1993 m_backdrillFrontLayerLabel->Enable( enableTop );
1994
1995 if( enableTop )
1996 {
1997 if( m_backdrillFrontLayer->GetLayerSelection() == UNDEFINED_LAYER )
1998 m_backdrillFrontLayer->SetLayerSelection( F_Cu );
1999
2000 if( m_backdrillFrontSize.GetIntValue() == 0 )
2001 {
2002 // Initialize backdrill slightly larger than main drill (see PADSTACK::SetBackdrillMode())
2003 m_backdrillFrontSize.SetValue( KiROUND( m_viaDrill.GetIntValue() * 1.1 ) );
2004 }
2005 }
2006
2007 m_backdrillBackSize.Enable( enableBottom );
2008 m_backdrillBackLayer->Enable( enableBottom ); // Back layer selector
2009 m_backdrillBackLayerLabel->Enable( enableBottom ); // Back layer label
2010
2011 if( enableBottom )
2012 {
2013 if( m_backdrillBackLayer->GetLayerSelection() == UNDEFINED_LAYER )
2014 m_backdrillBackLayer->SetLayerSelection( B_Cu );
2015
2016 if( m_backdrillBackSize.GetIntValue() == 0 )
2017 {
2018 // Initialize backdrill slightly larger than main drill (see PADSTACK::SetBackdrillMode())
2019 m_backdrillBackSize.SetValue( KiROUND( m_viaDrill.GetIntValue() * 1.1 ) );
2020 }
2021 }
2022}
2023
2024
2026{
2027 int selection = m_topPostMachine->GetSelection();
2028 // 0: None, 1: Countersink, 2: Counterbore
2029
2030 bool enable = ( selection != 0 );
2031 m_topPostMachineSize1.Enable( enable );
2032 m_topPostMachineSize2.Enable( enable );
2033 m_topPostMachineSize1Label->Enable( enable );
2034 m_topPostMachineSize2Label->Enable( enable );
2035
2036 if( selection == 1 ) // Countersink
2037 {
2038 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2039 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2041
2042 if( m_topPostMachineSize2.IsIndeterminate() || m_topPostMachineSize2.GetDoubleValue() == 0 )
2043 {
2044 m_topPostMachineSize2.SetDoubleValue( 82.0 );
2045 }
2046 }
2047 else if( selection == 2 ) // Counterbore
2048 {
2049 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2050 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
2051 m_topPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
2052 }
2053 else
2054 {
2055 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2056 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2058 }
2059}
2060
2061
2063{
2064 int selection = m_bottomPostMachine->GetSelection();
2065 // 0: None, 1: Countersink, 2: Counterbore
2066
2067 bool enable = ( selection != 0 );
2068 m_bottomPostMachineSize1.Enable( enable );
2069 m_bottomPostMachineSize2.Enable( enable );
2070 m_bottomPostMachineSize1Label->Enable( enable );
2071 m_bottomPostMachineSize2Label->Enable( enable );
2072
2073 if( selection == 1 ) // Countersink
2074 {
2075 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2076 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2078
2079 if( m_bottomPostMachineSize2.IsIndeterminate() || m_bottomPostMachineSize2.GetDoubleValue() == 0 )
2080 {
2081 m_bottomPostMachineSize2.SetDoubleValue( 82.0 );
2082 }
2083 }
2084 else if( selection == 2 ) // Counterbore
2085 {
2086 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2087 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
2088 m_bottomPostMachineSize2.SetUnits( m_frame->GetUserUnits() );
2089 }
2090}
2091
2092
const char * name
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
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
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:346
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:936
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1183
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
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)
bool m_standalone
Dialog was constructed for a standalone via (via stitching.
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
void commonInit(PCB_BASE_EDIT_FRAME *aParent)
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)
PCB_SELECTION m_viaStandaloneSelection
Used for standalone via mode to flow through the normal update logic.
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:901
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
Definition kidialog.h:48
int ShowModal() override
Definition kidialog.cpp:89
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:739
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:623
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:156
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:370
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:367
DRILL_PROPS & Drill()
Definition padstack.h:361
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:172
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:364
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:373
void SetSize(const VECTOR2I &aSize, PCB_LAYER_ID aLayer)
Definition padstack.cpp:854
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
Definition pad.h:61
const wxString & GetNumber() const
Definition pad.h:143
Common, abstract interface for edit frames.
bool HasSolderMask() const
Definition pcb_track.h:117
int GetStartY() const
Definition pcb_track.h:99
int GetEndX() const
Definition pcb_track.h:104
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:120
int GetEndY() const
Definition pcb_track.h:105
int GetStartX() const
Definition pcb_track.h:98
virtual int GetWidth() const
Definition pcb_track.h:87
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:833
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:580
const PADSTACK & Padstack() const
Definition pcb_track.h:418
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:410
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:179
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:192
This file is part of the common library.
#define EXCLUDE_ZONES
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
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)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
BACKDRILL_MODE
Definition padstack.h:83
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:53
VIATYPE
bool collide(T aObject, U aAnotherObject, int aLayer, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition shape_index.h:93
The properties of a padstack drill.
Definition padstack.h:272
PCB_LAYER_ID start
Definition padstack.h:275
PCB_LAYER_ID end
Definition padstack.h:276
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:273
PAD_DRILL_SHAPE shape
Definition padstack.h:274
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:287
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
KIBIS top(path, &reporter)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
#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:683