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 (C) 1992-2023 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 <board.h>
37#include <footprint.h>
38#include <pad.h>
39#include <pcb_track.h>
40#include <paths.h>
41#include <project.h>
42#include <dialog_gendrill.h>
44#include <reporter.h>
45#include <wx/msgdlg.h>
46#include <wx/dirdlg.h>
47#include <wx/filedlg.h>
48
49// list of allowed precision for EXCELLON files, for integer format:
50// Due to difference between inches and mm,
51// there are 2 precision values, one for inches and one for metric
52// Note: for decimla format, the precision is not used
55
56
57/* This function displays the dialog frame for drill tools
58 */
60{
61 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
62 DIALOG_GENDRILL dlg( editFrame, editFrame );
63
64 dlg.ShowModal();
65 return 0;
66}
67
68
69DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* aPcbEditFrame, wxWindow* aParent ) :
70 DIALOG_GENDRILL_BASE( aParent )
71{
72 m_pcbEditFrame = aPcbEditFrame;
75
76 SetupStandardButtons( { { wxID_OK, _( "Generate Drill File" ) },
77 { wxID_APPLY, _( "Generate Map File" ) },
78 { wxID_CANCEL, _( "Close" ) } } );
79
80 m_buttonsSizer->Layout();
81
82 SetReturnCode( 1 );
83 initDialog();
84 GetSizer()->SetSizeHints( this );
85}
86
87
88// Static members of DIALOG_GENDRILL
89int DIALOG_GENDRILL::m_UnitDrillIsInch = true; // Only for Excellon format
91bool DIALOG_GENDRILL::m_MinimalHeader = false; // Only for Excellon format
92bool DIALOG_GENDRILL::m_Mirror = false; // Only for Excellon format
93bool DIALOG_GENDRILL::m_Merge_PTH_NPTH = false; // Only for Excellon format
94int DIALOG_GENDRILL::m_mapFileType = 4; // The last choice in m_Choice_Drill_Map
96bool DIALOG_GENDRILL::m_UseRouteModeForOvalHoles = true; // Use G00 route mode to "drill" oval holes
97
99{
100}
101
102
104{
105 auto cfg = m_pcbEditFrame->GetPcbNewSettings();
106
107 m_Merge_PTH_NPTH = cfg->m_GenDrill.merge_pth_npth;
108 m_MinimalHeader = cfg->m_GenDrill.minimal_header;
109 m_Mirror = cfg->m_GenDrill.mirror;
110 m_UnitDrillIsInch = cfg->m_GenDrill.unit_drill_is_inch;
111 m_UseRouteModeForOvalHoles = cfg->m_GenDrill.use_route_for_oval_holes;
112 m_drillFileType = cfg->m_GenDrill.drill_file_type;
113 m_mapFileType = cfg->m_GenDrill.map_file_type;
114 m_ZerosFormat = cfg->m_GenDrill.zeros_format;
115
117
118 // Ensure validity of m_mapFileType
119 if( m_mapFileType < 0 || m_mapFileType >= (int)m_Choice_Drill_Map->GetCount() )
120 m_mapFileType = m_Choice_Drill_Map->GetCount() - 1; // last item in list = default = PDF
121
123}
124
125
127{
128 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
129
130 m_rbExcellon->SetValue( m_drillFileType == 0 );
131 m_rbGerberX2->SetValue( m_drillFileType == 1 );
132 m_Choice_Unit->SetSelection( m_UnitDrillIsInch ? 1 : 0 );
133 m_Choice_Zeros_Format->SetSelection( m_ZerosFormat );
135 m_Check_Minimal->SetValue( m_MinimalHeader );
136
137 m_Choice_Drill_Offset->SetSelection( m_drillOriginIsAuxAxis ? 1 : 0 );
138
139 m_Check_Mirror->SetValue( m_Mirror );
141 m_Choice_Drill_Map->SetSelection( m_mapFileType );
142 m_radioBoxOvalHoleMode->SetSelection( m_UseRouteModeForOvalHoles ? 0 : 1 );
143
149
150 for( FOOTPRINT* footprint : m_board->Footprints() )
151 {
152 for( PAD* pad : footprint->Pads() )
153 {
154 if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
155 {
156 if( pad->GetDrillSize().x != 0 )
157 {
158 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
160 else
162 }
163 }
164 else
165 {
166 if( pad->GetDrillSize().x != 0 && pad->GetDrillSize().y != 0 )
167 {
168 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
170 else
172 }
173 }
174 }
175 }
176
177 for( PCB_TRACK* track : m_board->Tracks() )
178 {
179 const PCB_VIA *via = dynamic_cast<const PCB_VIA*>( track );
180
181 if( via )
182 {
183 switch( via->GetViaType() )
184 {
185 case VIATYPE::THROUGH: m_throughViasCount++; break;
186 case VIATYPE::MICROVIA: m_microViasCount++; break;
187 case VIATYPE::BLIND_BURIED: m_blindOrBuriedViasCount++; break;
188 default: break;
189 }
190 }
191 }
192
193 // Display hole counts:
194 m_PlatedPadsCountInfoMsg->SetLabel( wxString() << m_platedPadsHoleCount );
195 m_NotPlatedPadsCountInfoMsg->SetLabel( wxString() << m_notplatedPadsHoleCount );
196 m_ThroughViasInfoMsg->SetLabel( wxString() << m_throughViasCount );
197 m_MicroViasInfoMsg->SetLabel( wxString() << m_microViasCount );
198 m_BuriedViasInfoMsg->SetLabel( wxString() << m_blindOrBuriedViasCount );
199
200 // Output directory
202
203 wxCommandEvent dummy;
205}
206
207
208void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
209{
210 bool enbl_Excellon = m_rbExcellon->GetValue();
211
212 m_drillFileType = enbl_Excellon ? 0 : 1;
213
214 m_Choice_Unit->Enable( enbl_Excellon );
215 m_Choice_Zeros_Format->Enable( enbl_Excellon );
216 m_Check_Mirror->Enable( enbl_Excellon );
217 m_Check_Minimal->Enable( enbl_Excellon );
218 m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
219 m_radioBoxOvalHoleMode->Enable( enbl_Excellon );
220
221 if( enbl_Excellon )
222 {
224 }
225 else
226 {
227 m_staticTextPrecision->Enable( true );
228 m_staticTextPrecision->SetLabel( m_plotOpts.GetGerberPrecision() == 6 ? wxT( "4.6" )
229 : wxT( "4.5" ) );
230 }
231}
232
233
235{
237
238 auto cfg = m_pcbEditFrame->GetPcbNewSettings();
239
241 cfg->m_GenDrill.minimal_header = m_MinimalHeader;
242 cfg->m_GenDrill.mirror = m_Mirror;
243 cfg->m_GenDrill.unit_drill_is_inch = m_UnitDrillIsInch;
244 cfg->m_GenDrill.use_route_for_oval_holes = m_UseRouteModeForOvalHoles;
245 cfg->m_GenDrill.drill_file_type = m_drillFileType;
246 cfg->m_GenDrill.map_file_type = m_mapFileType;
247 cfg->m_GenDrill.zeros_format = m_ZerosFormat;
248}
249
250
251void DIALOG_GENDRILL::OnSelDrillUnitsSelected( wxCommandEvent& event )
252{
254}
255
256
257void DIALOG_GENDRILL::OnGenMapFile( wxCommandEvent& event )
258{
259 GenDrillAndMapFiles( false, true );
260}
261
262
263void DIALOG_GENDRILL::OnGenDrillFile( wxCommandEvent& event )
264{
265 GenDrillAndMapFiles( true, false );
266}
267
268
269void DIALOG_GENDRILL::OnSelZerosFmtSelected( wxCommandEvent& event )
270{
272}
273
274
276{
277 if( m_Choice_Unit->GetSelection()== 1 )
278 {
279 // Units = inches
281 }
282 else
283 {
284 // metric options
286 }
287
289 m_staticTextPrecision->Enable( false );
290 else
291 m_staticTextPrecision->Enable( true );
292}
293
294
296{
297 // Build the absolute path of current output directory to preselect it in the file browser.
298 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
299 path = Prj().AbsolutePath( path );
300
301 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
302
303 if( dirDialog.ShowModal() == wxID_CANCEL )
304 return;
305
306 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
307 wxFileName fn( Prj().AbsolutePath( m_board->GetFileName() ) );
308 wxString defaultPath = fn.GetPathWithSep();
309 wxString msg;
310 msg.Printf( _( "Do you want to use a path relative to\n'%s'?" ), defaultPath );
311
312 wxMessageDialog dialog( this, msg, _( "Plot Output Directory" ),
313 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
314
315 if( dialog.ShowModal() == wxID_YES )
316 {
317 if( !dirName.MakeRelativeTo( defaultPath ) )
318 {
319 wxMessageBox( _( "Cannot make path relative (target volume different from board "
320 "file volume)!" ),
321 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
322 }
323 }
324
325 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
326}
327
328
330{
331 // Set output directory and replace backslashes with forward ones
332 wxString dirStr;
333 dirStr = m_outputDirectoryName->GetValue();
334 dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
336 m_drillOriginIsAuxAxis = m_Choice_Drill_Offset->GetSelection() == 1;
338
339 m_mapFileType = m_Choice_Drill_Map->GetSelection();
340
341 m_UnitDrillIsInch = (m_Choice_Unit->GetSelection() == 0) ? false : true;
342 m_MinimalHeader = m_Check_Minimal->IsChecked();
343 m_Mirror = m_Check_Mirror->IsChecked();
345 m_ZerosFormat = m_Choice_Zeros_Format->GetSelection();
347
348 if( m_Choice_Drill_Offset->GetSelection() == 0 )
349 m_DrillFileOffset = VECTOR2I( 0, 0 );
350 else
352
355 else
357
359 {
362 }
363}
364
365
366void DIALOG_GENDRILL::GenDrillAndMapFiles( bool aGenDrill, bool aGenMap )
367{
368 UpdateConfig(); // set params and Save drill options
369
372
373 const PLOT_FORMAT filefmt[] = {
374 // Keep these format ids in the same order than m_Choice_Drill_Map choices
375 PLOT_FORMAT::POST,
376 PLOT_FORMAT::GERBER, // Only X2 format because we need the .FileFunction attribute
377 PLOT_FORMAT::DXF,
378 PLOT_FORMAT::SVG,
379 PLOT_FORMAT::PDF
380 };
381
382 unsigned choice = (unsigned) m_Choice_Drill_Map->GetSelection();
383
384 if( choice >= arrayDim( filefmt ) )
385 choice = arrayDim( filefmt )-1; // Last choice = PDF
386
387 // Create output directory if it does not exist (also transform it in absolute form).
388 // Bail if it fails.
389
390 std::function<bool( wxString* )> textResolver =
391 [&]( wxString* token ) -> bool
392 {
393 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
394 return m_board->ResolveTextVar( token, 0 );
395 };
396
398 path = ExpandTextVars( path, &textResolver );
399 path = ExpandEnvVarSubstitutions( path, nullptr );
400
401 wxFileName outputDir = wxFileName::DirName( path );
402 wxString boardFilename = m_board->GetFileName();
403
404 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
405 {
406 wxString msg;
407 msg.Printf( _( "Could not write drill and/or map files to folder '%s'." ),
408 outputDir.GetPath() );
409 DisplayError( this, msg );
410 return;
411 }
412
413 if( m_drillFileType == 0 )
414 {
415 EXCELLON_WRITER excellonWriter( m_board );
420 excellonWriter.SetMapFileFormat( filefmt[choice] );
421
422 excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
423 &reporter );
424 }
425 else
426 {
427 GERBER_WRITER gerberWriter( m_board );
428 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
429 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
430 // the integer part precision is always 4, and units always mm
431 gerberWriter.SetFormat( m_plotOpts.GetGerberPrecision() );
432 gerberWriter.SetOptions( m_DrillFileOffset );
433 gerberWriter.SetMapFileFormat( filefmt[choice] );
434
435 gerberWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), aGenDrill, aGenMap,
436 &reporter );
437 }
438}
439
440
441void DIALOG_GENDRILL::OnGenReportFile( wxCommandEvent& event )
442{
443 UpdateConfig(); // set params and Save drill options
444
445 wxFileName fn = m_board->GetFileName();
446
447 fn.SetName( fn.GetName() + wxT( "-drl" ) );
448 fn.SetExt( FILEEXT::ReportFileExtension );
449
450 wxString defaultPath = ExpandEnvVarSubstitutions( m_plotOpts.GetOutputDirectory(), &Prj() );
451 defaultPath = Prj().AbsolutePath( defaultPath );
452
453 if( defaultPath.IsEmpty() )
454 defaultPath = PATHS::GetDefaultUserProjectsPath();
455
456 wxFileDialog dlg( this, _( "Save Drill Report File" ), defaultPath, fn.GetFullName(),
457 FILEEXT::ReportFileWildcard(), wxFD_SAVE );
458
459 if( dlg.ShowModal() == wxID_CANCEL )
460 return;
461
462 bool success;
463
464 // Info is slightly different between Excellon and Gerber
465 // (file ext, Merge PTH/NPTH option)
466 if( m_drillFileType == 0 )
467 {
468 EXCELLON_WRITER excellonWriter( m_board );
469 excellonWriter.SetMergeOption( m_Merge_PTH_NPTH );
470 success = excellonWriter.GenDrillReportFile( dlg.GetPath() );
471 }
472 else
473 {
474 GERBER_WRITER gerberWriter( m_board );
475 success = gerberWriter.GenDrillReportFile( dlg.GetPath() );
476 }
477
478 wxString msg;
479
480 if( ! success )
481 {
482 msg.Printf( _( "Failed to create file '%s'." ), dlg.GetPath() );
483 m_messagesBox->AppendText( msg );
484 }
485 else
486 {
487 msg.Printf( _( "Report file '%s' created." ), dlg.GetPath() );
488 m_messagesBox->AppendText( msg );
489 }
490}
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:654
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:395
FOOTPRINTS & Footprints()
Definition: board.h:318
TRACKS & Tracks()
Definition: board.h:315
const wxString & GetFileName() const
Definition: board.h:313
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:653
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:768
Class DIALOG_GENDRILL_BASE.
wxRadioButton * m_rbExcellon
wxRadioBox * m_Choice_Drill_Offset
wxStaticText * m_staticTextPrecision
STD_BITMAP_BUTTON * m_browseButton
wxStaticText * m_MicroViasInfoMsg
wxRadioButton * m_rbGerberX2
wxStaticText * m_PlatedPadsCountInfoMsg
wxCheckBox * m_Check_Merge_PTH_NPTH
wxStaticText * m_ThroughViasInfoMsg
wxStaticText * m_BuriedViasInfoMsg
wxStaticText * m_NotPlatedPadsCountInfoMsg
wxRadioBox * m_radioBoxOvalHoleMode
wxTextCtrl * m_outputDirectoryName
wxRadioBox * m_Choice_Zeros_Format
PCB_PLOT_PARAMS m_plotOpts
VECTOR2I m_DrillFileOffset
void onFileFormatSelection(wxCommandEvent &event) override
void OnSelDrillUnitsSelected(wxCommandEvent &event) override
static bool m_MinimalHeader
static bool m_Merge_PTH_NPTH
PCB_EDIT_FRAME * m_pcbEditFrame
static bool m_Mirror
DIALOG_GENDRILL(PCB_EDIT_FRAME *aPcbEditFrame, wxWindow *aParent)
void OnGenReportFile(wxCommandEvent &event) override
void GenDrillAndMapFiles(bool aGenDrill, bool aGenMap)
Call the functions to create EXCELLON drill files and/or drill map files.
void OnSelZerosFmtSelected(wxCommandEvent &event) override
void OnGenDrillFile(wxCommandEvent &event) override
static int m_UnitDrillIsInch
void UpdateDrillParams()
Update board drill/plot parameters.
static bool m_UseRouteModeForOvalHoles
static int m_ZerosFormat
void OnGenMapFile(wxCommandEvent &event) override
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
static int m_mapFileType
DRILL_PRECISION m_Precision
static int m_drillFileType
void SetupStandardButtons(std::map< int, wxString > aLabels={})
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.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
Definition: pad.h:59
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:140
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:320
void SetBitmap(const wxBitmapBundle &aBmp)
Generic, UI-independent tool event.
Definition: tool_event.h:167
A wrapper for reporting to a wxTextCtrl object.
Definition: reporter.h:138
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:334
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:362
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:58
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:280
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()
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:70
PLOT_FORMAT
The set of supported output plot formats.
Definition: plotter.h:64
std::vector< FAB_LAYER_COLOR > dummy
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.