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