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.

472 lines
15 KiB

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