KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_gendrill.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) 1992-2019 Jean_Pierre Charras <jp.charras at wanadoo.fr>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <confirm.h>
26#include <core/arraydim.h>
28#include <pcb_edit_frame.h>
29#include <pcbnew_settings.h>
30#include <pcbplot.h>
33#include <bitmaps.h>
35#include <footprint.h>
36#include <pad.h>
37#include <pcb_track.h>
38#include <paths.h>
39#include <dialog_gendrill.h>
41#include <reporter.h>
42#include <wx/msgdlg.h>
43#include <wx/dirdlg.h>
44#include <wx/filedlg.h>
46
47// list of allowed precision for EXCELLON files, for integer format:
48// Due to difference between inches and mm,
49// there are 2 precision values, one for inches and one for metric
50// Note: for decimla format, the precision is not used
53
54
55// Static members of DIALOG_GENDRILL
56int DIALOG_GENDRILL::g_unitDrillIsInch = false; // Only for Excellon format
58bool DIALOG_GENDRILL::g_minimalHeader = false; // Only for Excellon format
59bool DIALOG_GENDRILL::g_mirror = false; // Only for Excellon format
60bool DIALOG_GENDRILL::g_merge_PTH_NPTH = false; // Only for Excellon format
63int DIALOG_GENDRILL::g_mapFileType = 4; // The last choice in m_Choice_Drill_Map
65
66bool DIALOG_GENDRILL::g_useRouteModeForOvalHoles = true; // Use G00 route mode to "drill" oval
67 // holes
70
71
72/* This function displays the dialog frame for drill tools
73 */
75{
76 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
77 DIALOG_GENDRILL dlg( editFrame, editFrame );
78
79 dlg.ShowModal();
80 return 0;
81}
82
83
84DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* aPcbEditFrame, wxWindow* aParent ) :
85 DIALOG_GENDRILL_BASE( aParent )
86{
87 m_pcbEditFrame = aPcbEditFrame;
89 m_job = nullptr;
91
92 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
93
94 SetupStandardButtons( { { wxID_OK, _( "Generate" ) },
95 { wxID_CANCEL, _( "Close" ) } } );
96
97 initDialog();
99}
100
101
103 wxWindow* aParent ) :
104 DIALOG_GENDRILL_BASE( aParent )
105{
106 m_pcbEditFrame = aPcbEditFrame;
108 m_job = aJob;
109
110 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
111
112 // hide ui elements that dont belong for job config
113 m_buttonReport->Hide();
114 bMainSizer->Remove( bMsgSizer );
115 m_messagesBox->Hide();
116
118
119 initDialog();
121}
122
123
125{
126}
127
128
130{
131 if( !m_job )
132 {
133 genDrillAndMapFiles( true, m_cbGenerateMap->GetValue(),
134 m_generateTentingLayers->GetValue() );
135 // Keep the window open so that the user can see the result
136 return false;
137 }
138 else
139 {
145 m_job->m_drillOrigin = static_cast<JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN>( m_origin->GetSelection() );
148 m_job->m_excellonMirrorY = m_Check_Mirror->IsChecked();
150 m_job->m_mapFormat = static_cast<JOB_EXPORT_PCB_DRILL::MAP_FORMAT>( m_choiceDrillMap->GetSelection() );
151 m_job->m_zeroFormat = static_cast<JOB_EXPORT_PCB_DRILL::ZEROS_FORMAT>( m_zeros->GetSelection() );
152 m_job->m_generateMap = m_cbGenerateMap->IsChecked();
154 }
155
156 return true;
157}
158
159
161{
162 if( !m_job )
163 {
164 m_rbExcellon->SetValue( g_drillFileType == 0 );
165 m_rbGerberX2->SetValue( g_drillFileType == 1 );
166 m_units->SetSelection( g_unitDrillIsInch ? 1 : 0 );
167 m_zeros->SetSelection( g_zerosFormat );
169 m_Check_Minimal->SetValue( g_minimalHeader );
170
171 m_origin->SetSelection( m_drillOriginIsAuxAxis ? 1 : 0 );
172
173 m_Check_Mirror->SetValue( g_mirror );
175 m_choiceDrillMap->SetSelection( g_mapFileType );
177 m_cbGenerateMap->SetValue( g_generateMap );
179
180 // Output directory
182 }
183 else
184 {
185 m_browseButton->Hide();
187
191 m_zeros->SetSelection( static_cast<int>( m_job->m_zeroFormat ) );
194
196
199 m_choiceDrillMap->SetSelection( static_cast<int>( m_job->m_mapFormat ) );
201 m_cbGenerateMap->SetValue( m_job->m_generateMap );
203 }
204
205 wxCommandEvent dummy;
207 return true;
208}
209
210
212{
213 if( m_job )
214 {
215 SetTitle( m_job->GetSettingsDialogTitle() );
216 }
217 else
218 {
219 auto cfg = m_pcbEditFrame->GetPcbNewSettings();
220
221 g_merge_PTH_NPTH = cfg->m_GenDrill.merge_pth_npth;
222 g_minimalHeader = cfg->m_GenDrill.minimal_header;
223 g_mirror = cfg->m_GenDrill.mirror;
224 g_unitDrillIsInch = cfg->m_GenDrill.unit_drill_is_inch;
225 g_useRouteModeForOvalHoles = cfg->m_GenDrill.use_route_for_oval_holes;
226 g_drillFileType = cfg->m_GenDrill.drill_file_type;
227 g_mapFileType = cfg->m_GenDrill.map_file_type;
228 g_zerosFormat = cfg->m_GenDrill.zeros_format;
229 g_generateMap = cfg->m_GenDrill.generate_map;
230 g_generateTenting = cfg->m_GenDrill.generate_tenting;
231
232 // Ensure validity of g_mapFileType
233 if( g_mapFileType < 0 || g_mapFileType >= (int) m_choiceDrillMap->GetCount() )
234 g_mapFileType = m_choiceDrillMap->GetCount() - 1; // last item in list = default = PDF
235 }
236
237 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
238 // non-job versions (which have different sizes).
239 m_hash_key = TO_UTF8( GetTitle() );
240
242}
243
244
245void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
246{
247 bool enbl_Excellon = m_rbExcellon->GetValue();
248
249 g_drillFileType = enbl_Excellon ? 0 : 1;
250
251 m_unitsLabel->Enable( enbl_Excellon );
252 m_units->Enable( enbl_Excellon );
253 m_zerosLabel->Enable( enbl_Excellon );
254 m_zeros->Enable( enbl_Excellon );
255 m_Check_Mirror->Enable( enbl_Excellon );
256 m_Check_Minimal->Enable( enbl_Excellon );
257 m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
258 m_altDrillMode->Enable( enbl_Excellon );
259 m_generateTentingLayers->Enable( !enbl_Excellon );
260
261 if( enbl_Excellon )
262 {
264 }
265 else
266 {
267 m_precisionLabel->Enable( true );
268 m_staticTextPrecision->Enable( true );
269 m_staticTextPrecision->SetLabel( m_plotOpts.GetGerberPrecision() == 6 ? wxT( "4.6" )
270 : wxT( "4.5" ) );
271 }
272}
273
274
276{
278
280
291}
292
293
294void DIALOG_GENDRILL::onSelDrillUnitsSelected( wxCommandEvent& event )
295{
297}
298
299
300void DIALOG_GENDRILL::onSelZerosFmtSelected( wxCommandEvent& event )
301{
303}
304
305
307{
308 if( m_units->GetSelection() == 1 )
309 {
310 // Units = inches
312 }
313 else
314 {
315 // metric options
317 }
318
319 if( m_zeros->GetSelection() == EXCELLON_WRITER::DECIMAL_FORMAT )
320 {
321 m_precisionLabel->Enable( false );
322 m_staticTextPrecision->Enable( false );
323 }
324 else
325 {
326 m_precisionLabel->Enable( true );
327 m_staticTextPrecision->Enable( true );
328 }
329}
330
331
333{
334 // Build the absolute path of current output directory to preselect it in the file browser.
335 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
336 path = Prj().AbsolutePath( path );
337
338 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
339
340 if( dirDialog.ShowModal() == wxID_CANCEL )
341 return;
342
343 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
344 wxFileName fn( Prj().AbsolutePath( m_board->GetFileName() ) );
345 wxString defaultPath = fn.GetPathWithSep();
346 wxString msg;
347 msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
348
349 wxMessageDialog dialog( this, msg, _( "Plot Output Directory" ),
350 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
351
352 if( dialog.ShowModal() == wxID_YES )
353 {
354 if( !dirName.MakeRelativeTo( defaultPath ) )
355 {
356 wxMessageBox( _( "Cannot make path relative (target volume different from board "
357 "file volume)!" ),
358 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
359 }
360 }
361
362 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
363}
364
365
367{
368 // Set output directory and replace backslashes with forward ones
369 wxString dirStr;
370 dirStr = m_outputDirectoryName->GetValue();
371 dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
373 m_drillOriginIsAuxAxis = m_origin->GetSelection() == 1;
375
376 g_mapFileType = m_choiceDrillMap->GetSelection();
377
378 g_unitDrillIsInch = ( m_units->GetSelection() == 0 ) ? false : true;
379 g_minimalHeader = m_Check_Minimal->IsChecked();
380 g_mirror = m_Check_Mirror->IsChecked();
382 g_zerosFormat = m_zeros->GetSelection();
384 g_generateMap = m_cbGenerateMap->IsChecked();
386
387 if( m_origin->GetSelection() == 0 )
388 g_drillFileOffset = VECTOR2I( 0, 0 );
389 else
391
394 else
396
398 {
401 }
402}
403
404
405void DIALOG_GENDRILL::genDrillAndMapFiles( bool aGenDrill, bool aGenMap, bool aGenTenting )
406{
407 updateConfig(); // set params and Save drill options
408
411
412 const PLOT_FORMAT filefmt[] = {
413 // Keep these format ids in the same order than m_Choice_Drill_Map choices
414 PLOT_FORMAT::POST,
415 PLOT_FORMAT::GERBER, // Only X2 format because we need the .FileFunction attribute
416 PLOT_FORMAT::DXF,
417 PLOT_FORMAT::SVG,
418 PLOT_FORMAT::PDF
419 };
420
421 unsigned choice = (unsigned) m_choiceDrillMap->GetSelection();
422
423 if( choice >= arrayDim( filefmt ) )
424 choice = arrayDim( filefmt )-1; // Last choice = PDF
425
426 // Create output directory if it does not exist (also transform it in absolute form).
427 // Bail if it fails.
428
429 std::function<bool( wxString* )> textResolver =
430 [&]( wxString* token ) -> bool
431 {
432 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
433 return m_board->ResolveTextVar( token, 0 );
434 };
435
437 path = ExpandTextVars( path, &textResolver );
438 path = ExpandEnvVarSubstitutions( path, nullptr );
439
440 wxFileName outputDir = wxFileName::DirName( path );
441 wxString boardFilename = m_board->GetFileName();
442
443 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
444 {
445 wxString msg;
446 msg.Printf( _( "Could not write drill and/or map files to folder '%s'." ),
447 outputDir.GetPath() );
448 DisplayError( this, msg );
449 return;
450 }
451
452 if( g_drillFileType == 0 )
453 {
454 EXCELLON_WRITER excellonWriter( m_board );
459 excellonWriter.SetMapFileFormat( filefmt[choice] );
460
461 excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
462 &reporter );
463 }
464 else
465 {
466 GERBER_WRITER gerberWriter( m_board );
467 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
468 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
469 // the integer part precision is always 4, and units always mm
470 gerberWriter.SetFormat( m_plotOpts.GetGerberPrecision() );
471 gerberWriter.SetOptions( g_drillFileOffset );
472 gerberWriter.SetMapFileFormat( filefmt[choice] );
473
474 gerberWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
475 aGenTenting, &reporter );
476 }
477}
478
479
480void DIALOG_GENDRILL::onGenReportFile( wxCommandEvent& event )
481{
482 updateConfig(); // set params and Save drill options
483
484 wxFileName fn = m_board->GetFileName();
485
486 fn.SetName( fn.GetName() + wxT( "-drl" ) );
487 fn.SetExt( FILEEXT::ReportFileExtension );
488
489 wxString defaultPath = ExpandEnvVarSubstitutions( m_plotOpts.GetOutputDirectory(), &Prj() );
490 defaultPath = Prj().AbsolutePath( defaultPath );
491
492 if( defaultPath.IsEmpty() )
493 defaultPath = PATHS::GetDefaultUserProjectsPath();
494
495 wxFileDialog dlg( this, _( "Save Drill Report File" ), defaultPath, fn.GetFullName(),
496 FILEEXT::ReportFileWildcard(), wxFD_SAVE );
497
498 if( dlg.ShowModal() == wxID_CANCEL )
499 return;
500
501 bool success;
502
503 // Info is slightly different between Excellon and Gerber
504 // (file ext, Merge PTH/NPTH option)
505 if( g_drillFileType == 0 )
506 {
507 EXCELLON_WRITER excellonWriter( m_board );
508 excellonWriter.SetMergeOption( g_merge_PTH_NPTH );
509 success = excellonWriter.GenDrillReportFile( dlg.GetPath() );
510 }
511 else
512 {
513 GERBER_WRITER gerberWriter( m_board );
514 success = gerberWriter.GenDrillReportFile( dlg.GetPath() );
515 }
516
517 wxString msg;
518
519 if( ! success )
520 {
521 msg.Printf( _( "Failed to create file '%s'." ), dlg.GetPath() );
522 m_messagesBox->AppendText( msg );
523 }
524 else
525 {
526 msg.Printf( _( "Report file '%s' created." ), dlg.GetPath() );
527 m_messagesBox->AppendText( msg );
528 }
529}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
const VECTOR2I & GetAuxOrigin() const
int GenerateDrillFiles(const TOOL_EVENT &aEvent)
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:719
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:443
const wxString & GetFileName() const
Definition: board.h:334
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:718
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:955
Class DIALOG_GENDRILL_BASE.
wxRadioButton * m_rbExcellon
wxStaticText * m_staticTextPrecision
STD_BITMAP_BUTTON * m_browseButton
wxStaticBoxSizer * bMsgSizer
wxRadioButton * m_rbGerberX2
wxCheckBox * m_Check_Merge_PTH_NPTH
wxTextCtrl * m_outputDirectoryName
wxCheckBox * m_generateTentingLayers
wxStaticText * m_precisionLabel
PCB_PLOT_PARAMS m_plotOpts
static bool g_mirror
void onOutputDirectoryBrowseClicked(wxCommandEvent &event) override
void onFileFormatSelection(wxCommandEvent &event) override
void genDrillAndMapFiles(bool aGenDrill, bool aGenMap, bool aGenTenting)
Call the functions to create EXCELLON drill files and/or drill map files.
bool TransferDataFromWindow() override
PCB_EDIT_FRAME * m_pcbEditFrame
DIALOG_GENDRILL(PCB_EDIT_FRAME *aPcbEditFrame, wxWindow *aParent)
static int g_mapFileType
static bool g_generateTenting
bool TransferDataToWindow() override
static bool g_useRouteModeForOvalHoles
void onSelZerosFmtSelected(wxCommandEvent &event) override
static int g_drillFileType
static VECTOR2I g_drillFileOffset
void UpdateDrillParams()
Update board drill/plot parameters.
static bool g_merge_PTH_NPTH
static int g_unitDrillIsInch
static bool g_minimalHeader
void onGenReportFile(wxCommandEvent &event) override
JOB_EXPORT_PCB_DRILL * m_job
void onSelDrillUnitsSelected(wxCommandEvent &event) override
static int g_zerosFormat
static DRILL_PRECISION g_precision
static bool g_generateMap
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:194
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
int ShowModal() override
Helper to handle drill precision format in excellon files.
virtual void ClearMsgPanel()
Clear all messages from the message panel.
Create Excellon drill, drill map, and drill report files.
void SetFormat(bool aMetric, ZEROS_FMT aZerosFmt=DECIMAL_FORMAT, int aLeftDigits=0, int aRightDigits=0)
Initialize internal parameters to match the given format.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board.
void SetOptions(bool aMirror, bool aMinimalHeader, const VECTOR2I &aOffset, bool aMerge_PTH_NPTH)
Initialize internal parameters to match drill options.
void SetRouteModeForOvalHoles(bool aUseRouteModeForOvalHoles)
void SetMapFileFormat(PLOT_FORMAT aMapFmt)
Initialize the format for the drill map file.
bool GenDrillReportFile(const wxString &aFullFileName)
Create a plain text report file giving a list of drill values and drill count for through holes,...
void SetMergeOption(bool aMerge)
Set the option to make separate drill files for PTH and NPTH.
Used to create Gerber drill files.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, bool aGenTenting, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
void SetOptions(const VECTOR2I &aOffset)
Initialize internal parameters to match drill options.
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
wxString GetSettingsDialogTitle() const override
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition: job.cpp:153
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition: job.h:227
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:143
DIALOG_GENERATE_DRILL m_GenDrill
virtual const PCB_PLOT_PARAMS & GetPlotSettings() const
Return the PCB_PLOT_PARAMS for the BOARD owned by this frame.
PCBNEW_SETTINGS * GetPcbNewSettings() const
BOARD * GetBoard() const
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
bool GetUseAuxOrigin() const
void SetOutputDirectory(const wxString &aDir)
wxString GetOutputDirectory() const
int GetGerberPrecision() const
bool IsSameAs(const PCB_PLOT_PARAMS &aPcbPlotParams) const
Compare current settings to aPcbPlotParams, including not saved parameters in brd file.
void SetUseAuxOrigin(bool aAux)
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:370
void SetBitmap(const wxBitmapBundle &aBmp)
Generic, UI-independent tool event.
Definition: tool_event.h:168
A wrapper for reporting to a wxTextCtrl object.
Definition: reporter.h:164
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:353
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition: common.cpp:59
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.
Definition: common.cpp:374
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
#define _(s)
Classes used in drill files, map files and report files generation.
Classes used in drill files, map files and report files generation.
static const std::string ReportFileExtension
static wxString ReportFileWildcard()
PLOT_FORMAT
The set of supported output plot formats.
Definition: plotter.h:64
std::vector< FAB_LAYER_COLOR > dummy
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:429
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Definition of file extensions used in Kicad.