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.

492 lines
14 KiB

16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. /**
  27. * @file modules.cpp
  28. */
  29. #include <fctsys.h>
  30. #include <gr_basic.h>
  31. #include <class_drawpanel.h>
  32. #include <confirm.h>
  33. #include <pcb_edit_frame.h>
  34. #include <trigo.h>
  35. #include <macros.h>
  36. #include <class_board.h>
  37. #include <class_module.h>
  38. #include <pcbnew.h>
  39. #include <drag.h>
  40. #include <dialog_get_footprint_by_name.h>
  41. #include <connectivity_data.h>
  42. static void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  43. const wxPoint& aPosition, bool aErase );
  44. static void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC );
  45. static MODULE* s_ModuleInitialCopy = NULL; /* Copy of module for
  46. * abort/undo command
  47. */
  48. static PICKED_ITEMS_LIST s_PickedList; /* a picked list to
  49. * save initial module
  50. * and dragged tracks
  51. */
  52. MODULE* PCB_BASE_FRAME::GetFootprintFromBoardByReference()
  53. {
  54. wxString moduleName;
  55. MODULE* module = NULL;
  56. wxArrayString fplist;
  57. // Build list of available fp references, to display them in dialog
  58. for( MODULE* fp = GetBoard()->m_Modules; fp; fp = fp->Next() )
  59. fplist.Add( fp->GetReference() + wxT(" ( ") + fp->GetValue() + wxT(" )") );
  60. fplist.Sort();
  61. DIALOG_GET_FOOTPRINT_BY_NAME dlg( this, fplist );
  62. if( dlg.ShowModal() != wxID_OK ) //Aborted by user
  63. return NULL;
  64. moduleName = dlg.GetValue();
  65. moduleName.Trim( true );
  66. moduleName.Trim( false );
  67. if( !moduleName.IsEmpty() )
  68. {
  69. module = GetBoard()->m_Modules;
  70. while( module )
  71. {
  72. if( module->GetReference().CmpNoCase( moduleName ) == 0 )
  73. break;
  74. module = module->Next();
  75. }
  76. }
  77. return module;
  78. }
  79. void PCB_EDIT_FRAME::StartMoveModule( MODULE* aModule, wxDC* aDC,
  80. bool aDragConnectedTracks )
  81. {
  82. if( aModule == NULL )
  83. return;
  84. if( s_ModuleInitialCopy )
  85. delete s_ModuleInitialCopy;
  86. s_PickedList.ClearItemsList(); // Should be empty, but...
  87. // Creates a copy of the current module, for abort and undo commands
  88. s_ModuleInitialCopy = (MODULE*)aModule->Clone();
  89. s_ModuleInitialCopy->SetParent( GetBoard() );
  90. s_ModuleInitialCopy->ClearFlags();
  91. SetCurItem( aModule );
  92. GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
  93. aModule->SetFlags( IS_MOVED );
  94. /* Show ratsnest. */
  95. if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  96. DrawGeneralRatsnest( aDC );
  97. EraseDragList();
  98. if( aDragConnectedTracks )
  99. {
  100. DRAG_LIST drglist( GetBoard() );
  101. drglist.BuildDragListe( aModule );
  102. ITEM_PICKER itemWrapper( NULL, UR_CHANGED );
  103. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  104. {
  105. TRACK* segm = g_DragSegmentList[ii].m_Track;
  106. itemWrapper.SetItem( segm );
  107. itemWrapper.SetLink( segm->Clone() );
  108. itemWrapper.GetLink()->SetState( IN_EDIT, false );
  109. s_PickedList.PushItem( itemWrapper );
  110. }
  111. UndrawAndMarkSegmentsToDrag( m_canvas, aDC );
  112. }
  113. GetBoard()->m_Status_Pcb |= DO_NOT_SHOW_GENERAL_RASTNEST;
  114. m_canvas->SetMouseCapture( MoveFootprint, Abort_MoveOrCopyModule );
  115. m_canvas->SetAutoPanRequest( true );
  116. // Erase the module.
  117. if( aDC )
  118. {
  119. aModule->SetFlags( DO_NOT_DRAW );
  120. m_canvas->RefreshDrawingRect( aModule->GetBoundingBox() );
  121. aModule->ClearFlags( DO_NOT_DRAW );
  122. }
  123. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  124. }
  125. /* Called on a move or copy module command abort
  126. */
  127. void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC )
  128. {
  129. TRACK* pt_segm;
  130. MODULE* module;
  131. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
  132. module = (MODULE*) pcbframe->GetScreen()->GetCurItem();
  133. pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
  134. Panel->SetMouseCapture( NULL, NULL );
  135. if( module )
  136. {
  137. // Erase the current footprint on screen
  138. module->DrawOutlinesWhenMoving( Panel, DC, g_Offset_Module );
  139. /* If a move command: return to old position
  140. * If a copy command, delete the new footprint
  141. */
  142. if( module->IsMoving() )
  143. {
  144. /* Restore old position for dragged tracks */
  145. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  146. {
  147. pt_segm = g_DragSegmentList[ii].m_Track;
  148. pt_segm->Draw( Panel, DC, GR_XOR );
  149. pt_segm->SetState( IN_EDIT, false );
  150. pt_segm->ClearFlags();
  151. g_DragSegmentList[ii].RestoreInitialValues();
  152. pt_segm->Draw( Panel, DC, GR_OR );
  153. }
  154. EraseDragList();
  155. module->ClearFlags( IS_MOVED );
  156. }
  157. if( module->IsNew() ) // Copy command: delete new footprint
  158. {
  159. module->DeleteStructure();
  160. module = NULL;
  161. pcbframe->GetBoard()->m_Status_Pcb = 0;
  162. pcbframe->GetBoard()->BuildListOfNets();
  163. }
  164. }
  165. /* Redraw the module. */
  166. if( module && s_ModuleInitialCopy )
  167. {
  168. if( s_ModuleInitialCopy->GetOrientation() != module->GetOrientation() )
  169. pcbframe->Rotate_Module( NULL, module, s_ModuleInitialCopy->GetOrientation(), false );
  170. if( s_ModuleInitialCopy->GetLayer() != module->GetLayer() )
  171. pcbframe->Change_Side_Module( module, NULL );
  172. module->Draw( Panel, DC, GR_OR );
  173. }
  174. pcbframe->SetCurItem( NULL );
  175. delete s_ModuleInitialCopy;
  176. s_ModuleInitialCopy = NULL;
  177. s_PickedList.ClearListAndDeleteItems();
  178. // Display ratsnest is allowed
  179. pcbframe->GetBoard()->m_Status_Pcb &= ~DO_NOT_SHOW_GENERAL_RASTNEST;
  180. if( pcbframe->GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  181. pcbframe->DrawGeneralRatsnest( DC );
  182. #ifdef __WXMAC__
  183. Panel->Refresh();
  184. #endif
  185. }
  186. /* Redraw the footprint when moving the mouse.
  187. */
  188. void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
  189. {
  190. MODULE* module = (MODULE*) aPanel->GetScreen()->GetCurItem();
  191. if( module == NULL )
  192. return;
  193. /* Erase current footprint. */
  194. if( aErase )
  195. {
  196. module->DrawOutlinesWhenMoving( aPanel, aDC, g_Offset_Module );
  197. }
  198. /* Redraw the module at the new position. */
  199. g_Offset_Module = module->GetPosition() - aPanel->GetParent()->GetCrossHairPosition();
  200. module->DrawOutlinesWhenMoving( aPanel, aDC, g_Offset_Module );
  201. DrawSegmentWhileMovingFootprint( aPanel, aDC );
  202. }
  203. bool PCB_EDIT_FRAME::Delete_Module( MODULE* aModule, wxDC* aDC )
  204. {
  205. wxString msg;
  206. if( aModule == NULL )
  207. return false;
  208. SetMsgPanel( aModule );
  209. /* Remove module from list, and put it in undo command list */
  210. m_Pcb->Remove( aModule );
  211. aModule->SetState( IS_DELETED, true );
  212. SaveCopyInUndoList( aModule, UR_DELETED );
  213. if( aDC && GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  214. Compile_Ratsnest( aDC, true );
  215. // Redraw the full screen to ensure perfect display of board and ratsnest.
  216. if( aDC )
  217. m_canvas->Refresh();
  218. OnModify();
  219. return true;
  220. }
  221. void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
  222. {
  223. if( Module == NULL )
  224. return;
  225. if( ( Module->GetLayer() != F_Cu ) && ( Module->GetLayer() != B_Cu ) )
  226. return;
  227. OnModify();
  228. if( !Module->IsMoving() ) // This is a simple flip, no other edit in progress
  229. {
  230. if( DC )
  231. {
  232. Module->SetFlags( DO_NOT_DRAW );
  233. m_canvas->RefreshDrawingRect( Module->GetBoundingBox() );
  234. Module->ClearFlags( DO_NOT_DRAW );
  235. }
  236. /* Show ratsnest if necessary. */
  237. if( DC && GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  238. DrawGeneralRatsnest( DC );
  239. g_Offset_Module.x = 0;
  240. g_Offset_Module.y = 0;
  241. }
  242. else // Module is being moved.
  243. {
  244. /* Erase footprint and draw outline if it has been already drawn. */
  245. if( DC )
  246. {
  247. Module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module );
  248. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  249. }
  250. }
  251. /* Flip the module */
  252. Module->Flip( Module->GetPosition() );
  253. m_Pcb->GetConnectivity()->Update( Module );
  254. SetMsgPanel( Module );
  255. if( !Module->IsMoving() ) /* Inversion simple */
  256. {
  257. if( DC )
  258. {
  259. Module->Draw( m_canvas, DC, GR_OR );
  260. if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  261. Compile_Ratsnest( DC, true );
  262. }
  263. }
  264. else
  265. {
  266. if( DC )
  267. {
  268. Module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module );
  269. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  270. }
  271. }
  272. m_Pcb->GetConnectivity()->Update( Module );
  273. }
  274. void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aRecreateRatsnest )
  275. {
  276. wxPoint newpos;
  277. if( aModule == 0 )
  278. return;
  279. OnModify();
  280. if( aModule->IsNew() )
  281. {
  282. SaveCopyInUndoList( aModule, UR_NEW );
  283. }
  284. else if( aModule->IsMoving() )
  285. {
  286. ITEM_PICKER picker( aModule, UR_CHANGED );
  287. picker.SetLink( s_ModuleInitialCopy );
  288. s_PickedList.PushItem( picker );
  289. s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy.
  290. }
  291. if( s_PickedList.GetCount() )
  292. {
  293. SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
  294. // Clear list, but DO NOT delete items, because they are owned by the saved undo
  295. // list and they therefore in use
  296. s_PickedList.ClearItemsList();
  297. }
  298. auto displ_opts = (PCB_DISPLAY_OPTIONS*)GetDisplayOptions();
  299. if( displ_opts->m_Show_Module_Ratsnest && aDC )
  300. TraceModuleRatsNest( aDC );
  301. newpos = GetCrossHairPosition();
  302. aModule->SetPosition( newpos );
  303. aModule->ClearFlags();
  304. delete s_ModuleInitialCopy;
  305. s_ModuleInitialCopy = NULL;
  306. if( aDC )
  307. aModule->Draw( m_canvas, aDC, GR_OR );
  308. // Redraw dragged track segments, if any
  309. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  310. {
  311. TRACK * track = g_DragSegmentList[ii].m_Track;
  312. track->SetState( IN_EDIT, false );
  313. track->ClearFlags();
  314. if( aDC )
  315. track->Draw( m_canvas, aDC, GR_OR );
  316. }
  317. // Delete drag list
  318. EraseDragList();
  319. m_canvas->SetMouseCapture( NULL, NULL );
  320. if( aRecreateRatsnest )
  321. m_Pcb->GetConnectivity()->Update( aModule );
  322. if( ( GetBoard()->IsElementVisible( LAYER_RATSNEST ) || displ_opts->m_Show_Module_Ratsnest )
  323. && aRecreateRatsnest )
  324. Compile_Ratsnest( aDC, true );
  325. if( aDC )
  326. m_canvas->Refresh();
  327. SetMsgPanel( aModule );
  328. }
  329. /*
  330. * Rotate the footprint angle degrees in the direction < 0.
  331. * If incremental == true, the rotation is made from the last orientation,
  332. * If the module is placed in the absolute orientation angle.
  333. * If DC == NULL, the component does not redraw.
  334. * Otherwise, it erases and redraws turns
  335. */
  336. void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, double angle, bool incremental )
  337. {
  338. if( module == NULL )
  339. return;
  340. OnModify();
  341. if( !module->IsMoving() ) // This is a simple rotation, no other edit in progress
  342. {
  343. if( DC ) // Erase footprint to screen
  344. {
  345. module->SetFlags( DO_NOT_DRAW );
  346. m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
  347. module->ClearFlags( DO_NOT_DRAW );
  348. if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  349. DrawGeneralRatsnest( DC );
  350. }
  351. }
  352. else
  353. {
  354. if( DC )
  355. {
  356. module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module );
  357. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  358. }
  359. }
  360. if( incremental )
  361. module->SetOrientation( module->GetOrientation() + angle );
  362. else
  363. module->SetOrientation( angle );
  364. SetMsgPanel( module );
  365. m_Pcb->GetConnectivity()->Update( module );
  366. if( DC )
  367. {
  368. if( !module->IsMoving() )
  369. {
  370. // not beiing moved: redraw the module and update ratsnest
  371. module->Draw( m_canvas, DC, GR_OR );
  372. if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
  373. Compile_Ratsnest( DC, true );
  374. }
  375. else
  376. {
  377. // Beiing moved: just redraw it
  378. module->DrawOutlinesWhenMoving( m_canvas, DC, g_Offset_Module );
  379. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  380. }
  381. if( module->GetFlags() == 0 ) // module not in edit: redraw full screen
  382. m_canvas->Refresh();
  383. }
  384. }