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_numbers.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 <string_utils.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( PIN_NUMBERS::Compare( lhStr, rhStr ), 0 );
258  break;
259  case COL_NUMBER_SIZE:
260  case COL_NAME_SIZE:
261  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
262  break;
263  case COL_LENGTH:
264  case COL_POSX:
265  case COL_POSY:
266  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
267  break;
268  case COL_VISIBLE:
269  default:
270  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
271  break;
272  }
273 
274  return res;
275  }
276 
277  void RebuildRows( const LIB_PINS& aPins, bool groupByName )
278  {
279  if ( GetView() )
280  {
281  // Commit any pending in-place edits before the row gets moved out from under
282  // the editor.
283  if( auto grid = dynamic_cast<WX_GRID*>( GetView() ) )
284  grid->CommitPendingChanges( true );
285 
286  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
287  GetView()->ProcessTableMessage( msg );
288  }
289 
290  m_rows.clear();
291 
292  for( LIB_PIN* pin : aPins )
293  {
294  int rowIndex = -1;
295 
296  if( groupByName )
297  rowIndex = findRow( m_rows, pin->GetName() );
298 
299  if( rowIndex < 0 )
300  {
301  m_rows.emplace_back( LIB_PINS() );
302  rowIndex = m_rows.size() - 1;
303  }
304 
305  m_rows[ rowIndex ].push_back( pin );
306  }
307 
308  int sortCol = 0;
309  bool ascending = true;
310 
311  if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
312  {
313  sortCol = GetView()->GetSortingColumn();
314  ascending = GetView()->IsSortOrderAscending();
315  }
316 
317  for( LIB_PINS& row : m_rows )
318  SortPins( row );
319 
320  SortRows( sortCol, ascending );
321 
322  if ( GetView() )
323  {
324  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
325  GetView()->ProcessTableMessage( msg );
326  }
327  }
328 
329  void SortRows( int aSortCol, bool ascending )
330  {
331  std::sort( m_rows.begin(), m_rows.end(),
332  [ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
333  {
334  return compare( lhs, rhs, aSortCol, ascending, m_userUnits );
335  } );
336  }
337 
338  void SortPins( LIB_PINS& aRow )
339  {
340  std::sort( aRow.begin(), aRow.end(),
341  []( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
342  {
343  return PIN_NUMBERS::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
344  } );
345  }
346 
347  void AppendRow( LIB_PIN* aPin )
348  {
349  LIB_PINS row;
350  row.push_back( aPin );
351  m_rows.push_back( row );
352 
353  if ( GetView() )
354  {
355  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
356  GetView()->ProcessTableMessage( msg );
357  }
358  }
359 
360  LIB_PINS RemoveRow( int aRow )
361  {
362  LIB_PINS removedRow = m_rows[ aRow ];
363 
364  m_rows.erase( m_rows.begin() + aRow );
365 
366  if ( GetView() )
367  {
368  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
369  GetView()->ProcessTableMessage( msg );
370  }
371 
372  return removedRow;
373  }
374 
375  bool IsEdited()
376  {
377  return m_edited;
378  }
379 
380 private:
381  static wxString StringFromBool( bool aValue )
382  {
383  if( aValue )
384  return wxT( "1" );
385  else
386  return wxT( "0" );
387  }
388 
389  static bool BoolFromString( wxString aValue )
390  {
391  if( aValue == "1" )
392  {
393  return true;
394  }
395  else if( aValue == "0" )
396  {
397  return false;
398  }
399  else
400  {
401  wxFAIL_MSG( wxString::Format( "string \"%s\" can't be converted to boolean "
402  "correctly, it will have been perceived as FALSE",
403  aValue ) );
404  return false;
405  }
406  }
407 
408  // Because the rows of the grid can either be a single pin or a group of pins, the
409  // data model is a 2D vector. If we're in the single pin case, each row's LIB_PINS
410  // contains only a single pin.
411  std::vector<LIB_PINS> m_rows;
412 
414  bool m_edited;
415 };
416 
417 
419  LIB_SYMBOL* aSymbol ) :
421  m_editFrame( parent ),
422  m_part( aSymbol )
423 {
425 
426  // Save original columns widths so we can do proportional sizing.
427  for( int i = 0; i < COL_COUNT; ++i )
428  m_originalColWidths[ i ] = m_grid->GetColSize( i );
429 
430  // Give a bit more room for combobox editors
431  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
432 
434  m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
435 
436  // Show/hide columns according to the user's preference
437  auto cfg = parent->GetSettings();
438  m_columnsShown = cfg->m_PinTableVisibleColumns;
439 
441 
442  // Set special attributes
443  wxGridCellAttr* attr;
444 
445  attr = new wxGridCellAttr;
446  wxArrayString typeNames = PinTypeNames();
447  typeNames.push_back( INDETERMINATE_STATE );
448  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinTypeIcons(), typeNames ) );
449  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinTypeIcons(), typeNames ) );
450  m_grid->SetColAttr( COL_TYPE, attr );
451 
452  attr = new wxGridCellAttr;
453  wxArrayString shapeNames = PinShapeNames();
454  shapeNames.push_back( INDETERMINATE_STATE );
455  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinShapeIcons(), shapeNames ) );
456  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinShapeIcons(), shapeNames ) );
457  m_grid->SetColAttr( COL_SHAPE, attr );
458 
459  attr = new wxGridCellAttr;
460  wxArrayString orientationNames = PinOrientationNames();
461  orientationNames.push_back( INDETERMINATE_STATE );
462  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinOrientationIcons(),
463  orientationNames ) );
464  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinOrientationIcons(), orientationNames ) );
465  m_grid->SetColAttr( COL_ORIENTATION, attr );
466 
467  attr = new wxGridCellAttr;
468  attr->SetRenderer( new wxGridCellBoolRenderer() );
469  attr->SetEditor( new wxGridCellBoolEditor() );
470  attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
471  m_grid->SetColAttr( COL_VISIBLE, attr );
472 
473  /* Right-aligned position values look much better, but only MSW and GTK2+
474  * currently support right-aligned textEditCtrls, so the text jumps on all
475  * the other platforms when you edit it.
476  attr = new wxGridCellAttr;
477  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
478  m_grid->SetColAttr( COL_POSX, attr );
479 
480  attr = new wxGridCellAttr;
481  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
482  m_grid->SetColAttr( COL_POSY, attr );
483  */
484 
485  m_addButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
488 
489  GetSizer()->SetSizeHints(this);
490  Centre();
491 
492  if( !parent->IsSymbolEditable() || parent->IsSymbolAlias() )
493  {
494  m_ButtonsCancel->SetDefault();
495  m_ButtonsOK->SetLabel( _( "Read Only" ) );
496  m_ButtonsOK->Enable( false );
497  }
498  else
499  {
500  m_ButtonsOK->SetDefault();
501  }
502 
503  m_ButtonsOK->SetDefault();
504  m_initialized = true;
505  m_modified = false;
506  m_width = 0;
507 
508  // Connect Events
509  m_grid->Connect( wxEVT_GRID_COL_SORT,
510  wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
511 }
512 
513 
515 {
516  auto cfg = m_editFrame->GetSettings();
517  cfg->m_PinTableVisibleColumns = m_grid->GetShownColumns().ToStdString();
518 
519  // Disconnect Events
520  m_grid->Disconnect( wxEVT_GRID_COL_SORT,
521  wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
522 
523  // Prevents crash bug in wxGrid's d'tor
525 
526  // Delete the GRID_TRICKS.
527  m_grid->PopEventHandler( true );
528 
529  // This is our copy of the pins. If they were transferred to the part on an OK, then
530  // m_pins will already be empty.
531  for( auto pin : m_pins )
532  delete pin;
533 }
534 
535 
537 {
538  // Make a copy of the pins for editing
539  for( LIB_PIN* pin = m_part->GetNextPin( nullptr ); pin; pin = m_part->GetNextPin( pin ) )
540  m_pins.push_back( new LIB_PIN( *pin ) );
541 
542  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
543 
544  updateSummary();
545 
546  return true;
547 }
548 
549 
551 {
552  if( !m_grid->CommitPendingChanges() )
553  return false;
554 
555  // Delete the part's pins
556  while( LIB_PIN* pin = m_part->GetNextPin( nullptr ) )
558 
559  // Transfer our pins to the part
560  for( LIB_PIN* pin : m_pins )
561  {
562  pin->SetParent( m_part );
563  m_part->AddDrawItem( pin );
564  }
565 
566  m_pins.clear();
567 
568  return true;
569 }
570 
571 
572 void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent )
573 {
574  int sortCol = aEvent.GetCol();
575  bool ascending;
576 
577  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
578  // event, and if we ask it will give us pre-event info.
579  if( m_grid->IsSortingBy( sortCol ) )
580  // same column; invert ascending
581  ascending = !m_grid->IsSortOrderAscending();
582  else
583  // different column; start with ascending
584  ascending = true;
585 
586  m_dataModel->SortRows( sortCol, ascending );
587 }
588 
589 
590 void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
591 {
592  if( !m_grid->CommitPendingChanges() )
593  return;
594 
595  LIB_PIN* newPin = new LIB_PIN( nullptr );
596 
597  if( m_pins.size() > 0 )
598  {
599  LIB_PIN* last = m_pins.back();
600 
601  newPin->SetOrientation( last->GetOrientation() );
602  newPin->SetType( last->GetType() );
603  newPin->SetShape( last->GetShape() );
604 
605  wxPoint pos = last->GetPosition();
606 
608 
609  if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
610  pos.y -= Mils2iu(cfg->m_Repeat.pin_step);
611  else
612  pos.x += Mils2iu(cfg->m_Repeat.pin_step);
613 
614  newPin->SetPosition( pos );
615  }
616 
617  m_pins.push_back( newPin );
618 
619  m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] );
620 
621  m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 );
622  m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 );
623 
624  m_grid->EnableCellEditControl( true );
625  m_grid->ShowCellEditControl();
626 
627  updateSummary();
628 }
629 
630 
631 void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
632 {
633  if( !m_grid->CommitPendingChanges() )
634  return;
635 
636  if( m_pins.size() == 0 ) // empty table
637  return;
638 
639  int curRow = m_grid->GetGridCursorRow();
640 
641  if( curRow < 0 )
642  return;
643 
644  LIB_PINS removedRow = m_dataModel->RemoveRow( curRow );
645 
646  for( auto pin : removedRow )
647  m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
648 
649  curRow = std::min( curRow, m_grid->GetNumberRows() - 1 );
650  m_grid->GoToCell( curRow, m_grid->GetGridCursorCol() );
651  m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
652  m_grid->SelectRow( curRow );
653 
654 
655  updateSummary();
656 }
657 
658 
659 void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event )
660 {
661  updateSummary();
662 }
663 
664 
666 {
667  if( !m_grid->CommitPendingChanges() )
668  return;
669 
670  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
671 
672  adjustGridColumns( m_grid->GetRect().GetWidth() );
673 }
674 
675 
677 {
678  m_width = aWidth;
679 
680  // Account for scroll bars
681  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
682 
683  wxGridUpdateLocker deferRepaintsTillLeavingScope;
684 
685  // The Number and Name columns must be at least wide enough to hold their contents, but
686  // no less wide than their original widths.
687 
688  m_grid->AutoSizeColumn( COL_NUMBER );
689 
690  if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] )
691  m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] );
692 
693  m_grid->AutoSizeColumn( COL_NAME );
694 
695  if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] )
696  m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] );
697 
698  // If the grid is still wider than the columns, then stretch the Number and Name columns
699  // to fit.
700 
701  for( int i = 0; i < COL_COUNT; ++i )
702  aWidth -= m_grid->GetColSize( i );
703 
704  if( aWidth > 0 )
705  {
706  m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + aWidth / 2 );
707  m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + aWidth / 2 );
708  }
709 }
710 
711 
712 void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event )
713 {
714  auto new_size = event.GetSize().GetX();
715 
716  if( m_initialized && m_width != new_size )
717  {
718  adjustGridColumns( new_size );
719  }
720 
721  // Always propagate for a grid repaint (needed if the height changes, as well as width)
722  event.Skip();
723 }
724 
725 
726 void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
727 {
728  wxString columnsShown = m_grid->GetShownColumns();
729 
730  if( columnsShown != m_columnsShown )
731  {
732  m_columnsShown = columnsShown;
733 
734  if( !m_grid->IsCellEditControlShown() )
735  adjustGridColumns( m_grid->GetRect().GetWidth() );
736  }
737 }
738 
739 
740 void DIALOG_LIB_EDIT_PIN_TABLE::OnCancel( wxCommandEvent& event )
741 {
742  Close();
743 }
744 
745 
746 void DIALOG_LIB_EDIT_PIN_TABLE::OnClose( wxCloseEvent& event )
747 {
748  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
749  m_grid->CommitPendingChanges( true );
750 
751  int retval = wxID_CANCEL;
752 
753  if( m_dataModel->IsEdited() )
754  {
755  if( HandleUnsavedChanges( this, _( "Save changes?" ),
756  [&]() -> bool
757  {
758  if( TransferDataFromWindow() )
759  {
760  retval = wxID_OK;
761  return true;
762  }
763 
764  return false;
765  } ) )
766  {
767  if( IsQuasiModal() )
768  EndQuasiModal( retval );
769  else
770  EndDialog( retval );
771 
772  return;
773  }
774  else
775  {
776  event.Veto();
777  return;
778  }
779  }
780 
781  // No change in dialog: we can close it
782  if( IsQuasiModal() )
783  EndQuasiModal( retval );
784  else
785  EndDialog( retval );
786 
787  return;
788 }
789 
790 
792 {
793  PIN_NUMBERS pinNumbers;
794 
795  for( LIB_PIN* pin : m_pins )
796  {
797  if( pin->GetNumber().Length() )
798  pinNumbers.insert( pin->GetNumber() );
799  }
800 
801  m_summary->SetLabel( pinNumbers.GetSummary() );
802 }
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:239
const std::vector< BITMAPS > & PinOrientationIcons()
Definition: pin_type.cpp:228
void OnClose(wxCloseEvent &event) override
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:136
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
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:55
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:72
void RemoveDrawItem(LIB_ITEM *aItem)
Remove draw aItem from list.
Definition: lib_symbol.cpp:640
GRAPHIC_PINSHAPE
Definition: pin_type.h:55
wxString GetSummary() const
Definition: pin_numbers.cpp:71
void SetPosition(const wxPoint &aPos) override
Definition: lib_pin.h:211
Define a library symbol object.
Definition: lib_symbol.h:96
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:104
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
static int Compare(const wxString &lhs, const wxString &rhs)
bool IsSymbolAlias() const
Restore the empty editor screen, without any symbol or library selected.
void insert(value_type const &v)
Definition: pin_numbers.h:55
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:666
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:190
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:117
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
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
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.