KiCad PCB EDA Suite
widget_hotkey_list.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) 2016 Chris Pavlina <[email protected]>
5  * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <cctype>
26 
27 #include <confirm.h>
29 #include <tool/tool_event.h>
30 #include <dialog_shim.h>
31 
32 #include <wx/log.h>
33 #include <wx/dcclient.h>
34 #include <wx/menu.h>
35 #include <wx/msgdlg.h>
36 #include <wx/statline.h>
37 #include <wx/stattext.h>
38 #include <wx/treelist.h>
39 
44 {
49 };
50 
51 
58 class WIDGET_HOTKEY_CLIENT_DATA : public wxClientData
59 {
61 
62 public:
63  WIDGET_HOTKEY_CLIENT_DATA( HOTKEY& aChangedHotkey ) :
64  m_changed_hotkey( aChangedHotkey )
65  {}
66 
68 };
69 
70 
75 {
76 public:
77  HK_PROMPT_DIALOG( wxWindow* aParent, wxWindowID aId, const wxString& aTitle,
78  const wxString& aName, const wxString& aCurrentKey ) :
79  DIALOG_SHIM( aParent, aId, aTitle, wxDefaultPosition, wxDefaultSize )
80  {
81  wxPanel* panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize );
82  wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
83 
84  /* Dialog layout:
85  *
86  * inst_label........................
87  * ----------------------------------
88  *
89  * cmd_label_0 cmd_label_1 \
90  * | fgsizer
91  * key_label_0 key_label_1 /
92  */
93 
94  wxStaticText* inst_label = new wxStaticText( panel, wxID_ANY, wxEmptyString,
95  wxDefaultPosition, wxDefaultSize,
96  wxALIGN_CENTRE_HORIZONTAL );
97 
98  inst_label->SetLabelText( _( "Press a new hotkey, or press Esc to cancel..." ) );
99  sizer->Add( inst_label, 0, wxALL, 5 );
100 
101  sizer->Add( new wxStaticLine( panel ), 0, wxALL | wxEXPAND, 2 );
102 
103  wxFlexGridSizer* fgsizer = new wxFlexGridSizer( 2 );
104 
105  wxStaticText* cmd_label_0 = new wxStaticText( panel, wxID_ANY, _( "Command:" ) );
106  fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
107 
108  wxStaticText* cmd_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
109  cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
110  cmd_label_1->SetLabel( aName );
111  fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
112 
113  wxStaticText* key_label_0 = new wxStaticText( panel, wxID_ANY, _( "Current key:" ) );
114  fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
115 
116  wxStaticText* key_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
117  key_label_1->SetFont( key_label_1->GetFont().Bold() );
118  key_label_1->SetLabel( aCurrentKey );
119  fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
120 
121  sizer->Add( fgsizer, 1, wxEXPAND );
122 
123  // Wrap the sizer in a second to give a larger border around the whole dialog
124  wxBoxSizer* outer_sizer = new wxBoxSizer( wxVERTICAL );
125  outer_sizer->Add( sizer, 0, wxALL | wxEXPAND, 10 );
126  panel->SetSizer( outer_sizer );
127 
128  Layout();
129  outer_sizer->Fit( this );
130  Center();
131 
132  SetMinClientSize( GetClientSize() );
133 
134  // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events, including
135  // specials like Tab and Return, are received, particularly on MSW.
136  panel->Bind( wxEVT_CHAR, &HK_PROMPT_DIALOG::OnChar, this );
137  panel->Bind( wxEVT_CHAR_HOOK, &HK_PROMPT_DIALOG::OnCharHook, this );
138  panel->Bind( wxEVT_KEY_UP, &HK_PROMPT_DIALOG::OnKeyUp, this );
139  SetInitialFocus( panel );
140  }
141 
142  static wxKeyEvent PromptForKey( wxWindow* aParent, const wxString& aName,
143  const wxString& aCurrentKey )
144  {
145  HK_PROMPT_DIALOG dialog( aParent, wxID_ANY, _( "Set Hotkey" ), aName, aCurrentKey );
146 
147  if( dialog.ShowModal() == wxID_OK )
148  return dialog.m_event;
149  else
150  return wxKeyEvent();
151  }
152 
153 protected:
154  void OnCharHook( wxKeyEvent& aEvent ) override
155  {
156  // On certain platforms, EVT_CHAR_HOOK is the only handler that receives certain
157  // "special" keys. However, it doesn't always receive "normal" keys correctly. For
158  // example, with a US keyboard, it sees ? as shift+/.
159  //
160  // Untangling these incorrect keys would be too much trouble, so we bind both events,
161  // and simply skip the EVT_CHAR_HOOK if it receives a "normal" key.
162 
163  const enum wxKeyCode skipped_keys[] =
164  {
165  WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL, WXK_NUMLOCK, WXK_SCROLL,
166  WXK_RAW_CONTROL
167  };
168 
169  int key = aEvent.GetKeyCode();
170 
171  for( wxKeyCode skipped_key : skipped_keys )
172  {
173  if( key == skipped_key )
174  return;
175  }
176 
177  if( key <= 255 && isprint( key ) && !isspace( key ) )
178  {
179  // Let EVT_CHAR handle this one
180  aEvent.DoAllowNextEvent();
181 
182  // On Windows, wxEvent::Skip must NOT be called.
183  // On Linux and OSX, wxEvent::Skip MUST be called.
184  // No, I don't know why.
185 #ifndef __WXMSW__
186  aEvent.Skip();
187 #endif
188  }
189  else
190  {
191  OnChar( aEvent );
192  }
193  }
194 
195  void OnChar( wxKeyEvent& aEvent )
196  {
197  m_event = aEvent;
198  }
199 
200  void OnKeyUp( wxKeyEvent& aEvent )
201  {
202  // If dialog opened using Enter key, prevent closing when releasing Enter.
203  if( m_event.GetEventType() != wxEVT_NULL )
204  {
206  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
207  }
208  }
209 
210 private:
211  wxKeyEvent m_event;
212 };
213 
214 
219 {
220 public:
221  HOTKEY_FILTER( const wxString& aFilterStr )
222  {
223  m_normalised_filter_str = aFilterStr.Upper();
224  m_valid = m_normalised_filter_str.size() > 0;
225  }
226 
232  bool FilterMatches( const HOTKEY& aHotkey ) const
233  {
234  if( !m_valid )
235  return true;
236 
237  // Match in the (translated) filter string
238  const auto normedInfo = wxGetTranslation( aHotkey.m_Actions[ 0 ]->GetLabel() ).Upper();
239 
240  if( normedInfo.Contains( m_normalised_filter_str ) )
241  return true;
242 
243  const wxString keyName = KeyNameFromKeyCode( aHotkey.m_EditKeycode );
244 
245  if( keyName.Upper().Contains( m_normalised_filter_str ) )
246  return true;
247 
248  return false;
249  }
250 
251 private:
252  bool m_valid;
254 };
255 
256 
258 {
259  if( aItem.IsOk() )
260  {
261  wxClientData* data = GetItemData( aItem );
262 
263  if( data )
264  return static_cast<WIDGET_HOTKEY_CLIENT_DATA*>( data );
265  }
266 
267  return nullptr;
268 }
269 
270 
272 {
273  const auto hkdata = getHKClientData( aItem );
274 
275  // This probably means a hotkey-only action is being attempted on
276  // a row that is not a hotkey (like a section heading)
277  wxASSERT_MSG( hkdata != nullptr, "No hotkey data found for list item" );
278 
279  return hkdata;
280 }
281 
282 
284 {
285  for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
286  {
288 
289  if( hkdata )
290  {
291  const HOTKEY& changed_hk = hkdata->GetChangedHotkey();
292  wxString label = changed_hk.m_Actions[ 0 ]->GetLabel();
293  wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode );
294  wxString description = changed_hk.m_Actions[ 0 ]->GetDescription( false );
295 
296  if( label.IsEmpty() )
297  label = changed_hk.m_Actions[ 0 ]->GetName();
298 
299  // mark unsaved changes
300  if( changed_hk.m_EditKeycode != changed_hk.m_Actions[ 0 ]->GetHotKey() )
301  label += " *";
302 
303  SetItemText( i, 0, label );
304  SetItemText( i, 1, key_text);
305  SetItemText( i, 2, description );
306  }
307  }
308 }
309 
310 
311 void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey )
312 {
313  // See if this key code is handled in hotkeys names list
314  bool exists;
315  KeyNameFromKeyCode( aKey, &exists );
316 
317  if( exists && aHotkey.m_EditKeycode != aKey )
318  {
319  if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) )
320  aHotkey.m_EditKeycode = aKey;
321  }
322 }
323 
324 
325 void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem )
326 {
328 
329  if( !hkdata )
330  return;
331 
332  wxString name = GetItemText( aItem, 0 );
333  wxString current_key = GetItemText( aItem, 1 );
334 
335  wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( this, name, current_key );
336  long key = MapKeypressToKeycode( key_event );
337 
338  if( key )
339  {
340  auto it = m_reservedHotkeys.find( key );
341 
342  if( it != m_reservedHotkeys.end() )
343  {
344  wxString msg = wxString::Format(
345  _( "'%s' is a reserved hotkey in KiCad and cannot be assigned." ),
346  it->second );
347 
348  DisplayErrorMessage( this, msg );
349  return;
350  }
351 
352  changeHotkey( hkdata->GetChangedHotkey(), key );
354  }
355 }
356 
357 
358 void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
359 {
361 
362  if( !hkdata )
363  return;
364 
365  HOTKEY& changed_hk = hkdata->GetChangedHotkey();
366 
367  if( aResetId == ID_RESET )
368  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetHotKey() );
369  else if( aResetId == ID_CLEAR )
370  changeHotkey( changed_hk, 0 );
371  else if( aResetId == ID_DEFAULT )
372  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetDefaultHotKey() );
373 
375 }
376 
377 
378 void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
379 {
380  editItem( aEvent.GetItem());
381 }
382 
383 
384 void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
385 {
386  // Save the active event for use in OnMenu
387  m_context_menu_item = aEvent.GetItem();
388 
389  wxMenu menu;
390 
392 
393  // Some actions only apply if the row is hotkey data
394  if( hkdata )
395  {
396  menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
397  menu.Append( ID_RESET, _( "Undo Changes" ) );
398  menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
399  menu.Append( ID_DEFAULT, _( "Restore Default" ) );
400  menu.Append( wxID_SEPARATOR );
401 
402  PopupMenu( &menu );
403  }
404 }
405 
406 
407 void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
408 {
409  switch( aEvent.GetId() )
410  {
412  break;
413 
414  case ID_RESET:
415  case ID_CLEAR:
416  case ID_DEFAULT:resetItem( m_context_menu_item, aEvent.GetId());
417  break;
418 
419  default:
420  wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
421  }
422 }
423 
424 
426 {
427  HOTKEY* conflictingHotKey = nullptr;
428 
429  m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
430 
431  if( !conflictingHotKey )
432  return true;
433 
434  TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
435  wxString msg = wxString::Format( _( "'%s' is already assigned to '%s' in section '%s'. "
436  "Are you sure you want to change its assignment?" ),
437  KeyNameFromKeyCode( aKey ),
438  conflictingAction->GetLabel(),
439  HOTKEY_STORE::GetSectionName( conflictingAction ) );
440 
441  wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
442 
443  if( dlg.ShowModal() == wxID_YES )
444  {
445  // Reset the other hotkey
446  conflictingHotKey->m_EditKeycode = 0;
448  return true;
449  }
450 
451  return false;
452 }
453 
454 
455 WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
456  bool aReadOnly ) :
457  wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
458  m_hk_store( aHotkeyStore ),
459  m_readOnly( aReadOnly )
460 {
461  wxString command_header = _( "Command" );
462 
463  if( !m_readOnly )
464  command_header << " " << _( "(double-click to edit)" );
465 
466  AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
467  AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
468  AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
469 
470 
471 #if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
472  // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
473  // They are also broken in wxGTK 3.1.4
474 
475  wxDataViewCtrl* dv = GetDataView();
476 
477  wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
478  int pad = 20;
479 
480  dv->GetColumn( 0 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( command_header ).x + pad );
481  dv->GetColumn( 1 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( longKey ).x + pad );
482 
483  CallAfter( [&]()
484  {
485  GetDataView()->Update();
486  } );
487  #endif
488 
489  std::vector<wxString> reserved_keys =
490  {
491  "Ctrl+Tab",
492  "Ctrl+Shift+Tab"
493  };
494 
495  for( auto& key : reserved_keys )
496  {
497  long code = KeyCodeFromKeyName( key );
498 
499  if( code )
500  m_reservedHotkeys[code] = key;
501  else
502  {
503  wxLogWarning( "Unknown reserved keycode %s\n", key );
504  }
505  }
506 
507  GetDataView()->SetIndent( 10 );
508 
509  if( !m_readOnly )
510  {
511  // The event only apply if the widget is in editable mode
512  Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
513  Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
514  Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
515  }
516 }
517 
518 
519 void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
520 {
521  updateShownItems( aFilterStr );
522 }
523 
524 
525 void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
526 {
527  Freeze();
528 
529  // Reset all the hotkeys, not just the ones shown
530  // Should not need to check conflicts, as the state we're about
531  // to set to a should be consistent
532  if( aResetToDefault )
534  else
536 
539 
540  Thaw();
541 }
542 
543 
545 {
546  updateShownItems( "" );
548 
549  return true;
550 }
551 
552 
554 {
555  wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
556  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
557  col->SetWidth( col->GetWidth() );
558 
559 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
560  col->SetResizeable( true );
561 #endif
562 
563  col = GetDataView()->GetColumn( 1 );
564  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
565  col->SetWidth( col->GetWidth() );
566 
567 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
568  col->SetResizeable( true );
569 #endif
570 }
571 
572 
573 void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
574 {
575  Freeze();
576  DeleteAllItems();
577 
578  HOTKEY_FILTER filter( aFilterStr );
579 
580  for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
581  {
582  // Create parent tree item
583  wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
584 
585  for( HOTKEY& hotkey: section.m_HotKeys )
586  {
587  if( filter.FilterMatches( hotkey ) )
588  {
589  wxTreeListItem item = AppendItem( parent, wxEmptyString );
590  SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
591  }
592  }
593 
594  Expand( parent );
595  }
596 
598  Thaw();
599 }
600 
601 
603 {
605  return true;
606 }
607 
608 
609 long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
610 {
611  long key = aEvent.GetKeyCode();
612  bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
613 
614  if( key == WXK_ESCAPE )
615  {
616  return 0;
617  }
618  else
619  {
620  if( key >= 'a' && key <= 'z' ) // convert to uppercase
621  key = key + ('A' - 'a');
622 
623  // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
624  // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
625  if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
626  key += 'A' - 1;
627 
628  /* Disallow shift for keys that have two keycodes on them (e.g. number and
629  * punctuation keys) leaving only the "letter keys" of A-Z, tab and space
630  * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
631  * and Ctrl-( and Ctrl-5 (FR layout).
632  * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
633  */
634  bool keyIsLetter = key >= 'A' && key <= 'Z';
635 
636  if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
637  key |= MD_SHIFT;
638 
639  if( aEvent.ControlDown() )
640  key |= MD_CTRL;
641 
642  if( aEvent.AltDown() )
643  key |= MD_ALT;
644 
645  return key;
646  }
647 }
HK_PROMPT_DIALOG(wxWindow *aParent, wxWindowID aId, const wxString &aTitle, const wxString &aName, const wxString &aCurrentKey)
static long MapKeypressToKeycode(const wxKeyEvent &aEvent)
Static method MapKeypressToKeycode Map a keypress event to the correct key code for use as a hotkey.
void changeHotkey(HOTKEY &aHotkey, long aKey)
Attempt to change the given hotkey to the given key code.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:292
std::unordered_map< long, wxString > m_reservedHotkeys
This file is part of the common library.
void editItem(wxTreeListItem aItem)
Method editItem Prompt the user for a new hotkey given a list item.
A class that contains a set of hotkeys, arranged into "sections" and provides some book-keeping funct...
Definition: hotkey_store.h:62
bool TransferDataToControl()
Method TransferDataToControl Load the hotkey data from the store into the control.
void onActivated(wxTreeListEvent &aEvent)
Method onActivated Handle activation of a row.
void onContextMenu(wxTreeListEvent &aEvent)
Method onContextMenu Handle right-click on a row.
void SaveAllHotkeys()
Persist all changes to hotkeys in the store to the underlying data structures.
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:82
wxString m_normalised_filter_str
ID_WHKL_MENU_IDS
Menu IDs for the hotkey context menu.
static wxKeyEvent PromptForKey(wxWindow *aParent, const wxString &aName, const wxString &aCurrentKey)
WIDGET_HOTKEY_CLIENT_DATA * getExpectedHkClientData(wxTreeListItem aItem)
Get the WIDGET_HOTKEY_CLIENT_DATA form an item and assert if it isn't found.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
HOTKEY_STORE & m_hk_store
void updateShownItems(const wxString &aFilterStr)
Method updateShownItems.
void updateFromClientData()
Method updateFromClientData Refresh the visible text on the widget from the rows' client data objects...
wxTreeListItem m_context_menu_item
Store the hotkey change data associated with each row.
int KeyCodeFromKeyName(const wxString &keyname)
Return the key code from its user-friendly key name (ie: "Ctrl+M").
void ResetAllHotkeysToDefault()
Reset every hotkey in the store to the default values.
#define _(s)
void ApplyFilterString(const wxString &aFilterStr)
Method ApplyFilterString Apply a filter string to the hotkey list, selecting which hotkeys to show.
WIDGET_HOTKEY_LIST(wxWindow *aParent, HOTKEY_STORE &aHotkeyStore, bool aReadOnly)
Constructor WIDGET_HOTKEY_LIST Create a WIDGET_HOTKEY_LIST.
bool CheckKeyConflicts(TOOL_ACTION *aAction, long aKey, HOTKEY **aConflict)
Check whether the given key conflicts with anything in this store.
wxDataViewItem GetNextItem(wxDataViewCtrl const &aView, wxDataViewItem const &aItem)
Get the next item in list order.
void onMenu(wxCommandEvent &aEvent)
Method onMenu Handle activation of a context menu item.
void updateColumnWidths()
Recalculates column widths after model has changed.
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
std::vector< TOOL_ACTION * > m_Actions
Definition: hotkey_store.h:36
bool FilterMatches(const HOTKEY &aHotkey) const
Check if the filter matches the given hotkey.
wxString GetLabel() const
Definition: tool_action.cpp:83
std::vector< HOTKEY_SECTION > & GetSections()
Get the list of sections managed by this store.
const char * name
Definition: DXF_plotter.cpp:56
void OnChar(wxKeyEvent &aEvent)
void OnCharHook(wxKeyEvent &aEvent) override
Represent a single user action.
Definition: tool_action.h:67
void OnKeyUp(wxKeyEvent &aEvent)
void ResetAllHotkeysToOriginal()
Resets every hotkey to the original values.
Manage logic for filtering hotkeys based on user input.
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
void resetItem(wxTreeListItem aItem, int aResetId)
Method resetItem Reset the item to either the default, the value when the dialog was opened,...
WIDGET_HOTKEY_CLIENT_DATA(HOTKEY &aChangedHotkey)
bool resolveKeyConflicts(TOOL_ACTION *aAction, long aKey)
Method resolveKeyConflicts Check if we can set a hotkey, and prompt the user if there is a conflict b...
int m_EditKeycode
Definition: hotkey_store.h:37
HOTKEY_FILTER(const wxString &aFilterStr)
WIDGET_HOTKEY_CLIENT_DATA * getHKClientData(wxTreeListItem aItem)
Method getHKClientData Return the WIDGET_HOTKEY_CLIENT_DATA for the given item, or NULL if the item i...
Dialog to prompt the user to enter a key.
void ResetAllHotkeys(bool aResetToDefault)
Set hotkeys in the control to default or original values.
static wxString GetSectionName(TOOL_ACTION *aAction)
bool TransferDataFromControl()
Method TransferDataFromControl Save the hotkey data from the control.