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,
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 )
595 m_hk_store.ResetAllHotkeysToDefault();
596 else
597 m_hk_store.ResetAllHotkeysToOriginal();
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{
664 m_hk_store.SaveAllHotkeys();
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 );
673printf("key %lX mod %X\n", key, aEvent.GetModifiers());
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 int mods = aEvent.GetModifiers();
697
698 if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
699 key |= MD_SHIFT;
700
701 // the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
702 // So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
703 #if CAN_USE_ALTGR_KEY
704 if( wxmods & wxMOD_ALTGR )
705 mods |= MD_ALTGR;
706 else
707 #endif
708 {
709 if( mods & wxMOD_CONTROL )
710 key |= MD_CTRL;
711
712 if( mods & wxMOD_ALT )
713 key |= MD_ALT;
714 }
715
716#ifdef wxMOD_META
717 if( mods & wxMOD_META )
718 key |= MD_META;
719#endif
720
721#ifdef wxMOD_WIN
722 if( mods & wxMOD_WIN )
723 key |= MD_SUPER;
724#endif
725
726 return key;
727 }
728}
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)
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
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