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>
34 #include <pgm_base.h>
36 #include <kicad_string.h>
37 
38 class PIN_TABLE_DATA_MODEL : public wxGridTableBase
39 {
40 public:
41  PIN_TABLE_DATA_MODEL( EDA_UNITS aUserUnits ) : m_userUnits( aUserUnits ), m_edited( false )
42  {
43  }
44 
45  int GetNumberRows() override { return (int) m_rows.size(); }
46  int GetNumberCols() override { return COL_COUNT; }
47 
48  wxString GetColLabelValue( int aCol ) override
49  {
50  switch( aCol )
51  {
52  case COL_NUMBER: return _( "Number" );
53  case COL_NAME: return _( "Name" );
54  case COL_TYPE: return _( "Electrical Type" );
55  case COL_SHAPE: return _( "Graphic Style" );
56  case COL_ORIENTATION: return _( "Orientation" );
57  case COL_NUMBER_SIZE: return _( "Number Text Size" );
58  case COL_NAME_SIZE: return _( "Name Text Size" );
59  case COL_LENGTH: return _( "Length" );
60  case COL_POSX: return _( "X Position" );
61  case COL_POSY: return _( "Y Position" );
62  case COL_VISIBLE: return _( "Visible" );
63  default: wxFAIL; return wxEmptyString;
64  }
65  }
66 
67  bool IsEmptyCell( int row, int col ) override
68  {
69  return false; // don't allow adjacent cell overflow, even if we are actually empty
70  }
71 
72  wxString GetValue( int aRow, int aCol ) override
73  {
74  return GetValue( m_rows[ aRow ], aCol, m_userUnits );
75  }
76 
77  static wxString GetValue( const LIB_PINS& pins, int aCol, EDA_UNITS aUserUnits )
78  {
79  wxString fieldValue;
80 
81  if( pins.empty() )
82  return fieldValue;
83 
84  for( LIB_PIN* pin : pins )
85  {
86  wxString val;
87 
88  switch( aCol )
89  {
90  case COL_NUMBER:
91  val = pin->GetNumber();
92  break;
93  case COL_NAME:
94  val = pin->GetName();
95  break;
96  case COL_TYPE:
97  val = PinTypeNames()[static_cast<int>( pin->GetType() )];
98  break;
99  case COL_SHAPE:
100  val = PinShapeNames()[static_cast<int>( pin->GetShape() )];
101  break;
102  case COL_ORIENTATION:
103  if( PinOrientationIndex( pin->GetOrientation() ) >= 0 )
104  val = PinOrientationNames()[ PinOrientationIndex( pin->GetOrientation() ) ];
105  break;
106  case COL_NUMBER_SIZE:
107  val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true );
108  break;
109  case COL_NAME_SIZE:
110  val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true );
111  break;
112  case COL_LENGTH:
113  val = StringFromValue( aUserUnits, pin->GetLength() );
114  break;
115  case COL_POSX:
116  val = StringFromValue( aUserUnits, pin->GetPosition().x );
117  break;
118  case COL_POSY:
119  val = StringFromValue( aUserUnits, pin->GetPosition().y );
120  break;
121  case COL_VISIBLE:
122  val = StringFromBool( pin->IsVisible() );
123  break;
124  default:
125  wxFAIL;
126  break;
127  }
128 
129  if( aCol == COL_NUMBER )
130  {
131  if( fieldValue.length() )
132  fieldValue += wxT( ", " );
133  fieldValue += val;
134  }
135  else
136  {
137  if( !fieldValue.Length() )
138  fieldValue = val;
139  else if( val != fieldValue )
140  fieldValue = INDETERMINATE_STATE;
141  }
142  }
143 
144  return fieldValue;
145  }
146 
147  void SetValue( int aRow, int aCol, const wxString &aValue ) override
148  {
149  if( aValue == INDETERMINATE_STATE )
150  return;
151 
152  LIB_PINS pins = m_rows[ aRow ];
153 
154  for( LIB_PIN* pin : pins )
155  {
156  switch( aCol )
157  {
158  case COL_NUMBER:
159  pin->SetNumber( aValue );
160  break;
161 
162  case COL_NAME:
163  pin->SetName( aValue );
164  break;
165 
166  case COL_TYPE:
167  if( PinTypeNames().Index( aValue ) != wxNOT_FOUND )
168  pin->SetType( (ELECTRICAL_PINTYPE) PinTypeNames().Index( aValue ) );
169 
170  break;
171 
172  case COL_SHAPE:
173  if( PinShapeNames().Index( aValue ) != wxNOT_FOUND )
174  pin->SetShape( (GRAPHIC_PINSHAPE) PinShapeNames().Index( aValue ) );
175 
176  break;
177 
178  case COL_ORIENTATION:
179  if( PinOrientationNames().Index( aValue ) != wxNOT_FOUND )
180  pin->SetOrientation( PinOrientationCode( PinOrientationNames().Index( aValue ) ) );
181  break;
182 
183  case COL_NUMBER_SIZE:
184  pin->SetNumberTextSize( ValueFromString( m_userUnits, aValue ) );
185  break;
186 
187  case COL_NAME_SIZE:
188  pin->SetNameTextSize( ValueFromString( m_userUnits, aValue ) );
189  break;
190 
191  case COL_LENGTH:
192  pin->SetLength( ValueFromString( m_userUnits, aValue ) );
193  break;
194 
195  case COL_POSX:
196  pin->SetPosition( wxPoint( ValueFromString( m_userUnits, aValue ),
197  pin->GetPosition().y ) );
198  break;
199 
200  case COL_POSY:
201  pin->SetPosition( wxPoint( pin->GetPosition().x,
202  ValueFromString( m_userUnits, aValue ) ) );
203  break;
204 
205  case COL_VISIBLE:
206  pin->SetVisible(BoolFromString( aValue ));
207  break;
208  default:
209  wxFAIL;
210  break;
211  }
212  }
213 
214  m_edited = true;
215  }
216 
217  static int findRow( const std::vector<LIB_PINS>& aRowSet, const wxString& aName )
218  {
219  for( size_t i = 0; i < aRowSet.size(); ++i )
220  {
221  if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName )
222  return i;
223  }
224 
225  return -1;
226  }
227 
228  static bool compare( const LIB_PINS& lhs, const LIB_PINS& rhs, int sortCol, bool ascending,
229  EDA_UNITS units )
230  {
231  wxString lhStr = GetValue( lhs, sortCol, units );
232  wxString rhStr = GetValue( rhs, sortCol, units );
233 
234  if( lhStr == rhStr )
235  {
236  // Secondary sort key is always COL_NUMBER
237  sortCol = COL_NUMBER;
238  lhStr = GetValue( lhs, sortCol, units );
239  rhStr = GetValue( rhs, sortCol, units );
240  }
241 
242  bool res;
243 
244  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
245  // to get the opposite sort. i.e. ~(a<b) != (a>b)
246  auto cmp = [ ascending ]( const auto a, const auto b )
247  {
248  if( ascending )
249  return a < b;
250  else
251  return b < a;
252  };
253 
254  switch( sortCol )
255  {
256  case COL_NUMBER:
257  case COL_NAME:
258  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
259  break;
260  case COL_NUMBER_SIZE:
261  case COL_NAME_SIZE:
262  res = cmp( ValueFromString( units, lhStr ),
263  ValueFromString( units, rhStr ) );
264  break;
265  case COL_LENGTH:
266  case COL_POSX:
267  case COL_POSY:
268  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
269  break;
270  case COL_VISIBLE:
271  default:
272  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
273  break;
274  }
275 
276  return res;
277  }
278 
279  void RebuildRows( const LIB_PINS& aPins, bool groupByName )
280  {
281  if ( GetView() )
282  {
283  // Commit any pending in-place edits before the row gets moved out from under
284  // the editor.
285  if( auto grid = dynamic_cast<WX_GRID*>( GetView() ) )
286  grid->CommitPendingChanges( true );
287 
288  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
289  GetView()->ProcessTableMessage( msg );
290  }
291 
292  m_rows.clear();
293 
294  for( LIB_PIN* pin : aPins )
295  {
296  int rowIndex = -1;
297 
298  if( groupByName )
299  rowIndex = findRow( m_rows, pin->GetName() );
300 
301  if( rowIndex < 0 )
302  {
303  m_rows.emplace_back( LIB_PINS() );
304  rowIndex = m_rows.size() - 1;
305  }
306 
307  m_rows[ rowIndex ].push_back( pin );
308  }
309 
310  int sortCol = 0;
311  bool ascending = true;
312 
313  if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
314  {
315  sortCol = GetView()->GetSortingColumn();
316  ascending = GetView()->IsSortOrderAscending();
317  }
318 
319  for( LIB_PINS& row : m_rows )
320  SortPins( row );
321 
322  SortRows( sortCol, ascending );
323 
324  if ( GetView() )
325  {
326  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
327  GetView()->ProcessTableMessage( msg );
328  }
329  }
330 
331  void SortRows( int aSortCol, bool ascending )
332  {
333  std::sort( m_rows.begin(), m_rows.end(),
334  [ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
335  {
336  return compare( lhs, rhs, aSortCol, ascending, m_userUnits );
337  } );
338  }
339 
340  void SortPins( LIB_PINS& aRow )
341  {
342  std::sort( aRow.begin(), aRow.end(),
343  []( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
344  {
345  return PinNumbers::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
346  } );
347  }
348 
349  void AppendRow( LIB_PIN* aPin )
350  {
351  LIB_PINS row;
352  row.push_back( aPin );
353  m_rows.push_back( row );
354 
355  if ( GetView() )
356  {
357  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
358  GetView()->ProcessTableMessage( msg );
359  }
360  }
361 
362  LIB_PINS RemoveRow( int aRow )
363  {
364  LIB_PINS removedRow = m_rows[ aRow ];
365 
366  m_rows.erase( m_rows.begin() + aRow );
367 
368  if ( GetView() )
369  {
370  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
371  GetView()->ProcessTableMessage( msg );
372  }
373 
374  return removedRow;
375  }
376 
377  bool IsEdited()
378  {
379  return m_edited;
380  }
381 
382 private:
383  static wxString StringFromBool( bool aValue )
384  {
385  if( aValue )
386  return wxT( "1" );
387  else
388  return wxT( "0" );
389  }
390 
391  static bool BoolFromString( wxString aValue )
392  {
393  if( aValue == "1" )
394  {
395  return true;
396  }
397  else if( aValue == "0" )
398  {
399  return false;
400  }
401  else
402  {
403  wxFAIL_MSG( wxString::Format( "string \"%s\" can't be converted to boolean "
404  "correctly, it will have been perceived as FALSE",
405  aValue ) );
406  return false;
407  }
408  }
409 
410  // Because the rows of the grid can either be a single pin or a group of pins, the
411  // data model is a 2D vector. If we're in the single pin case, each row's LIB_PINS
412  // contains only a single pin.
413  std::vector<LIB_PINS> m_rows;
414 
416  bool m_edited;
417 };
418 
419 
422  m_editFrame( parent ),
423  m_part( aPart )
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( small_plus_xpm ) );
487  m_deleteButton->SetBitmap( KiBitmap( small_trash_xpm ) );
488  m_refreshButton->SetBitmap( KiBitmap( small_refresh_xpm ) );
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 ) )
558  m_part->RemoveDrawItem( pin );
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 
608  auto* cfg = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
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  EndModal( 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  EndModal( 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 }
const BITMAP_OPAQUE small_refresh_xpm[1]
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:208
void OnClose(wxCloseEvent &event) override
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:420
void OnSize(wxSizeEvent &event) override
void SetOrientation(int aOrientation)
Definition: lib_pin.h:126
PIN_TABLE_DATA_MODEL(EDA_UNITS aUserUnits)
This file is part of the common library.
const std::vector< BITMAP_DEF > & PinOrientationIcons()
Definition: pin_type.cpp:226
int GetOrientation() const
Definition: lib_pin.h:125
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:56
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition: lib_pin.h:129
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:128
const std::vector< BITMAP_DEF > & PinTypeIcons()
Definition: pin_type.cpp:190
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:107
int PinOrientationIndex(int code)
Definition: pin_type.cpp:145
int PinOrientationCode(int index)
Definition: pin_type.cpp:136
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
GRAPHIC_PINSHAPE
Definition: pin_type.h:54
DIALOG_LIB_EDIT_PIN_TABLE(SYMBOL_EDIT_FRAME *parent, LIB_PART *aPart)
void SetPosition(const wxPoint &aPos) override
Definition: lib_pin.h:259
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
void insert(value_type const &v)
Definition: pin_number.h:57
void RebuildRows(const LIB_PINS &aPins, bool groupByName)
const std::vector< BITMAP_DEF > & PinShapeIcons()
Definition: pin_type.cpp:208
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:120
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
Definition: lib_symbol.cpp:648
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
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:82
bool m_modified
true when there are unsaved changes
const wxArrayString & PinShapeNames()
Definition: pin_type.cpp:199
void SetType(ELECTRICAL_PINTYPE aType)
Definition: lib_pin.h:135
bool IsEmptyCell(int row, int col) override
bool IsSymbolAlias() const
Restore the empty editor screen, without any part 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:451
void OnRebuildRows(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
Define a library symbol object.
Definition: lib_symbol.h:93
const wxArrayString & PinTypeNames()
Definition: pin_type.cpp:181
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:182
const BITMAP_OPAQUE small_trash_xpm[1]
Definition: small_trash.cpp:23
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:258
Class DIALOG_LIB_EDIT_PIN_TABLE_BASE.
LIB_PIN * GetNextPin(LIB_PIN *aItem=NULL)
Return the next pin object from the draw list.
Definition: lib_symbol.h:365
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:217
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:165
ELECTRICAL_PINTYPE GetType() const
Definition: lib_pin.h:134
void EndQuasiModal(int retCode)
static int findRow(const std::vector< LIB_PINS > &aRowSet, const wxString &aName)
see class PGM_BASE
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
void OnDeleteRow(wxCommandEvent &event) override
ELECTRICAL_PINTYPE
The component library pin object electrical types used in ERC tests.
Definition: pin_type.h:34
#define _(s)
Definition: 3d_actions.cpp:33
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:225
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:48
std::vector< LIB_PINS > m_rows
void OnCancel(wxCommandEvent &event) override
const BITMAP_OPAQUE small_plus_xpm[1]
Definition: small_plus.cpp:18
static wxString StringFromBool(bool aValue)
void RemoveDrawItem(LIB_ITEM *aItem)
Remove draw aItem from list.
Definition: lib_symbol.cpp:622
The symbol library editor main window.