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.

715 lines
21 KiB

16 years ago
15 years ago
15 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) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file pinedit.cpp
  27. * @brief Eeschema pin edit code.
  28. */
  29. #include "fctsys.h"
  30. #include "gr_basic.h"
  31. #include "class_drawpanel.h"
  32. #include "confirm.h"
  33. #include "class_sch_screen.h"
  34. #include "libeditframe.h"
  35. #include "eeschema_id.h"
  36. #include "class_libentry.h"
  37. #include "lib_pin.h"
  38. #include "general.h"
  39. #include "protos.h"
  40. #include "../common/dialogs/dialog_display_info_HTML_base.h"
  41. #include "dialog_lib_edit_pin.h"
  42. extern void IncrementLabelMember( wxString& name );
  43. static void AbortPinMove( EDA_DRAW_PANEL* Panel, wxDC* DC );
  44. static void DrawMovePin( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPositon, bool aErase );
  45. static wxPoint OldPos;
  46. static wxPoint PinPreviousPos;
  47. static int LastPinType = PIN_INPUT;
  48. static int LastPinOrient = PIN_RIGHT;
  49. static int LastPinShape = NONE;
  50. static int LastPinLength = 300;
  51. static int LastPinNameSize = 50;
  52. static int LastPinNumSize = 50;
  53. static bool LastPinCommonConvert = false;
  54. static bool LastPinCommonUnit = false;
  55. static bool LastPinVisible = true;
  56. void LIB_EDIT_FRAME::OnEditPin( wxCommandEvent& event )
  57. {
  58. if( m_drawItem == NULL || m_drawItem->Type() != LIB_PIN_T )
  59. return;
  60. int item_flags = m_drawItem->GetFlags(); // save flags to restore them after editing
  61. LIB_PIN* pin = (LIB_PIN*) m_drawItem;
  62. DIALOG_LIB_EDIT_PIN dlg( this, pin );
  63. wxString units = GetUnitsLabel( g_UserUnit );
  64. dlg.SetOrientationList( LIB_PIN::GetOrientationNames(), LIB_PIN::GetOrientationSymbols() );
  65. dlg.SetOrientation( LIB_PIN::GetOrientationCodeIndex( pin->GetOrientation() ) );
  66. dlg.SetStyleList( LIB_PIN::GetStyleNames(), LIB_PIN::GetStyleSymbols() );
  67. dlg.SetStyle( LIB_PIN::GetStyleCodeIndex( pin->GetShape() ) );
  68. dlg.SetElectricalTypeList( LIB_PIN::GetElectricalTypeNames(),
  69. LIB_PIN::GetElectricalTypeSymbols() );
  70. dlg.SetElectricalType( pin->GetType() );
  71. dlg.SetName( pin->GetName() );
  72. dlg.SetNameTextSize( ReturnStringFromValue( g_UserUnit,
  73. pin->GetNameTextSize(),
  74. m_internalUnits ) );
  75. dlg.SetNameTextSizeUnits( units );
  76. dlg.SetPadName( pin->GetNumberString() );
  77. dlg.SetPadNameTextSize( ReturnStringFromValue( g_UserUnit,
  78. pin->GetNumberTextSize(),
  79. m_internalUnits ) );
  80. dlg.SetPadNameTextSizeUnits( units );
  81. dlg.SetLength( ReturnStringFromValue( g_UserUnit, pin->GetLength(), m_internalUnits ) );
  82. dlg.SetLengthUnits( units );
  83. dlg.SetAddToAllParts( pin->GetUnit() == 0 );
  84. dlg.SetAddToAllBodyStyles( pin->GetConvert() == 0 );
  85. dlg.SetVisible( pin->IsVisible() );
  86. /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier
  87. * versions for the flex grid sizer in wxGTK that prevents the last
  88. * column from being sized correctly. It doesn't cause any problems
  89. * on win32 so it doesn't need to wrapped in ugly #ifdef __WXGTK__
  90. * #endif.
  91. */
  92. dlg.Layout();
  93. dlg.Fit();
  94. dlg.SetMinSize( dlg.GetSize() );
  95. dlg.SetLastSizeAndPosition();
  96. if( dlg.ShowModal() == wxID_CANCEL )
  97. {
  98. if( pin->IsNew() )
  99. {
  100. pin->SetFlags( IS_CANCELLED );
  101. DrawPanel->EndMouseCapture();
  102. }
  103. return;
  104. }
  105. /* Save the pin properties to use for the next new pin. */
  106. LastPinNameSize = ReturnValueFromString( g_UserUnit, dlg.GetNameTextSize(), m_internalUnits );
  107. LastPinNumSize = ReturnValueFromString( g_UserUnit, dlg.GetPadNameTextSize(), m_internalUnits );
  108. LastPinOrient = LIB_PIN::GetOrientationCode( dlg.GetOrientation() );
  109. LastPinLength = ReturnValueFromString( g_UserUnit, dlg.GetLength(), m_internalUnits );
  110. LastPinShape = LIB_PIN::GetStyleCode( dlg.GetStyle() );
  111. LastPinType = dlg.GetElectricalType();
  112. LastPinCommonConvert = dlg.GetAddToAllBodyStyles();
  113. LastPinCommonUnit = dlg.GetAddToAllParts();
  114. LastPinVisible = dlg.GetVisible();
  115. pin->EnableEditMode( true, m_editPinsPerPartOrConvert );
  116. pin->SetName( dlg.GetName() );
  117. pin->SetNameTextSize( LastPinNameSize );
  118. pin->SetNumber( dlg.GetPadName() );
  119. pin->SetNumberTextSize( LastPinNumSize );
  120. pin->SetOrientation( LastPinOrient );
  121. pin->SetLength( LastPinLength );
  122. pin->SetType( LastPinType );
  123. pin->SetShape( LastPinShape );
  124. pin->SetConversion( ( LastPinCommonConvert ) ? 0 : m_convert );
  125. pin->SetPartNumber( ( LastPinCommonUnit ) ? 0 : m_unit );
  126. pin->SetVisible( LastPinVisible );
  127. if( pin->IsModified() || pin->IsNew() )
  128. {
  129. if( !pin->InEditMode() )
  130. SaveCopyInUndoList( pin->GetParent() );
  131. OnModify( );
  132. pin->DisplayInfo( this );
  133. DrawPanel->Refresh();
  134. }
  135. pin->EnableEditMode( false, m_editPinsPerPartOrConvert );
  136. // Restore pin flags, that can be changed by the dialog editor
  137. pin->ClearFlags();
  138. pin->SetFlags( item_flags );
  139. }
  140. /**
  141. * Clean up after aborting a move pin command.
  142. */
  143. static void AbortPinMove( EDA_DRAW_PANEL* Panel, wxDC* DC )
  144. {
  145. LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) Panel->GetParent();
  146. if( parent == NULL )
  147. return;
  148. LIB_PIN* pin = (LIB_PIN*) parent->GetDrawItem();
  149. if( pin == NULL || pin->Type() != LIB_PIN_T )
  150. return;
  151. pin->ClearFlags();
  152. if( pin->IsNew() )
  153. delete pin;
  154. else
  155. parent->RestoreComponent();
  156. /* clear edit flags */
  157. parent->SetDrawItem( NULL );
  158. parent->SetLastDrawItem( NULL );
  159. Panel->Refresh( true );
  160. }
  161. /**
  162. * Managed cursor callback for placing component pins.
  163. */
  164. void LIB_EDIT_FRAME::PlacePin( wxDC* DC )
  165. {
  166. LIB_PIN* Pin;
  167. LIB_PIN* CurrentPin = (LIB_PIN*) m_drawItem;
  168. bool ask_for_pin = true;
  169. wxPoint newpos;
  170. bool status;
  171. // Some tests
  172. if( (CurrentPin == NULL) || (CurrentPin->Type() != LIB_PIN_T) )
  173. {
  174. wxMessageBox( wxT( "LIB_EDIT_FRAME::PlacePin() error" ) );
  175. return;
  176. }
  177. newpos = GetScreen()->GetCrossHairPosition( true );
  178. // Test for an other pin in same new position:
  179. for( Pin = m_component->GetNextPin(); Pin != NULL; Pin = m_component->GetNextPin( Pin ) )
  180. {
  181. if( Pin == CurrentPin || newpos != Pin->GetPosition() || Pin->GetFlags() )
  182. continue;
  183. if( ask_for_pin && SynchronizePins() )
  184. {
  185. DrawPanel->m_IgnoreMouseEvents = true;
  186. status =
  187. IsOK( this, _( "This position is already occupied by \
  188. another pin. Continue?" ) );
  189. DrawPanel->MoveCursorToCrossHair();
  190. DrawPanel->m_IgnoreMouseEvents = false;
  191. if( !status )
  192. return;
  193. else
  194. ask_for_pin = false;
  195. }
  196. }
  197. // Create Undo from GetTempCopyComponent() if exists ( i.e. after a pin move)
  198. // or from m_component (pin add ...)
  199. if( GetTempCopyComponent() )
  200. SaveCopyInUndoList( GetTempCopyComponent() );
  201. else
  202. SaveCopyInUndoList( m_component );
  203. DrawPanel->SetMouseCapture( NULL, NULL );
  204. OnModify();
  205. CurrentPin->SetPosition( newpos );
  206. if( CurrentPin->IsNew() )
  207. {
  208. LastPinOrient = CurrentPin->GetOrientation();
  209. LastPinType = CurrentPin->GetType();
  210. LastPinShape = CurrentPin->GetShape();
  211. if( SynchronizePins() )
  212. CreateImagePins( CurrentPin, m_unit, m_convert, m_showDeMorgan );
  213. m_lastDrawItem = CurrentPin;
  214. m_component->AddDrawItem( m_drawItem );
  215. }
  216. /* Put linked pins in new position, and clear flags */
  217. for( Pin = m_component->GetNextPin(); Pin != NULL; Pin = m_component->GetNextPin( Pin ) )
  218. {
  219. if( Pin->GetFlags() == 0 )
  220. continue;
  221. Pin->SetPosition( CurrentPin->GetPosition() );
  222. Pin->ClearFlags();
  223. }
  224. DrawPanel->CrossHairOff( DC );
  225. bool showPinText = true;
  226. CurrentPin->Draw( DrawPanel, DC, wxPoint( 0, 0 ), -1, GR_DEFAULT_DRAWMODE,
  227. &showPinText, DefaultTransform );
  228. DrawPanel->CrossHairOn( DC );
  229. m_drawItem = NULL;
  230. }
  231. /**
  232. * Prepare the displacement of a pin
  233. *
  234. * Locate the pin pointed to by the cursor, and set the cursor management
  235. * function move the pin.
  236. */
  237. void LIB_EDIT_FRAME::StartMovePin( wxDC* DC )
  238. {
  239. LIB_PIN* Pin;
  240. LIB_PIN* CurrentPin = (LIB_PIN*) m_drawItem;
  241. wxPoint startPos;
  242. TempCopyComponent();
  243. /* Mark pins for moving. */
  244. Pin = m_component->GetNextPin();
  245. for( ; Pin != NULL; Pin = m_component->GetNextPin( Pin ) )
  246. {
  247. Pin->ClearFlags();
  248. if( Pin == CurrentPin )
  249. continue;
  250. if( ( Pin->GetPosition() == CurrentPin->GetPosition() )
  251. && ( Pin->GetOrientation() == CurrentPin->GetOrientation() )
  252. && SynchronizePins() )
  253. Pin->SetFlags( IS_LINKED | IS_MOVED );
  254. }
  255. CurrentPin->SetFlags( IS_LINKED | IS_MOVED );
  256. PinPreviousPos = OldPos = CurrentPin->GetPosition();
  257. startPos.x = OldPos.x;
  258. startPos.y = -OldPos.y;
  259. DrawPanel->CrossHairOff( DC );
  260. GetScreen()->SetCrossHairPosition( startPos );
  261. DrawPanel->MoveCursorToCrossHair();
  262. CurrentPin->DisplayInfo( this );
  263. DrawPanel->SetMouseCapture( DrawMovePin, AbortPinMove );
  264. DrawPanel->CrossHairOn( DC );
  265. }
  266. /* Move pin to the current mouse position. This function is called by the
  267. * cursor management code. */
  268. static void DrawMovePin( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  269. bool aErase )
  270. {
  271. LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) aPanel->GetParent();
  272. if( parent == NULL )
  273. return;
  274. LIB_PIN* CurrentPin = (LIB_PIN*) parent->GetDrawItem();
  275. if( CurrentPin == NULL || CurrentPin->Type() != LIB_PIN_T )
  276. return;
  277. wxPoint pinpos = CurrentPin->GetPosition();
  278. bool showPinText = true;
  279. /* Erase pin in old position */
  280. if( aErase )
  281. {
  282. CurrentPin->SetPosition( PinPreviousPos );
  283. CurrentPin->Draw( aPanel, aDC, wxPoint( 0, 0 ), -1, g_XorMode,
  284. &showPinText, DefaultTransform );
  285. }
  286. /* Redraw pin in new position */
  287. CurrentPin->SetPosition( aPanel->GetScreen()->GetCrossHairPosition( true ) );
  288. CurrentPin->Draw( aPanel, aDC, wxPoint( 0, 0 ), -1, g_XorMode, &showPinText, DefaultTransform );
  289. PinPreviousPos = CurrentPin->GetPosition();
  290. /* Keep the original position for existing pin (for Undo command)
  291. * and the current position for a new pin */
  292. if( !CurrentPin->IsNew() )
  293. CurrentPin->SetPosition( pinpos );
  294. }
  295. /*
  296. * Create a new pin.
  297. */
  298. void LIB_EDIT_FRAME::CreatePin( wxDC* DC )
  299. {
  300. LIB_PIN* pin;
  301. bool showPinText = true;
  302. if( m_component == NULL )
  303. return;
  304. m_component->ClearStatus();
  305. pin = new LIB_PIN( m_component );
  306. m_drawItem = pin;
  307. pin->SetFlags( IS_NEW );
  308. pin->SetUnit( m_unit );
  309. pin->SetConvert( m_convert );
  310. /* Flag pins to consider */
  311. if( SynchronizePins() )
  312. pin->SetFlags( IS_LINKED );
  313. pin->SetPosition( GetScreen()->GetCrossHairPosition( true ) );
  314. pin->SetLength( LastPinLength );
  315. pin->SetOrientation( LastPinOrient );
  316. pin->SetType( LastPinType );
  317. pin->SetShape( LastPinShape );
  318. pin->SetNameTextSize( LastPinNameSize );
  319. pin->SetNumberTextSize( LastPinNumSize );
  320. pin->SetConvert( LastPinCommonConvert ? 0 : m_convert );
  321. pin->SetUnit( LastPinCommonUnit ? 0 : m_unit );
  322. pin->SetVisible( LastPinVisible );
  323. PinPreviousPos = pin->GetPosition();
  324. DrawPanel->m_IgnoreMouseEvents = true;
  325. wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
  326. cmd.SetId( ID_LIBEDIT_EDIT_PIN );
  327. GetEventHandler()->ProcessEvent( cmd );
  328. DrawPanel->MoveCursorToCrossHair();
  329. DrawPanel->m_IgnoreMouseEvents = false;
  330. if( pin->GetFlags() & IS_CANCELLED )
  331. {
  332. deleteItem( DC );
  333. }
  334. else
  335. {
  336. ClearTempCopyComponent();
  337. DrawPanel->SetMouseCapture( DrawMovePin, AbortPinMove );
  338. if( DC )
  339. pin->Draw( DrawPanel, DC, wxPoint( 0, 0 ), -1, wxCOPY, &showPinText,
  340. DefaultTransform );
  341. }
  342. }
  343. void LIB_EDIT_FRAME::CreateImagePins( LIB_PIN* aPin, int aUnit, int aConvert, bool aDeMorgan )
  344. {
  345. int ii;
  346. LIB_PIN* NewPin;
  347. if( !SynchronizePins() )
  348. return;
  349. /* Create "convert" pin at the current position. */
  350. if( aDeMorgan && ( aPin->GetConvert() != 0 ) )
  351. {
  352. NewPin = (LIB_PIN*) aPin->Clone();
  353. if( aPin->GetConvert() > 1 )
  354. NewPin->SetConvert( 1 );
  355. else
  356. NewPin->SetConvert( 2 );
  357. aPin->GetParent()->AddDrawItem( NewPin );
  358. }
  359. for( ii = 1; ii <= aPin->GetParent()->GetPartCount(); ii++ )
  360. {
  361. if( ii == aUnit || aPin->GetUnit() == 0 )
  362. continue; /* Pin common to all units. */
  363. NewPin = (LIB_PIN*) aPin->Clone();
  364. if( aConvert != 0 )
  365. NewPin->SetConvert( 1 );
  366. NewPin->SetUnit( ii );
  367. aPin->GetParent()->AddDrawItem( NewPin );
  368. if( !( aDeMorgan && ( aPin->GetConvert() != 0 ) ) )
  369. continue;
  370. NewPin = (LIB_PIN*) aPin->Clone();
  371. NewPin->SetConvert( 2 );
  372. if( aPin->GetUnit() != 0 )
  373. NewPin->SetUnit( ii );
  374. aPin->GetParent()->AddDrawItem( NewPin );
  375. }
  376. }
  377. /* Depending on "id":
  378. * - Change pin text size (name or num) (range 10 .. 1000 mil)
  379. * - Change pin length.
  380. *
  381. * If Pin is selected ( .m_flag == IS_SELECTED ) only the other selected
  382. * pins are modified
  383. */
  384. void LIB_EDIT_FRAME::GlobalSetPins( wxDC* DC, LIB_PIN* MasterPin, int id )
  385. {
  386. LIB_PIN* Pin;
  387. bool selected = MasterPin->IsSelected();
  388. bool showPinText = true;
  389. if( ( m_component == NULL ) || ( MasterPin == NULL ) )
  390. return;
  391. if( MasterPin->Type() != LIB_PIN_T )
  392. return;
  393. OnModify( );
  394. Pin = m_component->GetNextPin();
  395. for( ; Pin != NULL; Pin = m_component->GetNextPin( Pin ) )
  396. {
  397. if( ( Pin->GetConvert() ) && ( Pin->GetConvert() != m_convert ) )
  398. continue;
  399. // Is it the "selected mode" ?
  400. if( selected && !Pin->IsSelected() )
  401. continue;
  402. Pin->Draw( DrawPanel, DC, wxPoint( 0, 0 ), -1, g_XorMode, &showPinText, DefaultTransform );
  403. switch( id )
  404. {
  405. case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNUMSIZE_ITEM:
  406. Pin->SetNumberTextSize( MasterPin->GetNumberTextSize() );
  407. break;
  408. case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINNAMESIZE_ITEM:
  409. Pin->SetNameTextSize( MasterPin->GetNameTextSize() );
  410. break;
  411. case ID_POPUP_LIBEDIT_PIN_GLOBAL_CHANGE_PINSIZE_ITEM:
  412. Pin->SetLength( MasterPin->GetLength() );
  413. break;
  414. }
  415. Pin->Draw( DrawPanel, DC, wxPoint( 0, 0 ), -1, GR_DEFAULT_DRAWMODE, &showPinText,
  416. DefaultTransform );
  417. }
  418. }
  419. /* Create a new pin based on the previous pin with an incremented pin number. */
  420. void LIB_EDIT_FRAME::RepeatPinItem( wxDC* DC, LIB_PIN* SourcePin )
  421. {
  422. LIB_PIN* Pin;
  423. wxString msg;
  424. if( m_component == NULL || SourcePin == NULL || SourcePin->Type() != LIB_PIN_T )
  425. return;
  426. Pin = (LIB_PIN*) SourcePin->Clone();
  427. Pin->ClearFlags();
  428. Pin->SetFlags( IS_NEW );
  429. Pin->SetPosition( Pin->GetPosition() + wxPoint( g_RepeatStep.x, -g_RepeatStep.y ) );
  430. wxString nextName = Pin->GetName();
  431. IncrementLabelMember( nextName );
  432. Pin->SetName( nextName );
  433. Pin->ReturnPinStringNum( msg );
  434. IncrementLabelMember( msg );
  435. Pin->SetPinNumFromString( msg );
  436. m_drawItem = Pin;
  437. if( SynchronizePins() )
  438. Pin->SetFlags( IS_LINKED );
  439. wxPoint savepos = GetScreen()->GetCrossHairPosition();
  440. DrawPanel->CrossHairOff( DC );
  441. GetScreen()->SetCrossHairPosition( wxPoint( Pin->GetPosition().x, -Pin->GetPosition().y ) );
  442. // Add this new pin in list, and creates pins for others parts if needed
  443. m_drawItem = Pin;
  444. ClearTempCopyComponent();
  445. PlacePin( DC );
  446. m_lastDrawItem = Pin;
  447. GetScreen()->SetCrossHairPosition( savepos );
  448. DrawPanel->CrossHairOn( DC );
  449. Pin->DisplayInfo( this );
  450. OnModify( );
  451. }
  452. /* helper function to sort pins by pin num */
  453. bool sort_by_pin_number( const LIB_PIN* ref, const LIB_PIN* tst )
  454. {
  455. int test = ref->GetNumber() - tst->GetNumber();
  456. if( test == 0 )
  457. {
  458. test = ref->GetConvert() - tst->GetConvert();
  459. }
  460. if( test == 0 )
  461. {
  462. test = ref->GetUnit() - tst->GetUnit();
  463. }
  464. return test < 0;
  465. }
  466. /* Test for duplicate pins and off grid pins:
  467. * Pins are considered off grid when they are not on the 25 mils grid
  468. * A grid smaller than 25 mils must be used only to build graphic shapes.
  469. */
  470. void LIB_EDIT_FRAME::OnCheckComponent( wxCommandEvent& event )
  471. {
  472. #define MIN_GRID_SIZE 25
  473. int dup_error;
  474. int offgrid_error;
  475. LIB_PIN* Pin;
  476. LIB_PINS PinList;
  477. wxString msg;
  478. wxString aux_msg;
  479. if( m_component == NULL )
  480. return;
  481. m_component->GetPins( PinList );
  482. if( PinList.size() == 0 )
  483. {
  484. DisplayInfoMessage( this, _( "No pins!" ) );
  485. return;
  486. }
  487. // Sort pins by pin num, so 2 duplicate pins
  488. // (pins with the same number) will be consecutive in list
  489. sort( PinList.begin(), PinList.end(), sort_by_pin_number );
  490. // Test for duplicates:
  491. dup_error = 0;
  492. DIALOG_DISPLAY_HTML_TEXT_BASE error_display( this, wxID_ANY,
  493. _( "Marker Information" ),
  494. wxDefaultPosition,
  495. wxSize( 750, 600 ) );
  496. for( unsigned ii = 1; ii < PinList.size(); ii++ )
  497. {
  498. wxString stringPinNum, stringCurrPinNum;
  499. LIB_PIN* curr_pin = PinList[ii];
  500. Pin = PinList[ii - 1];
  501. if( Pin->GetNumber() != curr_pin->GetNumber()
  502. || Pin->GetConvert() != curr_pin->GetConvert()
  503. || Pin->GetUnit() != curr_pin->GetUnit() )
  504. continue;
  505. dup_error++;
  506. Pin->ReturnPinStringNum( stringPinNum );
  507. curr_pin->ReturnPinStringNum( stringCurrPinNum );
  508. msg.Printf( _( "<b>Duplicate pin %s</b> \"%s\" at location <b>(%.3f, \
  509. %.3f)</b> conflicts with pin %s \"%s\" at location <b>(%.3f, %.3f)</b>" ),
  510. GetChars( stringCurrPinNum ),
  511. GetChars( curr_pin->GetName() ),
  512. (float) curr_pin->GetPosition().x / 1000.0,
  513. (float) -curr_pin->GetPosition().y / 1000.0,
  514. GetChars( stringPinNum ),
  515. GetChars( Pin->GetName() ),
  516. (float) Pin->GetPosition().x / 1000.0,
  517. (float) -Pin->GetPosition().y / 1000.0 );
  518. if( m_component->GetPartCount() > 1 )
  519. {
  520. aux_msg.Printf( _( " in part %c" ), 'A' + curr_pin->GetUnit() );
  521. msg += aux_msg;
  522. }
  523. if( m_showDeMorgan )
  524. {
  525. if( curr_pin->GetConvert() )
  526. msg += _( " of converted" );
  527. else
  528. msg += _( " of normal" );
  529. }
  530. msg += wxT( ".<br>" );
  531. error_display.m_htmlWindow->AppendToPage( msg );
  532. }
  533. // Test for off grid pins:
  534. offgrid_error = 0;
  535. for( unsigned ii = 0; ii < PinList.size(); ii++ )
  536. {
  537. Pin = PinList[ii];
  538. if( ( (Pin->GetPosition().x % MIN_GRID_SIZE) == 0 ) &&
  539. ( (Pin->GetPosition().y % MIN_GRID_SIZE) == 0 ) )
  540. continue;
  541. // A pin is found here off grid
  542. offgrid_error++;
  543. wxString stringPinNum;
  544. Pin->ReturnPinStringNum( stringPinNum );
  545. msg.Printf( _( "<b>Off grid pin %s</b> \"%s\" at location <b>(%.3f, %.3f)</b>" ),
  546. GetChars( stringPinNum ),
  547. GetChars( Pin->GetName() ),
  548. (float) Pin->GetPosition().x / 1000.0,
  549. (float) -Pin->GetPosition().y / 1000.0 );
  550. if( m_component->GetPartCount() > 1 )
  551. {
  552. aux_msg.Printf( _( " in part %c" ), 'A' + Pin->GetUnit() );
  553. msg += aux_msg;
  554. }
  555. if( m_showDeMorgan )
  556. {
  557. if( Pin->GetConvert() )
  558. msg += _( " of converted" );
  559. else
  560. msg += _( " of normal" );
  561. }
  562. msg += wxT( ".<br>" );
  563. error_display.m_htmlWindow->AppendToPage( msg );
  564. }
  565. if( !dup_error && !offgrid_error )
  566. DisplayInfoMessage( this, _( "No off grid or duplicate pins were found." ) );
  567. else
  568. error_display.ShowModal();
  569. }