30#include <wx/dcclient.h>
35#include <wx/statline.h>
36#include <wx/stattext.h>
37#include <wx/treelist.h>
38#include <wx/wupdlock.h>
80 const wxString& aName,
const wxString& aCurrentKey ) :
81 DIALOG_SHIM( aParent, aId, aTitle, wxDefaultPosition, wxDefaultSize )
83 wxBoxSizer* mainSizer =
new wxBoxSizer( wxVERTICAL );
84 SetSizer( mainSizer );
96 wxStaticText* inst_label =
new wxStaticText(
this, wxID_ANY, wxEmptyString,
97 wxDefaultPosition, wxDefaultSize,
98 wxALIGN_CENTRE_HORIZONTAL );
100 inst_label->SetLabelText(
_(
"Press a new hotkey, or press Esc to cancel..." ) );
101 mainSizer->Add( inst_label, 0, wxALL, 10 );
103 mainSizer->Add(
new wxStaticLine(
this ), 0, wxALL | wxEXPAND, 2 );
105 wxPanel* panelDisplayCurrent =
new wxPanel(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize );
106 mainSizer->Add( panelDisplayCurrent, 0, wxALL | wxEXPAND, 5 );
108 wxFlexGridSizer* fgsizer =
new wxFlexGridSizer( 2 );
109 panelDisplayCurrent->SetSizer( fgsizer );
111 wxStaticText* cmd_label_0 =
new wxStaticText( panelDisplayCurrent, wxID_ANY,
_(
"Command:" ) );
112 fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
114 wxStaticText* cmd_label_1 =
new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
115 cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
116 cmd_label_1->SetLabel( aName );
117 fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
119 wxStaticText* key_label_0 =
new wxStaticText( panelDisplayCurrent, wxID_ANY,
_(
"Current key:" ) );
120 fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
122 wxStaticText* key_label_1 =
new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
123 key_label_1->SetFont( key_label_1->GetFont().Bold() );
124 key_label_1->SetLabel( aCurrentKey );
125 fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
127 fgsizer->AddStretchSpacer();
129 wxButton* resetButton =
new wxButton(
this, wxID_ANY,
_(
"Clear assigned hotkey" ) );
131 mainSizer->Add( resetButton, 0, wxALL | wxALIGN_CENTRE_HORIZONTAL, 5 );
134 mainSizer->Fit(
this );
137 SetMinClientSize( GetClientSize() );
150 static std::optional<long>
PromptForKey( wxWindow* aParent,
const wxString& aName,
151 const wxString& aCurrentKey )
153 HK_PROMPT_DIALOG dialog( aParent, wxID_ANY,
_(
"Set Hotkey" ), aName, aCurrentKey );
159 return std::make_optional( 0 );
166 return std::make_optional( key );
187 const enum wxKeyCode skipped_keys[] =
189 WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL, WXK_NUMLOCK, WXK_SCROLL,
193 int key = aEvent.GetKeyCode();
195 for( wxKeyCode skipped_key : skipped_keys )
197 if( key == skipped_key )
201 if( key <= 255 && isprint( key ) && !isspace( key ) )
204 aEvent.DoAllowNextEvent();
229 if(
m_event.GetEventType() != wxEVT_NULL )
232 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
239 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
271 const auto normedInfo = wxGetTranslation( aHotkey.
m_Actions[0]->GetFriendlyName() ).Upper();
294 wxClientData* data = GetItemData( aItem );
306 for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
313 wxString label = changed_hk.
m_Actions[ 0 ]->GetFriendlyName();
316 wxString description = changed_hk.
m_Actions[ 0 ]->GetDescription();
318 if( label.IsEmpty() )
319 label = changed_hk.
m_Actions[ 0 ]->GetName();
321 label.Replace( wxT(
"..." ), wxEmptyString );
322 label.Replace( wxT(
"…" ), wxEmptyString );
326 label += wxS(
" *" );
328 description.Replace( wxS(
"\n" ), wxS(
" " ) );
329 description.Replace( wxS(
"\r" ), wxS(
" " ) );
331 SetItemText( i, 0, label );
332 SetItemText( i, 1, key_text );
333 SetItemText( i, 2, alt_text );
334 SetItemText( i, 3, description );
366 wxString
name = GetItemText( aItem, 0 );
367 wxString current_key = aEditId ==
ID_EDIT_HOTKEY ? GetItemText( aItem, 1 )
368 : GetItemText( aItem, 2 );
373 if( key.has_value() )
379 wxString msg = wxString::Format(
_(
"'%s' is a reserved hotkey in KiCad and cannot "
445 menu.Append(
ID_RESET,
_(
"Undo Changes" ) );
446 menu.Append(
ID_CLEAR,
_(
"Clear Assigned Hotkey" ) );
447 menu.Append(
ID_CLEAR_ALT,
_(
"Clear Assigned Alternate" ) );
448 menu.Append(
ID_DEFAULT,
_(
"Restore Defaults" ) );
449 menu.Append( wxID_SEPARATOR );
458 switch( aEvent.GetId() )
473 wxFAIL_MSG( wxT(
"Unknown ID in context menu event" ) );
489 if( aEvent.GetUnicodeKey() == WXK_NONE && aEvent.GetKeyCode() == WXK_NONE )
498 HOTKEY* conflictingHotKey =
nullptr;
500 m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
502 if( !conflictingHotKey )
506 wxString msg = wxString::Format(
_(
"'%s' is already assigned to '%s' in section '%s'. "
507 "Both bindings are kept, but only one runs per key "
508 "press. Continue?" ),
514 return dlg.ShowModal() == wxID_YES;
519 wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
522 wxString command_header;
525 command_header =
_(
"Command" );
527 command_header =
_(
"Command (double-click to edit)" );
529 AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
530 AppendColumn(
_(
"Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
531 AppendColumn(
_(
"Alternate" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
532 AppendColumn(
_(
"Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
535#if defined( __WXGTK__ )
539 wxDataViewCtrl* dv = GetDataView();
541 wxString longKey = wxT(
"Ctrl+Alt+Shift+X" );
544 dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 +
pad );
545 dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x +
pad );
546 dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( longKey ).x +
pad );
547 dv->GetColumn( 3 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 +
pad );
551 GetDataView()->Update();
555 std::vector<wxString> reserved_keys =
558 wxS(
"Ctrl+Shift+Tab" )
561 for(
const wxString& key : reserved_keys )
568 wxLogWarning( wxS(
"Unknown reserved keycode %s\n" ), key );
571 GetDataView()->SetIndent( 10 );
594 wxWindowUpdateLocker updateLock(
this );
599 if( aResetToDefault )
620 wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
621 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
622 col->SetWidth( col->GetWidth() );
624 col = GetDataView()->GetColumn( 1 );
625 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
626 col->SetWidth( col->GetWidth() );
628 col = GetDataView()->GetColumn( 2 );
629 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
630 col->SetWidth( col->GetWidth() );
632 col = GetDataView()->GetColumn( 3 );
633 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
634 col->SetWidth( col->GetWidth() );
640 wxWindowUpdateLocker updateLock(
this );
649 wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
651 for(
HOTKEY& hotkey: section.m_HotKeys )
653 if(
filter.FilterMatches( hotkey ) )
655 wxTreeListItem item = AppendItem( parent, wxEmptyString );
676 long key = aEvent.GetKeyCode();
677 bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
679 if( key == WXK_ESCAPE )
685 if( key >=
'a' && key <=
'z' )
686 key = key + (
'A' -
'a');
690 if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
699 bool keyIsLetter = key >=
'A' && key <=
'Z';
701 int mods = aEvent.GetModifiers();
703 if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
708 #if CAN_USE_ALTGR_KEY
709 if( wxmods & wxMOD_ALTGR )
714 if( mods & wxMOD_CONTROL )
717 if( mods & wxMOD_ALT )
722 if( mods & wxMOD_META )
727 if( mods & wxMOD_WIN )
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
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)
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)
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
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").
std::vector< TOOL_ACTION * > m_Actions