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
251 if( m_frame->IsContentModified() )
252 {
253 if( !HandleUnsavedChanges( m_frame, _( "The current footprint has been modified. "
254 "Save changes?" ),
255 [&]() -> bool
256 {
257 return m_frame->SaveFootprint( footprint() );
258 } ) )
259 {
260 return 0;
261 }
262 }
263
264 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_FOOTPRINT_WIZARD, true, m_frame ) )
265 {
266 FOOTPRINT_WIZARD_FRAME* wizard = static_cast<FOOTPRINT_WIZARD_FRAME*>( frame );
267
268 if( wizard->ShowModal( nullptr, m_frame ) )
269 {
270 // Creates the new footprint from python script wizard
271 FOOTPRINT* newFootprint = wizard->GetBuiltFootprint();
272
273 if( newFootprint ) // i.e. if create footprint command is OK
274 {
275 m_frame->Clear_Pcb( false );
276
278 // Add the new object to board
279 m_frame->AddFootprintToBoard( newFootprint );
280
281 // Initialize data relative to nets and netclasses (for a new footprint the
282 // defaults are used). This is mandatory to handle and draw pads.
284 newFootprint->SetPosition( VECTOR2I( 0, 0 ) );
285 newFootprint->ClearFlags();
286
287 m_frame->Zoom_Automatique( false );
288 m_frame->GetScreen()->SetContentModified();
289 m_frame->OnModify();
290
291 tryToSaveFootprintInLibrary( *newFootprint, selected );
292
293 m_frame->UpdateView();
294 canvas()->Refresh();
295 m_frame->Update3DView( true, true );
296
297 m_frame->SyncLibraryTree( false );
298 }
299 }
300
301 wizard->Destroy();
302 }
303
304 return 0;
305}
306
307
309{
310 if( !footprint() ) // no loaded footprint
311 return 0;
312
313 if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
314 {
315 if( m_frame->SaveFootprint( footprint() ) )
316 {
317 view()->Update( footprint() );
318
319 canvas()->ForceRefresh();
320 m_frame->ClearModify();
321 m_frame->UpdateTitle();
322 }
323 }
324
325 m_frame->RefreshLibraryTree();
326 return 0;
327}
328
329
331{
332 if( m_frame->GetTargetFPID().GetLibItemName().empty() )
333 {
335
336 // Save Library As
337 const wxString& src_libNickname = m_frame->GetTargetFPID().GetLibNickname();
338 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, src_libNickname, true );
339 wxCHECK( optUri, 0 );
340
341 if( m_frame->SaveLibraryAs( *optUri ) )
342 m_frame->SyncLibraryTree( true );
343 }
344 else if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
345 {
346 // Save Footprint As
347 if( footprint() && m_frame->SaveFootprintAs( footprint() ) )
348 {
349 view()->Update( footprint() );
350 m_frame->ClearModify();
351
352 // Get rid of the save-will-update-board-only (or any other dismissable warning)
353 WX_INFOBAR* infobar = m_frame->GetInfoBar();
354
355 if( infobar->IsShownOnScreen() && infobar->HasCloseButton() )
356 infobar->Dismiss();
357
358 canvas()->ForceRefresh();
359 m_frame->SyncLibraryTree( true );
360 }
361 }
362 else
363 {
364 // Save Selected Footprint As
365 FOOTPRINT* footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
366
367 if( footprint && m_frame->SaveFootprintAs( footprint ) )
368 {
369 m_frame->SyncLibraryTree( true );
370 m_frame->FocusOnLibID( footprint->GetFPID() );
371 }
372 }
373
374 m_frame->RefreshLibraryTree();
375 return 0;
376}
377
378
380{
381 getEditFrame<FOOTPRINT_EDIT_FRAME>()->RevertFootprint();
382 return 0;
383}
384
385
387{
388 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
389
390 if( fpID == m_frame->GetLoadedFPID() )
391 {
392 m_copiedFootprint = std::make_unique<FOOTPRINT>( *m_frame->GetBoard()->GetFirstFootprint() );
393 m_copiedFootprint->SetParent( nullptr );
394 }
395 else
396 {
397 m_copiedFootprint.reset( m_frame->LoadFootprint( fpID ) );
398 }
399
400 if( aEvent.IsAction( &PCB_ACTIONS::cutFootprint ) )
401 DeleteFootprint( aEvent );
402
403 return 0;
404}
405
406
408{
409 if( m_copiedFootprint && !m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname().empty() )
410 {
411 wxString newLib = m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname();
412 wxString newName = m_copiedFootprint->GetFPID().GetLibItemName();
413
414 while( PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->FootprintExists( newLib, newName ) )
415 newName += _( "_copy" );
416
417 m_copiedFootprint->SetFPID( LIB_ID( newLib, newName ) );
418 m_frame->SaveFootprintInLibrary( m_copiedFootprint.get(), newLib );
419
420 m_frame->SyncLibraryTree( true );
421 m_frame->LoadFootprintFromLibrary( m_copiedFootprint->GetFPID() );
422 m_frame->FocusOnLibID( m_copiedFootprint->GetFPID() );
423 m_frame->RefreshLibraryTree();
424 }
425
426 return 0;
427}
428
429
431{
432 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
434
435 if( fpID == m_frame->GetLoadedFPID() )
436 footprint = new FOOTPRINT( *m_frame->GetBoard()->GetFirstFootprint() );
437 else
438 footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
439
440 if( footprint && m_frame->DuplicateFootprint( footprint ) )
441 {
442 m_frame->SyncLibraryTree( true );
443 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
444 m_frame->FocusOnLibID( footprint->GetFPID() );
445 m_frame->RefreshLibraryTree();
446 }
447
448 return 0;
449}
450
451
453{
456
457 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
458 wxString libraryName = fpID.GetLibNickname();
459 wxString oldName = fpID.GetLibItemName();
460 wxString newName;
461 wxString msg;
462
463 if( !libTool->RenameLibrary( _( "Change Footprint Name" ), oldName,
464 [&]( const wxString& aNewName )
465 {
466 newName = aNewName;
467
468 if( newName.IsEmpty() )
469 {
470 wxMessageBox( _( "Footprint must have a name." ) );
471 return false;
472 }
473
474 // If no change, accept it without prompting
475 if( oldName != newName && adapter->FootprintExists( libraryName, newName ) )
476 {
477 msg = wxString::Format( _( "Footprint '%s' already exists in library '%s'." ),
478 newName, libraryName );
479
480 KIDIALOG errorDlg( m_frame, msg, _( "Confirmation" ),
481 wxOK | wxCANCEL | wxICON_WARNING );
482 errorDlg.SetOKLabel( _( "Overwrite" ) );
483
484 return errorDlg.ShowModal() == wxID_OK;
485 }
486
487 return true;
488 } ) )
489 {
490 return 0; // canceled by user
491 }
492
493 if( newName == oldName )
494 return 0;
495
496 FOOTPRINT* footprint = nullptr;
497
498 if( fpID == m_frame->GetLoadedFPID() )
499 {
500 footprint = m_frame->GetBoard()->GetFirstFootprint();
501
502 if( footprint )
503 {
504 footprint->SetFPID( LIB_ID( libraryName, newName ) );
505
506 if( footprint->GetValue() == oldName )
507 footprint->SetValue( newName );
508
509 m_frame->OnModify();
510 m_frame->UpdateView();
511 }
512 }
513 else
514 {
515 footprint = m_frame->LoadFootprint( fpID );
516
517 if( footprint )
518 {
519 try
520 {
521 footprint->SetFPID( LIB_ID( libraryName, newName ) );
522
523 if( footprint->GetValue() == oldName )
524 footprint->SetValue( newName );
525
526 m_frame->SaveFootprintInLibrary( footprint, libraryName );
527
528 adapter->DeleteFootprint( libraryName, oldName );
529 }
530 catch( const IO_ERROR& ioe )
531 {
532 DisplayErrorMessage( m_frame, _( "Error renaming footprint" ), ioe.What() );
533 }
534 catch( ... )
535 {
536 // Best efforts...
537 }
538 }
539 }
540
541 wxDataViewItem treeItem = m_frame->GetLibTreeAdapter()->FindItem( fpID );
542
543 if( footprint )
544 {
545 m_frame->UpdateLibraryTree( treeItem, footprint );
546 m_frame->FocusOnLibID( LIB_ID( libraryName, newName ) );
547 }
548
549 return 0;
550}
551
552
554{
556
557 if( frame->DeleteFootprintFromLibrary( frame->GetTargetFPID(), true ) )
558 {
559 if( frame->GetTargetFPID() == frame->GetLoadedFPID() )
560 frame->Clear_Pcb( false );
561
562 frame->SyncLibraryTree( true );
563 }
564
565 return 0;
566}
567
568
570{
571 bool is_last_fp_from_brd = m_frame->IsCurrentFPFromBoard();
572
573 if( !m_frame->Clear_Pcb( true ) )
574 return -1; // this command is aborted
575
577 m_frame->ImportFootprint();
578
579 if( m_frame->GetBoard()->GetFirstFootprint() )
580 m_frame->GetBoard()->GetFirstFootprint()->ClearFlags();
581
582 frame()->ClearUndoRedoList();
583
584 // Update the save items if needed.
585 if( is_last_fp_from_brd )
586 {
587 m_frame->ReCreateMenuBar();
588 m_frame->ReCreateHToolbar();
589 }
590
591 m_toolMgr->RunAction( ACTIONS::zoomFitScreen );
592 m_frame->OnModify();
593 return 0;
594}
595
596
598{
599 if( FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint() )
600 m_frame->ExportFootprint( fp );
601
602 return 0;
603}
604
605
607{
608 // No check for multi selection since the context menu option must be hidden in that case
609 LIB_ID libId = m_frame->GetTargetFPID();
610
611 wxString libName = libId.GetLibNickname();
612 wxString libItemName = libId.GetLibItemName();
613 wxString path = wxEmptyString;
614
616 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libName, true );
617
618 if( !optUri )
619 return 0;
620
621 path = *optUri;
622
623 wxString fileExt = wxEmptyString;
624
625 // If selection is footprint
626 if( !libItemName.IsEmpty() )
628
629 wxFileName fileName( path, libItemName, fileExt );
630 wxString explorerCommand;
631
632 if( COMMON_SETTINGS* cfg = Pgm().GetCommonSettings() )
633 explorerCommand = cfg->m_System.file_explorer;
634
635 if( explorerCommand.IsEmpty() )
636 {
637 path = fileName.GetFullPath().BeforeLast( wxFileName::GetPathSeparator() );
638
639 if( !path.IsEmpty() && wxDirExists( path ) )
641
642 return 0;
643 }
644
645 if( !explorerCommand.EndsWith( "%F" ) )
646 {
647 wxMessageBox( _( "Missing/malformed file explorer argument '%F' in common settings." ) );
648 return 0;
649 }
650
651 wxString escapedFilePath = fileName.GetFullPath();
652 escapedFilePath.Replace( wxS( "\"" ), wxS( "_" ) );
653
654 wxString fileArg = wxEmptyString;
655 fileArg << '"' << escapedFilePath << '"';
656
657 explorerCommand.Replace( wxT( "%F" ), fileArg );
658
659 if( !explorerCommand.IsEmpty() )
660 wxExecute( explorerCommand );
661
662 return 0;
663}
664
665
667{
668 wxString fullEditorName = Pgm().GetTextEditor();
669
670 if( fullEditorName.IsEmpty() )
671 {
672 wxMessageBox( _( "No text editor selected in KiCad. Please choose one." ) );
673 return 0;
674 }
675
676 // No check for multi selection since the context menu option must be hidden in that case
677 LIB_ID libId = m_frame->GetLibTree()->GetSelectedLibId();
678
680
681 wxString libName = libId.GetLibNickname();
682 wxString libItemName = wxEmptyString;
683
684 std::optional<wxString> optUri = manager.GetFullURI( LIBRARY_TABLE_TYPE::FOOTPRINT, libName, true );
685
686 if( !optUri )
687 return 0;
688
689 libItemName = *optUri;
690 libItemName << wxFileName::GetPathSeparator();
691 libItemName << libId.GetLibItemName();
692 libItemName << '.' + FILEEXT::KiCadFootprintFileExtension;
693
694 if( !wxFileName::FileExists( libItemName ) )
695 return 0;
696
697 ExecuteFile( fullEditorName, libItemName.wc_str(), nullptr, false );
698
699 return 0;
700}
701
702
704{
705 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
706 {
707 std::optional<wxString> url = GetFootprintDocumentationURL( *footprint );
708
709 if( !url.has_value() )
710 {
711 frame()->ShowInfoBarMsg( _( "No datasheet found in the footprint." ) );
712 }
713 else
714 {
715 // Only absolute URLs are supported
716 SEARCH_STACK* searchStack = nullptr;
717 GetAssociatedDocument( m_frame, *url, &m_frame->Prj(), searchStack,
718 { m_frame->GetBoard(), footprint } );
719 }
720 }
721 return 0;
722}
723
724
726{
727 m_frame->LoadFootprintFromLibrary( m_frame->GetLibTree()->GetSelectedLibId() );
728 return 0;
729}
730
731
733{
734 FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint();
735
736 if( !footprint || !m_frame->IsCurrentFPFromBoard() )
737 {
738 wxBell();
739 return 0;
740 }
741
742 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
743
744 if( !m_frame->IsLibraryTreeShown() )
745 m_frame->ToggleLibraryTree();
746
747 return 0;
748}
749
750
752{
753 m_frame->ToggleLayersManager();
754 return 0;
755}
756
757
759{
760 m_frame->ToggleProperties();
761 return 0;
762}
763
764
766{
767 // Check if called from tree context menu
769 {
770 LIB_ID treeLibId = m_frame->GetLibTree()->GetSelectedLibId();
771
772 // Check if a different footprint is selected in the tree
773 if( treeLibId.IsValid()
774 && ( !m_frame->GetBoard()->GetFirstFootprint()
775 || m_frame->GetBoard()->GetFirstFootprint()->GetFPID() != treeLibId ) )
776 {
777 // Edit properties directly from library without loading to canvas
779 return 0;
780 }
781 }
782
783 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
784 {
785 getEditFrame<FOOTPRINT_EDIT_FRAME>()->OnEditItemRequest( footprint );
786 m_frame->GetCanvas()->Refresh();
787 }
788
789 return 0;
790}
791
792
794{
795 // Load the footprint from the library (without adding it to the canvas)
796 FOOTPRINT* libraryFootprint = m_frame->LoadFootprint( aLibId );
797
798 if( !libraryFootprint )
799 return;
800
801 // Create a temporary board to hold the footprint (required by the dialog)
802 std::unique_ptr<BOARD> tempBoard( new BOARD() );
803
804 // Set up the temp board with the current project and board settings.
805 // Use reference-only mode to avoid modifying the project's settings.
806 tempBoard->SetDesignSettings( m_frame->GetBoard()->GetDesignSettings() );
807 tempBoard->SetProject( &m_frame->Prj(), true );
808 tempBoard->SetBoardUse( BOARD_USE::FPHOLDER );
809 tempBoard->SynchronizeProperties();
810
811 // Create a copy to work with and add it to the temporary board
812 FOOTPRINT* tempFootprint = static_cast<FOOTPRINT*>( libraryFootprint->Clone() );
813 delete libraryFootprint;
814
815 tempBoard->Add( tempFootprint );
816 tempFootprint->SetParent( tempBoard.get() );
817
818 LIB_ID oldFPID = tempFootprint->GetFPID();
819
820 // Open the properties dialog
821 DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR dialog( m_frame, tempFootprint );
822
823 if( dialog.ShowQuasiModal() != wxID_OK )
824 return;
825
826 // Remove from temporary board before saving (to avoid double-delete)
827 tempBoard->Remove( tempFootprint );
828
829 // Save the modified footprint back to the library
831 wxString libName = aLibId.GetLibNickname();
832
833 try
834 {
835 adapter->SaveFootprint( libName, tempFootprint, true );
836
837 // Update the tree view
838 wxDataViewItem treeItem = m_frame->GetLibTreeAdapter()->FindItem( oldFPID );
839 m_frame->UpdateLibraryTree( treeItem, tempFootprint );
840 m_frame->SyncLibraryTree( true );
841
842 // Clean up
843 delete tempFootprint;
844 }
845 catch( const IO_ERROR& ioe )
846 {
847 delete tempFootprint;
848 DisplayError( m_frame, ioe.What() );
849 }
850}
851
852
854{
855 getEditFrame<FOOTPRINT_EDIT_FRAME>()->ShowPadPropertiesDialog( nullptr );
856 return 0;
857}
858
859
861{
863 DIALOG_CLEANUP_GRAPHICS dlg( editFrame, true );
864
865 dlg.ShowModal();
866 return 0;
867}
868
869
871{
872 if( !m_checkerDialog )
873 {
875 m_checkerDialog->Show( true );
876 }
877 else // The dialog is just not visible (because the user has double clicked on an error item)
878 {
879 m_checkerDialog->Show( true );
880 }
881
882 return 0;
883}
884
885
887{
888 if( !m_checkerDialog )
890
891 if( !m_checkerDialog->IsShownOnScreen() )
892 m_checkerDialog->Show( true );
893
894 m_checkerDialog->SelectMarker( aMarker );
895}
896
897
899{
900 if( m_checkerDialog )
901 {
902 m_checkerDialog->Destroy();
903 m_checkerDialog = nullptr;
904 }
905}
906
907
909{
910 FOOTPRINT* footprint = board()->Footprints().front();
911 int errors = 0;
912 wxString details;
913
914 // Repair duplicate IDs and missing nets.
915 std::set<KIID> ids;
916 int duplicates = 0;
917
918 auto processItem =
919 [&]( EDA_ITEM* aItem )
920 {
921 if( ids.count( aItem->m_Uuid ) )
922 {
923 duplicates++;
924 const_cast<KIID&>( aItem->m_Uuid ) = KIID();
925 }
926
927 ids.insert( aItem->m_Uuid );
928 };
929
930 // Footprint IDs are the most important, so give them the first crack at "claiming" a
931 // particular KIID.
932
933 processItem( footprint );
934
935 // After that the principal use is for DRC marker pointers, which are most likely to pads.
936
937 for( PAD* pad : footprint->Pads() )
938 processItem( pad );
939
940 // From here out I don't think order matters much.
941
942 processItem( &footprint->Reference() );
943 processItem( &footprint->Value() );
944
945 for( BOARD_ITEM* item : footprint->GraphicalItems() )
946 processItem( item );
947
948 for( ZONE* zone : footprint->Zones() )
949 processItem( zone );
950
951 for( PCB_GROUP* group : footprint->Groups() )
952 processItem( group );
953
954 if( duplicates )
955 {
956 errors += duplicates;
957 details += wxString::Format( _( "%d duplicate IDs replaced.\n" ), duplicates );
958 }
959
960 if( errors )
961 {
962 m_frame->OnModify();
963
964 wxString msg = wxString::Format( _( "%d potential problems repaired." ), errors );
965 DisplayInfoMessage( m_frame, msg, details );
966 }
967 else
968 {
969 DisplayInfoMessage( m_frame, _( "No footprint problems found." ) );
970 }
971
972 return 0;
973}
974
975
977{
978 // clang-format off
987
993
996
1000
1003
1006
1011 // clang-format on
1012
1013 // Line modes for the footprint editor: explicit modes, next-mode, and toolbar sync
1019}
1020
1022{
1023 LEADER_MODE mode = aEvent.Parameter<LEADER_MODE>();
1024 GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode = mode;
1025 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1027 return 0;
1028}
1029
1031{
1033
1034 if( !f )
1035 return 0;
1036
1037 LEADER_MODE mode = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode;
1038
1039 switch( mode )
1040 {
1043 default:
1045 }
1046
1047 return 0;
1048}
@ FPHOLDER
Definition board.h:314
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:959
const FOOTPRINTS & Footprints() const
Definition board.h:363
int ShowModal() override
void SelectToolbarAction(const TOOL_ACTION &aAction)
Select the given action in the 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:150
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:350
EDA_ITEM * Clone() const override
Invoke a function on all children.
const LIB_ID & GetFPID() const
Definition footprint.h:349
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:214
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:134
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.
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.