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.

712 lines
21 KiB

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