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>
79 HK_PROMPT_DIALOG( wxWindow* aParent, wxWindowID aId,
const wxString& aTitle,
const wxString& aName,
80 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, wxDefaultPosition, wxDefaultSize,
97 wxALIGN_CENTRE_HORIZONTAL );
99 inst_label->SetLabelText(
_(
"Press a new hotkey, or press Esc to cancel..." ) );
100 mainSizer->Add( inst_label, 0, wxALL, 10 );
102 mainSizer->Add(
new wxStaticLine(
this ), 0, wxALL | wxEXPAND, 2 );
104 wxPanel* panelDisplayCurrent =
new wxPanel(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize );
105 mainSizer->Add( panelDisplayCurrent, 0, wxALL | wxEXPAND, 5 );
107 wxFlexGridSizer* fgsizer =
new wxFlexGridSizer( 2 );
108 panelDisplayCurrent->SetSizer( fgsizer );
110 wxStaticText* cmd_label_0 =
new wxStaticText( panelDisplayCurrent, wxID_ANY,
_(
"Command:" ) );
111 fgsizer->Add( cmd_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
113 wxStaticText* cmd_label_1 =
new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
114 cmd_label_1->SetFont( cmd_label_1->GetFont().Bold() );
115 cmd_label_1->SetLabel( aName );
116 fgsizer->Add( cmd_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
118 wxStaticText* key_label_0 =
new wxStaticText( panelDisplayCurrent, wxID_ANY,
_(
"Current key:" ) );
119 fgsizer->Add( key_label_0, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
121 wxStaticText* key_label_1 =
new wxStaticText( panelDisplayCurrent, wxID_ANY, wxEmptyString );
122 key_label_1->SetFont( key_label_1->GetFont().Bold() );
123 key_label_1->SetLabel( aCurrentKey );
124 fgsizer->Add( key_label_1, 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5 );
126 fgsizer->AddStretchSpacer();
128 wxButton* resetButton =
new wxButton(
this, wxID_ANY,
_(
"Clear assigned hotkey" ) );
130 mainSizer->Add( resetButton, 0, wxALL | wxALIGN_CENTRE_HORIZONTAL, 5 );
133 mainSizer->Fit(
this );
136 SetMinClientSize( GetClientSize() );
149 static std::optional<long>
PromptForKey( wxWindow* aParent,
const wxString& aName,
const wxString& aCurrentKey )
151 HK_PROMPT_DIALOG dialog( aParent, wxID_ANY,
_(
"Set Hotkey" ), aName, aCurrentKey );
157 return std::make_optional( 0 );
164 return std::make_optional( key );
185 const enum wxKeyCode skipped_keys[] =
187 WXK_NONE, WXK_SHIFT, WXK_ALT, WXK_CONTROL, WXK_CAPITAL, WXK_NUMLOCK, WXK_SCROLL,
191 int key = aEvent.GetKeyCode();
193 for( wxKeyCode skipped_key : skipped_keys )
195 if( key == skipped_key )
199 if( key <= 255 && isprint( key ) && !isspace( key ) )
202 aEvent.DoAllowNextEvent();
227 if(
m_event.GetEventType() != wxEVT_NULL )
230 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
237 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
269 const auto normedInfo = wxGetTranslation( aHotkey.
m_Actions[0]->GetFriendlyName() ).Upper();
292 wxClientData* data = GetItemData( aItem );
304 for( wxTreeListItem i = GetFirstItem(); i.IsOk(); i = GetNextItem( i ) )
311 wxString label = changed_hk.
m_Actions[ 0 ]->GetFriendlyName();
314 wxString description = changed_hk.
m_Actions[ 0 ]->GetDescription();
316 if( label.IsEmpty() )
317 label = changed_hk.
m_Actions[ 0 ]->GetName();
319 label.Replace( wxT(
"..." ), wxEmptyString );
320 label.Replace( wxT(
"…" ), wxEmptyString );
324 label += wxS(
" *" );
326 description.Replace( wxS(
"\n" ), wxS(
" " ) );
327 description.Replace( wxS(
"\r" ), wxS(
" " ) );
329 SetItemText( i, 0, label );
330 SetItemText( i, 1, key_text );
331 SetItemText( i, 2, alt_text );
332 SetItemText( i, 3, description );
342 if( keycode == aKey )
368 *aKeyName = it->second;
381 wxString
name = GetItemText( aItem, 0 );
382 wxString current_key = aEditId ==
ID_EDIT_HOTKEY ? GetItemText( aItem, 1 )
383 : GetItemText( aItem, 2 );
388 if( key.has_value() )
390 wxString reservedKeyName;
394 wxString msg = wxString::Format(
_(
"'%s' is a reserved hotkey in KiCad and cannot be assigned." ),
459 menu.Append(
ID_RESET,
_(
"Undo Changes" ) );
460 menu.Append(
ID_CLEAR,
_(
"Clear Assigned Hotkey" ) );
461 menu.Append(
ID_CLEAR_ALT,
_(
"Clear Assigned Alternate" ) );
462 menu.Append(
ID_DEFAULT,
_(
"Restore Defaults" ) );
463 menu.Append( wxID_SEPARATOR );
472 switch( aEvent.GetId() )
487 wxFAIL_MSG( wxT(
"Unknown ID in context menu event" ) );
503 if( aEvent.GetUnicodeKey() == WXK_NONE && aEvent.GetKeyCode() == WXK_NONE )
512 HOTKEY* conflictingHotKey =
nullptr;
514 m_hk_store.CheckKeyConflicts( aAction, aKey, &conflictingHotKey );
516 if( !conflictingHotKey )
520 wxString msg = wxString::Format(
_(
"'%s' is already assigned to '%s' in section '%s'. Both "
521 "bindings will be kept, but only one will run per key press. "
528 return dlg.ShowModal() == wxID_YES;
533 wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
536 wxString command_header;
539 command_header =
_(
"Command" );
541 command_header =
_(
"Command (double-click to edit)" );
543 AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
544 AppendColumn(
_(
"Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
545 AppendColumn(
_(
"Alternate" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
546 AppendColumn(
_(
"Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
549#if defined( __WXGTK__ )
553 wxDataViewCtrl* dv = GetDataView();
555 wxString longKey = wxT(
"Ctrl+Alt+Shift+X" );
558 dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 +
pad );
559 dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x +
pad );
560 dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( longKey ).x +
pad );
561 dv->GetColumn( 3 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 +
pad );
565 GetDataView()->Update();
569 std::vector<wxString> reserved_keys =
572 wxS(
"Ctrl+Shift+Tab" )
575 for(
const wxString& key : reserved_keys )
582 wxLogWarning( wxS(
"Unknown reserved keycode %s\n" ), key );
585 GetDataView()->SetIndent( 10 );
608 wxWindowUpdateLocker updateLock(
this );
613 if( aResetToDefault )
634 wxDataViewColumn* col = GetDataView()->GetColumn( 0 );
635 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
636 col->SetWidth( col->GetWidth() );
638 col = GetDataView()->GetColumn( 1 );
639 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
640 col->SetWidth( col->GetWidth() );
642 col = GetDataView()->GetColumn( 2 );
643 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
644 col->SetWidth( col->GetWidth() );
646 col = GetDataView()->GetColumn( 3 );
647 col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
648 col->SetWidth( col->GetWidth() );
654 wxWindowUpdateLocker updateLock(
this );
663 wxTreeListItem parent = AppendItem( GetRootItem(), section.m_SectionName );
665 for(
HOTKEY& hotkey: section.m_HotKeys )
667 if(
filter.FilterMatches( hotkey ) )
669 wxTreeListItem item = AppendItem( parent, wxEmptyString );
690 long key = aEvent.GetKeyCode();
691 bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
693 if( key == WXK_ESCAPE )
699 if( key >=
'a' && key <=
'z' )
700 key = key + (
'A' -
'a');
704 if( !is_tab && aEvent.ControlDown() && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
713 bool keyIsLetter = key >=
'A' && key <=
'Z';
715 int mods = aEvent.GetModifiers();
717 if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
722 #if CAN_USE_ALTGR_KEY
723 if( wxmods & wxMOD_ALTGR )
728 if( mods & wxMOD_CONTROL )
731 if( mods & wxMOD_ALT )
736 if( mods & wxMOD_META )
741 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