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
62int DIALOG_GENDRILL::g_mapFileType = 4; // The last choice in m_Choice_Drill_Map
64
65bool DIALOG_GENDRILL::g_useRouteModeForOvalHoles = true; // Use G00 route mode to "drill" oval
66 // holes
69
70
71/* This function displays the dialog frame for drill tools
72 */
74{
75 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
76 DIALOG_GENDRILL dlg( editFrame, editFrame );
77
78 dlg.ShowModal();
79 return 0;
80}
81
82
83DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* aPcbEditFrame, wxWindow* aParent ) :
84 DIALOG_GENDRILL_BASE( aParent )
85{
86 m_pcbEditFrame = aPcbEditFrame;
88 m_job = nullptr;
90
91 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
92
93 SetupStandardButtons( { { wxID_OK, _( "Generate" ) },
94 { wxID_CANCEL, _( "Close" ) } } );
95
96 initDialog();
98}
99
100
102 wxWindow* aParent ) :
103 DIALOG_GENDRILL_BASE( aParent )
104{
105 m_pcbEditFrame = aPcbEditFrame;
107 m_job = aJob;
108
109 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
110
111 // hide ui elements that dont belong for job config
112 m_buttonReport->Hide();
113 bMainSizer->Remove( bMsgSizer );
114 m_messagesBox->Hide();
115
117
118 initDialog();
120}
121
122
124{
125}
126
127
129{
130 if( !m_job )
131 {
132 genDrillAndMapFiles( true, m_cbGenerateMap->GetValue() );
133 }
134 else
135 {
139 m_job->m_drillUnits = m_units->GetSelection() == 0
142 m_job->m_drillOrigin = static_cast<JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN>( m_origin->GetSelection() );
145 m_job->m_excellonMirrorY = m_Check_Mirror->IsChecked();
147 m_job->m_mapFormat = static_cast<JOB_EXPORT_PCB_DRILL::MAP_FORMAT>( m_choiceDrillMap->GetSelection() );
148 m_job->m_zeroFormat = static_cast<JOB_EXPORT_PCB_DRILL::ZEROS_FORMAT>( m_zeros->GetSelection() );
149 m_job->m_generateMap = m_cbGenerateMap->IsChecked();
150 }
151
152 return true;
153}
154
155
157{
158 if( !m_job )
159 {
160 m_rbExcellon->SetValue( g_drillFileType == 0 );
161 m_rbGerberX2->SetValue( g_drillFileType == 1 );
162 m_units->SetSelection( g_unitDrillIsInch ? 1 : 0 );
163 m_zeros->SetSelection( g_zerosFormat );
165 m_Check_Minimal->SetValue( g_minimalHeader );
166
167 m_origin->SetSelection( m_drillOriginIsAuxAxis ? 1 : 0 );
168
169 m_Check_Mirror->SetValue( g_mirror );
171 m_choiceDrillMap->SetSelection( g_mapFileType );
173 m_cbGenerateMap->SetValue( g_generateMap );
174
175 // Output directory
177 }
178 else
179 {
180 m_browseButton->Hide();
182
186 m_zeros->SetSelection( static_cast<int>( m_job->m_zeroFormat ) );
189
191
194 m_choiceDrillMap->SetSelection( static_cast<int>( m_job->m_mapFormat ) );
196 m_cbGenerateMap->SetValue( m_job->m_generateMap );
197 }
198
199 wxCommandEvent dummy;
201 return true;
202}
203
204
206{
207 if( m_job )
208 {
209 SetTitle( m_job->GetSettingsDialogTitle() );
210 }
211 else
212 {
213 auto cfg = m_pcbEditFrame->GetPcbNewSettings();
214
215 g_merge_PTH_NPTH = cfg->m_GenDrill.merge_pth_npth;
216 g_minimalHeader = cfg->m_GenDrill.minimal_header;
217 g_mirror = cfg->m_GenDrill.mirror;
218 g_unitDrillIsInch = cfg->m_GenDrill.unit_drill_is_inch;
219 g_useRouteModeForOvalHoles = cfg->m_GenDrill.use_route_for_oval_holes;
220 g_drillFileType = cfg->m_GenDrill.drill_file_type;
221 g_mapFileType = cfg->m_GenDrill.map_file_type;
222 g_zerosFormat = cfg->m_GenDrill.zeros_format;
223 g_generateMap = cfg->m_GenDrill.generate_map;
224
225 // Ensure validity of g_mapFileType
226 if( g_mapFileType < 0 || g_mapFileType >= (int) m_choiceDrillMap->GetCount() )
227 g_mapFileType = m_choiceDrillMap->GetCount() - 1; // last item in list = default = PDF
228 }
229
230 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
231 // non-job versions (which have different sizes).
232 m_hash_key = TO_UTF8( GetTitle() );
233
235}
236
237
238void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
239{
240 bool enbl_Excellon = m_rbExcellon->GetValue();
241
242 g_drillFileType = enbl_Excellon ? 0 : 1;
243
244 m_unitsLabel->Enable( enbl_Excellon );
245 m_units->Enable( enbl_Excellon );
246 m_zerosLabel->Enable( enbl_Excellon );
247 m_zeros->Enable( enbl_Excellon );
248 m_Check_Mirror->Enable( enbl_Excellon );
249 m_Check_Minimal->Enable( enbl_Excellon );
250 m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
251 m_altDrillMode->Enable( enbl_Excellon );
252
253 if( enbl_Excellon )
254 {
256 }
257 else
258 {
259 m_precisionLabel->Enable( true );
260 m_staticTextPrecision->Enable( true );
261 m_staticTextPrecision->SetLabel( m_plotOpts.GetGerberPrecision() == 6 ? wxT( "4.6" )
262 : wxT( "4.5" ) );
263 }
264}
265
266
268{
270
272
282}
283
284
285void DIALOG_GENDRILL::onSelDrillUnitsSelected( wxCommandEvent& event )
286{
288}
289
290
291void DIALOG_GENDRILL::onSelZerosFmtSelected( wxCommandEvent& event )
292{
294}
295
296
298{
299 if( m_units->GetSelection() == 1 )
300 {
301 // Units = inches
303 }
304 else
305 {
306 // metric options
308 }
309
310 if( m_zeros->GetSelection() == EXCELLON_WRITER::DECIMAL_FORMAT )
311 {
312 m_precisionLabel->Enable( false );
313 m_staticTextPrecision->Enable( false );
314 }
315 else
316 {
317 m_precisionLabel->Enable( true );
318 m_staticTextPrecision->Enable( true );
319 }
320}
321
322
324{
325 // Build the absolute path of current output directory to preselect it in the file browser.
326 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
327 path = Prj().AbsolutePath( path );
328
329 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
330
331 if( dirDialog.ShowModal() == wxID_CANCEL )
332 return;
333
334 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
335 wxFileName fn( Prj().AbsolutePath( m_board->GetFileName() ) );
336 wxString defaultPath = fn.GetPathWithSep();
337 wxString msg;
338 msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
339
340 wxMessageDialog dialog( this, msg, _( "Plot Output Directory" ),
341 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
342
343 if( dialog.ShowModal() == wxID_YES )
344 {
345 if( !dirName.MakeRelativeTo( defaultPath ) )
346 {
347 wxMessageBox( _( "Cannot make path relative (target volume different from board "
348 "file volume)!" ),
349 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
350 }
351 }
352
353 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
354}
355
356
358{
359 // Set output directory and replace backslashes with forward ones
360 wxString dirStr;
361 dirStr = m_outputDirectoryName->GetValue();
362 dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
364 m_drillOriginIsAuxAxis = m_origin->GetSelection() == 1;
366
367 g_mapFileType = m_choiceDrillMap->GetSelection();
368
369 g_unitDrillIsInch = ( m_units->GetSelection() == 0 ) ? false : true;
370 g_minimalHeader = m_Check_Minimal->IsChecked();
371 g_mirror = m_Check_Mirror->IsChecked();
373 g_zerosFormat = m_zeros->GetSelection();
375 g_generateMap = m_cbGenerateMap->IsChecked();
376
377 if( m_origin->GetSelection() == 0 )
378 g_drillFileOffset = VECTOR2I( 0, 0 );
379 else
381
384 else
386
388 {
391 }
392}
393
394
395void DIALOG_GENDRILL::genDrillAndMapFiles( bool aGenDrill, bool aGenMap )
396{
397 updateConfig(); // set params and Save drill options
398
401
402 const PLOT_FORMAT filefmt[] = {
403 // Keep these format ids in the same order than m_Choice_Drill_Map choices
404 PLOT_FORMAT::POST,
405 PLOT_FORMAT::GERBER, // Only X2 format because we need the .FileFunction attribute
406 PLOT_FORMAT::DXF,
407 PLOT_FORMAT::SVG,
408 PLOT_FORMAT::PDF
409 };
410
411 unsigned choice = (unsigned) m_choiceDrillMap->GetSelection();
412
413 if( choice >= arrayDim( filefmt ) )
414 choice = arrayDim( filefmt )-1; // Last choice = PDF
415
416 // Create output directory if it does not exist (also transform it in absolute form).
417 // Bail if it fails.
418
419 std::function<bool( wxString* )> textResolver =
420 [&]( wxString* token ) -> bool
421 {
422 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
423 return m_board->ResolveTextVar( token, 0 );
424 };
425
427 path = ExpandTextVars( path, &textResolver );
428 path = ExpandEnvVarSubstitutions( path, nullptr );
429
430 wxFileName outputDir = wxFileName::DirName( path );
431 wxString boardFilename = m_board->GetFileName();
432
433 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
434 {
435 wxString msg;
436 msg.Printf( _( "Could not write drill and/or map files to folder '%s'." ),
437 outputDir.GetPath() );
438 DisplayError( this, msg );
439 return;
440 }
441
442 if( g_drillFileType == 0 )
443 {
444 EXCELLON_WRITER excellonWriter( m_board );
449 excellonWriter.SetMapFileFormat( filefmt[choice] );
450
451 excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
452 &reporter );
453 }
454 else
455 {
456 GERBER_WRITER gerberWriter( m_board );
457 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
458 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
459 // the integer part precision is always 4, and units always mm
460 gerberWriter.SetFormat( m_plotOpts.GetGerberPrecision() );
461 gerberWriter.SetOptions( g_drillFileOffset );
462 gerberWriter.SetMapFileFormat( filefmt[choice] );
463
464 gerberWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
465 &reporter );
466 }
467}
468
469
470void DIALOG_GENDRILL::onGenReportFile( wxCommandEvent& event )
471{
472 updateConfig(); // set params and Save drill options
473
474 wxFileName fn = m_board->GetFileName();
475
476 fn.SetName( fn.GetName() + wxT( "-drl" ) );
477 fn.SetExt( FILEEXT::ReportFileExtension );
478
479 wxString defaultPath = ExpandEnvVarSubstitutions( m_plotOpts.GetOutputDirectory(), &Prj() );
480 defaultPath = Prj().AbsolutePath( defaultPath );
481
482 if( defaultPath.IsEmpty() )
483 defaultPath = PATHS::GetDefaultUserProjectsPath();
484
485 wxFileDialog dlg( this, _( "Save Drill Report File" ), defaultPath, fn.GetFullName(),
486 FILEEXT::ReportFileWildcard(), wxFD_SAVE );
487
488 if( dlg.ShowModal() == wxID_CANCEL )
489 return;
490
491 bool success;
492
493 // Info is slightly different between Excellon and Gerber
494 // (file ext, Merge PTH/NPTH option)
495 if( g_drillFileType == 0 )
496 {
497 EXCELLON_WRITER excellonWriter( m_board );
498 excellonWriter.SetMergeOption( g_merge_PTH_NPTH );
499 success = excellonWriter.GenDrillReportFile( dlg.GetPath() );
500 }
501 else
502 {
503 GERBER_WRITER gerberWriter( m_board );
504 success = gerberWriter.GenDrillReportFile( dlg.GetPath() );
505 }
506
507 wxString msg;
508
509 if( ! success )
510 {
511 msg.Printf( _( "Failed to create file '%s'." ), dlg.GetPath() );
512 m_messagesBox->AppendText( msg );
513 }
514 else
515 {
516 msg.Printf( _( "Report file '%s' created." ), dlg.GetPath() );
517 m_messagesBox->AppendText( msg );
518 }
519}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
const VECTOR2I & GetAuxOrigin()
int GenerateDrillFiles(const TOOL_EVENT &aEvent)
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:701
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:433
const wxString & GetFileName() const
Definition: board.h:332
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:700
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:934
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
wxStaticText * m_precisionLabel
PCB_PLOT_PARAMS m_plotOpts
static bool g_mirror
void onOutputDirectoryBrowseClicked(wxCommandEvent &event) override
void onFileFormatSelection(wxCommandEvent &event) override
bool TransferDataFromWindow() override
PCB_EDIT_FRAME * m_pcbEditFrame
void genDrillAndMapFiles(bool aGenDrill, bool aGenMap)
Call the functions to create EXCELLON drill files and/or drill map files.
DIALOG_GENDRILL(PCB_EDIT_FRAME *aPcbEditFrame, wxWindow *aParent)
static int g_mapFileType
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:230
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, 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:226
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:145
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:351
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:372
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
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:65
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:398
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Definition of file extensions used in Kicad.