26#include <wx/clipbrd.h>
27#include <wx/dcmemory.h>
44enum class SHAPE_CHOICE
51enum class ROUNDING_CHOICE
59bool readMm(
const wxTextCtrl* aCtrl,
int& aIU )
63 if( !std::isfinite( mm ) )
71wxString formatMm(
int aIU )
73 return wxString::Format( wxT(
"%.3g" ),
pcbIUScale.IUTomm( aIU ) );
76struct PTH_PREVIEW_OPTIONS
78 bool m_showMinLeadSize =
false;
79 bool m_showMinHoleSize =
false;
80 bool m_showMaxHoleSize =
false;
81 wxColour m_backgroundColour;
88void drawPthSizePreview( wxBitmap& aBitmap,
const PTH_LEAD_DEF& aLead,
int aHoleIU,
int aHoleMinIU,
int aHoleMaxIU,
89 int aPadIU,
const PTH_PREVIEW_OPTIONS& aOptions )
91 wxMemoryDC dc( aBitmap );
93 dc.SetBackground( aOptions.m_backgroundColour );
97 const wxColour padOutlineColor( 0x80, 0x80, 0x80 );
98 const wxColour leadColor( 0xc8, 0xc8, 0xc8 );
99 const wxColour minLeadColor( 0x80, 0x80, 0x80 );
100 const wxColour minMaxHoleColor( 0x00, 0x60, 0xf0 );
104 const int size = std::min( aBitmap.GetWidth(), aBitmap.GetHeight() );
105 const double maxFeatureIU = std::max( aPadIU, aHoleMaxIU );
107 const int outlineWidth = 1;
109 const double scale =
static_cast<double>( size - 2 * outlineWidth ) / maxFeatureIU;
110 const wxPoint centre( aBitmap.GetWidth() / 2, aBitmap.GetHeight() / 2 );
112 const auto toPx = [
scale](
int aIU ) ->
int
117 const int padRadius = toPx( aPadIU ) / 2;
118 const int holeRadius = toPx( aHoleIU ) / 2;
123 dc.DrawCircle( centre, padRadius );
125 dc.SetBrush( wxBrush( aOptions.m_backgroundColour ) );
126 dc.SetPen( wxPen( aOptions.m_backgroundColour ) );
127 dc.DrawCircle( centre, holeRadius );
131 const int leadWidth = toPx( aLead.
m_maxX );
132 const int leadHeight = toPx( isRectangular ? aLead.
m_maxY : aLead.
m_maxX );
134 dc.SetBrush( wxBrush( leadColor ) );
135 dc.SetPen( wxPen( leadColor, outlineWidth ) );
138 dc.DrawCircle( centre, leadWidth / 2 );
140 dc.DrawRectangle( centre.x - leadWidth / 2, centre.y - leadHeight / 2, leadWidth, leadHeight );
143 if( aOptions.m_showMinLeadSize )
145 const int minLeadWidth = toPx( aLead.
m_minX );
146 const int minLeadHeight = toPx( isRectangular ? aLead.
m_minY : aLead.
m_minX );
148 dc.SetBrush( *wxTRANSPARENT_BRUSH );
149 dc.SetPen( wxPen( minLeadColor, outlineWidth, wxPENSTYLE_SHORT_DASH ) );
152 dc.DrawCircle( centre, minLeadWidth / 2 );
154 dc.DrawRectangle( centre.x - minLeadWidth / 2, centre.y - minLeadHeight / 2, minLeadWidth,
158 dc.SetBrush( *wxTRANSPARENT_BRUSH );
159 const wxPen outlinePen( padOutlineColor, outlineWidth );
160 dc.SetPen( outlinePen );
161 dc.DrawCircle( centre, padRadius );
162 dc.DrawCircle( centre, holeRadius );
165 if( aOptions.m_showMinHoleSize )
167 const wxPen holeMinRangePen( minMaxHoleColor, outlineWidth, wxPENSTYLE_SHORT_DASH );
168 dc.SetPen( holeMinRangePen );
169 dc.DrawCircle( centre, toPx( aHoleMinIU ) / 2 );
172 if( aOptions.m_showMaxHoleSize )
174 const wxPen holeMaxRangePen( minMaxHoleColor, outlineWidth, wxPENSTYLE_LONG_DASH );
175 dc.SetPen( holeMaxRangePen );
176 dc.DrawCircle( centre, toPx( aHoleMaxIU ) / 2 );
180 dc.SelectObject( wxNullBitmap );
186wxBitmap makePthSizePreviewBitmap(
const PTH_LEAD_DEF& aLead,
int aHoleIU,
int aHoleMinIU,
int aHoleMaxIU,
int aPadIU,
187 bool aShowMinLeadSize,
bool aShowMinHoleSize,
bool aShowMaxHoleSize,
int aPixelSize )
192 const auto render = [&](
const wxColour& aBackground )
194 wxBitmap bitmap( aPixelSize, aPixelSize );
196 PTH_PREVIEW_OPTIONS options;
197 options.m_showMinLeadSize = aShowMinLeadSize;
198 options.m_showMinHoleSize = aShowMinHoleSize;
199 options.m_showMaxHoleSize = aShowMaxHoleSize;
200 options.m_backgroundColour = aBackground;
202 drawPthSizePreview( bitmap, aLead, aHoleIU, aHoleMinIU, aHoleMaxIU, aPadIU, options );
204 return bitmap.ConvertToImage();
207 const wxImage imageOnWhite = render( *wxWHITE );
208 const wxImage imageOnBlack = render( *wxBLACK );
214 wxLogError(
"Failed to create alpha image for PTH size preview: %s", alphaImage.error() );
215 return wxBitmap( imageOnWhite );
218 return wxBitmap( *alphaImage );
223wxString padRight(
const wxString& aText,
size_t aWidth )
225 wxString
text = aText;
227 if(
text.length() < aWidth )
228 text += wxString(
' ', aWidth -
text.length() );
242 std::vector<std::vector<wxString>> rows;
244 wxString leadShapeText;
245 wxString leadSizeText;
250 leadShapeText =
_(
"Round" );
251 leadSizeText = wxString::Format(
_(
"%s \u2013 %s mm" ), formatMm( aLead.
m_minX ), formatMm( aLead.
m_maxX ) );
255 leadShapeText =
_(
"Square" );
256 leadSizeText = wxString::Format(
_(
"%s \u2013 %s mm" ), formatMm( aLead.
m_minX ), formatMm( aLead.
m_maxX ) );
260 leadShapeText =
_(
"Rectangular" );
261 leadSizeText = wxString::Format(
_(
"%s \u2013 %s mm x %s \u2013 %s mm" ), formatMm( aLead.
m_minX ),
267 rows.push_back( {
_(
"Production level:" ), aStandard->
GetLevelName( aLevel ) } );
268 rows.push_back( {
_(
"Lead shape:" ), leadShapeText } );
269 rows.push_back( {
_(
"Lead size:" ), leadSizeText } );
271 {
_(
"Effective lead size:" ), wxString::Format(
_(
"%s \u2013 %s mm" ), formatMm( aRange.
m_leadMin ),
274 rows.push_back( { wxEmptyString } );
276 rows.push_back( {
_(
"Minimum hole size:" ), wxString::Format(
_(
"%s mm" ), formatMm( aRange.
m_holeMin ) ) } );
277 rows.push_back( {
_(
"Maximum hole size:" ), wxString::Format(
_(
"%s mm" ), formatMm( aRange.
m_holeMax ) ) } );
278 rows.push_back( {
_(
"Recommended hole size:" ), wxString::Format(
_(
"%s mm" ), formatMm( aHoleIU ) ) } );
279 rows.push_back( {
_(
"Hole clearance over max. lead:" ),
280 wxString::Format(
_(
"%s mm" ), formatMm( aHoleIU - aRange.
m_leadMax ) ) } );
281 rows.push_back( {
_(
"Annular ring:" ), wxString::Format(
_(
"%s mm" ), formatMm( aAnnularIU ) ) } );
282 rows.push_back( {
_(
"Pad diameter:" ), wxString::Format(
_(
"%s mm" ), formatMm( aPadIU ) ) } );
285 size_t labelWidth = 0;
287 for(
const auto& row : rows )
290 labelWidth = std::max( labelWidth, row[0].length() );
295 for(
const auto& row : rows )
298 text += padRight( row[0], labelWidth ) + wxT(
" " ) + row[1] + wxT(
"\n" );
300 text += row[0] + wxT(
"\n" );
310 const wxString&
name ) :
333 m_bpCopyAll->SetToolTip(
_(
"Copy the report to the clipboard" ) );
336 m_ResultReport->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
337 wxFONTWEIGHT_NORMAL,
false, wxEmptyString ) );
343 GetSizer()->SetSizeHints(
this );
411 if( selection >= 0 && selection <
static_cast<int>( standards.size() ) )
415 wxString::Format(
_(
"%s Summary" ), standards[selection]->GetDisplayName() ) );
445 const int colCount =
grid->GetNumberCols();
447 if( levelCount > colCount )
448 grid->AppendCols( levelCount - colCount );
449 else if( levelCount < colCount )
450 grid->DeleteCols( levelCount, colCount - levelCount );
452 for(
int level = 0; level < levelCount; ++level )
458 grid->SetCellValue( 0, level,
459 wxString::Format(
_(
"Maximum lead diameter + %smm" ),
462 grid->SetCellValue( 1, level,
463 wxString::Format(
_(
"Minimum lead diameter + %smm" ),
467 grid->AutoSizeColumns();
473 const SHAPE_CHOICE shape =
static_cast<SHAPE_CHOICE
>(
m_shapeChoice->GetSelection() );
474 const bool showSizeY = shape == SHAPE_CHOICE::RECTANGULAR;
478 case SHAPE_CHOICE::ROUND:
483 case SHAPE_CHOICE::SQUARE:
513 int roundingStepIU = 0;
530 valid &= readMm(
m_annularCtrl, annularIU ) && annularIU >= 0;
540 const ROUNDING_CHOICE roundingChoice =
static_cast<ROUNDING_CHOICE
>(
m_choiceRounding->GetSelection() );
547 const int pad = hole + 2 * annularIU;
570 const double scale = GetDPIScaleFactor();
572 wxBitmap bitmap = makePthSizePreviewBitmap(
576 bitmap.SetScaleFactor(
scale );
590 if( wxTheClipboard->Open() )
592 wxTheClipboard->SetData(
new wxTextDataObject(
m_ResultReport->GetValue() ) );
593 wxTheClipboard->Close();
constexpr EDA_IU_SCALE pcbIUScale
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
wxTextCtrl * m_sizeYMaxCtrl
PANEL_PTH_SIZE_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
wxTextCtrl * m_sizeRoundingCtrl
wxCheckBox * m_cbShowMinHoleSize
wxGrid * m_ipc2222Summary
wxStaticText * m_staticTextSizeYUnit
wxTextCtrl * m_padSizeCtrl
wxStaticText * m_staticTextSizeY
wxStaticText * m_staticTextSummaryTitle
wxTextCtrl * m_holeSizeCtrl
wxTextCtrl * m_sizeXMaxCtrl
wxCheckBox * m_cbShowMaxHoleSize
wxTextCtrl * m_annularCtrl
wxChoice * m_choiceRounding
wxTextCtrl * m_sizeYMinCtrl
wxStaticBitmap * m_bitmapPreview
wxTextCtrl * m_ResultReport
wxBitmapButton * m_bpCopyAll
wxStaticText * m_staticTextSizeX
wxChoice * m_standardChoice
wxCheckBox * m_cbShowMinLeadSize
wxTextCtrl * m_sizeXMinCtrl
void populateStandardChoice()
void OnPreviewSettingCb(wxCommandEvent &aEvent) override
void ThemeChanged() override
Update UI elements of the panel when the theme changes to ensure the images and fonts/colors are appr...
void SaveSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Save the settings from the panel.
void OnControlsChanged(wxCommandEvent &aEvent) override
PANEL_PTH_SIZE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void LoadSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Load the settings into the panel.
PTH_HOLE_SIZE_RESULT m_lastRange
void OnCopyReportText(wxCommandEvent &aEvent) override
void OnValueChanged(wxCommandEvent &aEvent) override
PTH_LEAD_SHAPE m_leadShape
const PTH_HOLE_SIZE_STANDARD * m_holeSizeStandard
void updateSummaryTable()
A source of hole size rules for a plated through hole.
virtual const wxString & GetDisplayName() const =0
virtual wxString GetLevelName(int aLevel) const =0
static wxColor copperColor(220, 180, 30)
double DoubleFromString(const wxString &TextValue)
int ComputeRecommendedPthHoleSize(const PTH_HOLE_SIZE_RESULT &aRange, int aRoundingStep, PTH_HOLE_ROUNDING aRounding)
Choose a recommended hole within an allowable range.
const std::vector< const PTH_HOLE_SIZE_STANDARD * > & GetPthHoleSizeStandards()
tl::expected< wxImage, std::string > CreateAlphaImageFromTwoRenders(const wxImage &aOnWhite, const wxImage &aOnBlack)
Combine two opaque renders of the same content into a single image with an alpha channel.