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