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 The 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/button.h>
33#include <wx/log.h>
34#include <wx/dcclient.h>
35#include <wx/menu.h>
36#include <wx/msgdlg.h>
37#include <wx/panel.h>
38#include <wx/sizer.h>
39#include <wx/statline.h>
40#include <wx/stattext.h>
41#include <wx/treelist.h>
42
47{
54};
55
56
63class WIDGET_HOTKEY_CLIENT_DATA : public wxClientData
64{
66
67public:
68 WIDGET_HOTKEY_CLIENT_DATA( HOTKEY& aChangedHotkey ) :
69 m_changed_hotkey( aChangedHotkey )
70 {}
71
73};
74
75
80{
81public:
82 HK_PROMPT_DIALOG( wxWindow* aParent, wxWindowID aId, const wxString& aTitle,
83 const wxString& aName, const wxString& aCurrentKey ) :
84 DIALOG_SHIM( aParent, aId, aTitle, wxDefaultPosition, wxDefaultSize )
85 {
86 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
87 SetSizer( mainSizer );
88
89 /* Dialog layout:
90 *
91 * inst_label........................
92 * ----------------------------------
93 *
94 * cmd_label_0 cmd_label_1 \
95 * | fgsizer
96 * key_label_0 key_label_1 /
97 */
98
99 wxStaticText* inst_label = new wxStaticText( this, wxID_ANY, wxEmptyString,
100 wxDefaultPosition, wxDefaultSize,
101 wxALIGN_CENTRE_HORIZONTAL );
102
103 inst_label->SetLabelText( _( "Press a new hotkey, or press Esc to cancel..." ) );
104 mainSizer->Add( inst_label, 0, wxALL, 10 );
105
106 mainSizer->Add( new wxStaticLine( this ), 0, wxALL | wxEXPAND, 2 );
107
108 wxPanel* panelDisplayCurrent = new wxPanel( this, wxID_ANY, wxDefaultPosition,
109 wxDefaultSize );
110 mainSizer->Add( panelDisplayCurrent, 0, wxALL | wxEXPAND, 5 );
111
112 wxFlexGridSizer* fgsizer = new wxFlexGridSizer( 2 );
113 panelDisplayCurrent->SetSizer( fgsizer );
114
115 wxStaticText* cmd_label_0 = new wxStaticText( panelDisplayCurrent, wxID_ANY,
116 _( "Command:" ) );
117 fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
118
119 wxStaticText* cmd_label_1 = new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
120 cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
121 cmd_label_1->SetLabel( aName );
122 fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
123
124 wxStaticText* key_label_0 = new wxStaticText( panelDisplayCurrent, wxID_ANY,
125 _( "Current key:" ) );
126 fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
127
128 wxStaticText* key_label_1 = new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
129 key_label_1->SetFont( key_label_1->GetFont().Bold() );
130 key_label_1->SetLabel( aCurrentKey );
131 fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
132
133 fgsizer->AddStretchSpacer();
134
135 wxButton* resetButton = new wxButton( this, wxID_ANY, _( "Clear assigned hotkey" ),
136 wxDefaultPosition, wxDefaultSize, 0 );
137
138 mainSizer->Add( resetButton, 0, wxALL | wxALIGN_CENTRE_HORIZONTAL, 5 );
139
140 Layout();
141 mainSizer->Fit( this );
142 Center();
143
144 SetMinClientSize( GetClientSize() );
145
146 // Binding both EVT_CHAR and EVT_CHAR_HOOK ensures that all key events, including
147 // specials like Tab and Return, are received, particularly on MSW.
148 panelDisplayCurrent->Bind( wxEVT_CHAR, &HK_PROMPT_DIALOG::OnChar, this );
149 panelDisplayCurrent->Bind( wxEVT_CHAR_HOOK, &HK_PROMPT_DIALOG::OnCharHook, this );
150 panelDisplayCurrent->Bind( wxEVT_KEY_UP, &HK_PROMPT_DIALOG::OnKeyUp, this );
151
152 resetButton->Bind( wxEVT_COMMAND_BUTTON_CLICKED, &HK_PROMPT_DIALOG::onResetButton, this );
153
154 SetInitialFocus( panelDisplayCurrent );
155 }
156
157 static std::optional<long> PromptForKey( wxWindow* aParent, const wxString& aName,
158 const wxString& aCurrentKey )
159 {
160 HK_PROMPT_DIALOG dialog( aParent, wxID_ANY, _( "Set Hotkey" ), aName, aCurrentKey );
161
162 if( dialog.ShowModal() == wxID_OK )
163 {
164 if( dialog.m_resetkey )
165 {
166 return std::make_optional( 0 );
167 }
168 else
169 {
171
172 if( key )
173 return std::make_optional( key );
174 else // The ESC key was used to close the dialog
175 return std::nullopt;
176 }
177 }
178 else
179 {
180 return std::nullopt;
181 }
182 }
183
184protected:
185 void OnCharHook( wxKeyEvent& aEvent ) override
186 {
187 // On certain platforms, EVT_CHAR_HOOK is the only handler that receives certain
188 // "special" keys. However, it doesn't always receive "normal" keys correctly. For
189 // example, with a US keyboard, it sees ? as shift+/.
190 //
191 // Untangling these incorrect keys would be too much trouble, so we bind both events,
192 // and simply skip the EVT_CHAR_HOOK if it receives a "normal" key.
193
194 const enum wxKeyCode skipped_keys[] =
195 {
196 WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL, WXK_NUMLOCK, WXK_SCROLL,
197 WXK_RAW_CONTROL
198 };
199
200 int key = aEvent.GetKeyCode();
201
202 for( wxKeyCode skipped_key : skipped_keys )
203 {
204 if( key == skipped_key )
205 return;
206 }
207
208 if( key <= 255 && isprint( key ) && !isspace( key ) )
209 {
210 // Let EVT_CHAR handle this one
211 aEvent.DoAllowNextEvent();
212
213#ifdef __WXMSW__
214 // On Windows, looks like a OnChar event is not generated when
215 // using the Alt key modifier. So ensure m_event is up to date
216 // to handle the right key code when releasing the key and therefore
217 // closing the dialog
218 m_event = aEvent;
219#endif
220 aEvent.Skip();
221 }
222 else
223 {
224 OnChar( aEvent );
225 }
226 }
227
228 void OnChar( wxKeyEvent& aEvent )
229 {
230 m_event = aEvent;
231 }
232
233 void OnKeyUp( wxKeyEvent& aEvent )
234 {
235 // If dialog opened using Enter key, prevent closing when releasing Enter.
236 if( m_event.GetEventType() != wxEVT_NULL )
237 {
239 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
240 }
241 }
242
243 void onResetButton( wxCommandEvent& aEvent )
244 {
245 m_resetkey = true;
246 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
247 }
248
249private:
250 bool m_resetkey = false;
251 wxKeyEvent m_event;
252};
253
254
259{
260public:
261 HOTKEY_FILTER( const wxString& aFilterStr )
262 {
263 m_normalised_filter_str = aFilterStr.Upper();
264 m_valid = m_normalised_filter_str.size() > 0;
265 }
266
272 bool FilterMatches( const HOTKEY& aHotkey ) const
273 {
274 if( !m_valid )
275 return true;
276
277 // Match in the (translated) filter string
278 const auto normedInfo = wxGetTranslation( aHotkey.m_Actions[0]->GetFriendlyName() ).Upper();
279
280 if( normedInfo.Contains( m_normalised_filter_str ) )
281 return true;
282
283 const wxString keyName = KeyNameFromKeyCode( aHotkey.m_EditKeycode );
284
285 if( keyName.Upper().Contains( m_normalised_filter_str ) )
286 return true;
287
288 return false;
289 }
290
291private:
294};
295
296
298{
299 if( aItem.IsOk() )
300 {
301 wxClientData* data = GetItemData( aItem );
302
303 if( data )
304 return static_cast<WIDGET_HOTKEY_CLIENT_DATA*>( data );
305 }
306
307 return nullptr;
308}
309
310
312{
313 for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
314 {
316
317 if( hkdata )
318 {
319 const HOTKEY& changed_hk = hkdata->GetChangedHotkey();
320 wxString label = changed_hk.m_Actions[ 0 ]->GetFriendlyName();
321 wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode );
322 wxString alt_text = KeyNameFromKeyCode( changed_hk.m_EditKeycodeAlt );
323 wxString description = changed_hk.m_Actions[ 0 ]->GetDescription();
324
325 if( label.IsEmpty() )
326 label = changed_hk.m_Actions[ 0 ]->GetName();
327
328 label.Replace( wxT( "..." ), wxEmptyString );
329 label.Replace( wxT( "…" ), wxEmptyString );
330
331 // mark unsaved changes
332 if( changed_hk.m_EditKeycode != changed_hk.m_Actions[ 0 ]->GetHotKey() )
333 label += wxS( " *" );
334
335 description.Replace( wxS( "\n" ), wxS( " " ) );
336 description.Replace( wxS( "\r" ), wxS( " " ) );
337
338 SetItemText( i, 0, label );
339 SetItemText( i, 1, key_text );
340 SetItemText( i, 2, alt_text );
341 SetItemText( i, 3, description );
342 }
343 }
344}
345
346
347void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey, bool alternate )
348{
349 // See if this key code is handled in hotkeys names list
350 bool exists;
351 KeyNameFromKeyCode( aKey, &exists );
352
353 if( exists && aHotkey.m_EditKeycode != aKey )
354 {
355 if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) )
356 {
357 if( alternate )
358 aHotkey.m_EditKeycodeAlt = aKey;
359 else
360 aHotkey.m_EditKeycode = aKey;
361 }
362 }
363}
364
365
366void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem, int aEditId )
367{
369
370 if( !hkdata )
371 return;
372
373 wxString name = GetItemText( aItem, 0 );
374 wxString current_key = aEditId == ID_EDIT_HOTKEY ? GetItemText( aItem, 1 )
375 : GetItemText( aItem, 2 );
376
377 std::optional<long> key = HK_PROMPT_DIALOG::PromptForKey( this, name, current_key );
378
379 // An empty optional means don't change the key
380 if( key.has_value() )
381 {
382 auto it = m_reservedHotkeys.find( key.value() );
383
384 if( it != m_reservedHotkeys.end() )
385 {
386 wxString msg = wxString::Format( _( "'%s' is a reserved hotkey in KiCad and cannot "
387 "be assigned." ),
388 it->second );
389
390 DisplayErrorMessage( this, msg );
391 return;
392 }
393
394 changeHotkey( hkdata->GetChangedHotkey(), key.value(), aEditId == ID_EDIT_ALT );
396 }
397}
398
399
400void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
401{
403
404 if( !hkdata )
405 return;
406
407 HOTKEY& changed_hk = hkdata->GetChangedHotkey();
408
409 if( aResetId == ID_RESET )
410 {
411 changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetHotKey(), false );
412 changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetHotKey(), true );
413 }
414 else if( aResetId == ID_CLEAR )
415 {
416 changeHotkey( changed_hk, 0, false );
417 }
418 else if( aResetId == ID_CLEAR_ALT )
419 {
420 changeHotkey( changed_hk, 0, true );
421 }
422 else if( aResetId == ID_DEFAULT )
423 {
424 changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetDefaultHotKey(), false );
425 changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetDefaultHotKeyAlt(), true );
426 }
427
429}
430
431
432void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
433{
434 editItem( aEvent.GetItem(), ID_EDIT_HOTKEY );
435}
436
437
438void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
439{
440 // Save the active event for use in OnMenu
441 m_context_menu_item = aEvent.GetItem();
442
443 wxMenu menu;
444
446
447 // Some actions only apply if the row is hotkey data
448 if( hkdata )
449 {
450 menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
451 menu.Append( ID_EDIT_ALT, _( "Edit Alternate..." ) );
452 menu.Append( ID_RESET, _( "Undo Changes" ) );
453 menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
454 menu.Append( ID_CLEAR_ALT, _( "Clear Assigned Alternate" ) );
455 menu.Append( ID_DEFAULT, _( "Restore Defaults" ) );
456 menu.Append( wxID_SEPARATOR );
457
458 PopupMenu( &menu );
459 }
460}
461
462
463void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
464{
465 switch( aEvent.GetId() )
466 {
467 case ID_EDIT_HOTKEY:
468 case ID_EDIT_ALT:
469 editItem( m_context_menu_item, aEvent.GetId() );
470 break;
471
472 case ID_RESET:
473 case ID_CLEAR:
474 case ID_CLEAR_ALT:
475 case ID_DEFAULT:
476 resetItem( m_context_menu_item, aEvent.GetId() );
477 break;
478
479 default:
480 wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
481 }
482}
483
484
486{
487 HOTKEY* conflictingHotKey = nullptr;
488
489 m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
490
491 if( !conflictingHotKey )
492 return true;
493
494 TOOL_ACTION* conflictingAction = conflictingHotKey->m_Actions[ 0 ];
495 wxString msg = wxString::Format( _( "'%s' is already assigned to '%s' in section '%s'. "
496 "Are you sure you want to change its assignment?" ),
497 KeyNameFromKeyCode( aKey ),
498 conflictingAction->GetFriendlyName(),
499 HOTKEY_STORE::GetSectionName( conflictingAction ) );
500
501 wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );
502
503 if( dlg.ShowModal() == wxID_YES )
504 {
505 // Reset the other hotkey
506 conflictingHotKey->m_EditKeycode = 0;
508 return true;
509 }
510
511 return false;
512}
513
514
515WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
516 bool aReadOnly ) :
517 wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
518 m_hk_store( aHotkeyStore ),
519 m_readOnly( aReadOnly )
520{
521 wxString command_header = _( "Command" );
522
523 if( !m_readOnly )
524 command_header << wxS( " " ) << _( "(double-click to edit)" );
525
526 AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
527 AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
528 AppendColumn( _( "Alternate" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
529 AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
530
531
532#if defined( __WXGTK__ )// && !wxCHECK_VERSION( 3, 1, 0 )
533 // Automatic column widths are broken in wxGTK 3.0.x; set min widths to ensure visibility
534 // They are also broken in wxGTK 3.1.4
535
536 wxDataViewCtrl* dv = GetDataView();
537
538 wxString longKey = wxT( "Ctrl+Alt+Shift+X" );
539 int pad = 20;
540
541 dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 + pad );
542 dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
543 dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
544 dv->GetColumn( 3 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 + pad );
545
546 CallAfter( [this]()
547 {
548 GetDataView()->Update();
549 } );
550#endif
551
552 std::vector<wxString> reserved_keys =
553 {
554 wxS( "Ctrl+Tab" ),
555 wxS( "Ctrl+Shift+Tab" )
556 };
557
558 for( const wxString& key : reserved_keys )
559 {
560 long code = KeyCodeFromKeyName( key );
561
562 if( code )
563 m_reservedHotkeys[code] = key;
564 else
565 wxLogWarning( wxS( "Unknown reserved keycode %s\n" ), key );
566 }
567
568 GetDataView()->SetIndent( 10 );
569
570 if( !m_readOnly )
571 {
572 // The event only apply if the widget is in editable mode
573 Bind( wxEVT_TREELIST_ITEM_ACTIVATED, &WIDGET_HOTKEY_LIST::onActivated, this );
574 Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::onContextMenu, this );
575 Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::onMenu, this );
576 }
577}
578
579
580void WIDGET_HOTKEY_LIST::ApplyFilterString( const wxString& aFilterStr )
581{
582 updateShownItems( aFilterStr );
583}
584
585
586void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
587{
588 Freeze();
589
590 // Reset all the hotkeys, not just the ones shown
591 // Should not need to check conflicts, as the state we're about
592 // to set to a should be consistent
593 if( aResetToDefault )
595 else
597
600
601 Thaw();
602}
603
604
606{
607 updateShownItems( "" );
609
610 return true;
611}
612
613
615{
616 wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
617 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
618 col->SetWidth( col->GetWidth() );
619
620 col = GetDataView()->GetColumn( 1 );
621 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
622 col->SetWidth( col->GetWidth() );
623
624 col = GetDataView()->GetColumn( 2 );
625 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
626 col->SetWidth( col->GetWidth() );
627
628 col = GetDataView()->GetColumn( 3 );
629 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
630 col->SetWidth( col->GetWidth() );
631}
632
633
634void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
635{
636 Freeze();
637 DeleteAllItems();
638
639 HOTKEY_FILTER filter( aFilterStr );
640
641 for( HOTKEY_SECTION& section: m_hk_store.GetSections() )
642 {
643 // Create parent tree item
644 wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
645
646 for( HOTKEY& hotkey: section.m_HotKeys )
647 {
648 if( filter.FilterMatches( hotkey ) )
649 {
650 wxTreeListItem item = AppendItem( parent, wxEmptyString );
651 SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
652 }
653 }
654
655 Expand( parent );
656 }
657
659 Thaw();
660}
661
662
664{
666 return true;
667}
668
669
670long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
671{
672 long key = aEvent.GetKeyCode();
673 bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
674
675 if( key == WXK_ESCAPE )
676 {
677 return 0;
678 }
679 else
680 {
681 if( key >= 'a' && key <= 'z' ) // convert to uppercase
682 key = key + ('A' - 'a');
683
684 // Remap Ctrl A (=1+GR_KB_CTRL) to Ctrl Z(=26+GR_KB_CTRL)
685 // to GR_KB_CTRL+'A' .. GR_KB_CTRL+'Z'
686 if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
687 key += 'A' - 1;
688
689 /* Disallow shift for keys that have two keycodes on them (e.g. number and
690 * punctuation keys) leaving only the "letter keys" of A-Z, tab and space
691 * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
692 * and Ctrl-( and Ctrl-5 (FR layout).
693 * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
694 */
695 bool keyIsLetter = key >= 'A' && key <= 'Z';
696
697 if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
698 key |= MD_SHIFT;
699
700 if( aEvent.ControlDown() )
701 key |= MD_CTRL;
702
703 if( aEvent.AltDown() )
704 key |= MD_ALT;
705
706 return key;
707 }
708}
const char * name
Definition: DXF_plotter.cpp:59
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:102
int ShowModal() override
Dialog to prompt the user to enter a key.
static std::optional< long > 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 onResetButton(wxCommandEvent &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:66
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:269
wxString GetFriendlyName() const
Return the translated user-friendly name of the action.
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)
Create a WIDGET_HOTKEY_LIST.
void ResetAllHotkeys(bool aResetToDefault)
Set hotkeys in the control to default or original values.
void onActivated(wxTreeListEvent &aEvent)
Handle activation of a row.
void updateShownItems(const wxString &aFilterStr)
Update the items shown in the widget based on a given filter string.
void changeHotkey(HOTKEY &aHotkey, long aKey, bool alternate)
Attempt to change the given hotkey to the given key code.
void editItem(wxTreeListItem aItem, int aEditId)
Prompt the user for a new hotkey given a list item.
bool TransferDataToControl()
Load the hotkey data from the store into the control.
void onMenu(wxCommandEvent &aEvent)
Handle activation of a context menu item.
wxTreeListItem m_context_menu_item
bool TransferDataFromControl()
Save the hotkey data from the control.
void updateColumnWidths()
Recalculate column widths after model has changed.
void ApplyFilterString(const wxString &aFilterStr)
Apply a filter string to the hotkey list, selecting which hotkeys to show.
void updateFromClientData()
Refresh the visible text on the widget from the rows' client data objects.
void resetItem(wxTreeListItem aItem, int aResetId)
Reset the item to either the default, the value when the dialog was opened, or none.
WIDGET_HOTKEY_CLIENT_DATA * getHKClientData(wxTreeListItem aItem)
Return the WIDGET_HOTKEY_CLIENT_DATA for the given item, or NULL if the item is invalid.
void onContextMenu(wxTreeListEvent &aEvent)
Handle right-click on a row.
static long MapKeypressToKeycode(const wxKeyEvent &aEvent)
Map a keypress event to the correct key code for use as a hotkey.
HOTKEY_STORE & m_hk_store
std::unordered_map< long, wxString > m_reservedHotkeys
bool resolveKeyConflicts(TOOL_ACTION *aAction, long aKey)
Check if we can set a hotkey, and prompt the user if there is a conflict between keys.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
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_EditKeycodeAlt
Definition: hotkey_store.h:38
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:145
@ MD_CTRL
Definition: tool_event.h:144
@ MD_SHIFT
Definition: tool_event.h:143
ID_WHKL_MENU_IDS
Menu IDs for the hotkey context menu.
@ ID_EDIT_ALT
@ ID_CLEAR_ALT
@ ID_EDIT_HOTKEY
@ ID_DEFAULT
@ ID_CLEAR
@ ID_RESET