KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_board_statistics.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) 2019 Alexander Shuklin, [email protected]
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
27#include <board_statistics.h>
28
29#include <algorithm>
30
31#include <wx/filedlg.h>
32
33#include <board.h>
34#include <kiplatform/ui.h>
35#include <confirm.h>
36#include <pad.h>
37#include <pcb_edit_frame.h>
38#include <macros.h>
39#include <string_utils.h>
41#include <widgets/ui_common.h>
42#include <widgets/wx_grid.h>
44#include <algorithm>
45
46
47
48
49#define COL_LABEL 0
50#define COL_AMOUNT 1
51
52// Defines for components view
53#define ROW_LABEL 0
54#define COL_FRONT_SIDE 1
55#define COL_BOTTOM_SIDE 2
56#define COL_TOTAL 3
57
58// Defines for board view
59#define ROW_BOARD_DIMS 0
60#define ROW_BOARD_AREA 1
61#define ROW_FRONT_COPPER_AREA 2
62#define ROW_BACK_COPPER_AREA 3
63#define ROW_MIN_CLEARANCE 4
64#define ROW_MIN_TRACK_WIDTH 5
65#define ROW_MIN_DRILL_DIAMETER 6
66#define ROW_BOARD_THICKNESS 7
67#define ROW_FOOTPRINT_COURTYARD_FRONT_AREA 8
68#define ROW_FRONT_COMPONENT_DENSITY 9
69#define ROW_FOOTPRINT_COURTYARD_BACK_AREA 10
70#define ROW_BACK_COMPONENT_DENSITY 11
71
72
77{
85
86 // Flags to remember last checkboxes state
90
91 // Variables to save last report file name and folder
92 bool saveReportInitialized; // true after the 3 next string are initialized
93 wxString saveReportFolder; // last report folder
94 wxString saveReportName; // last report filename
95 wxString m_project; // name of the project used to create the last report
96 // used to reinit last state after a project change
97};
98
99
101
103 DIALOG_BOARD_STATISTICS_BASE( aParentFrame ),
104 m_frame( aParentFrame ),
107{
108 m_gridDrills->Connect( wxEVT_GRID_COL_SORT,
109 wxGridEventHandler( DIALOG_BOARD_STATISTICS::drillGridSort ),
110 nullptr, this );
111
112 m_checkBoxExcludeComponentsNoPins->SetValue( s_savedDialogState.excludeNoPins );
113 m_checkBoxSubtractHoles->SetValue( s_savedDialogState.subtractHoles );
114 m_checkBoxSubtractHolesFromCopper->SetValue( s_savedDialogState.subtractHolesFromCopper );
115
116 wxFont labelFont = KIUI::GetSmallInfoFont( this );
117 m_componentsLabel->SetFont( labelFont );
118 m_boardLabel->SetFont( labelFont );
119 m_padsLabel->SetFont( labelFont );
120 m_viasLabel->SetFont( labelFont );
121
122 // Make labels for grids
123 m_gridComponents->SetCellValue( ROW_LABEL, COL_FRONT_SIDE, _( "Front Side" ) );
124 m_gridComponents->SetCellValue( ROW_LABEL, COL_BOTTOM_SIDE, _( "Back Side" ) );
125 m_gridComponents->SetCellValue( ROW_LABEL, COL_TOTAL, _( "Total" ) );
126
127 wxFont headingFont = KIUI::GetStatusFont( this );
128
129 for( int col = COL_AMOUNT; col < m_gridComponents->GetNumberCols(); col++ )
130 m_gridComponents->SetCellFont( ROW_LABEL, col, headingFont );
131
132 m_gridBoard->SetCellValue( ROW_BOARD_DIMS, COL_LABEL, _( "Dimensions:" ) );
133 m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_LABEL, _( "Area:" ) );
134 m_gridBoard->SetCellValue( ROW_FRONT_COPPER_AREA, COL_LABEL, _( "Front copper area:" ) );
135 m_gridBoard->SetCellValue( ROW_BACK_COPPER_AREA, COL_LABEL, _( "Back copper area:" ) );
136 m_gridBoard->SetCellValue( ROW_MIN_CLEARANCE, COL_LABEL, _( "Min track clearance:" ) );
137 m_gridBoard->SetCellValue( ROW_MIN_TRACK_WIDTH, COL_LABEL, _( "Min track width:" ) );
138 m_gridBoard->SetCellValue( ROW_MIN_DRILL_DIAMETER, COL_LABEL, _( "Min drill diameter:" ) );
139 m_gridBoard->SetCellValue( ROW_BOARD_THICKNESS, COL_LABEL, _( "Board stackup thickness:" ) );
140 m_gridBoard->SetCellValue( ROW_FOOTPRINT_COURTYARD_FRONT_AREA, COL_LABEL, _( "Front footprint area:" ) );
141 m_gridBoard->SetCellValue( ROW_FRONT_COMPONENT_DENSITY, COL_LABEL, _( "Front footprint density:" ) );
142 m_gridBoard->SetCellValue( ROW_FOOTPRINT_COURTYARD_BACK_AREA, COL_LABEL, _( "Back footprint area:" ) );
143 m_gridBoard->SetCellValue( ROW_BACK_COMPONENT_DENSITY, COL_LABEL, _( "Back footprint density:" ) );
144
146 {
147 // Remove wxgrid's selection boxes
148 grid->SetCellHighlightPenWidth( 0 );
149 grid->SetColMinimalAcceptableWidth( 80 );
150
151 for( int row = 0; row < grid->GetNumberRows(); row++ )
152 {
153 grid->SetCellAlignment( row, COL_LABEL, wxALIGN_LEFT, wxALIGN_CENTRE );
154
155 for( int col = COL_AMOUNT; col < grid->GetNumberCols(); col++ )
156 grid->SetCellAlignment( row, col, wxALIGN_RIGHT, wxALIGN_CENTER );
157 }
158 }
159
160 wxFileName fn = m_frame->GetBoard()->GetFileName();
161
162 if( !s_savedDialogState.saveReportInitialized
163 || s_savedDialogState.m_project != Prj().GetProjectFullName() )
164 {
165 fn.SetName( fn.GetName() + wxT( "_report" ) );
166 fn.SetExt( wxT( "txt" ) );
167 s_savedDialogState.saveReportName = fn.GetFullName();
168 s_savedDialogState.saveReportFolder = wxPathOnly( Prj().GetProjectFullName() );
170 s_savedDialogState.saveReportInitialized = true;
171 }
172
173 // The wxStdDialogButtonSizer wxID_CANCLE button is in fact a close button
174 // Nothing to cancel:
175 m_sdbControlSizerCancel->SetLabel( _( "Close" ) );
176}
177
178
180{
182
183 int appendRows = static_cast<int>( m_statsData.footprintEntries.size() ) + 2 - m_gridComponents->GetNumberRows();
184
185 if( appendRows > 0 )
186 m_gridComponents->AppendRows( appendRows );
187
188 appendRows = static_cast<int>( m_statsData.padEntries.size() ) + 1
189 + static_cast<int>( m_statsData.padPropertyEntries.size() ) - m_gridPads->GetNumberRows();
190
191 if( appendRows > 0 )
192 m_gridPads->AppendRows( appendRows );
193
194 appendRows = static_cast<int>( m_statsData.viaEntries.size() ) + 1 - m_gridVias->GetNumberRows();
195
196 if( appendRows > 0 )
197 m_gridVias->AppendRows( appendRows );
198}
199
200
202{
206
207 Layout();
208 m_drillsPanel->Layout();
209
210 m_gridDrills->AutoSizeColumns();
213
214 // Add space for the vertical scrollbar, so that it won't overlap with the cells.
215 m_gridDrills->SetMinSize( wxSize( m_gridDrills->GetEffectiveMinSize().x
216 + wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ),
217 60 ) );
218
220
222 return true;
223}
224
225
227{
232
233 ComputeBoardStatistics( m_frame->GetBoard(), options, m_statsData );
234
235 m_gridDrills->ClearRows();
236
237 if( !m_statsData.drillEntries.empty() )
238 m_gridDrills->AppendRows( static_cast<int>( m_statsData.drillEntries.size() ) );
239}
240
241
242static wxString formatCount( int aCount )
243{
244 return wxString::Format( wxT( "%i" ), aCount );
245};
246
247
249{
250 int totalPads = 0;
251 int row = 0;
252
253 for( const BOARD_STATISTICS_INFO_ENTRY<PAD_ATTRIB>& line : m_statsData.padEntries )
254 {
255 m_gridPads->SetCellValue( row, COL_LABEL, line.title );
256 m_gridPads->SetCellValue( row, COL_AMOUNT, formatCount( line.quantity ) );
257 totalPads += line.quantity;
258 row++;
259 }
260
261 m_gridPads->SetCellValue( row, COL_LABEL, _( "Total:" ) );
262 m_gridPads->SetCellValue( row, COL_AMOUNT, formatCount( totalPads ) );
263 row++;
264
265 for( const BOARD_STATISTICS_INFO_ENTRY<PAD_PROP>& line : m_statsData.padPropertyEntries )
266 {
267 m_gridPads->SetCellValue( row, COL_LABEL, line.title );
268 m_gridPads->SetCellValue( row, COL_AMOUNT, formatCount( line.quantity ) );
269 row++;
270 }
271
272 int totalVias = 0;
273 row = 0;
274
275 for( const BOARD_STATISTICS_INFO_ENTRY<VIATYPE>& line : m_statsData.viaEntries )
276 {
277 m_gridVias->SetCellValue( row, COL_LABEL, line.title );
278 m_gridVias->SetCellValue( row, COL_AMOUNT, formatCount( line.quantity ) );
279 totalVias += line.quantity;
280 row++;
281 }
282
283 m_gridVias->SetCellValue( row, COL_LABEL, _( "Total:" ) );
284 m_gridVias->SetCellValue( row, COL_AMOUNT, formatCount( totalVias ) );
285
286
287 int totalFront = 0;
288 int totalBack = 0;
289
290 // We don't use row 0, as there labels are
291 row = 1;
292
293 for( const BOARD_STATISTICS_FP_ENTRY& line : m_statsData.footprintEntries )
294 {
295 m_gridComponents->SetCellValue( row, COL_LABEL, line.title );
296 m_gridComponents->SetCellValue( row, COL_FRONT_SIDE, formatCount( line.frontCount ) );
297 m_gridComponents->SetCellValue( row, COL_BOTTOM_SIDE, formatCount( line.backCount ) );
298 m_gridComponents->SetCellValue( row, 3, formatCount( line.frontCount + line.backCount ) );
299 totalFront += line.frontCount;
300 totalBack += line.backCount;
301 row++;
302 }
303
304 m_gridComponents->SetCellValue( row, COL_LABEL, _( "Total:" ) );
305 m_gridComponents->SetCellValue( row, COL_FRONT_SIDE, formatCount( totalFront ) );
306 m_gridComponents->SetCellValue( row, COL_BOTTOM_SIDE, formatCount( totalBack ) );
307 m_gridComponents->SetCellValue( row, COL_TOTAL, formatCount( totalFront + totalBack ) );
308
309 if( m_statsData.hasOutline )
310 {
311 m_gridBoard->SetCellValue( ROW_BOARD_DIMS, COL_AMOUNT,
312 wxString::Format( wxT( "%s x %s" ),
313 m_frame->MessageTextFromValue( m_statsData.boardWidth, false ),
314 m_frame->MessageTextFromValue( m_statsData.boardHeight, true ) ) );
315 m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_AMOUNT,
316 m_frame->MessageTextFromValue( m_statsData.boardArea, true, EDA_DATA_TYPE::AREA ) );
317
319 wxString::Format( "%.2f %%", m_statsData.frontFootprintDensity ) );
320
322 wxString::Format( "%.2f %%", m_statsData.backFootprintDensity ) );
323 }
324 else
325 {
326 m_gridBoard->SetCellValue( ROW_BOARD_DIMS, COL_AMOUNT, _( "unknown" ) );
327 m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_AMOUNT, _( "unknown" ) );
328 }
329
330 m_gridBoard->SetCellValue(
332 m_frame->MessageTextFromValue( m_statsData.frontFootprintCourtyardArea, true, EDA_DATA_TYPE::AREA ) );
333
334 m_gridBoard->SetCellValue(
336 m_frame->MessageTextFromValue( m_statsData.backFootprintCourtyardArea, true, EDA_DATA_TYPE::AREA ) );
337
338 m_gridBoard->SetCellValue(
340 m_frame->MessageTextFromValue( m_statsData.frontCopperArea, true, EDA_DATA_TYPE::AREA ) );
342 m_frame->MessageTextFromValue( m_statsData.backCopperArea, true, EDA_DATA_TYPE::AREA ) );
343
344 m_gridBoard->SetCellValue(
346 m_frame->MessageTextFromValue( m_statsData.minClearanceTrackToTrack, true, EDA_DATA_TYPE::DISTANCE ) );
347
348 m_gridBoard->SetCellValue(
350 m_frame->MessageTextFromValue( m_statsData.minTrackWidth, true, EDA_DATA_TYPE::DISTANCE ) );
351
352 m_gridBoard->SetCellValue(
354 m_frame->MessageTextFromValue( m_statsData.boardThickness, true, EDA_DATA_TYPE::DISTANCE ) );
355
357
358 m_gridBoard->SetCellValue(
360 m_frame->MessageTextFromValue( m_statsData.minDrillSize, true, EDA_DATA_TYPE::DISTANCE ) );
361
362 m_gridComponents->AutoSize();
363 m_gridPads->AutoSize();
364 m_gridBoard->AutoSize();
365 m_gridVias->AutoSize();
366
368}
369
370
372{
373 BOARD* board = m_frame->GetBoard();
374 int row = 0;
375
376 for( const DRILL_LINE_ITEM& line : m_statsData.drillEntries )
377 {
378 wxString shapeStr;
379 wxString startLayerStr;
380 wxString stopLayerStr;
381
382 switch( line.shape )
383 {
384 case PAD_DRILL_SHAPE::CIRCLE: shapeStr = _( "Round" ); break;
385 case PAD_DRILL_SHAPE::OBLONG: shapeStr = _( "Slot" ); break;
386 default: shapeStr = _( "???" ); break;
387 }
388
389 if( line.startLayer == UNDEFINED_LAYER )
390 startLayerStr = _( "N/A" );
391 else
392 startLayerStr = board->GetLayerName( line.startLayer );
393
394 if( line.stopLayer == UNDEFINED_LAYER )
395 stopLayerStr = _( "N/A" );
396 else
397 stopLayerStr = board->GetLayerName( line.stopLayer );
398
399 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_COUNT, formatCount( line.m_Qty ) );
400 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_SHAPE, shapeStr );
401 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_X_SIZE, m_frame->MessageTextFromValue( line.xSize ) );
402 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_Y_SIZE, m_frame->MessageTextFromValue( line.ySize ) );
403 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_PLATED, line.isPlated ? _( "PTH" ) : _( "NPTH" ) );
404 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_VIA_PAD, line.isPad ? _( "Pad" ) : _( "Via" ) );
405 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_START_LAYER, startLayerStr );
406 m_gridDrills->SetCellValue( row, DRILL_LINE_ITEM::COL_STOP_LAYER, stopLayerStr );
407
408 row++;
409 }
410}
411
412
414{
415 wxGridUpdateLocker deferRepaintsTillLeavingScope( m_gridDrills );
416
417 m_gridDrills->EnsureColLabelsVisible();
418
419 double remainingWidth = KIPLATFORM::UI::GetUnobscuredSize( m_gridDrills ).x;
420
421 // Find the total current width
422 for( int i = 0; i < m_gridDrills->GetNumberCols(); i++ )
423 {
425 remainingWidth -= m_gridDrills->GetColSize( i );
426 }
427
428 double scalingFactor = std::max( 1.0,
430 int startLayerColWidth = static_cast<int>( m_startLayerColInitialSize * scalingFactor );
431 int stopLayerColWidth = static_cast<int>( m_stopLayerColInitialSize * scalingFactor );
432
433 m_gridDrills->SetColSize( DRILL_LINE_ITEM::COL_START_LAYER, startLayerColWidth );
434 m_gridDrills->SetColSize( DRILL_LINE_ITEM::COL_STOP_LAYER, stopLayerColWidth );
435}
436
437
438void DIALOG_BOARD_STATISTICS::checkboxClicked( wxCommandEvent& aEvent )
439{
440 s_savedDialogState.excludeNoPins = m_checkBoxExcludeComponentsNoPins->GetValue();
441 s_savedDialogState.subtractHoles = m_checkBoxSubtractHoles->GetValue();
442 s_savedDialogState.subtractHolesFromCopper = m_checkBoxSubtractHolesFromCopper->GetValue();
446 Layout();
447 m_drillsPanel->Layout();
448}
449
450
451void DIALOG_BOARD_STATISTICS::saveReportClicked( wxCommandEvent& aEvent )
452{
453 FILE* outFile;
454 wxString msg;
455 wxString boardName;
456
457 wxFileName fn = m_frame->GetBoard()->GetFileName();
458 boardName = fn.GetName();
459 wxFileDialog dlg( this, _( "Save Report File" ), s_savedDialogState.saveReportFolder,
461 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
462
464
465 if( dlg.ShowModal() == wxID_CANCEL )
466 return;
467
468 s_savedDialogState.saveReportFolder = wxPathOnly( dlg.GetPath() );
469 s_savedDialogState.saveReportName = dlg.GetFilename();
470
471 outFile = wxFopen( dlg.GetPath(), wxT( "wt" ) );
472
473 if( outFile == nullptr )
474 {
475 msg.Printf( _( "Failed to create file '%s'." ), dlg.GetPath() );
476 DisplayErrorMessage( this, msg );
477 return;
478 }
479
480 const UNITS_PROVIDER& unitsProvider = *m_frame;
481 wxString report = FormatBoardStatisticsReport( m_statsData, m_frame->GetBoard(), unitsProvider,
482 Prj().GetProjectName(), boardName );
483
484 if( fprintf( outFile, "%s", TO_UTF8( report ) ) < 0 )
485 {
486 msg.Printf( _( "Error writing file '%s'." ), dlg.GetPath() );
487 DisplayErrorMessage( this, msg );
488 }
489
490 fclose( outFile );
491}
492
493
494void DIALOG_BOARD_STATISTICS::drillGridSize( wxSizeEvent& aEvent )
495{
496 aEvent.Skip();
498}
499
500void DIALOG_BOARD_STATISTICS::drillGridSort( wxGridEvent& aEvent )
501{
502 DRILL_LINE_ITEM::COL_ID colId = static_cast<DRILL_LINE_ITEM::COL_ID>( aEvent.GetCol() );
503 bool ascending = !( m_gridDrills->IsSortingBy( colId )
504 && m_gridDrills->IsSortOrderAscending() );
505
506 sort( m_statsData.drillEntries.begin(), m_statsData.drillEntries.end(),
507 DRILL_LINE_ITEM::COMPARE( colId, ascending ) );
508
510}
511
512
void ComputeBoardStatistics(BOARD *aBoard, const BOARD_STATISTICS_OPTIONS &aOptions, BOARD_STATISTICS_DATA &aData)
static wxString formatCount(int aCount)
wxString FormatBoardStatisticsReport(const BOARD_STATISTICS_DATA &aData, BOARD *aBoard, const UNITS_PROVIDER &aUnitsProvider, const wxString &aProjectName, const wxString &aBoardName)
void InitializeBoardStatisticsData(BOARD_STATISTICS_DATA &aData)
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:729
DIALOG_BOARD_STATISTICS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Board Statistics"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void checkboxClicked(wxCommandEvent &aEvent) override
Save board statistics to a file.
int m_startLayerColInitialSize
Width of the start layer column as calculated by the wxWidgets autosizing algorithm.
void updateWidgets()
Update drills grid.
void saveReportClicked(wxCommandEvent &aEvent) override
~DIALOG_BOARD_STATISTICS()
Get data from the PCB board and print it to dialog.
int m_stopLayerColInitialSize
Width of the stop layer column.
DIALOG_BOARD_STATISTICS(PCB_EDIT_FRAME *aParentFrame)
void drillGridSort(wxGridEvent &aEvent)
void refreshItemsTypes()
< Function to fill up all items types to be shown in the dialog.
void drillGridSize(wxSizeEvent &aEvent) override
BOARD_STATISTICS_DATA m_statsData
void getDataFromPCB()
Apply data to dialog widgets.
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
The main frame for Pcbnew.
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:171
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
This file is part of the common library.
static DIALOG_BOARD_STATISTICS_SAVED_STATE s_savedDialogState
#define ROW_FOOTPRINT_COURTYARD_FRONT_AREA
#define ROW_BOARD_AREA
#define ROW_BOARD_THICKNESS
#define COL_AMOUNT
#define ROW_FRONT_COMPONENT_DENSITY
#define ROW_LABEL
#define ROW_BACK_COMPONENT_DENSITY
#define COL_BOTTOM_SIDE
#define ROW_BACK_COPPER_AREA
#define ROW_MIN_TRACK_WIDTH
#define COL_LABEL
#define COL_TOTAL
#define ROW_MIN_DRILL_DIAMETER
#define ROW_FRONT_COPPER_AREA
#define ROW_BOARD_DIMS
static wxString formatCount(int aCount)
#define COL_FRONT_SIDE
#define ROW_MIN_CLEARANCE
#define ROW_FOOTPRINT_COURTYARD_BACK_AREA
#define _(s)
static wxString TextFileWildcard()
@ UNDEFINED_LAYER
Definition layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition wxgtk/ui.cpp:281
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
int quantity
wxString title
PCB_LAYER_ID stopLayer
PAD_DRILL_SHAPE shape
PCB_LAYER_ID startLayer
Functions to provide common constants and other functions to assist in making a consistent UI.
Definition of file extensions used in Kicad.