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 "dialog_gendrill.h"
26
27#include <wx/msgdlg.h>
28#include <wx/dirdlg.h>
29#include <wx/filedlg.h>
30
31#include <confirm.h>
32#include <core/arraydim.h>
34#include <pcb_edit_frame.h>
35#include <pcbplot.h>
38#include <bitmaps.h>
40#include <footprint.h>
41#include <pad.h>
42#include <pcb_track.h>
43#include <paths.h>
44#include <string_utils.h>
46#include <reporter.h>
48
49// List of allowed precision for EXCELLON files, for integer format. Due to difference between inches and mm,
50// there are 2 precision values, one for inches and one for metric.
51// Note: for decimal format, the precision is not used.
54
55
56/* This function displays the dialog frame for drill tools
57 */
59{
61 DIALOG_GENDRILL dlg( editFrame, editFrame );
62
63 dlg.ShowModal();
64 return 0;
65}
66
67
68DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* aPcbEditFrame, wxWindow* aParent ) :
69 DIALOG_GENDRILL_BASE( aParent ),
70 m_pcbEditFrame( aPcbEditFrame ),
71 m_board( aPcbEditFrame->GetBoard() ),
72 m_plotOpts( aPcbEditFrame->GetPlotSettings() ),
73 m_job( nullptr )
74{
76
77 SetupStandardButtons( { { wxID_OK, _( "Generate" ) },
78 { wxID_CANCEL, _( "Close" ) } } );
79
80 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
81 // non-job versions.
82 m_hash_key = TO_UTF8( GetTitle() );
83
85}
86
87
89 wxWindow* aParent ) :
90 DIALOG_GENDRILL_BASE( aParent ),
91 m_pcbEditFrame( aPcbEditFrame ),
93 m_job( aJob )
94{
96
97 // hide ui elements that dont belong for job config
98 m_buttonReport->Hide();
99 bMainSizer->Remove( bMsgSizer );
100 m_messagesBox->Hide();
101
103
104 SetTitle( m_job->GetSettingsDialogTitle() );
105
106 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
107 // non-job versions.
108 m_hash_key = TO_UTF8( GetTitle() );
109
111}
112
113
115{
116 m_messagesBox->Clear();
117
118 if( !m_job )
119 {
121
122 m_origin->SetSelection( m_plotOpts.GetUseAuxOrigin() ? 1 : 0 );
123
124 // Output directory
125 m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
126 }
127 else
128 {
129 m_browseButton->Hide();
130 m_outputDirectoryName->SetValue( m_job->GetConfiguredOutputPath() );
131
134 m_units->SetSelection( m_job->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::INCH );
135 m_zeros->SetSelection( static_cast<int>( m_job->m_zeroFormat ) );
137 m_Check_Minimal->SetValue( m_job->m_excellonMinimalHeader );
138
139 m_origin->SetSelection( m_job->m_drillOrigin == JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN::PLOT );
140
141 m_Check_Mirror->SetValue( m_job->m_excellonMirrorY );
142 m_Check_Merge_PTH_NPTH->SetValue( m_job->m_excellonCombinePTHNPTH );
143 m_choiceDrillMap->SetSelection( static_cast<int>( m_job->m_mapFormat ) );
144 m_altDrillMode->SetValue( !m_job->m_excellonOvalDrillRoute );
145 m_cbGenerateMap->SetValue( m_job->m_generateMap );
146 m_generateTentingLayers->SetValue( m_job->m_generateTenting );
147 }
148
149 wxCommandEvent dummy;
151 return true;
152}
153
154
156{
157 if( !m_job )
158 {
159 genDrillAndMapFiles( true, m_cbGenerateMap->GetValue(), m_generateTentingLayers->GetValue() );
160 // Keep the window open so that the user can see the result
161 return false;
162 }
163 else
164 {
165 m_job->SetConfiguredOutputPath( m_outputDirectoryName->GetValue() );
168 m_job->m_drillUnits = m_units->GetSelection() == 0 ? JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM
170 m_job->m_drillOrigin = static_cast<JOB_EXPORT_PCB_DRILL::DRILL_ORIGIN>( m_origin->GetSelection() );
171 m_job->m_excellonCombinePTHNPTH = m_Check_Merge_PTH_NPTH->IsChecked();
172 m_job->m_excellonMinimalHeader = m_Check_Minimal->IsChecked();
173 m_job->m_excellonMirrorY = m_Check_Mirror->IsChecked();
174 m_job->m_excellonOvalDrillRoute = !m_altDrillMode->GetValue();
175 m_job->m_mapFormat = static_cast<JOB_EXPORT_PCB_DRILL::MAP_FORMAT>( m_choiceDrillMap->GetSelection() );
176 m_job->m_zeroFormat = static_cast<JOB_EXPORT_PCB_DRILL::ZEROS_FORMAT>( m_zeros->GetSelection() );
177 m_job->m_generateMap = m_cbGenerateMap->IsChecked();
178 m_job->m_generateTenting = m_generateTentingLayers->IsChecked();
179 }
180
181 return true;
182}
183
184
185void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
186{
187 bool enbl_Excellon = m_rbExcellon->GetValue();
188
189 m_unitsLabel->Enable( enbl_Excellon );
190 m_units->Enable( enbl_Excellon );
191 m_zerosLabel->Enable( enbl_Excellon );
192 m_zeros->Enable( enbl_Excellon );
193 m_Check_Mirror->Enable( enbl_Excellon );
194 m_Check_Minimal->Enable( enbl_Excellon );
195 m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
196 m_altDrillMode->Enable( enbl_Excellon );
197 m_generateTentingLayers->Enable( !enbl_Excellon );
198
199 if( enbl_Excellon )
200 {
202 }
203 else
204 {
205 m_precisionLabel->Enable( true );
206 m_staticTextPrecision->Enable( true );
207 m_staticTextPrecision->SetLabel( m_plotOpts.GetGerberPrecision() == 6 ? wxT( "4.6" )
208 : wxT( "4.5" ) );
209 }
210}
211
212
214{
215 // Set output directory and replace backslashes with forward ones
216 wxString dirStr = m_outputDirectoryName->GetValue();
217 dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
218 m_plotOpts.SetOutputDirectory( dirStr );
219 m_plotOpts.SetUseAuxOrigin( m_origin->GetSelection() == 1 );
220
221 if( !m_plotOpts.IsSameAs( m_board->GetPlotOptions() ) )
222 {
223 m_board->SetPlotOptions( m_plotOpts );
224 m_pcbEditFrame->OnModify();
225 }
226}
227
228
229void DIALOG_GENDRILL::onSelDrillUnitsSelected( wxCommandEvent& event )
230{
232}
233
234
235void DIALOG_GENDRILL::onSelZerosFmtSelected( wxCommandEvent& event )
236{
238}
239
240
242{
243 if( m_units->GetSelection() == 1 )
244 {
245 // Units = inches
246 m_staticTextPrecision->SetLabel( precisionListForInches.GetPrecisionString() );
247 }
248 else
249 {
250 // metric options
251 m_staticTextPrecision->SetLabel( precisionListForMetric.GetPrecisionString() );
252 }
253
254 if( m_zeros->GetSelection() == EXCELLON_WRITER::DECIMAL_FORMAT )
255 {
256 m_precisionLabel->Enable( false );
257 m_staticTextPrecision->Enable( false );
258 }
259 else
260 {
261 m_precisionLabel->Enable( true );
262 m_staticTextPrecision->Enable( true );
263 }
264}
265
266
268{
269 // Build the absolute path of current output directory to preselect it in the file browser.
270 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
271 path = Prj().AbsolutePath( path );
272
273 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
274
275 if( dirDialog.ShowModal() == wxID_CANCEL )
276 return;
277
278 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
279 wxFileName fn( Prj().AbsolutePath( m_board->GetFileName() ) );
280 wxString defaultPath = fn.GetPathWithSep();
281
282 if( IsOK( this, wxString::Format( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath ) ) )
283 {
284 if( !dirName.MakeRelativeTo( defaultPath ) )
285 {
286 DisplayErrorMessage( this, _( "Cannot make path relative (target volume different from board "
287 "file volume)!" ) );
288 }
289 }
290
291 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
292}
293
294
295void DIALOG_GENDRILL::genDrillAndMapFiles( bool aGenDrill, bool aGenMap, bool aGenTenting )
296{
297 updateConfig(); // set params and Save drill options
298
299 m_pcbEditFrame->ClearMsgPanel();
300 m_messagesBox->Clear();
302
303 const PLOT_FORMAT filefmt[] = {
304 // Keep these format ids in the same order than m_Choice_Drill_Map choices
306 PLOT_FORMAT::GERBER, // Only X2 format because we need the .FileFunction attribute
310 };
311
312 unsigned choice = (unsigned) m_choiceDrillMap->GetSelection();
313
314 if( choice >= arrayDim( filefmt ) )
315 choice = arrayDim( filefmt )-1; // Last choice = PDF
316
317 // Create output directory if it does not exist (also transform it in absolute form).
318 // Bail if it fails.
319
320 std::function<bool( wxString* )> textResolver =
321 [&]( wxString* token ) -> bool
322 {
323 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
324 return m_board->ResolveTextVar( token, 0 );
325 };
326
327 wxString path = m_plotOpts.GetOutputDirectory();
328 path = ExpandTextVars( path, &textResolver );
329 path = ExpandEnvVarSubstitutions( path, nullptr );
330
331 wxFileName outputDir = wxFileName::DirName( path );
332 wxString boardFilename = m_board->GetFileName();
333
334 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
335 {
336 DisplayError( this, wxString::Format( _( "Could not write drill and/or map files to folder '%s'." ),
337 outputDir.GetPath() ) );
338 return;
339 }
340
341 VECTOR2I drillFileOffset;
342 DRILL_PRECISION precision;
343
344 if( m_origin->GetSelection() == 0 )
345 drillFileOffset = VECTOR2I( 0, 0 );
346 else
347 drillFileOffset = m_board->GetDesignSettings().GetAuxOrigin();
348
349 if( m_units->GetSelection() == 0 )
350 precision = precisionListForMetric;
351 else
352 precision = precisionListForInches;
353
354 if( m_rbExcellon->GetValue() )
355 {
356 EXCELLON_WRITER excellonWriter( m_board );
357 excellonWriter.SetFormat( m_units->GetSelection() == 0, (EXCELLON_WRITER::ZEROS_FMT) m_zeros->GetSelection(),
358 precision.m_Lhs, precision.m_Rhs );
359 excellonWriter.SetOptions( m_Check_Mirror->IsChecked(), m_Check_Minimal->IsChecked(), drillFileOffset,
360 m_Check_Merge_PTH_NPTH->IsChecked() );
361 excellonWriter.SetRouteModeForOvalHoles( !m_altDrillMode->GetValue() );
362 excellonWriter.SetMapFileFormat( filefmt[choice] );
363 excellonWriter.SetPageInfo( &m_board->GetPageSettings() );
364
365 excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap, &reporter );
366 }
367 else
368 {
369 GERBER_WRITER gerberWriter( m_board );
370 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
371 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
372 // the integer part precision is always 4, and units always mm
373 gerberWriter.SetFormat( m_plotOpts.GetGerberPrecision() );
374 gerberWriter.SetOptions( drillFileOffset );
375 gerberWriter.SetMapFileFormat( filefmt[choice] );
376 gerberWriter.SetPageInfo( &m_board->GetPageSettings() );
377
378 gerberWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap, aGenTenting, &reporter );
379 }
380}
381
382
383void DIALOG_GENDRILL::onGenReportFile( wxCommandEvent& event )
384{
385 updateConfig(); // set params and Save drill options
386
387 wxFileName fn = m_board->GetFileName();
388
389 fn.SetName( fn.GetName() + wxT( "-drl" ) );
390 fn.SetExt( FILEEXT::ReportFileExtension );
391
392 wxString defaultPath = ExpandEnvVarSubstitutions( m_plotOpts.GetOutputDirectory(), &Prj() );
393 defaultPath = Prj().AbsolutePath( defaultPath );
394
395 if( defaultPath.IsEmpty() )
396 defaultPath = PATHS::GetDefaultUserProjectsPath();
397
398 wxFileDialog dlg( this, _( "Save Drill Report File" ), defaultPath, fn.GetFullName(),
399 FILEEXT::ReportFileWildcard(), wxFD_SAVE );
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:31
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
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.
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.
void SetPageInfo(const PAGE_INFO *aPageInfo)
Set the page info used to plot drill maps.
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:136
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:386
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
Generic, UI-independent tool event.
Definition tool_event.h:171
A wrapper for reporting to a wxTextCtrl object.
Definition reporter.h:167
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:355
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:376
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:251
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:169
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()
BOARD * GetBoard()
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.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
Definition of file extensions used in Kicad.