22#include <wx/display.h>
23#include <wx/dcclient.h>
24#include <wx/filedlg.h>
26#include <wx/settings.h>
78 wxFAIL_MSG( wxT(
"Invalid pad shape" ) );
87 return _(
"Aperture" );
100 return wxEmptyString;
108 const auto isBackOnlyPad =
109 [](
const PAD&
pad ) ->
bool
111 const LSET layers =
pad.GetLayerSet();
128 if( isBackOnlyPad( aPad ) )
154 if( isBackOnlyPad( aPad ) )
183 bool aPreserveValues )
186 const wxColour drillTextColour = drillIsEditable ? aGrid.GetDefaultCellTextColour()
187 : wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
189 aGrid.SetReadOnly( aRowId, COLS::COL_DRILL_X, !drillIsEditable );
190 aGrid.SetReadOnly( aRowId, COLS::COL_DRILL_Y, !drillIsEditable );
191 aGrid.SetCellTextColour( aRowId, COLS::COL_DRILL_X, drillTextColour );
192 aGrid.SetCellTextColour( aRowId, COLS::COL_DRILL_Y, drillTextColour );
194 if( aPreserveValues )
198 aGrid.SetCellValue( aRowId, COLS::COL_DRILL_X, drill.
x > 0 ? aUnitsProvider.
StringFromValue( drill.
x,
true )
200 aGrid.SetCellValue( aRowId, COLS::COL_DRILL_Y, drill.
y > 0 ? aUnitsProvider.
StringFromValue( drill.
y,
true )
214 case COLS::COL_NUMBER:
return wxT(
"Number" );
215 case COLS::COL_TYPE:
return wxT(
"Type" );
216 case COLS::COL_SHAPE:
return wxT(
"Shape" );
217 case COLS::COL_POS_X:
return wxT(
"Pos X" );
218 case COLS::COL_POS_Y:
return wxT(
"Pos Y" );
219 case COLS::COL_SIZE_X:
return wxT(
"Size X" );
220 case COLS::COL_SIZE_Y:
return wxT(
"Size Y" );
221 case COLS::COL_DRILL_X:
return wxT(
"Drill X" );
222 case COLS::COL_DRILL_Y:
return wxT(
"Drill Y" );
223 case COLS::COL_P2D_LENGTH:
return wxT(
"Pad to die length" );
224 case COLS::COL_P2D_DELAY:
return wxT(
"Pad to die delay" );
226 wxFAIL_MSG( wxT(
"Invalid column index" ) );
227 return wxEmptyString;
234 for(
int i = 0; i < static_cast<int>( COLS::COL_COUNT ); i++ )
241 return COLS::COL_COUNT;
262 wxCHECK_MSG( aFieldId >= 0 && aFieldId <
static_cast<int>( COLS::COL_COUNT ), wxEmptyString,
263 wxT(
"Invalid column index" ) );
300 return wxEmptyString;
306 return wxEmptyString;
309 return wxEmptyString;
312 wxFAIL_MSG(
"Invalid column index" );
313 return wxEmptyString;
322 void UpdatePad(
PAD& aPad,
const wxString& aValue,
int aFieldId )
const
415 wxFAIL_MSG(
"Invalid column index" );
432 if(
m_grid->GetNumberRows() > 0 )
448 wxGridCellAttr* attr =
nullptr;
451 attr =
new wxGridCellAttr;
452 wxArrayString typeNames;
453 typeNames.push_back(
_(
"Through-hole" ) );
454 typeNames.push_back(
_(
"SMD" ) );
455 typeNames.push_back(
_(
"Connector" ) );
456 typeNames.push_back(
_(
"NPTH" ) );
457 typeNames.push_back(
_(
"Aperture" ) );
461 attr =
new wxGridCellAttr;
473 attr =
new wxGridCellAttr;
477 attr =
new wxGridCellAttr;
481 attr =
new wxGridCellAttr;
485 attr =
new wxGridCellAttr;
490 attr =
new wxGridCellAttr;
495 attr =
new wxGridCellAttr;
531 int displayIdx = wxDisplay::GetFromWindow( aParent );
533 if( displayIdx == wxNOT_FOUND )
536 wxRect displayArea = wxDisplay( (
unsigned int) displayIdx ).GetClientArea();
537 wxSize dlgSize = GetSize();
538 int maxH = ( displayArea.height * 4 ) / 5;
540 if( dlgSize.y > maxH )
547 wxSize minSz = GetMinSize();
564 m_grid->PopEventHandler(
true );
580 if( aPad->
GetSize( aLayer ).
x != size_x )
583 if( aPad->
GetSize( aLayer ).
y != size_y )
630 m_grid->AutoSizeColumns();
637 dc.SetFont(
m_grid->GetFont() );
653 dc.GetTextExtent( str, &w, &h );
654 maxWidth = std::max( maxWidth, w );
658 int padding = FromDIP( 30 );
667 wxSizeEvent sizeEvt( GetSize(), GetId() );
671 wxSizeEvent evt( sizeEvt );
676 if(
m_grid->GetNumberRows() > 0 )
678 m_grid->SetGridCursor( 0, 0 );
681 wxGridEvent ev(
m_grid->GetId(), wxEVT_GRID_SELECT_CELL,
m_grid, 0, 0, -1, -1,
true );
693 [
this, aRowId](
int aCol )
696 wxGridCellAttr* attr =
m_grid->GetOrCreateCellAttr( aRowId, aCol );
697 attr->SetEditor( cellEditor );
755 pad->ClearBrightened();
782 for(
PAD*
pad : livePads )
849 const wxString shape =
m_grid->GetCellValue( aRowId, aCol );
870 pos.
x =
m_grid->GetUnitValue( aRowId, aCol );
872 pos.
y =
m_grid->GetUnitValue( aRowId, aCol );
881 const wxString sizeValue =
m_grid->GetCellValue( aRowId, aCol );
886 const int size =
m_grid->GetUnitValue( aRowId, aCol );
898 aPad.
SetSize( aLayer, layerSize );
912 if( drillX > 0 || drillY > 0 )
929 const wxString lenStr =
m_grid->GetCellValue( aRowId, aCol );
931 if( lenStr.IsEmpty() )
941 const wxString delayStr =
m_grid->GetCellValue( aRowId, aCol );
943 if( delayStr.IsEmpty() )
952 wxFAIL_MSG( wxT(
"Invalid column index" ) );
960 if( !
m_grid->CommitPendingChanges() )
1001 const auto applyRowDataToPad =
1002 [&](
PAD& aPad,
int aRowId )
1004 for(
int col = 0; col <
m_grid->GetNumberCols(); ++col )
1015 applyRowDataToPad( *
pad, row );
1022 applyRowDataToPad( *
pad, row );
1035 commit.
Push(
_(
"Edit Pads" ) );
1053 int cols =
m_grid->GetNumberCols();
1055 std::vector<int> widths;
1056 widths.reserve( cols );
1058 for(
int c = 0; c < cols; ++c )
1060 int w =
m_grid->GetColSize( c );
1061 widths.push_back( w );
1068 for(
int w : widths )
1085 int cols =
m_grid->GetNumberCols();
1088 for(
int c = 0; c < cols; ++c )
1089 available +=
m_grid->GetColSize( c );
1092 int clientW =
m_grid->GetClientSize().x;
1095 available = clientW;
1099 for(
int c = 0; c < cols; ++c )
1108 m_grid->SetColSize( c, target );
1127 int row = aEvent.GetRow();
1128 int col = aEvent.GetCol();
1139 bool needCanvasRefresh =
true;
1147 if( drillsAreEditable )
1155 if( drillX > 0 || drillY > 0 )
1159 else if( !drillsWereEditable )
1163 const int defaultDrill =
pcbIUScale.mmToIU( 1.0 );
1164 target->
SetDrillSize( { defaultDrill, defaultDrill } );
1173 needCanvasRefresh =
false;
1182 if( needCanvasRefresh )
1192 base->GetCanvas()->ForceRefresh();
1200 int row = aEvent.GetRow();
1211 if(
pad->IsBrightened() )
1213 pad->ClearBrightened();
1225 pad->SetBrightened();
1241 int row =
m_grid->GetGridCursorRow();
1242 int col =
m_grid->GetGridCursorCol();
1249 wxGridCellEditor*
editor =
m_grid->GetCellEditor( row, col );
1278 if(
pad->GetNumber().Length() )
1282 const wxString summary = pinNumbers.
GetSummary();
1297 if( aRowId < 0 ||
static_cast<size_t>( aRowId ) >=
m_rowPads.size() )
1312 wxFileName fn(
m_footprint->GetFPID().GetLibItemName() );
1316 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1320 if( dlg.ShowModal() == wxID_CANCEL )
1323 filePath = dlg.GetPath();
1326 std::vector<PAD*> padsToExport;
1327 bool complexPadstacks =
false;
1333 complexPadstacks =
true;
1337 padsToExport.push_back(
pad );
1340 if( complexPadstacks )
1342 if( wxMessageBox(
_(
"Complex padstacks cannot be exported via CSV.\n\nThey will be skipped." ),
1343 _(
"Export Pad Table" ), wxOK | wxCANCEL | wxICON_WARNING,
this ) != wxOK )
1349 static const std::vector<COLS> exportCols {
1359 COLS::COL_P2D_LENGTH,
1360 COLS::COL_P2D_DELAY,
1366 std::vector<std::vector<wxString>>
table;
1367 table.reserve( padsToExport.size() + 1 );
1369 std::vector<wxString> header;
1370 header.reserve( exportCols.size() );
1372 for(
COLS col : exportCols )
1375 table.emplace_back( std::move( header ) );
1377 for(
PAD*
pad : padsToExport )
1379 std::vector<wxString>& row =
table.emplace_back();
1380 row.reserve( exportCols.size() );
1382 for(
COLS col : exportCols )
1383 row.emplace_back( formatter.
Format( *
pad, col ) );
1412 std::map<wxString, std::vector<PAD*>> padsByNumber;
1415 padsByNumber[
pad->GetNumber()].push_back(
pad );
1421 std::vector<std::unique_ptr<PAD>> createdPads;
1423 if( csvData && csvData->size() >= 2 )
1425 std::vector<COLS> headerCols;
1426 wxArrayString unknownHeaders;
1427 std::optional<size_t> numberColIdx;
1429 for(
const wxString& label : ( *csvData )[0] )
1433 if( col >= COLS::COL_COUNT )
1434 unknownHeaders.push_back( label );
1436 if( col == COLS::COL_NUMBER )
1437 numberColIdx = headerCols.size();
1439 headerCols.push_back( col );
1442 if( replaceAll && !numberColIdx.has_value() )
1444 wxString msg =
_(
"Imported pad data must include pad numbers." );
1445 wxMessageBox( msg,
_(
"Import error" ), wxOK | wxICON_ERROR,
this );
1449 if( !unknownHeaders.IsEmpty() )
1451 wxString msg = wxString::Format(
_(
"Unknown columns in data: %s. These columns will be ignored." ),
1458 int ret = wxMessageBox(
reporter.GetMessages(),
_(
"Errors" ), wxOK | wxCANCEL | wxICON_ERROR,
this );
1460 if( ret == wxCANCEL )
1464 for(
size_t i = 1; i < csvData->size(); ++i )
1466 const std::vector<wxString>& cols = ( *csvData )[i];
1470 std::unique_ptr<PAD> newPad;
1471 PAD* padToUpdate =
nullptr;
1473 const size_t numberCol = numberColIdx.value_or( cols.size() );
1475 if( replaceAll && numberCol < cols.size() && !cols[numberCol].IsEmpty() )
1477 auto bucketIt = padsByNumber.find( cols[numberCol] );
1479 if( bucketIt != padsByNumber.end() && !bucketIt->second.empty() )
1481 padToUpdate = bucketIt->second.front();
1482 bucketIt->second.erase( bucketIt->second.begin() );
1490 padToUpdate = newPad.get();
1493 size_t maxCol = std::min( headerCols.size(), cols.size() );
1495 for(
size_t j = 0; j < maxCol; ++j )
1497 if( headerCols[j] == COLS::COL_COUNT )
1500 fmt.
UpdatePad( *padToUpdate, cols[j], headerCols[j] );
1512 createdPads.push_back( std::move( newPad ) );
1516 if( !createdPads.empty() )
1520 std::vector<KIGFX::VIEW_ITEM*> viewPads;
1522 for(
const auto&
pad : createdPads )
1523 viewPads.push_back(
pad.get() );
1528 for( std::unique_ptr<PAD>&
pad : createdPads )
1537 for(
const auto& [number, pads] : padsByNumber )
1554 m_grid->CommitPendingChanges();
1565 int currentRows =
m_grid->GetNumberRows();
1566 int neededRows =
static_cast<int>(
m_rowPads.size() );
1568 if( neededRows > currentRows )
1569 m_grid->AppendRows( neededRows - currentRows );
1570 else if( neededRows < currentRows )
1571 m_grid->DeleteRows( neededRows, currentRows - neededRows );
1591 [&]() -> std::pair<int, int>
1593 PAD* newPad =
nullptr;
1599 newPad =
static_cast<PAD*
>(
m_rowPads.back()->Duplicate(
false,
nullptr ) );
1608 view->
Add( newPad );
1613 int row =
m_grid->GetNumberRows();
1638 if( row < 0 ||
static_cast<size_t>( row ) >=
m_rowPads.size() )
1643 pad->ClearBrightened();
1654 m_grid->DeleteRows( row, 1 );
constexpr EDA_IU_SCALE pcbIUScale
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
wxButton * m_btnImportFromFile
DIALOG_FP_EDIT_PAD_TABLE_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Pad Table"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
wxStaticText * m_pin_numbers_summary
STD_BITMAP_BUTTON * m_buttonDelete
STD_BITMAP_BUTTON * m_buttonAdd
wxRadioButton * m_rbReplaceExisting
wxButton * m_btnExportToFile
wxStaticText * m_duplicate_pins
wxStaticText * m_pin_count
void setPadFromGridCell(PAD &aPad, int aRowId, COLS aCol)
PAD * getPadForRow(int aRowId) const
void OnCellChanged(wxGridEvent &aEvent) override
DIALOG_FP_EDIT_PAD_TABLE(PCB_BASE_FRAME *aParent, FOOTPRINT *aFootprint)
void OnCharHook(wxKeyEvent &aEvent) override
void fillGridRow(int aRowId, PAD *aPad)
void CaptureOriginalPadState()
void OnSelectCell(wxGridEvent &aEvent) override
void InitColumnProportions()
void setRowNullableEditors(int aRowId) const
bool TransferDataFromWindow() override
bool TransferDataToWindow() override
void restoreOriginalPadData()
void OnImportButtonClick(wxCommandEvent &aEvent) override
std::vector< PAD * > m_rowPads
bool m_accepted
Set when the changes are committed on OK.
void OnExportButtonClick(wxCommandEvent &aEvent) override
std::map< PAD *, PAD_SNAPSHOT > m_originalPads
void OnDeleteRow(wxCommandEvent &aEvent) override
std::vector< int > m_minColWidths
void OnSize(wxSizeEvent &aEvent) override
void restorePadFromSnapshot(PAD &aPad, const PAD_SNAPSHOT &aSnap) const
~DIALOG_FP_EDIT_PAD_TABLE() override
void OnCancel(wxCommandEvent &aEvent) override
void RestoreOriginalPadState()
std::vector< double > m_colProportions
std::unique_ptr< UNITS_PROVIDER > m_unitsProvider
void OnUpdateUI(wxUpdateUIEvent &aEvent) override
std::vector< PAD * > m_removedPads
void OnAddRow(wxCommandEvent &aEvent) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void OnCharHook(wxKeyEvent &aEvt)
EDA_UNITS GetUserUnits() const
void ForceRefresh()
Force a redraw.
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
This class works around a bug in wxGrid where the first keystroke doesn't get sent through the valida...
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
const VECTOR2D & GetGridSize() const
Return the grid size.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
void AddBatch(const std::vector< VIEW_ITEM * > &aItems)
Add a batch of items to the view, using bulk-loaded R-trees for initial population.
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
LSET is a set of PCB_LAYER_IDs.
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
LSET & FlipStandardLayers(int aCopperLayersCount=0)
Flip the layers in this set.
A singleton reporter that reports to nowhere.
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
@ NORMAL
Shape is the same on all layers.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
bool IsAperturePad() const
void SetAttribute(PAD_ATTRIB aAttribute)
static wxString ShowPadShape(PAD_SHAPE aShape)
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
VECTOR2I GetPosition() const override
void Move(const VECTOR2I &aMoveVector) override
Move this object.
VECTOR2I GetDrillSize() const
void SetPadToDieDelay(int aDelay)
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
int GetPadToDieDelay() const
void SetPadstack(const PADSTACK &aPadstack)
void SetPosition(const VECTOR2I &aPos) override
const PADSTACK & Padstack() const
void SetDrillSize(const VECTOR2I &aSize)
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
static LSET SMDMask()
layer set for a SMD pad on Front layer
void SetLayerSet(const LSET &aLayers) override
void SetPadToDieLength(int aLength)
int GetPadToDieLength() const
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the KIGFX::VIEW instance used in the panel.
wxString GetDuplicates() const
Gets a formatted string of all the pins that have duplicate numbers.
void insert(value_type const &v)
wxString GetSummary() const
A pure virtual class used to derive REPORTER objects from.
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
A wrapper for reporting to a wxString object.
static void UpdateDrillCells(WX_GRID &aGrid, UNITS_PROVIDER &aUnitsProvider, int aRowId, const PAD &aPad, bool aPreserveValues)
Update the drill size cells in the pad table for a given pad.
static COLS GetColTypeForString(const wxString &aStr)
static wxString GetPadTableColLabel(COLS aCol)
Get the label for a given column in the pin table.
static wxString GetPadTypeString(const PAD &aPad)
static PAD_SHAPE ShapeFromString(const wxString &shape)
static bool DrillsAreEditable(const PAD &aPad)
static wxString ShapeToString(PAD_SHAPE shape)
static void SetPadTypeFromString(PAD &aPad, const wxString &aType)
DIALOG_FP_EDIT_PAD_TABLE::COLS COLS
static COL_ORDER GetColTypeForString(const wxString &aStr)
static std::map< int, wxString > shapeNames
static const std::string CsvFileExtension
static wxString CsvTsvFileWildcard()
PCB_LAYER_ID
A quick note on layer IDs:
@ REPAINT
Item needs to be redrawn.
@ LAYERS
Layers have changed.
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
void AccumulateDescriptions(wxString &aDesc, const T &aItemCollection)
Build a comma-separated list from a collection of wxStrings.
void WriteTableToFileOrClipboard(const wxString &aToFile, const std::vector< std::vector< wxString > > &aTable)
Write aTable as CSV to aToFile (if non-empty) or to the system clipboard.
std::optional< std::vector< std::vector< wxString > > > ReadTableFromFileOrClipboard(EDA_BASE_FRAME &aFrame, bool aFromFile)
Read a CSV/TSV table from a file selected via a dialog (aFromFile) or from the system clipboard.
IbisParser parser & reporter
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
VECTOR2< int32_t > VECTOR2I
Definition of file extensions used in Kicad.