KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_board_setup.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19#include <jobs/scratch_doc.h>
20#include <pcb_edit_frame.h>
21#include <panel_setup_layers.h>
30#include <confirm.h>
32#include <widgets/wx_infobar.h>
33#include <kiface_base.h>
34#include <drc/drc_item.h>
36#include <pcb_io/pcb_io.h>
37#include <pcb_io/pcb_io_mgr.h>
48#include <project.h>
54
55#include "dialog_board_setup.h"
56
57#include <advanced_config.h>
58#include <dialog_board_setup.h>
59#include <footprint.h>
60
61
62#define RESOLVE_PAGE( T, pageIndex ) static_cast<T*>( m_treebook->ResolvePage( pageIndex ) )
63
64DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame, wxWindow* aParentWindow ) :
65 PAGED_DIALOG( aParentWindow ? aParentWindow : aFrame, _( "Board Setup" ), false, false,
66 _( "Import Settings from Another Board..." ), wxSize( 980, 600 ) ),
67 m_frame( aFrame ),
68 m_layers( nullptr ),
69 m_boardFinish( nullptr ),
70 m_physicalStackup( nullptr ),
71 m_zones( nullptr ),
72 m_tuningProfiles( nullptr ),
73 m_netClasses( nullptr ),
74 m_currentPage( 0 ),
75 m_layersPage( 0 ),
78 m_defaultsPage( 0 ),
83 m_viaStacksPage( 0 ),
84 m_teardropsPage( 0 ),
90{
91 SetEvtHandlerEnabled( false );
92
93 /*
94 * WARNING: If you change page names you MUST update calls to ShowBoardSetupDialog().
95 */
96
97 m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Board Stackup" ) );
98
99 /*
100 * WARNING: Code currently relies on the layers setup coming before the physical stackup panel,
101 * and thus transferring data to the board first. See comment in
102 * PANEL_SETUP_BOARD_STACKUP::TransferDataFromWindow and rework this logic if it is determined
103 * that the order of these pages should be changed.
104 */
105 m_layersPage = m_treebook->GetPageCount();
106 m_treebook->AddLazySubPage(
107 [this]( wxWindow* aParent ) -> wxWindow*
108 {
109 return new PANEL_SETUP_LAYERS( aParent, m_frame );
110 }, _( "Board Editor Layers" ) );
111
112 m_physicalStackupPage = m_treebook->GetPageCount();
113 m_treebook->AddLazySubPage(
114 [this]( wxWindow* aParent ) -> wxWindow*
115 {
119 }, _( "Physical Stackup" ) );
120
121 m_boardFinishPage = m_treebook->GetPageCount();
122 m_treebook->AddLazySubPage(
123 [this]( wxWindow* aParent ) -> wxWindow*
124 {
125 return new PANEL_SETUP_BOARD_FINISH( aParent, m_frame );
126 }, _( "Board Finish" ) );
127
128 m_maskAndPastePage = m_treebook->GetPageCount();
129 m_treebook->AddLazySubPage(
130 [this]( wxWindow* aParent ) -> wxWindow*
131 {
132 return new PANEL_SETUP_MASK_AND_PASTE( aParent, m_frame );
133 }, _( "Solder Mask/Paste" ) );
134
135 m_drillChartPage = m_treebook->GetPageCount();
136 m_treebook->AddLazySubPage(
137 [this]( wxWindow* aParent ) -> wxWindow*
138 {
139 return new PANEL_SETUP_DRILL_CHART( aParent, m_frame );
140 }, _( "Drill Chart" ) );
141
142 m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Text & Graphics" ) );
143
144 m_defaultsPage = m_treebook->GetPageCount();
145 m_treebook->AddLazySubPage(
146 [this]( wxWindow* aParent ) -> wxWindow*
147 {
148 return new PANEL_SETUP_DEFAULTS( aParent, m_frame );
149 }, _( "Defaults" ) );
150
151 m_formattingPage = m_treebook->GetPageCount();
152 m_treebook->AddLazySubPage(
153 [this]( wxWindow* aParent ) -> wxWindow*
154 {
155 return new PANEL_SETUP_FORMATTING( aParent, m_frame );
156 }, _( "Formatting" ) );
157
158 m_treebook->AddLazySubPage(
159 [this]( wxWindow* aParent ) -> wxWindow*
160 {
161 return new PANEL_TEXT_VARIABLES( aParent, &Prj() );
162 }, _( "Text Variables" ) );
163
164 m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Design Rules" ) );
165
166 m_constraintsPage = m_treebook->GetPageCount();
167 m_treebook->AddLazySubPage(
168 [this]( wxWindow* aParent ) -> wxWindow*
169 {
170 return new PANEL_SETUP_CONSTRAINTS( aParent, m_frame );
171 }, _( "Constraints" ) );
172
173 m_tracksAndViasPage = m_treebook->GetPageCount();
174 m_treebook->AddLazySubPage(
175 [this]( wxWindow* aParent ) -> wxWindow*
176 {
177 return new PANEL_SETUP_TRACKS_AND_VIAS( aParent, m_frame );
178 }, _( "Pre-defined Sizes" ) );
179
180 m_viaStacksPage = m_treebook->GetPageCount();
181 m_treebook->AddLazySubPage(
182 [this]( wxWindow* aParent ) -> wxWindow*
183 {
184 return new PANEL_SETUP_VIA_STACKS( aParent, m_frame );
185 },
186 _( "Microvia Stacks" ) );
187
188 m_zonesPage = m_treebook->GetPageCount();
189 m_treebook->AddLazySubPage(
190 [this]( wxWindow* aParent ) -> wxWindow*
191 {
192 return new PANEL_SETUP_ZONES( aParent, m_frame, m_frame->GetBoard()->GetDesignSettings() );
193 },
194 _( "Zones" ) );
195
196 m_teardropsPage = m_treebook->GetPageCount();
197 m_treebook->AddLazySubPage(
198 [this]( wxWindow* aParent ) -> wxWindow*
199 {
200 return new PANEL_SETUP_TEARDROPS( aParent, m_frame );
201 }, _( "Teardrops" ) );
202
203 m_tuningPatternsPage = m_treebook->GetPageCount();
204 m_treebook->AddLazySubPage(
205 [this]( wxWindow* aParent ) -> wxWindow*
206 {
207 BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings();
208
209 return new PANEL_SETUP_TUNING_PATTERNS( aParent, m_frame,
213 }, _( "Length-tuning Patterns" ) );
214
215 m_tuningProfilesPage = m_treebook->GetPageCount();
216 m_treebook->AddLazySubPage(
217 [this]( wxWindow* aParent ) -> wxWindow*
218 {
219 BOARD* board = m_frame->GetBoard();
220 return new PANEL_SETUP_TUNING_PROFILES( aParent, m_frame, board,
221 m_frame->Prj().GetProjectFile().TuningProfileParameters() );
222 },
223 _( "Tuning Profiles" ) );
224
225 m_netclassesPage = m_treebook->GetPageCount();
226 m_treebook->AddLazySubPage(
227 [this]( wxWindow* aParent ) -> wxWindow*
228 {
229 BOARD* board = m_frame->GetBoard();
230 return new PANEL_SETUP_NETCLASSES( aParent, m_frame,
231 m_frame->Prj().GetProjectFile().NetSettings(),
233 false );
234 }, _( "Net Classes" ) );
235
236 m_componentClassesPage = m_treebook->GetPageCount();
237 m_treebook->AddLazySubPage(
238 [this]( wxWindow* aParent ) -> wxWindow*
239 {
240 // Construct the panel
242 aParent, m_frame, m_frame->Prj().GetProjectFile().ComponentClassSettings(),
243 this );
244 },
245 _( "Component Classes" ) );
246
247 m_customRulesPage = m_treebook->GetPageCount();
248 m_treebook->AddLazySubPage(
249 [this]( wxWindow* aParent ) -> wxWindow*
250 {
251 return new PANEL_SETUP_RULES( aParent, m_frame );
252 },
253 _( "Custom Rules" ) );
254
255 m_severitiesPage = m_treebook->GetPageCount();
256 m_treebook->AddLazySubPage(
257 [this]( wxWindow* aParent ) -> wxWindow*
258 {
259 BOARD* board = m_frame->GetBoard();
262 },
263 _( "Violation Severity" ) );
264
265 m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Board Data" ) );
266 m_embeddedFilesPage = m_treebook->GetPageCount();
267 m_treebook->AddLazySubPage(
268 [this]( wxWindow* aParent ) -> wxWindow*
269 {
270 BOARD* board = m_frame->GetBoard();
271
272 std::vector<const EMBEDDED_FILES*> inheritedFiles;
273
274 for( FOOTPRINT* fp : board->Footprints() )
275 inheritedFiles.push_back( fp->GetEmbeddedFiles() );
276
277 return new PANEL_EMBEDDED_FILES( aParent, board, NO_MARGINS, inheritedFiles );
278 },
279 _( "Embedded Files" ) );
280
281 for( size_t i = 0; i < m_treebook->GetPageCount(); ++i )
282 m_treebook->ExpandNode( i );
283
284 SetEvtHandlerEnabled( true );
285
287
288 if( Prj().IsReadOnly() )
289 {
290 m_infoBar->ShowMessage( _( "Project is missing or read-only. Some settings will not be editable." ),
291 wxICON_WARNING );
292 }
293
294 wxBookCtrlEvent evt( wxEVT_TREEBOOK_PAGE_CHANGED, wxID_ANY, 0 );
295
296 wxQueueEvent( m_treebook, evt.Clone() );
297}
298
299
303
304
305void DIALOG_BOARD_SETUP::onPageChanged( wxBookCtrlEvent& aEvent )
306{
308
309 size_t page = aEvent.GetSelection();
310
311 if( m_physicalStackupPage > 0 ) // Don't run this during initialization
312 {
314 || page == m_tuningProfilesPage || page == m_zonesPage )
315 {
321 }
322
323 // Ensure layer page always gets updated even if we aren't moving towards it
325 {
326 m_layers->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() );
327
328 // Avoid calling SyncCopperLayers twice if moving from stackup to tuning profiles directly
329 m_tuningProfiles->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() );
330 }
331
332 if( page == m_physicalStackupPage )
333 {
334 m_physicalStackup->OnLayersOptionsChanged( m_layers->GetUILayerMask() );
335 }
337 {
338 m_netClasses->UpdateDelayProfileNames( m_tuningProfiles->GetDelayProfileNames() );
339 }
340 else if( page == m_tuningProfilesPage )
341 {
342 m_tuningProfiles->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() );
343 }
344 else if( page == m_zonesPage )
345 {
346 m_zones->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() );
347 }
348
349 if( Prj().IsReadOnly() )
350 {
351 KIUI::Disable( m_treebook->GetPage( page ) );
352 }
353 }
354
355 m_currentPage = page;
356}
357
358
359void DIALOG_BOARD_SETUP::onAuxiliaryAction( wxCommandEvent& aEvent )
360{
361 DIALOG_IMPORT_SETTINGS importDlg( this, m_frame );
362
363 if( importDlg.ShowModal() == wxID_CANCEL )
364 return;
365
366 wxFileName boardFn( importDlg.GetFilePath() );
367
368 SCRATCH_PROJECT scratch( *m_frame->GetSettingsManager(), boardFn.GetFullPath(),
369 /*aRequireProjectFile=*/true );
370
371 if( !scratch.IsValid() )
372 {
373 wxFileName projectFn( boardFn );
374 projectFn.SetExt( FILEEXT::ProjectFileExtension );
375
376 wxString msg = wxString::Format( _( "Error importing settings from board:\n"
377 "Associated project file %s could not be loaded" ),
378 projectFn.GetFullPath() );
379 DisplayErrorMessage( this, msg );
380
381 return;
382 }
383
384 PROJECT* otherPrj = scratch.GetProject();
385
389
390 // Flag so user can stop work if it will result in deleted inner copper layers
391 // and still clean up this function properly.
392 bool okToProceed = true;
393
395 std::unique_ptr<BOARD> otherBoard;
396
397 try
398 {
399 WX_PROGRESS_REPORTER progressReporter( this, _( "Load PCB" ), 1, PR_CAN_ABORT );
400
401 pi->SetProgressReporter( &progressReporter );
402
403 otherBoard = pi->LoadBoard( boardFn.GetFullPath() );
404
405 if( importDlg.m_LayersOpt->GetValue() )
406 {
407 BOARD* loadedBoard = m_frame->GetBoard();
408
409 // Check if "Import Settings" board has more layers than the current board.
410 okToProceed = m_layers->CheckCopperLayerCount( loadedBoard, otherBoard.get() );
411 }
412 }
413 catch( const IO_CANCELLED& )
414 {
415 // A user-cancelled load is not an error.
416 return;
417 }
418 catch( const IO_ERROR& ioe )
419 {
420 // You wouldn't think boardFn.GetFullPath() would throw, but we get a stack buffer
421 // underflow from ASAN. While it's probably an ASAN error, a second try/catch doesn't
422 // cost us much.
423 try
424 {
425 wxString msg = wxString::Format( _( "Error loading board file:\n%s" ), boardFn.GetFullPath() );
426 DisplayErrorMessage( this, msg, ioe.What() );
427 }
428 catch(...)
429 {
430 // That was already our best-efforts
431 }
432
433 return;
434 }
435
436 if( okToProceed )
437 {
438 BOARD* other = otherBoard.get();
439
440 other->SetProject( otherPrj );
441
442 // Always ClearProject before destruction, even if a later
443 // ImportSettingsFrom throws. Skipping clear when otherPrj is the
444 // active project preserves the live editor's BoardSettings.
445 const bool activeProject = ( otherPrj == &m_frame->Prj() );
446
447 struct BOARD_DETACH_GUARD
448 {
449 BOARD* board;
450 bool skip;
451 ~BOARD_DETACH_GUARD() { if( board && !skip ) board->ClearProject(); }
452 } detachGuard{ other, activeProject };
453
454 // If layers options are imported, import also the stackup
455 // layers options and stackup are linked, so they cannot be imported
456 // separately, and stackup can be imported only after layers options
457 if( importDlg.m_LayersOpt->GetValue() )
458 {
459 m_physicalStackup->ImportSettingsFrom( other );
460 m_layers->ImportSettingsFrom( other );
461 m_boardFinish->ImportSettingsFrom( other );
462 }
463
464 if( importDlg.m_TextAndGraphicsOpt->GetValue() )
465 RESOLVE_PAGE( PANEL_SETUP_DEFAULTS, m_defaultsPage )->ImportSettingsFrom( other );
466
467 if( importDlg.m_FormattingOpt->GetValue() )
468 RESOLVE_PAGE( PANEL_SETUP_FORMATTING, m_formattingPage )->ImportSettingsFrom( other );
469
470 if( importDlg.m_ConstraintsOpt->GetValue() )
471 RESOLVE_PAGE( PANEL_SETUP_CONSTRAINTS, m_constraintsPage )->ImportSettingsFrom( other );
472
473 if( importDlg.m_NetclassesOpt->GetValue() )
474 {
475 PROJECT_FILE& otherProjectFile = otherPrj->GetProjectFile();
476
478 m_netclassesPage )->ImportSettingsFrom( otherProjectFile.m_NetSettings );
479 }
480
481 if( importDlg.m_ComponentClassesOpt->GetValue() )
482 {
483 PROJECT_FILE& otherProjectFile = otherPrj->GetProjectFile();
484
486 m_componentClassesPage )->ImportSettingsFrom( otherProjectFile.m_ComponentClassSettings );
487 }
488
489 if( importDlg.m_TracksAndViasOpt->GetValue() )
490 {
491 RESOLVE_PAGE( PANEL_SETUP_TRACKS_AND_VIAS, m_tracksAndViasPage )->ImportSettingsFrom( other );
492 RESOLVE_PAGE( PANEL_SETUP_VIA_STACKS, m_viaStacksPage )->ImportSettingsFrom( other );
493 }
494
495 if( importDlg.m_ZonesOpt->GetValue() )
496 RESOLVE_PAGE( PANEL_SETUP_ZONES, m_zonesPage )->ImportSettingsFrom( other );
497
498 if( importDlg.m_TeardropsOpt->GetValue() )
499 RESOLVE_PAGE( PANEL_SETUP_TEARDROPS, m_teardropsPage )->ImportSettingsFrom( other );
500
501 if( importDlg.m_TuningPatternsOpt->GetValue() )
502 RESOLVE_PAGE( PANEL_SETUP_TUNING_PATTERNS, m_tuningPatternsPage )->ImportSettingsFrom( other );
503
504 if( importDlg.m_MaskAndPasteOpt->GetValue() )
505 RESOLVE_PAGE( PANEL_SETUP_MASK_AND_PASTE, m_maskAndPastePage )->ImportSettingsFrom( other );
506
507 if( importDlg.m_ZoneHatchingOffsetsOpt->GetValue() )
508 RESOLVE_PAGE( PANEL_SETUP_ZONES, m_zonesPage )->ImportHatchOffsetsFrom( other );
509
510 if( importDlg.m_CustomRulesOpt->GetValue() )
511 RESOLVE_PAGE( PANEL_SETUP_RULES, m_customRulesPage )->ImportSettingsFrom( other );
512
513 if( importDlg.m_SeveritiesOpt->GetValue() )
514 {
515 BOARD_DESIGN_SETTINGS& otherSettings = other->GetDesignSettings();
516
518 m_severitiesPage )->ImportSettingsFrom( otherSettings.m_DRCSeverities );
519 }
520
521 if( importDlg.m_TuningProfilesOpt->GetValue() )
522 {
523 PROJECT_FILE& otherProjectFile = otherPrj->GetProjectFile();
524
526 m_tuningProfilesPage )->ImportSettingsFrom( otherProjectFile.TuningProfileParameters() );
527 }
528
529 }
530}
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
PNS::MEANDER_SETTINGS m_DiffPairMeanderSettings
PNS::MEANDER_SETTINGS m_SingleTrackMeanderSettings
PNS::MEANDER_SETTINGS m_SkewMeanderSettings
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
Definition board.cpp:3118
const FOOTPRINTS & Footprints() const
Definition board.h:463
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition board.cpp:374
void ClearProject()
Definition board.cpp:415
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
DIALOG_BOARD_SETUP(PCB_EDIT_FRAME *aFrame, wxWindow *aWindow=nullptr)
PCB_EDIT_FRAME * m_frame
PANEL_SETUP_TUNING_PROFILES * m_tuningProfiles
void onAuxiliaryAction(wxCommandEvent &aEvent) override
PANEL_SETUP_BOARD_STACKUP * m_physicalStackup
PANEL_SETUP_ZONES * m_zones
PANEL_SETUP_BOARD_FINISH * m_boardFinish
PANEL_SETUP_LAYERS * m_layers
void onPageChanged(wxBookCtrlEvent &aEvent) override
PANEL_SETUP_NETCLASSES * m_netClasses
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
int ShowModal() override
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition drc_item.h:159
An exception saying that the user cancelled an interactive part of a load, import,...
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
WX_TREEBOOK * GetTreebook()
WX_INFOBAR * m_infoBar
PAGED_DIALOG(wxWindow *aParent, const wxString &aTitle, bool aShowReset, bool aShowOpenFolder, const wxString &aAuxiliaryAction=wxEmptyString, const wxSize &aInitialSize=wxDefaultSize)
WX_TREEBOOK * m_treebook
virtual void onPageChanged(wxBookCtrlEvent &aEvent)
Board-wide drill chart and map setup.
The main frame for Pcbnew.
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:54
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
The backing store for a PROJECT, in JSON format.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
std::shared_ptr< TUNING_PROFILES > & TuningProfileParameters()
std::shared_ptr< COMPONENT_CLASS_SETTINGS > m_ComponentClassSettings
Component class settings for the project (owned here)
Container for project specific data.
Definition project.h:63
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
Move-only RAII wrapper for "load a foreign PROJECT non-active and unload it on scope exit.
Definition scratch_doc.h:55
bool IsValid() const
True iff the project loaded (or was already loaded).
PROJECT * GetProject() const
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
#define RESOLVE_PAGE(T, pageIndex)
#define _(s)
static const std::string ProjectFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
KICOMMON_API void Disable(wxWindow *aWindow)
Makes a window read-only.
#define NO_MARGINS
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT