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.

419 lines
13 KiB

16 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 CERN
  5. * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
  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 <tool/tool_manager.h>
  25. #include <tools/ee_selection_tool.h>
  26. #include <lib_edit_frame.h>
  27. #include <confirm.h>
  28. #include <ee_actions.h>
  29. #include <dialogs/dialog_pin_properties.h>
  30. #include <settings/settings_manager.h>
  31. #include <libedit/libedit_settings.h>
  32. #include <pgm_base.h>
  33. #include "lib_pin_tool.h"
  34. static ELECTRICAL_PINTYPE g_LastPinType = ELECTRICAL_PINTYPE::PT_INPUT;
  35. static int g_LastPinOrient = PIN_RIGHT;
  36. static GRAPHIC_PINSHAPE g_LastPinShape = GRAPHIC_PINSHAPE::LINE;
  37. static bool g_LastPinCommonConvert = false;
  38. static bool g_LastPinCommonUnit = false;
  39. static bool g_LastPinVisible = true;
  40. // The -1 is a non-valid value to trigger delayed initialization
  41. static int g_LastPinLength = -1;
  42. static int g_LastPinNameSize = -1;
  43. static int g_LastPinNumSize = -1;
  44. static int GetLastPinLength()
  45. {
  46. if( g_LastPinLength == -1 )
  47. {
  48. LIBEDIT_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<LIBEDIT_SETTINGS>();
  49. g_LastPinLength = Mils2iu( settings->m_Defaults.pin_length );
  50. }
  51. return g_LastPinLength;
  52. }
  53. static int GetLastPinNameSize()
  54. {
  55. if( g_LastPinNameSize == -1 )
  56. {
  57. LIBEDIT_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<LIBEDIT_SETTINGS>();
  58. g_LastPinNameSize = Mils2iu( settings->m_Defaults.pin_name_size );
  59. }
  60. return g_LastPinNameSize;
  61. }
  62. static int GetLastPinNumSize()
  63. {
  64. if( g_LastPinNumSize == -1 )
  65. {
  66. LIBEDIT_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<LIBEDIT_SETTINGS>();
  67. g_LastPinNumSize = Mils2iu( settings->m_Defaults.pin_num_size );
  68. }
  69. return g_LastPinNumSize;
  70. }
  71. extern void IncrementLabelMember( wxString& name, int aIncrement );
  72. LIB_PIN_TOOL::LIB_PIN_TOOL() :
  73. EE_TOOL_BASE<LIB_EDIT_FRAME>( "eeschema.PinEditing" )
  74. {
  75. }
  76. bool LIB_PIN_TOOL::Init()
  77. {
  78. EE_TOOL_BASE::Init();
  79. auto singlePinCondition = EE_CONDITIONS::Count( 1 ) && EE_CONDITIONS::OnlyType( LIB_PIN_T );
  80. CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
  81. selToolMenu.AddSeparator( 400 );
  82. selToolMenu.AddItem( EE_ACTIONS::pushPinLength, singlePinCondition, 400 );
  83. selToolMenu.AddItem( EE_ACTIONS::pushPinNameSize, singlePinCondition, 400 );
  84. selToolMenu.AddItem( EE_ACTIONS::pushPinNumSize, singlePinCondition, 400 );
  85. return true;
  86. }
  87. bool LIB_PIN_TOOL::EditPinProperties( LIB_PIN* aPin )
  88. {
  89. DIALOG_PIN_PROPERTIES dlg( m_frame, aPin );
  90. if( aPin->GetEditFlags() == 0 )
  91. m_frame->SaveCopyInUndoList( aPin->GetParent() );
  92. if( dlg.ShowModal() == wxID_CANCEL )
  93. {
  94. if( aPin->GetEditFlags() == 0 )
  95. m_frame->PopCommandFromUndoList();
  96. return false;
  97. }
  98. aPin->SetModified();
  99. if( !aPin->IsNew() && m_frame->SynchronizePins() && aPin->GetParent() )
  100. {
  101. LIB_PINS pinList;
  102. aPin->GetParent()->GetPins( pinList );
  103. for( LIB_PIN* other : pinList )
  104. {
  105. if( other == aPin )
  106. continue;
  107. if( other->GetPosition() == aPin->GetPosition()
  108. && other->GetOrientation() == aPin->GetOrientation() )
  109. {
  110. if( aPin->GetConvert() == 0 )
  111. {
  112. if( !aPin->GetUnit() || other->GetUnit() == aPin->GetUnit() )
  113. aPin->GetParent()->RemoveDrawItem( other );
  114. }
  115. else if( other->GetConvert() == aPin->GetConvert() )
  116. {
  117. other->SetPosition( aPin->GetPosition() );
  118. other->SetLength( aPin->GetLength() );
  119. other->SetShape( aPin->GetShape() );
  120. }
  121. if( aPin->GetUnit() == 0 )
  122. {
  123. if( !aPin->GetConvert() || other->GetConvert() == aPin->GetConvert() )
  124. aPin->GetParent()->RemoveDrawItem( other );
  125. }
  126. other->SetOrientation( aPin->GetOrientation() );
  127. other->SetType( aPin->GetType() );
  128. other->SetVisible( aPin->IsVisible() );
  129. other->SetName( aPin->GetName() );
  130. other->SetNameTextSize( aPin->GetNameTextSize() );
  131. other->SetNumberTextSize( aPin->GetNumberTextSize() );
  132. other->SetModified();
  133. }
  134. }
  135. }
  136. m_frame->UpdateItem( aPin );
  137. m_frame->OnModify( );
  138. MSG_PANEL_ITEMS items;
  139. aPin->GetMsgPanelInfo( m_frame, items );
  140. m_frame->SetMsgPanel( items );
  141. // Save the pin properties to use for the next new pin.
  142. g_LastPinNameSize = aPin->GetNameTextSize();
  143. g_LastPinNumSize = aPin->GetNumberTextSize();
  144. g_LastPinOrient = aPin->GetOrientation();
  145. g_LastPinLength = aPin->GetLength();
  146. g_LastPinShape = aPin->GetShape();
  147. g_LastPinType = aPin->GetType();
  148. g_LastPinCommonConvert = aPin->GetConvert() == 0;
  149. g_LastPinCommonUnit = aPin->GetUnit() == 0;
  150. g_LastPinVisible = aPin->IsVisible();
  151. return true;
  152. }
  153. bool LIB_PIN_TOOL::PlacePin( LIB_PIN* aPin )
  154. {
  155. LIB_PART* part = m_frame->GetCurPart();
  156. bool ask_for_pin = true; // Test for another pin in same position in other units
  157. for( LIB_PIN* test = part->GetNextPin(); test; test = part->GetNextPin( test ) )
  158. {
  159. if( test == aPin || aPin->GetPosition() != test->GetPosition() || test->GetEditFlags() )
  160. continue;
  161. // test for same body style
  162. if( test->GetConvert() && test->GetConvert() != aPin->GetConvert() )
  163. continue;
  164. if( ask_for_pin && m_frame->SynchronizePins() )
  165. {
  166. wxString msg;
  167. msg.Printf( _( "This position is already occupied by another pin, in unit %d." ),
  168. test->GetUnit() );
  169. KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
  170. dlg.SetOKLabel( _( "Place Pin Anyway" ) );
  171. dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
  172. bool status = dlg.ShowModal() == wxID_OK;
  173. if( !status )
  174. {
  175. if( aPin->IsNew() )
  176. delete aPin;
  177. return false;
  178. }
  179. else
  180. {
  181. ask_for_pin = false;
  182. }
  183. }
  184. }
  185. if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
  186. {
  187. g_LastPinOrient = aPin->GetOrientation();
  188. g_LastPinType = aPin->GetType();
  189. g_LastPinShape = aPin->GetShape();
  190. if( m_frame->SynchronizePins() )
  191. CreateImagePins( aPin );
  192. part->AddDrawItem( aPin );
  193. aPin->ClearFlags( IS_NEW );
  194. }
  195. // Put linked pins in new position, and clear flags
  196. for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
  197. {
  198. if( ( pin->GetEditFlags() & IS_LINKED ) == 0 )
  199. continue;
  200. pin->MoveTo( aPin->GetPosition() );
  201. pin->ClearFlags();
  202. }
  203. m_frame->RebuildView();
  204. m_frame->OnModify();
  205. return true;
  206. }
  207. /*
  208. * Create a new pin.
  209. */
  210. LIB_PIN* LIB_PIN_TOOL::CreatePin( const VECTOR2I& aPosition, LIB_PART* aPart )
  211. {
  212. aPart->ClearTempFlags();
  213. LIB_PIN* pin = new LIB_PIN( aPart );
  214. pin->SetFlags( IS_NEW );
  215. // Flag pins to consider
  216. if( m_frame->SynchronizePins() )
  217. pin->SetFlags( IS_LINKED );
  218. pin->MoveTo((wxPoint) aPosition );
  219. pin->SetLength( GetLastPinLength() );
  220. pin->SetOrientation( g_LastPinOrient );
  221. pin->SetType( g_LastPinType );
  222. pin->SetShape( g_LastPinShape );
  223. pin->SetNameTextSize( GetLastPinNameSize() );
  224. pin->SetNumberTextSize( GetLastPinNumSize() );
  225. pin->SetConvert( g_LastPinCommonConvert ? 0 : m_frame->GetConvert() );
  226. pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() );
  227. pin->SetVisible( g_LastPinVisible );
  228. if( !EditPinProperties( pin ) )
  229. {
  230. delete pin;
  231. pin = nullptr;
  232. }
  233. return pin;
  234. }
  235. void LIB_PIN_TOOL::CreateImagePins( LIB_PIN* aPin )
  236. {
  237. int ii;
  238. LIB_PIN* newPin;
  239. // if "synchronize pins editing" option is off, do not create any similar pin for other
  240. // units and/or shapes: each unit is edited regardless other units or body
  241. if( !m_frame->SynchronizePins() )
  242. return;
  243. if( aPin->GetUnit() == 0 ) // Pin common to all units: no need to create similar pins.
  244. return;
  245. // When units are interchangeable, all units are expected to have similar pins
  246. // at the same position
  247. // to facilitate pin editing, create pins for all other units for the current body style
  248. // at the same position as aPin
  249. for( ii = 1; ii <= aPin->GetParent()->GetUnitCount(); ii++ )
  250. {
  251. if( ii == aPin->GetUnit() )
  252. continue;
  253. newPin = (LIB_PIN*) aPin->Clone();
  254. // To avoid mistakes, gives this pin a new pin number because
  255. // it does no have the save pin number as the master pin
  256. // Because we do not know the actual number, give it a temporary number
  257. wxString unknownNum;
  258. unknownNum.Printf( "%s-U%c", aPin->GetNumber(), wxChar( 'A' + ii - 1 ) );
  259. newPin->SetNumber( unknownNum );
  260. newPin->SetUnit( ii );
  261. aPin->GetParent()->AddDrawItem( newPin );
  262. newPin->ClearFlags( IS_NEW );
  263. }
  264. }
  265. int LIB_PIN_TOOL::PushPinProperties( const TOOL_EVENT& aEvent )
  266. {
  267. LIB_PART* part = m_frame->GetCurPart();
  268. EE_SELECTION& selection = m_selectionTool->GetSelection();
  269. LIB_PIN* sourcePin = dynamic_cast<LIB_PIN*>( selection.Front() );
  270. if( !sourcePin )
  271. return 0;
  272. saveCopyInUndoList( part, UNDO_REDO::LIBEDIT );
  273. for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
  274. {
  275. if( pin == sourcePin )
  276. continue;
  277. if( aEvent.IsAction( &EE_ACTIONS::pushPinLength ) )
  278. {
  279. if( !pin->GetConvert() || pin->GetConvert() == m_frame->GetConvert() )
  280. pin->SetLength( sourcePin->GetLength() );
  281. }
  282. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNameSize ) )
  283. {
  284. pin->SetNameTextSize( sourcePin->GetNameTextSize() );
  285. }
  286. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNumSize ) )
  287. {
  288. pin->SetNumberTextSize( sourcePin->GetNumberTextSize() );
  289. }
  290. }
  291. m_frame->RebuildView();
  292. m_frame->OnModify();
  293. return 0;
  294. }
  295. // Create a new pin based on the previous pin with an incremented pin number.
  296. LIB_PIN* LIB_PIN_TOOL::RepeatPin( const LIB_PIN* aSourcePin )
  297. {
  298. LIB_PIN* pin = (LIB_PIN*) aSourcePin->Clone();
  299. wxPoint step;
  300. pin->ClearFlags();
  301. pin->SetFlags( IS_NEW );
  302. LIBEDIT_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<LIBEDIT_SETTINGS>();
  303. switch( pin->GetOrientation() )
  304. {
  305. case PIN_UP: step.x = settings->m_Repeat.pin_step; break;
  306. case PIN_DOWN: step.x = settings->m_Repeat.pin_step; break;
  307. case PIN_LEFT: step.y = -settings->m_Repeat.pin_step; break;
  308. case PIN_RIGHT: step.y = -settings->m_Repeat.pin_step; break;
  309. }
  310. pin->Offset( step );
  311. wxString nextName = pin->GetName();
  312. IncrementLabelMember( nextName, settings->m_Repeat.label_delta );
  313. pin->SetName( nextName );
  314. wxString nextNumber = pin->GetNumber();
  315. IncrementLabelMember( nextNumber, settings->m_Repeat.label_delta );
  316. pin->SetNumber( nextNumber );
  317. if( m_frame->SynchronizePins() )
  318. pin->SetFlags( IS_LINKED );
  319. if( PlacePin( pin ) )
  320. return pin;
  321. return nullptr;
  322. }
  323. void LIB_PIN_TOOL::setTransitions()
  324. {
  325. Go( &LIB_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinLength.MakeEvent() );
  326. Go( &LIB_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNameSize.MakeEvent() );
  327. Go( &LIB_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNumSize.MakeEvent() );
  328. }