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-2021 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 "grid_tricks.h"
26 #include "lib_pin.h"
27 #include "pin_number.h"
28 #include <bitmaps.h>
29 #include <confirm.h>
30 #include <symbol_edit_frame.h>
31 #include <symbol_editor_settings.h>
33 #include <widgets/wx_grid.h>
35 #include <kicad_string.h>
36 
37 class PIN_TABLE_DATA_MODEL : public wxGridTableBase
38 {
39 public:
40  PIN_TABLE_DATA_MODEL( EDA_UNITS aUserUnits ) : m_userUnits( aUserUnits ), m_edited( false )
41  {
42  }
43 
44  int GetNumberRows() override { return (int) m_rows.size(); }
45  int GetNumberCols() override { return COL_COUNT; }
46 
47  wxString GetColLabelValue( int aCol ) override
48  {
49  switch( aCol )
50  {
51  case COL_NUMBER: return _( "Number" );
52  case COL_NAME: return _( "Name" );
53  case COL_TYPE: return _( "Electrical Type" );
54  case COL_SHAPE: return _( "Graphic Style" );
55  case COL_ORIENTATION: return _( "Orientation" );
56  case COL_NUMBER_SIZE: return _( "Number Text Size" );
57  case COL_NAME_SIZE: return _( "Name Text Size" );
58  case COL_LENGTH: return _( "Length" );
59  case COL_POSX: return _( "X Position" );
60  case COL_POSY: return _( "Y Position" );
61  case COL_VISIBLE: return _( "Visible" );
62  default: wxFAIL; return wxEmptyString;
63  }
64  }
65 
66  bool IsEmptyCell( int row, int col ) override
67  {
68  return false; // don't allow adjacent cell overflow, even if we are actually empty
69  }
70 
71  wxString GetValue( int aRow, int aCol ) override
72  {
73  return GetValue( m_rows[ aRow ], aCol, m_userUnits );
74  }
75 
76  static wxString GetValue( const LIB_PINS& pins, int aCol, EDA_UNITS aUserUnits )
77  {
78  wxString fieldValue;
79 
80  if( pins.empty() )
81  return fieldValue;
82 
83  for( LIB_PIN* pin : pins )
84  {
85  wxString val;
86 
87  switch( aCol )
88  {
89  case COL_NUMBER:
90  val = pin->GetNumber();
91  break;
92  case COL_NAME:
93  val = pin->GetName();
94  break;
95  case COL_TYPE:
96  val = PinTypeNames()[static_cast<int>( pin->GetType() )];
97  break;
98  case COL_SHAPE:
99  val = PinShapeNames()[static_cast<int>( pin->GetShape() )];
100  break;
101  case COL_ORIENTATION:
102  if( PinOrientationIndex( pin->GetOrientation() ) >= 0 )
103  val = PinOrientationNames()[ PinOrientationIndex( pin->GetOrientation() ) ];
104  break;
105  case COL_NUMBER_SIZE:
106  val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true );
107  break;
108  case COL_NAME_SIZE:
109  val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true );
110  break;
111  case COL_LENGTH:
112  val = StringFromValue( aUserUnits, pin->GetLength() );
113  break;
114  case COL_POSX:
115  val = StringFromValue( aUserUnits, pin->GetPosition().x );
116  break;
117  case COL_POSY:
118  val = StringFromValue( aUserUnits, pin->GetPosition().y );
119  break;
120  case COL_VISIBLE:
121  val = StringFromBool( pin->IsVisible() );
122  break;
123  default:
124  wxFAIL;
125  break;
126  }
127 
128  if( aCol == COL_NUMBER )
129  {
130  if( fieldValue.length() )
131  fieldValue += wxT( ", " );
132  fieldValue += val;
133  }
134  else
135  {
136  if( !fieldValue.Length() )
137  fieldValue = val;
138  else if( val != fieldValue )
139  fieldValue = INDETERMINATE_STATE;
140  }
141  }
142 
143  return fieldValue;
144  }
145 
146  void SetValue( int aRow, int aCol, const wxString &aValue ) override
147  {
148  if( aValue == INDETERMINATE_STATE )
149  return;
150 
151  LIB_PINS pins = m_rows[ aRow ];
152 
153  for( LIB_PIN* pin : pins )
154  {
155  switch( aCol )
156  {
157  case COL_NUMBER:
158  pin->SetNumber( aValue );
159  break;
160 
161  case COL_NAME:
162  pin->SetName( aValue );
163  break;
164 
165  case COL_TYPE:
166  if( PinTypeNames().Index( aValue ) != wxNOT_FOUND )
167  pin->SetType( (ELECTRICAL_PINTYPE) PinTypeNames().Index( aValue ) );
168 
169  break;
170 
171  case COL_SHAPE:
172  if( PinShapeNames().Index( aValue ) != wxNOT_FOUND )
173  pin->SetShape( (GRAPHIC_PINSHAPE) PinShapeNames().Index( aValue ) );
174 
175  break;
176 
177  case COL_ORIENTATION:
178  if( PinOrientationNames().Index( aValue ) != wxNOT_FOUND )
179  pin->SetOrientation( PinOrientationCode( PinOrientationNames().Index( aValue ) ) );
180  break;
181 
182  case COL_NUMBER_SIZE:
183  pin->SetNumberTextSize( ValueFromString( m_userUnits, aValue ) );
184  break;
185 
186  case COL_NAME_SIZE:
187  pin->SetNameTextSize( ValueFromString( m_userUnits, aValue ) );
188  break;
189 
190  case COL_LENGTH:
191  pin->SetLength( ValueFromString( m_userUnits, aValue ) );
192  break;
193 
194  case COL_POSX:
195  pin->SetPosition( wxPoint( ValueFromString( m_userUnits, aValue ),
196  pin->GetPosition().y ) );
197  break;
198 
199  case COL_POSY:
200  pin->SetPosition( wxPoint( pin->GetPosition().x,
201  ValueFromString( m_userUnits, aValue ) ) );
202  break;
203 
204  case COL_VISIBLE:
205  pin->SetVisible(BoolFromString( aValue ));
206  break;
207  default:
208  wxFAIL;
209  break;
210  }
211  }
212 
213  m_edited = true;
214  }
215 
216  static int findRow( const std::vector<LIB_PINS>& aRowSet, const wxString& aName )
217  {
218  for( size_t i = 0; i < aRowSet.size(); ++i )
219  {
220  if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName )
221  return i;
222  }
223 
224  return -1;
225  }
226 
227  static bool compare( const LIB_PINS& lhs, const LIB_PINS& rhs, int sortCol, bool ascending,
228  EDA_UNITS units )
229  {
230  wxString lhStr = GetValue( lhs, sortCol, units );
231  wxString rhStr = GetValue( rhs, sortCol, units );
232 
233  if( lhStr == rhStr )
234  {
235  // Secondary sort key is always COL_NUMBER
236  sortCol = COL_NUMBER;
237  lhStr = GetValue( lhs, sortCol, units );
238  rhStr = GetValue( rhs, sortCol, units );
239  }
240 
241  bool res;
242 
243  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
244  // to get the opposite sort. i.e. ~(a<b) != (a>b)
245  auto cmp = [ ascending ]( const auto a, const auto b )
246  {
247  if( ascending )
248  return a < b;
249  else
250  return b < a;
251  };
252 
253  switch( sortCol )
254  {
255  case COL_NUMBER:
256  case COL_NAME:
257  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
258  break;
259  case COL_NUMBER_SIZE:
260  case COL_NAME_SIZE:
261  res = cmp( ValueFromString( units, lhStr ),
262  ValueFromString( units, rhStr ) );
263  break;
264  case COL_LENGTH:
265  case COL_POSX:
266  case COL_POSY:
267  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
268  break;
269  case COL_VISIBLE:
270  default:
271  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
272  break;
273  }
274 
275  return res;
276  }
277 
278  void RebuildRows( const LIB_PINS& aPins, bool groupByName )
279  {
280  if ( GetView() )
281  {
282  // Commit any pending in-place edits before the row gets moved out from under
283  // the editor.
284  if( auto grid = dynamic_cast<WX_GRID*>( GetView() ) )
285  grid->CommitPendingChanges( true );
286 
287  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
288  GetView()->ProcessTableMessage( msg );
289  }
290 
291  m_rows.clear();
292 
293  for( LIB_PIN* pin : aPins )
294  {
295  int rowIndex = -1;
296 
297  if( groupByName )
298  rowIndex = findRow( m_rows, pin->GetName() );
299 
300  if( rowIndex < 0 )
301  {
302  m_rows.emplace_back( LIB_PINS() );
303  rowIndex = m_rows.size() - 1;
304  }
305 
306  m_rows[ rowIndex ].push_back( pin );
307  }
308 
309  int sortCol = 0;
310  bool ascending = true;
311 
312  if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
313  {
314  sortCol = GetView()->GetSortingColumn();
315  ascending = GetView()->IsSortOrderAscending();
316  }
317 
318  for( LIB_PINS& row : m_rows )
319  SortPins( row );
320 
321  SortRows( sortCol, ascending );
322 
323  if ( GetView() )
324  {
325  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
326  GetView()->ProcessTableMessage( msg );
327  }
328  }
329 
330  void SortRows( int aSortCol, bool ascending )
331  {
332  std::sort( m_rows.begin(), m_rows.end(),
333  [ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
334  {
335  return compare( lhs, rhs, aSortCol, ascending, m_userUnits );
336  } );
337  }
338 
339  void SortPins( LIB_PINS& aRow )
340  {
341  std::sort( aRow.begin(), aRow.end(),
342  []( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
343  {
344  return PinNumbers::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
345  } );
346  }
347 
348  void AppendRow( LIB_PIN* aPin )
349  {
350  LIB_PINS row;
351  row.push_back( aPin );
352  m_rows.push_back( row );
353 
354  if ( GetView() )
355  {
356  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
357  GetView()->ProcessTableMessage( msg );
358  }
359  }
360 
361  LIB_PINS RemoveRow( int aRow )
362  {
363  LIB_PINS removedRow = m_rows[ aRow ];
364 
365  m_rows.erase( m_rows.begin() + aRow );
366 
367  if ( GetView() )
368  {
369  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
370  GetView()->ProcessTableMessage( msg );
371  }
372 
373  return removedRow;
374  }
375 
376  bool IsEdited()
377  {
378  return m_edited;
379  }
380 
381 private:
382  static wxString StringFromBool( bool aValue )
383  {
384  if( aValue )
385  return wxT( "1" );
386  else
387  return wxT( "0" );
388  }
389 
390  static bool BoolFromString( wxString aValue )
391  {
392  if( aValue == "1" )
393  {
394  return true;
395  }
396  else if( aValue == "0" )
397  {
398  return false;
399  }
400  else
401  {
402  wxFAIL_MSG( wxString::Format( "string \"%s\" can't be converted to boolean "
403  "correctly, it will have been perceived as FALSE",
404  aValue ) );
405  return false;
406  }
407  }
408 
409  // Because the rows of the grid can either be a single pin or a group of pins, the
410  // data model is a 2D vector. If we're in the single pin case, each row's LIB_PINS
411  // contains only a single pin.
412  std::vector<LIB_PINS> m_rows;
413 
415  bool m_edited;
416 };
417 
418 
420  LIB_SYMBOL* aSymbol ) :
422  m_editFrame( parent ),
423  m_part( aSymbol )
424 {
426 
427  // Save original columns widths so we can do proportional sizing.
428  for( int i = 0; i < COL_COUNT; ++i )
429  m_originalColWidths[ i ] = m_grid->GetColSize( i );
430 
431  // Give a bit more room for combobox editors
432  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
433 
435  m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
436 
437  // Show/hide columns according to the user's preference
438  auto cfg = parent->GetSettings();
439  m_columnsShown = cfg->m_PinTableVisibleColumns;
440 
442 
443  // Set special attributes
444  wxGridCellAttr* attr;
445 
446  attr = new wxGridCellAttr;
447  wxArrayString typeNames = PinTypeNames();
448  typeNames.push_back( INDETERMINATE_STATE );
449  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinTypeIcons(), typeNames ) );
450  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinTypeIcons(), typeNames ) );
451  m_grid->SetColAttr( COL_TYPE, attr );
452 
453  attr = new wxGridCellAttr;
454  wxArrayString shapeNames = PinShapeNames();
455  shapeNames.push_back( INDETERMINATE_STATE );
456  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinShapeIcons(), shapeNames ) );
457  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinShapeIcons(), shapeNames ) );
458  m_grid->SetColAttr( COL_SHAPE, attr );
459 
460  attr = new wxGridCellAttr;
461  wxArrayString orientationNames = PinOrientationNames();
462  orientationNames.push_back( INDETERMINATE_STATE );
463  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinOrientationIcons(),
464  orientationNames ) );
465  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinOrientationIcons(), orientationNames ) );
466  m_grid->SetColAttr( COL_ORIENTATION, attr );
467 
468  attr = new wxGridCellAttr;
469  attr->SetRenderer( new wxGridCellBoolRenderer() );
470  attr->SetEditor( new wxGridCellBoolEditor() );
471  attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
472  m_grid->SetColAttr( COL_VISIBLE, attr );
473 
474  /* Right-aligned position values look much better, but only MSW and GTK2+
475  * currently support right-aligned textEditCtrls, so the text jumps on all
476  * the other platforms when you edit it.
477  attr = new wxGridCellAttr;
478  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
479  m_grid->SetColAttr( COL_POSX, attr );
480 
481  attr = new wxGridCellAttr;
482  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
483  m_grid->SetColAttr( COL_POSY, attr );
484  */
485 
486  m_addButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
489 
490  GetSizer()->SetSizeHints(this);
491  Centre();
492 
493  if( !parent->IsSymbolEditable() || parent->IsSymbolAlias() )
494  {
495  m_ButtonsCancel->SetDefault();
496  m_ButtonsOK->SetLabel( _( "Read Only" ) );
497  m_ButtonsOK->Enable( false );
498  }
499  else
500  {
501  m_ButtonsOK->SetDefault();
502  }
503 
504  m_ButtonsOK->SetDefault();
505  m_initialized = true;
506  m_modified = false;
507  m_width = 0;
508 
509  // Connect Events
510  m_grid->Connect( wxEVT_GRID_COL_SORT,
511  wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
512 }
513 
514 
516 {
517  auto cfg = m_editFrame->GetSettings();
518  cfg->m_PinTableVisibleColumns = m_grid->GetShownColumns().ToStdString();
519 
520  // Disconnect Events
521  m_grid->Disconnect( wxEVT_GRID_COL_SORT,
522  wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
523 
524  // Prevents crash bug in wxGrid's d'tor
526 
527  // Delete the GRID_TRICKS.
528  m_grid->PopEventHandler( true );
529 
530  // This is our copy of the pins. If they were transferred to the part on an OK, then
531  // m_pins will already be empty.
532  for( auto pin : m_pins )
533  delete pin;
534 }
535 
536 
538 {
539  // Make a copy of the pins for editing
540  for( LIB_PIN* pin = m_part->GetNextPin( nullptr ); pin; pin = m_part->GetNextPin( pin ) )
541  m_pins.push_back( new LIB_PIN( *pin ) );
542 
543  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
544 
545  updateSummary();
546 
547  return true;
548 }
549 
550 
552 {
553  if( !m_grid->CommitPendingChanges() )
554  return false;
555 
556  // Delete the part's pins
557  while( LIB_PIN* pin = m_part->GetNextPin( nullptr ) )
559 
560  // Transfer our pins to the part
561  for( LIB_PIN* pin : m_pins )
562  {
563  pin->SetParent( m_part );
564  m_part->AddDrawItem( pin );
565  }
566 
567  m_pins.clear();
568 
569  return true;
570 }
571 
572 
573 void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent )
574 {
575  int sortCol = aEvent.GetCol();
576  bool ascending;
577 
578  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
579  // event, and if we ask it will give us pre-event info.
580  if( m_grid->IsSortingBy( sortCol ) )
581  // same column; invert ascending
582  ascending = !m_grid->IsSortOrderAscending();
583  else
584  // different column; start with ascending
585  ascending = true;
586 
587  m_dataModel->SortRows( sortCol, ascending );
588 }
589 
590 
591 void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
592 {
593  if( !m_grid->CommitPendingChanges() )
594  return;
595 
596  LIB_PIN* newPin = new LIB_PIN( nullptr );
597 
598  if( m_pins.size() > 0 )
599  {
600  LIB_PIN* last = m_pins.back();
601 
602  newPin->SetOrientation( last->GetOrientation() );
603  newPin->SetType( last->GetType() );
604  newPin->SetShape( last->GetShape() );
605 
606  wxPoint pos = last->GetPosition();
607 
609 
610  if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
611  pos.y -= Mils2iu(cfg->m_Repeat.pin_step);
612  else
613  pos.x += Mils2iu(cfg->m_Repeat.pin_step);
614 
615  newPin->SetPosition( pos );
616  }
617 
618  m_pins.push_back( newPin );
619 
620  m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] );
621 
622  m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 );
623  m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 );
624 
625  m_grid->EnableCellEditControl( true );
626  m_grid->ShowCellEditControl();
627 
628  updateSummary();
629 }
630 
631 
632 void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
633 {
634  if( !m_grid->CommitPendingChanges() )
635  return;
636 
637  if( m_pins.size() == 0 ) // empty table
638  return;
639 
640  int curRow = m_grid->GetGridCursorRow();
641 
642  if( curRow < 0 )
643  return;
644 
645  LIB_PINS removedRow = m_dataModel->RemoveRow( curRow );
646 
647  for( auto pin : removedRow )
648  m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
649 
650  curRow = std::max( 0, curRow - 1 );
651  m_grid->MakeCellVisible( curRow, m_grid->GetGridCursorCol() );
652  m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
653 
654  updateSummary();
655 }
656 
657 
658 void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event )
659 {
660  updateSummary();
661 }
662 
663 
665 {
666  if( !m_grid->CommitPendingChanges() )
667  return;
668 
669  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
670 
671  adjustGridColumns( m_grid->GetRect().GetWidth() );
672 }
673 
674 
676 {
677  m_width = aWidth;
678 
679  // Account for scroll bars
680  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
681 
682  wxGridUpdateLocker deferRepaintsTillLeavingScope;
683 
684  // The Number and Name columns must be at least wide enough to hold their contents, but
685  // no less wide than their original widths.
686 
687  m_grid->AutoSizeColumn( COL_NUMBER );
688 
689  if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] )
690  m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] );
691 
692  m_grid->AutoSizeColumn( COL_NAME );
693 
694  if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] )
695  m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] );
696 
697  // If the grid is still wider than the columns, then stretch the Number and Name columns
698  // to fit.
699 
700  for( int i = 0; i < COL_COUNT; ++i )
701  aWidth -= m_grid->GetColSize( i );
702 
703  if( aWidth > 0 )
704  {
705  m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + aWidth / 2 );
706  m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + aWidth / 2 );
707  }
708 }
709 
710 
711 void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event )
712 {
713  auto new_size = event.GetSize().GetX();
714 
715  if( m_initialized && m_width != new_size )
716  {
717  adjustGridColumns( new_size );
718  }
719 
720  // Always propagate for a grid repaint (needed if the height changes, as well as width)
721  event.Skip();
722 }
723 
724 
725 void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
726 {
727  wxString columnsShown = m_grid->GetShownColumns();
728 
729  if( columnsShown != m_columnsShown )
730  {
731  m_columnsShown = columnsShown;
732 
733  if( !m_grid->IsCellEditControlShown() )
734  adjustGridColumns( m_grid->GetRect().GetWidth() );
735  }
736 }
737 
738 
739 void DIALOG_LIB_EDIT_PIN_TABLE::OnCancel( wxCommandEvent& event )
740 {
741  Close();
742 }
743 
744 
745 void DIALOG_LIB_EDIT_PIN_TABLE::OnClose( wxCloseEvent& event )
746 {
747  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
748  m_grid->CommitPendingChanges( true );
749 
750  int retval = wxID_CANCEL;
751 
752  if( m_dataModel->IsEdited() )
753  {
754  if( HandleUnsavedChanges( this, _( "Save changes?" ),
755  [&]()->bool
756  {
757  if( TransferDataFromWindow() )
758  {
759  retval = wxID_OK;
760  return true;
761  }
762 
763  return false;
764  } ) )
765  {
766  if( IsQuasiModal() )
767  EndQuasiModal( retval );
768  else
769  EndDialog( retval );
770 
771  return;
772  }
773  else
774  {
775  event.Veto();
776  return;
777  }
778  }
779 
780  // No change in dialog: we can close it
781  if( IsQuasiModal() )
782  EndQuasiModal( retval );
783  else
784  EndDialog( retval );
785 
786  return;
787 }
788 
789 
791 {
792  PinNumbers pinNumbers;
793 
794  for( LIB_PIN* pin : m_pins )
795  {
796  if( pin->GetNumber().Length() )
797  pinNumbers.insert( pin->GetNumber() );
798  }
799 
800  m_summary->SetLabel( pinNumbers.GetSummary() );
801 }
static int Compare(PinNumber const &lhs, PinNumber const &rhs)
Definition: pin_number.cpp:111
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:207
const std::vector< BITMAPS > & PinOrientationIcons()
Definition: pin_type.cpp:228
void OnClose(wxCloseEvent &event) override
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:518
void OnSize(wxSizeEvent &event) override
void SetOrientation(int aOrientation)
Definition: lib_pin.h:76
PIN_TABLE_DATA_MODEL(EDA_UNITS aUserUnits)
const std::vector< BITMAPS > & PinShapeIcons()
Definition: pin_type.cpp:210
This file is part of the common library.
int GetOrientation() const
Definition: lib_pin.h:75
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:129
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)
Definition: lib_pin.h:79
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:78
void OnAddRow(wxCommandEvent &event) override
SYMBOL_EDITOR_SETTINGS * GetSettings() const
wxString GetSummary() const
Definition: pin_number.cpp:71
void OnCellEdited(wxGridEvent &event) override
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:52
bool IsQuasiModal() const
Definition: dialog_shim.h:106
int PinOrientationIndex(int code)
Definition: pin_type.cpp:147
int PinOrientationCode(int index)
Definition: pin_type.cpp:138
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:65
void RemoveDrawItem(LIB_ITEM *aItem)
Remove draw aItem from list.
Definition: lib_symbol.cpp:627
GRAPHIC_PINSHAPE
Definition: pin_type.h:55
void SetPosition(const wxPoint &aPos) override
Definition: lib_pin.h:211
Define a library symbol object.
Definition: lib_symbol.h:96
void insert(value_type const &v)
Definition: pin_number.h:57
void RebuildRows(const LIB_PINS &aPins, bool groupByName)
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:119
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:97
bool m_modified
true when there are unsaved changes
const wxArrayString & PinShapeNames()
Definition: pin_type.cpp:201
void SetType(ELECTRICAL_PINTYPE aType)
Definition: lib_pin.h:85
bool IsEmptyCell(int row, int col) override
bool IsSymbolAlias() const
Restore the empty editor screen, without any symbol or library selected.
static bool BoolFromString(wxString aValue)
void SortRows(int aSortCol, bool ascending)
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:416
void OnRebuildRows(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
const wxArrayString & PinTypeNames()
Definition: pin_type.cpp:183
#define _(s)
void AddDrawItem(LIB_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:653
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:180
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
wxString GetColLabelValue(int aCol) override
PIN_TABLE_DATA_MODEL * m_dataModel
wxString GetValue(int aRow, int aCol) override
static bool compare(const LIB_PINS &lhs, const LIB_PINS &rhs, int sortCol, bool ascending, EDA_UNITS units)
wxPoint GetPosition() const override
Definition: lib_pin.h:210
Class DIALOG_LIB_EDIT_PIN_TABLE_BASE.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
const wxArrayString & PinOrientationNames()
Definition: pin_type.cpp:219
EDA_UNITS
Definition: eda_units.h:38
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:110
const wxString & GetNumber() const
Definition: lib_pin.h:116
ELECTRICAL_PINTYPE GetType() const
Definition: lib_pin.h:84
void EndQuasiModal(int retCode)
static int findRow(const std::vector< LIB_PINS > &aRowSet, const wxString &aName)
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
DIALOG_LIB_EDIT_PIN_TABLE(SYMBOL_EDIT_FRAME *parent, LIB_SYMBOL *aSymbol)
void OnDeleteRow(wxCommandEvent &event) override
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition: pin_type.h:35
void OnColSort(wxGridEvent &aEvent)
static wxString GetValue(const LIB_PINS &pins, int aCol, EDA_UNITS aUserUnits)
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:204
LIB_PIN * GetNextPin(LIB_PIN *aItem=nullptr)
Return the next pin object from the draw list.
Definition: lib_symbol.h:372
void SetValue(int aRow, int aCol, const wxString &aValue) override
static std::map< int, wxString > shapeNames
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition: base_units.h:47
std::vector< LIB_PINS > m_rows
void OnCancel(wxCommandEvent &event) override
static wxString StringFromBool(bool aValue)
const std::vector< BITMAPS > & PinTypeIcons()
Definition: pin_type.cpp:192
The symbol library editor main window.