KiCad PCB EDA Suite
net_selector.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) 2018 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 
24 #include <string_utils.h>
25 #include <kiplatform/ui.h>
26 
27 #include <widgets/ui_common.h>
28 #include <widgets/net_selector.h>
29 
30 #include <board.h>
31 #include <netinfo.h>
32 #include <wx/arrstr.h>
33 #include <wx/display.h>
34 #include <wx/valtext.h>
35 #include <wx/listbox.h>
36 #include <wx/stattext.h>
37 #include <wx/sizer.h>
38 #include <wx/textctrl.h>
39 #include <wx/panel.h>
40 
41 
42 wxDEFINE_EVENT( NET_SELECTED, wxCommandEvent );
43 
44 #if defined( __WXOSX_MAC__ )
45  #define POPUP_PADDING 2
46  #define LIST_ITEM_PADDING 5
47  #define LIST_PADDING 5
48 #elif defined( __WXMSW__ )
49  #define POPUP_PADDING 0
50  #define LIST_ITEM_PADDING 2
51  #define LIST_PADDING 5
52 #else
53  #define POPUP_PADDING 0
54  #define LIST_ITEM_PADDING 6
55  #define LIST_PADDING 5
56 #endif
57 
58 #define NO_NET _( "<no net>" )
59 #define CREATE_NET _( "<create net>" )
60 
61 
62 class NET_SELECTOR_COMBOPOPUP : public wxPanel, public wxComboPopup
63 {
64 public:
66  m_filterValidator( nullptr ),
67  m_filterCtrl( nullptr ),
68  m_listBox( nullptr ),
69  m_minPopupWidth( -1 ),
70  m_maxPopupHeight( 1000 ),
71  m_netinfoList( nullptr ),
72  m_board( nullptr ),
73  m_selectedNetcode( 0 ),
74  m_focusHandler( nullptr )
75  { }
76 
77  bool Create(wxWindow* aParent) override
78  {
79  wxPanel::Create( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER );
80 
81  wxBoxSizer* mainSizer;
82  mainSizer = new wxBoxSizer( wxVERTICAL );
83 
84  wxStaticText* filterLabel = new wxStaticText( this, wxID_ANY, _( "Filter:" ) );
85  mainSizer->Add( filterLabel, 0, wxEXPAND, 0 );
86 
87  m_filterCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
88  wxDefaultSize, wxTE_PROCESS_ENTER );
89  m_filterValidator = new wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
90  m_filterValidator->SetCharExcludes( " " );
91  m_filterCtrl->SetValidator( *m_filterValidator );
92  mainSizer->Add( m_filterCtrl, 0, wxEXPAND, 0 );
93 
94  m_listBox = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr,
95  wxLB_SINGLE|wxLB_NEEDED_SB );
96  mainSizer->Add( m_listBox, 0, wxEXPAND|wxTOP, 2 );
97 
98  SetSizer( mainSizer );
99  Layout();
100 
101  Connect( wxEVT_IDLE, wxIdleEventHandler( NET_SELECTOR_COMBOPOPUP::onIdle ), nullptr, this );
102  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( NET_SELECTOR_COMBOPOPUP::onKeyDown ), nullptr, this );
103  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( NET_SELECTOR_COMBOPOPUP::onMouseClick ), nullptr, this );
104  m_listBox->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( NET_SELECTOR_COMBOPOPUP::onMouseClick ), nullptr, this );
105  m_filterCtrl->Connect( wxEVT_TEXT, wxCommandEventHandler( NET_SELECTOR_COMBOPOPUP::onFilterEdit ), nullptr, this );
106  m_filterCtrl->Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( NET_SELECTOR_COMBOPOPUP::onEnter ), nullptr, this );
107 
108  // <enter> in a ListBox comes in as a double-click on GTK
109  m_listBox->Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( NET_SELECTOR_COMBOPOPUP::onEnter ), nullptr, this );
110 
111  return true;
112  }
113 
114  wxWindow *GetControl() override { return this; }
115 
116  void SetStringValue( const wxString& aNetName ) override
117  {
118  // shouldn't be here (combo is read-only)
119  }
120 
121  wxString GetStringValue() const override
122  {
123  if( m_selectedNetcode == -1 )
124  return m_indeterminateLabel;
125 
127 
128  if( netInfo && netInfo->GetNetCode() > 0 )
129  return netInfo->GetNetname();
130 
131  return NO_NET;
132  }
133 
134  void SetNetInfo( NETINFO_LIST* aNetInfoList )
135  {
136  m_netinfoList = aNetInfoList;
137  rebuildList();
138  }
139 
140  void SetIndeterminateLabel( const wxString& aIndeterminateLabel )
141  {
142  m_indeterminateLabel = aIndeterminateLabel;
143  rebuildList();
144  }
145 
146  void SetBoard( BOARD* aBoard )
147  {
148  m_board = aBoard;
149  }
150 
152  bool IsIndeterminate() { return m_selectedNetcode == -1; }
153 
154  void SetSelectedNetcode( int aNetcode ) { m_selectedNetcode = aNetcode; }
156 
157  void SetSelectedNet( const wxString& aNetname )
158  {
159  if( m_netinfoList && m_netinfoList->GetNetItem( aNetname ) )
161  }
162 
164  {
167  else
168  return wxEmptyString;
169  }
170 
171  wxSize GetAdjustedSize( int aMinWidth, int aPrefHeight, int aMaxHeight ) override
172  {
173  // Called when the popup is first shown. Stash the minWidth and maxHeight so we
174  // can use them later when refreshing the sizes after filter changes.
175  m_minPopupWidth = aMinWidth;
176  m_maxPopupHeight = aMaxHeight;
177 
178  return updateSize();
179  }
180 
181  void OnPopup() override
182  {
183  // While it can sometimes be useful to keep the filter, it's always unexpected.
184  // Better to clear it.
185  m_filterCtrl->Clear();
186 
187  // The updateSize() call in GetAdjustedSize() leaves the height off-by-one for
188  // some reason, so do it again.
189  updateSize();
190  }
191 
192  void OnStartingKey( wxKeyEvent& aEvent )
193  {
195  doStartingKey( aEvent );
196  }
197 
198  void Accept()
199  {
200  wxString selectedNetName;
201  wxString escapedNetName;
202  wxString remainingName;
203  int selection = m_listBox->GetSelection();
204  wxString prefix = CREATE_NET;
205 
206  if( selection >= 0 )
207  selectedNetName = m_listBox->GetString( (unsigned) selection );
208 
209  auto it = m_unescapedNetNameMap.find( selectedNetName );
210 
211  if( it != m_unescapedNetNameMap.end() )
212  escapedNetName = it->second;
213  else // shouldn't happen....
214  escapedNetName = selectedNetName;
215 
216  Dismiss();
217 
218  if( escapedNetName.IsEmpty() || escapedNetName == m_indeterminateLabel )
219  {
220  m_selectedNetcode = -1;
221  GetComboCtrl()->SetValue( m_indeterminateLabel );
222  }
223  else if( escapedNetName == NO_NET )
224  {
225  m_selectedNetcode = 0;
226  GetComboCtrl()->SetValue( NO_NET );
227  }
228  else if( escapedNetName.StartsWith( CREATE_NET, &remainingName ) &&
229  !remainingName.IsEmpty() )
230  {
231  // Remove the first character ':' and all whitespace
232  remainingName = remainingName.Mid( 1 ).Trim().Trim( false );
233 
234  BOARD* board = m_netinfoList->GetParent();
235  NETINFO_ITEM *newnet = new NETINFO_ITEM( m_board, remainingName, 0 );
236 
237  // add the new netinfo through the board's function so that
238  // board listeners get notified and things stay in sync.
239  if( board != nullptr )
240  board->Add( newnet );
241  else
242  m_netinfoList->AppendNet( newnet );
243 
244  rebuildList();
245 
246  if( newnet->GetNetCode() > 0 )
247  {
248  m_selectedNetcode = newnet->GetNetCode();
249  GetComboCtrl()->SetValue( UnescapeString( remainingName ) );
250  }
251  else
252  {
253  // This indicates that the NETINFO_ITEM was not successfully appended
254  // to the list for unknown reasons
255  if( board != nullptr )
256  board->Remove( newnet );
257  else
258  m_netinfoList->RemoveNet( newnet );
259 
260  delete newnet;
261  }
262  }
263  else
264  {
265  NETINFO_ITEM* netInfo = m_netinfoList->GetNetItem( escapedNetName );
266 
267  if( netInfo == nullptr || netInfo->GetNetCode() == 0 )
268  {
269  m_selectedNetcode = 0;
270  GetComboCtrl()->SetValue( NO_NET );
271  }
272  else
273  {
274  m_selectedNetcode = netInfo->GetNetCode();
275  GetComboCtrl()->SetValue( UnescapeString( escapedNetName ) );
276  }
277  }
278 
279  wxCommandEvent changeEvent( NET_SELECTED );
280  wxPostEvent( GetComboCtrl(), changeEvent );
281  }
282 
283 protected:
284  wxSize updateSize()
285  {
286  int listTop = m_listBox->GetRect().y;
287  int itemHeight = KIUI::GetTextSize( wxT( "Xy" ), this ).y + LIST_ITEM_PADDING;
288  int listHeight = m_listBox->GetCount() * itemHeight + LIST_PADDING;
289 
290  if( listTop + listHeight >= m_maxPopupHeight )
291  listHeight = m_maxPopupHeight - listTop - 1;
292 
293  int listWidth = m_minPopupWidth;
294 
295  for( size_t i = 0; i < m_listBox->GetCount(); ++i )
296  {
297  int itemWidth = KIUI::GetTextSize( m_listBox->GetString( i ), m_listBox ).x;
298  listWidth = std::max( listWidth, itemWidth + LIST_PADDING * 3 );
299  }
300 
301  wxSize listSize( listWidth, listHeight );
302  wxSize popupSize( listWidth, listTop + listHeight );
303 
304  SetSize( popupSize ); // us
305  GetParent()->SetSize( popupSize ); // the window that wxComboCtrl put us in
306 
307  m_listBox->SetMinSize( listSize );
308  m_listBox->SetSize( listSize );
309 
310  return popupSize;
311  }
312 
313  void rebuildList()
314  {
315  wxArrayString netNames;
316  wxString netstring = m_filterCtrl->GetValue().Trim().Trim( false );
317  wxString filter = netstring.Lower();
318 
319  m_unescapedNetNameMap.clear();
320 
321  if( !filter.IsEmpty() )
322  filter = wxT( "*" ) + filter + wxT( "*" );
323 
324  for( NETINFO_ITEM* netinfo : *m_netinfoList )
325  {
326  if( netinfo->GetNetCode() > 0 && netinfo->IsCurrent() )
327  {
328  wxString netname = UnescapeString( netinfo->GetNetname() );
329 
330  if( filter.IsEmpty() || wxString( netname ).MakeLower().Matches( filter ) )
331  {
332  netNames.push_back( netname );
333  m_unescapedNetNameMap[ netname ] = netinfo->GetNetname();
334  }
335  }
336  }
337 
338  std::sort( netNames.begin(), netNames.end() );
339 
340  // Special handling for <no net>
341  if( filter.IsEmpty() || wxString( NO_NET ).MakeLower().Matches( filter ) )
342  netNames.insert( netNames.begin(), NO_NET );
343 
344  if( !filter.IsEmpty() && !m_netinfoList->GetNetItem( netstring ) )
345  {
346  wxString newnet = wxString::Format( "%s: %s", CREATE_NET, netstring );
347  netNames.insert( netNames.end(), newnet );
348  }
349 
350  if( !m_indeterminateLabel.IsEmpty() )
351  netNames.push_back( m_indeterminateLabel );
352 
353  m_listBox->Set( netNames );
354  }
355 
356  void onIdle( wxIdleEvent& aEvent )
357  {
358  // Generate synthetic (but reliable) MouseMoved events
359  static wxPoint lastPos;
360  wxPoint screenPos = wxGetMousePosition();
361 
362  if( screenPos != lastPos )
363  {
364  lastPos = screenPos;
365  onMouseMoved( screenPos );
366  }
367 
368  if( m_focusHandler )
369  {
370  m_filterCtrl->PushEventHandler( m_focusHandler );
371  m_focusHandler = nullptr;
372  }
373  }
374 
375  // Hot-track the mouse (for focus and listbox selection)
376  void onMouseMoved( const wxPoint aScreenPos )
377  {
378  if( m_listBox->GetScreenRect().Contains( aScreenPos ) )
379  {
381 
382  wxPoint relativePos = m_listBox->ScreenToClient( aScreenPos );
383  int item = m_listBox->HitTest( relativePos );
384 
385  if( item >= 0 )
386  m_listBox->SetSelection( item );
387  }
388  else if( m_filterCtrl->GetScreenRect().Contains( aScreenPos ) )
389  {
391  }
392  }
393 
394  void onMouseClick( wxMouseEvent& aEvent )
395  {
396  // Accept a click event from anywhere. Different platform implementations have
397  // different foibles with regard to transient popups and their children.
398 
399  if( aEvent.GetEventObject() == m_listBox )
400  {
401  m_listBox->SetSelection( m_listBox->HitTest( aEvent.GetPosition() ) );
402  Accept();
403  return;
404  }
405 
406  wxWindow* window = dynamic_cast<wxWindow*>( aEvent.GetEventObject() );
407 
408  if( window )
409  {
410  wxPoint screenPos = window->ClientToScreen( aEvent.GetPosition() );
411 
412  if( m_listBox->GetScreenRect().Contains( screenPos ) )
413  {
414  wxPoint localPos = m_listBox->ScreenToClient( screenPos );
415 
416  m_listBox->SetSelection( m_listBox->HitTest( localPos ) );
417  Accept();
418  }
419  }
420  }
421 
422  void onKeyDown( wxKeyEvent& aEvent )
423  {
424  switch( aEvent.GetKeyCode() )
425  {
426  // Control keys go to the parent combobox
427  case WXK_TAB:
428  Dismiss();
429 
430  m_parent->NavigateIn( ( aEvent.ShiftDown() ? 0 : wxNavigationKeyEvent::IsForward ) |
431  ( aEvent.ControlDown() ? wxNavigationKeyEvent::WinChange : 0 ) );
432  break;
433 
434  case WXK_ESCAPE:
435  Dismiss();
436  break;
437 
438  case WXK_RETURN:
439  Accept();
440  break;
441 
442  // Arrows go to the list box
443  case WXK_DOWN:
444  case WXK_NUMPAD_DOWN:
446  m_listBox->SetSelection( std::min( m_listBox->GetSelection() + 1, (int) m_listBox->GetCount() - 1 ) );
447  break;
448 
449  case WXK_UP:
450  case WXK_NUMPAD_UP:
452  m_listBox->SetSelection( std::max( m_listBox->GetSelection() - 1, 0 ) );
453  break;
454 
455  // Everything else goes to the filter textbox
456  default:
457  if( !m_filterCtrl->HasFocus() )
458  {
460 
461  // Because we didn't have focus we missed our chance to have the native widget
462  // handle the keystroke. We'll have to do the first character ourselves.
463  doStartingKey( aEvent );
464  }
465  else
466  {
467  // On some platforms a wxComboFocusHandler will have been pushed which
468  // unhelpfully gives the event right back to the popup. Make sure the filter
469  // control is going to get the event.
470  if( m_filterCtrl->GetEventHandler() != m_filterCtrl )
471  m_focusHandler = m_filterCtrl->PopEventHandler();
472 
473  aEvent.Skip();
474  }
475  break;
476  }
477  }
478 
479  void onEnter( wxCommandEvent& aEvent )
480  {
481  Accept();
482  }
483 
484  void onFilterEdit( wxCommandEvent& aEvent )
485  {
486  rebuildList();
487  updateSize();
488 
489  if( m_listBox->GetCount() > 0 )
490  m_listBox->SetSelection( 0 );
491  }
492 
493  void doStartingKey( wxKeyEvent& aEvent )
494  {
495  if( aEvent.GetKeyCode() == WXK_BACK )
496  {
497  const long pos = m_filterCtrl->GetLastPosition();
498  m_filterCtrl->Remove( pos - 1, pos );
499  }
500  else
501  {
502  bool isPrintable;
503  int ch = aEvent.GetUnicodeKey();
504 
505  if( ch != WXK_NONE )
506  isPrintable = true;
507  else
508  {
509  ch = aEvent.GetKeyCode();
510  isPrintable = ch > WXK_SPACE && ch < WXK_START;
511  }
512 
513  if( isPrintable )
514  {
515  wxString text( static_cast<wxChar>( ch ) );
516 
517  // wxCHAR_HOOK chars have been converted to uppercase.
518  if( !aEvent.ShiftDown() )
519  text.MakeLower();
520 
521  m_filterCtrl->AppendText( text );
522  }
523  }
524  }
525 
526  void doSetFocus( wxWindow* aWindow )
527  {
528  KIPLATFORM::UI::ForceFocus( aWindow );
529  }
530 
531 protected:
532  wxTextValidator* m_filterValidator;
533  wxTextCtrl* m_filterCtrl;
534  wxListBox* m_listBox;
537 
541 
543 
544  std::map<wxString, wxString> m_unescapedNetNameMap;
545 
546  wxEvtHandler* m_focusHandler;
547 };
548 
549 
550 NET_SELECTOR::NET_SELECTOR( wxWindow *parent, wxWindowID id, const wxPoint &pos,
551  const wxSize &size, long style ) :
552  wxComboCtrl( parent, id, wxEmptyString, pos, size, style|wxCB_READONLY|wxTE_PROCESS_ENTER )
553 {
554  UseAltPopupWindow();
555 
557  SetPopupControl( m_netSelectorPopup );
558 
559  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( NET_SELECTOR::onKeyDown ), nullptr, this );
560 }
561 
562 
564 {
565  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( NET_SELECTOR::onKeyDown ), nullptr, this );
566 }
567 
568 
569 void NET_SELECTOR::onKeyDown( wxKeyEvent& aEvt )
570 {
571  int key = aEvt.GetKeyCode();
572 
573  if( IsPopupShown() )
574  {
575  // If the popup is shown then it's CHAR_HOOK should be eating these before they
576  // even get to us. But just to be safe, we go ahead and skip.
577  aEvt.Skip();
578  }
579 
580  // Shift-return accepts dialog
581  else if( key == WXK_RETURN && aEvt.ShiftDown() )
582  {
583  wxPostEvent( m_parent, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
584  }
585 
586  // Return, arrow-down and space-bar all open popup
587  else if( key == WXK_RETURN || key == WXK_DOWN || key == WXK_NUMPAD_DOWN || key == WXK_SPACE )
588  {
589  Popup();
590  }
591 
592  // Non-control characters go to filterbox in popup
593  else if( key > WXK_SPACE && key < WXK_START )
594  {
595  Popup();
597  }
598 
599  else
600  {
601  aEvt.Skip();
602  }
603 }
604 
605 
607 {
608  m_netSelectorPopup->SetNetInfo( aNetInfoList );
609 }
610 
611 
612 void NET_SELECTOR::SetIndeterminateString( const wxString& aString )
613 {
614  m_indeterminateString = aString;
616 }
617 
618 
620 {
621  m_netSelectorPopup->SetBoard( aBoard );
622 }
623 
624 
626 {
629 }
630 
631 
632 void NET_SELECTOR::SetSelectedNet( const wxString& aNetname )
633 {
634  m_netSelectorPopup->SetSelectedNet( aNetname );
636 }
637 
638 
640 {
642 }
643 
644 
646 {
648  SetValue( m_indeterminateString );
649 }
650 
651 
653 {
655 }
656 
657 
659 {
661 }
662 
void SetIndeterminateString(const wxString &aString)
#define CREATE_NET
void SetSelectedNet(const wxString &aNetname)
BOARD * GetParent() const
Definition: netinfo.h:447
void onIdle(wxIdleEvent &aEvent)
void onFilterEdit(wxCommandEvent &aEvent)
wxTextValidator * m_filterValidator
void SetBoard(BOARD *aBoard)
wxString GetStringValue() const override
void SetNetInfo(NETINFO_LIST *aNetInfoList)
void SetSelectedNetcode(int aNetcode)
int GetSelectedNetcode()
wxEvtHandler * m_focusHandler
NET_SELECTOR(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0)
wxSize GetAdjustedSize(int aMinWidth, int aPrefHeight, int aMaxHeight) override
NETINFO_LIST * m_netinfoList
std::map< wxString, wxString > m_unescapedNetNameMap
wxString GetSelectedNetname()
bool Create(wxWindow *aParent) override
void SetBoard(BOARD *aBoard)
void AppendNet(NETINFO_ITEM *aNewElement)
Add aNewElement to the end of the net list.
wxWindow * GetControl() override
void onKeyDown(wxKeyEvent &aEvent)
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:608
void RemoveNet(NETINFO_ITEM *aNet)
Remove a net from the net list.
wxDEFINE_EVENT(NET_SELECTED, wxCommandEvent)
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: ui_common.cpp:70
void onKeyDown(wxKeyEvent &aEvt)
Container for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:315
void SetSelectedNetcode(int aNetcode)
bool IsIndeterminate()
const wxString & GetNetname() const
Definition: netinfo.h:119
Functions to provide common constants and other functions to assist in making a consistent UI.
#define LIST_ITEM_PADDING
#define _(s)
void OnPopup() override
void SetNetInfo(NETINFO_LIST *aNetInfoList)
void SetStringValue(const wxString &aNetName) override
void SetIndeterminateLabel(const wxString &aIndeterminateLabel)
#define NO_NET
wxString UnescapeString(const wxString &aSource)
wxString m_indeterminateString
Definition: net_selector.h:68
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
void doStartingKey(wxKeyEvent &aEvent)
Handle the data for a net.
Definition: netinfo.h:64
void SetIndeterminate()
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
void onEnter(wxCommandEvent &aEvent)
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition: gtk/ui.cpp:44
void SetSelectedNet(const wxString &aNetname)
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:710
~NET_SELECTOR() override
#define LIST_PADDING
void OnStartingKey(wxKeyEvent &aEvent)
void doSetFocus(wxWindow *aWindow)
NETINFO_ITEM * GetNetItem(int aNetCode) const
void onMouseClick(wxMouseEvent &aEvent)
NET_SELECTOR_COMBOPOPUP * m_netSelectorPopup
Definition: net_selector.h:67
void onMouseMoved(const wxPoint aScreenPos)
int GetNetCode() const
Definition: netinfo.h:113