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.

558 lines
16 KiB

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