KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_libraries_utils.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <algorithm>
21#include <memory>
22#include <wx/ffile.h>
23#include <pgm_base.h>
24#include <kiface_base.h>
25#include <confirm.h>
26#include <kidialog.h>
27#include <macros.h>
28#include <string_utils.h>
29#include <pcb_edit_frame.h>
30#include <eda_list_dialog.h>
31#include <filter_reader.h>
33#include <validators.h>
35#include <tool/tool_manager.h>
36#include <tools/pcb_actions.h>
38#include <tools/pad_tool.h>
39#include <footprint.h>
40#include <zone.h>
41#include <pcb_group.h>
48#include <env_paths.h>
49#include <paths.h>
51#include <kiplatform/ui.h>
52#include <project_pcb.h>
57#include <reporter.h>
58#include <view/view_controls.h>
59#include <wx/filedlg.h>
60#include <wx/fswatcher.h>
61
62
63static constexpr int ID_MAKE_NEW_LIBRARY = 4173;
64
65
66// unique, "file local" translations:
67
68
69static const wxString INFO_LEGACY_LIB_WARN_EDIT(
70 _( "Writing/modifying legacy libraries (.mod files) is not allowed\n"\
71 "Please save the current library to the new .pretty format\n"\
72 "and update your footprint lib table\n"\
73 "to save your footprint (a .kicad_mod file) in the .pretty library folder" ) );
74
75static const wxString INFO_LEGACY_LIB_WARN_DELETE(
76 _( "Modifying legacy libraries (.mod files) is not allowed\n"\
77 "Please save the current library under the new .pretty format\n"\
78 "and update your footprint lib table\n"\
79 "before deleting a footprint" ) );
80
81
83{
84 wxFileName fn;
85
86 if( !aName.empty() )
87 {
88 fn = aName;
89 }
90 else
91 {
92 // Prompt the user for a footprint file to open.
93 static int lastFilterIndex = 0; // To store the last choice during a session.
94 wxString fileFiltersStr;
95 std::vector<std::string> allExtensions;
96 std::set<wxString> allWildcardsSet;
97
98 for( const auto& plugin : PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins() )
99 {
100 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
101
102 if( !pi )
103 continue;
104
105 const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryFileDesc();
106
107 if( !desc )
108 continue;
109
110 if( !fileFiltersStr.IsEmpty() )
111 fileFiltersStr += wxChar( '|' );
112
113 fileFiltersStr += desc.FileFilter();
114
115 for( const std::string& ext : desc.m_FileExtensions )
116 {
117 allExtensions.emplace_back( ext );
118 allWildcardsSet.insert( wxT( "*." ) + formatWildcardExt( ext ) + wxT( ";" ) );
119 }
120 }
121
122 wxString allWildcardsStr;
123
124 for( const wxString& wildcard : allWildcardsSet )
125 allWildcardsStr << wildcard;
126
127 fileFiltersStr = _( "All supported formats" ) + wxT( "|" ) + allWildcardsStr + wxT( "|" )
128 + fileFiltersStr;
129
130 wxFileDialog dlg( this, _( "Import Footprint" ), m_mruPath, wxEmptyString, fileFiltersStr,
131 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
132
133 wxArrayString dummy1, dummy2;
134 const int nWildcards = wxParseCommonDialogsFilter( fileFiltersStr, dummy1, dummy2 );
135
136 if( lastFilterIndex >= 0 && lastFilterIndex < nWildcards )
137 dlg.SetFilterIndex( lastFilterIndex );
138
140
141 if( dlg.ShowModal() == wxID_CANCEL )
142 return nullptr;
143
144 lastFilterIndex = dlg.GetFilterIndex();
145
146 fn = dlg.GetPath();
147 }
148
149 if( !fn.IsOk() )
150 return nullptr;
151
152 if( !wxFileExists( fn.GetFullPath() ) )
153 {
154 wxString msg = wxString::Format( _( "File '%s' not found." ), fn.GetFullPath() );
155 DisplayError( this, msg );
156 return nullptr;
157 }
158
159 m_mruPath = fn.GetPath();
160
162
163 for( const auto& plugin : PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins() )
164 {
165 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
166
167 if( !pi )
168 continue;
169
170 if( pi->GetLibraryFileDesc().m_FileExtensions.empty() )
171 continue;
172
173 if( pi->CanReadFootprint( fn.GetFullPath() ) )
174 {
175 fileType = plugin.m_type;
176 break;
177 }
178 }
179
181 {
182 DisplayError( this, _( "Not a footprint file." ) );
183 return nullptr;
184 }
185
186 FOOTPRINT* footprint = nullptr;
187 wxString footprintName;
188
189 try
190 {
192
193 // This is a direct user action, so surface any import warnings rather than
194 // relying on a reporter that only the board loader would have attached.
195 pi->SetReporter( &WXLOG_REPORTER::GetInstance() );
196
197 footprint = pi->ImportFootprint( fn.GetFullPath(), footprintName);
198
199 if( !footprint )
200 {
201 wxString msg = wxString::Format( _( "Unable to load footprint '%s' from '%s'" ),
202 footprintName, fn.GetFullPath() );
203 DisplayError( this, msg );
204 return nullptr;
205 }
206 }
207 catch( const IO_ERROR& ioe )
208 {
209 DisplayError( this, ioe.What() );
210
211 // if the footprint is not loaded, exit.
212 // However, even if an error happens, it can be loaded, because in KICAD and GPCB format,
213 // a fp library is a set of separate files, and the error(s) are not necessary when
214 // reading the selected file
215
216 if( !footprint )
217 return nullptr;
218 }
219
220 footprint->SetFPID( LIB_ID( wxEmptyString, footprintName ) );
221
222 // An import has no library home to key a tab on and must not replace the document being edited, so
223 // it gets its own unnamed tab that a later save-as promotes
224 if( m_tabsPanel )
225 {
226 // The plugin's own board does not survive the tab switch; ReloadFootprint reparents the
227 // footprint to the incoming board
228 footprint->SetParent( nullptr );
230 }
231
232 // Insert footprint in list
233 AddFootprintToBoard( footprint );
234
235 // Display info :
236 SetMsgPanel( footprint );
237 PlaceFootprint( footprint );
238
239 footprint->SetPosition( VECTOR2I( 0, 0 ) );
240
242 UpdateView();
243
244 // The import lives only in its tab until saved to a library, so flag it dirty or closing the tab
245 // would silently discard it
246 if( m_tabsPanel )
247 OnModify();
248
249 return footprint;
250}
251
252
254{
255 wxFileName fn;
257
258 if( !aFootprint )
259 return;
260
261 fn.SetName( aFootprint->GetFPID().GetLibItemName() );
262
263 wxString wildcard = FILEEXT::KiCadFootprintLibFileWildcard();
264
266
267 if( !cfg->m_LastExportPath.empty() )
268 fn.SetPath( cfg->m_LastExportPath );
269 else
270 fn.SetPath( m_mruPath );
271
272 wxFileDialog dlg( this, _( "Export Footprint" ), fn.GetPath(), fn.GetFullName(),
273 wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
274
276
277 if( dlg.ShowModal() == wxID_CANCEL )
278 return;
279
281 cfg->m_LastExportPath = fn.GetPath();
282
283 try
284 {
285 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
286 // as an example on how it could also be used to send it to the system clipboard.
287
289
290 /* This footprint should *already* be "normalized" in a way such that
291 orientation is zero, etc., since it came from the Footprint Editor.
292
293 aFootprint->SetParent( 0 );
294 aFootprint->SetOrientation( 0 );
295 */
296
297 pcb_io.Format( aFootprint );
298
299 FILE* fp = wxFopen( dlg.GetPath(), wxT( "wt" ) );
300
301 if( fp == nullptr )
302 {
303 DisplayErrorMessage( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
304 dlg.GetPath() ) );
305 return;
306 }
307
308 std::string prettyData = pcb_io.GetStringOutput( false );
309 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::NORMAL );
310
311 fprintf( fp, "%s", prettyData.c_str() );
312 fclose( fp );
313 }
314 catch( const IO_ERROR& ioe )
315 {
316 DisplayError( this, ioe.What() );
317 return;
318 }
319
320 wxString msg = wxString::Format( _( "Footprint exported to file '%s'." ), dlg.GetPath() );
321 DisplayInfoMessage( this, msg );
322}
323
324
325wxString PCB_BASE_EDIT_FRAME::CreateNewProjectLibrary( const wxString& aDialogTitle, const wxString& aLibName )
326{
327 return createNewLibrary( aDialogTitle, aLibName, wxEmptyString, LIBRARY_TABLE_SCOPE::PROJECT );
328}
329
330
331wxString PCB_BASE_EDIT_FRAME::CreateNewLibrary( const wxString& aDialogTitle, const wxString& aInitialPath )
332{
333 return createNewLibrary( aDialogTitle, wxEmptyString, aInitialPath );
334}
335
336
337wxString PCB_BASE_EDIT_FRAME::createNewLibrary( const wxString& aDialogTitle, const wxString& aLibName,
338 const wxString& aInitialPath, std::optional<LIBRARY_TABLE_SCOPE> aScope )
339{
340 // Kicad cannot write legacy format libraries, only .pretty new format because the legacy
341 // format cannot handle current features.
342 // The footprint library is actually a directory.
343
344 wxFileName fn;
345 bool doAdd = false;
346 bool isGlobal = false;
347 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
348 FILEDLG_HOOK_NEW_LIBRARY* fileDlgHook = &tableChooser;
349
350 if( aScope )
351 fileDlgHook = nullptr;
352
353 if( aLibName.IsEmpty() )
354 {
355 fn = aInitialPath.IsEmpty() ? Prj().GetProjectPath() : aInitialPath;
356
357 if( !LibraryFileBrowser( aDialogTitle, false, fn, FILEEXT::KiCadFootprintLibPathWildcard(),
358 FILEEXT::KiCadFootprintLibPathExtension, false, fileDlgHook ) )
359 {
360 return wxEmptyString;
361 }
362
363 if( fileDlgHook )
364 {
365 isGlobal = fileDlgHook->GetUseGlobalTable();
367 }
368
369 doAdd = true;
370 }
371 else
372 {
374
375 if( !fn.IsAbsolute() )
376 {
377 fn.SetName( aLibName );
378 fn.MakeAbsolute( Prj().GetProjectPath() );
379 }
380 }
381
382 // We can save fp libs only using PCB_IO_MGR::KICAD_SEXP format (.pretty libraries)
384 wxString libPath = fn.GetFullPath();
385
386 try
387 {
389
390 bool writable = false;
391 bool exists = false;
392
393 try
394 {
395 writable = pi->IsLibraryWritable( libPath );
396 exists = true; // no exception was thrown, lib must exist.
397 }
398 catch( const IO_ERROR& )
399 {
400 // best efforts....
401 }
402
403 if( exists )
404 {
405 if( !writable )
406 {
407 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
408 ShowInfoBarError( msg );
409 return wxEmptyString;
410 }
411 else
412 {
413 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
414 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
415 dlg.SetOKLabel( _( "Overwrite" ) );
416 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
417
418 if( dlg.ShowModal() == wxID_CANCEL )
419 return wxEmptyString;
420
421 pi->DeleteLibrary( libPath );
422 }
423 }
424
425 pi->CreateLibrary( libPath );
426 }
427 catch( const IO_ERROR& ioe )
428 {
429 DisplayError( this, ioe.What() );
430 return wxEmptyString;
431 }
432
433 if( doAdd )
434 AddLibrary( aDialogTitle, libPath, aScope );
435
436 return libPath;
437}
438
439
440wxString PCB_BASE_EDIT_FRAME::SelectLibrary( const wxString& aDialogTitle, const wxString& aListLabel,
441 const std::vector<std::pair<wxString, bool*>>& aExtraCheckboxes )
442{
443 // Keep asking the user for a new name until they give a valid one or cancel the operation
444 while( true )
445 {
446 wxArrayString headers;
447 std::vector<wxArrayString> itemsToDisplay;
448
449 GetLibraryItemsForListDialog( headers, itemsToDisplay );
450
451 wxString libraryName = Prj().GetRString( PROJECT::PCB_LIB_NICKNAME );
452
453 EDA_LIST_DIALOG dlg( this, aDialogTitle, headers, itemsToDisplay, libraryName, false );
454 dlg.SetListLabel( aListLabel );
455
456 for( const auto& [label, val] : aExtraCheckboxes )
457 dlg.AddExtraCheckbox( label, val );
458
459 wxButton* newLibraryButton = new wxButton( &dlg, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
460 dlg.m_ButtonsSizer->Prepend( 80, 20 );
461 dlg.m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
462
463 newLibraryButton->Bind( wxEVT_BUTTON,
464 [&dlg]( wxCommandEvent& )
465 {
466 dlg.EndModal( ID_MAKE_NEW_LIBRARY );
468
469 dlg.Layout();
470 dlg.GetSizer()->Fit( &dlg );
471
472 int ret = dlg.ShowModal();
473
474 switch( ret )
475 {
476 case wxID_CANCEL:
477 return wxEmptyString;
478
479 case wxID_OK:
480 libraryName = dlg.GetTextSelection();
481 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, libraryName );
483 return libraryName;
484
486 {
487 wxFileName fn = CreateNewLibrary( _( "New Footprint Library" ),
488 Prj().GetRString( PROJECT::PCB_LIB_PATH ) );
489
490 Prj().SetRString( PROJECT::PCB_LIB_PATH, fn.GetPath() );
491 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, fn.GetName() );
492 break;
493 }
494
495 default:
496 break;
497 }
498 }
499}
500
501
502bool PCB_BASE_EDIT_FRAME::AddLibrary( const wxString& aDialogTitle, const wxString& aFilename,
503 std::optional<LIBRARY_TABLE_SCOPE> aScope )
504{
507 bool isGlobal = false;
508 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
509 FILEDLG_HOOK_NEW_LIBRARY* fileDlgHook = &tableChooser;
510
511 if( aScope )
512 {
513 isGlobal = ( *aScope == LIBRARY_TABLE_SCOPE::GLOBAL );
514 fileDlgHook = nullptr;
515 }
516
517 wxFileName fn( aFilename );
518
519 if( aFilename.IsEmpty() )
520 {
521 if( !LibraryFileBrowser( aDialogTitle, true, fn, FILEEXT::KiCadFootprintLibPathWildcard(),
522 FILEEXT::KiCadFootprintLibPathExtension, true, fileDlgHook ) )
523 {
524 return false;
525 }
526
527 if( fileDlgHook )
528 isGlobal = fileDlgHook->GetUseGlobalTable();
529 }
530
532
533 wxString libPath = fn.GetFullPath();
534 wxString libName = fn.GetName();
535
536 if( libName.IsEmpty() )
537 return false;
538
540
541 if( lib_type == PCB_IO_MGR::FILE_TYPE_NONE )
542 lib_type = PCB_IO_MGR::KICAD_SEXP;
543
544 wxString type = PCB_IO_MGR::ShowType( lib_type );
545
546 // KiCad lib is our default guess. So it might not have the .pretty extension
547 // In this case, the extension is part of the library name
548 if( lib_type == PCB_IO_MGR::KICAD_SEXP && fn.GetExt() != FILEEXT::KiCadFootprintLibPathExtension )
549 libName = fn.GetFullName();
550
551 // try to use path normalized to an environmental variable or project path
552 wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &Prj() );
553 bool success = true;
554
555 try
556 {
557 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::FOOTPRINT, aScope.value() );
558
559 if( !optTable )
560 return false;
561
562 LIBRARY_TABLE* table = optTable.value();
563
564 LIBRARY_TABLE_ROW& row = table->InsertRow();
565
566 row.SetNickname( libName );
567 row.SetURI( normalizedPath );
568 row.SetType( type );
569
570 table->Save().map_error(
571 [&]( const LIBRARY_ERROR& aError )
572 {
573 wxMessageBox( _( "Error saving library table:\n\n" ) + aError.message,
574 _( "File Save Error" ), wxOK | wxICON_ERROR );
575 success = false;
576 } );
577 }
578 catch( const IO_ERROR& ioe )
579 {
580 DisplayError( this, ioe.What() );
581 return false;
582 }
583
584 if( success )
585 {
586 manager.ReloadTables( aScope.value(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
587 adapter->LoadOne( fn.GetName() );
588
589 // Don't use dynamic_cast; it will fail across compile units on MacOS
591 {
592 LIB_ID libID( libName, wxEmptyString );
593 editor->SyncLibraryTree( true );
594 editor->FocusOnLibID( libID );
595 }
596
597 auto viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_VIEWER, false );
598
599 if( viewer )
600 viewer->ReCreateLibraryList();
601 }
602
603 return success;
604}
605
606
608{
609 if( !aFPID.IsValid() )
610 return false;
611
614
615 wxString nickname = aFPID.GetLibNickname();
616 wxString fpname = aFPID.GetLibItemName();
617 wxString libfullname;
618
619 // Legacy libraries are readable, but modifying legacy format is not allowed
620 // So prompt the user if he try to delete a footprint from a legacy lib
621 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, nickname ) )
622 libfullname = *optUri;
623 else
624 return false;
625
627 {
629 return false;
630 }
631
632 if( !adapter->IsFootprintLibWritable( nickname ) )
633 {
634 wxString msg = wxString::Format( _( "Library '%s' is read only." ), nickname );
635 ShowInfoBarError( msg );
636 return false;
637 }
638
639 // Confirmation
640 wxString msg = wxString::Format( _( "Delete footprint '%s' from library '%s'?" ),
641 fpname.GetData(),
642 nickname.GetData() );
643
644 if( aConfirm && !IsOK( this, msg ) )
645 return false;
646
647 try
648 {
649 adapter->DeleteFootprint( nickname, fpname );
650 }
651 catch( const IO_ERROR& ioe )
652 {
653 DisplayError( this, ioe.What() );
654 return false;
655 }
656
657 msg.Printf( _( "Footprint '%s' deleted from library '%s'" ),
658 fpname.GetData(),
659 nickname.GetData() );
660
661 SetStatusText( msg );
662
663 return true;
664}
665
666
667void PCB_EDIT_FRAME::ExportFootprintsToLibrary( bool aStoreInNewLib, const wxString& aLibName,
668 wxString* aLibPath )
669{
670 if( GetBoard()->GetFirstFootprint() == nullptr )
671 {
672 DisplayInfoMessage( this, _( "No footprints to export!" ) );
673 return;
674 }
675
676 bool map = false;
677 PROJECT& prj = Prj();
678 wxString nickname = SelectLibrary( _( "Export Footprints" ), _( "Export footprints to library:" ),
679 { { _( "Update board footprints to link to exported footprints" ), &map } } );
680
681 if( !nickname ) // Aborted
682 return;
683
684 prj.SetRString( PROJECT::PCB_LIB_NICKNAME, nickname );
685
686 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
687 {
688 bool saved = false;
689
690 try
691 {
693
694 if( !footprint->GetFPID().GetLibItemName().empty() ) // Handle old boards.
695 {
696 std::unique_ptr<FOOTPRINT> fpCopy(
697 static_cast<FOOTPRINT*>( footprint->Duplicate( IGNORE_PARENT_GROUP ) ) );
698
699 // Reset reference designator, group membership, and zone offset before saving
700
701 fpCopy->SetReference( "REF**" );
702 fpCopy->SetParentGroup( nullptr );
703
704 for( ZONE* zone : fpCopy->Zones() )
705 zone->Move( -fpCopy->GetPosition() );
706
707 adapter->SaveFootprint( nickname, fpCopy.get(), true );
708 saved = true;
709 }
710 }
711 catch( const IO_ERROR& ioe )
712 {
713 DisplayError( this, ioe.What() );
714 }
715
716 // Relink only if the footprint was actually written; otherwise the board would point
717 // at an entry the library does not contain.
718 if( map && saved )
719 {
720 LIB_ID id = footprint->GetFPID();
721 id.SetLibNickname( nickname );
722 footprint->SetFPID( id );
723 }
724 }
725}
726
727
729{
730 if( !aFootprint ) // Happen if no footprint loaded
731 return false;
732
733 PAD_TOOL* padTool = m_toolManager->GetTool<PAD_TOOL>();
734
735 if( padTool->InPadEditMode() )
737
738 wxString libraryName = aFootprint->GetFPID().GetLibNickname();
739 wxString footprintName = aFootprint->GetFPID().GetLibItemName();
740 bool nameChanged = m_footprintNameWhenLoaded != footprintName;
741
742 if( aFootprint->GetLink() != niluuid )
743 {
744 if( SaveFootprintToBoard( false ) )
745 {
746 m_footprintNameWhenLoaded = footprintName;
747 return true;
748 }
749
750 return false;
751 }
752 else if( libraryName.IsEmpty() || footprintName.IsEmpty() )
753 {
754 if( SaveFootprintAs( aFootprint ) )
755 {
756 // Re-read the name the save-as settled on; keeping the pre-save one would make the next
757 // save look like a rename and delete a library entry that was never ours
759 SyncLibraryTree( true );
760 return true;
761 }
762
763 return false;
764 }
765
767
768 // Legacy libraries are readable, but modifying legacy format is not allowed
769 // So prompt the user if he try to add/replace a footprint in a legacy lib
770 wxString libfullname;
771
772 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libraryName ) )
773 libfullname = *optUri;
774 else
775 return false;
776
778 {
780 return false;
781 }
782
783 // Save the renamed footprint before deleting the original, so a failed save does not
784 // destroy the old entry and lose the user's work (issue #23850).
785 if( !SaveFootprintInLibrary( aFootprint, libraryName ) )
786 return false;
787
788 if( nameChanged )
789 {
790 LIB_ID oldFPID( libraryName, m_footprintNameWhenLoaded );
791 DeleteFootprintFromLibrary( oldFPID, false );
792
793 m_footprintNameWhenLoaded = footprintName;
794 SyncLibraryTree( true );
795 }
796
797 return true;
798}
799
800
802{
805
806 LIB_ID fpID = aFootprint->GetFPID();
807 wxString libraryName = fpID.GetLibNickname();
808 wxString footprintName = fpID.GetLibItemName();
809
810 // Legacy libraries are readable, but modifying legacy format is not allowed
811 // So prompt the user if he try to add/replace a footprint in a legacy lib
812 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libraryName ) )
813 {
815 {
817 return false;
818 }
819 }
820 else
821 {
822 return false;
823 }
824
825 int i = 1;
826 wxString newName = footprintName;
827
828 // Append a number to the name until the name is unique in the library.
829 while( adapter->FootprintExists( libraryName, newName ) )
830 newName.Printf( "%s_%d", footprintName, i++ );
831
832 aFootprint->SetFPID( LIB_ID( libraryName, newName ) );
833
834 if( aFootprint->GetValue() == footprintName )
835 aFootprint->SetValue( newName );
836
837 return SaveFootprintInLibrary( aFootprint, libraryName );
838}
839
840
842 const wxString& aLibraryName )
843{
844 try
845 {
846 aFootprint->SetFPID( LIB_ID( wxEmptyString, aFootprint->GetFPID().GetLibItemName() ) );
847
848 // Clear selected, brightened, temp flags, edit flags, the whole shebang.
849 aFootprint->RunOnChildren(
850 []( BOARD_ITEM* child )
851 {
852 child->ClearFlags();
853 },
855
857
858 if( adapter->SaveFootprint( aLibraryName, aFootprint ) != FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK )
859 {
860 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
861
862 DisplayError( this, wxString::Format( _( "Footprint '%s' could not be saved to library '%s'." ),
863 aFootprint->GetFPID().GetUniStringLibItemName(),
864 aLibraryName ) );
865 return false;
866 }
867
868 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
869
870 if( aFootprint == GetBoard()->GetFirstFootprint() )
871 setFPWatcher( aFootprint );
872
873 return true;
874 }
875 catch( const IO_ERROR& ioe )
876 {
877 DisplayError( this, ioe.What() );
878
879 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
880 return false;
881 }
882}
883
884
886{
887 // update footprint in the current board,
888 // not just add it to the board with total disregard for the netlist...
889 PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB_EDITOR, false );
890
891 if( pcbframe == nullptr ) // happens when the board editor is not active (or closed)
892 {
893 ShowInfoBarError( _( "No board currently open." ) );
894 return false;
895 }
896
897 BOARD* mainpcb = pcbframe->GetBoard();
898 FOOTPRINT* sourceFootprint = nullptr;
899 FOOTPRINT* editorFootprint = GetBoard()->GetFirstFootprint();
900
901 if( !editorFootprint )
902 return false;
903
904 // Search the old footprint (source) if exists
905 // Because this source could be deleted when editing the main board...
906 if( editorFootprint->GetLink() != niluuid ) // this is not a new footprint ...
907 {
908 sourceFootprint = nullptr;
909
910 for( FOOTPRINT* candidate : mainpcb->Footprints() )
911 {
912 if( editorFootprint->GetLink() == candidate->m_Uuid )
913 {
914 sourceFootprint = candidate;
915 break;
916 }
917 }
918 }
919
920 if( !aAddNew && sourceFootprint == nullptr ) // source not found
921 {
922 DisplayError( this, _( "Unable to find the footprint on the main board.\nCannot save." ) );
923 return false;
924 }
925
926 TOOL_MANAGER* pcb_ToolManager = pcbframe->GetToolManager();
927
928 if( aAddNew && pcb_ToolManager->GetTool<BOARD_EDITOR_CONTROL>()->PlacingFootprint() )
929 {
930 DisplayError( this, _( "Previous footprint placement still in progress." ) );
931 return false;
932 }
933
935 BOARD_COMMIT commit( pcbframe );
936
937 // Create a copy for the board, first using Clone() to keep existing Uuids, and then either
938 // resetting the uuids to the board values or assigning new Uuids.
939 FOOTPRINT* newFootprint = static_cast<FOOTPRINT*>( editorFootprint->Clone() );
940 newFootprint->SetParent( mainpcb );
941 newFootprint->SetLink( niluuid );
942
943 auto fixUuid =
944 [&]( KIID& aUuid )
945 {
946 if( editorFootprint->GetLink() != niluuid && m_boardFootprintUuids.count( aUuid ) )
947 aUuid = m_boardFootprintUuids[ aUuid ];
948 else
949 aUuid = KIID();
950 };
951
952 {
953 KIID uuid = newFootprint->m_Uuid;
954 fixUuid( uuid );
955 newFootprint->SetUuid( uuid );
956 }
957
958 newFootprint->RunOnChildren(
959 [&]( BOARD_ITEM* aChild )
960 {
961 KIID uuid = aChild->m_Uuid;
962 fixUuid( uuid );
963 aChild->SetUuid( uuid );
964 },
966
967 // Right now, we only show the "Unconnected" net in the footprint editor, but this is still
968 // referenced in the footprint. So we need to update the net pointers in the footprint to
969 // point to the nets in the main board.
970 newFootprint->RunOnChildren(
971 [&]( BOARD_ITEM* aChild )
972 {
973 if( BOARD_CONNECTED_ITEM* conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( aChild ) )
974 {
975 NETINFO_ITEM* net = conn->GetNet();
976 auto& netmap = mainpcb->GetNetInfo().NetsByName();
977
978 if( net )
979 {
980 auto it = netmap.find( net->GetNetname() );
981
982 if( it != netmap.end() )
983 conn->SetNet( it->second );
984 }
985
986 }
987 },
989
990 BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
991
994 bds.m_StyleFPBarcodes );
995
996 if( sourceFootprint ) // this is an update command
997 {
998 // In the main board the new footprint replaces the old one (pos, orient, ref, value,
999 // connections and properties are kept) and the sourceFootprint (old footprint) is
1000 // deleted
1001 mainpcb->ExchangeFootprint( sourceFootprint, newFootprint, commit, true );
1002
1003 commit.Push( _( "Update Footprint" ) );
1004 }
1005 else // This is an insert command
1006 {
1007 KIGFX::VIEW_CONTROLS* viewControls = pcbframe->GetCanvas()->GetViewControls();
1008 VECTOR2D cursorPos = viewControls->GetCursorPosition();
1009
1010 commit.Add( newFootprint );
1011 viewControls->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
1012 pcbframe->PlaceFootprint( newFootprint );
1013 newFootprint->SetPosition( VECTOR2I( 0, 0 ) );
1014 viewControls->SetCrossHairCursorPosition( cursorPos, false );
1015 newFootprint->ResetUuid();
1016 commit.Push( _( "Insert Footprint" ) );
1017
1018 pcbframe->Raise();
1019 pcb_ToolManager->RunAction( PCB_ACTIONS::placeFootprint, newFootprint );
1020 }
1021
1022 newFootprint->ClearFlags();
1023
1024 return true;
1025}
1026
1027
1029{
1030public:
1031 SAVE_AS_DIALOG( FOOTPRINT_EDIT_FRAME* aParent, const wxString& aFootprintName,
1032 const wxString& aLibraryPreselect,
1033 std::function<bool( wxString libName, wxString fpName )> aValidator ) :
1034 EDA_LIST_DIALOG( aParent, _( "Save Footprint As" ), false ),
1035 m_validator( std::move( aValidator ) )
1036 {
1038 std::vector<wxString> nicknames = adapter->GetLibraryNames();
1039 wxArrayString headers;
1040 std::vector<wxArrayString> itemsToDisplay;
1041
1042 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
1043 initDialog( headers, itemsToDisplay, aLibraryPreselect );
1044
1045 SetListLabel( _( "Save in library:" ) );
1046 SetOKLabel( _( "Save" ) );
1047
1048 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
1049
1050 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
1051 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
1052
1053 m_fpNameCtrl = new wxTextCtrl( this, wxID_ANY, aFootprintName );
1054 bNameSizer->Add( m_fpNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
1055
1056 wxTextValidator nameValidator( wxFILTER_EXCLUDE_CHAR_LIST );
1057 nameValidator.SetCharExcludes( FOOTPRINT::StringLibNameInvalidChars( false ) );
1058 m_fpNameCtrl->SetValidator( nameValidator );
1059
1060 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
1061 m_ButtonsSizer->Prepend( 80, 20 );
1062 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
1063
1064 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
1065
1066 // If a footprint name was specified, disable loading of previously-saved state
1067 if( !aFootprintName.IsEmpty() )
1069
1070 Bind( wxEVT_BUTTON,
1071 [this]( wxCommandEvent& )
1072 {
1073 EndModal( ID_MAKE_NEW_LIBRARY );
1075
1076 // Move nameTextCtrl to the head of the tab-order
1077 if( GetChildren().DeleteObject( m_fpNameCtrl ) )
1078 GetChildren().Insert( m_fpNameCtrl );
1079
1081
1083
1084 Layout();
1085 GetSizer()->Fit( this );
1086
1087 Centre();
1088 }
1089
1090 wxString GetFPName()
1091 {
1092 wxString footprintName = m_fpNameCtrl->GetValue();
1093 footprintName.Trim( true );
1094 footprintName.Trim( false );
1095 return footprintName;
1096 }
1097
1098protected:
1099 bool TransferDataToWindow() override
1100 {
1101 // Respond to any filter text loaded from previously-saved state
1102 wxCommandEvent dummy;
1104
1105 return true;
1106 }
1107
1109 {
1110 return m_validator( GetTextSelection(), GetFPName() );
1111 }
1112
1113private:
1114 wxTextCtrl* m_fpNameCtrl;
1115 std::function<bool( wxString libName, wxString fpName )> m_validator;
1116};
1117
1118
1120{
1121 if( aFootprint == nullptr )
1122 return false;
1123
1124 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1126
1127 SetMsgPanel( aFootprint );
1128
1129 LIB_ID old_FPID = aFootprint->GetFPID();
1130 wxString libraryName = old_FPID.GetLibNickname();
1131 wxString footprintName = old_FPID.GetLibItemName();
1132 bool updateValue = aFootprint->GetValue() == footprintName;
1133 bool done = false;
1134 bool footprintExists = false;
1135
1136 while( !done )
1137 {
1138 SAVE_AS_DIALOG dlg( this, footprintName, libraryName,
1139 [&]( const wxString& newLib, const wxString& newName )
1140 {
1141 if( newLib.IsEmpty() )
1142 {
1143 wxMessageBox( _( "A library must be specified." ) );
1144 return false;
1145 }
1146
1147 if( newName.IsEmpty() )
1148 {
1149 wxMessageBox( _( "Footprint must have a name." ) );
1150 return false;
1151 }
1152
1153 // Legacy libraries are readable, but modifying legacy format is not allowed
1154 // So prompt the user if he try to add/replace a footprint in a legacy lib
1155 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, newLib ) )
1156 {
1158 {
1160 return false;
1161 }
1162 }
1163 else
1164 {
1165 return false;
1166 }
1167
1168 footprintExists = adapter->FootprintExists( newLib, newName );
1169
1170 if( footprintExists )
1171 {
1172 wxString msg = wxString::Format( _( "Footprint %s already exists in %s." ),
1173 newName,
1174 newLib );
1175
1176 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1177 errorDlg.SetOKLabel( _( "Overwrite" ) );
1178
1179 return errorDlg.ShowModal() == wxID_OK;
1180 }
1181
1182 return true;
1183 } );
1184
1185 int ret = dlg.ShowModal();
1186
1187 if( ret == wxID_CANCEL )
1188 {
1189 return false;
1190 }
1191 else if( ret == wxID_OK )
1192 {
1193 footprintName = dlg.GetFPName();
1194 libraryName = dlg.GetTextSelection();
1195 done = true;
1196 }
1197 else if( ret == ID_MAKE_NEW_LIBRARY )
1198 {
1199 wxFileName fn = CreateNewLibrary( _( "New Footprint Library" ),
1200 Prj().GetRString( PROJECT::PCB_LIB_PATH ) );
1201
1202 Prj().SetRString( PROJECT::PCB_LIB_PATH, fn.GetPath() );
1203 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, fn.GetName() );
1204 libraryName = fn.GetName();
1205 }
1206 }
1207
1208 aFootprint->SetFPID( LIB_ID( libraryName, footprintName ) );
1209
1210 if( updateValue )
1211 aFootprint->SetValue( footprintName );
1212
1213 if( !SaveFootprintInLibrary( aFootprint, libraryName ) )
1214 return false;
1215
1216 // Once saved-as a board footprint is no longer a board footprint
1217 aFootprint->SetLink( niluuid );
1218
1219 wxString fmt = footprintExists ? _( "Footprint '%s' replaced in '%s'" )
1220 : _( "Footprint '%s' added to '%s'" );
1221
1222 wxString msg = wxString::Format( fmt, footprintName.GetData(), libraryName.GetData() );
1223 SetStatusText( msg );
1224 RenameFootprintTab( old_FPID, aFootprint->GetFPID() );
1226
1227 return true;
1228}
1229
1230
1232{
1234 {
1235 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1236 GetLoadedFPID().GetLibItemName().wx_str() );
1237
1238 if( ConfirmRevertDialog( this, msg ) )
1239 {
1240 // Clone the baseline up front; a full clear drops the frame's copy of it
1241 std::unique_ptr<FOOTPRINT> restored(
1242 static_cast<FOOTPRINT*>( m_originalFootprintCopy->Clone() ) );
1243
1244 if( m_tabsPanel )
1245 {
1246 // Reverting one tab must leave the others open, so reload in place instead of
1247 // clearing the editor
1248 const wxString oldKey = m_activeTab ? m_activeTab->GetTabKey() : wxString();
1249
1251 installFootprintOnActiveBoard( restored.release() );
1252
1253 // The tab is keyed on the footprint name, which the revert may have rolled back
1254 if( m_activeTab && m_activeTab->GetTabKey() != oldKey )
1255 {
1256 m_tabsPanel->RenameTab( oldKey, m_activeTab->GetTabKey(),
1257 m_activeTab->GetDisplayName() );
1258 }
1259 }
1260 else
1261 {
1262 Clear_Pcb( false );
1263 installFootprintOnActiveBoard( restored.release() );
1264 }
1265
1266 Zoom_Automatique( false );
1267
1268 Update3DView( true, true );
1269
1271 ClearModify();
1272
1273 UpdateView();
1274 GetCanvas()->Refresh();
1275
1276 return true;
1277 }
1278 }
1279
1280 return false;
1281}
1282
1283
1284FOOTPRINT* PCB_BASE_FRAME::CreateNewFootprint( wxString aFootprintName, const wxString& aLibName )
1285{
1286 if( aFootprintName.IsEmpty() )
1287 aFootprintName = _( "Untitled" );
1288
1289 int footprintAttrs = FP_SMD;
1290
1291 if( !aLibName.IsEmpty() )
1292 {
1294 std::vector<wxString> fpnames;
1295 wxString baseName = aFootprintName;
1296 int idx = 1;
1297
1298 // Make sure the name is unique
1299 while( adapter->FootprintExists( aLibName, aFootprintName ) )
1300 aFootprintName = baseName + wxString::Format( wxS( "_%d" ), idx++ );
1301
1302 // Try to infer the footprint attributes from an existing footprint in the library
1303 try
1304 {
1305 fpnames = adapter->GetFootprintNames( aLibName, true );
1306
1307 if( !fpnames.empty() )
1308 {
1309 std::unique_ptr<FOOTPRINT> fp( adapter->LoadFootprint( aLibName, fpnames.back(), false ) );
1310
1311 if( fp )
1312 footprintAttrs = fp->GetAttributes();
1313 }
1314 }
1315 catch( ... )
1316 {
1317 // best efforts
1318 }
1319 }
1320
1321 // Create the new footprint and add it to the head of the linked list of footprints
1322 FOOTPRINT* footprint = new FOOTPRINT( GetBoard() );
1323
1324 // Update its name in lib
1325 footprint->SetFPID( LIB_ID( wxEmptyString, aFootprintName ) );
1326
1327 footprint->SetAttributes( footprintAttrs );
1328
1329 PCB_LAYER_ID txt_layer;
1330 VECTOR2I default_pos;
1332
1333 if( settings.m_DefaultFPTextItems.size() > 0 )
1334 {
1335 footprint->Reference().SetText( settings.m_DefaultFPTextItems[0].m_Text );
1336 footprint->Reference().SetVisible( settings.m_DefaultFPTextItems[0].m_Visible );
1337 }
1338
1339 txt_layer = settings.m_DefaultFPTextItems[0].m_Layer;
1340 footprint->Reference().SetLayer( txt_layer );
1341 default_pos.y -= settings.GetTextSize( txt_layer ).y / 2;
1342 footprint->Reference().SetPosition( default_pos );
1343 default_pos.y += settings.GetTextSize( txt_layer ).y;
1344
1345 if( settings.m_DefaultFPTextItems.size() > 1 )
1346 {
1347 footprint->Value().SetText( settings.m_DefaultFPTextItems[1].m_Text );
1348 footprint->Value().SetVisible( settings.m_DefaultFPTextItems[1].m_Visible );
1349 }
1350
1351 txt_layer = settings.m_DefaultFPTextItems[1].m_Layer;
1352 footprint->Value().SetLayer( txt_layer );
1353 default_pos.y += settings.GetTextSize( txt_layer ).y / 2;
1354 footprint->Value().SetPosition( default_pos );
1355 default_pos.y += settings.GetTextSize( txt_layer ).y;
1356
1357 for( size_t i = 2; i < settings.m_DefaultFPTextItems.size(); ++i )
1358 {
1359 PCB_TEXT* textItem = new PCB_TEXT( footprint );
1360 textItem->SetText( settings.m_DefaultFPTextItems[i].m_Text );
1361 txt_layer = (PCB_LAYER_ID) settings.m_DefaultFPTextItems[i].m_Layer;
1362 textItem->SetLayer( txt_layer );
1363 default_pos.y += settings.GetTextSize( txt_layer ).y / 2;
1364 textItem->SetPosition( default_pos );
1365 default_pos.y += settings.GetTextSize( txt_layer ).y;
1366 footprint->GraphicalItems().push_back( textItem );
1367 }
1368
1369 if( footprint->GetReference().IsEmpty() )
1370 footprint->SetReference( aFootprintName );
1371
1372 if( footprint->GetValue().IsEmpty() )
1373 footprint->SetValue( aFootprintName );
1374
1375 footprint->RunOnChildren(
1376 [&]( BOARD_ITEM* aChild )
1377 {
1378 if( aChild->Type() == PCB_FIELD_T || aChild->Type() == PCB_TEXT_T )
1379 {
1380 PCB_TEXT* textItem = static_cast<PCB_TEXT*>( aChild );
1381 PCB_LAYER_ID layer = textItem->GetLayer();
1382
1383 textItem->SetTextThickness( settings.GetTextThickness( layer ) );
1384 textItem->SetTextSize( settings.GetTextSize( layer ) );
1385 textItem->SetItalic( settings.GetTextItalic( layer ) );
1386 textItem->SetKeepUpright( settings.GetTextUpright( layer ) );
1387 }
1388 },
1390
1391 SetMsgPanel( footprint );
1392 return footprint;
1393}
1394
1395
1397 std::vector<wxArrayString>& aItemsToDisplay )
1398{
1399 aHeaders.Add( _( "Library" ) );
1400 aHeaders.Add( _( "Description" ) );
1401
1405 std::vector<wxString> nicknames = adapter->GetLibraryNames();
1406 std::vector<wxArrayString> unpinned;
1407
1408 for( const wxString& nickname : nicknames )
1409 {
1410 wxArrayString item;
1411 wxString description = adapter->GetLibraryDescription( nickname ).value_or( wxEmptyString );
1412
1413 if( alg::contains( project.m_PinnedFootprintLibs, nickname )
1414 || alg::contains( cfg->m_Session.pinned_fp_libs, nickname ) )
1415 {
1416 item.Add( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + nickname );
1417 item.Add( description );
1418 aItemsToDisplay.push_back( item );
1419 }
1420 else
1421 {
1422 item.Add( nickname );
1423 item.Add( description );
1424 unpinned.push_back( item );
1425 }
1426 }
1427
1428 std::sort( aItemsToDisplay.begin(), aItemsToDisplay.end(),
1429 []( const wxArrayString& a, const wxArrayString& b )
1430 {
1431 return StrNumCmp( a[0], b[0], true ) < 0;
1432 } );
1433
1434 std::sort( unpinned.begin(), unpinned.end(),
1435 []( const wxArrayString& a, const wxArrayString& b )
1436 {
1437 return StrNumCmp( a[0], b[0], true ) < 0;
1438 } );
1439
1440 std::ranges::copy( unpinned, std::back_inserter( aItemsToDisplay ) );
1441}
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
std::vector< TEXT_ITEM_INFO > m_DefaultFPTextItems
bool GetTextUpright(PCB_LAYER_ID aLayer) const
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.
Handle actions specific to the board editor in PcbNew.
bool PlacingFootprint() const
Re-entrancy checker for above.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:295
void SetUuid(const KIID &aUuid)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:343
void ResetUuid()
Definition board_item.h:249
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1098
void BuildListOfNets()
Definition board.h:1061
void ExchangeFootprint(FOOTPRINT *aExisting, FOOTPRINT *aNew, BOARD_COMMIT &aCommit, bool matchPadPositions, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true, bool resetTextPositions=true, bool resetTextContent=true, bool resetFabricationAttrs=true, bool resetClearanceOverrides=true, bool reset3DModels=true, bool resetTransform=false, bool *aUpdated=nullptr)
Replace aExisting with aNew, preserving connectivity and metadata.
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:599
const FOOTPRINTS & Footprints() const
Definition board.h:421
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
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={})
int ShowModal() override
UNDO_REDO_CONTAINER m_undoList
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, INFOBAR_MESSAGE_TYPE aType=INFOBAR_MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
UNDO_REDO_CONTAINER m_redoList
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
virtual void ReCreateHToolbar()
virtual void Zoom_Automatique(bool aWarpPointer)
Redraw the screen with best zoom level and the best centering that shows all the page or the board.
bool LibraryFileBrowser(const wxString &aTitle, bool doOpen, wxFileName &aFilename, const wxString &wildcard, const wxString &ext, bool isDirectory, FILEDLG_HOOK_NEW_LIBRARY *aFileDlgHook=nullptr)
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:154
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
A dialog which shows:
void textChangeInFilterBox(wxCommandEvent &event) override
void SetOKLabel(const wxString &aLabel)
void initDialog(const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText)
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
void AddExtraCheckbox(const wxString &aLabel, bool *aValuePtr)
Add a checkbox value to the dialog.
void GetExtraCheckboxValues()
Fills in the value pointers from the checkboxes after the dialog has run.
EDA_LIST_DIALOG(wxWindow *aParent, const wxString &aTitle, const wxArrayString &aItemHeaders, const std::vector< wxArrayString > &aItemList, const wxString &aPreselectText=wxEmptyString, bool aSortList=true)
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:420
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:302
FOOTPRINT_EDITOR_TAB_CONTEXT * createUnsavedFootprintTab()
Open a session-only tab for an imported footprint over a fresh fp-holder board and make it the active...
void SyncLibraryTree(bool aProgress)
Synchronize the footprint library tree to the current state of the footprint library table.
bool SaveFootprintInLibrary(FOOTPRINT *aFootprint, const wxString &aLibraryName)
FOOTPRINT_EDITOR_TAB_CONTEXT * m_activeTab
bool SaveFootprintAs(FOOTPRINT *aFootprint)
bool DuplicateFootprint(FOOTPRINT *aFootprint)
void ExportFootprint(FOOTPRINT *aFootprint)
Create a file containing only one footprint.
LIB_ID GetLoadedFPID() const
Return the LIB_ID of the part being edited.
bool SaveFootprintToBoard(bool aAddNew)
EDITOR_TABS_PANEL * m_tabsPanel
bool SaveFootprint(FOOTPRINT *aFootprint)
Save in an existing library a given footprint.
FOOTPRINT * ImportFootprint(const wxString &aName=wxT(""))
Read a file containing only one footprint.
std::map< KIID, KIID > m_boardFootprintUuids
bool IsContentModified() const override
Get if any footprints or libraries have been modified but not saved.
bool Clear_Pcb(bool doAskAboutUnsavedChanges)
Delete all and reinitialize the current board.
Definition initpcb.cpp:104
void RenameFootprintTab(const LIB_ID &aOldId, const LIB_ID &aNewId)
Update the open tab for aOldId, if any, to the renamed footprint aNewId so its label and key track th...
void AddFootprintToBoard(FOOTPRINT *aFootprint) override
Override from PCB_BASE_EDIT_FRAME which adds a footprint to the editor's dummy board,...
bool DeleteFootprintFromLibrary(const LIB_ID &aFPID, bool aConfirm)
Delete the given footprint from its library.
void OnModify() override
Must be called after a footprint change in order to set the "modify" flag of the current screen and p...
std::unique_ptr< FOOTPRINT > m_originalFootprintCopy
FOOTPRINT_EDITOR_SETTINGS * GetSettings()
void freeUndoRedoCommandsWithItems(UNDO_REDO_CONTAINER &aUndo, UNDO_REDO_CONTAINER &aRedo)
Free both the transient board items and the command wrappers in the given lists.
void installFootprintOnActiveBoard(FOOTPRINT *aFootprint)
Replace the active board's footprint with aFootprint and re-point the file watcher at it.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
bool IsFootprintLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
void DeleteFootprint(const wxString &aNickname, const wxString &aFootprintName)
Deletes the aFootprintName from the library given by aNickname.
SAVE_T SaveFootprint(const wxString &aNickname, const FOOTPRINT *aFootprint, bool aOverwrite=true)
Write aFootprint to an existing library given by aNickname.
std::vector< wxString > GetFootprintNames(const wxString &aNickname, bool aBestEfforts=false)
Retrieves a list of footprint names contained in a given loaded library.
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
bool FootprintExists(const wxString &aNickname, const wxString &aName)
Component library viewer main window.
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:445
void SetLink(const KIID &aLink)
Definition footprint.h:1192
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
void SetAttributes(int aAttributes)
Definition footprint.h:511
EDA_ITEM * Clone() const override
Invoke a function on all children.
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:893
const LIB_ID & GetFPID() const
Definition footprint.h:444
void SetReference(const wxString &aReference)
Definition footprint.h:863
void ApplyDefaultSettings(const BOARD &board, bool aStyleFields, bool aStyleText, bool aStyleShapes, bool aStyleDimensions, bool aStyleBarcodes)
Apply default board settings to the footprint field text properties.
void SetValue(const wxString &aValue)
Definition footprint.h:884
PCB_FIELD & Reference()
Definition footprint.h:894
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
KIID GetLink() const
Definition footprint.h:1191
static const wxChar * StringLibNameInvalidChars(bool aUserReadable)
Test for validity of the name in a library of the footprint ( no spaces, dir separators ....
const wxString & GetValue() const
Definition footprint.h:879
const wxString & GetReference() const
Definition footprint.h:857
DRAWINGS & GraphicalItems()
Definition footprint.h:378
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
Definition kiid.h:46
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:388
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:201
std::optional< wxString > GetLibraryDescription(const wxString &aNickname) const
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
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 wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
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
static const wxString GetPinningSymbol()
Handle the data for a net.
Definition netinfo.h:46
const wxString & GetNetname() const
Definition netinfo.h:100
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition netinfo.h:247
bool InPadEditMode()
Definition pad_tool.h:59
static TOOL_ACTION recombinePad
static TOOL_ACTION placeFootprint
wxString CreateNewLibrary(const wxString &aDialogTitle, const wxString &aInitialPath=wxEmptyString)
If a library name is given, creates a new footprint library in the project folder with the given name...
wxString SelectLibrary(const wxString &aDialogTitle, const wxString &aListLabel, const std::vector< std::pair< wxString, bool * > > &aExtraCheckboxes={})
Put up a dialog and allows the user to pick a library, for unspecified use.
wxString createNewLibrary(const wxString &aDialogTitle, const wxString &aLibName, const wxString &aInitialPath, std::optional< LIBRARY_TABLE_SCOPE > aScope=std::nullopt)
Create a new library in the given table.
wxString CreateNewProjectLibrary(const wxString &aDialogTitle, const wxString &aLibName)
bool AddLibrary(const wxString &aDialogTitle, const wxString &aLibName=wxEmptyString, std::optional< LIBRARY_TABLE_SCOPE > aScope=std::nullopt)
Add an existing library to either the global or project library table.
void setFPWatcher(FOOTPRINT *aFootprint)
Create or removes a watcher on the specified footprint.
FOOTPRINT * CreateNewFootprint(wxString aFootprintName, const wxString &aLibName)
Create a new footprint at position 0,0.
void GetLibraryItemsForListDialog(wxArrayString &aHeaders, std::vector< wxArrayString > &aItemsToDisplay)
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Return the BOARD_DESIGN_SETTINGS for the open project.
void PlaceFootprint(FOOTPRINT *aFootprint, bool aRecreateRatsnest=true, std::optional< VECTOR2I > aPosition=std::nullopt)
Place aFootprint at the current cursor position (or provided one) and updates footprint coordinates w...
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
The main frame for Pcbnew.
void ExportFootprintsToLibrary(bool aStoreInNewLib, const wxString &aLibName=wxEmptyString, wxString *aLibPath=nullptr)
Save footprints in a library:
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void Format(const BOARD_ITEM *aItem) const
Output aItem to aFormatter in s-expression format.
std::string GetStringOutput(bool doClear)
static PLUGIN_REGISTRY * Instance()
Definition pcb_io_mgr.h:97
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:52
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:54
@ LEGACY
Legacy Pcbnew file formats prior to s-expression.
Definition pcb_io_mgr.h:55
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a footprint library's libPath.
static const wxString ShowType(PCB_FILE_T aFileType)
Return a brief name for a plugin given aFileType enum.
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:496
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:468
virtual void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:95
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:562
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:126
The backing store for a PROJECT, in JSON format.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:63
@ PCB_LIB_PATH
Definition project.h:223
@ PCB_LIB_NICKNAME
Definition project.h:224
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition project.cpp:355
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition project.cpp:366
bool TransferDataFromWindow() override
SAVE_AS_DIALOG(FOOTPRINT_EDIT_FRAME *aParent, const wxString &aFootprintName, const wxString &aLibraryPreselect, std::function< bool(wxString libName, wxString fpName)> aValidator)
bool TransferDataToWindow() override
std::function< bool(wxString libName, wxString fpName)> m_validator
TOOL_MANAGER * m_toolManager
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Master controller class:
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
static REPORTER & GetInstance()
Definition reporter.cpp:279
Handle a list of polygons defining a copper zone.
Definition zone.h:70
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:792
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition confirm.cpp:133
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.
#define _(s)
@ RECURSE
Definition eda_item.h:49
#define IGNORE_PARENT_GROUP
Definition eda_item.h:53
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Definition env_paths.cpp:73
Helper functions to substitute paths with environmental variables.
@ FP_SMD
Definition footprint.h:84
static const wxString INFO_LEGACY_LIB_WARN_DELETE(_("Modifying legacy libraries (.mod files) is not allowed\n" "Please save the current library under the new .pretty format\n" "and update your footprint lib table\n" "before deleting a footprint"))
static const wxString INFO_LEGACY_LIB_WARN_EDIT(_("Writing/modifying legacy libraries (.mod files) is not allowed\n" "Please save the current library to the new .pretty format\n" "and update your footprint lib table\n" "to save your footprint (a .kicad_mod file) in the .pretty library folder"))
static constexpr int ID_MAKE_NEW_LIBRARY
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
static const std::string KiCadFootprintLibPathExtension
static const std::string KiCadFootprintFileExtension
static wxString KiCadFootprintLibFileWildcard()
static wxString KiCadFootprintLibPathWildcard()
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:728
KIID niluuid(0)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
This file contains miscellaneous commonly used macros and functions.
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:521
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
STL namespace.
Class to handle a set of BOARD_ITEMs.
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
KIWAY Kiway(KFCTL_STANDALONE)
std::vector< FAB_LAYER_COLOR > dummy
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
std::vector< wxString > pinned_fp_libs
Container that describes file type info.
Definition io_base.h:43
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition io_base.h:47
wxString FileFilter() const
Definition io_base.cpp:40
wxString message
@ ID_MAKE_NEW_LIBRARY
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:83
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.