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.

338 lines
10 KiB

  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) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2018 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. #include <fctsys.h>
  27. #include <class_drawpanel.h>
  28. #include <confirm.h>
  29. #include <trigo.h>
  30. #include <macros.h>
  31. #include <pcb_base_frame.h>
  32. #include <pcb_edit_frame.h>
  33. #include <footprint_edit_frame.h>
  34. #include <pcbnew.h>
  35. #include <class_board.h>
  36. #include <class_module.h>
  37. #include <class_pad.h>
  38. #include <board_design_settings.h>
  39. #include <dialog_push_pad_properties.h>
  40. /*
  41. * Exports the current pad settings to board design settings.
  42. */
  43. void PCB_BASE_FRAME::Export_Pad_Settings( D_PAD* aPad )
  44. {
  45. if( aPad == NULL )
  46. return;
  47. SetMsgPanel( aPad );
  48. D_PAD& masterPad = GetDesignSettings().m_Pad_Master;
  49. masterPad.ImportSettingsFromMaster( *aPad );
  50. }
  51. /*
  52. * Imports the board design settings to aPad
  53. * - The position, names, and keys are not modifed.
  54. * The parameters are expected to be correct (i.e. settings are valid)
  55. */
  56. void PCB_BASE_FRAME::Import_Pad_Settings( D_PAD* aPad, bool aDraw )
  57. {
  58. if( aDraw )
  59. {
  60. aPad->SetFlags( DO_NOT_DRAW );
  61. m_canvas->RefreshDrawingRect( aPad->GetBoundingBox() );
  62. aPad->ClearFlags( DO_NOT_DRAW );
  63. }
  64. const D_PAD& mp = GetDesignSettings().m_Pad_Master;
  65. aPad->ImportSettingsFromMaster( mp );
  66. if( aDraw )
  67. m_canvas->RefreshDrawingRect( aPad->GetBoundingBox() );
  68. aPad->GetParent()->SetLastEditTime();
  69. OnModify();
  70. }
  71. /*
  72. * Compute the 'next' pad number for autoincrement
  73. * aPadName is the last pad name used
  74. * */
  75. static wxString GetNextPadName( wxString aPadName )
  76. {
  77. // Automatically increment the current pad number.
  78. int num = 0;
  79. int ponder = 1;
  80. // Trim and extract the trailing numeric part
  81. while( aPadName.Len() && aPadName.Last() >= '0' && aPadName.Last() <= '9' )
  82. {
  83. num += ( aPadName.Last() - '0' ) * ponder;
  84. aPadName.RemoveLast();
  85. ponder *= 10;
  86. }
  87. num++; // Use next number for the new pad
  88. aPadName << num;
  89. return aPadName;
  90. }
  91. /*
  92. * Add a new pad to aModule.
  93. */
  94. void PCB_BASE_FRAME::AddPad( MODULE* aModule, bool draw )
  95. {
  96. m_Pcb->m_Status_Pcb = 0;
  97. aModule->SetLastEditTime();
  98. D_PAD* pad = new D_PAD( aModule );
  99. // Add the new pad to end of the module pad list.
  100. aModule->PadsList().PushBack( pad );
  101. // Update the pad properties,
  102. // and keep NETINFO_LIST::ORPHANED as net info
  103. // which is the default when nets cannot be handled.
  104. Import_Pad_Settings( pad, false );
  105. pad->SetPosition( GetCrossHairPosition() );
  106. // Set the relative pad position
  107. // ( pad position for module orient, 0, and relative to the module position)
  108. wxPoint pos0 = pad->GetPosition() - aModule->GetPosition();
  109. RotatePoint( &pos0, -aModule->GetOrientation() );
  110. pad->SetPos0( pos0 );
  111. /* NPTH pads take empty pad number (since they can't be connected),
  112. * other pads get incremented from the last one edited */
  113. wxString padName;
  114. if( pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
  115. padName = GetNextPadName( GetDesignSettings().m_Pad_Master.GetName() );
  116. pad->SetName( padName );
  117. GetDesignSettings().m_Pad_Master.SetName( padName );
  118. aModule->CalculateBoundingBox();
  119. SetMsgPanel( pad );
  120. if( draw )
  121. m_canvas->RefreshDrawingRect( aModule->GetBoundingBox() );
  122. }
  123. void PCB_BASE_FRAME::DeletePad( D_PAD* aPad, bool aQuery )
  124. {
  125. if( aPad == NULL )
  126. return;
  127. MODULE* module = aPad->GetParent();
  128. module->SetLastEditTime();
  129. // aQuery = true to prompt for confirmation, false to delete silently
  130. if( aQuery )
  131. {
  132. wxString msg = wxString::Format( _( "Delete pad (footprint %s %s)?" ),
  133. module->GetReference(),
  134. module->GetValue() );
  135. if( !IsOK( this, msg ) )
  136. return;
  137. }
  138. // Stores the initial bounding box to refresh the old area
  139. EDA_RECT bbox = module->GetBoundingBox();
  140. m_Pcb->m_Status_Pcb = 0;
  141. GetBoard()->PadDelete( aPad );
  142. // Update the bounding box
  143. module->CalculateBoundingBox();
  144. // Refresh the modified screen area, using the initial bounding box
  145. // which is perhaps larger than the new bounding box
  146. m_canvas->RefreshDrawingRect( bbox );
  147. OnModify();
  148. }
  149. /*
  150. * PCB_EDIT_FRAME::Function PushPadProperties
  151. * Function to change pad caracteristics for the given footprint or all identical footprints
  152. * Options are set by the opened dialog.
  153. */
  154. void PCB_EDIT_FRAME::PushPadProperties( D_PAD* aPad )
  155. {
  156. if( !aPad )
  157. return;
  158. MODULE* module = aPad->GetParent();
  159. if( !module )
  160. return;
  161. SetMsgPanel( module );
  162. DIALOG_PUSH_PAD_PROPERTIES dlg( this );
  163. int retCode = dlg.ShowModal();
  164. if( retCode == wxID_CANCEL )
  165. return;
  166. bool edit_Same_Modules = ( retCode == 1 );
  167. DoPushPadProperties( aPad, edit_Same_Modules,
  168. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Shape_Filter,
  169. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Orient_Filter,
  170. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Layer_Filter,
  171. true );
  172. }
  173. /*
  174. * FOOTPRINT_EDIT_FRAME::Function PushPadProperties
  175. * Function to change pad caracteristics for the footprint.
  176. * Options are set by the opened dialog.
  177. */
  178. void FOOTPRINT_EDIT_FRAME::PushPadProperties( D_PAD* aPad )
  179. {
  180. if( !aPad )
  181. return;
  182. MODULE* module = aPad->GetParent();
  183. if( !module )
  184. return;
  185. SetMsgPanel( module );
  186. DIALOG_PUSH_PAD_PROPERTIES dlg( this );
  187. int retCode = dlg.ShowModal();
  188. if( retCode == wxID_CANCEL )
  189. return;
  190. bool edit_Same_Modules = ( retCode == 1 );
  191. DoPushPadProperties( aPad, edit_Same_Modules,
  192. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Shape_Filter,
  193. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Orient_Filter,
  194. DIALOG_PUSH_PAD_PROPERTIES::m_Pad_Layer_Filter,
  195. false );
  196. }
  197. /*
  198. * Function DoPushPadProperties
  199. * Function to change pad properties for the given footprint or all identical footprints
  200. * aPad is the pattern. The given footprint is the parent of this pad
  201. * aSameFootprints: if true, make changes on all identical footprints
  202. * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad
  203. * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad
  204. * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad
  205. * aSaveForUndo: if true: create an entry in the Undo/Redo list
  206. * (usually: true in Schematic editor, false in Module editor)
  207. */
  208. void PCB_BASE_FRAME::DoPushPadProperties( D_PAD* aPad, bool aSameFootprints,
  209. bool aPadShapeFilter,
  210. bool aPadOrientFilter,
  211. bool aPadLayerFilter,
  212. bool aSaveForUndo )
  213. {
  214. MODULE* Module_Ref = aPad->GetParent();
  215. double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation();
  216. // Prepare an undo list:
  217. if( aSaveForUndo )
  218. {
  219. PICKED_ITEMS_LIST itemsList;
  220. if( aSameFootprints )
  221. {
  222. for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
  223. {
  224. if( module->GetFPID() == Module_Ref->GetFPID() )
  225. {
  226. ITEM_PICKER itemWrapper( module, UR_CHANGED );
  227. itemsList.PushItem( itemWrapper );
  228. }
  229. }
  230. }
  231. else
  232. {
  233. ITEM_PICKER itemWrapper( Module_Ref, UR_CHANGED );
  234. itemsList.PushItem( itemWrapper );
  235. }
  236. SaveCopyInUndoList( itemsList, UR_CHANGED );
  237. }
  238. // Update the current module and same others modules if requested.
  239. for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
  240. {
  241. if( !aSameFootprints && (module != Module_Ref) )
  242. continue;
  243. if( module->GetFPID() != Module_Ref->GetFPID() )
  244. continue;
  245. // Erase module on screen
  246. module->SetFlags( DO_NOT_DRAW );
  247. m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
  248. module->ClearFlags( DO_NOT_DRAW );
  249. for( D_PAD* pad = module->PadsList(); pad; pad = pad->Next() )
  250. {
  251. if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
  252. continue;
  253. double currpad_orient = pad->GetOrientation() - module->GetOrientation();
  254. if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
  255. continue;
  256. if( aPadLayerFilter && ( pad->GetLayerSet() != aPad->GetLayerSet() ) )
  257. continue;
  258. // Do not copy pad to itself, it can create issues with custom pad primitives.
  259. if( pad == aPad )
  260. continue;
  261. pad->ImportSettingsFromMaster( *aPad );
  262. }
  263. module->CalculateBoundingBox();
  264. m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
  265. }
  266. OnModify();
  267. }