KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_editor_control.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <advanced_config.h>
27#include <string_utils.h>
28#include <pgm_base.h>
30#include <tool/tool_manager.h>
32#include <tools/pcb_actions.h>
34#include <eda_doc.h>
37#include <pcbnew_settings.h>
38#include <pcbnew_id.h>
39#include <confirm.h>
40#include <kidialog.h>
41#include <wx/filename.h>
43#include <launch_ext.h> // To default when file manager setting is empty
44#include <gestfich.h> // To open with a text editor
45#include <widgets/wx_infobar.h>
46#include <footprint.h>
47#include <pad.h>
48#include <pcb_group.h>
49#include <zone.h>
55#include <kiway.h>
56#include <project_pcb.h>
57#include <view/view_controls.h>
58
59#include <memory>
60
62
63
65 PCB_TOOL_BASE( "pcbnew.ModuleEditor" ),
66 m_frame( nullptr ),
67 m_checkerDialog( nullptr )
68{
69}
70
71
79
80
82{
83 LIBRARY_EDITOR_CONTROL* libraryTreeTool = m_toolMgr->GetTool<LIBRARY_EDITOR_CONTROL>();
84
85 // Build a context menu for the footprint tree
86 //
87 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
88
89 auto libSelectedCondition =
90 [this]( const SELECTION& aSel )
91 {
92 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
93 return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
94 };
95
96 // The libInferredCondition allows you to do things like New Symbol and Paste with a
97 // symbol selected (in other words, when we know the library context even if the library
98 // itself isn't selected.
99 auto libInferredCondition =
100 [this]( const SELECTION& aSel )
101 {
102 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
103 return !sel.GetLibNickname().empty();
104 };
105
106 auto fpSelectedCondition =
107 [this]( const SELECTION& aSel )
108 {
109 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
110 return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
111 };
112
113 auto fpExportCondition =
114 [this]( const SELECTION& aSel )
115 {
116 FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint();
117 return fp != nullptr;
118 };
119
120 auto canOpenExternally =
121 [this]( const SELECTION& aSel )
122 {
123 // The option is shown if the editor has no current edits,
124 // dumb/simple guard against opening a new file that does not exist on disk
125 bool ret = !m_frame->IsContentModified();
126 return ret;
127 };
128
129// clang-format off
130 ctxMenu.AddItem( PCB_ACTIONS::newFootprint, libSelectedCondition, 10 );
131 ctxMenu.AddItem( PCB_ACTIONS::createFootprint, libSelectedCondition, 10 );
132
133 ctxMenu.AddSeparator( 10 );
134 ctxMenu.AddItem( ACTIONS::save, SELECTION_CONDITIONS::ShowAlways, 10 );
135 ctxMenu.AddItem( ACTIONS::saveAs, libSelectedCondition || fpSelectedCondition, 10 );
136 ctxMenu.AddItem( ACTIONS::revert, libSelectedCondition || libInferredCondition, 10 );
137
138 ctxMenu.AddSeparator( 10 );
139 ctxMenu.AddItem( PCB_ACTIONS::cutFootprint, fpSelectedCondition, 10 );
140 ctxMenu.AddItem( PCB_ACTIONS::copyFootprint, fpSelectedCondition, 10 );
141 ctxMenu.AddItem( PCB_ACTIONS::pasteFootprint, libInferredCondition, 10 );
142 ctxMenu.AddItem( PCB_ACTIONS::duplicateFootprint, fpSelectedCondition, 10 );
143 ctxMenu.AddItem( PCB_ACTIONS::renameFootprint, fpSelectedCondition, 10 );
144 ctxMenu.AddItem( PCB_ACTIONS::deleteFootprint, fpSelectedCondition, 10 );
145 ctxMenu.AddItem( PCB_ACTIONS::footprintProperties, fpSelectedCondition, 10 );
146
147 ctxMenu.AddSeparator( 100 );
148 ctxMenu.AddItem( PCB_ACTIONS::importFootprint, libInferredCondition, 100 );
149 ctxMenu.AddItem( PCB_ACTIONS::exportFootprint, fpExportCondition, 100 );
150
151 if( ADVANCED_CFG::GetCfg().m_EnableLibWithText )
152 {
153 ctxMenu.AddSeparator( 200 );
154 ctxMenu.AddItem( ACTIONS::openWithTextEditor, canOpenExternally && fpSelectedCondition, 200 );
155 }
156
157 if( ADVANCED_CFG::GetCfg().m_EnableLibDir )
158 {
159 ctxMenu.AddSeparator( 200 );
160 ctxMenu.AddItem( ACTIONS::openDirectory, canOpenExternally && ( libSelectedCondition || fpSelectedCondition ), 200 );
161 }
162// clang-format on
163
164 libraryTreeTool->AddContextMenuItems( &ctxMenu );
165
166 // Ensure the left toolbar's Line modes group reflects the current setting at startup
167 if( m_toolMgr )
169
170 return true;
171}
172
173
175 const LIB_ID& aTargetLib )
176{
177 const wxString libraryName = aTargetLib.GetUniStringLibNickname();
178
179 if( aTargetLib.GetLibNickname().empty() )
180 {
181 // Do nothing - the footprint will need to be saved manually to assign
182 // to a library.
183 }
184 else
185 {
186 if( !PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->IsFootprintLibWritable( libraryName ) )
187 {
188 // If the library is not writeable, we'll give the user a
189 // footprint not in a library. But add a warning to let them know
190 // they didn't quite get what they wanted.
191 m_frame->ShowInfoBarWarning(
192 wxString::Format(
193 _( "The footprint could not be added to the selected library ('%s'). "
194 "This library is read-only." ),
195 libraryName ),
196 false );
197 // And the footprint will need to be saved manually
198 }
199 else
200 {
201 // Go ahead and save it to the library
202 LIB_ID fpid = aFootprint.GetFPID();
203 fpid.SetLibNickname( aTargetLib.GetLibNickname() );
204 aFootprint.SetFPID( fpid );
205 m_frame->SaveFootprint( &aFootprint );
206 m_frame->ClearModify();
207 }
208 }
209}
210
211
213{
214 const LIB_ID selected = m_frame->GetTargetFPID();
215 const wxString libraryName = selected.GetUniStringLibNickname();
216 FOOTPRINT* newFootprint = m_frame->CreateNewFootprint( wxEmptyString, libraryName );
217
218 if( !newFootprint )
219 return 0;
220
221 if( !m_frame->Clear_Pcb( true ) )
222 return 0;
223
225 m_frame->AddFootprintToBoard( newFootprint );
226
227 // Initialize data relative to nets and netclasses (for a new footprint the defaults are
228 // used). This is mandatory to handle and draw pads.
230 newFootprint->SetPosition( VECTOR2I( 0, 0 ) );
231 newFootprint->ClearFlags();
232
233 m_frame->Zoom_Automatique( false );
234 m_frame->GetScreen()->SetContentModified();
235
236 tryToSaveFootprintInLibrary( *newFootprint, selected );
237
238 m_frame->UpdateView();
239 m_frame->GetCanvas()->ForceRefresh();
240 m_frame->Update3DView( true, true );
241
242 m_frame->SyncLibraryTree( false );
243 return 0;
244}
245
246
248{
249 LIB_ID selected = m_frame->GetLibTree()->GetSelectedLibId();
250 wxString libraryName = selected.GetUniStringLibNickname();
251
252 if( m_frame->IsContentModified() )
253 {
254 if( !HandleUnsavedChanges( m_frame, _( "The current footprint has been modified. "
255 "Save changes?" ),
256 [&]() -> bool
257 {
258 return m_frame->SaveFootprint( footprint() );
259 } ) )
260 {
261 return 0;
262 }
263 }
264
265 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_FOOTPRINT_WIZARD, true, m_frame ) )
266 {
267 FOOTPRINT_WIZARD_FRAME* wizard = static_cast<FOOTPRINT_WIZARD_FRAME*>( frame );
268
269 if( wizard->ShowModal( nullptr, m_frame ) )
270 {
271 // Creates the new footprint from python script wizard
272 FOOTPRINT* newFootprint = wizard->GetBuiltFootprint();
273
274 if( newFootprint ) // i.e. if create footprint command is OK
275 {
276 m_frame->Clear_Pcb( false );
277
279 // Add the new object to board
280 m_frame->AddFootprintToBoard( newFootprint );
281
282 // Initialize data relative to nets and netclasses (for a new footprint the
283 // defaults are used). This is mandatory to handle and draw pads.
285 newFootprint->SetPosition( VECTOR2I( 0, 0 ) );
286 newFootprint->ClearFlags();
287
288 m_frame->Zoom_Automatique( false );
289 m_frame->GetScreen()->SetContentModified();
290 m_frame->OnModify();
291
292 tryToSaveFootprintInLibrary( *newFootprint, selected );
293
294 m_frame->UpdateView();
295 canvas()->Refresh();
296 m_frame->Update3DView( true, true );
297
298 m_frame->SyncLibraryTree( false );
299 }
300 }
301
302 wizard->Destroy();
303 }
304
305 return 0;
306}
307
308
310{
311 if( !footprint() ) // no loaded footprint
312 return 0;
313
314 if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
315 {
316 if( m_frame->SaveFootprint( footprint() ) )
317 {
318 view()->Update( footprint() );
319
320 canvas()->ForceRefresh();
321 m_frame->ClearModify();
322 m_frame->UpdateTitle();
323 }
324 }
325
326 m_frame->RefreshLibraryTree();
327 return 0;
328}
329
330
332{
333 if( m_frame->GetTargetFPID().GetLibItemName().empty() )
334 {
336
337 // Save Library As
338 const wxString& src_libNickname = m_frame->GetTargetFPID().GetLibNickname();
339 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, src_libNickname, true );
340 wxCHECK( optUri, 0 );
341
342 if( m_frame->SaveLibraryAs( *optUri ) )
343 m_frame->SyncLibraryTree( true );
344 }
345 else if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
346 {
347 // Save Footprint As
348 if( footprint() && m_frame->SaveFootprintAs( footprint() ) )
349 {
350 view()->Update( footprint() );
351 m_frame->ClearModify();
352
353 // Get rid of the save-will-update-board-only (or any other dismissable warning)
354 WX_INFOBAR* infobar = m_frame->GetInfoBar();
355
356 if( infobar->IsShownOnScreen() && infobar->HasCloseButton() )
357 infobar->Dismiss();
358
359 canvas()->ForceRefresh();
360 m_frame->SyncLibraryTree( true );
361 }
362 }
363 else
364 {
365 // Save Selected Footprint As
366 FOOTPRINT* footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
367
368 if( footprint && m_frame->SaveFootprintAs( footprint ) )
369 {
370 m_frame->SyncLibraryTree( true );
371 m_frame->FocusOnLibID( footprint->GetFPID() );
372 }
373 }
374
375 m_frame->RefreshLibraryTree();
376 return 0;
377}
378
379
381{
382 getEditFrame<FOOTPRINT_EDIT_FRAME>()->RevertFootprint();
383 return 0;
384}
385
386
388{
389 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
390
391 if( fpID == m_frame->GetLoadedFPID() )
392 {
393 m_copiedFootprint = std::make_unique<FOOTPRINT>( *m_frame->GetBoard()->GetFirstFootprint() );
394 m_copiedFootprint->SetParent( nullptr );
395 }
396 else
397 {
398 m_copiedFootprint.reset( m_frame->LoadFootprint( fpID ) );
399 }
400
401 if( aEvent.IsAction( &PCB_ACTIONS::cutFootprint ) )
402 DeleteFootprint( aEvent );
403
404 return 0;
405}
406
407
409{
410 if( m_copiedFootprint && !m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname().empty() )
411 {
412 wxString newLib = m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname();
413 wxString newName = m_copiedFootprint->GetFPID().GetLibItemName();
414
415 while( PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->FootprintExists( newLib, newName ) )
416 newName += _( "_copy" );
417
418 m_copiedFootprint->SetFPID( LIB_ID( newLib, newName ) );
419 m_frame->SaveFootprintInLibrary( m_copiedFootprint.get(), newLib );
420
421 m_frame->SyncLibraryTree( true );
422 m_frame->LoadFootprintFromLibrary( m_copiedFootprint->GetFPID() );
423 m_frame->FocusOnLibID( m_copiedFootprint->GetFPID() );
424 m_frame->RefreshLibraryTree();
425 }
426
427 return 0;
428}
429
430
432{
433 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
435
436 if( fpID == m_frame->GetLoadedFPID() )
437 footprint = new FOOTPRINT( *m_frame->GetBoard()->GetFirstFootprint() );
438 else
439 footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
440
441 if( footprint && m_frame->DuplicateFootprint( footprint ) )
442 {
443 m_frame->SyncLibraryTree( true );
444 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
445 m_frame->FocusOnLibID( footprint->GetFPID() );
446 m_frame->RefreshLibraryTree();
447 }
448
449 return 0;
450}
451
452
454{
457
458 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
459 wxString libraryName = fpID.GetLibNickname();
460 wxString oldName = fpID.GetLibItemName();
461 wxString newName;
462 wxString msg;
463
464 if( !libTool->RenameLibrary( _( "Change Footprint Name" ), oldName,
465 [&]( const wxString& aNewName )
466 {
467 newName = aNewName;
468
469 if( newName.IsEmpty() )
470 {
471 wxMessageBox( _( "Footprint must have a name." ) );
472 return false;
473 }
474
475 // If no change, accept it without prompting
476 if( oldName != newName && adapter->FootprintExists( libraryName, newName ) )
477 {
478 msg = wxString::Format( _( "Footprint '%s' already exists in library '%s'." ),
479 newName, libraryName );
480
481 KIDIALOG errorDlg( m_frame, msg, _( "Confirmation" ),
482 wxOK | wxCANCEL | wxICON_WARNING );
483 errorDlg.SetOKLabel( _( "Overwrite" ) );
484
485 return errorDlg.ShowModal() == wxID_OK;
486 }
487
488 return true;
489 } ) )
490 {
491 return 0; // canceled by user
492 }
493
494 if( newName == oldName )
495 return 0;
496
497 FOOTPRINT* footprint = nullptr;
498
499 if( fpID == m_frame->GetLoadedFPID() )
500 {
501 footprint = m_frame->GetBoard()->GetFirstFootprint();
502
503 if( footprint )
504 {
505 footprint->SetFPID( LIB_ID( libraryName, newName ) );
506
507 if( footprint->GetValue() == oldName )
508 footprint->SetValue( newName );
509
510 m_frame->OnModify();
511 m_frame->UpdateView();
512 }
513 }
514 else
515 {
516 footprint = m_frame->LoadFootprint( fpID );
517
518 if( footprint )
519 {
520 try
521 {
522 footprint->SetFPID( LIB_ID( libraryName, newName ) );
523
524 if( footprint->GetValue() == oldName )
525 footprint->SetValue( newName );
526
527 m_frame->SaveFootprintInLibrary( footprint, libraryName );
528
529 adapter->DeleteFootprint( libraryName, oldName );
530 }
531 catch( const IO_ERROR& ioe )
532 {
533 DisplayErrorMessage( m_frame, _( "Error renaming footprint" ), ioe.What() );
534 }
535 catch( ... )
536 {
537 // Best efforts...
538 }
539 }
540 }
541
542 wxDataViewItem treeItem = m_frame->GetLibTreeAdapter()->FindItem( fpID );
543
544 if( footprint )
545 {
546 m_frame->UpdateLibraryTree( treeItem, footprint );
547 m_frame->FocusOnLibID( LIB_ID( libraryName, newName ) );
548 }
549
550 return 0;
551}
552
553
555{
557
558 if( frame->DeleteFootprintFromLibrary( frame->GetTargetFPID(), true ) )
559 {
560 if( frame->GetTargetFPID() == frame->GetLoadedFPID() )
561 frame->Clear_Pcb( false );
562
563 frame->SyncLibraryTree( true );
564 }
565
566 return 0;
567}
568
569
571{
572 bool is_last_fp_from_brd = m_frame->IsCurrentFPFromBoard();
573
574 if( !m_frame->Clear_Pcb( true ) )
575 return -1; // this command is aborted
576
578 m_frame->ImportFootprint();
579
580 if( m_frame->GetBoard()->GetFirstFootprint() )
581 m_frame->GetBoard()->GetFirstFootprint()->ClearFlags();
582
583 frame()->ClearUndoRedoList();
584
585 // Update the save items if needed.
586 if( is_last_fp_from_brd )
587 {
588 m_frame->ReCreateMenuBar();
589 m_frame->ReCreateHToolbar();
590 }
591
592 m_toolMgr->RunAction( ACTIONS::zoomFitScreen );
593 m_frame->OnModify();
594 return 0;
595}
596
597
599{
600 if( FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint() )
601 m_frame->ExportFootprint( fp );
602
603 return 0;
604}
605
606
608{
609 // No check for multi selection since the context menu option must be hidden in that case
610 LIB_ID libId = m_frame->GetTargetFPID();
611
612 wxString libName = libId.GetLibNickname();
613 wxString libItemName = libId.GetLibItemName();
614 wxString path = wxEmptyString;
615
617 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libName, true );
618
619 if( !optUri )
620 return 0;
621
622 path = *optUri;
623
624 wxString fileExt = wxEmptyString;
625
626 // If selection is footprint
627 if( !libItemName.IsEmpty() )
629
630 wxFileName fileName( path, libItemName, fileExt );
631 wxString explorerCommand;
632
633 if( COMMON_SETTINGS* cfg = Pgm().GetCommonSettings() )
634 explorerCommand = cfg->m_System.file_explorer;
635
636 if( explorerCommand.IsEmpty() )
637 {
638 path = fileName.GetFullPath().BeforeLast( wxFileName::GetPathSeparator() );
639
640 if( !path.IsEmpty() && wxDirExists( path ) )
642
643 return 0;
644 }
645
646 if( !explorerCommand.EndsWith( "%F" ) )
647 {
648 wxMessageBox( _( "Missing/malformed file explorer argument '%F' in common settings." ) );
649 return 0;
650 }
651
652 wxString escapedFilePath = fileName.GetFullPath();
653 escapedFilePath.Replace( wxS( "\"" ), wxS( "_" ) );
654
655 wxString fileArg = wxEmptyString;
656 fileArg << '"' << escapedFilePath << '"';
657
658 explorerCommand.Replace( wxT( "%F" ), fileArg );
659
660 if( !explorerCommand.IsEmpty() )
661 wxExecute( explorerCommand );
662
663 return 0;
664}
665
666
668{
669 wxString fullEditorName = Pgm().GetTextEditor();
670
671 if( fullEditorName.IsEmpty() )
672 {
673 wxMessageBox( _( "No text editor selected in KiCad. Please choose one." ) );
674 return 0;
675 }
676
677 // No check for multi selection since the context menu option must be hidden in that case
678 LIB_ID libId = m_frame->GetLibTree()->GetSelectedLibId();
679
681
682 wxString libName = libId.GetLibNickname();
683 wxString libItemName = wxEmptyString;
684
685 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libName, true );
686
687 if( !optUri )
688 return 0;
689
690 libItemName = *optUri;
691 libItemName << wxFileName::GetPathSeparator();
692 libItemName << libId.GetLibItemName();
693 libItemName << '.' + FILEEXT::KiCadFootprintFileExtension;
694
695 if( !wxFileName::FileExists( libItemName ) )
696 return 0;
697
698 ExecuteFile( fullEditorName, libItemName.wc_str(), nullptr, false );
699
700 return 0;
701}
702
703
705{
706 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
707 {
708 std::optional<wxString> url = GetFootprintDocumentationURL( *footprint );
709
710 if( !url.has_value() )
711 {
712 frame()->ShowInfoBarMsg( _( "No datasheet found in the footprint." ) );
713 }
714 else
715 {
716 // Only absolute URLs are supported
717 SEARCH_STACK* searchStack = nullptr;
718 GetAssociatedDocument( m_frame, *url, &m_frame->Prj(), searchStack,
719 { m_frame->GetBoard(), footprint } );
720 }
721 }
722 return 0;
723}
724
725
727{
728 m_frame->LoadFootprintFromLibrary( m_frame->GetLibTree()->GetSelectedLibId() );
729 return 0;
730}
731
732
734{
735 FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint();
736
737 if( !footprint || !m_frame->IsCurrentFPFromBoard() )
738 {
739 wxBell();
740 return 0;
741 }
742
743 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
744
745 if( !m_frame->IsLibraryTreeShown() )
746 m_frame->ToggleLibraryTree();
747
748 return 0;
749}
750
751
753{
754 m_frame->ToggleLayersManager();
755 return 0;
756}
757
758
760{
761 m_frame->ToggleProperties();
762 return 0;
763}
764
765
767{
768 // Check if called from tree context menu
770 {
771 LIB_ID treeLibId = m_frame->GetLibTree()->GetSelectedLibId();
772
773 // Check if a different footprint is selected in the tree
774 if( treeLibId.IsValid()
775 && ( !m_frame->GetBoard()->GetFirstFootprint()
776 || m_frame->GetBoard()->GetFirstFootprint()->GetFPID() != treeLibId ) )
777 {
778 // Edit properties directly from library without loading to canvas
780 return 0;
781 }
782 }
783
784 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
785 {
786 getEditFrame<FOOTPRINT_EDIT_FRAME>()->OnEditItemRequest( footprint );
787 m_frame->GetCanvas()->Refresh();
788 }
789
790 return 0;
791}
792
793
795{
796 // Load the footprint from the library (without adding it to the canvas)
797 FOOTPRINT* libraryFootprint = m_frame->LoadFootprint( aLibId );
798
799 if( !libraryFootprint )
800 return;
801
802 // Create a temporary board to hold the footprint (required by the dialog)
803 std::unique_ptr<BOARD> tempBoard( new BOARD() );
804
805 // Create a copy to work with and add it to the temporary board
806 FOOTPRINT* tempFootprint = static_cast<FOOTPRINT*>( libraryFootprint->Clone() );
807 delete libraryFootprint;
808
809 tempBoard->Add( tempFootprint );
810 tempFootprint->SetParent( tempBoard.get() );
811
812 LIB_ID oldFPID = tempFootprint->GetFPID();
813
814 // Open the properties dialog
815 DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR dialog( m_frame, tempFootprint );
816
817 if( dialog.ShowQuasiModal() != wxID_OK )
818 return;
819
820 // Remove from temporary board before saving (to avoid double-delete)
821 tempBoard->Remove( tempFootprint );
822
823 // Save the modified footprint back to the library
825 wxString libName = aLibId.GetLibNickname();
826
827 try
828 {
829 adapter->SaveFootprint( libName, tempFootprint, true );
830
831 // Update the tree view
832 wxDataViewItem treeItem = m_frame->GetLibTreeAdapter()->FindItem( oldFPID );
833 m_frame->UpdateLibraryTree( treeItem, tempFootprint );
834 m_frame->SyncLibraryTree( true );
835
836 // Clean up
837 delete tempFootprint;
838 }
839 catch( const IO_ERROR& ioe )
840 {
841 delete tempFootprint;
842 DisplayError( m_frame, ioe.What() );
843 }
844}
845
846
848{
849 getEditFrame<FOOTPRINT_EDIT_FRAME>()->ShowPadPropertiesDialog( nullptr );
850 return 0;
851}
852
853
855{
857 DIALOG_CLEANUP_GRAPHICS dlg( editFrame, true );
858
859 dlg.ShowModal();
860 return 0;
861}
862
863
865{
866 if( !m_checkerDialog )
867 {
869 m_checkerDialog->Show( true );
870 }
871 else // The dialog is just not visible (because the user has double clicked on an error item)
872 {
873 m_checkerDialog->Show( true );
874 }
875
876 return 0;
877}
878
879
881{
882 if( !m_checkerDialog )
884
885 if( !m_checkerDialog->IsShownOnScreen() )
886 m_checkerDialog->Show( true );
887
888 m_checkerDialog->SelectMarker( aMarker );
889}
890
891
893{
894 if( m_checkerDialog )
895 {
896 m_checkerDialog->Destroy();
897 m_checkerDialog = nullptr;
898 }
899}
900
901
903{
904 FOOTPRINT* footprint = board()->Footprints().front();
905 int errors = 0;
906 wxString details;
907
908 // Repair duplicate IDs and missing nets.
909 std::set<KIID> ids;
910 int duplicates = 0;
911
912 auto processItem =
913 [&]( EDA_ITEM* aItem )
914 {
915 if( ids.count( aItem->m_Uuid ) )
916 {
917 duplicates++;
918 const_cast<KIID&>( aItem->m_Uuid ) = KIID();
919 }
920
921 ids.insert( aItem->m_Uuid );
922 };
923
924 // Footprint IDs are the most important, so give them the first crack at "claiming" a
925 // particular KIID.
926
927 processItem( footprint );
928
929 // After that the principal use is for DRC marker pointers, which are most likely to pads.
930
931 for( PAD* pad : footprint->Pads() )
932 processItem( pad );
933
934 // From here out I don't think order matters much.
935
936 processItem( &footprint->Reference() );
937 processItem( &footprint->Value() );
938
939 for( BOARD_ITEM* item : footprint->GraphicalItems() )
940 processItem( item );
941
942 for( ZONE* zone : footprint->Zones() )
943 processItem( zone );
944
945 for( PCB_GROUP* group : footprint->Groups() )
946 processItem( group );
947
948 if( duplicates )
949 {
950 errors += duplicates;
951 details += wxString::Format( _( "%d duplicate IDs replaced.\n" ), duplicates );
952 }
953
954 if( errors )
955 {
956 m_frame->OnModify();
957
958 wxString msg = wxString::Format( _( "%d potential problems repaired." ), errors );
959 DisplayInfoMessage( m_frame, msg, details );
960 }
961 else
962 {
963 DisplayInfoMessage( m_frame, _( "No footprint problems found." ) );
964 }
965
966 return 0;
967}
968
969
971{
972 // clang-format off
981
987
990
994
997
1000
1005 // clang-format on
1006
1007 // Line modes for the footprint editor: explicit modes, next-mode, and toolbar sync
1013}
1014
1016{
1017 LEADER_MODE mode = aEvent.Parameter<LEADER_MODE>();
1018 GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode = mode;
1019 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1021 return 0;
1022}
1023
1025{
1027
1028 if( !f )
1029 return 0;
1030
1031 LEADER_MODE mode = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode;
1032
1033 switch( mode )
1034 {
1037 break;
1038 case LEADER_MODE::DEG90:
1040 break;
1041 case LEADER_MODE::DEG45:
1042 default:
1044 break;
1045 }
1046
1047 return 0;
1048}
static TOOL_ACTION openWithTextEditor
Definition actions.h:68
static TOOL_ACTION revert
Definition actions.h:62
static TOOL_ACTION saveAs
Definition actions.h:59
static TOOL_ACTION openDirectory
Definition actions.h:69
static TOOL_ACTION showDatasheet
Definition actions.h:267
static TOOL_ACTION save
Definition actions.h:58
static TOOL_ACTION zoomFitScreen
Definition actions.h:142
static TOOL_ACTION showProperties
Definition actions.h:266
static TOOL_ACTION refreshPreview
Definition actions.h:159
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
void BuildListOfNets()
Definition board.h:918
const FOOTPRINTS & Footprints() const
Definition board.h:363
int ShowModal() override
void SelectLeftToolbarAction(const TOOL_ACTION &aAction)
Select the given action in the left toolbar group which contains it, if any.
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
void ForceRefresh()
Force a redraw.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:144
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
int Revert(const TOOL_EVENT &aEvent)
int OpenWithTextEditor(const TOOL_EVENT &aEvent)
int PasteFootprint(const TOOL_EVENT &aEvent)
DIALOG_FOOTPRINT_CHECKER * m_checkerDialog
int CutCopyFootprint(const TOOL_EVENT &aEvent)
int EditFootprint(const TOOL_EVENT &aEvent)
int ToggleProperties(const TOOL_EVENT &aEvent)
int Save(const TOOL_EVENT &aEvent)
int OpenDirectory(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int CreateFootprint(const TOOL_EVENT &aEvent)
int NewFootprint(const TOOL_EVENT &aEvent)
int DefaultPadProperties(const TOOL_EVENT &aEvent)
Edit the properties used for new pad creation.
void CrossProbe(const PCB_MARKER *aMarker)
int ChangeLineMode(const TOOL_EVENT &aEvent)
int ImportFootprint(const TOOL_EVENT &aEvent)
int CleanupGraphics(const TOOL_EVENT &aEvent)
int ShowDatasheet(const TOOL_EVENT &aEvent)
void tryToSaveFootprintInLibrary(FOOTPRINT &aFootprint, const LIB_ID &aLibId)
Try to save the footprint in the library, if it is valid and writable.
int Properties(const TOOL_EVENT &aEvent)
int ToggleLayersManager(const TOOL_EVENT &aEvent)
int RepairFootprint(const TOOL_EVENT &aEvent)
int RenameFootprint(const TOOL_EVENT &aEvent)
int DuplicateFootprint(const TOOL_EVENT &aEvent)
std::unique_ptr< FOOTPRINT > m_copiedFootprint
bool Init() override
Init() is called once upon a registration of the tool.
int OnAngleSnapModeChanged(const TOOL_EVENT &aEvent)
int ExportFootprint(const TOOL_EVENT &aEvent)
int EditLibraryFootprint(const TOOL_EVENT &aEvent)
void editFootprintPropertiesFromLibrary(const LIB_ID &aLibId)
int DeleteFootprint(const TOOL_EVENT &aEvent)
int SaveAs(const TOOL_EVENT &aEvent)
void setTransitions() override
< Set up handlers for various events.
int CheckFootprint(const TOOL_EVENT &aEvent)
An interface to the global shared library manager that is schematic-specific and linked to one projec...
SAVE_T SaveFootprint(const wxString &aNickname, const FOOTPRINT *aFootprint, bool aOverwrite=true)
Write aFootprint to an existing library given by aNickname.
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:270
EDA_ITEM * Clone() const override
Invoke a function on all children.
const LIB_ID & GetFPID() const
Definition footprint.h:269
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:42
int ShowModal() override
Definition kidialog.cpp:93
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:91
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
Definition kiid.h:49
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
virtual bool ShowModal(wxString *aResult=nullptr, wxWindow *aResultantFocusWindow=nullptr)
Show this wxFrame as if it were a modal dialog, with all other instantiated wxFrames disabled until t...
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
Module editor specific tools.
bool RenameLibrary(const wxString &aTitle, const wxString &aName, std::function< bool(const wxString &aNewName)> aValidator)
void AddContextMenuItems(CONDITIONAL_MENU *aMenu)
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:100
const wxString GetUniStringLibNickname() const
Definition lib_id.h:88
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
Definition pad.h:55
static TOOL_ACTION lineModeFree
Unconstrained angle mode (icon lines_any)
static TOOL_ACTION deleteFootprint
static TOOL_ACTION renameFootprint
static TOOL_ACTION showLayersManager
static TOOL_ACTION createFootprint
static TOOL_ACTION editFootprint
static TOOL_ACTION exportFootprint
static TOOL_ACTION editTextAndGraphics
static TOOL_ACTION lineMode45
45-degree-or-orthogonal mode (icon hv45mode)
static TOOL_ACTION angleSnapModeChanged
Notification event when angle mode changes.
static TOOL_ACTION newFootprint
static TOOL_ACTION defaultPadProperties
static TOOL_ACTION importFootprint
static TOOL_ACTION pasteFootprint
static TOOL_ACTION footprintProperties
static TOOL_ACTION lineMode90
90-degree-only mode (icon lines90)
static TOOL_ACTION checkFootprint
static TOOL_ACTION editLibFpInFpEditor
static TOOL_ACTION duplicateFootprint
static TOOL_ACTION cutFootprint
static TOOL_ACTION repairFootprint
static TOOL_ACTION copyFootprint
static TOOL_ACTION cleanupGraphics
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
T * frame() const
KIGFX::PCB_VIEW * view() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
FOOTPRINT * footprint() const
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
Definition pgm_base.cpp:206
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:131
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Look for files in a number of paths.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:171
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
bool empty() const
Definition utf8.h:109
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
bool HasCloseButton() const
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Handle a list of polygons defining a copper zone.
Definition zone.h:74
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:230
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:131
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
#define _(s)
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject, SEARCH_STACK *aPaths, std::vector< EMBEDDED_FILES * > aFilesStack)
Open a document (file) with the suitable browser.
Definition eda_doc.cpp:63
This file is part of the common library.
@ FRAME_FOOTPRINT_WIZARD
Definition frame_type.h:46
std::optional< wxString > GetFootprintDocumentationURL(const FOOTPRINT &aFootprint)
Get a URL to the documentation for a LIB_ID in a #FP_LIB_TABLE.
LEADER_MODE
The kind of the leader line.
@ DEG45
45 Degree only
@ DIRECT
Unconstrained point-to-point.
@ DEG90
90 Degree only
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback, bool aFileForKicad)
Call the executable file aEditorName with the parameter aFileName.
Definition gestfich.cpp:145
static const std::string KiCadFootprintFileExtension
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
Class to handle a set of BOARD_ITEMs.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
T * GetAppSettings(const char *aFilename)
std::string path
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
Definition of file extensions used in Kicad.