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