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