KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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
58class WIDGET_HOTKEY_CLIENT_DATA : public wxClientData
59{
61
62public:
63 WIDGET_HOTKEY_CLIENT_DATA( HOTKEY& aChangedHotkey ) :
64 m_changed_hotkey( aChangedHotkey )
65 {}
66
68};
69
70
75{
76public:
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
153protected:
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
210private:
211 wxKeyEvent m_event;
212};
213
214
219{
220public:
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
251private:
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 label.Replace( wxT( "..." ), wxEmptyString );
300 label.Replace( wxT( "…" ), wxEmptyString );
301
302 // mark unsaved changes
303 if( changed_hk.m_EditKeycode != changed_hk.m_Actions[ 0 ]->GetHotKey() )
304 label += wxS( " *" );
305
306 description.Replace( wxS( "\n" ), wxS( " " ) );
307 description.Replace( wxS( "\r" ), wxS( " " ) );
308
309 SetItemText( i, 0, label );
310 SetItemText( i, 1, key_text);
311 SetItemText( i, 2, description );
312 }
313 }
314}
315
316
317void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey )
318{
319 // See if this key code is handled in hotkeys names list
320 bool exists;
321 KeyNameFromKeyCode( aKey, &exists );
322
323 if( exists && aHotkey.m_EditKeycode != aKey )
324 {
325 if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) )
326 aHotkey.m_EditKeycode = aKey;
327 }
328}
329
330
331void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem )
332{
334
335 if( !hkdata )
336 return;
337
338 wxString name = GetItemText( aItem, 0 );
339 wxString current_key = GetItemText( aItem, 1 );
340
341 wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( this, name, current_key );
342 long key = MapKeypressToKeycode( key_event );
343
344 if( key )
345 {
346 auto it = m_reservedHotkeys.find( key );
347
348 if( it != m_reservedHotkeys.end() )
349 {
350 wxString msg = wxString::Format( _( "'%s' is a reserved hotkey in KiCad and cannot "
351 "be assigned." ),
352 it->second );
353
354 DisplayErrorMessage( this, msg );
355 return;
356 }
357
358 changeHotkey( hkdata->GetChangedHotkey(), key );
360 }
361}
362
363
364void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
365{
367
368 if( !hkdata )
369 return;
370
371 HOTKEY& changed_hk = hkdata->GetChangedHotkey();
372
373 if( aResetId == ID_RESET )
374 changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetHotKey() );
375 else if( aResetId == ID_CLEAR )
376 changeHotkey( changed_hk, 0 );
377 else if( aResetId == ID_DEFAULT )
378 changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetDefaultHotKey() );
379
381}
382
383
384void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
385{
386 editItem( aEvent.GetItem());
387}
388
389
390void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
391{
392 // Save the active event for use in OnMenu
393 m_context_menu_item = aEvent.GetItem();
394
395 wxMenu menu;
396
398
399 // Some actions only apply if the row is hotkey data
400 if( hkdata )
401 {
402 menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
403 menu.Append( ID_RESET, _( "Undo Changes" ) );
404 menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
405 menu.Append( ID_DEFAULT, _( "Restore Default" ) );
406 menu.Append( wxID_SEPARATOR );
407
408 PopupMenu( &menu );
409 }
410}
411
412
413void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
414{
415 switch( aEvent.GetId() )
416 {
417 case ID_EDIT_HOTKEY:
419 break;
420
421 case ID_RESET:
422 case ID_CLEAR:
423 case ID_DEFAULT:
424 resetItem( m_context_menu_item, aEvent.GetId());
425 break;
426
427 default:
428 wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
429 }
430}
431
432
434{
435 HOTKEY* conflictingHotKey = nullptr;
436
437 m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
438
439 if( !conflictingHotKey )
440 return true;
441
442 TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
443 wxString msg = wxString::Format( _( "'%s' is already assigned to '%s' in section '%s'. "
444 "Are you sure you want to change its assignment?" ),
445 KeyNameFromKeyCode( aKey ),
446 conflictingAction->GetLabel(),
447 HOTKEY_STORE::GetSectionName( conflictingAction ) );
448
449 wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
450
451 if( dlg.ShowModal() == wxID_YES )
452 {
453 // Reset the other hotkey
454 conflictingHotKey->m_EditKeycode = 0;
456 return true;
457 }
458
459 return false;
460}
461
462
463WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
464 bool aReadOnly ) :
465 wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
466 m_hk_store( aHotkeyStore ),
467 m_readOnly( aReadOnly )
468{
469 wxString command_header = _( "Command" );
470
471 if( !m_readOnly )
472 command_header << wxS( " " ) << _( "(double-click to edit)" );
473
474 AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
475 AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
476 AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
477
478
479#if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
480 // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
481 // They are also broken in wxGTK 3.1.4
482
483 wxDataViewCtrl* dv = GetDataView();
484
485 wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
486 int pad = 20;
487
488 dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 + pad );
489 dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
490 dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 + pad );
491
492 CallAfter( [&]()
493 {
494 GetDataView()->Update();
495 } );
496#endif
497
498 std::vector<wxString> reserved_keys =
499 {
500 wxS( "Ctrl+Tab" ),
501 wxS( "Ctrl+Shift+Tab" )
502 };
503
504 for( const wxString& key : reserved_keys )
505 {
506 long code = KeyCodeFromKeyName( key );
507
508 if( code )
509 m_reservedHotkeys[code] = key;
510 else
511 wxLogWarning( wxS( "Unknown reserved keycode %s\n" ), key );
512 }
513
514 GetDataView()->SetIndent( 10 );
515
516 if( !m_readOnly )
517 {
518 // The event only apply if the widget is in editable mode
519 Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
520 Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
521 Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
522 }
523}
524
525
526void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
527{
528 updateShownItems( aFilterStr );
529}
530
531
532void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
533{
534 Freeze();
535
536 // Reset all the hotkeys, not just the ones shown
537 // Should not need to check conflicts, as the state we're about
538 // to set to a should be consistent
539 if( aResetToDefault )
541 else
543
546
547 Thaw();
548}
549
550
552{
553 updateShownItems( "" );
555
556 return true;
557}
558
559
561{
562 wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
563 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
564 col->SetWidth( col->GetWidth() );
565
566#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
567 col->SetResizeable( true );
568#endif
569
570 col = GetDataView()->GetColumn( 1 );
571 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
572 col->SetWidth( col->GetWidth() );
573
574#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
575 col->SetResizeable( true );
576#endif
577
578 col = GetDataView()->GetColumn( 2 );
579 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
580 col->SetWidth( col->GetWidth() );
581
582#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
583 col->SetResizeable( true );
584#endif
585}
586
587
588void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
589{
590 Freeze();
591 DeleteAllItems();
592
593 HOTKEY_FILTER filter( aFilterStr );
594
595 for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
596 {
597 // Create parent tree item
598 wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
599
600 for( HOTKEY& hotkey: section.m_HotKeys )
601 {
602 if( filter.FilterMatches( hotkey ) )
603 {
604 wxTreeListItem item = AppendItem( parent, wxEmptyString );
605 SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
606 }
607 }
608
609 Expand( parent );
610 }
611
613 Thaw();
614}
615
616
618{
620 return true;
621}
622
623
624long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
625{
626 long key = aEvent.GetKeyCode();
627 bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
628
629 if( key == WXK_ESCAPE )
630 {
631 return 0;
632 }
633 else
634 {
635 if( key >= 'a' && key <= 'z' ) // convert to uppercase
636 key = key + ('A' - 'a');
637
638 // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
639 // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
640 if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
641 key += 'A' - 1;
642
643 /* Disallow shift for keys that have two keycodes on them (e.g. number and
644 * punctuation keys) leaving only the "letter keys" of A-Z, tab and space
645 * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
646 * and Ctrl-( and Ctrl-5 (FR layout).
647 * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
648 */
649 bool keyIsLetter = key >= 'A' && key <= 'Z';
650
651 if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
652 key |= MD_SHIFT;
653
654 if( aEvent.ControlDown() )
655 key |= MD_CTRL;
656
657 if( aEvent.AltDown() )
658 key |= MD_ALT;
659
660 return key;
661 }
662}
const char * name
Definition: DXF_plotter.cpp:56
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
Dialog to prompt the user to enter a key.
static wxKeyEvent PromptForKey(wxWindow *aParent, const wxString &aName, const wxString &aCurrentKey)
void OnCharHook(wxKeyEvent &aEvent) override
HK_PROMPT_DIALOG(wxWindow *aParent, wxWindowID aId, const wxString &aTitle, const wxString &aName, const wxString &aCurrentKey)
void OnKeyUp(wxKeyEvent &aEvent)
void OnChar(wxKeyEvent &aEvent)
Manage logic for filtering hotkeys based on user input.
wxString m_normalised_filter_str
bool FilterMatches(const HOTKEY &aHotkey) const
Check if the filter matches the given hotkey.
HOTKEY_FILTER(const wxString &aFilterStr)
A class that contains a set of hotkeys, arranged into "sections" and provides some book-keeping funct...
Definition: hotkey_store.h:63
bool CheckKeyConflicts(TOOL_ACTION *aAction, long aKey, HOTKEY **aConflict)
Check whether the given key conflicts with anything in this store.
void ResetAllHotkeysToOriginal()
Resets every hotkey to the original values.
void ResetAllHotkeysToDefault()
Reset every hotkey in the store to the default values.
std::vector< HOTKEY_SECTION > & GetSections()
Get the list of sections managed by this store.
void SaveAllHotkeys()
Persist all changes to hotkeys in the store to the underlying data structures.
static wxString GetSectionName(TOOL_ACTION *aAction)
Represent a single user action.
Definition: tool_action.h:68
wxString GetLabel() const
Definition: tool_action.cpp:83
Store the hotkey change data associated with each row.
WIDGET_HOTKEY_CLIENT_DATA(HOTKEY &aChangedHotkey)
WIDGET_HOTKEY_LIST(wxWindow *aParent, HOTKEY_STORE &aHotkeyStore, bool aReadOnly)
Constructor WIDGET_HOTKEY_LIST Create a WIDGET_HOTKEY_LIST.
void ResetAllHotkeys(bool aResetToDefault)
Set hotkeys in the control to default or original values.
void onActivated(wxTreeListEvent &aEvent)
Method onActivated Handle activation of a row.
void updateShownItems(const wxString &aFilterStr)
Method updateShownItems.
bool TransferDataToControl()
Method TransferDataToControl Load the hotkey data from the store into the control.
void changeHotkey(HOTKEY &aHotkey, long aKey)
Attempt to change the given hotkey to the given key code.
void onMenu(wxCommandEvent &aEvent)
Method onMenu Handle activation of a context menu item.
wxTreeListItem m_context_menu_item
bool TransferDataFromControl()
Method TransferDataFromControl Save the hotkey data from the control.
void updateColumnWidths()
Recalculates column widths after model has changed.
void ApplyFilterString(const wxString &aFilterStr)
Method ApplyFilterString Apply a filter string to the hotkey list, selecting which hotkeys to show.
void updateFromClientData()
Method updateFromClientData Refresh the visible text on the widget from the rows' client data objects...
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 * getExpectedHkClientData(wxTreeListItem aItem)
Get the WIDGET_HOTKEY_CLIENT_DATA form an item and assert if it isn't found.
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...
void onContextMenu(wxTreeListEvent &aEvent)
Method onContextMenu Handle right-click on a row.
static long MapKeypressToKeycode(const wxKeyEvent &aEvent)
Static method MapKeypressToKeycode Map a keypress event to the correct key code for use as a hotkey.
void editItem(wxTreeListItem aItem)
Method editItem Prompt the user for a new hotkey given a list item.
HOTKEY_STORE & m_hk_store
std::unordered_map< long, wxString > m_reservedHotkeys
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...
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
This file is part of the common library.
#define _(s)
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
int KeyCodeFromKeyName(const wxString &keyname)
Return the key code from its user-friendly key name (ie: "Ctrl+M").
int m_EditKeycode
Definition: hotkey_store.h:37
std::vector< TOOL_ACTION * > m_Actions
Definition: hotkey_store.h:36
@ MD_ALT
Definition: tool_event.h:140
@ MD_CTRL
Definition: tool_event.h:139
@ MD_SHIFT
Definition: tool_event.h:138
ID_WHKL_MENU_IDS
Menu IDs for the hotkey context menu.
@ ID_EDIT_HOTKEY
@ ID_DEFAULT
@ ID_CLEAR
@ ID_RESET