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.

1053 lines
30 KiB

12 years ago
12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014-2016 CERN
  5. * @author Maciej Suminski <maciej.suminski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <cstdint>
  25. #include "pcbnew_control.h"
  26. #include "pcb_actions.h"
  27. #include "selection_tool.h"
  28. #include "edit_tool.h"
  29. #include "picker_tool.h"
  30. #include "pcb_editor_control.h"
  31. #include "grid_helper.h"
  32. #include <class_board.h>
  33. #include <class_module.h>
  34. #include <class_track.h>
  35. #include <class_zone.h>
  36. #include <pcb_screen.h>
  37. #include <confirm.h>
  38. #include <hotkeys.h>
  39. #include <properties.h>
  40. #include <io_mgr.h>
  41. #include <kicad_plugin.h>
  42. #include <kicad_clipboard.h>
  43. #include <pcbnew_id.h>
  44. #include <pcb_edit_frame.h>
  45. #include <pcb_draw_panel_gal.h>
  46. #include <connectivity/connectivity_data.h>
  47. #include <tool/tool_manager.h>
  48. #include <gal/graphics_abstraction_layer.h>
  49. #include <view/view_controls.h>
  50. #include <pcb_painter.h>
  51. #include <origin_viewitem.h>
  52. #include <board_commit.h>
  53. #include <bitmaps.h>
  54. #include <functional>
  55. using namespace std::placeholders;
  56. // files.cpp
  57. extern bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName,
  58. bool aKicadFilesOnly = false );
  59. extern IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl );
  60. // Display modes
  61. TOOL_ACTION PCB_ACTIONS::trackDisplayMode( "pcbnew.Control.trackDisplayMode",
  62. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_DISPLAY_MODE ),
  63. "", "" );
  64. TOOL_ACTION PCB_ACTIONS::padDisplayMode( "pcbnew.Control.padDisplayMode",
  65. AS_GLOBAL, 0,
  66. "", "" );
  67. TOOL_ACTION PCB_ACTIONS::viaDisplayMode( "pcbnew.Control.viaDisplayMode",
  68. AS_GLOBAL, 0,
  69. "", "" );
  70. TOOL_ACTION PCB_ACTIONS::graphicDisplayMode( "pcbnew.Control.graphicDisplayMode",
  71. AS_GLOBAL, 0,
  72. "", "" );
  73. TOOL_ACTION PCB_ACTIONS::moduleEdgeOutlines( "pcbnew.Control.graphicOutlines",
  74. AS_GLOBAL, 0,
  75. "", "" );
  76. TOOL_ACTION PCB_ACTIONS::moduleTextOutlines( "pcbnew.Control.textOutlines",
  77. AS_GLOBAL, 0,
  78. "", "" );
  79. TOOL_ACTION PCB_ACTIONS::zoneDisplayEnable( "pcbnew.Control.zoneDisplayEnable",
  80. AS_GLOBAL, 0,
  81. "", "" );
  82. TOOL_ACTION PCB_ACTIONS::zoneDisplayDisable( "pcbnew.Control.zoneDisplayDisable",
  83. AS_GLOBAL, 0,
  84. "", "" );
  85. TOOL_ACTION PCB_ACTIONS::zoneDisplayOutlines( "pcbnew.Control.zoneDisplayOutlines",
  86. AS_GLOBAL, 0,
  87. "", "" );
  88. TOOL_ACTION PCB_ACTIONS::highContrastMode( "pcbnew.Control.highContrastMode",
  89. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_HIGHCONTRAST_MODE ),
  90. "", "" );
  91. TOOL_ACTION PCB_ACTIONS::highContrastInc( "pcbnew.Control.highContrastInc",
  92. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_HIGHCONTRAST_INC ),
  93. "", "" );
  94. TOOL_ACTION PCB_ACTIONS::highContrastDec( "pcbnew.Control.highContrastDec",
  95. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_HIGHCONTRAST_DEC ),
  96. "", "" );
  97. // Layer control
  98. TOOL_ACTION PCB_ACTIONS::layerTop( "pcbnew.Control.layerTop",
  99. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COMPONENT ),
  100. "", "", NULL, AF_NONE, (void*) F_Cu );
  101. TOOL_ACTION PCB_ACTIONS::layerInner1( "pcbnew.Control.layerInner1",
  102. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER1 ),
  103. "", "", NULL, AF_NONE, (void*) In1_Cu );
  104. TOOL_ACTION PCB_ACTIONS::layerInner2( "pcbnew.Control.layerInner2",
  105. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER2 ),
  106. "", "", NULL, AF_NONE, (void*) In2_Cu );
  107. TOOL_ACTION PCB_ACTIONS::layerInner3( "pcbnew.Control.layerInner3",
  108. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER3 ),
  109. "", "", NULL, AF_NONE, (void*) In3_Cu );
  110. TOOL_ACTION PCB_ACTIONS::layerInner4( "pcbnew.Control.layerInner4",
  111. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER4 ),
  112. "", "", NULL, AF_NONE, (void*) In4_Cu );
  113. TOOL_ACTION PCB_ACTIONS::layerInner5( "pcbnew.Control.layerInner5",
  114. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER5 ),
  115. "", "", NULL, AF_NONE, (void*) In5_Cu );
  116. TOOL_ACTION PCB_ACTIONS::layerInner6( "pcbnew.Control.layerInner6",
  117. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER6 ),
  118. "", "", NULL, AF_NONE, (void*) In6_Cu );
  119. TOOL_ACTION PCB_ACTIONS::layerBottom( "pcbnew.Control.layerBottom",
  120. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COPPER ),
  121. "", "", NULL, AF_NONE, (void*) B_Cu );
  122. TOOL_ACTION PCB_ACTIONS::layerNext( "pcbnew.Control.layerNext",
  123. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_NEXT ),
  124. "", "" );
  125. TOOL_ACTION PCB_ACTIONS::layerPrev( "pcbnew.Control.layerPrev",
  126. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_PREVIOUS ),
  127. "", "" );
  128. TOOL_ACTION PCB_ACTIONS::layerToggle( "pcbnew.Control.layerToggle",
  129. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_THROUGH_VIA ),
  130. "", "" );
  131. TOOL_ACTION PCB_ACTIONS::layerAlphaInc( "pcbnew.Control.layerAlphaInc",
  132. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_INC_LAYER_ALPHA ),
  133. "", "" );
  134. TOOL_ACTION PCB_ACTIONS::layerAlphaDec( "pcbnew.Control.layerAlphaDec",
  135. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DEC_LAYER_ALPHA ),
  136. "", "" );
  137. TOOL_ACTION PCB_ACTIONS::layerChanged( "pcbnew.Control.layerChanged",
  138. AS_GLOBAL, 0,
  139. "", "", NULL, AF_NOTIFY );
  140. // Miscellaneous
  141. TOOL_ACTION PCB_ACTIONS::selectionTool( "pcbnew.Control.selectionTool",
  142. AS_GLOBAL, 0,
  143. "", "", NULL, AF_ACTIVATE );
  144. TOOL_ACTION PCB_ACTIONS::resetCoords( "pcbnew.Control.resetCoords",
  145. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_RESET_LOCAL_COORD ),
  146. "", "" );
  147. TOOL_ACTION PCB_ACTIONS::switchCursor( "pcbnew.Control.switchCursor",
  148. AS_GLOBAL, 0,
  149. "", "" );
  150. TOOL_ACTION PCB_ACTIONS::switchUnits( "pcbnew.Control.switchUnits",
  151. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_UNITS ),
  152. "", "" );
  153. TOOL_ACTION PCB_ACTIONS::deleteItemCursor( "pcbnew.Control.deleteItemCursor",
  154. AS_GLOBAL, 0,
  155. "", "" );
  156. TOOL_ACTION PCB_ACTIONS::showHelp( "pcbnew.Control.showHelp",
  157. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_HELP ),
  158. "", "" );
  159. TOOL_ACTION PCB_ACTIONS::toBeDone( "pcbnew.Control.toBeDone",
  160. AS_GLOBAL, 0, // dialog saying it is not implemented yet
  161. "", "" ); // so users are aware of that
  162. TOOL_ACTION PCB_ACTIONS::pasteFromClipboard( "pcbnew.InteractiveEdit.pasteFromClipboard",
  163. AS_GLOBAL, 0, // do not define a hotkey and let TranslateLegacyId() handle the event
  164. _( "Paste" ), _( "Paste content from clipboard" ),
  165. paste_xpm );
  166. PCBNEW_CONTROL::PCBNEW_CONTROL() :
  167. PCB_TOOL( "pcbnew.Control" ), m_frame( NULL )
  168. {
  169. m_gridOrigin.reset( new KIGFX::ORIGIN_VIEWITEM() );
  170. }
  171. PCBNEW_CONTROL::~PCBNEW_CONTROL()
  172. {
  173. }
  174. void PCBNEW_CONTROL::Reset( RESET_REASON aReason )
  175. {
  176. m_frame = getEditFrame<PCB_BASE_FRAME>();
  177. if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH )
  178. {
  179. m_gridOrigin->SetPosition( board()->GetGridOrigin() );
  180. m_gridOrigin->SetColor( m_frame->GetGridColor() );
  181. getView()->Remove( m_gridOrigin.get() );
  182. getView()->Add( m_gridOrigin.get() );
  183. }
  184. }
  185. template<class T> void Flip( T& aValue )
  186. {
  187. aValue = !aValue;
  188. }
  189. int PCBNEW_CONTROL::TrackDisplayMode( const TOOL_EVENT& aEvent )
  190. {
  191. auto opts = displayOptions();
  192. Flip( opts->m_DisplayPcbTrackFill );
  193. view()->UpdateDisplayOptions( opts );
  194. for( auto track : board()->Tracks() )
  195. {
  196. if( track->Type() == PCB_TRACE_T )
  197. view()->Update( track, KIGFX::GEOMETRY );
  198. }
  199. canvas()->Refresh();
  200. return 0;
  201. }
  202. int PCBNEW_CONTROL::PadDisplayMode( const TOOL_EVENT& aEvent )
  203. {
  204. auto opts = displayOptions();
  205. Flip( opts->m_DisplayPadFill );
  206. view()->UpdateDisplayOptions( opts );
  207. for( auto module : board()->Modules() ) // fixme: move to PCB_VIEW
  208. {
  209. for( auto pad : module->Pads() )
  210. view()->Update( pad, KIGFX::GEOMETRY );
  211. }
  212. canvas()->Refresh();
  213. return 0;
  214. }
  215. int PCBNEW_CONTROL::ViaDisplayMode( const TOOL_EVENT& aEvent )
  216. {
  217. auto opts = displayOptions();
  218. Flip( opts->m_DisplayViaFill );
  219. view()->UpdateDisplayOptions( opts );
  220. for( auto track : board()->Tracks() )
  221. {
  222. if( track->Type() == PCB_TRACE_T || track->Type() == PCB_VIA_T )
  223. view()->Update( track, KIGFX::GEOMETRY );
  224. }
  225. canvas()->Refresh();
  226. return 0;
  227. }
  228. int PCBNEW_CONTROL::GraphicDisplayMode( const TOOL_EVENT& aEvent )
  229. {
  230. auto opts = displayOptions();
  231. Flip( opts->m_DisplayDrawItemsFill );
  232. view()->UpdateDisplayOptions( opts );
  233. for( auto item : board()->Drawings() )
  234. {
  235. view()->Update( item, KIGFX::GEOMETRY );
  236. }
  237. canvas()->Refresh();
  238. return 0;
  239. }
  240. int PCBNEW_CONTROL::ModuleEdgeOutlines( const TOOL_EVENT& aEvent )
  241. {
  242. auto opts = displayOptions();
  243. Flip( opts->m_DisplayModEdgeFill );
  244. view()->UpdateDisplayOptions( opts );
  245. for( auto module : board()->Modules() )
  246. {
  247. for( auto item : module->GraphicalItems() )
  248. {
  249. if( item->Type() == PCB_MODULE_EDGE_T )
  250. view()->Update( item, KIGFX::GEOMETRY );
  251. }
  252. }
  253. canvas()->Refresh();
  254. return 0;
  255. }
  256. int PCBNEW_CONTROL::ModuleTextOutlines( const TOOL_EVENT& aEvent )
  257. {
  258. auto opts = displayOptions();
  259. Flip( opts->m_DisplayModTextFill );
  260. view()->UpdateDisplayOptions( opts );
  261. for( auto module : board()->Modules() )
  262. {
  263. for( auto item : module->GraphicalItems() )
  264. {
  265. if( item->Type() == PCB_MODULE_TEXT_T )
  266. view()->Update( item, KIGFX::GEOMETRY );
  267. }
  268. view()->Update( &module->Reference(), KIGFX::GEOMETRY );
  269. view()->Update( &module->Value(), KIGFX::GEOMETRY );
  270. }
  271. canvas()->Refresh();
  272. return 0;
  273. }
  274. int PCBNEW_CONTROL::ZoneDisplayMode( const TOOL_EVENT& aEvent )
  275. {
  276. auto opts = displayOptions();
  277. // Apply new display options to the GAL canvas
  278. if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayEnable ) )
  279. opts->m_DisplayZonesMode = 0;
  280. else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayDisable ) )
  281. opts->m_DisplayZonesMode = 1;
  282. else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayOutlines ) )
  283. opts->m_DisplayZonesMode = 2;
  284. else
  285. wxFAIL;
  286. view()->UpdateDisplayOptions( opts );
  287. for( int i = 0; i < board()->GetAreaCount(); ++i )
  288. view()->Update( board()->GetArea( i ), KIGFX::GEOMETRY );
  289. canvas()->Refresh();
  290. return 0;
  291. }
  292. int PCBNEW_CONTROL::HighContrastMode( const TOOL_EVENT& aEvent )
  293. {
  294. auto opts = displayOptions();
  295. Flip( opts->m_ContrastModeDisplay );
  296. view()->UpdateDisplayOptions( opts );
  297. canvas()->SetHighContrastLayer( m_frame->GetActiveLayer() );
  298. return 0;
  299. }
  300. int PCBNEW_CONTROL::HighContrastInc( const TOOL_EVENT& aEvent )
  301. {
  302. return 0;
  303. }
  304. int PCBNEW_CONTROL::HighContrastDec( const TOOL_EVENT& aEvent )
  305. {
  306. return 0;
  307. }
  308. // Layer control
  309. int PCBNEW_CONTROL::LayerSwitch( const TOOL_EVENT& aEvent )
  310. {
  311. m_frame->SwitchLayer( NULL, (PCB_LAYER_ID) aEvent.Parameter<intptr_t>() );
  312. return 0;
  313. }
  314. int PCBNEW_CONTROL::LayerNext( const TOOL_EVENT& aEvent )
  315. {
  316. PCB_BASE_FRAME* editFrame = m_frame;
  317. LAYER_NUM layer = editFrame->GetActiveLayer();
  318. if( layer < F_Cu || layer > B_Cu )
  319. return 0;
  320. int layerCount = board()->GetCopperLayerCount();
  321. if( layer == layerCount - 2 || layerCount < 2 )
  322. layer = B_Cu;
  323. else if( layer == B_Cu )
  324. layer = F_Cu;
  325. else
  326. ++layer;
  327. wxCHECK( IsCopperLayer( layer ), 0 );
  328. editFrame->SwitchLayer( NULL, ToLAYER_ID( layer ) );
  329. return 0;
  330. }
  331. int PCBNEW_CONTROL::LayerPrev( const TOOL_EVENT& aEvent )
  332. {
  333. PCB_BASE_FRAME* editFrame = m_frame;
  334. LAYER_NUM layer = editFrame->GetActiveLayer();
  335. if( layer < F_Cu || layer > B_Cu )
  336. return 0;
  337. int layerCount = board()->GetCopperLayerCount();
  338. if( layer == F_Cu || layerCount < 2 )
  339. layer = B_Cu;
  340. else if( layer == B_Cu )
  341. layer = layerCount - 2;
  342. else
  343. --layer;
  344. wxCHECK( IsCopperLayer( layer ), 0 );
  345. editFrame->SwitchLayer( NULL, ToLAYER_ID( layer ) );
  346. return 0;
  347. }
  348. int PCBNEW_CONTROL::LayerToggle( const TOOL_EVENT& aEvent )
  349. {
  350. LAYER_NUM currentLayer = m_frame->GetActiveLayer();
  351. PCB_SCREEN* screen = m_frame->GetScreen();
  352. if( currentLayer == screen->m_Route_Layer_TOP )
  353. m_frame->SwitchLayer( NULL, screen->m_Route_Layer_BOTTOM );
  354. else
  355. m_frame->SwitchLayer( NULL, screen->m_Route_Layer_TOP );
  356. return 0;
  357. }
  358. // It'd be nice to share the min/max with the DIALOG_COLOR_PICKER, but those are
  359. // set in wxFormBuilder.
  360. #define ALPHA_MIN 0.20
  361. #define ALPHA_MAX 1.00
  362. #define ALPHA_STEP 0.05
  363. int PCBNEW_CONTROL::LayerAlphaInc( const TOOL_EVENT& aEvent )
  364. {
  365. auto painter = static_cast<KIGFX::PCB_PAINTER*>( getView()->GetPainter() );
  366. auto settings = painter->GetSettings();
  367. LAYER_NUM currentLayer = m_frame->GetActiveLayer();
  368. KIGFX::COLOR4D currentColor = settings->GetLayerColor( currentLayer );
  369. if( currentColor.a <= ALPHA_MAX - ALPHA_STEP )
  370. {
  371. currentColor.a += ALPHA_STEP;
  372. settings->SetLayerColor( currentLayer, currentColor );
  373. m_frame->GetGalCanvas()->GetView()->UpdateLayerColor( currentLayer );
  374. wxUpdateUIEvent dummy;
  375. static_cast<PCB_EDIT_FRAME*>( m_frame )->OnUpdateLayerAlpha( dummy );
  376. }
  377. else
  378. wxBell();
  379. return 0;
  380. }
  381. int PCBNEW_CONTROL::LayerAlphaDec( const TOOL_EVENT& aEvent )
  382. {
  383. auto painter = static_cast<KIGFX::PCB_PAINTER*>( getView()->GetPainter() );
  384. auto settings = painter->GetSettings();
  385. LAYER_NUM currentLayer = m_frame->GetActiveLayer();
  386. KIGFX::COLOR4D currentColor = settings->GetLayerColor( currentLayer );
  387. if( currentColor.a >= ALPHA_MIN + ALPHA_STEP )
  388. {
  389. currentColor.a -= ALPHA_STEP;
  390. settings->SetLayerColor( currentLayer, currentColor );
  391. m_frame->GetGalCanvas()->GetView()->UpdateLayerColor( currentLayer );
  392. wxUpdateUIEvent dummy;
  393. static_cast<PCB_BASE_FRAME*>( m_frame )->OnUpdateLayerAlpha( dummy );
  394. }
  395. else
  396. wxBell();
  397. return 0;
  398. }
  399. // Grid control
  400. int PCBNEW_CONTROL::GridFast1( const TOOL_EVENT& aEvent )
  401. {
  402. m_frame->SetFastGrid1();
  403. updateGrid();
  404. return 0;
  405. }
  406. int PCBNEW_CONTROL::GridFast2( const TOOL_EVENT& aEvent )
  407. {
  408. m_frame->SetFastGrid2();
  409. updateGrid();
  410. return 0;
  411. }
  412. bool PCBNEW_CONTROL::DoSetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
  413. BOARD_ITEM* originViewItem, const VECTOR2D& aPoint )
  414. {
  415. aFrame->SetGridOrigin( wxPoint( aPoint.x, aPoint.y ) );
  416. aView->GetGAL()->SetGridOrigin( aPoint );
  417. originViewItem->SetPosition( wxPoint( aPoint.x, aPoint.y ) );
  418. aView->MarkDirty();
  419. aFrame->OnModify();
  420. return true;
  421. }
  422. bool PCBNEW_CONTROL::SetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
  423. BOARD_ITEM* originViewItem, const VECTOR2D& aPoint )
  424. {
  425. aFrame->SaveCopyInUndoList( originViewItem, UR_GRIDORIGIN );
  426. return DoSetGridOrigin( aView, aFrame, originViewItem, aPoint );
  427. }
  428. int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
  429. {
  430. VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
  431. if( origin )
  432. {
  433. // We can't undo the other grid dialog settings, so no sense undoing just the origin
  434. DoSetGridOrigin( getView(), m_frame, m_gridOrigin.get(), *origin );
  435. delete origin;
  436. }
  437. else
  438. {
  439. Activate();
  440. PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
  441. wxCHECK( picker, 0 );
  442. // TODO it will not check the toolbar button in module editor, as it uses a different ID..
  443. m_frame->SetToolID( ID_PCB_PLACE_GRID_COORD_BUTT, wxCURSOR_PENCIL, _( "Adjust grid origin" ) );
  444. picker->SetClickHandler( std::bind( SetGridOrigin, getView(), m_frame, m_gridOrigin.get(), _1 ) );
  445. picker->Activate();
  446. Wait();
  447. }
  448. return 0;
  449. }
  450. int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent )
  451. {
  452. SetGridOrigin( getView(), m_frame, m_gridOrigin.get(), VECTOR2D( 0, 0 ) );
  453. return 0;
  454. }
  455. // Miscellaneous
  456. int PCBNEW_CONTROL::ResetCoords( const TOOL_EVENT& aEvent )
  457. {
  458. auto vcSettings = m_toolMgr->GetCurrentToolVC();
  459. // Use either the active tool forced cursor position or the general settings
  460. VECTOR2I cursorPos = vcSettings.m_forceCursorPosition ? vcSettings.m_forcedPosition :
  461. getViewControls()->GetCursorPosition();
  462. m_frame->GetScreen()->m_O_Curseur = wxPoint( cursorPos.x, cursorPos.y );
  463. m_frame->UpdateStatusBar();
  464. return 0;
  465. }
  466. int PCBNEW_CONTROL::SwitchCursor( const TOOL_EVENT& aEvent )
  467. {
  468. auto& galOpts = m_frame->GetGalDisplayOptions();
  469. galOpts.m_fullscreenCursor = !galOpts.m_fullscreenCursor;
  470. galOpts.NotifyChanged();
  471. return 0;
  472. }
  473. int PCBNEW_CONTROL::SwitchUnits( const TOOL_EVENT& aEvent )
  474. {
  475. // TODO should not it be refactored to pcb_frame member function?
  476. wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
  477. if( m_frame->GetUserUnits() == INCHES )
  478. evt.SetId( ID_TB_OPTIONS_SELECT_UNIT_MM );
  479. else
  480. evt.SetId( ID_TB_OPTIONS_SELECT_UNIT_INCH );
  481. m_frame->ProcessEvent( evt );
  482. return 0;
  483. }
  484. static bool deleteItem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
  485. {
  486. SELECTION_TOOL* selectionTool = aToolMgr->GetTool<SELECTION_TOOL>();
  487. wxCHECK( selectionTool, false );
  488. aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
  489. const SELECTION& selection = selectionTool->RequestSelection(
  490. []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
  491. { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED ); } );
  492. if( selection.Empty() )
  493. return true;
  494. aToolMgr->RunAction( PCB_ACTIONS::remove, true );
  495. return true;
  496. }
  497. int PCBNEW_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent )
  498. {
  499. Activate();
  500. PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
  501. wxCHECK( picker, 0 );
  502. m_frame->SetToolID( m_editModules ? ID_MODEDIT_DELETE_TOOL : ID_PCB_DELETE_ITEM_BUTT,
  503. wxCURSOR_BULLSEYE, _( "Delete item" ) );
  504. picker->SetSnapping( false );
  505. picker->SetClickHandler( std::bind( deleteItem, m_toolMgr, _1 ) );
  506. picker->Activate();
  507. Wait();
  508. return 0;
  509. }
  510. int PCBNEW_CONTROL::PasteItemsFromClipboard( const TOOL_EVENT& aEvent )
  511. {
  512. CLIPBOARD_IO pi;
  513. BOARD_ITEM* clipItem = pi.Parse();
  514. if( !clipItem )
  515. return 0;
  516. if( clipItem->Type() == PCB_T )
  517. static_cast<BOARD*>( clipItem )->ClearAllNetCodes();
  518. bool editModules = m_editModules || frame()->IsType( FRAME_PCB_MODULE_EDITOR );
  519. // The clipboard can contain two different things, an entire kicad_pcb
  520. // or a single module
  521. if( editModules && ( !board() || !module() ) )
  522. {
  523. wxLogDebug( wxT( "Attempting to paste to empty module editor window\n") );
  524. return 0;
  525. }
  526. switch( clipItem->Type() )
  527. {
  528. case PCB_T:
  529. {
  530. if( editModules )
  531. {
  532. wxLogDebug( wxT( "attempting to paste a pcb in the footprint editor\n") );
  533. return 0;
  534. }
  535. placeBoardItems( static_cast<BOARD*>( clipItem ) );
  536. break;
  537. }
  538. case PCB_MODULE_T:
  539. {
  540. std::vector<BOARD_ITEM*> items;
  541. clipItem->SetParent( board() );
  542. if( editModules )
  543. {
  544. auto oldModule = static_cast<MODULE*>( clipItem );
  545. auto newModule = board()->m_Modules.GetFirst();
  546. for( D_PAD* pad = oldModule->PadsList(), *next = nullptr; pad; pad = next )
  547. {
  548. next = pad->Next();
  549. oldModule->Remove( pad );
  550. pad->SetParent( newModule );
  551. items.push_back( pad );
  552. }
  553. for( BOARD_ITEM* item = oldModule->GraphicalItemsList(), *next = nullptr;
  554. item; item = next )
  555. {
  556. next = item->Next();
  557. oldModule->Remove( item );
  558. item->SetParent( newModule );
  559. items.push_back( item );
  560. }
  561. }
  562. else
  563. {
  564. items.push_back( clipItem );
  565. }
  566. placeBoardItems( items, true );
  567. break;
  568. }
  569. default:
  570. m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
  571. break;
  572. }
  573. return 1;
  574. }
  575. int PCBNEW_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent )
  576. {
  577. int open_ctl;
  578. wxString fileName;
  579. PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
  580. if( !editFrame )
  581. return 1;
  582. // Pick a file to append
  583. if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) )
  584. return 1;
  585. IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl );
  586. PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
  587. return AppendBoard( *pi, fileName );
  588. }
  589. // Helper function for PCBNEW_CONTROL::placeBoardItems()
  590. template<typename T>
  591. static void moveNoFlagToVector( DLIST<T>& aList, std::vector<BOARD_ITEM*>& aTarget, bool aIsNew )
  592. {
  593. for( auto obj = aIsNew ? aList.PopFront() : aList.GetFirst(); obj;
  594. obj = aIsNew ? aList.PopFront() : obj->Next() )
  595. {
  596. if( obj->GetFlags() & FLAG0 )
  597. obj->ClearFlags( FLAG0 );
  598. else
  599. aTarget.push_back( obj );
  600. }
  601. }
  602. static void moveNoFlagToVector( ZONE_CONTAINERS& aList, std::vector<BOARD_ITEM*>& aTarget, bool aIsNew )
  603. {
  604. if( aList.size() == 0 )
  605. return;
  606. auto obj = aList.front();
  607. int idx = 0;
  608. if( aIsNew )
  609. {
  610. obj = aList.back();
  611. aList.pop_back();
  612. }
  613. for( ; obj ; )
  614. {
  615. if( obj->GetFlags() & FLAG0 )
  616. obj->ClearFlags( FLAG0 );
  617. else
  618. aTarget.push_back( obj );
  619. if( aIsNew )
  620. {
  621. if( aList.size() )
  622. {
  623. obj = aList.back();
  624. aList.pop_back();
  625. }
  626. else
  627. obj = nullptr;
  628. }
  629. else
  630. obj = idx < int(aList.size()-1) ? aList[++idx] : nullptr;
  631. }
  632. }
  633. int PCBNEW_CONTROL::placeBoardItems( BOARD* aBoard )
  634. {
  635. // items are new if the current board is not the board source
  636. bool isNew = board() != aBoard;
  637. std::vector<BOARD_ITEM*> items;
  638. moveNoFlagToVector( aBoard->m_Track, items, isNew );
  639. moveNoFlagToVector( aBoard->m_Modules, items, isNew );
  640. moveNoFlagToVector( aBoard->DrawingsList(), items, isNew );
  641. moveNoFlagToVector( aBoard->Zones(), items, isNew );
  642. return placeBoardItems( items, isNew );
  643. }
  644. int PCBNEW_CONTROL::placeBoardItems( std::vector<BOARD_ITEM*>& aItems, bool aIsNew )
  645. {
  646. m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
  647. auto selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  648. auto editTool = m_toolMgr->GetTool<EDIT_TOOL>();
  649. SELECTION& selection = selectionTool->GetSelection();
  650. for( auto item : aItems )
  651. {
  652. item->SetSelected();
  653. selection.Add( item );
  654. // Add or just select items for the move/place command
  655. if( aIsNew )
  656. editTool->GetCurrentCommit()->Add( item );
  657. else
  658. editTool->GetCurrentCommit()->Added( item );
  659. }
  660. selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
  661. m_toolMgr->ProcessEvent( SELECTION_TOOL::SelectedEvent );
  662. m_toolMgr->RunAction( PCB_ACTIONS::move, true );
  663. return 0;
  664. }
  665. int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
  666. {
  667. PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
  668. if( !editFrame )
  669. return 1;
  670. BOARD* brd = board();
  671. if( !brd )
  672. return 1;
  673. // Mark existing items, in order to know what are the new items
  674. // to be ble to select only the new items after loadind
  675. for( auto track : brd->Tracks() )
  676. {
  677. track->SetFlags( FLAG0 );
  678. }
  679. for( auto module : brd->Modules() )
  680. {
  681. module->SetFlags( FLAG0 );
  682. }
  683. for( auto drawing : brd->Drawings() )
  684. {
  685. drawing->SetFlags( FLAG0 );
  686. }
  687. for( auto zone : brd->Zones() )
  688. {
  689. zone->SetFlags( FLAG0 );
  690. }
  691. // Keep also the count of copper layers, to adjust if necessary
  692. int initialCopperLayerCount = brd->GetCopperLayerCount();
  693. LSET initialEnabledLayers = brd->GetEnabledLayers();
  694. // Load the data
  695. try
  696. {
  697. PROPERTIES props;
  698. char xbuf[30];
  699. char ybuf[30];
  700. // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
  701. sprintf( xbuf, "%d", editFrame->GetPageSizeIU().x );
  702. sprintf( ybuf, "%d", editFrame->GetPageSizeIU().y );
  703. props["page_width"] = xbuf;
  704. props["page_height"] = ybuf;
  705. editFrame->GetDesignSettings().m_NetClasses.Clear();
  706. pi.Load( fileName, brd, &props );
  707. }
  708. catch( const IO_ERROR& ioe )
  709. {
  710. wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.What() ));
  711. DisplayError( editFrame, msg );
  712. return 0;
  713. }
  714. // rebuild nets and ratsnest before any use of nets
  715. brd->BuildListOfNets();
  716. brd->SynchronizeNetsAndNetClasses();
  717. brd->BuildConnectivity();
  718. // Synchronize layers
  719. // we should not ask PLUGINs to do these items:
  720. int copperLayerCount = brd->GetCopperLayerCount();
  721. if( copperLayerCount > initialCopperLayerCount )
  722. brd->SetCopperLayerCount( copperLayerCount );
  723. // Enable all used layers, and make them visible:
  724. LSET enabledLayers = brd->GetEnabledLayers();
  725. enabledLayers |= initialEnabledLayers;
  726. brd->SetEnabledLayers( enabledLayers );
  727. brd->SetVisibleLayers( enabledLayers );
  728. return placeBoardItems( brd );
  729. }
  730. int PCBNEW_CONTROL::ShowHelp( const TOOL_EVENT& aEvent )
  731. {
  732. DisplayHotkeyList( m_frame, m_frame->GetHotkeyConfig() );
  733. return 0;
  734. }
  735. int PCBNEW_CONTROL::ToBeDone( const TOOL_EVENT& aEvent )
  736. {
  737. DisplayInfoMessage( m_frame, _( "Not available in OpenGL/Cairo canvases." ) );
  738. return 0;
  739. }
  740. void PCBNEW_CONTROL::setTransitions()
  741. {
  742. // Display modes
  743. Go( &PCBNEW_CONTROL::TrackDisplayMode, PCB_ACTIONS::trackDisplayMode.MakeEvent() );
  744. Go( &PCBNEW_CONTROL::PadDisplayMode, PCB_ACTIONS::padDisplayMode.MakeEvent() );
  745. Go( &PCBNEW_CONTROL::ViaDisplayMode, PCB_ACTIONS::viaDisplayMode.MakeEvent() );
  746. Go( &PCBNEW_CONTROL::GraphicDisplayMode, PCB_ACTIONS::graphicDisplayMode.MakeEvent() );
  747. Go( &PCBNEW_CONTROL::ModuleEdgeOutlines, PCB_ACTIONS::moduleEdgeOutlines.MakeEvent() );
  748. Go( &PCBNEW_CONTROL::ModuleTextOutlines, PCB_ACTIONS::moduleTextOutlines.MakeEvent() );
  749. Go( &PCBNEW_CONTROL::ZoneDisplayMode, PCB_ACTIONS::zoneDisplayEnable.MakeEvent() );
  750. Go( &PCBNEW_CONTROL::ZoneDisplayMode, PCB_ACTIONS::zoneDisplayDisable.MakeEvent() );
  751. Go( &PCBNEW_CONTROL::ZoneDisplayMode, PCB_ACTIONS::zoneDisplayOutlines.MakeEvent() );
  752. Go( &PCBNEW_CONTROL::HighContrastMode, PCB_ACTIONS::highContrastMode.MakeEvent() );
  753. Go( &PCBNEW_CONTROL::HighContrastInc, PCB_ACTIONS::highContrastInc.MakeEvent() );
  754. Go( &PCBNEW_CONTROL::HighContrastDec, PCB_ACTIONS::highContrastDec.MakeEvent() );
  755. // Layer control
  756. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerTop.MakeEvent() );
  757. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner1.MakeEvent() );
  758. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner2.MakeEvent() );
  759. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner3.MakeEvent() );
  760. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner4.MakeEvent() );
  761. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner5.MakeEvent() );
  762. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerInner6.MakeEvent() );
  763. Go( &PCBNEW_CONTROL::LayerSwitch, PCB_ACTIONS::layerBottom.MakeEvent() );
  764. Go( &PCBNEW_CONTROL::LayerNext, PCB_ACTIONS::layerNext.MakeEvent() );
  765. Go( &PCBNEW_CONTROL::LayerPrev, PCB_ACTIONS::layerPrev.MakeEvent() );
  766. Go( &PCBNEW_CONTROL::LayerToggle, PCB_ACTIONS::layerToggle.MakeEvent() );
  767. Go( &PCBNEW_CONTROL::LayerAlphaInc, PCB_ACTIONS::layerAlphaInc.MakeEvent() );
  768. Go( &PCBNEW_CONTROL::LayerAlphaDec, PCB_ACTIONS::layerAlphaDec.MakeEvent() );
  769. // Grid control
  770. Go( &PCBNEW_CONTROL::GridFast1, ACTIONS::gridFast1.MakeEvent() );
  771. Go( &PCBNEW_CONTROL::GridFast2, ACTIONS::gridFast2.MakeEvent() );
  772. Go( &PCBNEW_CONTROL::GridSetOrigin, ACTIONS::gridSetOrigin.MakeEvent() );
  773. Go( &PCBNEW_CONTROL::GridResetOrigin, ACTIONS::gridResetOrigin.MakeEvent() );
  774. // Miscellaneous
  775. Go( &PCBNEW_CONTROL::ResetCoords, PCB_ACTIONS::resetCoords.MakeEvent() );
  776. Go( &PCBNEW_CONTROL::SwitchCursor, PCB_ACTIONS::switchCursor.MakeEvent() );
  777. Go( &PCBNEW_CONTROL::SwitchUnits, PCB_ACTIONS::switchUnits.MakeEvent() );
  778. Go( &PCBNEW_CONTROL::DeleteItemCursor, PCB_ACTIONS::deleteItemCursor.MakeEvent() );
  779. Go( &PCBNEW_CONTROL::ShowHelp, PCB_ACTIONS::showHelp.MakeEvent() );
  780. Go( &PCBNEW_CONTROL::ToBeDone, PCB_ACTIONS::toBeDone.MakeEvent() );
  781. // Append control
  782. Go( &PCBNEW_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() );
  783. Go( &PCBNEW_CONTROL::PasteItemsFromClipboard, PCB_ACTIONS::pasteFromClipboard.MakeEvent() );
  784. }
  785. void PCBNEW_CONTROL::updateGrid()
  786. {
  787. BASE_SCREEN* screen = m_frame->GetScreen();
  788. //GRID_TYPE grid = screen->GetGrid( idx );
  789. getView()->GetGAL()->SetGridSize( VECTOR2D( screen->GetGridSize() ) );
  790. getView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
  791. }