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>
50#include <fp_lib_table.h>
54#include <kiway.h>
55#include <project_pcb.h>
56#include <view/view_controls.h>
57
58#include <memory>
59
61
62
64 PCB_TOOL_BASE( "pcbnew.ModuleEditor" ),
65 m_frame( nullptr ),
66 m_checkerDialog( nullptr )
67{
68}
69
70
78
79
81{
82 LIBRARY_EDITOR_CONTROL* libraryTreeTool = m_toolMgr->GetTool<LIBRARY_EDITOR_CONTROL>();
83
84 // Build a context menu for the footprint tree
85 //
86 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
87
88 auto libSelectedCondition =
89 [this]( const SELECTION& aSel )
90 {
91 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
92 return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
93 };
94
95 // The libInferredCondition allows you to do things like New Symbol and Paste with a
96 // symbol selected (in other words, when we know the library context even if the library
97 // itself isn't selected.
98 auto libInferredCondition =
99 [this]( const SELECTION& aSel )
100 {
101 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
102 return !sel.GetLibNickname().empty();
103 };
104
105 auto fpSelectedCondition =
106 [this]( const SELECTION& aSel )
107 {
108 LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
109 return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
110 };
111
112 auto fpExportCondition =
113 [this]( const SELECTION& aSel )
114 {
115 FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint();
116 return fp != nullptr;
117 };
118
119 auto canOpenExternally =
120 [this]( const SELECTION& aSel )
121 {
122 // The option is shown if the editor has no current edits,
123 // dumb/simple guard against opening a new file that does not exist on disk
124 bool ret = !m_frame->IsContentModified();
125 return ret;
126 };
127
128// clang-format off
129 ctxMenu.AddItem( PCB_ACTIONS::newFootprint, libSelectedCondition, 10 );
130 ctxMenu.AddItem( PCB_ACTIONS::createFootprint, libSelectedCondition, 10 );
131
132 ctxMenu.AddSeparator( 10 );
133 ctxMenu.AddItem( ACTIONS::save, SELECTION_CONDITIONS::ShowAlways, 10 );
134 ctxMenu.AddItem( ACTIONS::saveAs, libSelectedCondition || fpSelectedCondition, 10 );
135 ctxMenu.AddItem( ACTIONS::revert, libSelectedCondition || libInferredCondition, 10 );
136
137 ctxMenu.AddSeparator( 10 );
138 ctxMenu.AddItem( PCB_ACTIONS::cutFootprint, fpSelectedCondition, 10 );
139 ctxMenu.AddItem( PCB_ACTIONS::copyFootprint, fpSelectedCondition, 10 );
140 ctxMenu.AddItem( PCB_ACTIONS::pasteFootprint, libInferredCondition, 10 );
141 ctxMenu.AddItem( PCB_ACTIONS::duplicateFootprint, fpSelectedCondition, 10 );
142 ctxMenu.AddItem( PCB_ACTIONS::renameFootprint, fpSelectedCondition, 10 );
143 ctxMenu.AddItem( PCB_ACTIONS::deleteFootprint, fpSelectedCondition, 10 );
144
145 ctxMenu.AddSeparator( 100 );
146 ctxMenu.AddItem( PCB_ACTIONS::importFootprint, libInferredCondition, 100 );
147 ctxMenu.AddItem( PCB_ACTIONS::exportFootprint, fpExportCondition, 100 );
148
149 if( ADVANCED_CFG::GetCfg().m_EnableLibWithText )
150 {
151 ctxMenu.AddSeparator( 200 );
152 ctxMenu.AddItem( ACTIONS::openWithTextEditor, canOpenExternally && fpSelectedCondition, 200 );
153 }
154
155 if( ADVANCED_CFG::GetCfg().m_EnableLibDir )
156 {
157 ctxMenu.AddSeparator( 200 );
158 ctxMenu.AddItem( ACTIONS::openDirectory, canOpenExternally && ( libSelectedCondition || fpSelectedCondition ), 200 );
159 }
160// clang-format on
161
162 libraryTreeTool->AddContextMenuItems( &ctxMenu );
163
164 // Ensure the left toolbar's Line modes group reflects the current setting at startup
165 if( m_toolMgr )
167
168 return true;
169}
170
171
173 const LIB_ID& aTargetLib )
174{
175 const wxString libraryName = aTargetLib.GetUniStringLibNickname();
176
177 if( aTargetLib.GetLibNickname().empty() )
178 {
179 // Do nothing - the footprint will need to be saved manually to assign
180 // to a library.
181 }
182 else
183 {
184 FP_LIB_TABLE& libTable = *PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() );
185
186 if( !libTable.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 {
335 // Save Library As
336 const wxString& src_libNickname = m_frame->GetTargetFPID().GetLibNickname();
337 wxString src_libFullName = PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() )->GetFullURI( src_libNickname );
338
339 if( m_frame->SaveLibraryAs( src_libFullName ) )
340 m_frame->SyncLibraryTree( true );
341 }
342 else if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
343 {
344 // Save Footprint As
345 if( footprint() && m_frame->SaveFootprintAs( footprint() ) )
346 {
347 view()->Update( footprint() );
348 m_frame->ClearModify();
349
350 // Get rid of the save-will-update-board-only (or any other dismissable warning)
351 WX_INFOBAR* infobar = m_frame->GetInfoBar();
352
353 if( infobar->IsShownOnScreen() && infobar->HasCloseButton() )
354 infobar->Dismiss();
355
356 canvas()->ForceRefresh();
357 m_frame->SyncLibraryTree( true );
358 }
359 }
360 else
361 {
362 // Save Selected Footprint As
363 FOOTPRINT* footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
364
365 if( footprint && m_frame->SaveFootprintAs( footprint ) )
366 {
367 m_frame->SyncLibraryTree( true );
368 m_frame->FocusOnLibID( footprint->GetFPID() );
369 }
370 }
371
372 m_frame->RefreshLibraryTree();
373 return 0;
374}
375
376
378{
379 getEditFrame<FOOTPRINT_EDIT_FRAME>()->RevertFootprint();
380 return 0;
381}
382
383
385{
386 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
387
388 if( fpID == m_frame->GetLoadedFPID() )
389 {
390 m_copiedFootprint = std::make_unique<FOOTPRINT>( *m_frame->GetBoard()->GetFirstFootprint() );
391 m_copiedFootprint->SetParent( nullptr );
392 }
393 else
394 {
395 m_copiedFootprint.reset( m_frame->LoadFootprint( fpID ) );
396 }
397
398 if( aEvent.IsAction( &PCB_ACTIONS::cutFootprint ) )
399 DeleteFootprint( aEvent );
400
401 return 0;
402}
403
404
406{
407 if( m_copiedFootprint && !m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname().empty() )
408 {
409 wxString newLib = m_frame->GetLibTree()->GetSelectedLibId().GetLibNickname();
410 wxString newName = m_copiedFootprint->GetFPID().GetLibItemName();
411
412 while( PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() )->FootprintExists( newLib, newName ) )
413 newName += _( "_copy" );
414
415 m_copiedFootprint->SetFPID( LIB_ID( newLib, newName ) );
416 m_frame->SaveFootprintInLibrary( m_copiedFootprint.get(), newLib );
417
418 m_frame->SyncLibraryTree( true );
419 m_frame->LoadFootprintFromLibrary( m_copiedFootprint->GetFPID() );
420 m_frame->FocusOnLibID( m_copiedFootprint->GetFPID() );
421 m_frame->RefreshLibraryTree();
422 }
423
424 return 0;
425}
426
427
429{
430 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
432
433 if( fpID == m_frame->GetLoadedFPID() )
434 footprint = new FOOTPRINT( *m_frame->GetBoard()->GetFirstFootprint() );
435 else
436 footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
437
438 if( footprint && m_frame->DuplicateFootprint( footprint ) )
439 {
440 m_frame->SyncLibraryTree( true );
441 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
442 m_frame->FocusOnLibID( footprint->GetFPID() );
443 m_frame->RefreshLibraryTree();
444 }
445
446 return 0;
447}
448
449
451{
454
455 LIB_ID fpID = m_frame->GetLibTree()->GetSelectedLibId();
456 wxString libraryName = fpID.GetLibNickname();
457 wxString oldName = fpID.GetLibItemName();
458 wxString newName;
459 wxString msg;
460
461 if( !libTool->RenameLibrary( _( "Change Footprint Name" ), oldName,
462 [&]( const wxString& aNewName )
463 {
464 newName = aNewName;
465
466 if( newName.IsEmpty() )
467 {
468 wxMessageBox( _( "Footprint must have a name." ) );
469 return false;
470 }
471
472 // If no change, accept it without prompting
473 if( oldName != newName && tbl->FootprintExists( libraryName, newName ) )
474 {
475 msg = wxString::Format( _( "Footprint '%s' already exists in library '%s'." ),
476 newName, libraryName );
477
478 KIDIALOG errorDlg( m_frame, msg, _( "Confirmation" ),
479 wxOK | wxCANCEL | wxICON_WARNING );
480 errorDlg.SetOKLabel( _( "Overwrite" ) );
481
482 return errorDlg.ShowModal() == wxID_OK;
483 }
484
485 return true;
486 } ) )
487 {
488 return 0; // canceled by user
489 }
490
491 if( newName == oldName )
492 return 0;
493
494 FOOTPRINT* footprint = nullptr;
495
496 if( fpID == m_frame->GetLoadedFPID() )
497 {
498 footprint = m_frame->GetBoard()->GetFirstFootprint();
499
500 if( footprint )
501 {
502 footprint->SetFPID( LIB_ID( libraryName, newName ) );
503
504 if( footprint->GetValue() == oldName )
505 footprint->SetValue( newName );
506
507 m_frame->OnModify();
508 m_frame->UpdateView();
509 }
510 }
511 else
512 {
513 footprint = m_frame->LoadFootprint( fpID );
514
515 if( footprint )
516 {
517 try
518 {
519 footprint->SetFPID( LIB_ID( libraryName, newName ) );
520
521 if( footprint->GetValue() == oldName )
522 footprint->SetValue( newName );
523
524 m_frame->SaveFootprintInLibrary( footprint, libraryName );
525
526 PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() )->FootprintDelete( libraryName, oldName );
527 }
528 catch( const IO_ERROR& ioe )
529 {
530 DisplayErrorMessage( m_frame, _( "Error renaming footprint" ), ioe.What() );
531 }
532 catch( ... )
533 {
534 // Best efforts...
535 }
536 }
537 }
538
539 wxDataViewItem treeItem = m_frame->GetLibTreeAdapter()->FindItem( fpID );
540
541 if( footprint )
542 {
543 m_frame->UpdateLibraryTree( treeItem, footprint );
544 m_frame->FocusOnLibID( LIB_ID( libraryName, newName ) );
545 }
546
547 return 0;
548}
549
550
552{
554
555 if( frame->DeleteFootprintFromLibrary( frame->GetTargetFPID(), true ) )
556 {
557 if( frame->GetTargetFPID() == frame->GetLoadedFPID() )
558 frame->Clear_Pcb( false );
559
560 frame->SyncLibraryTree( true );
561 }
562
563 return 0;
564}
565
566
568{
569 bool is_last_fp_from_brd = m_frame->IsCurrentFPFromBoard();
570
571 if( !m_frame->Clear_Pcb( true ) )
572 return -1; // this command is aborted
573
575 m_frame->ImportFootprint();
576
577 if( m_frame->GetBoard()->GetFirstFootprint() )
578 m_frame->GetBoard()->GetFirstFootprint()->ClearFlags();
579
580 frame()->ClearUndoRedoList();
581
582 // Update the save items if needed.
583 if( is_last_fp_from_brd )
584 {
585 m_frame->ReCreateMenuBar();
586 m_frame->ReCreateHToolbar();
587 }
588
589 m_toolMgr->RunAction( ACTIONS::zoomFitScreen );
590 m_frame->OnModify();
591 return 0;
592}
593
594
596{
597 if( FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint() )
598 m_frame->ExportFootprint( fp );
599
600 return 0;
601}
602
603
605{
606 // No check for multi selection since the context menu option must be hidden in that case
607 FP_LIB_TABLE* globalTable = dynamic_cast<FP_LIB_TABLE*>( &GFootprintTable );
608 FP_LIB_TABLE* projectTable = PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() );
609 LIB_ID libId = m_frame->GetTargetFPID();
610
611 wxString libName = libId.GetLibNickname();
612 wxString libItemName = libId.GetLibItemName();
613 wxString path = wxEmptyString;
614
615 for( FP_LIB_TABLE* table : { globalTable, projectTable } )
616 {
617 if( !table )
618 break;
619
620 try
621 {
622 path = table->FindRow( libName, true )->GetFullURI( true );
623 }
624 catch( IO_ERROR& )
625 {
626 // Do nothing: libName can be not found in globalTable if libName is in projectTable
627 }
628
629 if( !path.IsEmpty() )
630 break;
631 }
632
633 wxString fileExt = wxEmptyString;
634
635 // If selection is footprint
636 if( !libItemName.IsEmpty() )
638
639 wxFileName fileName( path, libItemName, fileExt );
640 wxString explorerCommand;
641
642 if( COMMON_SETTINGS* cfg = Pgm().GetCommonSettings() )
643 explorerCommand = cfg->m_System.file_explorer;
644
645 if( explorerCommand.IsEmpty() )
646 {
647 path = fileName.GetFullPath().BeforeLast( wxFileName::GetPathSeparator() );
648
649 if( !path.IsEmpty() && wxDirExists( path ) )
651
652 return 0;
653 }
654
655 if( !explorerCommand.EndsWith( "%F" ) )
656 {
657 wxMessageBox( _( "Missing/malformed file explorer argument '%F' in common settings." ) );
658 return 0;
659 }
660
661 wxString escapedFilePath = fileName.GetFullPath();
662 escapedFilePath.Replace( wxS( "\"" ), wxS( "_" ) );
663
664 wxString fileArg = wxEmptyString;
665 fileArg << '"' << escapedFilePath << '"';
666
667 explorerCommand.Replace( wxT( "%F" ), fileArg );
668
669 if( !explorerCommand.IsEmpty() )
670 wxExecute( explorerCommand );
671
672 return 0;
673}
674
675
677{
678 wxString fullEditorName = Pgm().GetTextEditor();
679
680 if( fullEditorName.IsEmpty() )
681 {
682 wxMessageBox( _( "No text editor selected in KiCad. Please choose one." ) );
683 return 0;
684 }
685
686 // No check for multi selection since the context menu option must be hidden in that case
687 FP_LIB_TABLE* globalTable = dynamic_cast<FP_LIB_TABLE*>( &GFootprintTable );
688 FP_LIB_TABLE* projectTable = PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() );
689 LIB_ID libId = m_frame->GetLibTree()->GetSelectedLibId();
690
691 wxString libName = libId.GetLibNickname();
692 wxString libItemName = wxEmptyString;
693
694 for( FP_LIB_TABLE* table : { globalTable, projectTable } )
695 {
696 if( !table )
697 break;
698
699 try
700 {
701 libItemName = table->FindRow( libName, true )->GetFullURI( true );
702 }
703 catch( IO_ERROR& )
704 {
705 // Do nothing: libName can be not found in globalTable if libName is in projectTable
706 }
707
708 if( !libItemName.IsEmpty() )
709 break;
710 }
711
712 libItemName << wxFileName::GetPathSeparator();
713 libItemName << libId.GetLibItemName();
714 libItemName << '.' + FILEEXT::KiCadFootprintFileExtension;
715
716 if( !wxFileName::FileExists( libItemName ) )
717 return 0;
718
719 ExecuteFile( fullEditorName, libItemName.wc_str(), nullptr, false );
720
721 return 0;
722}
723
724
726{
727 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
728 {
729 std::optional<wxString> url = GetFootprintDocumentationURL( *footprint );
730
731 if( !url.has_value() )
732 {
733 frame()->ShowInfoBarMsg( _( "No datasheet found in the footprint." ) );
734 }
735 else
736 {
737 // Only absolute URLs are supported
738 SEARCH_STACK* searchStack = nullptr;
739 GetAssociatedDocument( m_frame, *url, &m_frame->Prj(), searchStack,
740 { m_frame->GetBoard(), footprint } );
741 }
742 }
743 return 0;
744}
745
746
748{
749 m_frame->LoadFootprintFromLibrary( m_frame->GetLibTree()->GetSelectedLibId() );
750 return 0;
751}
752
753
755{
756 FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint();
757
758 if( !footprint || !m_frame->IsCurrentFPFromBoard() )
759 {
760 wxBell();
761 return 0;
762 }
763
764 m_frame->LoadFootprintFromLibrary( footprint->GetFPID() );
765
766 if( !m_frame->IsLibraryTreeShown() )
767 m_frame->ToggleLibraryTree();
768
769 return 0;
770}
771
772
774{
775 m_frame->ToggleLayersManager();
776 return 0;
777}
778
779
781{
782 m_frame->ToggleProperties();
783 return 0;
784}
785
786
788{
789 if( FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint() )
790 {
791 getEditFrame<FOOTPRINT_EDIT_FRAME>()->OnEditItemRequest( footprint );
792 m_frame->GetCanvas()->Refresh();
793 }
794
795 return 0;
796}
797
798
800{
801 getEditFrame<FOOTPRINT_EDIT_FRAME>()->ShowPadPropertiesDialog( nullptr );
802 return 0;
803}
804
805
807{
809 DIALOG_CLEANUP_GRAPHICS dlg( editFrame, true );
810
811 dlg.ShowModal();
812 return 0;
813}
814
815
817{
818 if( !m_checkerDialog )
819 {
821 m_checkerDialog->Show( true );
822 }
823 else // The dialog is just not visible (because the user has double clicked on an error item)
824 {
825 m_checkerDialog->Show( true );
826 }
827
828 return 0;
829}
830
831
833{
834 if( !m_checkerDialog )
836
837 if( !m_checkerDialog->IsShownOnScreen() )
838 m_checkerDialog->Show( true );
839
840 m_checkerDialog->SelectMarker( aMarker );
841}
842
843
845{
846 if( m_checkerDialog )
847 {
848 m_checkerDialog->Destroy();
849 m_checkerDialog = nullptr;
850 }
851}
852
853
855{
856 FOOTPRINT* footprint = board()->Footprints().front();
857 int errors = 0;
858 wxString details;
859
860 // Repair duplicate IDs and missing nets.
861 std::set<KIID> ids;
862 int duplicates = 0;
863
864 auto processItem =
865 [&]( EDA_ITEM* aItem )
866 {
867 if( ids.count( aItem->m_Uuid ) )
868 {
869 duplicates++;
870 const_cast<KIID&>( aItem->m_Uuid ) = KIID();
871 }
872
873 ids.insert( aItem->m_Uuid );
874 };
875
876 // Footprint IDs are the most important, so give them the first crack at "claiming" a
877 // particular KIID.
878
879 processItem( footprint );
880
881 // After that the principal use is for DRC marker pointers, which are most likely to pads.
882
883 for( PAD* pad : footprint->Pads() )
884 processItem( pad );
885
886 // From here out I don't think order matters much.
887
888 processItem( &footprint->Reference() );
889 processItem( &footprint->Value() );
890
891 for( BOARD_ITEM* item : footprint->GraphicalItems() )
892 processItem( item );
893
894 for( ZONE* zone : footprint->Zones() )
895 processItem( zone );
896
897 for( PCB_GROUP* group : footprint->Groups() )
898 processItem( group );
899
900 if( duplicates )
901 {
902 errors += duplicates;
903 details += wxString::Format( _( "%d duplicate IDs replaced.\n" ), duplicates );
904 }
905
906 if( errors )
907 {
908 m_frame->OnModify();
909
910 wxString msg = wxString::Format( _( "%d potential problems repaired." ), errors );
911 DisplayInfoMessage( m_frame, msg, details );
912 }
913 else
914 {
915 DisplayInfoMessage( m_frame, _( "No footprint problems found." ) );
916 }
917
918 return 0;
919}
920
921
923{
924 // clang-format off
933
939
942
946
949
952
957 // clang-format on
958
959 // Line modes for the footprint editor: explicit modes, next-mode, and toolbar sync
965}
966
968{
969 LEADER_MODE mode = aEvent.Parameter<LEADER_MODE>();
970 GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode = mode;
971 m_toolMgr->PostAction( ACTIONS::refreshPreview );
973 return 0;
974}
975
977{
979
980 if( !f )
981 return 0;
982
983 LEADER_MODE mode = GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>( "fpedit" )->m_AngleSnapMode;
984
985 switch( mode )
986 {
989 break;
992 break;
994 default:
996 break;
997 }
998
999 return 0;
1000}
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:266
static TOOL_ACTION save
Definition actions.h:58
static TOOL_ACTION zoomFitScreen
Definition actions.h:141
static TOOL_ACTION showProperties
Definition actions.h:265
static TOOL_ACTION refreshPreview
Definition actions.h:158
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:79
void BuildListOfNets()
Definition board.h:916
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
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)
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)
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:270
const LIB_ID & GetFPID() const
Definition footprint.h:269
void FootprintDelete(const wxString &aNickname, const wxString &aFootprintName)
Delete the aFootprintName from the library given by aNickname.
bool IsFootprintLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
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)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
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
wxString GetFullURI(const wxString &aLibNickname, bool aExpandEnvVars=true) const
Return the full URI of the library mapped to aLibNickname.
Definition pad.h:54
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:204
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
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:110
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:222
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:129
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
This file is part of the common library.
FP_LIB_TABLE GFootprintTable
The global footprint library table.
Definition cvpcb.cpp:150
#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:62
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:143
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:913
see class PGM_BASE
T * GetAppSettings(const char *aFilename)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
Definition of file extensions used in Kicad.