KiCad PCB EDA Suite
dialog_lib_edit_pin_table.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
25 #include "lib_pin.h"
26 #include "pin_number.h"
27 #include "grid_tricks.h"
29 #include <widgets/wx_grid.h>
30 #include <queue>
31 #include <base_units.h>
32 #include <bitmaps.h>
33 #include <wx/bmpcbox.h>
34 #include <kiface_i.h>
35 #include <kicad_string.h>
36 #include <confirm.h>
37 #include <lib_edit_frame.h>
38 
39 #define PinTableShownColumnsKey wxT( "PinTableShownColumns" )
40 
41 
42 static std::vector<BITMAP_DEF> g_typeIcons;
43 static wxArrayString g_typeNames;
44 
45 static std::vector<BITMAP_DEF> g_shapeIcons;
46 static wxArrayString g_shapeNames;
47 
48 static std::vector<BITMAP_DEF> g_orientationIcons;
49 static wxArrayString g_orientationNames;
50 
51 
52 class PIN_TABLE_DATA_MODEL : public wxGridTableBase
53 {
54 
55 private:
56  // Because the rows of the grid can either be a single pin or a group of pins, the
57  // data model is a 2D vector. If we're in the single pin case, each row's LIB_PINS
58  // contains only a single pin.
59  std::vector<LIB_PINS> m_rows;
60 
62  bool m_edited;
63 
64 public:
66  m_userUnits( aUserUnits ), m_edited( false )
67  {}
68 
69  int GetNumberRows() override { return (int) m_rows.size(); }
70  int GetNumberCols() override { return COL_COUNT; }
71 
72  wxString GetColLabelValue( int aCol ) override
73  {
74  switch( aCol )
75  {
76  case COL_NUMBER: return _( "Number" );
77  case COL_NAME: return _( "Name" );
78  case COL_TYPE: return _( "Electrical Type" );
79  case COL_SHAPE: return _( "Graphic Style" );
80  case COL_ORIENTATION: return _( "Orientation" );
81  case COL_NUMBER_SIZE: return _( "Number Text Size" );
82  case COL_NAME_SIZE: return _( "Name Text Size" );
83  case COL_LENGTH: return _( "Length" );
84  case COL_POSX: return _( "X Position" );
85  case COL_POSY: return _( "Y Position" );
86  default: wxFAIL; return wxEmptyString;
87  }
88  }
89 
90  bool IsEmptyCell( int row, int col ) override
91  {
92  return false; // don't allow adjacent cell overflow, even if we are actually empty
93  }
94 
95  wxString GetValue( int aRow, int aCol ) override
96  {
97  return GetValue( m_rows[ aRow ], aCol, m_userUnits );
98  }
99 
100  static wxString GetValue( const LIB_PINS& pins, int aCol, EDA_UNITS_T aUserUnits )
101  {
102  wxString fieldValue;
103 
104  if( pins.empty())
105  return fieldValue;
106 
107  for( LIB_PIN* pin : pins )
108  {
109  wxString val;
110 
111  switch( aCol )
112  {
113  case COL_NUMBER:
114  val = pin->GetNumber();
115  break;
116  case COL_NAME:
117  val = pin->GetName();
118  break;
119  case COL_TYPE:
120  val = g_typeNames[ pin->GetType() ];
121  break;
122  case COL_SHAPE:
123  val = g_shapeNames[ pin->GetShape() ];
124  break;
125  case COL_ORIENTATION:
126  val = g_orientationNames[ LIB_PIN::GetOrientationIndex( pin->GetOrientation() ) ];
127  break;
128  case COL_NUMBER_SIZE:
129  val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true, true );
130  break;
131  case COL_NAME_SIZE:
132  val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true, true );
133  break;
134  case COL_LENGTH:
135  val = StringFromValue( aUserUnits, pin->GetLength(), true );
136  break;
137  case COL_POSX:
138  val = StringFromValue( aUserUnits, pin->GetPosition().x, true );
139  break;
140  case COL_POSY:
141  val = StringFromValue( aUserUnits, pin->GetPosition().y, true );
142  break;
143  default:
144  wxFAIL;
145  break;
146  }
147 
148  if( aCol == COL_NUMBER )
149  {
150  if( fieldValue.length() )
151  fieldValue += wxT( ", " );
152  fieldValue += val;
153  }
154  else
155  {
156  if( !fieldValue.Length() )
157  fieldValue = val;
158  else if( val != fieldValue )
159  fieldValue = INDETERMINATE;
160  }
161  }
162 
163  return fieldValue;
164  }
165 
166  void SetValue( int aRow, int aCol, const wxString &aValue ) override
167  {
168  if( aValue == INDETERMINATE )
169  return;
170 
171  LIB_PINS pins = m_rows[ aRow ];
172 
173  for( LIB_PIN* pin : pins )
174  {
175  switch( aCol )
176  {
177  case COL_NUMBER:
178  pin->SetNumber( aValue );
179  break;
180  case COL_NAME:
181  pin->SetName( aValue );
182  break;
183  case COL_TYPE:
184  if( g_typeNames.Index( aValue ) != wxNOT_FOUND )
185  pin->SetType( (ELECTRICAL_PINTYPE) g_typeNames.Index( aValue ), false );
186 
187  break;
188  case COL_SHAPE:
189  if( g_shapeNames.Index( aValue ) != wxNOT_FOUND )
190  pin->SetShape( (GRAPHIC_PINSHAPE) g_shapeNames.Index( aValue ) );
191 
192  break;
193  case COL_ORIENTATION:
194  if( g_orientationNames.Index( aValue ) != wxNOT_FOUND )
195  pin->SetOrientation( LIB_PIN::GetOrientationCode(
196  g_orientationNames.Index( aValue ) ), false );
197  break;
198  case COL_NUMBER_SIZE:
199  pin->SetNumberTextSize( ValueFromString( m_userUnits, aValue, true ) );
200  break;
201  case COL_NAME_SIZE:
202  pin->SetNameTextSize( ValueFromString( m_userUnits, aValue, true ) );
203  break;
204  case COL_LENGTH:
205  pin->SetLength( ValueFromString( m_userUnits, aValue ) );
206  break;
207  case COL_POSX:
208  pin->SetPinPosition( wxPoint( ValueFromString( m_userUnits, aValue ),
209  pin->GetPosition().y ) );
210  break;
211  case COL_POSY:
212  pin->SetPinPosition( wxPoint( pin->GetPosition().x,
213  ValueFromString( m_userUnits, aValue ) ) );
214  break;
215  default:
216  wxFAIL;
217  break;
218  }
219  }
220 
221  m_edited = true;
222  }
223 
224  static int findRow( const std::vector<LIB_PINS>& aRowSet, const wxString& aName )
225  {
226  for( size_t i = 0; i < aRowSet.size(); ++i )
227  {
228  if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName )
229  return i;
230  }
231 
232  return -1;
233  }
234 
235  static bool compare( const LIB_PINS& lhs, const LIB_PINS& rhs,
236  int sortCol, bool ascending, EDA_UNITS_T units )
237  {
238  wxString lhStr = GetValue( lhs, sortCol, units );
239  wxString rhStr = GetValue( rhs, sortCol, units );
240 
241  if( lhStr == rhStr )
242  {
243  // Secondary sort key is always COL_NUMBER
244  sortCol = COL_NUMBER;
245  lhStr = GetValue( lhs, sortCol, units );
246  rhStr = GetValue( rhs, sortCol, units );
247  }
248 
249  bool res;
250 
251  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
252  // to get the opposite sort. i.e. ~(a<b) != (a>b)
253  auto cmp = [ ascending ]( const auto a, const auto b )
254  {
255  if( ascending )
256  return a < b;
257  else
258  return b < a;
259  };
260 
261  switch( sortCol )
262  {
263  case COL_NUMBER:
264  case COL_NAME:
265  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
266  break;
267  case COL_NUMBER_SIZE:
268  case COL_NAME_SIZE:
269  res = cmp( ValueFromString( units, lhStr, true ),
270  ValueFromString( units, rhStr, true ) );
271  break;
272  case COL_LENGTH:
273  case COL_POSX:
274  case COL_POSY:
275  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
276  break;
277  default:
278  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
279  break;
280  }
281 
282  return res;
283  }
284 
285  void RebuildRows( LIB_PINS& aPins, bool groupByName )
286  {
287  if ( GetView() )
288  {
289  // Commit any pending in-place edits before the row gets moved out from under
290  // the editor.
291  dynamic_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
292 
293  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
294  GetView()->ProcessTableMessage( msg );
295  }
296 
297  m_rows.clear();
298 
299  for( LIB_PIN* pin : aPins )
300  {
301  int rowIndex = -1;
302 
303  if( groupByName )
304  rowIndex = findRow( m_rows, pin->GetName() );
305 
306  if( rowIndex < 0 )
307  {
308  m_rows.emplace_back( LIB_PINS() );
309  rowIndex = m_rows.size() - 1;
310  }
311 
312  m_rows[ rowIndex ].push_back( pin );
313  }
314 
315  int sortCol = 0;
316  bool ascending = true;
317 
318  if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
319  {
320  sortCol = GetView()->GetSortingColumn();
321  ascending = GetView()->IsSortOrderAscending();
322  }
323 
324  for( LIB_PINS& row : m_rows )
325  SortPins( row );
326 
327  SortRows( sortCol, ascending );
328 
329  if ( GetView() )
330  {
331  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
332  GetView()->ProcessTableMessage( msg );
333  }
334  }
335 
336  void SortRows( int aSortCol, bool ascending )
337  {
338  std::sort( m_rows.begin(), m_rows.end(),
339  [ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
340  {
341  return compare( lhs, rhs, aSortCol, ascending, m_userUnits );
342  } );
343  }
344 
345  void SortPins( LIB_PINS& aRow )
346  {
347  std::sort( aRow.begin(), aRow.end(),
348  []( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
349  {
350  return PinNumbers::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
351  } );
352  }
353 
354  void AppendRow( LIB_PIN* aPin )
355  {
356  LIB_PINS row;
357  row.push_back( aPin );
358  m_rows.push_back( row );
359 
360  if ( GetView() )
361  {
362  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
363  GetView()->ProcessTableMessage( msg );
364  }
365  }
366 
367  LIB_PINS RemoveRow( int aRow )
368  {
369  LIB_PINS removedRow = m_rows[ aRow ];
370 
371  m_rows.erase( m_rows.begin() + aRow );
372 
373  if ( GetView() )
374  {
375  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
376  GetView()->ProcessTableMessage( msg );
377  }
378 
379  return removedRow;
380  }
381 
382  bool IsEdited()
383  {
384  return m_edited;
385  }
386 };
387 
388 
391  m_editFrame( parent ),
392  m_part( aPart )
393 {
395 
396  if( g_typeNames.empty())
397  {
398  for( unsigned i = 0; i < PINTYPE_COUNT; ++i )
399  g_typeIcons.push_back( GetBitmap( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
400  for( unsigned i = 0; i < PINTYPE_COUNT; ++i )
401  g_typeNames.push_back( GetText( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
402  g_typeNames.push_back( INDETERMINATE );
403 
404  for( unsigned i = 0; i < PINSHAPE_COUNT; ++i )
405  g_shapeIcons.push_back( GetBitmap( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
406  for( unsigned i = 0; i < PINSHAPE_COUNT; ++i )
407  g_shapeNames.push_back( GetText( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
408  g_shapeNames.push_back( INDETERMINATE );
409 
410  for( unsigned i = 0; i < LIB_PIN::GetOrientationNames().size(); ++i )
413  g_orientationNames.push_back( INDETERMINATE );
414  }
415 
417 
418  // Save original columns widths so we can do proportional sizing.
419  for( int i = 0; i < COL_COUNT; ++i )
420  m_originalColWidths[ i ] = m_grid->GetColSize( i );
421 
422  // Give a bit more room for combobox editors
423  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
424 
426  m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
427 
428  // Show/hide columns according to the user's preference
429  m_config->Read( PinTableShownColumnsKey, &m_columnsShown, wxT( "0 1 2 3 4 8 9" ) );
431 
432  // Set special attributes
433  wxGridCellAttr* attr;
434 
435  attr = new wxGridCellAttr;
436  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_typeIcons, g_typeNames ) );
437  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_typeIcons, g_typeNames ) );
438  m_grid->SetColAttr( COL_TYPE, attr );
439 
440  attr = new wxGridCellAttr;
441  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_shapeIcons, g_shapeNames ) );
442  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_shapeIcons, g_shapeNames ) );
443  m_grid->SetColAttr( COL_SHAPE, attr );
444 
445  attr = new wxGridCellAttr;
448  m_grid->SetColAttr( COL_ORIENTATION, attr );
449 
450  /* Right-aligned position values look much better, but only MSW and GTK2+
451  * currently support righ-aligned textEditCtrls, so the text jumps on all
452  * the other platforms when you edit it.
453  attr = new wxGridCellAttr;
454  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
455  m_grid->SetColAttr( COL_POSX, attr );
456 
457  attr = new wxGridCellAttr;
458  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
459  m_grid->SetColAttr( COL_POSY, attr );
460  */
461 
462  m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
463  m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );
464  m_refreshButton->SetBitmap( KiBitmap( refresh_xpm ) );
465 
466  GetSizer()->SetSizeHints(this);
467  Centre();
468 
469  m_ButtonsOK->SetDefault();
470  m_initialized = true;
471  m_modified = false;
472  m_width = 0;
473 
474  // Connect Events
475  m_grid->Connect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
476 }
477 
478 
480 {
482 
483  // Disconnect Events
484  m_grid->Disconnect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
485 
486  // Prevents crash bug in wxGrid's d'tor
488 
489  // Delete the GRID_TRICKS.
490  m_grid->PopEventHandler( true );
491 
492  // This is our copy of the pins. If they were transfered to the part on an OK, then
493  // m_pins will already be empty.
494  for( auto pin : m_pins )
495  delete pin;
496 }
497 
498 
500 {
501  // Make a copy of the pins for editing
502  for( LIB_PIN* pin = m_part->GetNextPin( nullptr ); pin; pin = m_part->GetNextPin( pin ) )
503  m_pins.push_back( new LIB_PIN( *pin ) );
504 
505  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
506 
507  updateSummary();
508 
509  return true;
510 }
511 
512 
514 {
515  if( !m_grid->CommitPendingChanges() )
516  return false;
517 
518  // Delete the part's pins
519  while( LIB_PIN* pin = m_part->GetNextPin( nullptr ) )
520  m_part->RemoveDrawItem( pin );
521 
522  // Transfer our pins to the part
523  for( LIB_PIN* pin : m_pins )
524  {
525  pin->SetParent( m_part );
526  m_part->AddDrawItem( pin );
527  }
528 
529  m_pins.clear();
530 
531  return true;
532 }
533 
534 
535 void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent )
536 {
537  int sortCol = aEvent.GetCol();
538  bool ascending;
539 
540  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
541  // event, and if we ask it will give us pre-event info.
542  if( m_grid->IsSortingBy( sortCol ) )
543  // same column; invert ascending
544  ascending = !m_grid->IsSortOrderAscending();
545  else
546  // different column; start with ascending
547  ascending = true;
548 
549  m_dataModel->SortRows( sortCol, ascending );
550 }
551 
552 
553 void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
554 {
555  if( !m_grid->CommitPendingChanges() )
556  return;
557 
558  LIB_PIN* newPin = new LIB_PIN( nullptr );
559 
560  if( m_pins.size() > 0 )
561  {
562  LIB_PIN* last = m_pins.back();
563 
564  newPin->SetOrientation( last->GetOrientation() );
565  newPin->SetType( last->GetType() );
566  newPin->SetShape( last->GetShape() );
567 
568  wxPoint pos = last->GetPosition();
569 
570  if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
571  pos.y -= m_editFrame->GetRepeatPinStep();
572  else
573  pos.x += m_editFrame->GetRepeatPinStep();
574 
575  newPin->SetPosition( pos );
576  }
577 
578  m_pins.push_back( newPin );
579 
580  m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] );
581 
582  m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 );
583  m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 );
584 
585  m_grid->EnableCellEditControl( true );
586  m_grid->ShowCellEditControl();
587 
588  updateSummary();
589 }
590 
591 
592 void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
593 {
594  if( !m_grid->CommitPendingChanges() )
595  return;
596 
597  if( m_pins.size() == 0 ) // empty table
598  return;
599 
600  int curRow = m_grid->GetGridCursorRow();
601 
602  if( curRow < 0 )
603  return;
604 
605  LIB_PINS removedRow = m_dataModel->RemoveRow( curRow );
606 
607  for( auto pin : removedRow )
608  m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
609 
610  curRow = std::max( 0, curRow - 1 );
611  m_grid->MakeCellVisible( curRow, m_grid->GetGridCursorCol() );
612  m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
613 
614  updateSummary();
615 }
616 
617 
618 void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event )
619 {
620  updateSummary();
621 }
622 
623 
625 {
626  if( !m_grid->CommitPendingChanges() )
627  return;
628 
629  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
630 
631  adjustGridColumns( m_grid->GetRect().GetWidth() );
632 }
633 
634 
636 {
637  m_width = aWidth;
638 
639  // Account for scroll bars
640  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
641 
642  wxGridUpdateLocker deferRepaintsTillLeavingScope;
643 
644  // The Number and Name columns must be at least wide enough to hold their contents, but
645  // no less wide than their original widths.
646 
647  m_grid->AutoSizeColumn( COL_NUMBER );
648 
649  if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] )
650  m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] );
651 
652  m_grid->AutoSizeColumn( COL_NAME );
653 
654  if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] )
655  m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] );
656 
657  // If the grid is still wider than the columns, then stretch the Number and Name columns
658  // to fit.
659 
660  for( int i = 0; i < COL_COUNT; ++i )
661  aWidth -= m_grid->GetColSize( i );
662 
663  if( aWidth > 0 )
664  {
665  m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + aWidth / 2 );
666  m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + aWidth / 2 );
667  }
668 }
669 
670 
671 void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event )
672 {
673  auto new_size = event.GetSize().GetX();
674 
675  if( m_initialized && m_width != new_size )
676  {
677  adjustGridColumns( new_size );
678  }
679 
680  // Always propagate for a grid repaint (needed if the height changes, as well as width)
681  event.Skip();
682 }
683 
684 
685 void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
686 {
687  wxString columnsShown = m_grid->GetShownColumns();
688 
689  if( columnsShown != m_columnsShown )
690  {
691  m_columnsShown = columnsShown;
692 
693  if( !m_grid->IsCellEditControlShown() )
694  adjustGridColumns( m_grid->GetRect().GetWidth() );
695  }
696 }
697 
698 
699 void DIALOG_LIB_EDIT_PIN_TABLE::OnCancel( wxCommandEvent& event )
700 {
701  Close();
702 }
703 
704 
705 void DIALOG_LIB_EDIT_PIN_TABLE::OnClose( wxCloseEvent& event )
706 {
707  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
708  m_grid->CommitPendingChanges( true );
709 
710  if( m_dataModel->IsEdited() )
711  {
712  if( !HandleUnsavedChanges( this, wxEmptyString,
713  [&]()->bool { return TransferDataFromWindow(); } ) )
714  {
715  event.Veto();
716  return;
717  }
718  }
719 
720  if( IsQuasiModal() )
721  EndQuasiModal( wxID_CANCEL );
722  else if( IsModal() )
723  EndModal( wxID_CANCEL );
724  else
725  event.Skip();
726 }
727 
728 
730 {
731  PinNumbers pinNumbers;
732 
733  for( LIB_PIN* pin : m_pins )
734  {
735  if( pin->GetNumber().Length() )
736  pinNumbers.insert( pin->GetNumber() );
737  }
738 
739  m_summary->SetLabel( pinNumbers.GetSummary() );
740 }
static int Compare(PinNumber const &lhs, PinNumber const &rhs)
Definition: pin_number.cpp:111
static wxArrayString g_typeNames
static std::vector< BITMAP_DEF > g_orientationIcons
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:201
void OnClose(wxCloseEvent &event) override
static wxArrayString g_shapeNames
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:354
static std::vector< BITMAP_DEF > g_shapeIcons
void OnSize(wxSizeEvent &event) override
void SetPosition(const wxPoint &aPosition)
Definition: lib_item.h:252
static int GetOrientationIndex(int aCode)
Get the index of the orientation code.
Definition: lib_pin.cpp:1580
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
static wxArrayString GetOrientationNames()
Get a list of pin orientation names.
Definition: lib_pin.cpp:1560
int GetOrientation() const
Definition: lib_pin.h:204
DIALOG_LIB_EDIT_PIN_TABLE(LIB_EDIT_FRAME *parent, LIB_PART *aPart)
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:119
std::vector< LIB_PIN * > LIB_PINS
Helper for defining a list of pin object pointers.
Definition: lib_item.h:55
void SetShape(GRAPHIC_PINSHAPE aShape)
Set the shape of the pin to aShape.
Definition: lib_pin.cpp:299
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:216
void OnAddRow(wxCommandEvent &event) override
wxString GetSummary() const
Definition: pin_number.cpp:71
PIN_TABLE_DATA_MODEL(EDA_UNITS_T aUserUnits)
void OnCellEdited(wxGridEvent &event) override
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
Class GRID_TRICKS is used to add mouse and command handling (such as cut, copy, and paste) to a WX_GR...
Definition: grid_tricks.h:51
static const BITMAP_DEF * GetOrientationSymbols()
Get a list of pin orientation bitmaps for menus and dialogs.
Definition: lib_pin.cpp:1594
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:57
void insert(value_type const &v)
Definition: pin_number.h:57
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
void DestroyTable(wxGridTableBase *aTable)
Work-around for a bug in wxGrid which crashes when deleting the table if the cell edit control was no...
Definition: wx_grid.cpp:88
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
bool m_modified
true when there are unsaved changes
GRAPHIC_PINSHAPE
Definition: pin_shape.h:35
bool IsEmptyCell(int row, int col) override
void SortRows(int aSortCol, bool ascending)
#define INDETERMINATE
void OnRebuildRows(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
Define a library symbol object.
bool IsQuasiModal()
Definition: dialog_shim.h:124
wxString GetText(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:33
static wxArrayString g_orientationNames
void RebuildRows(LIB_PINS &aPins, bool groupByName)
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:172
#define _(s)
static bool compare(const LIB_PINS &lhs, const LIB_PINS &rhs, int sortCol, bool ascending, EDA_UNITS_T units)
wxString GetColLabelValue(int aCol) override
PIN_TABLE_DATA_MODEL * m_dataModel
wxString GetValue(int aRow, int aCol) override
#define PinTableShownColumnsKey
YYCODETYPE lhs
wxPoint GetPosition() const override
Definition: lib_pin.h:427
Class DIALOG_LIB_EDIT_PIN_TABLE_BASE.
LIB_PIN * GetNextPin(LIB_PIN *aItem=NULL)
Return the next pin object from the draw list.
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:101
ELECTRICAL_PINTYPE GetType() const
Get the electrical type of the pin.
Definition: lib_pin.h:232
void EndQuasiModal(int retCode)
static int findRow(const std::vector< LIB_PINS > &aRowSet, const wxString &aName)
The symbol library editor main window.
static wxString GetValue(const LIB_PINS &pins, int aCol, EDA_UNITS_T aUserUnits)
EDA_UNITS_T GetUserUnits() const
Definition: dialog_shim.h:132
void OnDeleteRow(wxCommandEvent &event) override
ELECTRICAL_PINTYPE
The component library pin object electrical types used in ERC tests.
Definition: pin_type.h:37
#define max(a, b)
Definition: auxiliary.h:86
size_t i
Definition: json11.cpp:649
void SetType(ELECTRICAL_PINTYPE aType, bool aTestOtherPins=true)
Set the electrical type of the pin.
Definition: lib_pin.cpp:328
void OnColSort(wxGridEvent &aEvent)
void SetValue(int aRow, int aCol, const wxString &aValue) override
void SetOrientation(int aOrientation, bool aTestOtherPins=true)
Set orientation on the pin.
Definition: lib_pin.cpp:270
static std::vector< BITMAP_DEF > g_typeIcons
BITMAP_DEF GetBitmap(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:70
int GetRepeatPinStep() const
std::vector< LIB_PINS > m_rows
void OnCancel(wxCommandEvent &event) override
EDA_UNITS_T
Definition: common.h:133
long long int ValueFromString(EDA_UNITS_T aUnits, const wxString &aTextValue, bool aUseMils)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:427
wxString StringFromValue(EDA_UNITS_T aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:217
void RemoveDrawItem(LIB_ITEM *aItem)
Remove draw aItem from list.
static int GetOrientationCode(int aIndex)
Get the orientation code by index used to set the pin orientation.
Definition: lib_pin.cpp:1571