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.

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