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.

461 lines
14 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-2022 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 <symbol_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 <symbol_editor/symbol_editor_settings.h>
  32. #include <pgm_base.h>
  33. #include <wx/log.h>
  34. #include "symbol_editor_pin_tool.h"
  35. static ELECTRICAL_PINTYPE g_LastPinType = ELECTRICAL_PINTYPE::PT_INPUT;
  36. static int g_LastPinOrient = PIN_RIGHT;
  37. static GRAPHIC_PINSHAPE g_LastPinShape = GRAPHIC_PINSHAPE::LINE;
  38. static bool g_LastPinCommonConvert = false;
  39. static bool g_LastPinCommonUnit = false;
  40. static bool g_LastPinVisible = true;
  41. // The -1 is a non-valid value to trigger delayed initialization
  42. static int g_LastPinLength = -1;
  43. static int g_LastPinNameSize = -1;
  44. static int g_LastPinNumSize = -1;
  45. static int GetLastPinLength()
  46. {
  47. if( g_LastPinLength == -1 )
  48. {
  49. auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  50. g_LastPinLength = schIUScale.MilsToIU( settings->m_Defaults.pin_length );
  51. }
  52. return g_LastPinLength;
  53. }
  54. static int GetLastPinNameSize()
  55. {
  56. if( g_LastPinNameSize == -1 )
  57. {
  58. auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  59. g_LastPinNameSize = schIUScale.MilsToIU( settings->m_Defaults.pin_name_size );
  60. }
  61. return g_LastPinNameSize;
  62. }
  63. static int GetLastPinNumSize()
  64. {
  65. if( g_LastPinNumSize == -1 )
  66. {
  67. auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  68. g_LastPinNumSize = schIUScale.MilsToIU( settings->m_Defaults.pin_num_size );
  69. }
  70. return g_LastPinNumSize;
  71. }
  72. extern bool IncrementLabelMember( wxString& name, int aIncrement );
  73. SYMBOL_EDITOR_PIN_TOOL::SYMBOL_EDITOR_PIN_TOOL() :
  74. EE_TOOL_BASE<SYMBOL_EDIT_FRAME>( "eeschema.PinEditing" )
  75. {
  76. }
  77. bool SYMBOL_EDITOR_PIN_TOOL::Init()
  78. {
  79. EE_TOOL_BASE::Init();
  80. auto canEdit =
  81. [&]( const SELECTION& sel )
  82. {
  83. SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
  84. wxCHECK( editor, false );
  85. return editor->IsSymbolEditable() && !editor->IsSymbolAlias();
  86. };
  87. auto singlePinCondition = EE_CONDITIONS::Count( 1 ) && EE_CONDITIONS::OnlyTypes( { LIB_PIN_T } );
  88. CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
  89. selToolMenu.AddSeparator( 250 );
  90. selToolMenu.AddItem( EE_ACTIONS::pushPinLength, canEdit && singlePinCondition, 250 );
  91. selToolMenu.AddItem( EE_ACTIONS::pushPinNameSize, canEdit && singlePinCondition, 250 );
  92. selToolMenu.AddItem( EE_ACTIONS::pushPinNumSize, canEdit && singlePinCondition, 250 );
  93. return true;
  94. }
  95. bool SYMBOL_EDITOR_PIN_TOOL::EditPinProperties( LIB_PIN* aPin )
  96. {
  97. LIB_PIN original_pin( *aPin );
  98. DIALOG_PIN_PROPERTIES dlg( m_frame, aPin );
  99. if( aPin->GetEditFlags() == 0 )
  100. m_frame->SaveCopyInUndoList( aPin->GetParent() );
  101. if( dlg.ShowModal() == wxID_CANCEL )
  102. {
  103. if( aPin->GetEditFlags() == 0 )
  104. m_frame->PopCommandFromUndoList();
  105. return false;
  106. }
  107. aPin->SetModified();
  108. if( !aPin->IsNew() && m_frame->SynchronizePins() && aPin->GetParent() )
  109. {
  110. LIB_PINS pinList;
  111. aPin->GetParent()->GetPins( pinList );
  112. // a pin can have a unit id = 0 (common to all units) to unit count
  113. // So we need a buffer size = GetUnitCount()+1 to store a value in a vector
  114. // when using the unit id of a pin as index
  115. std::vector<bool> got_unit( aPin->GetParent()->GetUnitCount() + 1 );
  116. got_unit[static_cast<size_t>(aPin->GetUnit())] = true;
  117. for( LIB_PIN* other : pinList )
  118. {
  119. if( other == aPin )
  120. continue;
  121. /// Only change one pin per unit to allow stacking pins
  122. /// If you change all units on the position, then pins are not
  123. /// uniquely editable
  124. if( got_unit[static_cast<size_t>( other->GetUnit() )] )
  125. continue;
  126. if( other->GetPosition() == original_pin.GetPosition()
  127. && other->GetOrientation() == original_pin.GetOrientation()
  128. && other->GetType() == original_pin.GetType()
  129. && other->IsVisible() == original_pin.IsVisible()
  130. && other->GetName() == original_pin.GetName() )
  131. {
  132. if( aPin->GetConvert() == 0 )
  133. {
  134. if( !aPin->GetUnit() || other->GetUnit() == aPin->GetUnit() )
  135. aPin->GetParent()->RemoveDrawItem( other );
  136. }
  137. else if( other->GetConvert() == aPin->GetConvert() )
  138. {
  139. other->SetPosition( aPin->GetPosition() );
  140. other->ChangeLength( aPin->GetLength() );
  141. other->SetShape( aPin->GetShape() );
  142. }
  143. if( aPin->GetUnit() == 0 )
  144. {
  145. if( !aPin->GetConvert() || other->GetConvert() == aPin->GetConvert() )
  146. aPin->GetParent()->RemoveDrawItem( other );
  147. }
  148. other->SetOrientation( aPin->GetOrientation() );
  149. other->SetType( aPin->GetType() );
  150. other->SetVisible( aPin->IsVisible() );
  151. other->SetName( aPin->GetName() );
  152. other->SetNameTextSize( aPin->GetNameTextSize() );
  153. other->SetNumberTextSize( aPin->GetNumberTextSize() );
  154. other->SetModified();
  155. got_unit[static_cast<size_t>( other->GetUnit() )] = true;
  156. }
  157. }
  158. }
  159. m_frame->UpdateItem( aPin, false, true );
  160. m_frame->OnModify( );
  161. std::vector<MSG_PANEL_ITEM> items;
  162. aPin->GetMsgPanelInfo( m_frame, items );
  163. m_frame->SetMsgPanel( items );
  164. // Save the pin properties to use for the next new pin.
  165. g_LastPinNameSize = aPin->GetNameTextSize();
  166. g_LastPinNumSize = aPin->GetNumberTextSize();
  167. g_LastPinOrient = aPin->GetOrientation();
  168. g_LastPinLength = aPin->GetLength();
  169. g_LastPinShape = aPin->GetShape();
  170. g_LastPinType = aPin->GetType();
  171. g_LastPinCommonConvert = aPin->GetConvert() == 0;
  172. g_LastPinCommonUnit = aPin->GetUnit() == 0;
  173. g_LastPinVisible = aPin->IsVisible();
  174. return true;
  175. }
  176. bool SYMBOL_EDITOR_PIN_TOOL::PlacePin( LIB_PIN* aPin )
  177. {
  178. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  179. bool ask_for_pin = true; // Test for another pin in same position in other units
  180. std::vector<LIB_PIN*> pins = symbol->GetAllLibPins();
  181. for( LIB_PIN* test : pins )
  182. {
  183. if( test == aPin || aPin->GetPosition() != test->GetPosition() || test->GetEditFlags() )
  184. continue;
  185. // test for same body style
  186. if( test->GetConvert() && test->GetConvert() != aPin->GetConvert() )
  187. continue;
  188. if( ask_for_pin && m_frame->SynchronizePins() )
  189. {
  190. wxString msg;
  191. msg.Printf( _( "This position is already occupied by another pin, in unit %d." ),
  192. test->GetUnit() );
  193. KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
  194. dlg.SetOKLabel( _( "Place Pin Anyway" ) );
  195. dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
  196. bool status = dlg.ShowModal() == wxID_OK;
  197. if( !status )
  198. {
  199. if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
  200. delete aPin;
  201. return false;
  202. }
  203. else
  204. {
  205. ask_for_pin = false;
  206. }
  207. }
  208. }
  209. if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
  210. {
  211. g_LastPinOrient = aPin->GetOrientation();
  212. g_LastPinType = aPin->GetType();
  213. g_LastPinShape = aPin->GetShape();
  214. if( m_frame->SynchronizePins() )
  215. CreateImagePins( aPin );
  216. symbol->AddDrawItem( aPin );
  217. aPin->ClearFlags( IS_NEW );
  218. }
  219. // Put linked pins in new position, and clear flags
  220. for( LIB_PIN* pin : pins )
  221. {
  222. if( ( pin->GetEditFlags() & IS_LINKED ) == 0 )
  223. continue;
  224. pin->MoveTo( aPin->GetPosition() );
  225. pin->ClearFlags();
  226. }
  227. m_frame->RebuildView();
  228. m_frame->OnModify();
  229. return true;
  230. }
  231. /*
  232. * Create a new pin.
  233. */
  234. LIB_PIN* SYMBOL_EDITOR_PIN_TOOL::CreatePin( const VECTOR2I& aPosition, LIB_SYMBOL* aSymbol )
  235. {
  236. aSymbol->ClearTempFlags();
  237. LIB_PIN* pin = new LIB_PIN( aSymbol );
  238. pin->SetFlags( IS_NEW );
  239. // Flag pins to consider
  240. if( m_frame->SynchronizePins() )
  241. pin->SetFlags( IS_LINKED );
  242. pin->MoveTo( aPosition );
  243. pin->SetLength( GetLastPinLength() );
  244. pin->SetOrientation( g_LastPinOrient );
  245. pin->SetType( g_LastPinType );
  246. pin->SetShape( g_LastPinShape );
  247. pin->SetNameTextSize( GetLastPinNameSize() );
  248. pin->SetNumberTextSize( GetLastPinNumSize() );
  249. pin->SetConvert( g_LastPinCommonConvert ? 0 : m_frame->GetConvert() );
  250. pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() );
  251. pin->SetVisible( g_LastPinVisible );
  252. if( !EditPinProperties( pin ) )
  253. {
  254. delete pin;
  255. pin = nullptr;
  256. }
  257. return pin;
  258. }
  259. void SYMBOL_EDITOR_PIN_TOOL::CreateImagePins( LIB_PIN* aPin )
  260. {
  261. int ii;
  262. LIB_PIN* newPin;
  263. // if "synchronize pins editing" option is off, do not create any similar pin for other
  264. // units and/or shapes: each unit is edited regardless other units or body
  265. if( !m_frame->SynchronizePins() )
  266. return;
  267. if( aPin->GetUnit() == 0 ) // Pin common to all units: no need to create similar pins.
  268. return;
  269. // When units are interchangeable, all units are expected to have similar pins
  270. // at the same position
  271. // to facilitate pin editing, create pins for all other units for the current body style
  272. // at the same position as aPin
  273. for( ii = 1; ii <= aPin->GetParent()->GetUnitCount(); ii++ )
  274. {
  275. if( ii == aPin->GetUnit() )
  276. continue;
  277. newPin = (LIB_PIN*) aPin->Clone();
  278. // To avoid mistakes, gives this pin a new pin number because
  279. // it does no have the save pin number as the master pin
  280. // Because we do not know the actual number, give it a temporary number
  281. wxString unknownNum;
  282. unknownNum.Printf( "%s-U%c", aPin->GetNumber(), wxChar( 'A' + ii - 1 ) );
  283. newPin->SetNumber( unknownNum );
  284. newPin->SetUnit( ii );
  285. try
  286. {
  287. aPin->GetParent()->AddDrawItem( newPin );
  288. }
  289. catch( const boost::bad_pointer& e )
  290. {
  291. wxLogError( "Cannot add new pin to symbol. Boost pointer error %s occurred.",
  292. e.what() );
  293. delete newPin;
  294. return;
  295. }
  296. newPin->ClearFlags( IS_NEW );
  297. }
  298. }
  299. int SYMBOL_EDITOR_PIN_TOOL::PushPinProperties( const TOOL_EVENT& aEvent )
  300. {
  301. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  302. EE_SELECTION& selection = m_selectionTool->GetSelection();
  303. LIB_PIN* sourcePin = dynamic_cast<LIB_PIN*>( selection.Front() );
  304. if( !sourcePin )
  305. return 0;
  306. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  307. std::vector<LIB_PIN*> pins = symbol->GetAllLibPins();
  308. for( LIB_PIN* pin : pins )
  309. {
  310. if( pin == sourcePin )
  311. continue;
  312. if( aEvent.IsAction( &EE_ACTIONS::pushPinLength ) )
  313. {
  314. if( !pin->GetConvert() || pin->GetConvert() == m_frame->GetConvert() )
  315. pin->ChangeLength( sourcePin->GetLength() );
  316. }
  317. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNameSize ) )
  318. {
  319. pin->SetNameTextSize( sourcePin->GetNameTextSize() );
  320. }
  321. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNumSize ) )
  322. {
  323. pin->SetNumberTextSize( sourcePin->GetNumberTextSize() );
  324. }
  325. }
  326. m_frame->RebuildView();
  327. m_frame->OnModify();
  328. return 0;
  329. }
  330. // Create a new pin based on the previous pin with an incremented pin number.
  331. LIB_PIN* SYMBOL_EDITOR_PIN_TOOL::RepeatPin( const LIB_PIN* aSourcePin )
  332. {
  333. LIB_PIN* pin = (LIB_PIN*) aSourcePin->Clone();
  334. VECTOR2I step;
  335. pin->ClearFlags();
  336. pin->SetFlags( IS_NEW );
  337. auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  338. switch( pin->GetOrientation() )
  339. {
  340. case PIN_UP: step.x = schIUScale.MilsToIU(settings->m_Repeat.pin_step); break;
  341. case PIN_DOWN: step.x = schIUScale.MilsToIU(settings->m_Repeat.pin_step); break;
  342. case PIN_LEFT: step.y = schIUScale.MilsToIU(-settings->m_Repeat.pin_step); break;
  343. case PIN_RIGHT: step.y = schIUScale.MilsToIU(-settings->m_Repeat.pin_step); break;
  344. }
  345. pin->Offset( step );
  346. wxString nextName = pin->GetName();
  347. IncrementLabelMember( nextName, settings->m_Repeat.label_delta );
  348. pin->SetName( nextName );
  349. wxString nextNumber = pin->GetNumber();
  350. IncrementLabelMember( nextNumber, settings->m_Repeat.label_delta );
  351. pin->SetNumber( nextNumber );
  352. if( m_frame->SynchronizePins() )
  353. pin->SetFlags( IS_LINKED );
  354. if( PlacePin( pin ) )
  355. return pin;
  356. return nullptr;
  357. }
  358. void SYMBOL_EDITOR_PIN_TOOL::setTransitions()
  359. {
  360. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinLength.MakeEvent() );
  361. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNameSize.MakeEvent() );
  362. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNumSize.MakeEvent() );
  363. }