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.

465 lines
15 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 <tools/ee_selection_tool.h>
  25. #include <symbol_edit_frame.h>
  26. #include <sch_commit.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 PIN_ORIENTATION g_LastPinOrient = PIN_ORIENTATION::PIN_RIGHT;
  37. static GRAPHIC_PINSHAPE g_LastPinShape = GRAPHIC_PINSHAPE::LINE;
  38. static bool g_LastPinCommonBodyStyle = 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. SCH_COMMIT commit( m_frame );
  100. if( aPin->GetEditFlags() == 0 )
  101. commit.Modify( aPin->GetParent() );
  102. if( dlg.ShowModal() == wxID_CANCEL )
  103. return false;
  104. if( !aPin->IsNew() && m_frame->SynchronizePins() && aPin->GetParent() )
  105. {
  106. LIB_PINS pinList;
  107. aPin->GetParent()->GetPins( pinList );
  108. // a pin can have a unit id = 0 (common to all units) to unit count
  109. // So we need a buffer size = GetUnitCount()+1 to store a value in a vector
  110. // when using the unit id of a pin as index
  111. std::vector<bool> got_unit( aPin->GetParent()->GetUnitCount() + 1 );
  112. got_unit[static_cast<size_t>(aPin->GetUnit())] = true;
  113. for( LIB_PIN* other : pinList )
  114. {
  115. if( other == aPin )
  116. continue;
  117. /// Only change one pin per unit to allow stacking pins
  118. /// If you change all units on the position, then pins are not
  119. /// uniquely editable
  120. if( got_unit[static_cast<size_t>( other->GetUnit() )] )
  121. continue;
  122. if( other->GetPosition() == original_pin.GetPosition()
  123. && other->GetOrientation() == original_pin.GetOrientation()
  124. && other->GetType() == original_pin.GetType()
  125. && other->IsVisible() == original_pin.IsVisible()
  126. && other->GetName() == original_pin.GetName() )
  127. {
  128. if( aPin->GetBodyStyle() == 0 )
  129. {
  130. if( !aPin->GetUnit() || other->GetUnit() == aPin->GetUnit() )
  131. aPin->GetParent()->RemoveDrawItem( other );
  132. }
  133. if( other->GetBodyStyle() == aPin->GetBodyStyle() )
  134. {
  135. other->ChangeLength( aPin->GetLength() );
  136. // Must be done after ChangeLenght(), which can alter the position
  137. other->SetPosition( aPin->GetPosition() );
  138. other->SetShape( aPin->GetShape() );
  139. }
  140. if( aPin->GetUnit() == 0 )
  141. {
  142. if( !aPin->GetBodyStyle() || other->GetBodyStyle() == aPin->GetBodyStyle() )
  143. aPin->GetParent()->RemoveDrawItem( other );
  144. }
  145. other->SetOrientation( aPin->GetOrientation() );
  146. other->SetType( aPin->GetType() );
  147. other->SetVisible( aPin->IsVisible() );
  148. other->SetName( aPin->GetName() );
  149. other->SetNameTextSize( aPin->GetNameTextSize() );
  150. other->SetNumberTextSize( aPin->GetNumberTextSize() );
  151. got_unit[static_cast<size_t>( other->GetUnit() )] = true;
  152. }
  153. }
  154. }
  155. commit.Push( _( "Edit Pin Properties" ) );
  156. std::vector<MSG_PANEL_ITEM> items;
  157. aPin->GetMsgPanelInfo( m_frame, items );
  158. m_frame->SetMsgPanel( items );
  159. // Save the pin properties to use for the next new pin.
  160. g_LastPinNameSize = aPin->GetNameTextSize();
  161. g_LastPinNumSize = aPin->GetNumberTextSize();
  162. g_LastPinOrient = aPin->GetOrientation();
  163. g_LastPinLength = aPin->GetLength();
  164. g_LastPinShape = aPin->GetShape();
  165. g_LastPinType = aPin->GetType();
  166. g_LastPinCommonBodyStyle = aPin->GetBodyStyle() == 0;
  167. g_LastPinCommonUnit = aPin->GetUnit() == 0;
  168. g_LastPinVisible = aPin->IsVisible();
  169. return true;
  170. }
  171. bool SYMBOL_EDITOR_PIN_TOOL::PlacePin( LIB_PIN* aPin )
  172. {
  173. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  174. bool ask_for_pin = true; // Test for another pin in same position in other units
  175. std::vector<LIB_PIN*> pins = symbol->GetAllLibPins();
  176. for( LIB_PIN* test : pins )
  177. {
  178. if( test == aPin || aPin->GetPosition() != test->GetPosition() || test->GetEditFlags() )
  179. continue;
  180. // test for same body style
  181. if( test->GetBodyStyle() && test->GetBodyStyle() != aPin->GetBodyStyle() )
  182. continue;
  183. if( ask_for_pin && m_frame->SynchronizePins() )
  184. {
  185. wxString msg;
  186. msg.Printf( _( "This position is already occupied by another pin, in unit %d." ),
  187. test->GetUnit() );
  188. KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
  189. dlg.SetOKLabel( _( "Place Pin Anyway" ) );
  190. dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
  191. bool status = dlg.ShowModal() == wxID_OK;
  192. if( !status )
  193. {
  194. if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
  195. delete aPin;
  196. return false;
  197. }
  198. else
  199. {
  200. ask_for_pin = false;
  201. }
  202. }
  203. }
  204. if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
  205. {
  206. g_LastPinOrient = aPin->GetOrientation();
  207. g_LastPinType = aPin->GetType();
  208. g_LastPinShape = aPin->GetShape();
  209. if( m_frame->SynchronizePins() )
  210. CreateImagePins( aPin );
  211. symbol->AddDrawItem( aPin );
  212. aPin->ClearFlags( IS_NEW );
  213. }
  214. // Put linked pins in new position, and clear flags
  215. for( LIB_PIN* pin : pins )
  216. {
  217. if( ( pin->GetEditFlags() & IS_LINKED ) == 0 )
  218. continue;
  219. pin->MoveTo( aPin->GetPosition() );
  220. pin->ClearFlags();
  221. }
  222. m_frame->RebuildView();
  223. m_frame->OnModify();
  224. return true;
  225. }
  226. /*
  227. * Create a new pin.
  228. */
  229. LIB_PIN* SYMBOL_EDITOR_PIN_TOOL::CreatePin( const VECTOR2I& aPosition, LIB_SYMBOL* aSymbol )
  230. {
  231. aSymbol->ClearTempFlags();
  232. LIB_PIN* pin = new LIB_PIN( aSymbol );
  233. pin->SetFlags( IS_NEW );
  234. // Flag pins to consider
  235. if( m_frame->SynchronizePins() )
  236. pin->SetFlags( IS_LINKED );
  237. pin->MoveTo( aPosition );
  238. pin->SetLength( GetLastPinLength() );
  239. pin->SetOrientation( g_LastPinOrient );
  240. pin->SetType( g_LastPinType );
  241. pin->SetShape( g_LastPinShape );
  242. pin->SetNameTextSize( GetLastPinNameSize() );
  243. pin->SetNumberTextSize( GetLastPinNumSize() );
  244. pin->SetBodyStyle( g_LastPinCommonBodyStyle ? 0 : m_frame->GetBodyStyle() );
  245. pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() );
  246. pin->SetVisible( g_LastPinVisible );
  247. if( !EditPinProperties( pin ) )
  248. {
  249. delete pin;
  250. pin = nullptr;
  251. }
  252. return pin;
  253. }
  254. void SYMBOL_EDITOR_PIN_TOOL::CreateImagePins( LIB_PIN* aPin )
  255. {
  256. int ii;
  257. LIB_PIN* newPin;
  258. // if "synchronize pins editing" option is off, do not create any similar pin for other
  259. // units and/or shapes: each unit is edited regardless other units or body
  260. if( !m_frame->SynchronizePins() )
  261. return;
  262. if( aPin->GetUnit() == 0 ) // Pin common to all units: no need to create similar pins.
  263. return;
  264. // When units are interchangeable, all units are expected to have similar pins
  265. // at the same position
  266. // to facilitate pin editing, create pins for all other units for the current body style
  267. // at the same position as aPin
  268. for( ii = 1; ii <= aPin->GetParent()->GetUnitCount(); ii++ )
  269. {
  270. if( ii == aPin->GetUnit() )
  271. continue;
  272. newPin = (LIB_PIN*) aPin->Duplicate();
  273. // To avoid mistakes, gives this pin a new pin number because
  274. // it does no have the save pin number as the master pin
  275. // Because we do not know the actual number, give it a temporary number
  276. wxString unknownNum;
  277. unknownNum.Printf( "%s-U%c", aPin->GetNumber(), wxChar( 'A' + ii - 1 ) );
  278. newPin->SetNumber( unknownNum );
  279. newPin->SetUnit( ii );
  280. try
  281. {
  282. aPin->GetParent()->AddDrawItem( newPin );
  283. }
  284. catch( const boost::bad_pointer& e )
  285. {
  286. wxLogError( "Cannot add new pin to symbol. Boost pointer error %s occurred.",
  287. e.what() );
  288. delete newPin;
  289. return;
  290. }
  291. newPin->ClearFlags( IS_NEW );
  292. }
  293. }
  294. int SYMBOL_EDITOR_PIN_TOOL::PushPinProperties( const TOOL_EVENT& aEvent )
  295. {
  296. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  297. EE_SELECTION& selection = m_selectionTool->GetSelection();
  298. LIB_PIN* sourcePin = dynamic_cast<LIB_PIN*>( selection.Front() );
  299. if( !sourcePin )
  300. return 0;
  301. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  302. std::vector<LIB_PIN*> pins = symbol->GetAllLibPins();
  303. for( LIB_PIN* pin : pins )
  304. {
  305. if( pin == sourcePin )
  306. continue;
  307. if( aEvent.IsAction( &EE_ACTIONS::pushPinLength ) )
  308. {
  309. if( !pin->GetBodyStyle() || pin->GetBodyStyle() == m_frame->GetBodyStyle() )
  310. pin->ChangeLength( sourcePin->GetLength() );
  311. }
  312. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNameSize ) )
  313. {
  314. pin->SetNameTextSize( sourcePin->GetNameTextSize() );
  315. }
  316. else if( aEvent.IsAction( &EE_ACTIONS::pushPinNumSize ) )
  317. {
  318. pin->SetNumberTextSize( sourcePin->GetNumberTextSize() );
  319. }
  320. }
  321. m_frame->RebuildView();
  322. m_frame->OnModify();
  323. return 0;
  324. }
  325. // Create a new pin based on the previous pin with an incremented pin number.
  326. LIB_PIN* SYMBOL_EDITOR_PIN_TOOL::RepeatPin( const LIB_PIN* aSourcePin )
  327. {
  328. SCH_COMMIT commit( m_frame );
  329. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  330. commit.Modify( symbol );
  331. LIB_PIN* pin = (LIB_PIN*) aSourcePin->Duplicate();
  332. VECTOR2I step;
  333. pin->ClearFlags();
  334. pin->SetFlags( IS_NEW );
  335. auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  336. switch( pin->GetOrientation() )
  337. {
  338. case PIN_ORIENTATION::PIN_UP: step.x = schIUScale.MilsToIU(settings->m_Repeat.pin_step); break;
  339. case PIN_ORIENTATION::PIN_DOWN: step.x = schIUScale.MilsToIU(settings->m_Repeat.pin_step); break;
  340. case PIN_ORIENTATION::PIN_LEFT: step.y = schIUScale.MilsToIU(-settings->m_Repeat.pin_step); break;
  341. case PIN_ORIENTATION::PIN_RIGHT: step.y = schIUScale.MilsToIU(-settings->m_Repeat.pin_step); break;
  342. }
  343. pin->Offset( step );
  344. wxString nextName = pin->GetName();
  345. IncrementLabelMember( nextName, settings->m_Repeat.label_delta );
  346. pin->SetName( nextName );
  347. wxString nextNumber = pin->GetNumber();
  348. IncrementLabelMember( nextNumber, settings->m_Repeat.label_delta );
  349. pin->SetNumber( nextNumber );
  350. if( m_frame->SynchronizePins() )
  351. pin->SetFlags( IS_LINKED );
  352. if( PlacePin( pin ) )
  353. {
  354. commit.Push( _( "Repeat Pin" ) );
  355. return pin;
  356. }
  357. return nullptr;
  358. }
  359. void SYMBOL_EDITOR_PIN_TOOL::setTransitions()
  360. {
  361. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinLength.MakeEvent() );
  362. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNameSize.MakeEvent() );
  363. Go( &SYMBOL_EDITOR_PIN_TOOL::PushPinProperties, EE_ACTIONS::pushPinNumSize.MakeEvent() );
  364. }