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-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  {
203  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
204  }
205 
206 private:
207  wxKeyEvent m_event;
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( this, name, current_key );
332  long key = MapKeypressToKeycode( key_event );
333 
334  if( key )
335  {
336  auto it = m_reservedHotkeys.find( key );
337 
338  if( it != m_reservedHotkeys.end() )
339  {
340  wxString msg = wxString::Format(
341  _( "'%s' is a reserved hotkey in KiCad and cannot be assigned." ),
342  it->second );
343 
344  DisplayErrorMessage( this, msg );
345  return;
346  }
347 
348  changeHotkey( hkdata->GetChangedHotkey(), key );
350  }
351 }
352 
353 
354 void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
355 {
357 
358  if( !hkdata )
359  return;
360 
361  HOTKEY& changed_hk = hkdata->GetChangedHotkey();
362 
363  if( aResetId == ID_RESET )
364  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetHotKey() );
365  else if( aResetId == ID_CLEAR )
366  changeHotkey( changed_hk, 0 );
367  else if( aResetId == ID_DEFAULT )
368  changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetDefaultHotKey() );
369 
371 }
372 
373 
374 void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
375 {
376  editItem( aEvent.GetItem());
377 }
378 
379 
380 void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
381 {
382  // Save the active event for use in OnMenu
383  m_context_menu_item = aEvent.GetItem();
384 
385  wxMenu menu;
386 
388 
389  // Some actions only apply if the row is hotkey data
390  if( hkdata )
391  {
392  menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
393  menu.Append( ID_RESET, _( "Undo Changes" ) );
394  menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
395  menu.Append( ID_DEFAULT, _( "Restore Default" ) );
396  menu.Append( wxID_SEPARATOR );
397 
398  PopupMenu( &menu );
399  }
400 }
401 
402 
403 void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
404 {
405  switch( aEvent.GetId() )
406  {
408  break;
409 
410  case ID_RESET:
411  case ID_CLEAR:
412  case ID_DEFAULT:resetItem( m_context_menu_item, aEvent.GetId());
413  break;
414 
415  default:
416  wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
417  }
418 }
419 
420 
422 {
423  HOTKEY* conflictingHotKey = nullptr;
424 
425  m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
426 
427  if( !conflictingHotKey )
428  return true;
429 
430  TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
431  wxString msg = wxString::Format( _( "'%s' is already assigned to '%s' in section '%s'. "
432  "Are you sure you want to change its assignment?" ),
433  KeyNameFromKeyCode( aKey ),
434  conflictingAction->GetLabel(),
435  HOTKEY_STORE::GetSectionName( conflictingAction ) );
436 
437  wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
438 
439  if( dlg.ShowModal() == wxID_YES )
440  {
441  // Reset the other hotkey
442  conflictingHotKey->m_EditKeycode = 0;
444  return true;
445  }
446 
447  return false;
448 }
449 
450 
451 WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
452  bool aReadOnly ) :
453  wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
454  m_hk_store( aHotkeyStore ),
455  m_readOnly( aReadOnly )
456 {
457  wxString command_header = _( "Command" );
458 
459  if( !m_readOnly )
460  command_header << " " << _( "(double-click to edit)" );
461 
462  AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
463  AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
464  AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
465 
466 
467 #if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
468  // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
469  // They are also broken in wxGTK 3.1.4
470 
471  wxDataViewCtrl* dv = GetDataView();
472 
473  wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
474  int pad = 20;
475 
476  dv->GetColumn( 0 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( command_header ).x + pad );
477  dv->GetColumn( 1 )->SetMinWidth( dv->GetMainWindow()->GetTextExtent( longKey ).x + pad );
478 #endif
479 
480  std::vector<wxString> reserved_keys =
481  {
482  "Ctrl+Tab",
483  "Ctrl+Shift+Tab"
484  };
485 
486  for( auto& key : reserved_keys )
487  {
488  long code = KeyCodeFromKeyName( key );
489 
490  if( code )
491  m_reservedHotkeys[code] = key;
492  else
493  {
494  wxLogWarning( "Unknown reserved keycode %s\n", key );
495  }
496  }
497 
498  GetDataView()->SetIndent( 10 );
499 
500  if( !m_readOnly )
501  {
502  // The event only apply if the widget is in editable mode
503  Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
504  Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
505  Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
506  }
507 }
508 
509 
510 void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
511 {
512  updateShownItems( aFilterStr );
513 }
514 
515 
516 void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
517 {
518  Freeze();
519 
520  // Reset all the hotkeys, not just the ones shown
521  // Should not need to check conflicts, as the state we're about
522  // to set to a should be consistent
523  if( aResetToDefault )
525  else
527 
530 
531  Thaw();
532 }
533 
534 
536 {
537  updateShownItems( "" );
539 
540  return true;
541 }
542 
543 
545 {
546  wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
547  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
548  col->SetWidth( col->GetWidth() );
549 
550 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
551  col->SetResizeable( true );
552 #endif
553 
554  col = GetDataView()->GetColumn( 1 );
555  col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
556  col->SetWidth( col->GetWidth() );
557 
558 #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
559  col->SetResizeable( true );
560 #endif
561 }
562 
563 
564 void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
565 {
566  Freeze();
567  DeleteAllItems();
568 
569  HOTKEY_FILTER filter( aFilterStr );
570 
571  for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
572  {
573  // Create parent tree item
574  wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
575 
576  for( HOTKEY& hotkey: section.m_HotKeys )
577  {
578  if( filter.FilterMatches( hotkey ) )
579  {
580  wxTreeListItem item = AppendItem( parent, wxEmptyString );
581  SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
582  }
583  }
584 
585  Expand( parent );
586  }
587 
589  Thaw();
590 }
591 
592 
594 {
596  return true;
597 }
598 
599 
600 long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
601 {
602  long key = aEvent.GetKeyCode();
603  bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
604 
605  if( key == WXK_ESCAPE )
606  {
607  return 0;
608  }
609  else
610  {
611  if( key >= 'a' && key <= 'z' ) // convert to uppercase
612  key = key + ('A' - 'a');
613 
614  // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
615  // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
616  if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
617  key += 'A' - 1;
618 
619  /* Disallow shift for keys that have two keycodes on them (e.g. number and
620  * punctuation keys) leaving only the "letter keys" of A-Z, tab and space
621  * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
622  * and Ctrl-( and Ctrl-5 (FR layout).
623  * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
624  */
625  bool keyIsLetter = key >= 'A' && key <= 'Z';
626 
627  if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
628  key |= MD_SHIFT;
629 
630  if( aEvent.ControlDown() )
631  key |= MD_CTRL;
632 
633  if( aEvent.AltDown() )
634  key |= MD_ALT;
635 
636  return key;
637  }
638 }
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:284
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.