KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_zone_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) 2023 Ethan Chien <[email protected]>
5 * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
6 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
28
29#include <grid_tricks.h>
30#include <wx/radiobut.h>
31#include <kiface_base.h>
32#include <confirm.h>
33#include <pcb_edit_frame.h>
34#include <pcbnew_settings.h>
35#include <wx/string.h>
36#include <widgets/unit_binder.h>
38#include <widgets/wx_grid.h>
39#include <pad.h>
41
43
44
45wxDEFINE_EVENT( EVT_ZONE_NAME_UPDATE, wxCommandEvent );
46wxDEFINE_EVENT( EVT_ZONE_NET_UPDATE, wxCommandEvent );
47
49 ZONES_CONTAINER& aZoneContainer ) :
51 m_ZoneContainer( aZoneContainer ),
62{
63 m_Parent = aFrame;
64
65 m_netSelector->SetNetInfo( &m_Parent->GetBoard()->GetNetInfo() );
66
68 [&]() -> LSET
69 {
70 return m_settings->m_Layers;
71 } );
72
75 m_layerSpecificOverrides->SetSelectionMode( wxGrid::wxGridSelectRows );
76
77 wxGridCellAttr* attr = new wxGridCellAttr;
78 attr->SetRenderer( new GRID_CELL_LAYER_RENDERER( nullptr ) );
79 LSET forbiddenLayers = LSET::AllNonCuMask();
80
81 for( PCB_LAYER_ID copper : LSET::AllCuMask() )
82 {
83 if( !m_Parent->GetBoard()->IsLayerEnabled( copper ) )
84 forbiddenLayers.set( copper );
85 }
86
87 attr->SetEditor( new GRID_CELL_LAYER_SELECTOR( nullptr, forbiddenLayers ) );
88 m_layerSpecificOverrides->SetColAttr( 0, attr );
89 m_layerSpecificOverrides->SetupColumnAutosizer( 0 );
90
93
94 m_netSelector->Bind( FILTERED_ITEM_SELECTED, &PANEL_ZONE_PROPERTIES::onNetSelector, this );
95}
96
97
99{
100 // we passed ownership of table to grid
101 // delete m_layerPropsTable;
102
103 m_layerSpecificOverrides->PopEventHandler( true );
104
105 m_netSelector->Unbind( FILTERED_ITEM_SELECTED, &PANEL_ZONE_PROPERTIES::onNetSelector, this );
106}
107
108
119
120
125
126
128{
129 if( !m_settings )
130 return false;
131
132 m_tcZoneName->SetValue( m_settings->m_Name );
133 m_netSelector->SetSelectedNetcode( std::max( 0, m_settings->m_Netcode ) );
134 m_cbLocked->SetValue( m_settings->m_Locked );
135 m_cornerSmoothingChoice->SetSelection( m_settings->GetCornerSmoothingType() );
136 m_cornerRadius.SetValue( m_settings->GetCornerRadius() );
137
138 if( m_isTeardrop ) // outlines are never smoothed: they have already the right shape
139 {
140 m_cornerSmoothingChoice->SetSelection( 0 );
141 m_cornerSmoothingChoice->Enable( false );
142 m_cornerRadius.Show( false );
143 }
144
145 switch( m_settings->m_ZoneBorderDisplayStyle )
146 {
147 case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: m_OutlineDisplayCtrl->SetSelection( 0 ); break;
151 }
152
153 m_outlineHatchPitch.SetValue( m_settings->m_BorderHatchPitch );
154
155 m_clearance.SetValue( m_settings->m_ZoneClearance );
156 m_minThickness.SetValue( m_settings->m_ZoneMinThickness );
157
158 switch( m_settings->GetPadConnection() )
159 {
160 default:
161 case ZONE_CONNECTION::THERMAL: m_PadInZoneOpt->SetSelection( 1 ); break;
162 case ZONE_CONNECTION::THT_THERMAL: m_PadInZoneOpt->SetSelection( 2 ); break;
163 case ZONE_CONNECTION::NONE: m_PadInZoneOpt->SetSelection( 3 ); break;
164 case ZONE_CONNECTION::FULL: m_PadInZoneOpt->SetSelection( 0 ); break;
165 }
166
167 if( m_isTeardrop )
168 {
169 m_PadInZoneOpt->SetSelection( 0 );
170 m_PadInZoneOpt->Enable( false );
171 m_antipadClearance.Enable( false );
172 m_spokeWidth.Enable( false );
173 }
174
175 // Do not enable/disable antipad clearance and spoke width. They might be needed if
176 // a footprint or pad overrides the zone to specify a thermal connection.
177 m_antipadClearance.SetValue( m_settings->m_ThermalReliefGap );
178 m_spokeWidth.SetValue( m_settings->m_ThermalReliefSpokeWidth );
179
181 m_islandThreshold.SetDoubleValue( static_cast<double>( m_settings->GetMinIslandArea() ) );
182
183 m_cbRemoveIslands->SetSelection( static_cast<int>( m_settings->GetIslandRemovalMode() ) );
184
186
188 m_gridStyleRotation.SetAngleValue( m_settings->m_HatchOrientation );
189 m_gridStyleThickness.SetValue( m_settings->m_HatchThickness );
190 m_gridStyleGap.SetValue( m_settings->m_HatchGap );
191
192 m_spinCtrlSmoothLevel->SetValue( m_settings->m_HatchSmoothingLevel );
193 m_spinCtrlSmoothValue->SetValue( m_settings->m_HatchSmoothingValue );
194
195 for( const auto& [layer, props] : m_settings->m_LayerProperties )
196 {
197 if( props.hatching_offset.has_value() )
198 m_layerPropsTable->AddItem( layer, props );
199 }
200
201 // Enable/Disable some widgets
202 wxCommandEvent aEvent;
203 onNetSelector( aEvent );
205 OnRemoveIslandsSelection( aEvent );
206 onHatched( aEvent );
207
208 Fit();
209
210 return true;
211}
212
213
215{
216 m_islandThreshold.Show( m_cbRemoveIslands->GetSelection() == 2 );
217
218 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( this ) ) )
219 dlg->Layout();
220}
221
222
224{
225 switch( m_cornerSmoothingChoice->GetSelection() )
226 {
228 m_cornerRadiusLabel->SetLabel( _( "Chamfer:" ) );
229 m_cornerRadius.Show( true );
230 break;
231
233 m_cornerRadiusLabel->SetLabel( _( "Fillet:" ) );
234 m_cornerRadius.Show( true );
235 break;
236
237 default:
238 m_cornerRadius.Show( false );
239 break;
240 }
241
242 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( this ) ) )
243 dlg->Layout();
244}
245
246
247void PANEL_ZONE_PROPERTIES::OnZoneNameChanged( wxCommandEvent& aEvent )
248{
249 wxCommandEvent* evt = new wxCommandEvent( EVT_ZONE_NAME_UPDATE );
250 evt->SetString( m_tcZoneName->GetValue() );
251 wxQueueEvent( m_parent, evt );
252}
253
254
256{
257 if( !m_layerSpecificOverrides->CommitPendingChanges() )
258 return false;
259
260 if( !m_settings )
261 return false;
262
263 if( !AcceptOptions() )
264 return false;
265
266 return true;
267}
268
269
270bool PANEL_ZONE_PROPERTIES::AcceptOptions( bool aUseExportableSetupOnly )
271{
272 if( !m_clearance.Validate( 0, pcbIUScale.mmToIU( ZONE_CLEARANCE_MAX_VALUE_MM ) ) )
273 return false;
274
275 if( !m_minThickness.Validate( pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM ), INT_MAX ) )
276 return false;
277
278 if( !m_cornerRadius.Validate( 0, INT_MAX ) )
279 return false;
280
281 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
282 return false;
283
285
286 if( m_settings->m_FillMode == ZONE_FILL_MODE::HATCH_PATTERN )
287 {
288 int minThickness = m_minThickness.GetIntValue();
289
290 if( !m_gridStyleThickness.Validate( minThickness, INT_MAX ) )
291 return false;
292
293 if( !m_gridStyleGap.Validate( minThickness, INT_MAX ) )
294 return false;
295 }
296
297 switch( m_PadInZoneOpt->GetSelection() )
298 {
299 case 3: m_settings->SetPadConnection( ZONE_CONNECTION::NONE ); break;
300 case 2: m_settings->SetPadConnection( ZONE_CONNECTION::THT_THERMAL ); break;
301 case 1: m_settings->SetPadConnection( ZONE_CONNECTION::THERMAL ); break;
302 case 0: m_settings->SetPadConnection( ZONE_CONNECTION::FULL ); break;
303 }
304
305 switch( m_OutlineDisplayCtrl->GetSelection() )
306 {
307 case 0: m_settings->m_ZoneBorderDisplayStyle = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH; break;
308 case 1: m_settings->m_ZoneBorderDisplayStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; break;
309 case 2: m_settings->m_ZoneBorderDisplayStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL; break;
310 }
311
314 {
315 return false;
316 }
317
318 m_settings->m_BorderHatchPitch = m_outlineHatchPitch.GetIntValue();
319
320 m_settings->m_ZoneClearance = m_clearance.GetIntValue();
321 m_settings->m_ZoneMinThickness = m_minThickness.GetIntValue();
322
323 m_settings->SetCornerSmoothingType( m_cornerSmoothingChoice->GetSelection() );
324
325 if( m_settings->GetCornerSmoothingType() == ZONE_SETTINGS::SMOOTHING_NONE )
326 m_settings->SetCornerRadius( 0 );
327 else
328 m_settings->SetCornerRadius( m_cornerRadius.GetIntValue() );
329
330 m_settings->m_Locked = m_cbLocked->GetValue();
331
332 m_settings->m_ThermalReliefGap = m_antipadClearance.GetValue();
333 m_settings->m_ThermalReliefSpokeWidth = m_spokeWidth.GetValue();
334
335 if( m_settings->m_ThermalReliefSpokeWidth < m_settings->m_ZoneMinThickness )
336 {
337 DisplayErrorMessage( this, _( "Thermal spoke width cannot be smaller than the minimum width." ) );
338 return false;
339 }
340
341 m_settings->SetIslandRemovalMode( (ISLAND_REMOVAL_MODE) m_cbRemoveIslands->GetSelection() );
342 m_settings->SetMinIslandArea( m_islandThreshold.GetValue() );
343
344 // If we use only exportable to others zones parameters, exit here:
345 if( aUseExportableSetupOnly )
346 return true;
347
348 m_settings->m_Netcode = m_netSelector->GetSelectedNetcode();
349 m_settings->m_Name = m_tcZoneName->GetValue();
350
352 m_settings->m_HatchOrientation = m_gridStyleRotation.GetAngleValue();
353 m_settings->m_HatchThickness = m_gridStyleThickness.GetIntValue();
354 m_settings->m_HatchGap = m_gridStyleGap.GetIntValue();
355 m_settings->m_HatchSmoothingLevel = m_spinCtrlSmoothLevel->GetValue();
356 m_settings->m_HatchSmoothingValue = m_spinCtrlSmoothValue->GetValue();
357
358 for( auto& [layer, props] : m_settings->m_LayerProperties )
359 props.hatching_offset = std::nullopt;
360
361 for( const auto& [layer, props] : m_layerPropsTable->GetItems() )
362 m_settings->m_LayerProperties[layer] = props;
363
364 return true;
365}
366
367
368void PANEL_ZONE_PROPERTIES::onNetSelector( wxCommandEvent& aEvent )
369{
370 // Zones with no net never have islands removed
371 if( m_netSelector->GetSelectedNetcode() == INVALID_NET_CODE )
372 {
373 if( m_cbRemoveIslands->IsEnabled() )
374 m_settings->SetIslandRemovalMode( (ISLAND_REMOVAL_MODE) m_cbRemoveIslands->GetSelection() );
375
376 m_cbRemoveIslands->SetSelection( 1 );
377 m_staticText40->Enable( false );
378 m_cbRemoveIslands->Enable( false );
379 }
380 else if( !m_cbRemoveIslands->IsEnabled() )
381 {
382 m_cbRemoveIslands->SetSelection( static_cast<int>( m_settings->GetIslandRemovalMode() ) );
383 m_staticText40->Enable( true );
384 m_cbRemoveIslands->Enable( true );
385 }
386
387 wxCommandEvent* evt = new wxCommandEvent( EVT_ZONE_NET_UPDATE );
388 evt->SetId( m_netSelector->GetSelectedNetcode() );
389 wxQueueEvent( m_parent, evt );
390}
391
392
393void PANEL_ZONE_PROPERTIES::onHatched( wxCommandEvent& event )
394{
395 bool enable = m_cbHatched->GetValue();
396 m_gridStyleThickness.Enable( enable );
397 m_gridStyleGap.Enable( enable );
398 m_gridStyleRotation.Enable( enable );
399 m_staticTextGridSmoothingLevel->Enable( enable );
400 m_spinCtrlSmoothLevel->Enable( enable );
401 m_staticTextGridSmootingVal->Enable( enable );
402 m_spinCtrlSmoothValue->Enable( enable );
403 m_offsetOverridesLabel->Enable( enable );
404 m_layerSpecificOverrides->Enable( enable );
405 m_bpAddCustomLayer->Enable( enable );
406 m_bpDeleteCustomLayer->Enable( enable );
407}
408
409
410void PANEL_ZONE_PROPERTIES::OnAddLayerItem( wxCommandEvent& event )
411{
412 m_layerSpecificOverrides->OnAddRow(
413 [&]() -> std::pair<int, int>
414 {
415 m_layerSpecificOverrides->GetTable()->AppendRows( 1 );
416 return { m_layerSpecificOverrides->GetNumberRows() - 1, -1 };
417 } );
418}
419
420
421void PANEL_ZONE_PROPERTIES::OnDeleteLayerItem( wxCommandEvent& event )
422{
423 m_layerSpecificOverrides->OnDeleteRows(
424 [&]( int row )
425 {
426 m_layerSpecificOverrides->GetTable()->DeleteRows( row, 1 );
427 } );
428}
429
430
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
BASE_SET & set(size_t pos)
Definition base_set.h:116
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:68
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:610
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
PANEL_ZONE_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void OnAddLayerItem(wxCommandEvent &event) override
static constexpr int INVALID_NET_CODE
ZONES_CONTAINER & m_ZoneContainer
void ActivateSelectedZone(ZONE *new_zone) override
void OnZoneNameChanged(wxCommandEvent &event) override
void onNetSelector(wxCommandEvent &aEvent)
bool AcceptOptions(bool aUseExportableSetupOnly=false)
void onHatched(wxCommandEvent &event) override
void OnRemoveIslandsSelection(wxCommandEvent &event) override
void OnDeleteLayerItem(wxCommandEvent &event) override
std::shared_ptr< ZONE_SETTINGS > m_settings
PANEL_ZONE_PROPERTIES(wxWindow *aParent, PCB_BASE_FRAME *aFrame, ZONES_CONTAINER &aZoneContainer)
void OnCornerSmoothingSelection(wxCommandEvent &event) override
LAYER_PROPERTIES_GRID_TABLE * m_layerPropsTable
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
This file is part of the common library.
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
wxDEFINE_EVENT(EVT_ZONE_NAME_UPDATE, wxCommandEvent)
T NormalizeAngle180(T Angle)
Normalize angle to be in the -180.0 .
Definition trigo.h:196
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
#define ZONE_CLEARANCE_MAX_VALUE_MM
Definition zones.h:38
@ THERMAL
Use thermal relief for pads.
Definition zones.h:50
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:52
@ NONE
Pads are not covered.
Definition zones.h:49
@ FULL
pads are covered by copper
Definition zones.h:51
#define ZONE_BORDER_HATCH_MINDIST_MM
Definition zones.h:40
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition zones.h:36
#define ZONE_BORDER_HATCH_MAXDIST_MM
Definition zones.h:41