KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_footprint_properties_fp_editor.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2015 Dick Hollenbeck, [email protected]
6 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
24
25#include <optional>
26
27#include <wx/debug.h>
28#include <wx/tokenzr.h>
29
32#include <bitmaps.h>
33#include <board.h>
34#include <board_commit.h>
36#include <confirm.h>
37#include <core/kicad_algo.h>
38
41#include <embedded_files.h>
42#include <filename_resolver.h>
43#include <footprint.h>
45#include <pad.h>
48#include <layer_utils.h>
49#include <kiplatform/ui.h>
52#include <pgm_base.h>
54#include <template_fieldnames.h>
55#include <tool/tool_manager.h>
56#include <tools/pcb_actions.h>
58#include <validators.h>
62#include <widgets/wx_grid.h>
63#include <zone.h>
64
66#include <project_pcb.h>
67#include <kidialog.h>
68
69
70class LAYERS_GRID_TABLE : public WX_GRID_TABLE_BASE, public std::vector<PCB_LAYER_ID>
71{
72public:
73 LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame, const LSET& aForbiddenLayers );
75
76 int GetNumberRows() override { return (int) size(); }
77 int GetNumberCols() override { return 1; }
78
79 bool CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
80 bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
81 wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) override;
82
83 wxString GetValue( int aRow, int aCol ) override;
84 long GetValueAsLong( int aRow, int aCol ) override;
85
86 void SetValue( int aRow, int aCol, const wxString& aValue ) override;
87 void SetValueAsLong( int aRow, int aCol, long aValue ) override;
88
89private:
91 wxGridCellAttr* m_layerColAttr;
92};
93
94
95LAYERS_GRID_TABLE::LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame, const LSET& aForbiddenLayers ) :
96 m_frame( aFrame )
97{
98 m_layerColAttr = new wxGridCellAttr;
99 m_layerColAttr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_frame ) );
100
101 m_layerColAttr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_frame, aForbiddenLayers, true ) );
102}
103
104
109
110
111bool LAYERS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
112{
113 return aTypeName == wxGRID_VALUE_NUMBER;
114}
115
116
117bool LAYERS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
118{
119 return aTypeName == wxGRID_VALUE_NUMBER;
120}
121
122
123wxGridCellAttr* LAYERS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
124{
125 m_layerColAttr->IncRef();
126 return enhanceAttr( m_layerColAttr, aRow, aCol, aKind );
127}
128
129
130wxString LAYERS_GRID_TABLE::GetValue( int aRow, int aCol )
131{
132 return m_frame->GetBoard()->GetLayerName( this->at( (size_t) aRow ) );
133}
134
135
136long LAYERS_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
137{
138 return this->at( (size_t) aRow );
139}
140
141
142void LAYERS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString& aValue )
143{
144 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
145}
146
147
148void LAYERS_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
149{
150 this->at( (size_t) aRow ) = ToLAYER_ID( (int) aValue );
151}
152
153
154// Remember the last open page during session.
155
157
158
160 FOOTPRINT* aFootprint ) :
162 m_frame( aParent ),
163 m_footprint( aFootprint ),
164 m_initialized( false ),
169{
170 SetEvtHandlerEnabled( false );
171
172 // Create the extra panels.
175
176 m_NoteBook->AddPage( m_3dPanel, _("3D Models"), false );
177 m_NoteBook->AddPage( m_embeddedFiles, _( "Embedded Files" ) );
178
179 m_fields = new PCB_FIELDS_GRID_TABLE( m_frame, this, { m_embeddedFiles->GetLocalFiles() } );
180
181 {
182 LSET forbiddenLayers = LSET::AllCuMask() | LSET::AllTechMask();
183 forbiddenLayers.set( Edge_Cuts );
184 forbiddenLayers.set( Margin );
185
186 m_privateLayers = new LAYERS_GRID_TABLE( m_frame, forbiddenLayers );
187 }
188
189 {
190 LSET forbiddenLayers = LSET::AllLayersMask() & ~LSET::UserDefinedLayersMask();
191 m_customUserLayers = new LAYERS_GRID_TABLE( m_frame, forbiddenLayers );
192 }
193
194 m_delayedErrorMessage = wxEmptyString;
195 m_delayedFocusCtrl = nullptr;
196 m_delayedFocusGrid = nullptr;
200
201 // Give an icon
202 wxIcon icon;
203 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit ) );
204 SetIcon( icon );
205
206 m_itemsGrid->SetTable( m_fields );
207 m_itemsGrid->OverrideMinSize( 1.0, 1.0 );
210
211 m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
212 m_itemsGrid->Bind( wxEVT_GRID_CELL_CHANGING, &DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridCellChanging, this );
214 [this]( wxCommandEvent& aEvent )
215 {
216 OnAddPrivateLayer( aEvent );
217 } ) );
218 m_nettieGroupsGrid->PushEventHandler( new GRID_TRICKS( m_nettieGroupsGrid,
219 [this]( wxCommandEvent& aEvent )
220 {
221 OnAddNettieGroup( aEvent );
222 } ) );
223 m_jumperGroupsGrid->PushEventHandler( new GRID_TRICKS( m_jumperGroupsGrid,
224 [this]( wxCommandEvent& aEvent )
225 {
226 OnAddJumperGroup( aEvent );
227 } ) );
229 [this]( wxCommandEvent& aEvent )
230 {
231 OnAddCustomLayer( aEvent );
232 } ) );
233
234 m_itemsGrid->SetupColumnAutosizer( PFC_VALUE );
235 m_privateLayersGrid->SetupColumnAutosizer( 0 );
236 m_nettieGroupsGrid->SetupColumnAutosizer( 0 );
237 m_jumperGroupsGrid->SetupColumnAutosizer( 0 );
238 m_customUserLayersGrid->SetupColumnAutosizer( 0 );
239
240 m_itemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
241 m_privateLayersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
242 m_nettieGroupsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
243 m_jumperGroupsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
244 m_customUserLayersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
245
246 m_itemsGrid->ShowHideColumns( "0 1 2 3 4 5 7" );
247
249
250 // Set font sizes
251 wxFont infoFont = KIUI::GetInfoFont( this ).Italic();
252 m_staticTextInfoCopper->SetFont( infoFont );
253 m_staticTextInfoPaste->SetFont( infoFont );
254
255 if( static_cast<int>( m_page ) >= 0 )
256 m_NoteBook->SetSelection( (unsigned) m_page );
257
259 {
264 }
266 {
268 }
269
270 // Update label text and tooltip for combined offset + ratio field
271 m_SolderPasteMarginLabel->SetLabel( _( "Solder paste clearance:" ) );
272 m_SolderPasteMarginLabel->SetToolTip( _( "Local solder paste clearance for this footprint.\n"
273 "Enter an absolute value (e.g., -0.1mm), a percentage "
274 "(e.g., -5%), or both (e.g., -0.1mm - 5%).\n"
275 "If blank, the global value is used." ) );
276
277 // Hide the old ratio controls - they're no longer needed
278 m_PasteMarginRatioLabel->Show( false );
279 m_PasteMarginRatioCtrl->Show( false );
280 m_PasteMarginRatioUnits->Show( false );
281
282 // Configure button logos
293
295
297 SetEvtHandlerEnabled( true );
298}
299
300
302{
303 m_itemsGrid->Unbind( wxEVT_GRID_CELL_CHANGING, &DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridCellChanging, this );
304
305 // Prevents crash bug in wxGrid's d'tor
306 m_itemsGrid->DestroyTable( m_fields );
307 m_privateLayersGrid->DestroyTable( m_privateLayers );
309
310 // Delete the GRID_TRICKS.
311 m_itemsGrid->PopEventHandler( true );
312 m_privateLayersGrid->PopEventHandler( true );
313 m_nettieGroupsGrid->PopEventHandler( true );
314 m_jumperGroupsGrid->PopEventHandler( true );
315 m_customUserLayersGrid->PopEventHandler( true );
316
317 m_page = static_cast<NOTEBOOK_PAGES>( m_NoteBook->GetSelection() );
318
319 // the GL canvas on the 3D models page has to be visible before it is destroyed
320 m_NoteBook->SetSelection( static_cast<int>( NOTEBOOK_PAGES::PAGE_3D_MODELS ) );
321}
322
323
325{
326 if( !wxDialog::TransferDataToWindow() )
327 return false;
328
329 if( !m_PanelGeneral->TransferDataToWindow() )
330 return false;
331
332 LIB_ID fpID = m_footprint->GetFPID();
333 wxString footprintName = fpID.GetLibItemName();
334
335 m_FootprintNameCtrl->ChangeValue( footprintName );
336
337 m_DocCtrl->SetValue( EscapeString( m_footprint->GetLibDescription(), CTX_LINE ) );
338 m_KeywordCtrl->SetValue( m_footprint->GetKeywords() );
339
340 if( m_footprint->GetHeight() != 0 )
341 m_height.SetValue( m_footprint->GetHeight() );
342 else
343 m_height.SetValue( wxEmptyString );
344
345 // Add the models to the panel
346 (void) m_3dPanel->TransferDataToWindow();
347
348 (void) m_embeddedFiles->TransferDataToWindow();
349
350 // Footprint Fields
351 for( PCB_FIELD* field : m_footprint->GetFields() )
352 {
353 wxCHECK2( field, continue );
354
355 m_fields->push_back( *field );
356 }
357
358 // Notify the grid
359 wxGridTableMessage tmsg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->GetNumberRows() );
360 m_itemsGrid->ProcessTableMessage( tmsg );
361
362 if( m_footprint->GetAttributes() & FP_THROUGH_HOLE )
363 m_componentType->SetSelection( 0 );
364 else if( m_footprint->GetAttributes() & FP_SMD )
365 m_componentType->SetSelection( 1 );
366 else
367 m_componentType->SetSelection( 2 );
368
369 // Private layers
370 for( PCB_LAYER_ID privateLayer : m_footprint->GetPrivateLayers().UIOrder() )
371 m_privateLayers->push_back( privateLayer );
372
373 // Notify the grid
374 wxGridTableMessage gridTableMessagesg( m_privateLayers, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
375 m_privateLayers->GetNumberRows() );
376 m_privateLayersGrid->ProcessTableMessage( gridTableMessagesg );
377
378 switch( m_footprint->GetStackupMode() )
379 {
381 {
382 m_cbCustomLayers->SetValue( false );
383
384 // Seed the inactive custom controls so switching to them keeps every layer in use
386 const LSET usedUserLayers = usedLayers & LSET::UserDefinedLayersMask();
387
388 for( PCB_LAYER_ID userLayer : usedUserLayers )
389 m_customUserLayers->push_back( userLayer );
390
391 m_copperLayerCount->SetSelection( LAYER_UTILS::MinimalCopperLayerCount( usedLayers ) / 2 - 1 );
392 break;
393 }
395 {
396 m_cbCustomLayers->SetValue( true );
397
398 const LSET& customFpLayers = m_footprint->GetStackupLayers();
399 const LSET customUserLayers = customFpLayers & LSET::UserDefinedLayersMask();
400
401 for( PCB_LAYER_ID customUserLayer : customUserLayers )
402 {
403 m_customUserLayers->push_back( customUserLayer );
404 }
405
406 // Set the number of copper layers
407 m_copperLayerCount->SetSelection( ( customFpLayers & LSET::AllCuMask() ).count() / 2 - 1 );
408 break;
409 }
410 }
412
413 // Notify the grid
414 {
415 wxGridTableMessage gridTableMessagesCustom( m_customUserLayers, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
416 m_customUserLayers->GetNumberRows() );
417 m_customUserLayersGrid->ProcessTableMessage( gridTableMessagesCustom );
418 }
419
420 m_boardOnly->SetValue( m_footprint->GetAttributes() & FP_BOARD_ONLY );
421 m_cbExcludeFromSim->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_SIM );
422 m_excludeFromPosFiles->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES );
423 m_excludeFromBOM->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_BOM );
424 m_cbDNP->SetValue( m_footprint->GetAttributes() & FP_DNP );
425
426 // Local Clearances
427
428 if( m_footprint->GetLocalClearance().has_value() )
429 m_netClearance.SetValue( m_footprint->GetLocalClearance().value() );
430 else
431 m_netClearance.SetValue( wxEmptyString );
432
433 if( m_footprint->GetLocalSolderMaskMargin().has_value() )
434 m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin().value() );
435 else
436 m_solderMask.SetValue( wxEmptyString );
437
438 m_solderPaste.SetOffsetValue( m_footprint->GetLocalSolderPasteMargin() );
439 m_solderPaste.SetRatioValue( m_footprint->GetLocalSolderPasteMarginRatio() );
440
441 m_noCourtyards->SetValue( m_footprint->AllowMissingCourtyard() );
442 m_allowBridges->SetValue( m_footprint->AllowSolderMaskBridges() );
443
444 switch( m_footprint->GetLocalZoneConnection() )
445 {
446 default:
447 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
448 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
449 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
450 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
451 }
452
453 for( const wxString& group : m_footprint->GetNetTiePadGroups() )
454 {
455 if( !group.IsEmpty() )
456 {
457 m_nettieGroupsGrid->AppendRows( 1 );
458 m_nettieGroupsGrid->SetCellValue( m_nettieGroupsGrid->GetNumberRows() - 1, 0, group );
459 }
460 }
461
462 m_cbDuplicatePadsAreJumpers->SetValue( m_footprint->GetDuplicatePadNumbersAreJumpers() );
463
464 for( const JUMPER_GROUP& group : m_footprint->JumperPadGroups().GetAll() )
465 {
466 wxString groupTxt;
467
468 for( const wxString& pinNumber : group.GetNames() )
469 {
470 if( !groupTxt.IsEmpty() )
471 groupTxt << ", ";
472
473 groupTxt << pinNumber;
474 }
475
476 m_jumperGroupsGrid->AppendRows( 1 );
477 m_jumperGroupsGrid->SetCellValue( m_jumperGroupsGrid->GetNumberRows() - 1, 0, groupTxt );
478 }
479
480 // Items grid
481 for( int col = 0; col < m_itemsGrid->GetNumberCols(); col++ )
482 {
483 // Adjust min size to the column label size
484 m_itemsGrid->SetColMinimalWidth( col, m_itemsGrid->GetVisibleWidth( col, true, false ) );
485 // Adjust the column size.
486 int col_size = m_itemsGrid->GetVisibleWidth( col );
487
488 if( col == PFC_LAYER ) // This one's a drop-down. Check all possible values.
489 {
490 BOARD* board = m_footprint->GetBoard();
491
492 for( PCB_LAYER_ID layer : board->GetEnabledLayers() )
493 col_size = std::max( col_size, GetTextExtent( board->GetLayerName( layer ) ).x );
494
495 // Swatch and gaps:
496 col_size += KiROUND( 14 * GetDPIScaleFactor() ) + 12;
497 }
498
499 if( m_itemsGrid->IsColShown( col ) )
500 m_itemsGrid->SetColSize( col, col_size );
501 }
502
503 m_itemsGrid->SetRowLabelSize( 0 );
504
505 Layout();
506 m_itemsGrid->SetMinVisibleRows( this, 4 );
507 m_initialized = true;
508
509 return true;
510}
511
512
514 LIB_ID* doOverwrite )
515{
516 if( aFootprintName.IsEmpty() )
517 {
518 m_delayedErrorMessage = _( "Footprint must have a name." );
519 return false;
520 }
521 else if( !FOOTPRINT::IsLibNameValid( aFootprintName ) )
522 {
523 m_delayedErrorMessage.Printf( _( "Footprint name may not contain '%s'." ),
525 return false;
526 }
527
528 LIB_ID fpID = m_footprint->GetFPID();
529 wxString libraryName = fpID.GetLibNickname();
530 wxString originalFPName = fpID.GetLibItemName();
531
533
534 if( aFootprintName != originalFPName && adapter->FootprintExists( libraryName, aFootprintName ) )
535 {
536 wxString msg = wxString::Format( _( "Footprint '%s' already exists in library '%s'." ),
537 aFootprintName, libraryName );
538
539 KIDIALOG errorDlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
540 errorDlg.SetOKLabel( _( "Overwrite" ) );
541
542 if( errorDlg.ShowModal() == wxID_OK )
543 {
544 doOverwrite->SetLibNickname( libraryName );
545 doOverwrite->SetLibItemName( aFootprintName );
546 return true;
547 }
548 }
549
550 return true;
551}
552
553
555{
556 LSET userLayers;
557 if( m_cbCustomLayers->GetValue() )
558 {
559 userLayers |= LSET::AllCuMask( ( m_copperLayerCount->GetSelection() + 1 ) * 2 );
560
561 for( PCB_LAYER_ID layer : *m_customUserLayers )
562 {
563 userLayers.set( layer );
564 }
565 }
566 else
567 {
568 // The default stackup restricts nothing, so every standard layer is available.
569 userLayers |= LSET{ F_Cu, B_Cu };
570 userLayers |= LSET::InternalCuMask();
571 userLayers |= LSET::UserDefinedLayersMask();
572 }
573
574 return userLayers;
575}
576
577
579{
580 if( !m_itemsGrid->CommitPendingChanges() )
581 return false;
582
583 if( !DIALOG_SHIM::Validate() )
584 return false;
585
586 // First, test for invalid chars in footprint name
587 wxString footprintName = m_FootprintNameCtrl->GetValue();
588 LIB_ID overwrite;
589
590 if( !checkFootprintName( footprintName, &overwrite ) )
591 {
592 if( m_NoteBook->GetSelection() != 0 )
593 m_NoteBook->SetSelection( 0 );
594
597
598 return false;
599 }
600
601 // Check for valid field text properties
602 for( int i = 0; i < (int) m_fields->size(); ++i )
603 {
604 PCB_FIELD& field = m_fields->at( i );
605
606 // Check for missing field names.
607 if( field.GetName( false ).IsEmpty() )
608 {
610 m_delayedErrorMessage = wxString::Format( _( "Fields must have a name." ) );
613
614 return false;
615 }
616
617 int minSize = pcbIUScale.mmToIU( TEXT_MIN_SIZE_MM );
618 int maxSize = pcbIUScale.mmToIU( TEXT_MAX_SIZE_MM );
619
620 if( field.GetTextWidth() < minSize || field.GetTextWidth() > maxSize )
621 {
623 m_delayedErrorMessage = wxString::Format( _( "The text width must be between %s and %s." ),
624 m_frame->StringFromValue( minSize, true ),
625 m_frame->StringFromValue( maxSize, true ) );
628
629 return false;
630 }
631
632 if( field.GetTextHeight() < minSize || field.GetTextHeight() > maxSize )
633 {
635 m_delayedErrorMessage = wxString::Format( _( "The text height must be between %s and %s." ),
636 m_frame->StringFromValue( minSize, true ),
637 m_frame->StringFromValue( maxSize, true ) );
640
641 return false;
642 }
643
644 // Test for acceptable values for thickness and size and clamp if fails
645 int maxPenWidth = ClampTextPenSize( field.GetTextThickness(), field.GetTextSize() );
646
647 if( field.GetTextThickness() > maxPenWidth )
648 {
649 m_itemsGrid->SetCellValue( i, PFC_THICKNESS, m_frame->StringFromValue( maxPenWidth, true ) );
650
652 m_delayedErrorMessage = _( "The text thickness is too large for the text size.\n"
653 "It will be clamped." );
656
657 return false;
658 }
659 }
660
661 if( !m_netClearance.Validate( 0, INT_MAX ) )
662 return false;
663
664 if( overwrite.IsValid() )
665 {
666 if( m_frame->DeleteFootprintFromLibrary( overwrite, false /* already confirmed */ ) )
667 m_frame->SyncLibraryTree( true );
668 }
669
670 // A custom layer set restricts which layers the footprint may use, so check that the user
671 // isn't removing a layer that is still used by the footprint. The default stackup imposes no
672 // such restriction, so nothing can be orphaned in that case.
673 if( m_cbCustomLayers->GetValue() )
674 {
677
678 if( orphanLayers.any() )
679 {
681 wxString::Format( _( "You are trying to remove layers that are used by the footprint: %s.\n"
682 "Please remove the objects that use these layers first." ),
683 LAYER_UTILS::AccumulateNames( orphanLayers, m_frame->GetBoard() ) );
688 return false;
689 }
690 }
691
692 return true;
693}
694
695
697{
698 if( !m_itemsGrid->CommitPendingChanges()
699 || !m_privateLayersGrid->CommitPendingChanges()
700 || !m_nettieGroupsGrid->CommitPendingChanges()
701 || !m_jumperGroupsGrid->CommitPendingChanges()
702 || !m_customUserLayersGrid->CommitPendingChanges()
703 || !m_3dPanel->CommitPendingChanges()
704 || !m_embeddedFiles->CommitPendingChanges() )
705 {
706 return false;
707 }
708
709 if( !m_3dPanel->Validate() )
710 return false;
711
712 KIGFX::PCB_VIEW* view = nullptr;
713 PCB_SELECTION_TOOL* selectionTool = nullptr;
714 std::optional<BOARD_COMMIT> commit;
715
716 // When invoked from the library tree (Footprint Properties context menu), we edit a temporary
717 // footprint that is not loaded in the editor. Only update the editor's undo list, view, and
718 // selection when editing its current footprint. The library-tree path saves its copy directly.
719 bool editingCurrentFootprint = ( m_footprint == m_frame->GetBoard()->GetFirstFootprint() );
720
721 if( editingCurrentFootprint )
722 {
723 view = m_frame->GetCanvas()->GetView();
724 selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
725 commit.emplace( m_frame );
726 commit->Modify( m_footprint );
727 }
728
729 // This will call TransferDataToWindow() on the 3D panel and the embedded files panel. For an
730 // editor footprint, this must be done after Modify() to capture those changes in the undo state.
731 if( !DIALOG_SHIM::TransferDataFromWindow() )
732 return false;
733
734 // Clear out embedded files that are no longer in use
735 std::set<wxString> files;
736 std::set<wxString> files_to_delete;
737
738 // Get the new files from the footprint fields
739 for( const PCB_FIELD& field : *m_fields )
740 {
741 if( field.GetText().StartsWith( FILEEXT::KiCadUriPrefix ) )
742 files.insert( field.GetText() );
743 }
744
745 // Find any files referenced in the old fields that are not in the new fields
746 for( PCB_FIELD* field : m_footprint->GetFields() )
747 {
748 wxCHECK2( field, continue );
749
750 if( field->GetText().StartsWith( FILEEXT::KiCadUriPrefix ) )
751 {
752 if( files.find( field->GetText() ) == files.end() )
753 files_to_delete.insert( field->GetText() );
754 }
755 }
756
757 for( const wxString& file : files_to_delete )
758 {
759 wxString name = file.Mid( FILEEXT::KiCadUriPrefix.size() + 3 ); // Skip "kicad-embed://"
760 m_footprint->RemoveFile( name );
761 }
762
763 LIB_ID fpID = m_footprint->GetFPID();
764 fpID.SetLibItemName( m_FootprintNameCtrl->GetValue() );
765 m_footprint->SetFPID( fpID );
766
767 m_footprint->SetLibDescription( UnescapeString( m_DocCtrl->GetValue() ) );
768 m_footprint->SetKeywords( m_KeywordCtrl->GetValue() );
769 m_footprint->SetHeight( static_cast<int>( m_height.GetValue() ) );
770
771 // Update fields
772 if( editingCurrentFootprint )
773 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
774
775 std::vector<PCB_FIELD*> addedFields;
776 std::vector<PCB_FIELD*> detachedFields;
777
778 m_footprint->UpdateFields( *m_fields, addedFields, detachedFields );
779
780 for( PCB_FIELD* field : detachedFields )
781 {
782 if( view )
783 view->Remove( field );
784
785 delete field;
786 }
787
788 for( PCB_FIELD* field : m_footprint->GetFields() )
789 {
790 // Reused fields are already known to the view
791 if( view )
792 {
793 if( alg::contains( addedFields, field ) )
794 view->Add( field );
795 else
796 view->Update( field );
797 }
798
799 if( selectionTool && field->IsSelected() )
800 {
801 // The old copy was in the selection list, but this one is not. Remove the
802 // out-of-sync selection flag so we can re-add the field to the selection.
803 field->ClearSelected();
804 selectionTool->AddItemToSel( field, true );
805 }
806 }
807
808 LSET privateLayers;
809
810 for( PCB_LAYER_ID layer : *m_privateLayers )
811 privateLayers.set( layer );
812
813 m_footprint->SetPrivateLayers( privateLayers );
814
815 if( m_cbCustomLayers->GetValue() )
816 {
817 const LSET customLayers = getCustomLayersFromControls();
818
820 m_footprint->SetStackupLayers( std::move( customLayers ) );
821 }
822 else
823 {
824 // Just use the default stackup mode
826 }
827
828 int attributes = 0;
829
830 switch( m_componentType->GetSelection() )
831 {
832 case 0: attributes |= FP_THROUGH_HOLE; break;
833 case 1: attributes |= FP_SMD; break;
834 default: break;
835 }
836
837 if( m_boardOnly->GetValue() )
838 attributes |= FP_BOARD_ONLY;
839
840 if( m_cbExcludeFromSim->GetValue() )
841 attributes |= FP_EXCLUDE_FROM_SIM;
842
843 if( m_excludeFromPosFiles->GetValue() )
844 attributes |= FP_EXCLUDE_FROM_POS_FILES;
845
846 if( m_excludeFromBOM->GetValue() )
847 attributes |= FP_EXCLUDE_FROM_BOM;
848
849 if( m_cbDNP->GetValue() )
850 attributes |= FP_DNP;
851
852 m_footprint->SetAttributes( attributes );
853
854 m_footprint->SetAllowMissingCourtyard( m_noCourtyards->GetValue() );
855 m_footprint->SetAllowSolderMaskBridges( m_allowBridges->GetValue() );
856
857 // Initialize mask clearances
858 if( m_netClearance.IsNull() )
859 m_footprint->SetLocalClearance( {} );
860 else
861 m_footprint->SetLocalClearance( m_netClearance.GetValue() );
862
863 if( m_solderMask.IsNull() )
864 m_footprint->SetLocalSolderMaskMargin( {} );
865 else
866 m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() );
867
868 m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetOffsetValue() );
869 m_footprint->SetLocalSolderPasteMarginRatio( m_solderPaste.GetRatioValue() );
870
871 switch( m_ZoneConnectionChoice->GetSelection() )
872 {
873 default:
874 case 0: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
875 case 1: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
876 case 2: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
877 case 3: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
878 }
879
880 m_footprint->ClearNetTiePadGroups();
881
882 for( int ii = 0; ii < m_nettieGroupsGrid->GetNumberRows(); ++ii )
883 {
884 wxString group = m_nettieGroupsGrid->GetCellValue( ii, 0 );
885
886 if( !group.IsEmpty() )
887 m_footprint->AddNetTiePadGroup( group );
888 }
889
890 m_footprint->SetDuplicatePadNumbersAreJumpers( m_cbDuplicatePadsAreJumpers->GetValue() );
891
892 std::set<wxString> availablePads;
893
894 for( const PAD* pad : m_footprint->Pads() )
895 availablePads.insert( pad->GetNumber() );
896
897 JUMPER_GROUP_SET newJumpers;
898
899 for( int ii = 0; ii < m_jumperGroupsGrid->GetNumberRows(); ++ii )
900 {
901 wxStringTokenizer tokenizer( m_jumperGroupsGrid->GetCellValue( ii, 0 ), ", \t\r\n", wxTOKEN_STRTOK );
902 std::set<wxString> names;
903
904 while( tokenizer.HasMoreTokens() )
905 {
906 wxString token = tokenizer.GetNextToken();
907
908 if( token.IsEmpty() )
909 continue;
910
911 if( !availablePads.count( token ) )
912 {
913 wxString msg;
914 msg.Printf( _( "Pad '%s' in jumper pad group %d does not exist in this footprint." ),
915 token, ii + 1 );
916 DisplayErrorMessage( this, msg );
917 return false;
918 }
919
920 names.insert( token );
921 }
922
923 if( std::optional<JUMPER_GROUP> group = JUMPER_GROUP::Make( std::move( names ) ) )
924 newJumpers.Add( std::move( *group ) );
925 }
926
927 m_footprint->JumperPadGroups() = std::move( newJumpers );
928
929 // Copy the models from the panel to the footprint
930 std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList();
931 std::vector<FP_3DMODEL>* fpList = &m_footprint->Models();
932 fpList->clear();
933 fpList->insert( fpList->end(), panelList.begin(), panelList.end() );
934
935 if( commit )
936 commit->Push( _( "Edit Footprint Properties" ) );
937
938 return true;
939}
940
941
943{
944 m_itemsGrid->OnAddRow(
945 [&]() -> std::pair<int, int>
946 {
947 const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
948
950
951 // Set active layer if legal; otherwise copy layer from previous text item
952 if( LSET::AllTechMask().test( m_frame->GetActiveLayer() ) )
953 newField.SetLayer( m_frame->GetActiveLayer() );
954 else
955 newField.SetLayer( m_fields->at( m_fields->size() - 1 ).GetLayer() );
956
957 newField.SetTextSize( dsnSettings.GetTextSize( newField.GetLayer() ) );
958 newField.SetTextThickness( dsnSettings.GetTextThickness( newField.GetLayer() ) );
959 newField.SetItalic( dsnSettings.GetTextItalic( newField.GetLayer() ) );
960
961 m_fields->push_back( newField );
962
963 // notify the grid
964 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
965 m_itemsGrid->ProcessTableMessage( msg );
966 OnModify();
967
968 return { m_fields->size() - 1, PFC_NAME };
969 } );
970}
971
972
974{
975 m_itemsGrid->OnDeleteRows(
976 [&]( int row )
977 {
978 if( row < m_fields->GetMandatoryRowCount() )
979 {
980 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
981 m_fields->GetMandatoryRowCount() ) );
982 return false;
983 }
984
985 return true;
986 },
987 [&]( int row )
988 {
989 m_fields->DeleteRows( row );
990 } );
991
992 OnModify();
993}
994
995
997 int aRow )
998{
999 aLayerTable.erase( aLayerTable.begin() + aRow );
1000
1001 // notify the grid
1002 wxGridTableMessage msg( &aLayerTable, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
1003 aGrid.ProcessTableMessage( msg );
1004
1005 OnModify();
1006}
1007
1008
1010 LAYERS_GRID_TABLE& aGridTable )
1011{
1012 PCB_LAYER_ID nextLayer = User_1;
1013
1014 while( alg::contains( aGridTable, nextLayer ) && nextLayer < User_45 )
1015 nextLayer = ToLAYER_ID( nextLayer + 2 );
1016
1017 aGridTable.push_back( nextLayer );
1018
1019 // notify the grid
1020 wxGridTableMessage msg( &aGridTable, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
1021 aGrid.ProcessTableMessage( msg );
1022 OnModify();
1023
1024 return { aGridTable.size() - 1, -1 };
1025}
1026
1027
1029{
1030 m_privateLayersGrid->OnAddRow(
1031 [&]()
1032 {
1034 } );
1035}
1036
1037
1039{
1040 m_privateLayersGrid->OnDeleteRows(
1041 [&]( int row )
1042 {
1044 } );
1045}
1046
1047
1052
1053
1055{
1056 m_customUserLayersGrid->OnAddRow(
1057 [&]()
1058 {
1060 } );
1061}
1062
1063
1065{
1066 m_customUserLayersGrid->OnDeleteRows(
1067 [&]( int row )
1068 {
1070 } );
1071}
1072
1073
1078
1079
1084
1085
1090
1091
1096
1097
1099{
1100 aGrid->OnAddRow(
1101 [&]() -> std::pair<int, int>
1102 {
1103 aGrid->AppendRows( 1 );
1104 OnModify();
1105
1106 return { aGrid->GetNumberRows() - 1, 0 };
1107 } );
1108}
1109
1110
1112{
1113 aGrid->OnDeleteRows(
1114 [&]( int row )
1115 {
1116 aGrid->DeleteRows( row, 1 );
1117 } );
1118
1119 OnModify();
1120}
1121
1122
1124{
1125 wxGridCellEditor* editor = m_itemsGrid->GetCellEditor( aEvent.GetRow(), aEvent.GetCol() );
1126 wxControl* control = editor->GetControl();
1127
1128 if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
1129 {
1130 aEvent.Veto();
1132 m_delayedFocusRow = aEvent.GetRow();
1133 m_delayedFocusColumn = aEvent.GetCol();
1135 }
1136 else if( aEvent.GetCol() == PFC_NAME )
1137 {
1138 wxString newName = aEvent.GetString();
1139
1140 for( int row = 0; row < m_itemsGrid->GetNumberRows(); ++row )
1141 {
1142 if( row == aEvent.GetRow() )
1143 continue;
1144
1145 if( FieldNamesAreDuplicates( newName, m_itemsGrid->GetCellValue( row, PFC_NAME ) ) )
1146 {
1147 aEvent.Veto();
1149 m_delayedFocusRow = aEvent.GetRow();
1150 m_delayedFocusColumn = aEvent.GetCol();
1152 m_delayedErrorMessage = wxString::Format( _( "Field name '%s' already in use." ), newName );
1153 break;
1154 }
1155 }
1156 }
1157
1158 editor->DecRef();
1159}
1160
1161
1163{
1164 // Handle a delayed focus. The delay allows us to:
1165 // a) change focus when the error was triggered from within a killFocus handler
1166 // b) show the correct notebook page in the background before the error dialog comes up
1167 // when triggered from an OK or a notebook page change
1168
1169 if( static_cast<int>( m_delayedFocusPage ) >= 0 )
1170 {
1171 if( m_NoteBook->GetSelection() != static_cast<int>( m_delayedFocusPage ) )
1172 {
1173 const int newPage = static_cast<int>( m_delayedFocusPage );
1174 const int oldPage = m_NoteBook->ChangeSelection( newPage );
1175
1176 // Notify page tools without rerunning the validation that requested this switch.
1177 wxBookCtrlEvent changed( wxEVT_NOTEBOOK_PAGE_CHANGED, m_NoteBook->GetId(), newPage, oldPage );
1178 changed.SetEventObject( m_NoteBook );
1179 m_NoteBook->GetEventHandler()->ProcessEvent( changed );
1180 }
1181
1183 }
1184
1185 if( !m_delayedErrorMessage.IsEmpty() )
1186 {
1187 // We will re-enter this routine when the error dialog is displayed, so make
1188 // sure we don't keep putting up more dialogs.
1189 wxString msg = m_delayedErrorMessage;
1190 m_delayedErrorMessage = wxEmptyString;
1191
1192 // Do not use DisplayErrorMessage(); it screws up window order on Mac
1193 DisplayError( nullptr, msg );
1194 }
1195
1196 if( m_delayedFocusCtrl )
1197 {
1198 m_delayedFocusCtrl->SetFocus();
1199
1200 if( wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_delayedFocusCtrl ) )
1201 textEntry->SelectAll();
1202
1203 m_delayedFocusCtrl = nullptr;
1204 }
1205 else if( m_delayedFocusGrid )
1206 {
1207 m_delayedFocusGrid->SetFocus();
1210
1211 if( !( m_delayedFocusColumn == 0 && m_delayedFocusRow < m_fields->GetMandatoryRowCount() ) )
1212 m_delayedFocusGrid->EnableCellEditControl( true );
1213
1214 m_delayedFocusGrid->ShowCellEditControl();
1215
1216 m_delayedFocusGrid = nullptr;
1217 m_delayedFocusRow = -1;
1219 }
1220}
1221
1222
1224{
1225 bool enableCustomCtrls = m_cbCustomLayers->GetValue();
1226
1227 m_copperLayerCount->Enable( enableCustomCtrls );
1228 m_customUserLayersGrid->Enable( enableCustomCtrls );
1229 m_bpAddCustomLayer->Enable( enableCustomCtrls );
1230 m_bpDeleteCustomLayer->Enable( enableCustomCtrls );
1231}
1232
1233
1235{
1236 if( !m_itemsGrid->CommitPendingChanges() )
1237 aEvent.Veto();
1238
1239 if( !m_privateLayersGrid->CommitPendingChanges() )
1240 aEvent.Veto();
1241
1242 if( !m_customUserLayersGrid->CommitPendingChanges() )
1243 aEvent.Veto();
1244
1245 m_3dPanel->UpdateEmbeddedFiles();
1246}
1247
1248
1250{
1251 if( m_initialized )
1252 OnModify();
1253}
1254
1255
1257{
1258 if( m_initialized )
1259 OnModify();
1260}
1261
1262
1264{
1265 if( m_initialized )
1266 OnModify();
1267}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
BASE_SET & set(size_t pos)
Definition base_set.h:126
Container for design settings for a BOARD object.
int GetTextThickness(PCB_LAYER_ID aLayer) const
Return the default text thickness from the layer class for the given layer.
bool GetTextItalic(PCB_LAYER_ID aLayer) const
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:383
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:932
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1174
DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Footprint Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(FOOTPRINT_EDIT_FRAME *aParent, FOOTPRINT *aFootprint)
LSET getCustomLayersFromControls() const
Get the layers for the footprint from the controls that can be affected by the stackup.
bool checkFootprintName(const wxString &aFootprintName, LIB_ID *doOverwrite)
void onLayerGridRowDelete(WX_GRID &aGrid, LAYERS_GRID_TABLE &aLayerTable, int aRow)
std::pair< int, int > onLayerGridRowAddUserLayer(WX_GRID &aGrid, LAYERS_GRID_TABLE &aLayerTable)
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
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 int GetTextHeight() const
Definition eda_text.h:307
virtual int GetTextWidth() const
Definition eda_text.h:304
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:290
An interface to the global shared library manager that is schematic-specific and linked to one projec...
bool FootprintExists(const wxString &aNickname, const wxString &aName)
Provide a custom wxValidator object for limiting the allowable characters when defining footprint nam...
Definition validators.h:49
static bool IsLibNameValid(const wxString &aName)
Test for validity of a name of a footprint to be used in a footprint library ( no spaces,...
static const wxChar * StringLibNameInvalidChars(bool aUserReadable)
Test for validity of the name in a library of the footprint ( no spaces, dir separators ....
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:57
Represents an (ordered) list of JUMPER_GROUP objects.
void Add(JUMPER_GROUP aGroup)
Add a JUMPER_GROUP to the set.
Represents a group of jumper pins or pads, keyed by name.
static std::optional< JUMPER_GROUP > Make(std::set< wxString > aNames)
Factory method to create a JUMPER_GROUP from a set of names.
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
int ShowModal() override
Definition kidialog.cpp:89
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...
Definition pcb_view.cpp:87
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition pcb_view.cpp:53
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition pcb_view.cpp:70
LAYERS_GRID_TABLE(PCB_BASE_FRAME *aFrame, const LSET &aForbiddenLayers)
wxString GetValue(int aRow, int aCol) override
bool CanGetValueAs(int aRow, int aCol, const wxString &aTypeName) override
void SetValueAsLong(int aRow, int aCol, long aValue) override
long GetValueAsLong(int aRow, int aCol) override
bool CanSetValueAs(int aRow, int aCol, const wxString &aTypeName) override
void SetValue(int aRow, int aCol, const wxString &aValue) override
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:672
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static const LSET & AllLayersMask()
Definition lset.cpp:637
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
Definition lset.cpp:700
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition lset.cpp:573
Definition pad.h:61
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
The selection tool: currently supports:
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:512
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:484
int GetTextThickness() const override
Definition pcb_text.cpp:497
VECTOR2I GetTextSize() const override
Definition pcb_text.cpp:470
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
int AddItemToSel(const TOOL_EVENT &aEvent)
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition wx_grid.cpp:44
void OnDeleteRows(const std::function< void(int row)> &aDeleter)
Handles a row deletion event.
Definition wx_grid.cpp:839
void OnAddRow(const std::function< std::pair< int, int >()> &aAdder)
Definition wx_grid.cpp:819
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
Declaration of the eda_3d_viewer class.
#define TEXT_MIN_SIZE_MM
Minimum text size (1 micron).
Definition eda_text.h:61
#define TEXT_MAX_SIZE_MM
Maximum text size in mm (~10 inches)
Definition eda_text.h:62
@ FP_SMD
Definition footprint.h:87
@ FP_DNP
Definition footprint.h:92
@ FP_EXCLUDE_FROM_POS_FILES
Definition footprint.h:88
@ FP_BOARD_ONLY
Definition footprint.h:90
@ FP_EXCLUDE_FROM_BOM
Definition footprint.h:89
@ FP_EXCLUDE_FROM_SIM
Definition footprint.h:93
@ FP_THROUGH_HOLE
Definition footprint.h:86
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:111
@ CUSTOM_LAYERS
Stackup handling where the footprint can have any number of copper layers, and objects on those layer...
Definition footprint.h:116
int ClampTextPenSize(int aPenSize, int aSize, bool aStrict)
Pen width should not allow characters to become cluttered up in their own fatness.
Definition gr_text.cpp:70
static const std::string KiCadUriPrefix
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ User_45
Definition layer_ids.h:164
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
@ Margin
Definition layer_ids.h:109
@ User_1
Definition layer_ids.h:120
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
wxString AccumulateNames(const LSEQ &aLayers, const BOARD *aBoard)
Accumulate layer names from a layer set into a comma separated string.
LSET GetUsedFootprintLayers(const FOOTPRINT &aFootprint)
Return the layers the footprint's items actually occupy.
int MinimalCopperLayerCount(const LSET &aLayers)
Return the smallest even copper layer count whose stackup contains every copper layer in aLayers.
LSET GetOrphanedFootprintLayers(const FOOTPRINT &aFootprint, const LSET &aCustomUserLayers)
Compute the set of footprint-used layers that would be orphaned if the footprint's allowed layer set ...
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
@ PFC_THICKNESS
see class PGM_BASE
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LINE
bool FieldNamesAreDuplicates(const wxString &aLhs, const wxString &aRhs, std::initializer_list< FIELD_T > aMandatoryFields)
Test whether two field names should be treated as duplicates for the purposes of field name uniquenes...
wxString GetUserFieldName(int aFieldNdx, TRANSLATION aTranslation)
@ USER
The field ID hasn't been set yet; field is invalid.
@ TRANSLATED
Custom text control validator definitions.
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ NONE
Pads are not covered.
Definition zones.h:45
@ FULL
pads are covered by copper
Definition zones.h:47