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.

474 lines
14 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014 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 <boost/bind.hpp>
  25. #include "pcb_editor_control.h"
  26. #include "common_actions.h"
  27. #include <tool/tool_manager.h>
  28. #include "selection_tool.h"
  29. #include <project.h>
  30. #include <pcbnew_id.h>
  31. #include <wxPcbStruct.h>
  32. #include <class_board.h>
  33. #include <class_zone.h>
  34. #include <class_draw_panel_gal.h>
  35. #include <class_module.h>
  36. #include <class_mire.h>
  37. #include <view/view_group.h>
  38. #include <view/view_controls.h>
  39. class ZONE_CONTEXT_MENU : public CONTEXT_MENU
  40. {
  41. public:
  42. ZONE_CONTEXT_MENU()
  43. {
  44. SetIcon( add_zone_xpm );
  45. Add( COMMON_ACTIONS::zoneFill );
  46. Add( COMMON_ACTIONS::zoneFillAll );
  47. Add( COMMON_ACTIONS::zoneUnfill );
  48. Add( COMMON_ACTIONS::zoneUnfillAll );
  49. }
  50. };
  51. PCB_EDITOR_CONTROL::PCB_EDITOR_CONTROL() :
  52. TOOL_INTERACTIVE( "pcbnew.EditorControl" ), m_frame( NULL )
  53. {
  54. }
  55. void PCB_EDITOR_CONTROL::Reset( RESET_REASON aReason )
  56. {
  57. m_frame = getEditFrame<PCB_EDIT_FRAME>();
  58. }
  59. bool PCB_EDITOR_CONTROL::Init()
  60. {
  61. SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  62. if( selTool )
  63. {
  64. selTool->GetMenu().AddMenu( new ZONE_CONTEXT_MENU, _( "Zones" ), false,
  65. SELECTION_CONDITIONS::OnlyType( PCB_ZONE_AREA_T ) );
  66. }
  67. return true;
  68. }
  69. // Track & via size control
  70. int PCB_EDITOR_CONTROL::TrackWidthInc( const TOOL_EVENT& aEvent )
  71. {
  72. BOARD* board = getModel<BOARD>();
  73. int widthIndex = board->GetDesignSettings().GetTrackWidthIndex() + 1;
  74. if( widthIndex >= (int) board->GetDesignSettings().m_TrackWidthList.size() )
  75. widthIndex = board->GetDesignSettings().m_TrackWidthList.size() - 1;
  76. board->GetDesignSettings().SetTrackWidthIndex( widthIndex );
  77. board->GetDesignSettings().UseCustomTrackViaSize( false );
  78. wxUpdateUIEvent dummy;
  79. m_frame->OnUpdateSelectTrackWidth( dummy );
  80. m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged );
  81. return 0;
  82. }
  83. int PCB_EDITOR_CONTROL::TrackWidthDec( const TOOL_EVENT& aEvent )
  84. {
  85. BOARD* board = getModel<BOARD>();
  86. int widthIndex = board->GetDesignSettings().GetTrackWidthIndex() - 1;
  87. if( widthIndex < 0 )
  88. widthIndex = 0;
  89. board->GetDesignSettings().SetTrackWidthIndex( widthIndex );
  90. board->GetDesignSettings().UseCustomTrackViaSize( false );
  91. wxUpdateUIEvent dummy;
  92. m_frame->OnUpdateSelectTrackWidth( dummy );
  93. m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged );
  94. return 0;
  95. }
  96. int PCB_EDITOR_CONTROL::ViaSizeInc( const TOOL_EVENT& aEvent )
  97. {
  98. BOARD* board = getModel<BOARD>();
  99. int sizeIndex = board->GetDesignSettings().GetViaSizeIndex() + 1;
  100. if( sizeIndex >= (int) board->GetDesignSettings().m_ViasDimensionsList.size() )
  101. sizeIndex = board->GetDesignSettings().m_ViasDimensionsList.size() - 1;
  102. board->GetDesignSettings().SetViaSizeIndex( sizeIndex );
  103. board->GetDesignSettings().UseCustomTrackViaSize( false );
  104. wxUpdateUIEvent dummy;
  105. m_frame->OnUpdateSelectViaSize( dummy );
  106. m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged );
  107. return 0;
  108. }
  109. int PCB_EDITOR_CONTROL::ViaSizeDec( const TOOL_EVENT& aEvent )
  110. {
  111. BOARD* board = getModel<BOARD>();
  112. int sizeIndex = board->GetDesignSettings().GetViaSizeIndex() - 1;
  113. if( sizeIndex < 0 )
  114. sizeIndex = 0;
  115. board->GetDesignSettings().SetViaSizeIndex( sizeIndex );
  116. board->GetDesignSettings().UseCustomTrackViaSize( false );
  117. wxUpdateUIEvent dummy;
  118. m_frame->OnUpdateSelectViaSize( dummy );
  119. m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged );
  120. return 0;
  121. }
  122. int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent )
  123. {
  124. MODULE* module = NULL;
  125. KIGFX::VIEW* view = getView();
  126. KIGFX::VIEW_CONTROLS* controls = getViewControls();
  127. BOARD* board = getModel<BOARD>();
  128. // Add a VIEW_GROUP that serves as a preview for the new item
  129. KIGFX::VIEW_GROUP preview( view );
  130. view->Add( &preview );
  131. m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
  132. controls->ShowCursor( true );
  133. controls->SetSnapping( true );
  134. controls->SetAutoPan( true );
  135. controls->CaptureCursor( true );
  136. Activate();
  137. m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add module" ) );
  138. // Main loop: keep receiving events
  139. while( OPT_TOOL_EVENT evt = Wait() )
  140. {
  141. VECTOR2I cursorPos = controls->GetCursorPosition();
  142. if( evt->IsCancel() || evt->IsActivate() )
  143. {
  144. if( module )
  145. {
  146. board->Delete( module ); // it was added by LoadModuleFromLibrary()
  147. module = NULL;
  148. preview.Clear();
  149. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  150. controls->ShowCursor( true );
  151. }
  152. else
  153. break;
  154. if( evt->IsActivate() ) // now finish unconditionally
  155. break;
  156. }
  157. else if( module && evt->Category() == TC_COMMAND )
  158. {
  159. if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
  160. {
  161. module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() );
  162. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  163. }
  164. else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
  165. {
  166. module->Flip( module->GetPosition() );
  167. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  168. }
  169. }
  170. else if( evt->IsClick( BUT_LEFT ) )
  171. {
  172. if( !module )
  173. {
  174. // Init the new item attributes
  175. module = m_frame->LoadModuleFromLibrary( wxEmptyString,
  176. m_frame->Prj().PcbFootprintLibs(),
  177. true, NULL );
  178. if( module == NULL )
  179. continue;
  180. controls->ShowCursor( false );
  181. module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
  182. // Add all the drawable parts to preview
  183. preview.Add( module );
  184. module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) );
  185. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  186. }
  187. else
  188. {
  189. module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
  190. view->Add( module );
  191. module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  192. m_frame->OnModify();
  193. m_frame->SaveCopyInUndoList( module, UR_NEW );
  194. // Remove from preview
  195. preview.Remove( module );
  196. module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) );
  197. module = NULL; // to indicate that there is no module that we currently modify
  198. controls->ShowCursor( true );
  199. }
  200. }
  201. else if( module && evt->IsMotion() )
  202. {
  203. module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
  204. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  205. }
  206. }
  207. controls->ShowCursor( false );
  208. controls->SetSnapping( false );
  209. controls->SetAutoPan( false );
  210. controls->CaptureCursor( false );
  211. view->Remove( &preview );
  212. m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
  213. return 0;
  214. }
  215. int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent )
  216. {
  217. KIGFX::VIEW* view = getView();
  218. KIGFX::VIEW_CONTROLS* controls = getViewControls();
  219. BOARD* board = getModel<BOARD>();
  220. PCB_TARGET* target = new PCB_TARGET( board );
  221. // Init the new item attributes
  222. target->SetLayer( Edge_Cuts );
  223. target->SetWidth( board->GetDesignSettings().m_EdgeSegmentWidth );
  224. target->SetSize( Millimeter2iu( 5 ) );
  225. VECTOR2I cursorPos = controls->GetCursorPosition();
  226. target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
  227. // Add a VIEW_GROUP that serves as a preview for the new item
  228. KIGFX::VIEW_GROUP preview( view );
  229. preview.Add( target );
  230. view->Add( &preview );
  231. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  232. m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
  233. controls->SetSnapping( true );
  234. controls->SetAutoPan( true );
  235. controls->CaptureCursor( true );
  236. Activate();
  237. m_frame->SetToolID( ID_PCB_MIRE_BUTT, wxCURSOR_PENCIL, _( "Add layer alignment target" ) );
  238. // Main loop: keep receiving events
  239. while( OPT_TOOL_EVENT evt = Wait() )
  240. {
  241. cursorPos = controls->GetCursorPosition();
  242. if( evt->IsCancel() || evt->IsActivate() )
  243. break;
  244. else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) )
  245. {
  246. target->SetWidth( target->GetWidth() + WIDTH_STEP );
  247. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  248. }
  249. else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) )
  250. {
  251. int width = target->GetWidth();
  252. if( width > WIDTH_STEP )
  253. {
  254. target->SetWidth( width - WIDTH_STEP );
  255. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  256. }
  257. }
  258. else if( evt->IsClick( BUT_LEFT ) )
  259. {
  260. assert( target->GetSize() > 0 );
  261. assert( target->GetWidth() > 0 );
  262. view->Add( target );
  263. board->Add( target );
  264. target->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  265. m_frame->OnModify();
  266. m_frame->SaveCopyInUndoList( target, UR_NEW );
  267. preview.Remove( target );
  268. // Create next PCB_TARGET
  269. target = new PCB_TARGET( *target );
  270. preview.Add( target );
  271. }
  272. else if( evt->IsMotion() )
  273. {
  274. target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
  275. preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  276. }
  277. }
  278. delete target;
  279. controls->SetSnapping( false );
  280. controls->SetAutoPan( false );
  281. controls->CaptureCursor( false );
  282. view->Remove( &preview );
  283. m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
  284. return 0;
  285. }
  286. // Zone actions
  287. int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
  288. {
  289. SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  290. const SELECTION& selection = selTool->GetSelection();
  291. for( int i = 0; i < selection.Size(); ++i )
  292. {
  293. assert( selection.Item<BOARD_ITEM>( i )->Type() == PCB_ZONE_AREA_T );
  294. ZONE_CONTAINER* zone = selection.Item<ZONE_CONTAINER>( i );
  295. m_frame->Fill_Zone( zone );
  296. zone->SetIsFilled( true );
  297. zone->ViewUpdate();
  298. }
  299. return 0;
  300. }
  301. int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
  302. {
  303. BOARD* board = getModel<BOARD>();
  304. for( int i = 0; i < board->GetAreaCount(); ++i )
  305. {
  306. ZONE_CONTAINER* zone = board->GetArea( i );
  307. m_frame->Fill_Zone( zone );
  308. zone->SetIsFilled( true );
  309. zone->ViewUpdate();
  310. }
  311. return 0;
  312. }
  313. int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
  314. {
  315. SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  316. const SELECTION& selection = selTool->GetSelection();
  317. for( int i = 0; i < selection.Size(); ++i )
  318. {
  319. assert( selection.Item<BOARD_ITEM>( i )->Type() == PCB_ZONE_AREA_T );
  320. ZONE_CONTAINER* zone = selection.Item<ZONE_CONTAINER>( i );
  321. zone->SetIsFilled( false );
  322. zone->ClearFilledPolysList();
  323. zone->ViewUpdate();
  324. }
  325. return 0;
  326. }
  327. int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
  328. {
  329. BOARD* board = getModel<BOARD>();
  330. for( int i = 0; i < board->GetAreaCount(); ++i )
  331. {
  332. ZONE_CONTAINER* zone = board->GetArea( i );
  333. zone->SetIsFilled( false );
  334. zone->ClearFilledPolysList();
  335. zone->ViewUpdate();
  336. }
  337. return 0;
  338. }
  339. int PCB_EDITOR_CONTROL::SelectionCrossProbe( const TOOL_EVENT& aEvent )
  340. {
  341. SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  342. const SELECTION& selection = selTool->GetSelection();
  343. if( selection.Size() == 1 )
  344. m_frame->SendMessageToEESCHEMA( selection.Item<BOARD_ITEM>( 0 ) );
  345. return 0;
  346. }
  347. void PCB_EDITOR_CONTROL::SetTransitions()
  348. {
  349. // Track & via size control
  350. Go( &PCB_EDITOR_CONTROL::TrackWidthInc, COMMON_ACTIONS::trackWidthInc.MakeEvent() );
  351. Go( &PCB_EDITOR_CONTROL::TrackWidthDec, COMMON_ACTIONS::trackWidthDec.MakeEvent() );
  352. Go( &PCB_EDITOR_CONTROL::ViaSizeInc, COMMON_ACTIONS::viaSizeInc.MakeEvent() );
  353. Go( &PCB_EDITOR_CONTROL::ViaSizeDec, COMMON_ACTIONS::viaSizeDec.MakeEvent() );
  354. // Zone actions
  355. Go( &PCB_EDITOR_CONTROL::ZoneFill, COMMON_ACTIONS::zoneFill.MakeEvent() );
  356. Go( &PCB_EDITOR_CONTROL::ZoneFillAll, COMMON_ACTIONS::zoneFillAll.MakeEvent() );
  357. Go( &PCB_EDITOR_CONTROL::ZoneUnfill, COMMON_ACTIONS::zoneUnfill.MakeEvent() );
  358. Go( &PCB_EDITOR_CONTROL::ZoneUnfillAll, COMMON_ACTIONS::zoneUnfillAll.MakeEvent() );
  359. // Placing tools
  360. Go( &PCB_EDITOR_CONTROL::PlaceTarget, COMMON_ACTIONS::placeTarget.MakeEvent() );
  361. Go( &PCB_EDITOR_CONTROL::PlaceModule, COMMON_ACTIONS::placeModule.MakeEvent() );
  362. Go( &PCB_EDITOR_CONTROL::SelectionCrossProbe, SELECTION_TOOL::SelectedEvent );
  363. }
  364. const int PCB_EDITOR_CONTROL::WIDTH_STEP = 100000;