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 "grid_tricks.h"
26 #include "lib_pin.h"
27 #include "pin_number.h"
28 #include <base_units.h>
29 #include <bitmaps.h>
30 #include <confirm.h>
31 #include <kicad_string.h>
32 #include <kiface_i.h>
33 #include <lib_edit_frame.h>
34 #include <libedit_settings.h>
35 #include <queue>
37 #include <widgets/wx_grid.h>
38 #include <wx/bmpcbox.h>
39 #include <pgm_base.h>
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:
65  PIN_TABLE_DATA_MODEL( EDA_UNITS aUserUnits ) : m_userUnits( aUserUnits ), m_edited( false )
66  {
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 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[static_cast<int>( pin->GetType() )];
121  break;
122  case COL_SHAPE:
123  val = g_shapeNames[static_cast<int>( pin->GetShape() )];
124  break;
125  case COL_ORIENTATION:
126  if( LIB_PIN::GetOrientationIndex( pin->GetOrientation() ) >= 0 )
127  val = g_orientationNames[ LIB_PIN::GetOrientationIndex( pin->GetOrientation() ) ];
128  break;
129  case COL_NUMBER_SIZE:
130  val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true, true );
131  break;
132  case COL_NAME_SIZE:
133  val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true, true );
134  break;
135  case COL_LENGTH:
136  val = StringFromValue( aUserUnits, pin->GetLength(), true );
137  break;
138  case COL_POSX:
139  val = StringFromValue( aUserUnits, pin->GetPosition().x, true );
140  break;
141  case COL_POSY:
142  val = StringFromValue( aUserUnits, pin->GetPosition().y, true );
143  break;
144  default:
145  wxFAIL;
146  break;
147  }
148 
149  if( aCol == COL_NUMBER )
150  {
151  if( fieldValue.length() )
152  fieldValue += wxT( ", " );
153  fieldValue += val;
154  }
155  else
156  {
157  if( !fieldValue.Length() )
158  fieldValue = val;
159  else if( val != fieldValue )
160  fieldValue = INDETERMINATE_STATE;
161  }
162  }
163 
164  return fieldValue;
165  }
166 
167  void SetValue( int aRow, int aCol, const wxString &aValue ) override
168  {
169  if( aValue == INDETERMINATE_STATE )
170  return;
171 
172  LIB_PINS pins = m_rows[ aRow ];
173 
174  for( LIB_PIN* pin : pins )
175  {
176  switch( aCol )
177  {
178  case COL_NUMBER:
179  pin->SetNumber( aValue );
180  break;
181  case COL_NAME:
182  pin->SetName( aValue );
183  break;
184  case COL_TYPE:
185  if( g_typeNames.Index( aValue ) != wxNOT_FOUND )
186  pin->SetType( (ELECTRICAL_PINTYPE) g_typeNames.Index( aValue ), false );
187 
188  break;
189  case COL_SHAPE:
190  if( g_shapeNames.Index( aValue ) != wxNOT_FOUND )
191  pin->SetShape( (GRAPHIC_PINSHAPE) g_shapeNames.Index( aValue ) );
192 
193  break;
194  case COL_ORIENTATION:
195  if( g_orientationNames.Index( aValue ) != wxNOT_FOUND )
196  pin->SetOrientation( LIB_PIN::GetOrientationCode(
197  g_orientationNames.Index( aValue ) ), false );
198  break;
199  case COL_NUMBER_SIZE:
200  pin->SetNumberTextSize( ValueFromString( m_userUnits, aValue, true ) );
201  break;
202  case COL_NAME_SIZE:
203  pin->SetNameTextSize( ValueFromString( m_userUnits, aValue, true ) );
204  break;
205  case COL_LENGTH:
206  pin->SetLength( ValueFromString( m_userUnits, aValue ) );
207  break;
208  case COL_POSX:
209  pin->SetPinPosition( wxPoint( ValueFromString( m_userUnits, aValue ),
210  pin->GetPosition().y ) );
211  break;
212  case COL_POSY:
213  pin->SetPinPosition( wxPoint( pin->GetPosition().x,
214  ValueFromString( m_userUnits, aValue ) ) );
215  break;
216  default:
217  wxFAIL;
218  break;
219  }
220  }
221 
222  m_edited = true;
223  }
224 
225  static int findRow( const std::vector<LIB_PINS>& aRowSet, const wxString& aName )
226  {
227  for( size_t i = 0; i < aRowSet.size(); ++i )
228  {
229  if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName )
230  return i;
231  }
232 
233  return -1;
234  }
235 
236  static bool compare(
237  const LIB_PINS& lhs, const LIB_PINS& rhs, int sortCol, bool ascending, EDA_UNITS units )
238  {
239  wxString lhStr = GetValue( lhs, sortCol, units );
240  wxString rhStr = GetValue( rhs, sortCol, units );
241 
242  if( lhStr == rhStr )
243  {
244  // Secondary sort key is always COL_NUMBER
245  sortCol = COL_NUMBER;
246  lhStr = GetValue( lhs, sortCol, units );
247  rhStr = GetValue( rhs, sortCol, units );
248  }
249 
250  bool res;
251 
252  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
253  // to get the opposite sort. i.e. ~(a<b) != (a>b)
254  auto cmp = [ ascending ]( const auto a, const auto b )
255  {
256  if( ascending )
257  return a < b;
258  else
259  return b < a;
260  };
261 
262  switch( sortCol )
263  {
264  case COL_NUMBER:
265  case COL_NAME:
266  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
267  break;
268  case COL_NUMBER_SIZE:
269  case COL_NAME_SIZE:
270  res = cmp( ValueFromString( units, lhStr, true ),
271  ValueFromString( units, rhStr, true ) );
272  break;
273  case COL_LENGTH:
274  case COL_POSX:
275  case COL_POSY:
276  res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
277  break;
278  default:
279  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
280  break;
281  }
282 
283  return res;
284  }
285 
286  void RebuildRows( LIB_PINS& aPins, bool groupByName )
287  {
288  if ( GetView() )
289  {
290  // Commit any pending in-place edits before the row gets moved out from under
291  // the editor.
292  if( auto grid = dynamic_cast<WX_GRID*>( GetView() ) )
293  grid->CommitPendingChanges( true );
294 
295  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
296  GetView()->ProcessTableMessage( msg );
297  }
298 
299  m_rows.clear();
300 
301  for( LIB_PIN* pin : aPins )
302  {
303  int rowIndex = -1;
304 
305  if( groupByName )
306  rowIndex = findRow( m_rows, pin->GetName() );
307 
308  if( rowIndex < 0 )
309  {
310  m_rows.emplace_back( LIB_PINS() );
311  rowIndex = m_rows.size() - 1;
312  }
313 
314  m_rows[ rowIndex ].push_back( pin );
315  }
316 
317  int sortCol = 0;
318  bool ascending = true;
319 
320  if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
321  {
322  sortCol = GetView()->GetSortingColumn();
323  ascending = GetView()->IsSortOrderAscending();
324  }
325 
326  for( LIB_PINS& row : m_rows )
327  SortPins( row );
328 
329  SortRows( sortCol, ascending );
330 
331  if ( GetView() )
332  {
333  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
334  GetView()->ProcessTableMessage( msg );
335  }
336  }
337 
338  void SortRows( int aSortCol, bool ascending )
339  {
340  std::sort( m_rows.begin(), m_rows.end(),
341  [ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
342  {
343  return compare( lhs, rhs, aSortCol, ascending, m_userUnits );
344  } );
345  }
346 
347  void SortPins( LIB_PINS& aRow )
348  {
349  std::sort( aRow.begin(), aRow.end(),
350  []( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
351  {
352  return PinNumbers::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
353  } );
354  }
355 
356  void AppendRow( LIB_PIN* aPin )
357  {
358  LIB_PINS row;
359  row.push_back( aPin );
360  m_rows.push_back( row );
361 
362  if ( GetView() )
363  {
364  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
365  GetView()->ProcessTableMessage( msg );
366  }
367  }
368 
369  LIB_PINS RemoveRow( int aRow )
370  {
371  LIB_PINS removedRow = m_rows[ aRow ];
372 
373  m_rows.erase( m_rows.begin() + aRow );
374 
375  if ( GetView() )
376  {
377  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
378  GetView()->ProcessTableMessage( msg );
379  }
380 
381  return removedRow;
382  }
383 
384  bool IsEdited()
385  {
386  return m_edited;
387  }
388 };
389 
390 
393  m_editFrame( parent ),
394  m_part( aPart )
395 {
396  if( g_typeNames.empty())
397  {
398  for( unsigned i = 0; i < ELECTRICAL_PINTYPES_TOTAL; ++i )
399  g_typeIcons.push_back( GetBitmap( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
400 
401  for( unsigned i = 0; i < ELECTRICAL_PINTYPES_TOTAL; ++i )
402  g_typeNames.push_back( GetText( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
403 
404  g_typeNames.push_back( INDETERMINATE_STATE );
405 
406  for( unsigned i = 0; i < GRAPHIC_PINSHAPES_TOTAL; ++i )
407  g_shapeIcons.push_back( GetBitmap( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
408 
409  for( unsigned i = 0; i < GRAPHIC_PINSHAPES_TOTAL; ++i )
410  g_shapeNames.push_back( GetText( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
411 
412  g_shapeNames.push_back( INDETERMINATE_STATE );
413 
414  for( unsigned i = 0; i < LIB_PIN::GetOrientationNames().size(); ++i )
416 
419  }
420 
422 
423  // Save original columns widths so we can do proportional sizing.
424  for( int i = 0; i < COL_COUNT; ++i )
425  m_originalColWidths[ i ] = m_grid->GetColSize( i );
426 
427  // Give a bit more room for combobox editors
428  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
429 
431  m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
432 
433  // Show/hide columns according to the user's preference
434  auto cfg = parent->GetSettings();
435  m_columnsShown = cfg->m_PinTableVisibleColumns;
436 
438 
439  // Set special attributes
440  wxGridCellAttr* attr;
441 
442  attr = new wxGridCellAttr;
443  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_typeIcons, g_typeNames ) );
444  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_typeIcons, g_typeNames ) );
445  m_grid->SetColAttr( COL_TYPE, attr );
446 
447  attr = new wxGridCellAttr;
448  attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_shapeIcons, g_shapeNames ) );
449  attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_shapeIcons, g_shapeNames ) );
450  m_grid->SetColAttr( COL_SHAPE, attr );
451 
452  attr = new wxGridCellAttr;
455  m_grid->SetColAttr( COL_ORIENTATION, attr );
456 
457  /* Right-aligned position values look much better, but only MSW and GTK2+
458  * currently support righ-aligned textEditCtrls, so the text jumps on all
459  * the other platforms when you edit it.
460  attr = new wxGridCellAttr;
461  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
462  m_grid->SetColAttr( COL_POSX, attr );
463 
464  attr = new wxGridCellAttr;
465  attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
466  m_grid->SetColAttr( COL_POSY, attr );
467  */
468 
469  m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
470  m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );
471  m_refreshButton->SetBitmap( KiBitmap( refresh_xpm ) );
472 
473  GetSizer()->SetSizeHints(this);
474  Centre();
475 
476  m_ButtonsOK->SetDefault();
477  m_initialized = true;
478  m_modified = false;
479  m_width = 0;
480 
481  // Connect Events
482  m_grid->Connect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
483 }
484 
485 
487 {
488  auto cfg = m_editFrame->GetSettings();
489  cfg->m_PinTableVisibleColumns = m_grid->GetShownColumns().ToStdString();
490 
491  // Disconnect Events
492  m_grid->Disconnect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
493 
494  // Prevents crash bug in wxGrid's d'tor
496 
497  // Delete the GRID_TRICKS.
498  m_grid->PopEventHandler( true );
499 
500  // This is our copy of the pins. If they were transfered to the part on an OK, then
501  // m_pins will already be empty.
502  for( auto pin : m_pins )
503  delete pin;
504 }
505 
506 
508 {
509  // Make a copy of the pins for editing
510  for( LIB_PIN* pin = m_part->GetNextPin( nullptr ); pin; pin = m_part->GetNextPin( pin ) )
511  m_pins.push_back( new LIB_PIN( *pin ) );
512 
513  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
514 
515  updateSummary();
516 
517  return true;
518 }
519 
520 
522 {
523  if( !m_grid->CommitPendingChanges() )
524  return false;
525 
526  // Delete the part's pins
527  while( LIB_PIN* pin = m_part->GetNextPin( nullptr ) )
528  m_part->RemoveDrawItem( pin );
529 
530  // Transfer our pins to the part
531  for( LIB_PIN* pin : m_pins )
532  {
533  pin->SetParent( m_part );
534  m_part->AddDrawItem( pin );
535  }
536 
537  m_pins.clear();
538 
539  return true;
540 }
541 
542 
543 void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent )
544 {
545  int sortCol = aEvent.GetCol();
546  bool ascending;
547 
548  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
549  // event, and if we ask it will give us pre-event info.
550  if( m_grid->IsSortingBy( sortCol ) )
551  // same column; invert ascending
552  ascending = !m_grid->IsSortOrderAscending();
553  else
554  // different column; start with ascending
555  ascending = true;
556 
557  m_dataModel->SortRows( sortCol, ascending );
558 }
559 
560 
561 void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
562 {
563  if( !m_grid->CommitPendingChanges() )
564  return;
565 
566  LIB_PIN* newPin = new LIB_PIN( nullptr );
567 
568  if( m_pins.size() > 0 )
569  {
570  LIB_PIN* last = m_pins.back();
571 
572  newPin->SetOrientation( last->GetOrientation() );
573  newPin->SetType( last->GetType() );
574  newPin->SetShape( last->GetShape() );
575 
576  wxPoint pos = last->GetPosition();
577 
578  LIBEDIT_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<LIBEDIT_SETTINGS>();
579 
580  if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
581  pos.y -= cfg->m_Repeat.pin_step;
582  else
583  pos.x += cfg->m_Repeat.pin_step;
584 
585  newPin->SetPosition( pos );
586  }
587 
588  m_pins.push_back( newPin );
589 
590  m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] );
591 
592  m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 );
593  m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 );
594 
595  m_grid->EnableCellEditControl( true );
596  m_grid->ShowCellEditControl();
597 
598  updateSummary();
599 }
600 
601 
602 void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
603 {
604  if( !m_grid->CommitPendingChanges() )
605  return;
606 
607  if( m_pins.size() == 0 ) // empty table
608  return;
609 
610  int curRow = m_grid->GetGridCursorRow();
611 
612  if( curRow < 0 )
613  return;
614 
615  LIB_PINS removedRow = m_dataModel->RemoveRow( curRow );
616 
617  for( auto pin : removedRow )
618  m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
619 
620  curRow = std::max( 0, curRow - 1 );
621  m_grid->MakeCellVisible( curRow, m_grid->GetGridCursorCol() );
622  m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
623 
624  updateSummary();
625 }
626 
627 
628 void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event )
629 {
630  updateSummary();
631 }
632 
633 
635 {
636  if( !m_grid->CommitPendingChanges() )
637  return;
638 
639  m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
640 
641  adjustGridColumns( m_grid->GetRect().GetWidth() );
642 }
643 
644 
646 {
647  m_width = aWidth;
648 
649  // Account for scroll bars
650  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
651 
652  wxGridUpdateLocker deferRepaintsTillLeavingScope;
653 
654  // The Number and Name columns must be at least wide enough to hold their contents, but
655  // no less wide than their original widths.
656 
657  m_grid->AutoSizeColumn( COL_NUMBER );
658 
659  if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] )
660  m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] );
661 
662  m_grid->AutoSizeColumn( COL_NAME );
663 
664  if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] )
665  m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] );
666 
667  // If the grid is still wider than the columns, then stretch the Number and Name columns
668  // to fit.
669 
670  for( int i = 0; i < COL_COUNT; ++i )
671  aWidth -= m_grid->GetColSize( i );
672 
673  if( aWidth > 0 )
674  {
675  m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + aWidth / 2 );
676  m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + aWidth / 2 );
677  }
678 }
679 
680 
681 void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event )
682 {
683  auto new_size = event.GetSize().GetX();
684 
685  if( m_initialized && m_width != new_size )
686  {
687  adjustGridColumns( new_size );
688  }
689 
690  // Always propagate for a grid repaint (needed if the height changes, as well as width)
691  event.Skip();
692 }
693 
694 
695 void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
696 {
697  wxString columnsShown = m_grid->GetShownColumns();
698 
699  if( columnsShown != m_columnsShown )
700  {
701  m_columnsShown = columnsShown;
702 
703  if( !m_grid->IsCellEditControlShown() )
704  adjustGridColumns( m_grid->GetRect().GetWidth() );
705  }
706 }
707 
708 
709 void DIALOG_LIB_EDIT_PIN_TABLE::OnCancel( wxCommandEvent& event )
710 {
711  Close();
712 }
713 
714 
715 void DIALOG_LIB_EDIT_PIN_TABLE::OnClose( wxCloseEvent& event )
716 {
717  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
718  m_grid->CommitPendingChanges( true );
719 
720  if( m_dataModel->IsEdited() )
721  {
722  if( !HandleUnsavedChanges( this, wxEmptyString,
723  [&]()->bool { return TransferDataFromWindow(); } ) )
724  {
725  event.Veto();
726  return;
727  }
728  }
729 
730  if( IsQuasiModal() )
731  EndQuasiModal( wxID_CANCEL );
732  else if( IsModal() )
733  EndModal( wxID_CANCEL );
734  else
735  event.Skip();
736 }
737 
738 
740 {
741  PinNumbers pinNumbers;
742 
743  for( LIB_PIN* pin : m_pins )
744  {
745  if( pin->GetNumber().Length() )
746  pinNumbers.insert( pin->GetNumber() );
747  }
748 
749  m_summary->SetLabel( pinNumbers.GetSummary() );
750 }
EDA_UNITS
Definition: common.h:198
static int Compare(PinNumber const &lhs, PinNumber const &rhs)
Definition: pin_number.cpp:111
const BITMAP_OPAQUE trash_xpm[1]
Definition: trash.cpp:46
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
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
static wxArrayString g_shapeNames
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:388
static std::vector< BITMAP_DEF > g_shapeIcons
void OnSize(wxSizeEvent &event) override
#define INDETERMINATE_STATE
void SetPosition(const wxPoint &aPosition)
Definition: lib_item.h:248
PIN_TABLE_DATA_MODEL(EDA_UNITS aUserUnits)
static int GetOrientationIndex(int aCode)
Get the index of the orientation code.
Definition: lib_pin.cpp:1632
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:1612
int GetOrientation() const
Definition: lib_pin.h:206
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:121
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:325
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:218
void OnAddRow(wxCommandEvent &event) override
wxString GetSummary() const
Definition: pin_number.cpp:71
void OnCellEdited(wxGridEvent &event) override
BITMAP_DEF GetBitmap(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:68
GRID_TRICKS is used to add mouse and command handling (such as cut, copy, and paste) to a WX_GRID ins...
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:1646
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:59
wxString m_PinTableVisibleColumns
void insert(value_type const &v)
Definition: pin_number.h:57
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:131
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:90
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
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)
wxString GetText(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:58
void OnRebuildRows(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
Define a library symbol object.
bool IsQuasiModal()
Definition: dialog_shim.h:123
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:174
const wxPoint GetPosition() const override
Definition: lib_pin.h:430
wxString GetColLabelValue(int aCol) override
PIN_TABLE_DATA_MODEL * m_dataModel
wxString GetValue(int aRow, int aCol) override
const BITMAP_OPAQUE refresh_xpm[1]
Definition: refresh.cpp:32
static bool compare(const LIB_PINS &lhs, const LIB_PINS &rhs, int sortCol, bool ascending, EDA_UNITS units)
YYCODETYPE lhs
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:103
ELECTRICAL_PINTYPE GetType() const
Get the electrical type of the pin.
Definition: lib_pin.h:234
void EndQuasiModal(int retCode)
static int findRow(const std::vector< LIB_PINS > &aRowSet, const wxString &aName)
The symbol library editor main window.
see class PGM_BASE
void OnDeleteRow(wxCommandEvent &event) override
ELECTRICAL_PINTYPE
The component library pin object electrical types used in ERC tests.
Definition: pin_type.h:37
#define _(s)
Definition: 3d_actions.cpp:33
void SetType(ELECTRICAL_PINTYPE aType, bool aTestOtherPins=true)
Set the electrical type of the pin.
Definition: lib_pin.cpp:352
void OnColSort(wxGridEvent &aEvent)
LIBEDIT_SETTINGS * GetSettings()
static wxString GetValue(const LIB_PINS &pins, int aCol, EDA_UNITS aUserUnits)
void SetValue(int aRow, int aCol, const wxString &aValue) override
#define GRAPHIC_PINSHAPES_TOTAL
Definition: pin_shape.h:50
void SetOrientation(int aOrientation, bool aTestOtherPins=true)
Set orientation on the pin.
Definition: lib_pin.cpp:296
static std::vector< BITMAP_DEF > g_typeIcons
#define ELECTRICAL_PINTYPES_TOTAL
Definition: pin_type.h:54
std::vector< LIB_PINS > m_rows
void OnCancel(wxCommandEvent &event) override
const BITMAP_OPAQUE small_plus_xpm[1]
Definition: small_plus.cpp:20
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils, EDA_DATA_TYPE aType)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:233
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:471
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:1623