You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

631 lines
20 KiB

5 years ago
  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 (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. * @author Maciej Suminski <maciej.suminski@cern.ch>
  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. #include "footprint_editor_control.h"
  26. #include "kicad_clipboard.h"
  27. #include <tool/tool_manager.h>
  28. #include <tools/pcb_actions.h>
  29. #include <view/view_controls.h>
  30. #include <footprint_edit_frame.h>
  31. #include <pcbnew_id.h>
  32. #include <confirm.h>
  33. #include <widgets/infobar.h>
  34. #include <bitmaps.h>
  35. #include <footprint.h>
  36. #include <pad.h>
  37. #include <pcb_group.h>
  38. #include <zone.h>
  39. #include <project.h>
  40. #include <fp_lib_table.h>
  41. #include <dialogs/dialog_cleanup_graphics.h>
  42. #include <dialogs/dialog_footprint_checker.h>
  43. #include <footprint_wizard_frame.h>
  44. #include <kiway.h>
  45. #include <drc/drc_results_provider.h>
  46. FOOTPRINT_EDITOR_CONTROL::FOOTPRINT_EDITOR_CONTROL() :
  47. PCB_TOOL_BASE( "pcbnew.ModuleEditor" ),
  48. m_frame( nullptr ),
  49. m_checkerDialog( nullptr )
  50. {
  51. }
  52. FOOTPRINT_EDITOR_CONTROL::~FOOTPRINT_EDITOR_CONTROL()
  53. {
  54. }
  55. void FOOTPRINT_EDITOR_CONTROL::Reset( RESET_REASON aReason )
  56. {
  57. m_frame = getEditFrame<FOOTPRINT_EDIT_FRAME>();
  58. if( m_checkerDialog )
  59. DestroyCheckerDialog();
  60. }
  61. bool FOOTPRINT_EDITOR_CONTROL::Init()
  62. {
  63. // Build a context menu for the footprint tree
  64. //
  65. CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
  66. auto libSelectedCondition =
  67. [ this ]( const SELECTION& aSel )
  68. {
  69. LIB_ID sel = m_frame->GetTreeFPID();
  70. return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
  71. };
  72. // The libInferredCondition allows you to do things like New Symbol and Paste with a
  73. // symbol selected (in other words, when we know the library context even if the library
  74. // itself isn't selected.
  75. auto libInferredCondition =
  76. [ this ]( const SELECTION& aSel )
  77. {
  78. LIB_ID sel = m_frame->GetTreeFPID();
  79. return !sel.GetLibNickname().empty();
  80. };
  81. auto pinnedLibSelectedCondition =
  82. [ this ]( const SELECTION& aSel )
  83. {
  84. LIB_TREE_NODE* current = m_frame->GetCurrentTreeNode();
  85. return current && current->m_Type == LIB_TREE_NODE::LIB && current->m_Pinned;
  86. };
  87. auto unpinnedLibSelectedCondition =
  88. [ this ](const SELECTION& aSel )
  89. {
  90. LIB_TREE_NODE* current = m_frame->GetCurrentTreeNode();
  91. return current && current->m_Type == LIB_TREE_NODE::LIB && !current->m_Pinned;
  92. };
  93. auto fpSelectedCondition =
  94. [ this ]( const SELECTION& aSel )
  95. {
  96. LIB_ID sel = m_frame->GetTreeFPID();
  97. return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
  98. };
  99. ctxMenu.AddItem( ACTIONS::pinLibrary, unpinnedLibSelectedCondition );
  100. ctxMenu.AddItem( ACTIONS::unpinLibrary, pinnedLibSelectedCondition );
  101. ctxMenu.AddSeparator();
  102. ctxMenu.AddItem( PCB_ACTIONS::newFootprint, libSelectedCondition );
  103. ctxMenu.AddItem( PCB_ACTIONS::createFootprint, libSelectedCondition );
  104. ctxMenu.AddSeparator();
  105. ctxMenu.AddItem( ACTIONS::save, libSelectedCondition || libInferredCondition );
  106. ctxMenu.AddItem( ACTIONS::saveAs, libSelectedCondition );
  107. ctxMenu.AddItem( ACTIONS::saveCopyAs, fpSelectedCondition );
  108. ctxMenu.AddItem( ACTIONS::revert, libSelectedCondition || libInferredCondition );
  109. ctxMenu.AddSeparator();
  110. ctxMenu.AddItem( PCB_ACTIONS::cutFootprint, fpSelectedCondition );
  111. ctxMenu.AddItem( PCB_ACTIONS::copyFootprint, fpSelectedCondition );
  112. ctxMenu.AddItem( PCB_ACTIONS::pasteFootprint, libInferredCondition );
  113. ctxMenu.AddItem( PCB_ACTIONS::deleteFootprint, fpSelectedCondition );
  114. ctxMenu.AddSeparator();
  115. ctxMenu.AddItem( PCB_ACTIONS::importFootprint, libInferredCondition );
  116. ctxMenu.AddItem( PCB_ACTIONS::exportFootprint, fpSelectedCondition );
  117. // If we've got nothing else to show, at least show a hide tree option
  118. ctxMenu.AddItem( PCB_ACTIONS::hideFootprintTree, !libInferredCondition );
  119. return true;
  120. }
  121. int FOOTPRINT_EDITOR_CONTROL::NewFootprint( const TOOL_EVENT& aEvent )
  122. {
  123. LIB_ID selected = m_frame->GetTreeFPID();
  124. FOOTPRINT* newFootprint = m_frame->CreateNewFootprint( wxEmptyString );
  125. if( !newFootprint )
  126. return 0;
  127. if( !m_frame->Clear_Pcb( true ) )
  128. return 0;
  129. canvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
  130. m_frame->AddFootprintToBoard( newFootprint );
  131. // Initialize data relative to nets and netclasses (for a new footprint the defaults are
  132. // used). This is mandatory to handle and draw pads.
  133. board()->BuildListOfNets();
  134. newFootprint->SetPosition( wxPoint( 0, 0 ) );
  135. newFootprint->ClearFlags();
  136. m_frame->Zoom_Automatique( false );
  137. m_frame->GetScreen()->SetContentModified();
  138. // If selected from the library tree then go ahead and save it there
  139. if( !selected.GetLibNickname().empty() )
  140. {
  141. LIB_ID fpid = newFootprint->GetFPID();
  142. fpid.SetLibNickname( selected.GetLibNickname() );
  143. newFootprint->SetFPID( fpid );
  144. m_frame->SaveFootprint( newFootprint );
  145. m_frame->ClearModify();
  146. }
  147. m_frame->UpdateView();
  148. m_frame->Update3DView( true, true );
  149. m_frame->SyncLibraryTree( false );
  150. return 0;
  151. }
  152. int FOOTPRINT_EDITOR_CONTROL::CreateFootprint( const TOOL_EVENT& aEvent )
  153. {
  154. LIB_ID selected = m_frame->GetTreeFPID();
  155. if( m_frame->IsContentModified() )
  156. {
  157. if( !HandleUnsavedChanges( m_frame, _( "The current footprint has been modified. "
  158. "Save changes?" ),
  159. [&]() -> bool
  160. {
  161. return m_frame->SaveFootprint( footprint() );
  162. } ) )
  163. {
  164. return 0;
  165. }
  166. }
  167. auto* wizard = (FOOTPRINT_WIZARD_FRAME*) m_frame->Kiway().Player( FRAME_FOOTPRINT_WIZARD,
  168. true, m_frame );
  169. if( wizard->ShowModal( nullptr, m_frame ) )
  170. {
  171. // Creates the new footprint from python script wizard
  172. FOOTPRINT* newFootprint = wizard->GetBuiltFootprint();
  173. if( newFootprint ) // i.e. if create footprint command is OK
  174. {
  175. m_frame->Clear_Pcb( false );
  176. canvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
  177. // Add the new object to board
  178. m_frame->AddFootprintToBoard( newFootprint );
  179. // Initialize data relative to nets and netclasses (for a new footprint the defaults
  180. // are used). This is mandatory to handle and draw pads.
  181. board()->BuildListOfNets();
  182. newFootprint->SetPosition( wxPoint( 0, 0 ) );
  183. newFootprint->ClearFlags();
  184. m_frame->Zoom_Automatique( false );
  185. m_frame->GetScreen()->SetContentModified();
  186. // If selected from the library tree then go ahead and save it there
  187. if( !selected.GetLibNickname().empty() )
  188. {
  189. LIB_ID fpid = newFootprint->GetFPID();
  190. fpid.SetLibNickname( selected.GetLibNickname() );
  191. newFootprint->SetFPID( fpid );
  192. m_frame->SaveFootprint( newFootprint );
  193. m_frame->ClearModify();
  194. }
  195. m_frame->UpdateView();
  196. canvas()->Refresh();
  197. m_frame->Update3DView( true, true );
  198. m_frame->SyncLibraryTree( false );
  199. }
  200. }
  201. wizard->Destroy();
  202. return 0;
  203. }
  204. int FOOTPRINT_EDITOR_CONTROL::Save( const TOOL_EVENT& aEvent )
  205. {
  206. if( !footprint() ) // no loaded footprint
  207. return 0;
  208. if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
  209. {
  210. if( m_frame->SaveFootprint( footprint() ) )
  211. {
  212. view()->Update( footprint() );
  213. canvas()->ForceRefresh();
  214. m_frame->ClearModify();
  215. m_frame->UpdateTitle();
  216. }
  217. }
  218. m_frame->RefreshLibraryTree();
  219. return 0;
  220. }
  221. int FOOTPRINT_EDITOR_CONTROL::SaveAs( const TOOL_EVENT& aEvent )
  222. {
  223. if( m_frame->GetTargetFPID().GetLibItemName().empty() )
  224. {
  225. // Save Library As
  226. const wxString& src_libNickname = m_frame->GetTargetFPID().GetLibNickname();
  227. wxString src_libFullName = m_frame->Prj().PcbFootprintLibs()->GetFullURI( src_libNickname );
  228. if( m_frame->SaveLibraryAs( src_libFullName ) )
  229. m_frame->SyncLibraryTree( true );
  230. }
  231. else if( m_frame->GetTargetFPID() == m_frame->GetLoadedFPID() )
  232. {
  233. // Save Board Footprint As
  234. if( footprint() && m_frame->SaveFootprintAs( footprint() ) )
  235. {
  236. view()->Update( footprint() );
  237. m_frame->ClearModify();
  238. // Get rid of the save-will-update-board-only (or any other dismissable warning)
  239. WX_INFOBAR* infobar = m_frame->GetInfoBar();
  240. if( infobar->IsShown() && infobar->HasCloseButton() )
  241. infobar->Dismiss();
  242. canvas()->ForceRefresh();
  243. m_frame->SyncLibraryTree( true );
  244. }
  245. }
  246. else
  247. {
  248. // Save Selected Footprint As
  249. FOOTPRINT* footprint = m_frame->LoadFootprint( m_frame->GetTargetFPID() );
  250. if( footprint && m_frame->SaveFootprintAs( footprint ) )
  251. {
  252. m_frame->SyncLibraryTree( true );
  253. m_frame->FocusOnLibID( footprint->GetFPID() );
  254. }
  255. }
  256. m_frame->RefreshLibraryTree();
  257. return 0;
  258. }
  259. int FOOTPRINT_EDITOR_CONTROL::Revert( const TOOL_EVENT& aEvent )
  260. {
  261. getEditFrame<FOOTPRINT_EDIT_FRAME>()->RevertFootprint();
  262. return 0;
  263. }
  264. int FOOTPRINT_EDITOR_CONTROL::CutCopyFootprint( const TOOL_EVENT& aEvent )
  265. {
  266. LIB_ID fpID = m_frame->GetTreeFPID();
  267. if( fpID == m_frame->GetLoadedFPID() )
  268. m_copiedFootprint.reset( new FOOTPRINT( *m_frame->GetBoard()->GetFirstFootprint() ) );
  269. else
  270. m_copiedFootprint.reset( m_frame->LoadFootprint( fpID ) );
  271. if( aEvent.IsAction( &PCB_ACTIONS::cutFootprint ) )
  272. DeleteFootprint( aEvent );
  273. return 0;
  274. }
  275. int FOOTPRINT_EDITOR_CONTROL::PasteFootprint( const TOOL_EVENT& aEvent )
  276. {
  277. if( m_copiedFootprint && !m_frame->GetTreeFPID().GetLibNickname().empty() )
  278. {
  279. wxString newLib = m_frame->GetTreeFPID().GetLibNickname();
  280. wxString newName = m_copiedFootprint->GetFPID().GetLibItemName();
  281. while( m_frame->Prj().PcbFootprintLibs()->FootprintExists( newLib, newName ) )
  282. newName += _( "_copy" );
  283. m_copiedFootprint->SetFPID( LIB_ID( newLib, newName ) );
  284. m_frame->SaveFootprintInLibrary( m_copiedFootprint.get(), newLib );
  285. m_frame->SyncLibraryTree( true );
  286. m_frame->FocusOnLibID( m_copiedFootprint->GetFPID() );
  287. }
  288. return 0;
  289. }
  290. int FOOTPRINT_EDITOR_CONTROL::DeleteFootprint( const TOOL_EVENT& aEvent )
  291. {
  292. FOOTPRINT_EDIT_FRAME* frame = getEditFrame<FOOTPRINT_EDIT_FRAME>();
  293. if( frame->DeleteFootprintFromLibrary( frame->GetTargetFPID(), true ) )
  294. {
  295. if( frame->GetTargetFPID() == frame->GetLoadedFPID() )
  296. frame->Clear_Pcb( false );
  297. frame->SyncLibraryTree( true );
  298. }
  299. return 0;
  300. }
  301. int FOOTPRINT_EDITOR_CONTROL::ImportFootprint( const TOOL_EVENT& aEvent )
  302. {
  303. bool is_last_fp_from_brd = m_frame->IsCurrentFPFromBoard();
  304. if( !m_frame->Clear_Pcb( true ) )
  305. return -1; // this command is aborted
  306. getViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
  307. m_frame->ImportFootprint();
  308. if( m_frame->GetBoard()->GetFirstFootprint() )
  309. m_frame->GetBoard()->GetFirstFootprint()->ClearFlags();
  310. frame()->ClearUndoRedoList();
  311. // Update the save items if needed.
  312. if( is_last_fp_from_brd )
  313. {
  314. m_frame->ReCreateMenuBar();
  315. m_frame->ReCreateHToolbar();
  316. }
  317. m_toolMgr->RunAction( ACTIONS::zoomFitScreen, true );
  318. m_frame->OnModify();
  319. return 0;
  320. }
  321. int FOOTPRINT_EDITOR_CONTROL::ExportFootprint( const TOOL_EVENT& aEvent )
  322. {
  323. LIB_ID fpID = m_frame->GetTreeFPID();
  324. FOOTPRINT* fp;
  325. if( !fpID.IsValid() )
  326. fp = m_frame->GetBoard()->GetFirstFootprint();
  327. else
  328. fp = m_frame->LoadFootprint( fpID );
  329. m_frame->ExportFootprint( fp );
  330. return 0;
  331. }
  332. int FOOTPRINT_EDITOR_CONTROL::EditFootprint( const TOOL_EVENT& aEvent )
  333. {
  334. m_frame->LoadFootprintFromLibrary( m_frame->GetTreeFPID() );
  335. return 0;
  336. }
  337. int FOOTPRINT_EDITOR_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
  338. {
  339. LIB_TREE_NODE* currentNode = m_frame->GetCurrentTreeNode();
  340. if( currentNode && !currentNode->m_Pinned )
  341. {
  342. currentNode->m_Pinned = true;
  343. m_frame->RegenerateLibraryTree();
  344. }
  345. return 0;
  346. }
  347. int FOOTPRINT_EDITOR_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
  348. {
  349. LIB_TREE_NODE* currentNode = m_frame->GetCurrentTreeNode();
  350. if( currentNode && currentNode->m_Pinned )
  351. {
  352. currentNode->m_Pinned = false;
  353. m_frame->RegenerateLibraryTree();
  354. }
  355. return 0;
  356. }
  357. int FOOTPRINT_EDITOR_CONTROL::ToggleFootprintTree( const TOOL_EVENT& aEvent )
  358. {
  359. m_frame->ToggleSearchTree();
  360. return 0;
  361. }
  362. int FOOTPRINT_EDITOR_CONTROL::ToggleLayersManager( const TOOL_EVENT& aEvent )
  363. {
  364. m_frame->ToggleLayersManager();
  365. return 0;
  366. }
  367. int FOOTPRINT_EDITOR_CONTROL::Properties( const TOOL_EVENT& aEvent )
  368. {
  369. FOOTPRINT* footprint = m_frame->GetBoard()->GetFirstFootprint();
  370. if( footprint )
  371. {
  372. getEditFrame<FOOTPRINT_EDIT_FRAME>()->OnEditItemRequest( footprint );
  373. m_frame->GetCanvas()->Refresh();
  374. }
  375. return 0;
  376. }
  377. int FOOTPRINT_EDITOR_CONTROL::DefaultPadProperties( const TOOL_EVENT& aEvent )
  378. {
  379. getEditFrame<FOOTPRINT_EDIT_FRAME>()->ShowPadPropertiesDialog( nullptr );
  380. return 0;
  381. }
  382. int FOOTPRINT_EDITOR_CONTROL::CleanupGraphics( const TOOL_EVENT& aEvent )
  383. {
  384. FOOTPRINT_EDIT_FRAME* editFrame = getEditFrame<FOOTPRINT_EDIT_FRAME>();
  385. DIALOG_CLEANUP_GRAPHICS dlg( editFrame, true );
  386. dlg.ShowModal();
  387. return 0;
  388. }
  389. int FOOTPRINT_EDITOR_CONTROL::CheckFootprint( const TOOL_EVENT& aEvent )
  390. {
  391. if( !m_checkerDialog )
  392. {
  393. m_checkerDialog = new DIALOG_FOOTPRINT_CHECKER( m_frame );
  394. m_checkerDialog->Show( true );
  395. }
  396. else // The dialog is just not visible (because the user has double clicked on an error item)
  397. {
  398. m_checkerDialog->SetMarkersProvider( new BOARD_DRC_ITEMS_PROVIDER( m_frame->GetBoard() ) );
  399. m_checkerDialog->Show( true );
  400. }
  401. return 0;
  402. }
  403. void FOOTPRINT_EDITOR_CONTROL::DestroyCheckerDialog()
  404. {
  405. if( m_checkerDialog )
  406. {
  407. m_checkerDialog->Destroy();
  408. m_checkerDialog = nullptr;
  409. }
  410. }
  411. int FOOTPRINT_EDITOR_CONTROL::RepairFootprint( const TOOL_EVENT& aEvent )
  412. {
  413. FOOTPRINT* footprint = board()->Footprints().front();
  414. int errors = 0;
  415. wxString details;
  416. // Repair duplicate IDs and missing nets.
  417. std::set<KIID> ids;
  418. int duplicates = 0;
  419. auto processItem =
  420. [&]( EDA_ITEM* aItem )
  421. {
  422. if( ids.count( aItem->m_Uuid ) )
  423. {
  424. duplicates++;
  425. const_cast<KIID&>( aItem->m_Uuid ) = KIID();
  426. }
  427. ids.insert( aItem->m_Uuid );
  428. };
  429. // Footprint IDs are the most important, so give them the first crack at "claiming" a
  430. // particular KIID.
  431. processItem( footprint );
  432. // After that the principal use is for DRC marker pointers, which are most likely to pads.
  433. for( PAD* pad : footprint->Pads() )
  434. processItem( pad );
  435. // From here out I don't think order matters much.
  436. processItem( &footprint->Reference() );
  437. processItem( &footprint->Value() );
  438. for( BOARD_ITEM* item : footprint->GraphicalItems() )
  439. processItem( item );
  440. for( ZONE* zone : footprint->Zones() )
  441. processItem( zone );
  442. for( PCB_GROUP* group : footprint->Groups() )
  443. processItem( group );
  444. if( duplicates )
  445. {
  446. errors += duplicates;
  447. details += wxString::Format( _( "%d duplicate IDs replaced.\n" ), duplicates );
  448. }
  449. /*******************************
  450. * Your test here
  451. */
  452. /*******************************
  453. * Inform the user
  454. */
  455. if( errors )
  456. {
  457. m_frame->OnModify();
  458. wxString msg = wxString::Format( _( "%d potential problems repaired." ), errors );
  459. DisplayInfoMessage( m_frame, msg, details );
  460. }
  461. else
  462. {
  463. DisplayInfoMessage( m_frame, _( "No footprint problems found." ) );
  464. }
  465. return 0;
  466. }
  467. void FOOTPRINT_EDITOR_CONTROL::setTransitions()
  468. {
  469. Go( &FOOTPRINT_EDITOR_CONTROL::NewFootprint, PCB_ACTIONS::newFootprint.MakeEvent() );
  470. Go( &FOOTPRINT_EDITOR_CONTROL::CreateFootprint, PCB_ACTIONS::createFootprint.MakeEvent() );
  471. Go( &FOOTPRINT_EDITOR_CONTROL::Save, ACTIONS::save.MakeEvent() );
  472. Go( &FOOTPRINT_EDITOR_CONTROL::SaveAs, ACTIONS::saveAs.MakeEvent() );
  473. Go( &FOOTPRINT_EDITOR_CONTROL::SaveAs, ACTIONS::saveCopyAs.MakeEvent() );
  474. Go( &FOOTPRINT_EDITOR_CONTROL::Revert, ACTIONS::revert.MakeEvent() );
  475. Go( &FOOTPRINT_EDITOR_CONTROL::DeleteFootprint, PCB_ACTIONS::deleteFootprint.MakeEvent() );
  476. Go( &FOOTPRINT_EDITOR_CONTROL::EditFootprint, PCB_ACTIONS::editFootprint.MakeEvent() );
  477. Go( &FOOTPRINT_EDITOR_CONTROL::CutCopyFootprint, PCB_ACTIONS::cutFootprint.MakeEvent() );
  478. Go( &FOOTPRINT_EDITOR_CONTROL::CutCopyFootprint, PCB_ACTIONS::copyFootprint.MakeEvent() );
  479. Go( &FOOTPRINT_EDITOR_CONTROL::PasteFootprint, PCB_ACTIONS::pasteFootprint.MakeEvent() );
  480. Go( &FOOTPRINT_EDITOR_CONTROL::ImportFootprint, PCB_ACTIONS::importFootprint.MakeEvent() );
  481. Go( &FOOTPRINT_EDITOR_CONTROL::ExportFootprint, PCB_ACTIONS::exportFootprint.MakeEvent() );
  482. Go( &FOOTPRINT_EDITOR_CONTROL::CleanupGraphics, PCB_ACTIONS::cleanupGraphics.MakeEvent() );
  483. Go( &FOOTPRINT_EDITOR_CONTROL::CheckFootprint, PCB_ACTIONS::checkFootprint.MakeEvent() );
  484. Go( &FOOTPRINT_EDITOR_CONTROL::RepairFootprint, PCB_ACTIONS::repairFootprint.MakeEvent() );
  485. Go( &FOOTPRINT_EDITOR_CONTROL::PinLibrary, ACTIONS::pinLibrary.MakeEvent() );
  486. Go( &FOOTPRINT_EDITOR_CONTROL::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
  487. Go( &FOOTPRINT_EDITOR_CONTROL::ToggleFootprintTree, PCB_ACTIONS::showFootprintTree.MakeEvent() );
  488. Go( &FOOTPRINT_EDITOR_CONTROL::ToggleFootprintTree, PCB_ACTIONS::hideFootprintTree.MakeEvent() );
  489. Go( &FOOTPRINT_EDITOR_CONTROL::Properties, PCB_ACTIONS::footprintProperties.MakeEvent() );
  490. Go( &FOOTPRINT_EDITOR_CONTROL::DefaultPadProperties, PCB_ACTIONS::defaultPadProperties.MakeEvent() );
  491. Go( &FOOTPRINT_EDITOR_CONTROL::ToggleLayersManager, PCB_ACTIONS::showLayersManager.MakeEvent() );
  492. }