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.

536 lines
15 KiB

16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
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) 2012 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-2012 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 <wxPcbStruct.h>
  34. #include <trigo.h>
  35. #include <macros.h>
  36. #include <pcbcommon.h>
  37. #include <class_board.h>
  38. #include <class_module.h>
  39. #include <pcbnew.h>
  40. #include <protos.h>
  41. #include <drag.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. /* Get a module name from user and return a pointer to the corresponding module
  53. */
  54. MODULE* PCB_BASE_FRAME::GetModuleByName()
  55. {
  56. wxString moduleName;
  57. MODULE* module = NULL;
  58. wxTextEntryDialog dlg( this, _( "Name:" ), _( "Search footprint" ), moduleName );
  59. if( dlg.ShowModal() != wxID_OK )
  60. return NULL; //Aborted by user
  61. moduleName = dlg.GetValue();
  62. moduleName.Trim( true );
  63. moduleName.Trim( false );
  64. if( !moduleName.IsEmpty() )
  65. {
  66. module = GetBoard()->m_Modules;
  67. while( module )
  68. {
  69. if( module->m_Reference->m_Text.CmpNoCase( moduleName ) == 0 )
  70. break;
  71. module = module->Next();
  72. }
  73. }
  74. return module;
  75. }
  76. void PCB_EDIT_FRAME::StartMove_Module( MODULE* module, wxDC* DC )
  77. {
  78. if( module == NULL )
  79. return;
  80. if( s_ModuleInitialCopy )
  81. delete s_ModuleInitialCopy;
  82. s_PickedList.ClearItemsList(); // Should be empty, but...
  83. // Creates a copy of the current module, for abort and undo commands
  84. s_ModuleInitialCopy = (MODULE*)module->Clone();
  85. s_ModuleInitialCopy->SetParent( GetBoard() );
  86. s_ModuleInitialCopy->ClearFlags();
  87. SetCurItem( module );
  88. GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
  89. module->SetFlags( IS_MOVED );
  90. /* Show ratsnest. */
  91. if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  92. DrawGeneralRatsnest( DC );
  93. EraseDragList();
  94. if( g_Drag_Pistes_On )
  95. {
  96. Build_Drag_Liste( m_canvas, DC, module );
  97. ITEM_PICKER itemWrapper( NULL, UR_CHANGED );
  98. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  99. {
  100. TRACK* segm = g_DragSegmentList[ii].m_Segm;
  101. itemWrapper.SetItem( segm );
  102. itemWrapper.SetLink( segm->Clone() );
  103. itemWrapper.GetLink()->SetState( IN_EDIT, OFF );
  104. s_PickedList.PushItem( itemWrapper );
  105. }
  106. }
  107. GetBoard()->m_Status_Pcb |= DO_NOT_SHOW_GENERAL_RASTNEST;
  108. m_canvas->SetMouseCapture( MoveFootprint, Abort_MoveOrCopyModule );
  109. m_canvas->SetAutoPanRequest( true );
  110. // Erase the module.
  111. if( DC )
  112. {
  113. module->SetFlags( DO_NOT_DRAW );
  114. m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
  115. module->ClearFlags( DO_NOT_DRAW );
  116. }
  117. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  118. }
  119. /* Called on a move or copy module command abort
  120. */
  121. void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC )
  122. {
  123. TRACK* pt_segm;
  124. MODULE* module;
  125. PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
  126. module = (MODULE*) pcbframe->GetScreen()->GetCurItem();
  127. pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
  128. Panel->SetMouseCapture( NULL, NULL );
  129. if( module )
  130. {
  131. // Erase the current footprint on screen
  132. DrawModuleOutlines( Panel, DC, module );
  133. /* If a move command: return to old position
  134. * If a copy command, delete the new footprint
  135. */
  136. if( module->IsMoving() )
  137. {
  138. if( g_Drag_Pistes_On )
  139. {
  140. /* Erase on screen dragged tracks */
  141. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  142. {
  143. pt_segm = g_DragSegmentList[ii].m_Segm;
  144. pt_segm->Draw( Panel, DC, GR_XOR );
  145. }
  146. }
  147. /* Go to old position for dragged tracks */
  148. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  149. {
  150. pt_segm = g_DragSegmentList[ii].m_Segm;
  151. pt_segm->SetState( IN_EDIT, OFF );
  152. g_DragSegmentList[ii].SetInitialValues();
  153. pt_segm->Draw( Panel, DC, GR_OR );
  154. }
  155. EraseDragList();
  156. module->ClearFlags( IS_MOVED );
  157. }
  158. if( module->IsNew() ) // Copy command: delete new footprint
  159. {
  160. module->DeleteStructure();
  161. module = NULL;
  162. pcbframe->GetBoard()->m_Status_Pcb = 0;
  163. pcbframe->GetBoard()->BuildListOfNets();
  164. }
  165. }
  166. /* Redraw the module. */
  167. if( module && s_ModuleInitialCopy )
  168. {
  169. if( s_ModuleInitialCopy->m_Orient != module->m_Orient )
  170. pcbframe->Rotate_Module( NULL, module, s_ModuleInitialCopy->m_Orient, false );
  171. if( s_ModuleInitialCopy->GetLayer() != module->GetLayer() )
  172. pcbframe->Change_Side_Module( module, NULL );
  173. module->Draw( Panel, DC, GR_OR );
  174. }
  175. g_Drag_Pistes_On = false;
  176. pcbframe->SetCurItem( NULL );
  177. delete s_ModuleInitialCopy;
  178. s_ModuleInitialCopy = NULL;
  179. s_PickedList.ClearListAndDeleteItems();
  180. // Display ratsnest is allowed
  181. pcbframe->GetBoard()->m_Status_Pcb &= ~DO_NOT_SHOW_GENERAL_RASTNEST;
  182. if( pcbframe->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  183. pcbframe->DrawGeneralRatsnest( DC );
  184. #ifdef __WXMAC__
  185. Panel->Refresh();
  186. #endif
  187. }
  188. /* Redraw the footprint when moving the mouse.
  189. */
  190. void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
  191. {
  192. MODULE* module = (MODULE*) aPanel->GetScreen()->GetCurItem();
  193. if( module == NULL )
  194. return;
  195. /* Erase current footprint. */
  196. if( aErase )
  197. {
  198. DrawModuleOutlines( aPanel, aDC, module );
  199. }
  200. /* Redraw the module at the new position. */
  201. g_Offset_Module = module->m_Pos - aPanel->GetScreen()->GetCrossHairPosition();
  202. DrawModuleOutlines( aPanel, aDC, module );
  203. DrawSegmentWhileMovingFootprint( aPanel, aDC );
  204. }
  205. bool PCB_EDIT_FRAME::Delete_Module( MODULE* aModule, wxDC* aDC, bool aAskBeforeDeleting )
  206. {
  207. wxString msg;
  208. if( aModule == NULL )
  209. return false;
  210. aModule->DisplayInfo( this );
  211. /* Confirm module delete. */
  212. if( aAskBeforeDeleting )
  213. {
  214. msg.Printf( _( "Delete Module %s (value %s) ?" ),
  215. GetChars( aModule->m_Reference->m_Text ),
  216. GetChars( aModule->m_Value->m_Text ) );
  217. if( !IsOK( this, msg ) )
  218. {
  219. return false;
  220. }
  221. }
  222. OnModify();
  223. /* Remove module from list, and put it in undo command list */
  224. m_Pcb->m_Modules.Remove( aModule );
  225. aModule->SetState( IS_DELETED, ON );
  226. SaveCopyInUndoList( aModule, UR_DELETED );
  227. if( aDC && GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  228. Compile_Ratsnest( aDC, true );
  229. // Redraw the full screen to ensure perfect display of board and ratsnest.
  230. if( aDC )
  231. m_canvas->Refresh();
  232. return true;
  233. }
  234. void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
  235. {
  236. if( Module == NULL )
  237. return;
  238. if( ( Module->GetLayer() != LAYER_N_FRONT ) && ( Module->GetLayer() != LAYER_N_BACK ) )
  239. return;
  240. OnModify();
  241. if( !Module->IsMoving() ) /* This is a simple flip, no other edition in progress */
  242. {
  243. GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
  244. if( DC )
  245. {
  246. Module->SetFlags( DO_NOT_DRAW );
  247. m_canvas->RefreshDrawingRect( Module->GetBoundingBox() );
  248. Module->ClearFlags( DO_NOT_DRAW );
  249. }
  250. /* Show ratsnest if necessary. */
  251. if( DC && GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  252. DrawGeneralRatsnest( DC );
  253. g_Offset_Module.x = 0;
  254. g_Offset_Module.y = 0;
  255. }
  256. else // Module is being moved.
  257. {
  258. /* Erase footprint and draw outline if it has been already drawn. */
  259. if( DC )
  260. {
  261. DrawModuleOutlines( m_canvas, DC, Module );
  262. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  263. }
  264. }
  265. /* Flip the module */
  266. Module->Flip( Module->m_Pos );
  267. Module->DisplayInfo( this );
  268. if( !Module->IsMoving() ) /* Inversion simple */
  269. {
  270. if( DC )
  271. {
  272. Module->Draw( m_canvas, DC, GR_OR );
  273. if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  274. Compile_Ratsnest( DC, true );
  275. }
  276. }
  277. else
  278. {
  279. if( DC )
  280. {
  281. DrawModuleOutlines( m_canvas, DC, Module );
  282. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  283. }
  284. GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
  285. }
  286. }
  287. void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreateRatsnest )
  288. {
  289. TRACK* pt_segm;
  290. wxPoint newpos;
  291. if( aModule == 0 )
  292. return;
  293. OnModify();
  294. GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
  295. if( aModule->IsNew() )
  296. {
  297. SaveCopyInUndoList( aModule, UR_NEW );
  298. }
  299. else if( aModule->IsMoving() )
  300. {
  301. ITEM_PICKER picker( aModule, UR_CHANGED );
  302. picker.SetLink( s_ModuleInitialCopy );
  303. s_PickedList.PushItem( picker );
  304. s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy.
  305. }
  306. if( s_PickedList.GetCount() )
  307. {
  308. SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
  309. // Clear list, but DO NOT delete items, because they are owned by the saved undo
  310. // list and they therefore in use
  311. s_PickedList.ClearItemsList();
  312. }
  313. if( g_Show_Module_Ratsnest && ( GetBoard()->m_Status_Pcb & LISTE_PAD_OK ) && aDC )
  314. TraceModuleRatsNest( aDC );
  315. newpos = GetScreen()->GetCrossHairPosition();
  316. aModule->SetPosition( newpos );
  317. aModule->ClearFlags();
  318. delete s_ModuleInitialCopy;
  319. s_ModuleInitialCopy = NULL;
  320. if( aDC )
  321. aModule->Draw( m_canvas, aDC, GR_OR );
  322. if( g_DragSegmentList.size() )
  323. {
  324. /* Redraw dragged track segments */
  325. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  326. {
  327. pt_segm = g_DragSegmentList[ii].m_Segm;
  328. pt_segm->SetState( IN_EDIT, OFF );
  329. if( aDC )
  330. pt_segm->Draw( m_canvas, aDC, GR_OR );
  331. }
  332. // Delete drag list
  333. EraseDragList();
  334. }
  335. g_Drag_Pistes_On = false;
  336. m_canvas->SetMouseCapture( NULL, NULL );
  337. if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) && !aDoNotRecreateRatsnest )
  338. Compile_Ratsnest( aDC, true );
  339. if( aDC )
  340. m_canvas->Refresh();
  341. aModule->DisplayInfo( this );
  342. }
  343. /*
  344. * Rotate the footprint angle degrees in the direction < 0.
  345. * If incremental == true, the rotation is made from the last orientation,
  346. * If the module is placed in the absolute orientation angle.
  347. * If DC == NULL, the component does not redraw.
  348. * Otherwise, it erases and redraws turns
  349. */
  350. void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, int angle, bool incremental )
  351. {
  352. if( module == NULL )
  353. return;
  354. OnModify();
  355. if( !module->IsMoving() ) /* This is a simple rotation, no other
  356. * edition in progress */
  357. {
  358. if( DC ) // Erase footprint to screen
  359. {
  360. module->SetFlags( DO_NOT_DRAW );
  361. m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
  362. module->ClearFlags( DO_NOT_DRAW );
  363. if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  364. DrawGeneralRatsnest( DC );
  365. }
  366. }
  367. else
  368. {
  369. if( DC )
  370. {
  371. DrawModuleOutlines( m_canvas, DC, module );
  372. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  373. }
  374. }
  375. GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
  376. if( incremental )
  377. module->SetOrientation( module->m_Orient + angle );
  378. else
  379. module->SetOrientation( angle );
  380. module->DisplayInfo( this );
  381. if( DC )
  382. {
  383. if( !module->IsMoving() )
  384. {
  385. // not beiing moved: redraw the module and update ratsnest
  386. module->Draw( m_canvas, DC, GR_OR );
  387. if( GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  388. Compile_Ratsnest( DC, true );
  389. }
  390. else
  391. {
  392. // Beiing moved: just redraw it
  393. DrawModuleOutlines( m_canvas, DC, module );
  394. DrawSegmentWhileMovingFootprint( m_canvas, DC );
  395. }
  396. if( module->GetFlags() == 0 ) // module not in edit: redraw full screen
  397. m_canvas->Refresh();
  398. }
  399. }
  400. /*************************************************/
  401. /* Redraw in XOR mode the outlines of a module. */
  402. /*************************************************/
  403. void DrawModuleOutlines( EDA_DRAW_PANEL* panel, wxDC* DC, MODULE* module )
  404. {
  405. int pad_fill_tmp;
  406. D_PAD* pt_pad;
  407. if( module == NULL )
  408. return;
  409. module->DrawEdgesOnly( panel, DC, g_Offset_Module, GR_XOR );
  410. // Show pads in sketch mode to speedu up drawings
  411. pad_fill_tmp = DisplayOpt.DisplayPadFill;
  412. DisplayOpt.DisplayPadFill = true;
  413. pt_pad = module->m_Pads;
  414. for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
  415. pt_pad->Draw( panel, DC, GR_XOR, g_Offset_Module );
  416. DisplayOpt.DisplayPadFill = pad_fill_tmp;
  417. if( g_Show_Module_Ratsnest && panel )
  418. {
  419. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
  420. frame->build_ratsnest_module( module );
  421. frame->TraceModuleRatsNest( DC );
  422. }
  423. }