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