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
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 += " *";
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(
351 _( "'%s' is a reserved hotkey in KiCad and cannot 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 {
418 break;
419
420 case ID_RESET:
421 case ID_CLEAR:
422 case ID_DEFAULT:resetItem( m_context_menu_item, aEvent.GetId());
423 break;
424
425 default:
426 wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
427 }
428}
429
430
432{
433 HOTKEY* conflictingHotKey = nullptr;
434
435 m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
436
437 if( !conflictingHotKey )
438 return true;
439
440 TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
441 wxString msg = wxString::Format( _( "'%s' is already assigned to '%s' in section '%s'. "
442 "Are you sure you want to change its assignment?" ),
443 KeyNameFromKeyCode( aKey ),
444 conflictingAction->GetLabel(),
445 HOTKEY_STORE::GetSectionName( conflictingAction ) );
446
447 wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
448
449 if( dlg.ShowModal() == wxID_YES )
450 {
451 // Reset the other hotkey
452 conflictingHotKey->m_EditKeycode = 0;
454 return true;
455 }
456
457 return false;
458}
459
460
461WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
462 bool aReadOnly ) :
463 wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
464 m_hk_store( aHotkeyStore ),
465 m_readOnly( aReadOnly )
466{
467 wxString command_header = _( "Command" );
468
469 if( !m_readOnly )
470 command_header << " " << _( "(double-click to edit)" );
471
472 AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
473 AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
474 AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
475
476
477#if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
478 // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
479 // They are also broken in wxGTK 3.1.4
480
481 wxDataViewCtrl* dv = GetDataView();
482
483 wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
484 int pad = 20;
485
486 dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 + pad );
487 dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
488 dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 + pad );
489
490 CallAfter( [&]()
491 {
492 GetDataView()->Update();
493 } );
494#endif
495
496 std::vector<wxString> reserved_keys =
497 {
498 "Ctrl+Tab",
499 "Ctrl+Shift+Tab"
500 };
501
502 for( const wxString& key : reserved_keys )
503 {
504 long code = KeyCodeFromKeyName( key );
505
506 if( code )
507 m_reservedHotkeys[code] = key;
508 else
509 wxLogWarning( "Unknown reserved keycode %s\n", key );
510 }
511
512 GetDataView()->SetIndent( 10 );
513
514 if( !m_readOnly )
515 {
516 // The event only apply if the widget is in editable mode
517 Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
518 Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
519 Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
520 }
521}
522
523
524void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
525{
526 updateShownItems( aFilterStr );
527}
528
529
530void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
531{
532 Freeze();
533
534 // Reset all the hotkeys, not just the ones shown
535 // Should not need to check conflicts, as the state we're about
536 // to set to a should be consistent
537 if( aResetToDefault )
539 else
541
544
545 Thaw();
546}
547
548
550{
551 updateShownItems( "" );
553
554 return true;
555}
556
557
559{
560 wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
561 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
562 col->SetWidth( col->GetWidth() );
563
564#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
565 col->SetResizeable( true );
566#endif
567
568 col = GetDataView()->GetColumn( 1 );
569 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
570 col->SetWidth( col->GetWidth() );
571
572#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
573 col->SetResizeable( true );
574#endif
575
576 col = GetDataView()->GetColumn( 2 );
577 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
578 col->SetWidth( col->GetWidth() );
579
580#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
581 col->SetResizeable( true );
582#endif
583}
584
585
586void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
587{
588 Freeze();
589 DeleteAllItems();
590
591 HOTKEY_FILTER filter( aFilterStr );
592
593 for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
594 {
595 // Create parent tree item
596 wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
597
598 for( HOTKEY& hotkey: section.m_HotKeys )
599 {
600 if( filter.FilterMatches( hotkey ) )
601 {
602 wxTreeListItem item = AppendItem( parent, wxEmptyString );
603 SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
604 }
605 }
606
607 Expand( parent );
608 }
609
611 Thaw();
612}
613
614
616{
618 return true;
619}
620
621
622long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
623{
624 long key = aEvent.GetKeyCode();
625 bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
626
627 if( key == WXK_ESCAPE )
628 {
629 return 0;
630 }
631 else
632 {
633 if( key >= 'a' && key <= 'z' ) // convert to uppercase
634 key = key + ('A' - 'a');
635
636 // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
637 // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
638 if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
639 key += 'A' - 1;
640
641 /* Disallow shift for keys that have two keycodes on them (e.g. number and
642 * punctuation keys) leaving only the "letter keys" of A-Z, tab and space
643 * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
644 * and Ctrl-( and Ctrl-5 (FR layout).
645 * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
646 */
647 bool keyIsLetter = key >= 'A' && key <= 'Z';
648
649 if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
650 key |= MD_SHIFT;
651
652 if( aEvent.ControlDown() )
653 key |= MD_CTRL;
654
655 if( aEvent.AltDown() )
656 key |= MD_ALT;
657
658 return key;
659 }
660}
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:299
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").
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
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
wxDataViewItem GetNextItem(wxDataViewCtrl const &aView, wxDataViewItem const &aItem)
Get the next item in list order.