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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include "dialog_gendrill.h"
22
23#include <common.h>
24#include <wx/msgdlg.h>
25#include <wx/dirdlg.h>
26#include <wx/filedlg.h>
27#include <kiplatform/ui.h>
28
29#include <confirm.h>
30#include <core/arraydim.h>
32#include <pcb_edit_frame.h>
33#include <pcbplot.h>
36#include <bitmaps.h>
38#include <footprint.h>
39#include <pad.h>
40#include <pcb_track.h>
41#include <paths.h>
42#include <string_utils.h>
44#include <reporter.h>
46
47// List of allowed precision for EXCELLON files, for integer format. Due to difference between inches and mm,
48// there are 2 precision values, one for inches and one for metric.
49// Note: for decimal format, the precision is not used.
52
53
54/* This function displays the dialog frame for drill tools
55 */
57{
59 DIALOG_GENDRILL dlg( editFrame, editFrame );
60
61 dlg.ShowModal();
62 return 0;
63}
64
65
66DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* aPcbEditFrame, wxWindow* aParent ) :
67 DIALOG_GENDRILL_BASE( aParent ),
68 m_pcbEditFrame( aPcbEditFrame ),
69 m_board( aPcbEditFrame->GetBoard() ),
70 m_plotOpts( aPcbEditFrame->GetPlotSettings() ),
71 m_job( nullptr )
72{
74
75 SetupStandardButtons( { { wxID_OK, _( "Generate" ) },
76 { wxID_CANCEL, _( "Close" ) } } );
77
78 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
79 // non-job versions.
80 m_hash_key = TO_UTF8( GetTitle() );
81
83}
84
85
87 wxWindow* aParent ) :
88 DIALOG_GENDRILL_BASE( aParent ),
89 m_pcbEditFrame( aPcbEditFrame ),
90 m_board( m_pcbEditFrame->GetBoard() ),
91 m_job( aJob )
92{
94
95 // hide ui elements that dont belong for job config
96 m_buttonReport->Hide();
97 bMainSizer->Remove( bMsgSizer );
98 m_messagesBox->Hide();
99
101
102 SetTitle( m_job->GetSettingsDialogTitle() );
103
104 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
105 // non-job versions.
106 m_hash_key = TO_UTF8( GetTitle() );
107
109}
110
111
113{
114 m_messagesBox->Clear();
115
116 if( !m_job )
117 {
119
120 m_origin->SetSelection( m_plotOpts.GetUseAuxOrigin() ? 1 : 0 );
121
122 // Output directory
123 m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
124 }
125 else
126 {
127 m_browseButton->Hide();
128 m_outputDirectoryName->SetValue( m_job->GetConfiguredOutputPath() );
129
132 m_units->SetSelection( m_job->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::INCH );
133 m_zeros->SetSelection( static_cast<int>( m_job->m_zeroFormat ) );
135 m_Check_Minimal->SetValue( m_job->m_excellonMinimalHeader );
136
137 m_origin->SetSelection( m_job->m_drillOrigin == JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN::PLOT );
138
139 m_Check_Mirror->SetValue( m_job->m_excellonMirrorY );
140 m_Check_Merge_PTH_NPTH->SetValue( m_job->m_excellonCombinePTHNPTH );
141 m_choiceDrillMap->SetSelection( static_cast<int>( m_job->m_mapFormat ) );
142 m_altDrillMode->SetValue( !m_job->m_excellonOvalDrillRoute );
143 m_cbGenerateMap->SetValue( m_job->m_generateMap );
144 m_generateTentingLayers->SetValue( m_job->m_generateTenting );
145 }
146
147 wxCommandEvent dummy;
149 return true;
150}
151
152
154{
155 if( !m_job )
156 {
157 genDrillAndMapFiles( true, m_cbGenerateMap->GetValue(), m_generateTentingLayers->GetValue() );
158 // Keep the window open so that the user can see the result
159 return false;
160 }
161 else
162 {
163 m_job->SetConfiguredOutputPath( m_outputDirectoryName->GetValue() );
166 m_job->m_drillUnits = m_units->GetSelection() == 0 ? JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM
168 m_job->m_drillOrigin = static_cast<JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN>( m_origin->GetSelection() );
169 m_job->m_excellonCombinePTHNPTH = m_Check_Merge_PTH_NPTH->IsChecked();
170 m_job->m_excellonMinimalHeader = m_Check_Minimal->IsChecked();
171 m_job->m_excellonMirrorY = m_Check_Mirror->IsChecked();
172 m_job->m_excellonOvalDrillRoute = !m_altDrillMode->GetValue();
173 m_job->m_mapFormat = static_cast<JOB_EXPORT_PCB_DRILL::MAP_FORMAT>( m_choiceDrillMap->GetSelection() );
174 m_job->m_zeroFormat = static_cast<JOB_EXPORT_PCB_DRILL::ZEROS_FORMAT>( m_zeros->GetSelection() );
175 m_job->m_generateMap = m_cbGenerateMap->IsChecked();
176 m_job->m_generateTenting = m_generateTentingLayers->IsChecked();
177 }
178
179 return true;
180}
181
182
183void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
184{
185 bool enbl_Excellon = m_rbExcellon->GetValue();
186
187 m_unitsLabel->Enable( enbl_Excellon );
188 m_units->Enable( enbl_Excellon );
189 m_zerosLabel->Enable( enbl_Excellon );
190 m_zeros->Enable( enbl_Excellon );
191 m_Check_Mirror->Enable( enbl_Excellon );
192 m_Check_Minimal->Enable( enbl_Excellon );
193 m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
194 m_altDrillMode->Enable( enbl_Excellon );
195 m_generateTentingLayers->Enable( !enbl_Excellon );
196
197 if( enbl_Excellon )
198 {
200 }
201 else
202 {
203 m_precisionLabel->Enable( true );
204 m_staticTextPrecision->Enable( true );
205 m_staticTextPrecision->SetLabel( m_plotOpts.GetGerberPrecision() == 6 ? wxT( "4.6" )
206 : wxT( "4.5" ) );
207 }
208}
209
210
212{
213 // Set output directory and replace backslashes with forward ones
214 wxString dirStr = m_outputDirectoryName->GetValue();
215 dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
216 m_plotOpts.SetOutputDirectory( dirStr );
217 m_plotOpts.SetUseAuxOrigin( m_origin->GetSelection() == 1 );
218
219 if( !m_plotOpts.IsSameAs( m_board->GetPlotOptions() ) )
220 {
221 m_board->SetPlotOptions( m_plotOpts );
222 m_pcbEditFrame->OnModify();
223 }
224}
225
226
227void DIALOG_GENDRILL::onSelDrillUnitsSelected( wxCommandEvent& event )
228{
230}
231
232
233void DIALOG_GENDRILL::onSelZerosFmtSelected( wxCommandEvent& event )
234{
236}
237
238
240{
241 if( m_units->GetSelection() == 1 )
242 {
243 // Units = inches
244 m_staticTextPrecision->SetLabel( precisionListForInches.GetPrecisionString() );
245 }
246 else
247 {
248 // metric options
249 m_staticTextPrecision->SetLabel( precisionListForMetric.GetPrecisionString() );
250 }
251
252 if( m_zeros->GetSelection() == EXCELLON_WRITER::DECIMAL_FORMAT )
253 {
254 m_precisionLabel->Enable( false );
255 m_staticTextPrecision->Enable( false );
256 }
257 else
258 {
259 m_precisionLabel->Enable( true );
260 m_staticTextPrecision->Enable( true );
261 }
262}
263
264
266{
267 // Build the absolute path of current output directory to preselect it in the file browser.
268 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
269 path = Prj().AbsolutePath( path );
270
271 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
272
273 if( dirDialog.ShowModal() == wxID_CANCEL )
274 return;
275
276 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
277 wxFileName fn( Prj().AbsolutePath( m_board->GetFileName() ) );
278 wxString defaultPath = fn.GetPathWithSep();
279
280 if( IsOK( this, wxString::Format( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath ) ) )
281 {
282 if( !dirName.MakeRelativeTo( defaultPath ) )
283 {
284 DisplayErrorMessage( this, _( "Cannot make path relative (target volume different from board "
285 "file volume)!" ) );
286 }
287 }
288
289 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
290}
291
292
293void DIALOG_GENDRILL::genDrillAndMapFiles( bool aGenDrill, bool aGenMap, bool aGenTenting )
294{
295 updateConfig(); // set params and Save drill options
296
297 m_pcbEditFrame->ClearMsgPanel();
298 m_messagesBox->Clear();
300
301 const PLOT_FORMAT filefmt[] = {
302 // Keep these format ids in the same order than m_Choice_Drill_Map choices
304 PLOT_FORMAT::GERBER, // Only X2 format because we need the .FileFunction attribute
308 };
309
310 unsigned choice = (unsigned) m_choiceDrillMap->GetSelection();
311
312 if( choice >= arrayDim( filefmt ) )
313 choice = arrayDim( filefmt )-1; // Last choice = PDF
314
315 // Create output directory if it does not exist (also transform it in absolute form).
316 // Bail if it fails.
317
318 std::function<bool( wxString* )> textResolver =
319 [&]( wxString* token ) -> bool
320 {
321 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
322 return m_board->ResolveTextVar( token, 0 );
323 };
324
325 wxString path = m_plotOpts.GetOutputDirectory();
326 path = ExpandTextVars( path, &textResolver );
328
329 wxFileName outputDir = wxFileName::DirName( path );
330 wxString boardFilename = m_board->GetFileName();
331
332 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
333 {
334 DisplayError( this, wxString::Format( _( "Could not write drill and/or map files to folder '%s'." ),
335 outputDir.GetPath() ) );
336 return;
337 }
338
339 VECTOR2I drillFileOffset;
340 DRILL_PRECISION precision;
341
342 if( m_origin->GetSelection() == 0 )
343 drillFileOffset = VECTOR2I( 0, 0 );
344 else
345 drillFileOffset = m_board->GetDesignSettings().GetAuxOrigin();
346
347 if( m_units->GetSelection() == 0 )
348 precision = precisionListForMetric;
349 else
350 precision = precisionListForInches;
351
352 if( m_rbExcellon->GetValue() )
353 {
354 EXCELLON_WRITER excellonWriter( m_board );
355 excellonWriter.SetFormat( m_units->GetSelection() == 0, (EXCELLON_WRITER::ZEROS_FMT) m_zeros->GetSelection(),
356 precision.m_Lhs, precision.m_Rhs );
357 excellonWriter.SetOptions( m_Check_Mirror->IsChecked(), m_Check_Minimal->IsChecked(), drillFileOffset,
358 m_Check_Merge_PTH_NPTH->IsChecked() );
359 excellonWriter.SetRouteModeForOvalHoles( !m_altDrillMode->GetValue() );
360 excellonWriter.SetMapFileFormat( filefmt[choice] );
361 excellonWriter.SetPageInfo( &m_board->GetPageSettings() );
362
363 excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap, &reporter );
364 }
365 else
366 {
367 GERBER_WRITER gerberWriter( m_board );
368 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
369 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
370 // the integer part precision is always 4, and units always mm
371 gerberWriter.SetFormat( m_plotOpts.GetGerberPrecision() );
372 gerberWriter.SetOptions( drillFileOffset );
373 gerberWriter.SetMapFileFormat( filefmt[choice] );
374 gerberWriter.SetPageInfo( &m_board->GetPageSettings() );
375
376 gerberWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap, aGenTenting, &reporter );
377 }
378}
379
380
381void DIALOG_GENDRILL::onGenReportFile( wxCommandEvent& event )
382{
383 updateConfig(); // set params and Save drill options
384
385 wxFileName fn = m_board->GetFileName();
386
387 fn.SetName( fn.GetName() + wxT( "-drl" ) );
388 fn.SetExt( FILEEXT::ReportFileExtension );
389
390 wxString defaultPath = ExpandEnvVarSubstitutions( m_plotOpts.GetOutputDirectory(), &Prj() );
391 defaultPath = Prj().AbsolutePath( defaultPath );
392
393 if( defaultPath.IsEmpty() )
394 defaultPath = PATHS::GetDefaultUserProjectsPath();
395
396 wxFileDialog dlg( this, _( "Save Drill Report File" ), defaultPath, fn.GetFullName(),
397 FILEEXT::ReportFileWildcard(), wxFD_SAVE );
398
400
401 if( dlg.ShowModal() == wxID_CANCEL )
402 return;
403
404 m_messagesBox->Clear();
405 bool success;
406
407 // Info is slightly different between Excellon and Gerber
408 // (file ext, Merge PTH/NPTH option)
409 if( m_rbExcellon->GetValue() == 0 )
410 {
411 EXCELLON_WRITER excellonWriter( m_board );
412 excellonWriter.SetMergeOption( m_Check_Merge_PTH_NPTH->IsChecked() );
413 success = excellonWriter.GenDrillReportFile( dlg.GetPath() );
414 }
415 else
416 {
417 GERBER_WRITER gerberWriter( m_board );
418 success = gerberWriter.GenDrillReportFile( dlg.GetPath() );
419 }
420
421 if( !success )
422 m_messagesBox->AppendText( wxString::Format( _( "Failed to create file '%s'." ), dlg.GetPath() ) );
423 else
424 m_messagesBox->AppendText( wxString::Format( _( "Report file '%s' created." ), dlg.GetPath() ) );
425}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition arraydim.h:27
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
int GenerateDrillFiles(const TOOL_EVENT &aEvent)
wxStaticText * m_staticTextPrecision
STD_BITMAP_BUTTON * m_browseButton
wxStaticBoxSizer * bMsgSizer
DIALOG_GENDRILL_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Generate Drill Files"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
wxCheckBox * m_Check_Merge_PTH_NPTH
wxCheckBox * m_generateTentingLayers
wxStaticText * m_precisionLabel
PCB_PLOT_PARAMS m_plotOpts
void onOutputDirectoryBrowseClicked(wxCommandEvent &event) override
void onFileFormatSelection(wxCommandEvent &event) override
void genDrillAndMapFiles(bool aGenDrill, bool aGenMap, bool aGenTenting)
Call 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)
bool TransferDataToWindow() override
void onSelZerosFmtSelected(wxCommandEvent &event) override
void onGenReportFile(wxCommandEvent &event) override
JOB_EXPORT_PCB_DRILL * m_job
void onSelDrillUnitsSelected(wxCommandEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
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.
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.
void SetMergeOption(bool aMerge)
Set the option to make separate drill files for PTH and NPTH.
void SetPageInfo(const PAGE_INFO *aPageInfo)
Set the page info used to plot drill maps.
bool GenDrillReportFile(const wxString &aFullFileName, REPORTER *aReporter=nullptr)
Create a plain text report file giving a list of drill values and drill count for through holes,...
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.
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:137
The main frame for Pcbnew.
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:407
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
Generic, UI-independent tool event.
Definition tool_event.h:167
A wrapper for reporting to a wxTextCtrl object.
Definition reporter.h:165
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:704
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:725
The common library.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
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()
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
PLOT_FORMAT
The set of supported output plot formats.
Definition plotter.h:60
std::vector< FAB_LAYER_COLOR > dummy
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::string path
IbisParser parser & reporter
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
Definition of file extensions used in Kicad.