2015-07-09 13:35:51 +02:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 CERN
|
2025-01-01 13:30:11 -08:00
|
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
2015-07-09 13:35:51 +02:00
|
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2020-12-27 16:35:07 +00:00
|
|
|
#include <core/kicad_algo.h>
|
2015-07-09 13:35:51 +02:00
|
|
|
#include <dialogs/dialog_track_via_properties.h>
|
2018-01-31 09:23:20 +01:00
|
|
|
#include <pcb_layer_box_selector.h>
|
2020-12-16 13:31:32 +00:00
|
|
|
#include <tools/pcb_selection_tool.h>
|
2021-06-06 15:03:10 -04:00
|
|
|
#include <board_design_settings.h>
|
2021-06-03 19:05:43 +01:00
|
|
|
#include <footprint.h>
|
2021-06-06 15:03:10 -04:00
|
|
|
#include <pad.h>
|
2021-06-11 22:07:02 +01:00
|
|
|
#include <pcb_track.h>
|
2015-07-09 13:35:51 +02:00
|
|
|
#include <confirm.h>
|
2024-04-27 22:57:24 +03:00
|
|
|
#include <kidialog.h>
|
2018-10-11 23:17:15 -07:00
|
|
|
#include <connectivity/connectivity_data.h>
|
2016-06-20 15:46:58 +02:00
|
|
|
#include <board_commit.h>
|
2025-03-01 18:02:54 +00:00
|
|
|
#include <magic_enum.hpp>
|
2025-07-07 20:23:49 +01:00
|
|
|
#include <macros.h>
|
2025-03-01 18:02:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool DIALOG_TRACK_VIA_PROPERTIES::IPC4761_CONFIGURATION::operator==(
|
|
|
|
const IPC4761_CONFIGURATION& aOther ) const
|
|
|
|
{
|
|
|
|
return ( tent == aOther.tent ) && ( plug == aOther.plug ) && ( cover == aOther.cover )
|
|
|
|
&& ( cap == aOther.cap ) && ( fill == aOther.fill );
|
|
|
|
}
|
2016-06-20 15:46:58 +02:00
|
|
|
|
2024-12-08 15:53:13 +01:00
|
|
|
|
2025-02-25 17:07:59 +00:00
|
|
|
DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent,
|
2023-06-27 16:52:50 +01:00
|
|
|
const PCB_SELECTION& aItems ) :
|
2024-02-23 14:38:22 +00:00
|
|
|
DIALOG_TRACK_VIA_PROPERTIES_BASE( aParent ),
|
|
|
|
m_frame( aParent ),
|
|
|
|
m_items( aItems ),
|
|
|
|
m_trackStartX( aParent, m_TrackStartXLabel, m_TrackStartXCtrl, nullptr ),
|
|
|
|
m_trackStartY( aParent, m_TrackStartYLabel, m_TrackStartYCtrl, m_TrackStartYUnit ),
|
|
|
|
m_trackEndX( aParent, m_TrackEndXLabel, m_TrackEndXCtrl, nullptr ),
|
|
|
|
m_trackEndY( aParent, m_TrackEndYLabel, m_TrackEndYCtrl, m_TrackEndYUnit ),
|
|
|
|
m_trackWidth( aParent, m_TrackWidthLabel, m_TrackWidthCtrl, m_TrackWidthUnit ),
|
2024-09-29 13:25:21 +02:00
|
|
|
m_trackMaskMargin( aParent, m_trackMaskMarginLabel, m_trackMaskMarginCtrl, m_trackMaskMarginUnit ),
|
2024-02-23 14:38:22 +00:00
|
|
|
m_viaX( aParent, m_ViaXLabel, m_ViaXCtrl, nullptr ),
|
|
|
|
m_viaY( aParent, m_ViaYLabel, m_ViaYCtrl, m_ViaYUnit ),
|
|
|
|
m_viaDiameter( aParent, m_ViaDiameterLabel, m_ViaDiameterCtrl, m_ViaDiameterUnit ),
|
|
|
|
m_viaDrill( aParent, m_ViaDrillLabel, m_ViaDrillCtrl, m_ViaDrillUnit ),
|
|
|
|
m_teardropHDPercent( aParent, m_stHDRatio, m_tcHDRatio, m_stHDRatioUnits ),
|
|
|
|
m_teardropLenPercent( aParent, m_stLenPercentLabel, m_tcLenPercent, nullptr ),
|
|
|
|
m_teardropMaxLen( aParent, m_stMaxLen, m_tcTdMaxLen, m_stMaxLenUnits ),
|
|
|
|
m_teardropWidthPercent( aParent, m_stWidthPercentLabel, m_tcWidthPercent, nullptr ),
|
|
|
|
m_teardropMaxWidth( aParent, m_stMaxWidthLabel, m_tcMaxWidth, m_stMaxWidthUnits ),
|
|
|
|
m_tracks( false ),
|
2024-11-02 10:02:17 -04:00
|
|
|
m_vias( false ),
|
|
|
|
m_editLayer( PADSTACK::ALL_LAYERS )
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
2021-01-07 00:45:32 +00:00
|
|
|
m_useCalculatedSize = true;
|
|
|
|
|
2017-08-11 11:38:06 +02:00
|
|
|
wxASSERT( !m_items.Empty() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2023-10-21 14:56:19 -04:00
|
|
|
m_legacyTeardropsIcon->SetBitmap( KiBitmapBundle( BITMAPS::dialog_warning ) );
|
2023-05-12 22:03:54 +01:00
|
|
|
m_legacyTeardropsWarning->Show( m_frame->GetBoard()->LegacyTeardrops() );
|
|
|
|
|
2023-10-21 14:56:19 -04:00
|
|
|
m_bitmapTeardrop->SetBitmap( KiBitmapBundle( BITMAPS::teardrop_sizes ) );
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
m_teardropHDPercent.SetUnits( EDA_UNITS::PERCENT );
|
|
|
|
m_teardropLenPercent.SetUnits( EDA_UNITS::PERCENT );
|
2024-02-23 14:38:22 +00:00
|
|
|
m_teardropWidthPercent.SetUnits( EDA_UNITS::PERCENT );
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
m_minTrackWidthHint->SetFont( KIUI::GetInfoFont( this ).Italic() );
|
|
|
|
|
2020-07-06 10:41:29 -04:00
|
|
|
// Configure display origin transforms
|
|
|
|
m_trackStartX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
|
|
|
|
m_trackStartY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
|
|
|
|
m_trackEndX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
|
|
|
|
m_trackEndY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
|
|
|
|
m_viaX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
|
|
|
|
m_viaY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
|
|
|
|
|
2019-12-28 00:55:11 +00:00
|
|
|
VIATYPE viaType = VIATYPE::NOT_DEFINED;
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2018-07-20 20:26:50 +01:00
|
|
|
m_TrackLayerCtrl->SetLayersHotkeys( false );
|
|
|
|
m_TrackLayerCtrl->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
|
|
|
|
m_TrackLayerCtrl->SetBoardFrame( aParent );
|
|
|
|
m_TrackLayerCtrl->Resync();
|
|
|
|
|
|
|
|
m_ViaStartLayer->SetLayersHotkeys( false );
|
|
|
|
m_ViaStartLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
|
|
|
|
m_ViaStartLayer->SetBoardFrame( aParent );
|
|
|
|
m_ViaStartLayer->Resync();
|
|
|
|
|
|
|
|
m_ViaEndLayer->SetLayersHotkeys( false );
|
|
|
|
m_ViaEndLayer->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
|
|
|
|
m_ViaEndLayer->SetBoardFrame( aParent );
|
|
|
|
m_ViaEndLayer->Resync();
|
|
|
|
|
2025-04-27 17:33:06 +01:00
|
|
|
wxFont infoFont = KIUI::GetSmallInfoFont( this );
|
2024-09-29 13:25:21 +02:00
|
|
|
m_techLayersLabel->SetFont( infoFont );
|
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
bool nets = false;
|
|
|
|
int net = 0;
|
2016-08-15 17:16:48 +02:00
|
|
|
bool hasLocked = false;
|
|
|
|
bool hasUnlocked = false;
|
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
// Start and end layers of vias
|
|
|
|
// if at least 2 vias do not have the same start or the same end layer
|
|
|
|
// the layers will be set as undefined
|
|
|
|
int selection_first_layer = -1;
|
|
|
|
int selection_last_layer = -1;
|
|
|
|
|
|
|
|
// The selection layer for tracks
|
|
|
|
int track_selection_layer = -1;
|
|
|
|
|
2025-03-01 18:02:54 +00:00
|
|
|
auto getAnnularRingSelection = []( const PCB_VIA* via ) -> int
|
|
|
|
{
|
|
|
|
switch( via->Padstack().UnconnectedLayerMode() )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL: return 0;
|
|
|
|
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END: return 1;
|
|
|
|
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL: return 2;
|
|
|
|
}
|
|
|
|
};
|
2021-08-14 01:44:23 +01:00
|
|
|
|
2025-03-01 18:02:54 +00:00
|
|
|
for( auto& preset : magic_enum::enum_values<IPC4761_PRESET>() )
|
|
|
|
{
|
|
|
|
if( preset >= IPC4761_PRESET::CUSTOM )
|
|
|
|
continue;
|
2024-06-09 18:28:19 -04:00
|
|
|
|
2025-03-01 18:02:54 +00:00
|
|
|
const auto& name_it = m_IPC4761Names.find( preset );
|
2024-06-09 12:44:30 -04:00
|
|
|
|
2025-03-01 18:02:54 +00:00
|
|
|
wxString name = _( "Unknown choice" );
|
2024-06-09 12:44:30 -04:00
|
|
|
|
2025-03-01 18:02:54 +00:00
|
|
|
if( name_it != m_IPC4761Names.end() )
|
|
|
|
name = name_it->second;
|
|
|
|
|
|
|
|
m_protectionFeatures->AppendString( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getProtectionSurface = []( const std::optional<bool>& front,
|
|
|
|
const std::optional<bool>& back ) -> IPC4761_SURFACE
|
|
|
|
{
|
|
|
|
IPC4761_SURFACE value = IPC4761_SURFACE::CUSTOM;
|
|
|
|
|
|
|
|
if( !front.has_value() )
|
|
|
|
value = IPC4761_SURFACE::FROM_RULES;
|
|
|
|
else if( front.value() )
|
|
|
|
value = IPC4761_SURFACE::FRONT;
|
|
|
|
else
|
|
|
|
value = IPC4761_SURFACE::NONE;
|
|
|
|
|
|
|
|
if( !back.has_value() )
|
|
|
|
{
|
|
|
|
if( value == IPC4761_SURFACE::FROM_RULES )
|
|
|
|
return IPC4761_SURFACE::FROM_RULES;
|
|
|
|
}
|
|
|
|
else if( back.value() )
|
|
|
|
{
|
|
|
|
if( value == IPC4761_SURFACE::FRONT )
|
|
|
|
return IPC4761_SURFACE::BOTH;
|
|
|
|
else if( value == IPC4761_SURFACE::NONE )
|
|
|
|
return IPC4761_SURFACE::BACK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( value == IPC4761_SURFACE::FRONT )
|
|
|
|
return IPC4761_SURFACE::FRONT;
|
|
|
|
else if( value == IPC4761_SURFACE::NONE )
|
|
|
|
return IPC4761_SURFACE::NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IPC4761_SURFACE::CUSTOM;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto getProtectionDrill = []( const std::optional<bool>& drill ) -> IPC4761_DRILL
|
|
|
|
{
|
|
|
|
if( !drill.has_value() )
|
|
|
|
return IPC4761_DRILL::FROM_RULES;
|
|
|
|
if( drill.value() )
|
|
|
|
return IPC4761_DRILL::SET;
|
|
|
|
|
|
|
|
return IPC4761_DRILL::NOT_SET;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto getViaConfiguration = [&]( const PCB_VIA* via ) -> IPC4761_PRESET
|
|
|
|
{
|
|
|
|
IPC4761_CONFIGURATION config;
|
|
|
|
config.tent = getProtectionSurface( via->Padstack().FrontOuterLayers().has_solder_mask,
|
|
|
|
via->Padstack().BackOuterLayers().has_solder_mask );
|
|
|
|
|
|
|
|
config.cover = getProtectionSurface( via->Padstack().FrontOuterLayers().has_covering,
|
|
|
|
via->Padstack().BackOuterLayers().has_covering );
|
|
|
|
|
|
|
|
config.plug = getProtectionSurface( via->Padstack().FrontOuterLayers().has_plugging,
|
|
|
|
via->Padstack().BackOuterLayers().has_plugging );
|
|
|
|
|
|
|
|
config.cap = getProtectionDrill( via->Padstack().Drill().is_capped );
|
|
|
|
|
|
|
|
config.fill = getProtectionDrill( via->Padstack().Drill().is_filled );
|
|
|
|
|
|
|
|
for( const auto& [preset, configuration] : m_IPC4761Presets )
|
|
|
|
{
|
|
|
|
if( configuration == config )
|
|
|
|
return preset;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IPC4761_PRESET::CUSTOM;
|
|
|
|
};
|
2024-06-09 12:44:30 -04:00
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
// Look for values that are common for every item that is selected
|
2020-05-05 16:40:18 +01:00
|
|
|
for( EDA_ITEM* item : m_items )
|
2017-07-03 19:14:35 +02:00
|
|
|
{
|
2018-08-19 17:11:58 +01:00
|
|
|
if( !nets )
|
2017-07-03 19:14:35 +02:00
|
|
|
{
|
2018-08-19 17:11:58 +01:00
|
|
|
net = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode();
|
|
|
|
nets = true;
|
|
|
|
}
|
|
|
|
else if( net != static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetCode() )
|
|
|
|
{
|
|
|
|
net = -1;
|
2017-07-03 19:14:35 +02:00
|
|
|
}
|
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
switch( item->Type() )
|
|
|
|
{
|
|
|
|
case PCB_TRACE_T:
|
2019-05-16 17:13:21 -07:00
|
|
|
case PCB_ARC_T:
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
2021-06-11 22:07:02 +01:00
|
|
|
const PCB_TRACK* t = static_cast<const PCB_TRACK*>( item );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
|
|
|
if( !m_tracks ) // first track in the list
|
|
|
|
{
|
2024-11-28 05:37:47 +08:00
|
|
|
m_trackStartX.SetValue( t->GetStartX() );
|
|
|
|
m_trackStartY.SetValue( t->GetStartY() );
|
|
|
|
m_trackEndX.SetValue( t->GetEndX() );
|
|
|
|
m_trackEndY.SetValue( t->GetEndY() );
|
2018-02-03 09:09:53 +00:00
|
|
|
m_trackWidth.SetValue( t->GetWidth() );
|
2021-11-24 17:36:10 +01:00
|
|
|
track_selection_layer = t->GetLayer();
|
2024-09-29 13:25:21 +02:00
|
|
|
m_trackHasSolderMask->SetValue ( t->HasSolderMask() );
|
|
|
|
|
|
|
|
if( t->GetLocalSolderMaskMargin().has_value() )
|
|
|
|
m_trackMaskMargin.SetValue( t->GetLocalSolderMaskMargin().value() );
|
|
|
|
else
|
|
|
|
m_trackMaskMargin.SetValue( wxEmptyString );
|
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
m_tracks = true;
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
else // check if values are the same for every selected track
|
|
|
|
{
|
2024-11-28 05:37:47 +08:00
|
|
|
if( m_trackStartX.GetValue() != t->GetStartX() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_trackStartX.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-11-28 05:37:47 +08:00
|
|
|
if( m_trackStartY.GetValue() != t->GetStartY() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_trackStartY.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-11-28 05:37:47 +08:00
|
|
|
if( m_trackEndX.GetValue() != t->GetEndX() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_trackEndX.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-11-28 05:37:47 +08:00
|
|
|
if( m_trackEndY.GetValue() != t->GetEndY() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_trackEndY.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( m_trackWidth.GetValue() != t->GetWidth() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_trackWidth.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
if( track_selection_layer != t->GetLayer() )
|
|
|
|
track_selection_layer = UNDEFINED_LAYER;
|
2024-09-29 13:25:21 +02:00
|
|
|
|
|
|
|
if( m_trackHasSolderMask->GetValue() != t->HasSolderMask() )
|
|
|
|
m_trackHasSolderMask->Set3StateValue( wxCHK_UNDETERMINED );
|
|
|
|
|
|
|
|
if( m_trackMaskMargin.GetValue() != t->GetLocalSolderMaskMargin() )
|
|
|
|
m_trackMaskMargin.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
2016-08-15 17:16:48 +02:00
|
|
|
|
2016-08-15 17:16:53 +02:00
|
|
|
if( t->IsLocked() )
|
2016-08-15 17:16:48 +02:00
|
|
|
hasLocked = true;
|
|
|
|
else
|
|
|
|
hasUnlocked = true;
|
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PCB_VIA_T:
|
|
|
|
{
|
2023-05-12 22:03:54 +01:00
|
|
|
PCB_VIA* v = static_cast<PCB_VIA*>( item );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
|
|
|
if( !m_vias ) // first via in the list
|
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
m_viaX.SetValue( v->GetPosition().x );
|
|
|
|
m_viaY.SetValue( v->GetPosition().y );
|
2024-11-02 10:02:17 -04:00
|
|
|
m_viaStack = std::make_unique<PADSTACK>( v->Padstack() );
|
|
|
|
m_viaDiameter.SetValue( v->GetWidth( m_editLayer ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
m_viaDrill.SetValue( v->GetDrillValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
m_vias = true;
|
2018-01-06 23:32:22 +01:00
|
|
|
viaType = v->GetViaType();
|
2020-12-20 16:29:43 -05:00
|
|
|
m_viaNotFree->SetValue( !v->GetIsFree() );
|
2021-08-14 01:44:23 +01:00
|
|
|
m_annularRingsCtrl->SetSelection( getAnnularRingSelection( v ) );
|
2024-06-09 18:28:19 -04:00
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
selection_first_layer = v->TopLayer();
|
|
|
|
selection_last_layer = v->BottomLayer();
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
m_cbTeardrops->SetValue( v->GetTeardropParams().m_Enabled );
|
|
|
|
m_cbTeardropsUseNextTrack->SetValue( v->GetTeardropParams().m_AllowUseTwoTracks );
|
|
|
|
m_teardropMaxLen.SetValue( v->GetTeardropParams().m_TdMaxLen );
|
2024-02-23 14:38:22 +00:00
|
|
|
m_teardropMaxWidth.SetValue( v->GetTeardropParams().m_TdMaxWidth );
|
2023-05-12 22:03:54 +01:00
|
|
|
m_teardropLenPercent.SetDoubleValue( v->GetTeardropParams().m_BestLengthRatio*100.0 );
|
2024-02-23 14:38:22 +00:00
|
|
|
m_teardropWidthPercent.SetDoubleValue( v->GetTeardropParams().m_BestWidthRatio*100.0 );
|
2023-05-12 22:03:54 +01:00
|
|
|
m_teardropHDPercent.SetDoubleValue( v->GetTeardropParams().m_WidthtoSizeFilterRatio*100.0 );
|
2024-12-28 22:38:18 +00:00
|
|
|
m_curvedEdges->SetValue( v->GetTeardropParams().m_CurvedEdges );
|
2025-03-01 18:02:54 +00:00
|
|
|
|
|
|
|
IPC4761_PRESET preset = getViaConfiguration( v );
|
|
|
|
|
|
|
|
if( preset >= IPC4761_PRESET::CUSTOM )
|
|
|
|
{
|
|
|
|
m_protectionFeatures->SetSelection(
|
|
|
|
m_protectionFeatures->Append( INDETERMINATE_ACTION ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_protectionFeatures->SetSelection( static_cast<int>( preset ) );
|
|
|
|
}
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
else // check if values are the same for every selected via
|
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
if( m_viaX.GetValue() != v->GetPosition().x )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_viaX.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( m_viaY.GetValue() != v->GetPosition().y )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_viaY.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-11-02 10:02:17 -04:00
|
|
|
if( m_viaDiameter.GetValue() != v->GetWidth( m_editLayer ) )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_viaDiameter.SetValue( INDETERMINATE_STATE );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( m_viaDrill.GetValue() != v->GetDrillValue() )
|
2020-05-05 16:40:18 +01:00
|
|
|
m_viaDrill.SetValue( INDETERMINATE_STATE );
|
2018-01-06 23:32:22 +01:00
|
|
|
|
|
|
|
if( viaType != v->GetViaType() )
|
2019-12-28 00:55:11 +00:00
|
|
|
viaType = VIATYPE::NOT_DEFINED;
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2020-12-20 16:29:43 -05:00
|
|
|
if( v->GetIsFree() != !m_viaNotFree->GetValue() )
|
|
|
|
m_viaNotFree->Set3StateValue( wxCHK_UNDETERMINED );
|
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
if( selection_first_layer != v->TopLayer() )
|
|
|
|
selection_first_layer = UNDEFINED_LAYER;
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
if( selection_last_layer != v->BottomLayer() )
|
|
|
|
selection_last_layer = UNDEFINED_LAYER;
|
2021-08-14 01:44:23 +01:00
|
|
|
|
|
|
|
if( m_annularRingsCtrl->GetSelection() != getAnnularRingSelection( v ) )
|
|
|
|
{
|
|
|
|
if( m_annularRingsCtrl->GetStrings().size() < 4 )
|
|
|
|
m_annularRingsCtrl->AppendString( INDETERMINATE_STATE );
|
|
|
|
|
|
|
|
m_annularRingsCtrl->SetSelection( 3 );
|
|
|
|
}
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( m_cbTeardrops->GetValue() != v->GetTeardropParams().m_Enabled )
|
|
|
|
m_cbTeardrops->Set3StateValue( wxCHK_UNDETERMINED );
|
|
|
|
|
|
|
|
if( m_cbTeardropsUseNextTrack->GetValue() != v->GetTeardropParams().m_AllowUseTwoTracks )
|
|
|
|
m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
|
|
|
|
|
|
|
|
if( m_teardropMaxLen.GetValue() != v->GetTeardropParams().m_TdMaxLen )
|
|
|
|
m_teardropMaxLen.SetValue( INDETERMINATE_STATE );
|
|
|
|
|
2024-02-23 14:38:22 +00:00
|
|
|
if( m_teardropMaxWidth.GetValue() != v->GetTeardropParams().m_TdMaxWidth )
|
|
|
|
m_teardropMaxWidth.SetValue( INDETERMINATE_STATE );
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( m_teardropLenPercent.GetDoubleValue() != v->GetTeardropParams().m_BestLengthRatio *100.0 )
|
|
|
|
m_teardropLenPercent.SetValue( INDETERMINATE_STATE );
|
|
|
|
|
2024-02-23 14:38:22 +00:00
|
|
|
if( m_teardropWidthPercent.GetDoubleValue() != v->GetTeardropParams().m_BestWidthRatio *100.0 )
|
|
|
|
m_teardropWidthPercent.SetValue( INDETERMINATE_STATE );
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( m_teardropHDPercent.GetDoubleValue() != v->GetTeardropParams().m_WidthtoSizeFilterRatio*100.0 )
|
|
|
|
m_teardropHDPercent.SetValue( INDETERMINATE_STATE );
|
2025-03-01 18:02:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
if( static_cast<int>( getViaConfiguration( v ) )
|
|
|
|
!= m_protectionFeatures->GetSelection() )
|
|
|
|
{
|
|
|
|
m_protectionFeatures->SetSelection(
|
|
|
|
m_protectionFeatures->Append( INDETERMINATE_STATE ) );
|
|
|
|
}
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
2016-08-15 17:16:48 +02:00
|
|
|
|
2016-08-15 17:16:53 +02:00
|
|
|
if( v->IsLocked() )
|
2016-08-15 17:16:48 +02:00
|
|
|
hasLocked = true;
|
|
|
|
else
|
|
|
|
hasUnlocked = true;
|
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2018-01-06 23:32:22 +01:00
|
|
|
{
|
2025-07-07 20:23:49 +01:00
|
|
|
UNIMPLEMENTED_FOR( item->GetClass() );
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
2018-01-06 23:32:22 +01:00
|
|
|
}
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
if( m_tracks )
|
|
|
|
{
|
|
|
|
// Set the track layer selection state:
|
|
|
|
if( track_selection_layer == UNDEFINED_LAYER )
|
|
|
|
{
|
|
|
|
m_TrackLayerCtrl->SetUndefinedLayerName( INDETERMINATE_STATE );
|
|
|
|
m_TrackLayerCtrl->Resync();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_TrackLayerCtrl->SetLayerSelection( track_selection_layer );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the vias layers selections state:
|
|
|
|
if( m_vias )
|
|
|
|
{
|
|
|
|
if( selection_first_layer == UNDEFINED_LAYER )
|
|
|
|
{
|
|
|
|
m_ViaStartLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
|
|
|
|
m_ViaStartLayer->Resync();
|
|
|
|
}
|
2022-11-24 18:05:37 +00:00
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
m_ViaStartLayer->SetLayerSelection( selection_first_layer );
|
|
|
|
|
|
|
|
if( selection_last_layer == UNDEFINED_LAYER )
|
|
|
|
{
|
|
|
|
m_ViaEndLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
|
|
|
|
m_ViaEndLayer->Resync();
|
|
|
|
}
|
2022-11-24 18:05:37 +00:00
|
|
|
|
2021-11-24 17:36:10 +01:00
|
|
|
m_ViaEndLayer->SetLayerSelection( selection_last_layer );
|
|
|
|
}
|
|
|
|
|
2020-05-05 16:40:18 +01:00
|
|
|
m_netSelector->SetNetInfo( &aParent->GetBoard()->GetNetInfo() );
|
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
if ( net >= 0 )
|
2020-05-05 16:40:18 +01:00
|
|
|
{
|
2018-08-19 17:11:58 +01:00
|
|
|
m_netSelector->SetSelectedNetcode( net );
|
2020-05-05 16:40:18 +01:00
|
|
|
}
|
2018-08-19 17:11:58 +01:00
|
|
|
else
|
2020-05-05 16:40:18 +01:00
|
|
|
{
|
|
|
|
m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
|
2018-08-19 17:11:58 +01:00
|
|
|
m_netSelector->SetIndeterminate();
|
2020-05-05 16:40:18 +01:00
|
|
|
}
|
2018-08-19 17:11:58 +01:00
|
|
|
|
2017-08-11 11:38:06 +02:00
|
|
|
wxASSERT( m_tracks || m_vias );
|
2015-07-15 14:08:50 +02:00
|
|
|
|
|
|
|
if( m_vias )
|
|
|
|
{
|
2022-09-20 11:36:44 +01:00
|
|
|
if( m_viaNotFree->GetValue() && !m_tracks )
|
2021-01-06 15:35:25 +00:00
|
|
|
{
|
2022-09-20 11:36:44 +01:00
|
|
|
// Disable net selector to re-inforce meaning of "Automatically update via nets",
|
|
|
|
// but not when tracks are also selected as then things get harder if you want to
|
|
|
|
// update all the nets to match.
|
2021-01-06 15:35:25 +00:00
|
|
|
m_netSelectorLabel->Disable();
|
|
|
|
m_netSelector->Disable();
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
int viaSelection = wxNOT_FOUND;
|
|
|
|
|
|
|
|
// 0 is the netclass place-holder
|
|
|
|
for( unsigned ii = 1; ii < aParent->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
|
2017-09-18 10:28:08 +02:00
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
VIA_DIMENSION* viaDimension = &aParent->GetDesignSettings().m_ViasDimensionsList[ii];
|
|
|
|
wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
|
|
|
|
+ wxT( " / " )
|
|
|
|
+ m_frame->StringFromValue( viaDimension->m_Drill );
|
|
|
|
m_predefinedViaSizesCtrl->Append( msg, viaDimension );
|
2023-11-18 12:17:44 +00:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
if( viaSelection == wxNOT_FOUND
|
|
|
|
&& m_viaDiameter.GetValue() == viaDimension->m_Diameter
|
|
|
|
&& m_viaDrill.GetValue() == viaDimension->m_Drill )
|
2017-09-18 10:28:08 +02:00
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
viaSelection = ii - 1;
|
2017-09-18 10:28:08 +02:00
|
|
|
}
|
2023-11-18 12:17:44 +00:00
|
|
|
}
|
2017-09-18 10:28:08 +02:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedViaSizesCtrl->SetSelection( viaSelection );
|
|
|
|
m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
|
|
|
|
|
2018-01-06 23:32:22 +01:00
|
|
|
m_ViaTypeChoice->Enable();
|
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
switch( viaType )
|
|
|
|
{
|
2021-08-14 01:44:23 +01:00
|
|
|
case VIATYPE::THROUGH: m_ViaTypeChoice->SetSelection( 0 ); break;
|
|
|
|
case VIATYPE::MICROVIA: m_ViaTypeChoice->SetSelection( 1 ); break;
|
|
|
|
case VIATYPE::BLIND_BURIED: m_ViaTypeChoice->SetSelection( 2 ); break;
|
|
|
|
case VIATYPE::NOT_DEFINED: m_ViaTypeChoice->SetSelection( wxNOT_FOUND ); break;
|
2018-08-19 17:11:58 +01:00
|
|
|
}
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2019-12-28 00:55:11 +00:00
|
|
|
m_ViaStartLayer->Enable( viaType != VIATYPE::THROUGH );
|
|
|
|
m_ViaEndLayer->Enable( viaType != VIATYPE::THROUGH );
|
2022-11-24 18:05:37 +00:00
|
|
|
|
|
|
|
m_annularRingsLabel->Show( getLayerDepth() > 1 );
|
|
|
|
m_annularRingsCtrl->Show( getLayerDepth() > 1 );
|
2024-11-02 10:02:17 -04:00
|
|
|
|
|
|
|
afterPadstackModeChanged();
|
2015-07-15 14:08:50 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-06 15:35:25 +00:00
|
|
|
m_viaNotFree->Hide();
|
2015-08-18 18:15:57 +02:00
|
|
|
m_MainSizer->Hide( m_sbViaSizer, true );
|
2015-07-15 14:08:50 +02:00
|
|
|
}
|
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
if( m_tracks )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
int widthSelection = wxNOT_FOUND;
|
2017-08-25 16:46:49 +02:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
// 0 is the netclass place-holder
|
|
|
|
for( unsigned ii = 1; ii < aParent->GetDesignSettings().m_TrackWidthList.size(); ii++ )
|
|
|
|
{
|
|
|
|
int width = aParent->GetDesignSettings().m_TrackWidthList[ii];
|
|
|
|
wxString msg = m_frame->StringFromValue( width );
|
|
|
|
m_predefinedTrackWidthsCtrl->Append( msg );
|
2023-11-18 12:17:44 +00:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
if( widthSelection == wxNOT_FOUND && m_trackWidth.GetValue() == width )
|
|
|
|
widthSelection = ii - 1;
|
2023-11-18 12:17:44 +00:00
|
|
|
}
|
2023-12-13 14:14:34 +00:00
|
|
|
|
|
|
|
m_predefinedTrackWidthsCtrl->SetSelection( widthSelection );
|
|
|
|
m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
|
2024-09-29 13:25:21 +02:00
|
|
|
|
|
|
|
wxCommandEvent event;
|
|
|
|
onTrackEdit( event );
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-08-18 18:15:57 +02:00
|
|
|
m_MainSizer->Hide( m_sbTrackSizer, true );
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
|
2016-08-15 17:16:53 +02:00
|
|
|
if( hasLocked && hasUnlocked )
|
2016-08-15 17:16:48 +02:00
|
|
|
m_lockedCbox->Set3StateValue( wxCHK_UNDETERMINED );
|
2016-08-15 17:16:53 +02:00
|
|
|
else if( hasLocked )
|
2016-08-15 17:16:48 +02:00
|
|
|
m_lockedCbox->Set3StateValue( wxCHK_CHECKED );
|
|
|
|
else
|
|
|
|
m_lockedCbox->Set3StateValue( wxCHK_UNCHECKED );
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2021-11-15 13:02:18 +00:00
|
|
|
if( m_tracks )
|
|
|
|
SetInitialFocus( m_TrackWidthCtrl );
|
|
|
|
else if( m_netSelector->IsEnabled() )
|
|
|
|
SetInitialFocus( m_netSelector );
|
|
|
|
else
|
|
|
|
SetInitialFocus( m_ViaDiameterCtrl );
|
2018-03-06 05:33:04 +00:00
|
|
|
|
2021-11-16 19:39:58 +00:00
|
|
|
SetupStandardButtons();
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2023-03-13 12:03:48 -04:00
|
|
|
m_frame->Bind( EDA_EVT_UNITS_CHANGED, &DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged, this );
|
2024-10-27 02:53:25 +08:00
|
|
|
m_netSelector->Bind( FILTERED_ITEM_SELECTED, &DIALOG_TRACK_VIA_PROPERTIES::onNetSelector, this );
|
2021-12-23 13:11:26 +00:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
// Now all widgets have the size fixed, call FinishDialogSettings
|
2020-11-16 11:16:44 +00:00
|
|
|
finishDialogSettings();
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-23 13:11:26 +00:00
|
|
|
DIALOG_TRACK_VIA_PROPERTIES::~DIALOG_TRACK_VIA_PROPERTIES()
|
|
|
|
{
|
2023-03-13 12:03:48 -04:00
|
|
|
m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged, this );
|
2021-12-23 13:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onUnitsChanged( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
if( m_vias )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
int viaSel = m_predefinedViaSizesCtrl->GetSelection();
|
2021-12-23 13:11:26 +00:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedViaSizesCtrl->Clear();
|
2021-12-23 13:11:26 +00:00
|
|
|
|
|
|
|
// 0 is the netclass place-holder
|
|
|
|
for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_ViasDimensionsList.size(); ii++ )
|
|
|
|
{
|
|
|
|
VIA_DIMENSION* viaDimension = &m_frame->GetDesignSettings().m_ViasDimensionsList[ii];
|
2022-09-19 10:25:20 +01:00
|
|
|
wxString msg = m_frame->StringFromValue( viaDimension->m_Diameter )
|
|
|
|
+ wxT( " / " )
|
|
|
|
+ m_frame->StringFromValue( viaDimension->m_Drill );
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedViaSizesCtrl->Append( msg, viaDimension );
|
2021-12-23 13:11:26 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedViaSizesCtrl->SetSelection( viaSel );
|
|
|
|
m_predefinedViaSizesUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
|
2021-12-23 13:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( m_tracks )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
int trackSel = m_predefinedTrackWidthsCtrl->GetSelection();
|
2021-12-23 13:11:26 +00:00
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedTrackWidthsCtrl->Clear();
|
2021-12-23 13:11:26 +00:00
|
|
|
|
|
|
|
// 0 is the netclass place-holder
|
|
|
|
for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ii++ )
|
|
|
|
{
|
2022-09-19 10:25:20 +01:00
|
|
|
int width = m_frame->GetDesignSettings().m_TrackWidthList[ii];
|
|
|
|
wxString msg = m_frame->StringFromValue( width );
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedTrackWidthsCtrl->Append( msg );
|
2021-12-23 13:11:26 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedTrackWidthsCtrl->SetSelection( trackSel );
|
|
|
|
m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
|
2021-12-23 13:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
bool DIALOG_TRACK_VIA_PROPERTIES::confirmShortingNets( int aNet, const std::set<int>& shortingNets )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
if( shortingNets.size() == 1 )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Applying these changes will short net %s with %s." ),
|
|
|
|
m_netSelector->GetValue(),
|
|
|
|
m_frame->GetBoard()->FindNet( *shortingNets.begin() )->GetNetname() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Applying these changes will short net %s with other nets." ),
|
|
|
|
m_netSelector->GetValue() );
|
|
|
|
}
|
|
|
|
|
|
|
|
KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
|
|
|
|
dlg.SetOKCancelLabels( _( "Apply Anyway" ), _( "Cancel Changes" ) );
|
|
|
|
dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
|
|
|
|
|
|
|
|
return dlg.ShowModal() == wxID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-25 17:07:59 +00:00
|
|
|
bool DIALOG_TRACK_VIA_PROPERTIES::confirmPadChange( const std::set<PAD*>& changingPads )
|
2018-08-19 17:11:58 +01:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
2018-08-29 22:42:10 +01:00
|
|
|
if( changingPads.size() == 1 )
|
2018-08-19 17:11:58 +01:00
|
|
|
{
|
2020-11-12 22:30:02 +00:00
|
|
|
PAD* pad = *changingPads.begin();
|
2020-12-27 16:35:07 +00:00
|
|
|
msg.Printf( _( "Changing the net will also update %s pad %s to %s." ),
|
2023-06-24 19:54:50 +01:00
|
|
|
pad->GetParentFootprint()->GetReference(),
|
2021-08-24 00:10:21 +01:00
|
|
|
pad->GetNumber(),
|
2018-08-19 17:11:58 +01:00
|
|
|
m_netSelector->GetValue() );
|
|
|
|
}
|
2018-08-29 22:42:10 +01:00
|
|
|
else if( changingPads.size() == 2 )
|
2018-08-19 17:11:58 +01:00
|
|
|
{
|
2020-11-12 22:30:02 +00:00
|
|
|
PAD* pad1 = *changingPads.begin();
|
|
|
|
PAD* pad2 = *( ++changingPads.begin() );
|
2020-12-27 16:35:07 +00:00
|
|
|
msg.Printf( _( "Changing the net will also update %s pad %s and %s pad %s to %s." ),
|
2023-06-24 19:54:50 +01:00
|
|
|
pad1->GetParentFootprint()->GetReference(),
|
2021-08-24 00:10:21 +01:00
|
|
|
pad1->GetNumber(),
|
2023-06-24 19:54:50 +01:00
|
|
|
pad2->GetParentFootprint()->GetReference(),
|
2021-08-24 00:10:21 +01:00
|
|
|
pad2->GetNumber(),
|
2018-08-19 17:11:58 +01:00
|
|
|
m_netSelector->GetValue() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-27 16:35:07 +00:00
|
|
|
msg.Printf( _( "Changing the net will also update %lu connected pads to %s." ),
|
2019-06-23 16:40:24 -07:00
|
|
|
static_cast<unsigned long>( changingPads.size() ),
|
2018-08-19 17:11:58 +01:00
|
|
|
m_netSelector->GetValue() );
|
|
|
|
}
|
|
|
|
|
|
|
|
KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
|
2020-12-27 16:35:07 +00:00
|
|
|
dlg.SetOKCancelLabels( _( "Change Nets" ), _( "Leave Nets Unchanged" ) );
|
2018-08-29 23:37:20 +01:00
|
|
|
dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
|
2018-08-19 17:11:58 +01:00
|
|
|
|
|
|
|
return dlg.ShowModal() == wxID_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
2025-04-13 18:17:32 +01:00
|
|
|
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_frame->GetBoard()->GetConnectivity();
|
|
|
|
std::vector<PCB_TRACK*> selected_tracks;
|
|
|
|
std::set<PCB_TRACK*> connected_tracks;
|
2025-02-25 17:07:59 +00:00
|
|
|
|
|
|
|
for( EDA_ITEM* item : m_items )
|
|
|
|
{
|
|
|
|
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
|
2025-02-26 10:55:19 +00:00
|
|
|
selected_tracks.push_back( track );
|
2025-02-25 17:07:59 +00:00
|
|
|
}
|
|
|
|
|
2025-04-13 18:17:32 +01:00
|
|
|
for( PCB_TRACK* selected_track : selected_tracks )
|
|
|
|
{
|
|
|
|
for( BOARD_CONNECTED_ITEM* connected_item : connectivity->GetConnectedItems( selected_track ) )
|
|
|
|
{
|
|
|
|
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( connected_item ) )
|
|
|
|
connected_tracks.insert( track );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-24 18:05:37 +00:00
|
|
|
// Check for malformed data ONLY; design rules and constraints are the business of DRC.
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2018-08-19 17:11:58 +01:00
|
|
|
if( m_vias )
|
|
|
|
{
|
2024-11-02 10:02:17 -04:00
|
|
|
// TODO: This needs to move into the via class, not the dialog
|
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
if( !m_viaDiameter.Validate( GEOMETRY_MIN_SIZE, INT_MAX )
|
|
|
|
|| !m_viaDrill.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) )
|
2023-05-12 22:03:54 +01:00
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
return false;
|
2023-05-12 22:03:54 +01:00
|
|
|
}
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2018-09-01 00:44:00 +01:00
|
|
|
if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate()
|
|
|
|
&& m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate()
|
|
|
|
&& m_viaDiameter.GetValue() <= m_viaDrill.GetValue() )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2021-01-11 13:46:00 +00:00
|
|
|
DisplayError( GetParent(), _( "Via hole size must be smaller than via diameter" ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
m_ViaDrillCtrl->SelectAll();
|
|
|
|
m_ViaDrillCtrl->SetFocus();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-20 20:26:50 +01:00
|
|
|
if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER &&
|
|
|
|
m_ViaStartLayer->GetLayerSelection() == m_ViaEndLayer->GetLayerSelection() )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
|
|
|
DisplayError( GetParent(), _( "Via start layer and end layer cannot be the same" ) );
|
|
|
|
return false;
|
|
|
|
}
|
2024-11-02 10:02:17 -04:00
|
|
|
|
|
|
|
if( !m_viaDiameter.IsIndeterminate() )
|
|
|
|
{
|
|
|
|
int diameter = m_viaDiameter.GetValue();
|
|
|
|
m_viaStack->SetSize( { diameter, diameter }, m_editLayer );
|
|
|
|
}
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( m_tracks )
|
|
|
|
{
|
2018-11-29 18:59:38 +00:00
|
|
|
if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) )
|
2018-02-03 09:09:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we survived that, then save the changes:
|
2020-12-27 16:35:07 +00:00
|
|
|
//
|
|
|
|
// We don't bother with updating the nets at this point as it will be useless (any connected
|
|
|
|
// pads will simply drive their existing nets back onto the track segments and vias).
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2023-06-27 16:52:50 +01:00
|
|
|
BOARD_COMMIT commit( m_frame );
|
|
|
|
bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED;
|
|
|
|
bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED;
|
2016-08-15 17:16:48 +02:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
for( PCB_TRACK* track : selected_tracks )
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
2025-02-25 17:07:59 +00:00
|
|
|
commit.Modify( track );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2025-02-25 17:07:59 +00:00
|
|
|
switch( track->Type() )
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
|
|
|
case PCB_TRACE_T:
|
2019-05-16 17:13:21 -07:00
|
|
|
case PCB_ARC_T:
|
2015-07-09 13:35:51 +02:00
|
|
|
{
|
2017-08-11 11:38:06 +02:00
|
|
|
wxASSERT( m_tracks );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( !m_trackStartX.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetStartX( m_trackStartX.GetIntValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( !m_trackStartY.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetStartY( m_trackStartY.GetIntValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( !m_trackEndX.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetEndX( m_trackEndX.GetIntValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
if( !m_trackEndY.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetEndY( m_trackEndY.GetIntValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-03-12 22:28:44 +00:00
|
|
|
if( !m_trackWidth.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetWidth( m_trackWidth.GetIntValue() );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2021-07-22 00:14:56 +01:00
|
|
|
int layer = m_TrackLayerCtrl->GetLayerSelection();
|
2015-07-09 13:35:51 +02:00
|
|
|
|
|
|
|
if( layer != UNDEFINED_LAYER )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetLayer( (PCB_LAYER_ID) layer );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2024-09-29 13:25:21 +02:00
|
|
|
if ( m_trackHasSolderMask->Get3StateValue() != wxCHK_UNDETERMINED )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetHasSolderMask( m_trackHasSolderMask->GetValue() );
|
2024-09-29 13:25:21 +02:00
|
|
|
|
|
|
|
if( !m_trackMaskMargin.IsIndeterminate() )
|
|
|
|
{
|
|
|
|
if( m_trackMaskMargin.IsNull() )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetLocalSolderMaskMargin( {} );
|
2024-09-29 13:25:21 +02:00
|
|
|
else
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetLocalSolderMaskMargin( m_trackMaskMargin.GetIntValue() );
|
2024-09-29 13:25:21 +02:00
|
|
|
}
|
|
|
|
|
2016-08-15 17:16:48 +02:00
|
|
|
if( changeLock )
|
2025-02-25 17:07:59 +00:00
|
|
|
track->SetLocked( setLock );
|
2016-08-15 17:16:48 +02:00
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PCB_VIA_T:
|
|
|
|
{
|
2017-08-11 11:38:06 +02:00
|
|
|
wxASSERT( m_vias );
|
2025-02-25 17:07:59 +00:00
|
|
|
PCB_VIA* via = static_cast<PCB_VIA*>( track );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2018-07-21 14:04:30 +01:00
|
|
|
if( !m_viaX.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetPosition( VECTOR2I( m_viaX.GetIntValue(), via->GetPosition().y ) );
|
2018-07-21 14:04:30 +01:00
|
|
|
|
|
|
|
if( !m_viaY.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetPosition( VECTOR2I( via->GetPosition().x, m_viaY.GetIntValue() ) );
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2020-12-20 16:29:43 -05:00
|
|
|
if( m_viaNotFree->Get3StateValue() != wxCHK_UNDETERMINED )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetIsFree( !m_viaNotFree->GetValue() );
|
2020-12-20 16:29:43 -05:00
|
|
|
|
2024-12-30 11:35:55 -05:00
|
|
|
if( !m_viaDiameter.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetPadstack( *m_viaStack );
|
2024-12-30 11:35:55 -05:00
|
|
|
|
2020-03-01 19:29:41 +00:00
|
|
|
switch( m_ViaTypeChoice->GetSelection() )
|
2018-01-06 23:32:22 +01:00
|
|
|
{
|
2025-04-13 18:16:07 +01:00
|
|
|
case 0: via->SetViaType( VIATYPE::THROUGH ); break;
|
|
|
|
case 1: via->SetViaType( VIATYPE::MICROVIA ); break;
|
|
|
|
case 2: via->SetViaType( VIATYPE::BLIND_BURIED ); break;
|
|
|
|
default: break;
|
2018-01-06 23:32:22 +01:00
|
|
|
}
|
|
|
|
|
2024-12-08 15:53:13 +01:00
|
|
|
PCB_LAYER_ID startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() );
|
|
|
|
PCB_LAYER_ID endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() );
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2024-12-30 11:35:55 -05:00
|
|
|
if( startLayer != UNDEFINED_LAYER )
|
2024-12-08 15:53:13 +01:00
|
|
|
{
|
|
|
|
m_viaStack->Drill().start = startLayer;
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetTopLayer( startLayer );
|
2024-12-08 15:53:13 +01:00
|
|
|
}
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2024-12-30 11:35:55 -05:00
|
|
|
if( endLayer != UNDEFINED_LAYER )
|
2024-12-08 15:53:13 +01:00
|
|
|
{
|
|
|
|
m_viaStack->Drill().end = endLayer;
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetBottomLayer( endLayer );
|
2024-12-08 15:53:13 +01:00
|
|
|
}
|
2018-01-06 23:32:22 +01:00
|
|
|
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SanitizeLayers();
|
2024-12-30 11:35:55 -05:00
|
|
|
|
2021-08-14 01:44:23 +01:00
|
|
|
switch( m_annularRingsCtrl->GetSelection() )
|
|
|
|
{
|
|
|
|
case 0:
|
2025-02-25 17:07:59 +00:00
|
|
|
via->Padstack().SetUnconnectedLayerMode(
|
2024-04-08 09:09:20 -04:00
|
|
|
PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
2021-08-14 01:44:23 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2025-02-25 17:07:59 +00:00
|
|
|
via->Padstack().SetUnconnectedLayerMode(
|
2024-04-08 09:09:20 -04:00
|
|
|
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
|
2021-08-14 01:44:23 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2025-02-25 17:07:59 +00:00
|
|
|
via->Padstack().SetUnconnectedLayerMode(
|
2024-04-08 09:09:20 -04:00
|
|
|
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
2021-08-14 01:44:23 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-06-09 12:44:30 -04:00
|
|
|
|
2024-03-12 22:28:44 +00:00
|
|
|
if( !m_viaDrill.IsIndeterminate() )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetDrill( m_viaDrill.GetIntValue() );
|
2023-05-12 22:03:54 +01:00
|
|
|
|
2025-02-25 17:07:59 +00:00
|
|
|
TEARDROP_PARAMETERS* targetParams = &via->GetTeardropParams();
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( m_cbTeardrops->Get3StateValue() != wxCHK_UNDETERMINED )
|
|
|
|
targetParams->m_Enabled = m_cbTeardrops->GetValue();
|
|
|
|
|
|
|
|
if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
|
|
|
|
targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
|
|
|
|
|
|
|
|
if( !m_teardropMaxLen.IsIndeterminate() )
|
|
|
|
targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
|
|
|
|
|
2024-02-23 14:38:22 +00:00
|
|
|
if( !m_teardropMaxWidth.IsIndeterminate() )
|
|
|
|
targetParams->m_TdMaxWidth = m_teardropMaxWidth.GetIntValue();
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( !m_teardropLenPercent.IsIndeterminate() )
|
|
|
|
targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
|
|
|
|
|
2024-02-23 14:38:22 +00:00
|
|
|
if( !m_teardropWidthPercent.IsIndeterminate() )
|
|
|
|
targetParams->m_BestWidthRatio =
|
|
|
|
m_teardropWidthPercent.GetDoubleValue() / 100.0;
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
if( !m_teardropHDPercent.IsIndeterminate() )
|
|
|
|
targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
|
|
|
|
|
2023-05-23 17:45:26 +01:00
|
|
|
if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
|
2024-12-28 22:38:18 +00:00
|
|
|
targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
|
2017-07-03 19:14:35 +02:00
|
|
|
|
2016-08-15 17:16:48 +02:00
|
|
|
if( changeLock )
|
2025-02-25 17:07:59 +00:00
|
|
|
via->SetLocked( setLock );
|
2016-08-15 17:16:48 +02:00
|
|
|
|
2025-04-13 18:16:07 +01:00
|
|
|
auto setSurfaceProtection =
|
|
|
|
[&]( std::optional<bool>& aFront, std::optional<bool>& aBack, IPC4761_SURFACE aProtection )
|
|
|
|
{
|
|
|
|
switch( aProtection )
|
|
|
|
{
|
|
|
|
case IPC4761_SURFACE::FROM_RULES:
|
|
|
|
aFront.reset();
|
|
|
|
aBack.reset();
|
|
|
|
break;
|
|
|
|
case IPC4761_SURFACE::NONE:
|
|
|
|
aFront = false;
|
|
|
|
aBack = false;
|
|
|
|
break;
|
|
|
|
case IPC4761_SURFACE::FRONT:
|
|
|
|
aFront = true;
|
|
|
|
aBack = false;
|
|
|
|
break;
|
|
|
|
case IPC4761_SURFACE::BACK:
|
|
|
|
aFront = false;
|
|
|
|
aBack = true;
|
|
|
|
break;
|
|
|
|
case IPC4761_SURFACE::BOTH:
|
|
|
|
aFront = true;
|
|
|
|
aBack = true;
|
|
|
|
break;
|
|
|
|
case IPC4761_SURFACE::CUSTOM: return;
|
|
|
|
}
|
|
|
|
};
|
2025-03-01 18:02:54 +00:00
|
|
|
|
|
|
|
auto setDrillProtection =
|
|
|
|
[&]( std::optional<bool>& aDrill, IPC4761_DRILL aProtection )
|
2025-04-13 18:16:07 +01:00
|
|
|
{
|
|
|
|
switch( aProtection )
|
|
|
|
{
|
|
|
|
case IPC4761_DRILL::FROM_RULES: aDrill.reset(); break;
|
|
|
|
case IPC4761_DRILL::NOT_SET: aDrill = false; break;
|
|
|
|
case IPC4761_DRILL::SET: aDrill = true; break;
|
|
|
|
}
|
|
|
|
};
|
2025-03-01 18:02:54 +00:00
|
|
|
|
2025-04-13 18:16:07 +01:00
|
|
|
IPC4761_PRESET selectedPreset = static_cast<IPC4761_PRESET>( m_protectionFeatures->GetSelection() );
|
2025-03-01 18:02:54 +00:00
|
|
|
|
|
|
|
if( selectedPreset < IPC4761_PRESET::CUSTOM ) // Do not change custom feaure list.
|
|
|
|
{
|
|
|
|
const IPC4761_CONFIGURATION config = m_IPC4761Presets.at( selectedPreset );
|
|
|
|
|
|
|
|
setSurfaceProtection( via->Padstack().FrontOuterLayers().has_solder_mask,
|
|
|
|
via->Padstack().BackOuterLayers().has_solder_mask,
|
|
|
|
config.tent );
|
|
|
|
|
|
|
|
setSurfaceProtection( via->Padstack().FrontOuterLayers().has_plugging,
|
|
|
|
via->Padstack().BackOuterLayers().has_plugging,
|
|
|
|
config.plug );
|
|
|
|
|
|
|
|
setSurfaceProtection( via->Padstack().FrontOuterLayers().has_covering,
|
|
|
|
via->Padstack().BackOuterLayers().has_covering,
|
|
|
|
config.cover );
|
|
|
|
|
|
|
|
setDrillProtection( via->Padstack().Drill().is_filled, config.fill );
|
|
|
|
|
|
|
|
setDrillProtection( via->Padstack().Drill().is_capped, config.cap );
|
|
|
|
}
|
|
|
|
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2025-07-07 20:23:49 +01:00
|
|
|
UNIMPLEMENTED_FOR( track->GetClass() );
|
2015-07-09 13:35:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
std::set<int> shortingNets;
|
2025-02-25 17:07:59 +00:00
|
|
|
int newNetCode = m_netSelector->GetSelectedNetcode();
|
|
|
|
std::set<PAD*> changingPads;
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
// Do NOT use the connectivity code here. It will propagate through zones, and we haven't
|
|
|
|
// refilled those yet so it's going to pick up a whole bunch of other nets any time the track
|
|
|
|
// width was increased.
|
|
|
|
auto collide =
|
|
|
|
[&]( BOARD_CONNECTED_ITEM* a, BOARD_CONNECTED_ITEM* b )
|
|
|
|
{
|
2025-07-14 19:12:44 +01:00
|
|
|
for( PCB_LAYER_ID layer : LSET( a->GetLayerSet() & b->GetLayerSet() ) )
|
2025-02-26 10:55:19 +00:00
|
|
|
{
|
|
|
|
if( a->GetEffectiveShape( layer )->Collide( b->GetEffectiveShape( layer ).get() ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-04-13 18:17:32 +01:00
|
|
|
for( PCB_TRACK* track : connected_tracks )
|
2025-02-26 10:55:19 +00:00
|
|
|
{
|
|
|
|
for( PCB_TRACK* other : m_frame->GetBoard()->Tracks() )
|
2020-12-27 16:35:07 +00:00
|
|
|
{
|
2025-02-26 10:55:19 +00:00
|
|
|
if( other->GetNetCode() == track->GetNetCode() || other->GetNetCode() == newNetCode )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( collide( track, other ) )
|
|
|
|
shortingNets.insert( other->GetNetCode() );
|
|
|
|
}
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
|
|
|
|
{
|
|
|
|
for( PAD* pad : footprint->Pads() )
|
2020-12-27 16:35:07 +00:00
|
|
|
{
|
2025-02-26 10:55:19 +00:00
|
|
|
if( pad->GetNetCode() == newNetCode )
|
|
|
|
continue;
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
if( collide( track, pad ) )
|
|
|
|
{
|
|
|
|
if( pad->GetNetCode() == track->GetNetCode() )
|
2025-02-25 17:07:59 +00:00
|
|
|
changingPads.insert( pad );
|
2025-02-26 10:55:19 +00:00
|
|
|
else
|
|
|
|
shortingNets.insert( pad->GetNetCode() );
|
2020-12-27 16:35:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
if( shortingNets.size() && !confirmShortingNets( newNetCode, shortingNets ) )
|
|
|
|
{
|
|
|
|
commit.Revert();
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
if( !m_netSelector->IsIndeterminate() )
|
2020-12-27 16:35:07 +00:00
|
|
|
{
|
2025-02-26 10:55:19 +00:00
|
|
|
if( changingPads.empty() || confirmPadChange( changingPads ) )
|
2020-12-27 16:35:07 +00:00
|
|
|
{
|
2025-02-26 10:55:19 +00:00
|
|
|
for( PCB_TRACK* track : selected_tracks )
|
|
|
|
track->SetNetCode( newNetCode );
|
2020-12-27 16:35:07 +00:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
for( PAD* pad : changingPads )
|
2020-12-27 16:35:07 +00:00
|
|
|
{
|
2025-02-26 10:55:19 +00:00
|
|
|
commit.Modify( pad );
|
|
|
|
pad->SetNetCode( newNetCode );
|
2020-12-27 16:35:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-09 13:35:51 +02:00
|
|
|
|
2025-02-26 10:55:19 +00:00
|
|
|
commit.Push( _( "Edit Track/Via Properties" ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
return true;
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-09-20 11:36:44 +01:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onNetSelector( wxCommandEvent& aEvent )
|
2021-01-06 15:35:25 +00:00
|
|
|
{
|
2022-09-20 11:36:44 +01:00
|
|
|
m_viaNotFree->SetValue( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onViaNotFreeClicked( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
if( !m_tracks )
|
|
|
|
{
|
|
|
|
m_netSelectorLabel->Enable( !m_viaNotFree->GetValue() );
|
|
|
|
m_netSelector->Enable( !m_viaNotFree->GetValue() );
|
|
|
|
}
|
2021-01-06 15:35:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-16 20:58:24 +01:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onWidthSelect( wxCommandEvent& aEvent )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
m_TrackWidthCtrl->ChangeValue( m_predefinedTrackWidthsCtrl->GetStringSelection() );
|
2019-08-25 11:06:01 +01:00
|
|
|
m_TrackWidthCtrl->SelectAll();
|
2018-08-16 20:58:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onWidthEdit( wxCommandEvent& aEvent )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedTrackWidthsCtrl->SetStringSelection( m_TrackWidthCtrl->GetValue() );
|
2018-08-16 20:58:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-18 10:28:08 +02:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onViaSelect( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
VIA_DIMENSION* viaDimension = static_cast<VIA_DIMENSION*> ( aEvent.GetClientData() );
|
|
|
|
|
2018-10-09 19:11:19 +01:00
|
|
|
m_viaDiameter.ChangeValue( viaDimension->m_Diameter );
|
|
|
|
m_viaDrill.ChangeValue( viaDimension->m_Drill );
|
2017-09-18 10:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-11-02 10:02:17 -04:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onPadstackModeChanged( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onPadstackModeChanged" );
|
|
|
|
|
|
|
|
switch( m_cbPadstackMode->GetSelection() )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case 0: m_viaStack->SetMode( PADSTACK::MODE::NORMAL ); break;
|
|
|
|
case 1: m_viaStack->SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
|
|
|
|
case 2: m_viaStack->SetMode( PADSTACK::MODE::CUSTOM ); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
afterPadstackModeChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onEditLayerChanged( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in onEditLayerChanged" );
|
|
|
|
|
|
|
|
// Save data from the previous layer
|
|
|
|
if( !m_viaDiameter.IsIndeterminate() )
|
|
|
|
{
|
|
|
|
int diameter = m_viaDiameter.GetValue();
|
|
|
|
m_viaStack->SetSize( { diameter, diameter }, m_editLayer );
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( m_viaStack->Mode() )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case PADSTACK::MODE::NORMAL:
|
|
|
|
m_editLayer = PADSTACK::ALL_LAYERS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PADSTACK::MODE::FRONT_INNER_BACK:
|
|
|
|
switch( m_cbEditLayer->GetSelection() )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case 0: m_editLayer = F_Cu; break;
|
|
|
|
case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
|
|
|
|
case 2: m_editLayer = B_Cu; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PADSTACK::MODE::CUSTOM:
|
|
|
|
{
|
|
|
|
int layer = m_cbEditLayer->GetSelection();
|
|
|
|
|
|
|
|
if( layer < 0 )
|
|
|
|
layer = 0;
|
|
|
|
|
|
|
|
if( m_editLayerCtrlMap.contains( layer ) )
|
|
|
|
m_editLayer = m_editLayerCtrlMap.at( layer );
|
|
|
|
else
|
|
|
|
m_editLayer = F_Cu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load controls with the current layer
|
|
|
|
m_viaDiameter.SetValue( m_viaStack->Size( m_editLayer ).x );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::afterPadstackModeChanged()
|
|
|
|
{
|
|
|
|
// NOTE: synchronize changes here with DIALOG_PAD_PROPERTIES::afterPadstackModeChanged
|
|
|
|
|
|
|
|
wxCHECK_MSG( m_viaStack, /* void */, "Expected valid via stack in afterPadstackModeChanged" );
|
|
|
|
m_cbEditLayer->Clear();
|
|
|
|
|
|
|
|
BOARD* board = m_frame->GetBoard();
|
|
|
|
|
|
|
|
switch( m_viaStack->Mode() )
|
|
|
|
{
|
|
|
|
case PADSTACK::MODE::NORMAL:
|
|
|
|
m_cbPadstackMode->SetSelection( 0 );
|
|
|
|
m_cbEditLayer->Append( _( "All layers" ) );
|
|
|
|
m_cbEditLayer->Disable();
|
|
|
|
m_editLayer = PADSTACK::ALL_LAYERS;
|
|
|
|
m_editLayerCtrlMap = { { 0, PADSTACK::ALL_LAYERS } };
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PADSTACK::MODE::FRONT_INNER_BACK:
|
|
|
|
{
|
|
|
|
m_cbPadstackMode->SetSelection( 1 );
|
|
|
|
m_cbEditLayer->Enable();
|
|
|
|
|
|
|
|
std::vector choices = {
|
|
|
|
board->GetLayerName( F_Cu ),
|
|
|
|
_( "Inner Layers" ),
|
|
|
|
board->GetLayerName( B_Cu )
|
|
|
|
};
|
|
|
|
|
|
|
|
m_cbEditLayer->Append( choices );
|
|
|
|
|
|
|
|
m_editLayerCtrlMap = {
|
|
|
|
{ 0, F_Cu },
|
|
|
|
{ 1, PADSTACK::INNER_LAYERS },
|
|
|
|
{ 2, B_Cu }
|
|
|
|
};
|
|
|
|
|
|
|
|
if( m_editLayer != F_Cu && m_editLayer != B_Cu )
|
|
|
|
m_editLayer = PADSTACK::INNER_LAYERS;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PADSTACK::MODE::CUSTOM:
|
|
|
|
{
|
|
|
|
m_cbPadstackMode->SetSelection( 2 );
|
|
|
|
m_cbEditLayer->Enable();
|
|
|
|
LSET layers = LSET::AllCuMask() & board->GetEnabledLayers();
|
|
|
|
|
|
|
|
for( PCB_LAYER_ID layer : layers.UIOrder() )
|
|
|
|
{
|
|
|
|
int idx = m_cbEditLayer->Append( board->GetLayerName( layer ) );
|
|
|
|
m_editLayerCtrlMap[idx] = layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( const auto& [idx, layer] : m_editLayerCtrlMap )
|
|
|
|
{
|
|
|
|
if( layer == m_editLayer )
|
|
|
|
{
|
|
|
|
m_cbEditLayer->SetSelection( idx );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-11-24 18:05:37 +00:00
|
|
|
int DIALOG_TRACK_VIA_PROPERTIES::getLayerDepth()
|
|
|
|
{
|
|
|
|
int viaType = m_ViaTypeChoice->GetSelection();
|
|
|
|
|
|
|
|
if( viaType <= 0 )
|
|
|
|
return m_frame->GetBoard()->GetCopperLayerCount() - 1;
|
|
|
|
|
|
|
|
int startLayer = m_ViaStartLayer->GetLayerSelection();
|
|
|
|
int endLayer = m_ViaEndLayer->GetLayerSelection();
|
|
|
|
|
|
|
|
if( startLayer < 0 || endLayer < 0 )
|
|
|
|
return m_frame->GetBoard()->GetCopperLayerCount() - 1;
|
|
|
|
else
|
|
|
|
return m_frame->GetBoard()->LayerDepth( ToLAYER_ID( startLayer ), ToLAYER_ID( endLayer ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-18 10:28:08 +02:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
|
|
|
|
{
|
2023-12-13 14:14:34 +00:00
|
|
|
m_predefinedViaSizesCtrl->SetSelection( wxNOT_FOUND );
|
2018-01-06 23:32:22 +01:00
|
|
|
|
|
|
|
if( m_vias )
|
|
|
|
{
|
2021-06-09 19:32:58 +00:00
|
|
|
if( m_ViaTypeChoice->GetSelection() != 0 ) // check if selected type isn't through.
|
2018-01-06 23:32:22 +01:00
|
|
|
{
|
|
|
|
m_ViaStartLayer->Enable();
|
|
|
|
m_ViaEndLayer->Enable();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_ViaStartLayer->SetLayerSelection( F_Cu );
|
|
|
|
m_ViaEndLayer->SetLayerSelection( B_Cu );
|
|
|
|
|
|
|
|
m_ViaStartLayer->Enable( false );
|
|
|
|
m_ViaEndLayer->Enable( false );
|
|
|
|
}
|
2022-11-24 18:05:37 +00:00
|
|
|
|
|
|
|
m_annularRingsLabel->Show( getLayerDepth() > 1 );
|
|
|
|
m_annularRingsCtrl->Show( getLayerDepth() > 1 );
|
2018-01-06 23:32:22 +01:00
|
|
|
}
|
2015-07-09 13:35:51 +02:00
|
|
|
}
|
2023-05-12 22:03:54 +01:00
|
|
|
|
|
|
|
|
2024-09-29 13:25:21 +02:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onTrackEdit( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
bool externalCuLayer = m_TrackLayerCtrl->GetLayerSelection() == F_Cu
|
|
|
|
|| m_TrackLayerCtrl->GetLayerSelection() == B_Cu;
|
|
|
|
|
|
|
|
m_techLayersLabel->Enable( externalCuLayer );
|
|
|
|
m_trackHasSolderMask->Enable( externalCuLayer );
|
|
|
|
|
|
|
|
bool showMaskMargin = externalCuLayer && m_trackHasSolderMask->GetValue();
|
|
|
|
|
|
|
|
m_trackMaskMarginCtrl->Enable( showMaskMargin );
|
|
|
|
m_trackMaskMarginLabel->Enable( showMaskMargin );
|
|
|
|
m_trackMaskMarginUnit->Enable( showMaskMargin );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-12 22:03:54 +01:00
|
|
|
void DIALOG_TRACK_VIA_PROPERTIES::onTeardropsUpdateUi( wxUpdateUIEvent& event )
|
|
|
|
{
|
|
|
|
event.Enable( !m_frame->GetBoard()->LegacyTeardrops() );
|
|
|
|
}
|
|
|
|
|