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 std::unique_ptr<FOOTPRINT> footprint;
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 // The plugin's own board does not survive the tab switch; ReloadFootprint reparents the
225 // footprint to the incoming board
226 footprint->SetParent( nullptr );
228
229 // AddFootprintToBoard takes ownership of the footprint from here on
230 FOOTPRINT* fp = footprint.get();
231
232 // Insert footprint in list
233 AddFootprintToBoard( footprint.release() );
234
235 // Display info :
236 SetMsgPanel( fp );
237 PlaceFootprint( fp );
238
239 fp->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 OnModify();
247
248 return fp;
249}
250
251
253{
254 wxFileName fn;
256
257 if( !aFootprint )
258 return;
259
260 fn.SetName( aFootprint->GetFPID().GetLibItemName() );
261
262 wxString wildcard = FILEEXT::KiCadFootprintLibFileWildcard();
263
265
266 if( !cfg->m_LastExportPath.empty() )
267 fn.SetPath( cfg->m_LastExportPath );
268 else
269 fn.SetPath( m_mruPath );
270
271 wxFileDialog dlg( this, _( "Export Footprint" ), fn.GetPath(), fn.GetFullName(),
272 wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
273
275
276 if( dlg.ShowModal() == wxID_CANCEL )
277 return;
278
280 cfg->m_LastExportPath = fn.GetPath();
281
282 try
283 {
284 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
285 // as an example on how it could also be used to send it to the system clipboard.
286
288
289 /* This footprint should *already* be "normalized" in a way such that
290 orientation is zero, etc., since it came from the Footprint Editor.
291
292 aFootprint->SetParent( 0 );
293 aFootprint->SetOrientation( 0 );
294 */
295
296 pcb_io.Format( aFootprint );
297
298 FILE* fp = wxFopen( dlg.GetPath(), wxT( "wt" ) );
299
300 if( fp == nullptr )
301 {
302 DisplayErrorMessage( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
303 dlg.GetPath() ) );
304 return;
305 }
306
307 std::string prettyData = pcb_io.GetStringOutput( false );
308 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::NORMAL );
309
310 fprintf( fp, "%s", prettyData.c_str() );
311 fclose( fp );
312 }
313 catch( const IO_ERROR& ioe )
314 {
315 DisplayError( this, ioe.What() );
316 return;
317 }
318
319 wxString msg = wxString::Format( _( "Footprint exported to file '%s'." ), dlg.GetPath() );
320 DisplayInfoMessage( this, msg );
321}
322
323
324wxString PCB_BASE_EDIT_FRAME::CreateNewProjectLibrary( const wxString& aDialogTitle, const wxString& aLibName )
325{
326 return createNewLibrary( aDialogTitle, aLibName, wxEmptyString, LIBRARY_TABLE_SCOPE::PROJECT );
327}
328
329
330wxString PCB_BASE_EDIT_FRAME::CreateNewLibrary( const wxString& aDialogTitle, const wxString& aInitialPath )
331{
332 return createNewLibrary( aDialogTitle, wxEmptyString, aInitialPath );
333}
334
335
336wxString PCB_BASE_EDIT_FRAME::createNewLibrary( const wxString& aDialogTitle, const wxString& aLibName,
337 const wxString& aInitialPath, std::optional<LIBRARY_TABLE_SCOPE> aScope )
338{
339 // Kicad cannot write legacy format libraries, only .pretty new format because the legacy
340 // format cannot handle current features.
341 // The footprint library is actually a directory.
342
343 wxFileName fn;
344 bool doAdd = false;
345 bool isGlobal = false;
346 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
347 FILEDLG_HOOK_NEW_LIBRARY* fileDlgHook = &tableChooser;
348
349 if( aScope )
350 fileDlgHook = nullptr;
351
352 if( aLibName.IsEmpty() )
353 {
354 fn = aInitialPath.IsEmpty() ? Prj().GetProjectPath() : aInitialPath;
355
356 if( !LibraryFileBrowser( aDialogTitle, false, fn, FILEEXT::KiCadFootprintLibPathWildcard(),
357 FILEEXT::KiCadFootprintLibPathExtension, false, fileDlgHook ) )
358 {
359 return wxEmptyString;
360 }
361
362 if( fileDlgHook )
363 {
364 isGlobal = fileDlgHook->GetUseGlobalTable();
366 }
367
368 doAdd = true;
369 }
370 else
371 {
373
374 if( !fn.IsAbsolute() )
375 {
376 fn.SetName( aLibName );
377 fn.MakeAbsolute( Prj().GetProjectPath() );
378 }
379 }
380
381 // We can save fp libs only using PCB_IO_MGR::KICAD_SEXP format (.pretty libraries)
383 wxString libPath = fn.GetFullPath();
384
385 try
386 {
388
389 bool writable = false;
390 bool exists = false;
391
392 try
393 {
394 writable = pi->IsLibraryWritable( libPath );
395 exists = true; // no exception was thrown, lib must exist.
396 }
397 catch( const IO_ERROR& )
398 {
399 // best efforts....
400 }
401
402 if( exists )
403 {
404 if( !writable )
405 {
406 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
407 ShowInfoBarError( msg );
408 return wxEmptyString;
409 }
410 else
411 {
412 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
413 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
414 dlg.SetOKLabel( _( "Overwrite" ) );
415 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
416
417 if( dlg.ShowModal() == wxID_CANCEL )
418 return wxEmptyString;
419
420 pi->DeleteLibrary( libPath );
421 }
422 }
423
424 pi->CreateLibrary( libPath );
425 }
426 catch( const IO_ERROR& ioe )
427 {
428 DisplayError( this, ioe.What() );
429 return wxEmptyString;
430 }
431
432 if( doAdd )
433 AddLibrary( aDialogTitle, libPath, aScope );
434
435 return libPath;
436}
437
438
439wxString PCB_BASE_EDIT_FRAME::SelectLibrary( const wxString& aDialogTitle, const wxString& aListLabel,
440 const std::vector<std::pair<wxString, bool*>>& aExtraCheckboxes )
441{
442 // Keep asking the user for a new name until they give a valid one or cancel the operation
443 while( true )
444 {
445 wxArrayString headers;
446 std::vector<wxArrayString> itemsToDisplay;
447
448 GetLibraryItemsForListDialog( headers, itemsToDisplay );
449
450 wxString libraryName = Prj().GetRString( PROJECT::PCB_LIB_NICKNAME );
451
452 EDA_LIST_DIALOG dlg( this, aDialogTitle, headers, itemsToDisplay, libraryName, false );
453 dlg.SetListLabel( aListLabel );
454
455 for( const auto& [label, val] : aExtraCheckboxes )
456 dlg.AddExtraCheckbox( label, val );
457
458 wxButton* newLibraryButton = new wxButton( &dlg, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
459 dlg.m_ButtonsSizer->Prepend( 80, 20 );
460 dlg.m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
461
462 newLibraryButton->Bind( wxEVT_BUTTON,
463 [&dlg]( wxCommandEvent& )
464 {
465 dlg.EndModal( ID_MAKE_NEW_LIBRARY );
467
468 dlg.Layout();
469 dlg.GetSizer()->Fit( &dlg );
470
471 int ret = dlg.ShowModal();
472
473 switch( ret )
474 {
475 case wxID_CANCEL:
476 return wxEmptyString;
477
478 case wxID_OK:
479 libraryName = dlg.GetTextSelection();
480 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, libraryName );
482 return libraryName;
483
485 {
486 wxFileName fn = CreateNewLibrary( _( "New Footprint Library" ),
487 Prj().GetRString( PROJECT::PCB_LIB_PATH ) );
488
489 Prj().SetRString( PROJECT::PCB_LIB_PATH, fn.GetPath() );
490 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, fn.GetName() );
491 break;
492 }
493
494 default:
495 break;
496 }
497 }
498}
499
500
501bool PCB_BASE_EDIT_FRAME::AddLibrary( const wxString& aDialogTitle, const wxString& aFilename,
502 std::optional<LIBRARY_TABLE_SCOPE> aScope )
503{
506 bool isGlobal = false;
507 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
508 FILEDLG_HOOK_NEW_LIBRARY* fileDlgHook = &tableChooser;
509
510 if( aScope )
511 {
512 isGlobal = ( *aScope == LIBRARY_TABLE_SCOPE::GLOBAL );
513 fileDlgHook = nullptr;
514 }
515
516 wxFileName fn( aFilename );
517
518 if( aFilename.IsEmpty() )
519 {
520 if( !LibraryFileBrowser( aDialogTitle, true, fn, FILEEXT::KiCadFootprintLibPathWildcard(),
521 FILEEXT::KiCadFootprintLibPathExtension, true, fileDlgHook ) )
522 {
523 return false;
524 }
525
526 if( fileDlgHook )
527 isGlobal = fileDlgHook->GetUseGlobalTable();
528 }
529
531
532 wxString libPath = fn.GetFullPath();
533 wxString libName = fn.GetName();
534
535 if( libName.IsEmpty() )
536 return false;
537
539
540 if( lib_type == PCB_IO_MGR::FILE_TYPE_NONE )
541 lib_type = PCB_IO_MGR::KICAD_SEXP;
542
543 wxString type = PCB_IO_MGR::ShowType( lib_type );
544
545 // KiCad lib is our default guess. So it might not have the .pretty extension
546 // In this case, the extension is part of the library name
547 if( lib_type == PCB_IO_MGR::KICAD_SEXP && fn.GetExt() != FILEEXT::KiCadFootprintLibPathExtension )
548 libName = fn.GetFullName();
549
550 // try to use path normalized to an environmental variable or project path
551 wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &Prj() );
552 bool success = true;
553
554 try
555 {
556 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::FOOTPRINT, aScope.value() );
557
558 if( !optTable )
559 return false;
560
561 LIBRARY_TABLE* table = optTable.value();
562
563 LIBRARY_TABLE_ROW& row = table->InsertRow();
564
565 row.SetNickname( libName );
566 row.SetURI( normalizedPath );
567 row.SetType( type );
568
569 table->Save().map_error(
570 [&]( const LIBRARY_ERROR& aError )
571 {
572 wxMessageBox( _( "Error saving library table:\n\n" ) + aError.message,
573 _( "File Save Error" ), wxOK | wxICON_ERROR );
574 success = false;
575 } );
576 }
577 catch( const IO_ERROR& ioe )
578 {
579 DisplayError( this, ioe.What() );
580 return false;
581 }
582
583 if( success )
584 {
585 manager.ReloadTables( aScope.value(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
586 adapter->LoadOne( fn.GetName() );
587
588 // Don't use dynamic_cast; it will fail across compile units on MacOS
590 {
591 LIB_ID libID( libName, wxEmptyString );
592 editor->SyncLibraryTree( true );
593 editor->FocusOnLibID( libID );
594 }
595
596 auto viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_VIEWER, false );
597
598 if( viewer )
599 viewer->ReCreateLibraryList();
600 }
601
602 return success;
603}
604
605
607{
608 if( !aFPID.IsValid() )
609 return false;
610
613
614 wxString nickname = aFPID.GetLibNickname();
615 wxString fpname = aFPID.GetLibItemName();
616 wxString libfullname;
617
618 // Legacy libraries are readable, but modifying legacy format is not allowed
619 // So prompt the user if he try to delete a footprint from a legacy lib
620 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, nickname ) )
621 libfullname = *optUri;
622 else
623 return false;
624
626 {
628 return false;
629 }
630
631 if( !adapter->IsFootprintLibWritable( nickname ) )
632 {
633 wxString msg = wxString::Format( _( "Library '%s' is read only." ), nickname );
634 ShowInfoBarError( msg );
635 return false;
636 }
637
638 // Confirmation
639 wxString msg = wxString::Format( _( "Delete footprint '%s' from library '%s'?" ),
640 fpname.GetData(),
641 nickname.GetData() );
642
643 if( aConfirm && !IsOK( this, msg ) )
644 return false;
645
646 try
647 {
648 adapter->DeleteFootprint( nickname, fpname );
649 }
650 catch( const IO_ERROR& ioe )
651 {
652 DisplayError( this, ioe.What() );
653 return false;
654 }
655
656 msg.Printf( _( "Footprint '%s' deleted from library '%s'" ),
657 fpname.GetData(),
658 nickname.GetData() );
659
660 SetStatusText( msg );
661
662 return true;
663}
664
665
666void PCB_EDIT_FRAME::ExportFootprintsToLibrary( bool aStoreInNewLib, const wxString& aLibName,
667 wxString* aLibPath )
668{
669 if( GetBoard()->GetFirstFootprint() == nullptr )
670 {
671 DisplayInfoMessage( this, _( "No footprints to export!" ) );
672 return;
673 }
674
675 bool map = false;
676 PROJECT& prj = Prj();
677 wxString nickname = SelectLibrary( _( "Export Footprints" ), _( "Export footprints to library:" ),
678 { { _( "Update board footprints to link to exported footprints" ), &map } } );
679
680 if( !nickname ) // Aborted
681 return;
682
683 prj.SetRString( PROJECT::PCB_LIB_NICKNAME, nickname );
684
685 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
686 {
687 bool saved = false;
688
689 try
690 {
692
693 if( !footprint->GetFPID().GetLibItemName().empty() ) // Handle old boards.
694 {
695 std::unique_ptr<FOOTPRINT> fpCopy(
696 static_cast<FOOTPRINT*>( footprint->Duplicate( IGNORE_PARENT_GROUP ) ) );
697
698 // Reset reference designator, group membership, and zone offset before saving
699
700 fpCopy->SetReference( "REF**" );
701 fpCopy->SetParentGroup( nullptr );
702
703 for( ZONE* zone : fpCopy->Zones() )
704 zone->Move( -fpCopy->GetPosition() );
705
706 adapter->SaveFootprint( nickname, fpCopy.get(), true );
707 saved = true;
708 }
709 }
710 catch( const IO_ERROR& ioe )
711 {
712 DisplayError( this, ioe.What() );
713 }
714
715 // Relink only if the footprint was actually written; otherwise the board would point
716 // at an entry the library does not contain.
717 if( map && saved )
718 {
719 LIB_ID id = footprint->GetFPID();
720 id.SetLibNickname( nickname );
721 footprint->SetFPID( id );
722 }
723 }
724}
725
726
728{
729 if( !aFootprint ) // Happen if no footprint loaded
730 return false;
731
732 PAD_TOOL* padTool = m_toolManager->GetTool<PAD_TOOL>();
733
734 if( padTool->InPadEditMode() )
736
737 wxString libraryName = aFootprint->GetFPID().GetLibNickname();
738 wxString footprintName = aFootprint->GetFPID().GetLibItemName();
739 bool nameChanged = m_footprintNameWhenLoaded != footprintName;
740
741 if( aFootprint->GetLink() != niluuid )
742 {
743 if( SaveFootprintToBoard( false ) )
744 {
745 m_footprintNameWhenLoaded = footprintName;
746 return true;
747 }
748
749 return false;
750 }
751 else if( libraryName.IsEmpty() || footprintName.IsEmpty() )
752 {
753 if( SaveFootprintAs( aFootprint ) )
754 {
755 // Re-read the name the save-as settled on; keeping the pre-save one would make the next
756 // save look like a rename and delete a library entry that was never ours
758 SyncLibraryTree( true );
759 return true;
760 }
761
762 return false;
763 }
764
766
767 // Legacy libraries are readable, but modifying legacy format is not allowed
768 // So prompt the user if he try to add/replace a footprint in a legacy lib
769 wxString libfullname;
770
771 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libraryName ) )
772 libfullname = *optUri;
773 else
774 return false;
775
777 {
779 return false;
780 }
781
782 // Save the renamed footprint before deleting the original, so a failed save does not
783 // destroy the old entry and lose the user's work (issue #23850).
784 if( !SaveFootprintInLibrary( aFootprint, libraryName ) )
785 return false;
786
787 if( nameChanged )
788 {
789 LIB_ID oldFPID( libraryName, m_footprintNameWhenLoaded );
790 DeleteFootprintFromLibrary( oldFPID, false );
791
792 m_footprintNameWhenLoaded = footprintName;
793 SyncLibraryTree( true );
794 }
795
796 return true;
797}
798
799
801{
804
805 LIB_ID fpID = aFootprint->GetFPID();
806 wxString libraryName = fpID.GetLibNickname();
807 wxString footprintName = fpID.GetLibItemName();
808
809 // Legacy libraries are readable, but modifying legacy format is not allowed
810 // So prompt the user if he try to add/replace a footprint in a legacy lib
811 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libraryName ) )
812 {
814 {
816 return false;
817 }
818 }
819 else
820 {
821 return false;
822 }
823
824 int i = 1;
825 wxString newName = footprintName;
826
827 // Append a number to the name until the name is unique in the library.
828 while( adapter->FootprintExists( libraryName, newName ) )
829 newName.Printf( "%s_%d", footprintName, i++ );
830
831 aFootprint->SetFPID( LIB_ID( libraryName, newName ) );
832
833 if( aFootprint->GetValue() == footprintName )
834 aFootprint->SetValue( newName );
835
836 return SaveFootprintInLibrary( aFootprint, libraryName );
837}
838
839
841 const wxString& aLibraryName )
842{
843 try
844 {
845 aFootprint->SetFPID( LIB_ID( wxEmptyString, aFootprint->GetFPID().GetLibItemName() ) );
846
847 // Clear selected, brightened, temp flags, edit flags, the whole shebang.
848 aFootprint->RunOnChildren(
849 []( BOARD_ITEM* child )
850 {
851 child->ClearFlags();
852 },
854
856
857 if( adapter->SaveFootprint( aLibraryName, aFootprint ) != FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK )
858 {
859 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
860
861 DisplayError( this, wxString::Format( _( "Footprint '%s' could not be saved to library '%s'." ),
862 aFootprint->GetFPID().GetUniStringLibItemName(),
863 aLibraryName ) );
864 return false;
865 }
866
867 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
868
869 if( aFootprint == GetBoard()->GetFirstFootprint() )
870 setFPWatcher( aFootprint );
871
872 return true;
873 }
874 catch( const IO_ERROR& ioe )
875 {
876 DisplayError( this, ioe.What() );
877
878 aFootprint->SetFPID( LIB_ID( aLibraryName, aFootprint->GetFPID().GetLibItemName() ) );
879 return false;
880 }
881}
882
883
885{
886 // update footprint in the current board,
887 // not just add it to the board with total disregard for the netlist...
888 PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB_EDITOR, false );
889
890 if( pcbframe == nullptr ) // happens when the board editor is not active (or closed)
891 {
892 ShowInfoBarError( _( "No board currently open." ) );
893 return false;
894 }
895
896 BOARD* mainpcb = pcbframe->GetBoard();
897 FOOTPRINT* sourceFootprint = nullptr;
898 FOOTPRINT* editorFootprint = GetBoard()->GetFirstFootprint();
899
900 if( !editorFootprint )
901 return false;
902
903 // Search the old footprint (source) if exists
904 // Because this source could be deleted when editing the main board...
905 if( editorFootprint->GetLink() != niluuid ) // this is not a new footprint ...
906 {
907 sourceFootprint = nullptr;
908
909 for( FOOTPRINT* candidate : mainpcb->Footprints() )
910 {
911 if( editorFootprint->GetLink() == candidate->m_Uuid )
912 {
913 sourceFootprint = candidate;
914 break;
915 }
916 }
917 }
918
919 if( !aAddNew && sourceFootprint == nullptr ) // source not found
920 {
921 DisplayError( this, _( "Unable to find the footprint on the main board.\nCannot save." ) );
922 return false;
923 }
924
925 TOOL_MANAGER* pcb_ToolManager = pcbframe->GetToolManager();
926
927 if( aAddNew && pcb_ToolManager->GetTool<BOARD_EDITOR_CONTROL>()->PlacingFootprint() )
928 {
929 DisplayError( this, _( "Previous footprint placement still in progress." ) );
930 return false;
931 }
932
934 BOARD_COMMIT commit( pcbframe );
935
936 // Create a copy for the board, first using Clone() to keep existing Uuids, and then either
937 // resetting the uuids to the board values or assigning new Uuids.
938 FOOTPRINT* newFootprint = static_cast<FOOTPRINT*>( editorFootprint->Clone() );
939 newFootprint->SetParent( mainpcb );
940 newFootprint->SetLink( niluuid );
941
942 auto fixUuid =
943 [&]( KIID& aUuid )
944 {
945 if( editorFootprint->GetLink() != niluuid && m_boardFootprintUuids.count( aUuid ) )
946 aUuid = m_boardFootprintUuids[ aUuid ];
947 else
948 aUuid = KIID();
949 };
950
951 {
952 KIID uuid = newFootprint->m_Uuid;
953 fixUuid( uuid );
954 newFootprint->SetUuid( uuid );
955 }
956
957 newFootprint->RunOnChildren(
958 [&]( BOARD_ITEM* aChild )
959 {
960 KIID uuid = aChild->m_Uuid;
961 fixUuid( uuid );
962 aChild->SetUuid( uuid );
963 },
965
966 // Right now, we only show the "Unconnected" net in the footprint editor, but this is still
967 // referenced in the footprint. So we need to update the net pointers in the footprint to
968 // point to the nets in the main board.
969 newFootprint->RunOnChildren(
970 [&]( BOARD_ITEM* aChild )
971 {
972 if( BOARD_CONNECTED_ITEM* conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( aChild ) )
973 {
974 NETINFO_ITEM* net = conn->GetNet();
975 auto& netmap = mainpcb->GetNetInfo().NetsByName();
976
977 if( net )
978 {
979 auto it = netmap.find( net->GetNetname() );
980
981 if( it != netmap.end() )
982 conn->SetNet( it->second );
983 }
984
985 }
986 },
988
989 BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
990
993
994 if( sourceFootprint ) // this is an update command
995 {
996 // In the main board the new footprint replaces the old one (pos, orient, ref, value, connections
997 // and properties are kept) and the sourceFootprint (old footprint) is deleted
998 mainpcb->ExchangeFootprint( sourceFootprint, newFootprint, commit, true /* match pad positions */ );
999
1000 commit.Push( _( "Update Footprint" ) );
1001 }
1002 else // This is an insert command
1003 {
1004 KIGFX::VIEW_CONTROLS* viewControls = pcbframe->GetCanvas()->GetViewControls();
1005 VECTOR2D cursorPos = viewControls->GetCursorPosition();
1006
1007 commit.Add( newFootprint );
1008 viewControls->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
1009 pcbframe->PlaceFootprint( newFootprint );
1010 newFootprint->SetPosition( VECTOR2I( 0, 0 ) );
1011 viewControls->SetCrossHairCursorPosition( cursorPos, false );
1012 newFootprint->ResetUuid();
1013 commit.Push( _( "Insert Footprint" ) );
1014
1015 pcbframe->Raise();
1016 pcb_ToolManager->RunAction( PCB_ACTIONS::placeFootprint, newFootprint );
1017 }
1018
1019 newFootprint->ClearFlags();
1020
1021 return true;
1022}
1023
1024
1026{
1027public:
1028 SAVE_AS_DIALOG( FOOTPRINT_EDIT_FRAME* aParent, const wxString& aFootprintName,
1029 const wxString& aLibraryPreselect,
1030 std::function<bool( wxString libName, wxString fpName )> aValidator ) :
1031 EDA_LIST_DIALOG( aParent, _( "Save Footprint As" ), false ),
1032 m_validator( std::move( aValidator ) )
1033 {
1035 std::vector<wxString> nicknames = adapter->GetLibraryNames();
1036 wxArrayString headers;
1037 std::vector<wxArrayString> itemsToDisplay;
1038
1039 aParent->GetLibraryItemsForListDialog( headers, itemsToDisplay );
1040 initDialog( headers, itemsToDisplay, aLibraryPreselect );
1041
1042 SetListLabel( _( "Save in library:" ) );
1043 SetOKLabel( _( "Save" ) );
1044
1045 wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
1046
1047 wxStaticText* label = new wxStaticText( this, wxID_ANY, _( "Name:" ) );
1048 bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
1049
1050 m_fpNameCtrl = new wxTextCtrl( this, wxID_ANY, aFootprintName );
1051 bNameSizer->Add( m_fpNameCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
1052
1053 wxTextValidator nameValidator( wxFILTER_EXCLUDE_CHAR_LIST );
1054 nameValidator.SetCharExcludes( FOOTPRINT::StringLibNameInvalidChars( false ) );
1055 m_fpNameCtrl->SetValidator( nameValidator );
1056
1057 wxButton* newLibraryButton = new wxButton( this, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
1058 m_ButtonsSizer->Prepend( 80, 20 );
1059 m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
1060
1061 GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
1062
1063 // If a footprint name was specified, disable loading of previously-saved state
1064 if( !aFootprintName.IsEmpty() )
1066
1067 Bind( wxEVT_BUTTON,
1068 [this]( wxCommandEvent& )
1069 {
1070 EndModal( ID_MAKE_NEW_LIBRARY );
1072
1073 // Move nameTextCtrl to the head of the tab-order
1074 if( GetChildren().DeleteObject( m_fpNameCtrl ) )
1075 GetChildren().Insert( m_fpNameCtrl );
1076
1078
1080
1081 Layout();
1082 GetSizer()->Fit( this );
1083
1084 Centre();
1085 }
1086
1087 wxString GetFPName()
1088 {
1089 wxString footprintName = m_fpNameCtrl->GetValue();
1090 footprintName.Trim( true );
1091 footprintName.Trim( false );
1092 return footprintName;
1093 }
1094
1095 bool TransferDataToWindow() override
1096 {
1097 // Respond to any filter text loaded from previously-saved state
1098 wxCommandEvent dummy;
1100
1101 return true;
1102 }
1103
1105 {
1106 return m_validator( GetTextSelection(), GetFPName() );
1107 }
1108
1109private:
1110 wxTextCtrl* m_fpNameCtrl;
1111 std::function<bool( wxString libName, wxString fpName )> m_validator;
1112};
1113
1114
1116{
1117 if( aFootprint == nullptr )
1118 return false;
1119
1120 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1122
1123 SetMsgPanel( aFootprint );
1124
1125 LIB_ID old_FPID = aFootprint->GetFPID();
1126 wxString libraryName = old_FPID.GetLibNickname();
1127 wxString footprintName = old_FPID.GetLibItemName();
1128 bool updateValue = aFootprint->GetValue() == footprintName;
1129 bool done = false;
1130 bool footprintExists = false;
1131
1132 while( !done )
1133 {
1134 SAVE_AS_DIALOG dlg( this, footprintName, libraryName,
1135 [&]( const wxString& newLib, const wxString& newName )
1136 {
1137 if( newLib.IsEmpty() )
1138 {
1139 wxMessageBox( _( "A library must be specified." ) );
1140 return false;
1141 }
1142
1143 if( newName.IsEmpty() )
1144 {
1145 wxMessageBox( _( "Footprint must have a name." ) );
1146 return false;
1147 }
1148
1149 // Legacy libraries are readable, but modifying legacy format is not allowed
1150 // So prompt the user if he try to add/replace a footprint in a legacy lib
1151 if( std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, newLib ) )
1152 {
1154 {
1156 return false;
1157 }
1158 }
1159 else
1160 {
1161 return false;
1162 }
1163
1164 footprintExists = adapter->FootprintExists( newLib, newName );
1165
1166 if( footprintExists )
1167 {
1168 wxString msg = wxString::Format( _( "Footprint %s already exists in %s." ),
1169 newName,
1170 newLib );
1171
1172 KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
1173 errorDlg.SetOKLabel( _( "Overwrite" ) );
1174
1175 return errorDlg.ShowModal() == wxID_OK;
1176 }
1177
1178 return true;
1179 } );
1180
1181 int ret = dlg.ShowModal();
1182
1183 if( ret == wxID_CANCEL )
1184 {
1185 return false;
1186 }
1187 else if( ret == wxID_OK )
1188 {
1189 footprintName = dlg.GetFPName();
1190 libraryName = dlg.GetTextSelection();
1191 done = true;
1192 }
1193 else if( ret == ID_MAKE_NEW_LIBRARY )
1194 {
1195 wxFileName fn = CreateNewLibrary( _( "New Footprint Library" ),
1196 Prj().GetRString( PROJECT::PCB_LIB_PATH ) );
1197
1198 Prj().SetRString( PROJECT::PCB_LIB_PATH, fn.GetPath() );
1199 Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, fn.GetName() );
1200 libraryName = fn.GetName();
1201 }
1202 }
1203
1204 aFootprint->SetFPID( LIB_ID( libraryName, footprintName ) );
1205
1206 if( updateValue )
1207 aFootprint->SetValue( footprintName );
1208
1209 if( !SaveFootprintInLibrary( aFootprint, libraryName ) )
1210 return false;
1211
1212 // Once saved-as a board footprint is no longer a board footprint
1213 aFootprint->SetLink( niluuid );
1214
1215 wxString fmt = footprintExists ? _( "Footprint '%s' replaced in '%s'" )
1216 : _( "Footprint '%s' added to '%s'" );
1217
1218 wxString msg = wxString::Format( fmt, footprintName.GetData(), libraryName.GetData() );
1219 SetStatusText( msg );
1220 RenameFootprintTab( old_FPID, aFootprint->GetFPID() );
1222
1223 return true;
1224}
1225
1226
1228{
1230 {
1231 wxString msg = wxString::Format( _( "Revert '%s' to last version saved?" ),
1232 GetLoadedFPID().GetLibItemName().wx_str() );
1233
1234 if( ConfirmRevertDialog( this, msg ) )
1235 {
1236 // Clone the baseline up front; a full clear drops the frame's copy of it
1237 std::unique_ptr<FOOTPRINT> restored( static_cast<FOOTPRINT*>( m_originalFootprintCopy->Clone() ) );
1238
1239 // Reverting one tab must leave the others open, so reload in place instead of
1240 // clearing the editor
1241 const wxString oldKey = m_activeTab ? m_activeTab->GetTabKey() : wxString();
1242
1244 installFootprintOnActiveBoard( restored.release() );
1245
1246 // The tab is keyed on the footprint name, which the revert may have rolled back
1247 if( m_activeTab && m_activeTab->GetTabKey() != oldKey )
1248 m_tabsPanel->RenameTab( oldKey, m_activeTab->GetTabKey(), m_activeTab->GetDisplayName() );
1249
1250 Zoom_Automatique( false );
1251
1252 Update3DView( true, true );
1253
1255 ClearModify();
1256
1257 UpdateView();
1258 GetCanvas()->Refresh();
1259
1260 return true;
1261 }
1262 }
1263
1264 return false;
1265}
1266
1267
1268FOOTPRINT* PCB_BASE_FRAME::CreateNewFootprint( wxString aFootprintName, const wxString& aLibName )
1269{
1270 if( aFootprintName.IsEmpty() )
1271 aFootprintName = _( "Untitled" );
1272
1273 int footprintAttrs = FP_SMD;
1274
1275 if( !aLibName.IsEmpty() )
1276 {
1278 std::vector<wxString> fpnames;
1279 wxString baseName = aFootprintName;
1280 int idx = 1;
1281
1282 // Make sure the name is unique
1283 while( adapter->FootprintExists( aLibName, aFootprintName ) )
1284 aFootprintName = baseName + wxString::Format( wxS( "_%d" ), idx++ );
1285
1286 // Try to infer the footprint attributes from an existing footprint in the library
1287 try
1288 {
1289 fpnames = adapter->GetFootprintNames( aLibName, true );
1290
1291 if( !fpnames.empty() )
1292 {
1293 std::unique_ptr<FOOTPRINT> fp( adapter->LoadFootprint( aLibName, fpnames.back(), false ) );
1294
1295 if( fp )
1296 footprintAttrs = fp->GetAttributes();
1297 }
1298 }
1299 catch( ... )
1300 {
1301 // best efforts
1302 }
1303 }
1304
1305 // Create the new footprint and add it to the head of the linked list of footprints
1306 FOOTPRINT* footprint = new FOOTPRINT( GetBoard() );
1307
1308 // Update its name in lib
1309 footprint->SetFPID( LIB_ID( wxEmptyString, aFootprintName ) );
1310
1311 footprint->SetAttributes( footprintAttrs );
1312
1313 PCB_LAYER_ID txt_layer;
1314 VECTOR2I default_pos;
1316
1317 if( settings.m_DefaultFPTextItems.size() > 0 )
1318 {
1319 footprint->Reference().SetText( settings.m_DefaultFPTextItems[0].m_Text );
1320 footprint->Reference().SetVisible( settings.m_DefaultFPTextItems[0].m_Visible );
1321 }
1322
1323 txt_layer = settings.m_DefaultFPTextItems[0].m_Layer;
1324 footprint->Reference().SetLayer( txt_layer );
1325 default_pos.y -= settings.GetTextSize( txt_layer ).y / 2;
1326 footprint->Reference().SetPosition( default_pos );
1327 default_pos.y += settings.GetTextSize( txt_layer ).y;
1328
1329 if( settings.m_DefaultFPTextItems.size() > 1 )
1330 {
1331 footprint->Value().SetText( settings.m_DefaultFPTextItems[1].m_Text );
1332 footprint->Value().SetVisible( settings.m_DefaultFPTextItems[1].m_Visible );
1333 }
1334
1335 txt_layer = settings.m_DefaultFPTextItems[1].m_Layer;
1336 footprint->Value().SetLayer( txt_layer );
1337 default_pos.y += settings.GetTextSize( txt_layer ).y / 2;
1338 footprint->Value().SetPosition( default_pos );
1339 default_pos.y += settings.GetTextSize( txt_layer ).y;
1340
1341 for( size_t i = 2; i < settings.m_DefaultFPTextItems.size(); ++i )
1342 {
1343 PCB_TEXT* textItem = new PCB_TEXT( footprint );
1344 textItem->SetText( settings.m_DefaultFPTextItems[i].m_Text );
1345 txt_layer = (PCB_LAYER_ID) settings.m_DefaultFPTextItems[i].m_Layer;
1346 textItem->SetLayer( txt_layer );
1347 default_pos.y += settings.GetTextSize( txt_layer ).y / 2;
1348 textItem->SetPosition( default_pos );
1349 default_pos.y += settings.GetTextSize( txt_layer ).y;
1350 footprint->GraphicalItems().push_back( textItem );
1351 }
1352
1353 if( footprint->GetReference().IsEmpty() )
1354 footprint->SetReference( aFootprintName );
1355
1356 if( footprint->GetValue().IsEmpty() )
1357 footprint->SetValue( aFootprintName );
1358
1359 footprint->RunOnChildren(
1360 [&]( BOARD_ITEM* aChild )
1361 {
1362 if( aChild->Type() == PCB_FIELD_T || aChild->Type() == PCB_TEXT_T )
1363 {
1364 PCB_TEXT* textItem = static_cast<PCB_TEXT*>( aChild );
1365 PCB_LAYER_ID layer = textItem->GetLayer();
1366
1367 textItem->SetTextThickness( settings.GetTextThickness( layer ) );
1368 textItem->SetTextSize( settings.GetTextSize( layer ) );
1369 textItem->SetItalic( settings.GetTextItalic( layer ) );
1370 textItem->SetKeepUpright( settings.GetTextUpright( layer ) );
1371 }
1372 },
1374
1375 SetMsgPanel( footprint );
1376 return footprint;
1377}
1378
1379
1381 std::vector<wxArrayString>& aItemsToDisplay )
1382{
1383 aHeaders.Add( _( "Library" ) );
1384 aHeaders.Add( _( "Description" ) );
1385
1389 std::vector<wxString> nicknames = adapter->GetLibraryNames();
1390 std::vector<wxArrayString> unpinned;
1391
1392 for( const wxString& nickname : nicknames )
1393 {
1394 wxArrayString item;
1395 wxString description = adapter->GetLibraryDescription( nickname ).value_or( wxEmptyString );
1396
1397 if( alg::contains( project.m_PinnedFootprintLibs, nickname )
1398 || alg::contains( cfg->m_Session.pinned_fp_libs, nickname ) )
1399 {
1400 item.Add( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + nickname );
1401 item.Add( description );
1402 aItemsToDisplay.push_back( item );
1403 }
1404 else
1405 {
1406 item.Add( nickname );
1407 item.Add( description );
1408 unpinned.push_back( item );
1409 }
1410 }
1411
1412 std::sort( aItemsToDisplay.begin(), aItemsToDisplay.end(),
1413 []( const wxArrayString& a, const wxArrayString& b )
1414 {
1415 return StrNumCmp( a[0], b[0], true ) < 0;
1416 } );
1417
1418 std::sort( unpinned.begin(), unpinned.end(),
1419 []( const wxArrayString& a, const wxArrayString& b )
1420 {
1421 return StrNumCmp( a[0], b[0], true ) < 0;
1422 } );
1423
1424 std::ranges::copy( unpinned, std::back_inserter( aItemsToDisplay ) );
1425}
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:84
void SetUuid(const KIID &aUuid)
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:374
void ResetUuid()
Definition board_item.h:280
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1207
void ExchangeFootprint(FOOTPRINT *aExisting, FOOTPRINT *aNew, BOARD_COMMIT &aCommit, bool aMatchPadPositions, bool aDeleteExtraTexts=true, bool aResetTextLayers=true, bool aResetTextEffects=true, bool aResetTextPositions=true, bool aResetTextContent=true, bool aResetFabricationAttrs=true, bool aResetClearanceOverrides=true, bool aReset3DModels=true, bool aResetTransform=false, bool *aUpdated=nullptr, bool *aShifted=nullptr)
Replace aExisting with aNew, preserving connectivity and metadata.
void BuildListOfNets()
Definition board.h:1170
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:704
const FOOTPRINTS & Footprints() const
Definition board.h:463
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:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
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:342
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:381
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:231
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:285
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.
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:474
void SetLink(const KIID &aLink)
Definition footprint.h:1259
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:551
EDA_ITEM * Clone() const override
Invoke a function on all children.
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:939
const LIB_ID & GetFPID() const
Definition footprint.h:473
void SetReference(const wxString &aReference)
Definition footprint.h:907
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:930
PCB_FIELD & Reference()
Definition footprint.h:940
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:1258
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:925
const wxString & GetReference() const
Definition footprint.h:901
DRAWINGS & GraphicalItems()
Definition footprint.h:407
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:50
const wxString & GetNetname() const
Definition netinfo.h:110
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition netinfo.h:257
bool InPadEditMode()
Definition pad_tool.h:58
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:98
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:512
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:484
void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:102
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:546
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
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:324
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:848
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:51
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
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:86
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:727
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.
static std::string normalizedPath(std::string aPath)
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:84
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
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.