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 <pavlina.chris@gmail.com>
5  * Copyright (C) 2016-2020 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>
27 #include <wx/statline.h>
28 #include <wx/treelist.h>
29 #include <wx/msgdlg.h>
30 #include <wx/menu.h>
31 #include <tool/tool_event.h>
32 #include <dialog_shim.h>
33 #include <wx/dcclient.h>
34 #include <wx/stattext.h>
35 
40 {
45 };
46 
47 
54 class WIDGET_HOTKEY_CLIENT_DATA : public wxClientData
55 {
57 
58 public:
59  WIDGET_HOTKEY_CLIENT_DATA( HOTKEY& aChangedHotkey ) :
60  m_changed_hotkey( aChangedHotkey )
61  {}
62 
64 };
65 
66 
71 {
72  wxKeyEvent m_event;
73 
74 public:
75  HK_PROMPT_DIALOG( wxWindow* aParent, wxWindowID aId, const wxString& aTitle,
76  const wxString& aName, const wxString& aCurrentKey ) :
77  DIALOG_SHIM( aParent, aId, aTitle, wxDefaultPosition, wxDefaultSize )
78  {
79  wxPanel* panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize );
80  wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
81 
82  /* Dialog layout:
83  *
84  * inst_label........................
85  * ----------------------------------
86  *
87  * cmd_label_0 cmd_label_1 \
88  * | fgsizer
89  * key_label_0 key_label_1 /
90  */
91 
92  wxStaticText* inst_label = new wxStaticText( panel, wxID_ANY, wxEmptyString,
93  wxDefaultPosition, wxDefaultSize,
94  wxALIGN_CENTRE_HORIZONTAL );
95 
96  inst_label->SetLabelText( _( "Press a new hotkey, or press Esc to cancel..." ) );
97  sizer->Add( inst_label, 0, wxALL, 5 );
98 
99  sizer->Add( new wxStaticLine( panel ), 0, wxALL | wxEXPAND, 2 );
100 
101  wxFlexGridSizer* fgsizer = new wxFlexGridSizer( 2 );
102 
103  wxStaticText* cmd_label_0 = new wxStaticText( panel, wxID_ANY, _( "Command:" ) );
104  fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
105 
106  wxStaticText* cmd_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
107  cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
108  cmd_label_1->SetLabel( aName );
109  fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
110 
111  wxStaticText* key_label_0 = new wxStaticText( panel, wxID_ANY, _( "Current key:" ) );
112  fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
113 
114  wxStaticText* key_label_1 = new wxStaticText( panel, wxID_ANY, wxEmptyString );
115  key_label_1->SetFont( key_label_1->GetFont().Bold() );
116  key_label_1->SetLabel( aCurrentKey );
117  fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
118 
119  sizer->Add( fgsizer, 1, wxEXPAND );
120 
121  // Wrap the sizer in a second to give a larger border around the whole dialog
122  wxBoxSizer* outer_sizer = new wxBoxSizer( wxVERTICAL );
123  outer_sizer->Add( sizer, 0, wxALL | wxEXPAND, 10 );
124  panel->SetSizer( outer_sizer );
125 
126  Layout();
127  outer_sizer->Fit( this );
128  Center();
129 
130  SetMinClientSize( GetClientSize() );
131 
132  // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events, including
133  // specials like Tab and Return, are received, particularly on MSW.
134  panel->Bind( wxEVT_CHAR, &HK_PROMPT_DIALOG::OnChar, this );
135  panel->Bind( wxEVT_CHAR_HOOK, &HK_PROMPT_DIALOG::OnCharHook, this );
136  SetInitialFocus( panel );
137  }
138 
142  void EndFlexible( int aRtnCode )
143  {
144  if( IsQuasiModal() )
145  EndQuasiModal( aRtnCode );
146  else
147  EndModal( aRtnCode );
148  }
149 
150  static wxKeyEvent PromptForKey( wxWindow* aParent, const wxString& aName,
151  const wxString& aCurrentKey )
152  {
153  HK_PROMPT_DIALOG dialog( aParent, wxID_ANY, _( "Set Hotkey" ), aName, aCurrentKey );
154 
155  if( dialog.ShowModal() == wxID_OK )
156  return dialog.m_event;
157  else
158  return wxKeyEvent();
159  }
160 
161 protected:
162  void OnCharHook( wxKeyEvent& aEvent ) override
163  {
164  // On certain platforms, EVT_CHAR_HOOK is the only handler that receives certain
165  // "special" keys. However, it doesn't always receive "normal" keys correctly. For
166  // example, with a US keyboard, it sees ? as shift+/.
167  //
168  // Untangling these incorrect keys would be too much trouble, so we bind both events,
169  // and simply skip the EVT_CHAR_HOOK if it receives a "normal" key.
170 
171  const enum wxKeyCode skipped_keys[] =
172  {
173  WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL, WXK_NUMLOCK, WXK_SCROLL,
174  WXK_RAW_CONTROL
175  };
176 
177  int key = aEvent.GetKeyCode();
178 
179  for( wxKeyCode skipped_key : skipped_keys )
180  {
181  if( key == skipped_key )
182  return;
183  }
184 
185  if( key <= 255 && isprint( key ) && !isspace( key ) )
186  {
187  // Let EVT_CHAR handle this one
188  aEvent.DoAllowNextEvent();
189 
190  // On Windows, wxEvent::Skip must NOT be called.
191  // On Linux and OSX, wxEvent::Skip MUST be called.
192  // No, I don't know why.
193 #ifndef __WXMSW__
194  aEvent.Skip();
195 #endif
196  }
197  else
198  {
199  OnChar( aEvent );
200  }
201  }
202 
203  void OnChar( wxKeyEvent& aEvent )
204  {
205  m_event = aEvent;
206  EndFlexible( wxID_OK );
207  }
208 };
209 
210 
215 {
216 public:
217  HOTKEY_FILTER( const wxString& aFilterStr )
218  {
219  m_normalised_filter_str = aFilterStr.Upper();
220  m_valid = m_normalised_filter_str.size() > 0;
221  }
222 
228  bool FilterMatches( const HOTKEY& aHotkey ) const
229  {
230  if( !m_valid )
231  return true;
232 
233  // Match in the (translated) filter string
234  const auto normedInfo = wxGetTranslation( aHotkey.m_Actions[ 0 ]->GetLabel() ).Upper();
235 
236  if( normedInfo.Contains( m_normalised_filter_str ) )
237  return true;
238 
239  const wxString keyName = KeyNameFromKeyCode( aHotkey.m_EditKeycode );
240 
241  if( keyName.Upper().Contains( m_normalised_filter_str ) )
242  return true;
243 
244  return false;
245  }
246 
247 private:
248  bool m_valid;
250 };
251 
252 
254 {
255  if( aItem.IsOk() )
256  {
257  wxClientData* data = GetItemData( aItem );
258 
259  if( data )
260  return static_cast<WIDGET_HOTKEY_CLIENT_DATA*>( data );
261  }
262 
263  return nullptr;
264 }
265 
266 
268 {
269  const auto hkdata = getHKClientData( aItem );
270 
271  // This probably means a hotkey-only action is being attempted on
272  // a row that is not a hotkey (like a section heading)
273  wxASSERT_MSG( hkdata != nullptr, "No hotkey data found for list item" );
274 
275  return hkdata;
276 }
277 
278 
280 {
281  for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
282  {
284 
285  if( hkdata )
286  {
287  const HOTKEY& changed_hk = hkdata->GetChangedHotkey();
288  wxString label = changed_hk.m_Actions[ 0 ]->GetLabel();
289  wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode );
290  wxString description = changed_hk.m_Actions[ 0 ]->GetDescription( false );
291 
292  if( label.IsEmpty() )
293  label = changed_hk.m_Actions[ 0 ]->GetName();
294 
295  // mark unsaved changes
296  if( changed_hk.m_EditKeycode != changed_hk.m_Actions[ 0 ]->GetHotKey() )
297  label += " *";
298 
299  SetItemText( i, 0, label );
300  SetItemText( i, 1, key_text);
301  SetItemText( i, 2, description );
302  }
303  }
304 }
305 
306 
307 void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey )
308 {
309  // See if this key code is handled in hotkeys names list
310  bool exists;
311  KeyNameFromKeyCode( aKey, &exists );
312 
313  if( exists && aHotkey.m_EditKeycode != aKey )
314  {
315  if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) )
316  aHotkey.m_EditKeycode = aKey;
317  }
318 }
319 
320 
321 void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem )
322 {
324 
325  if( !hkdata )
326  return;
327 
328  wxString name = GetItemText( aItem, 0 );
329  wxString current_key = GetItemText( aItem, 1 );
330 
331  wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( GetParent(), name, current_key );
332  long key = MapKeypressToKeycode( key_event );
333 
334  if( key )
335  {
336  changeHotkey( hkdata->GetChangedHotkey(), key );
338  }
339 }
340 
341 
342 void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
343 {
345 
346  if( !hkdata )
347  return;
348 
349  HOTKEY& changed_hk = hkdata->GetChangedHotkey();
350 
351  if( aResetId == ID_RESET )
352  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetHotKey() );
353  else if( aResetId == ID_CLEAR )
354  changeHotkey( changed_hk, 0 );
355  else if( aResetId == ID_DEFAULT )
356  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetDefaultHotKey() );
357 
359 }
360 
361 
362 void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
363 {
364  editItem( aEvent.GetItem());
365 }
366 
367 
368 void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
369 {
370  // Save the active event for use in OnMenu
371  m_context_menu_item = aEvent.GetItem();
372 
373  wxMenu menu;
374 
376 
377  // Some actions only apply if the row is hotkey data
378  if( hkdata )
379  {
380  menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
381  menu.Append( ID_RESET, _( "Undo Changes" ) );
382  menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
383  menu.Append( ID_DEFAULT, _( "Restore Default" ) );
384  menu.Append( wxID_SEPARATOR );
385 
386  PopupMenu( &menu );
387  }
388 }
389 
390 
391 void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
392 {
393  switch( aEvent.GetId() )
394  {
396  break;
397 
398  case ID_RESET:
399  case ID_CLEAR:
400  case ID_DEFAULT:resetItem( m_context_menu_item, aEvent.GetId());
401  break;
402 
403  default:
404  wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
405  }
406 }
407 
408 
410 {
411  HOTKEY* conflictingHotKey = nullptr;
412 
413  m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
414 
415  if( !conflictingHotKey )
416  return true;
417 
418  TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
419  wxString msg = wxString::Format( _( "\"%s\" is already assigned to \"%s\" in section \"%s\". "
420  "Are you sure you want to change its assignment?" ),
421  KeyNameFromKeyCode( aKey ),
422  conflictingAction->GetLabel(),
423  HOTKEY_STORE::GetSectionName( conflictingAction ) );
424 
425  wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
426 
427  if( dlg.ShowModal() == wxID_YES )
428  {
429  // Reset the other hotkey
430  conflictingHotKey->m_EditKeycode = 0;
432  return true;
433  }
434 
435  return false;
436 }
437 
438 
439 WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
440  bool aReadOnly ) :
441  wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
442  m_hk_store( aHotkeyStore ),
443  m_readOnly( aReadOnly )
444 {
445  wxString command_header = _( "Command" );
446 
447  if( !m_readOnly )
448  command_header << " " << _( "(double-click to edit)" );
449 
450  AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
451  AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
452  AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
453 
454 
455 #if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
456  // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
457  // They are also broken in wxGTK 3.1.4
458 
459  wxDataViewCtrl* dv = GetDataView();
460 
461  wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
462  int pad = 20;
463 
464  dv->GetColumn( 0 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( command_header ).x + pad );
465  dv->GetColumn( 1 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( longKey ).x + pad );
466 #endif
467 
468  GetDataView()->SetIndent( 10 );
469 
470  if( !m_readOnly )
471  {
472  // The event only apply if the widget is in editable mode
473  Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
474  Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
475  Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
476  }
477 }
478 
479 
480 void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
481 {
482  updateShownItems( aFilterStr );
483 }
484 
485 
486 void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
487 {
488  Freeze();
489 
490  // Reset all the hotkeys, not just the ones shown
491  // Should not need to check conflicts, as the state we're about
492  // to set to a should be consistent
493  if( aResetToDefault )
495  else
497 
500 
501  Thaw();
502 }
503 
504 
506 {
507  updateShownItems( "" );
509 
510  return true;
511 }
512 
513 
515 {
516  wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
517  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
518  col->SetWidth( col->GetWidth() );
519 
520 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
521  col->SetResizeable( true );
522 #endif
523 
524  col = GetDataView()->GetColumn( 1 );
525  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
526  col->SetWidth( col->GetWidth() );
527 
528 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
529  col->SetResizeable( true );
530 #endif
531 }
532 
533 
534 void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
535 {
536  Freeze();
537  DeleteAllItems();
538 
539  HOTKEY_FILTER filter( aFilterStr );
540 
541  for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
542  {
543  // Create parent tree item
544  wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
545 
546  for( HOTKEY& hotkey: section.m_HotKeys )
547  {
548  if( filter.FilterMatches( hotkey ) )
549  {
550  wxTreeListItem item = AppendItem( parent, wxEmptyString );
551  SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
552  }
553  }
554 
555  Expand( parent );
556  }
557 
559  Thaw();
560 }
561 
562 
564 {
566  return true;
567 }
568 
569 
570 long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
571 {
572  long key = aEvent.GetKeyCode();
573 
574  if( key == WXK_ESCAPE )
575  {
576  return 0;
577  }
578  else
579  {
580  if( key >= 'a' && key <= 'z' ) // convert to uppercase
581  key = key + ('A' - 'a');
582 
583  // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
584  // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
585  if( aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
586  key += 'A' - 1;
587 
588  /* Disallow shift for keys that have two keycodes on them (e.g. number and
589  * punctuation keys) leaving only the "letter keys" of A-Z.
590  * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
591  * and Ctrl-( and Ctrl-5 (FR layout).
592  * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
593  */
594  bool keyIsLetter = key >= 'A' && key <= 'Z';
595 
596  if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 ) )
597  key |= MD_SHIFT;
598 
599  if( aEvent.ControlDown() )
600  key |= MD_CTRL;
601 
602  if( aEvent.AltDown() )
603  key |= MD_ALT;
604 
605  return key;
606  }
607 }
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 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.
bool IsQuasiModal() const
Definition: dialog_shim.h:106
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.
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
void EndQuasiModal(int retCode)
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.
void EndFlexible(int aRtnCode)
End the dialog whether modal or quasimodal.
const char * name
Definition: DXF_plotter.cpp:59
void OnChar(wxKeyEvent &aEvent)
void OnCharHook(wxKeyEvent &aEvent) override
Represent a single user action.
Definition: tool_action.h:67
void ResetAllHotkeysToOriginal()
Resets every hotkey to the original values.
Class to 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.