Hotkeys: add support for alternate hotkeys

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/4422
This commit is contained in:
Mike Williams 2023-07-13 10:08:00 -04:00
parent 4cad021ef4
commit c0a5be4e9f
11 changed files with 132 additions and 52 deletions

View File

@ -191,7 +191,7 @@ void PANEL_HOTKEYS_EDITOR::ImportHotKeys()
if( filename.IsEmpty() ) if( filename.IsEmpty() )
return; return;
std::map<std::string, int> importedHotKeys; std::map<std::string, std::pair<int, int>> importedHotKeys;
ReadHotKeyConfig( filename, importedHotKeys ); ReadHotKeyConfig( filename, importedHotKeys );
m_frame->SetMruPath( wxFileName( filename ).GetPath() ); m_frame->SetMruPath( wxFileName( filename ).GetPath() );
@ -201,7 +201,10 @@ void PANEL_HOTKEYS_EDITOR::ImportHotKeys()
for( HOTKEY& hotkey: section.m_HotKeys ) for( HOTKEY& hotkey: section.m_HotKeys )
{ {
if( importedHotKeys.count( hotkey.m_Actions[ 0 ]->GetName() ) ) if( importedHotKeys.count( hotkey.m_Actions[ 0 ]->GetName() ) )
hotkey.m_EditKeycode = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ]; {
hotkey.m_EditKeycode = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ].first;
hotkey.m_EditKeycodeAlt = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ].second;
}
} }
} }

View File

@ -114,7 +114,10 @@ void HOTKEY_STORE::Init( std::vector<TOOL_ACTION*> aActionsList, bool aIncludeRe
hotkey.m_Actions.push_back( action ); hotkey.m_Actions.push_back( action );
if( !hotkey.m_EditKeycode ) if( !hotkey.m_EditKeycode )
{
hotkey.m_EditKeycode = action->GetHotKey(); hotkey.m_EditKeycode = action->GetHotKey();
hotkey.m_EditKeycodeAlt = action->GetHotKeyAlt();
}
} }
wxString currentApp; wxString currentApp;
@ -170,7 +173,7 @@ void HOTKEY_STORE::SaveAllHotkeys()
for( HOTKEY& hotkey : section.m_HotKeys ) for( HOTKEY& hotkey : section.m_HotKeys )
{ {
for( TOOL_ACTION* action : hotkey.m_Actions ) for( TOOL_ACTION* action : hotkey.m_Actions )
action->SetHotKey( hotkey.m_EditKeycode ); action->SetHotKey( hotkey.m_EditKeycode, hotkey.m_EditKeycodeAlt );
} }
} }
} }
@ -181,7 +184,10 @@ void HOTKEY_STORE::ResetAllHotkeysToDefault()
for( HOTKEY_SECTION& section : m_hk_sections ) for( HOTKEY_SECTION& section : m_hk_sections )
{ {
for( HOTKEY& hotkey : section.m_HotKeys ) for( HOTKEY& hotkey : section.m_HotKeys )
{
hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetDefaultHotKey(); hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetDefaultHotKey();
hotkey.m_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetDefaultHotKeyAlt();
}
} }
} }
@ -191,7 +197,10 @@ void HOTKEY_STORE::ResetAllHotkeysToOriginal()
for( HOTKEY_SECTION& section : m_hk_sections ) for( HOTKEY_SECTION& section : m_hk_sections )
{ {
for( HOTKEY& hotkey : section.m_HotKeys ) for( HOTKEY& hotkey : section.m_HotKeys )
{
hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetHotKey(); hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetHotKey();
hotkey.m_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetHotKeyAlt();
}
} }
} }
@ -219,7 +228,7 @@ bool HOTKEY_STORE::CheckKeyConflicts( TOOL_ACTION* aAction, long aKey, HOTKEY**
if( hotkey.m_Actions[0] == aAction ) if( hotkey.m_Actions[0] == aAction )
continue; continue;
if( hotkey.m_EditKeycode == aKey ) if( hotkey.m_EditKeycode == aKey || hotkey.m_EditKeycodeAlt == aKey )
{ {
// We can use the same key for a different action if both actions are contextual and // We can use the same key for a different action if both actions are contextual and
// for different tools. // for different tools.

View File

@ -348,7 +348,8 @@ void DisplayHotkeyList( EDA_BASE_FRAME* aParent )
} }
void ReadHotKeyConfig( const wxString& aFileName, std::map<std::string, int>& aHotKeys ) void ReadHotKeyConfig( const wxString& aFileName,
std::map<std::string, std::pair<int, int>>& aHotKeys )
{ {
wxString fileName = aFileName; wxString fileName = aFileName;
@ -378,17 +379,19 @@ void ReadHotKeyConfig( const wxString& aFileName, std::map<std::string, int>& aH
wxStringTokenizer lineTokenizer( fileTokenizer.GetNextToken(), wxS( "\t" ) ); wxStringTokenizer lineTokenizer( fileTokenizer.GetNextToken(), wxS( "\t" ) );
wxString cmdName = lineTokenizer.GetNextToken(); wxString cmdName = lineTokenizer.GetNextToken();
wxString keyName = lineTokenizer.GetNextToken(); wxString primary = lineTokenizer.GetNextToken();
wxString secondary = lineTokenizer.GetNextToken();
if( !cmdName.IsEmpty() ) if( !cmdName.IsEmpty() )
aHotKeys[ cmdName.ToStdString() ] = KeyCodeFromKeyName( keyName ); aHotKeys[cmdName.ToStdString()] = std::pair<int, int>(
KeyCodeFromKeyName( primary ), KeyCodeFromKeyName( secondary ) );
} }
} }
void ReadHotKeyConfigIntoActions( const wxString& aFileName, std::vector<TOOL_ACTION*>& aActions ) void ReadHotKeyConfigIntoActions( const wxString& aFileName, std::vector<TOOL_ACTION*>& aActions )
{ {
std::map<std::string, int> hotkeys; std::map<std::string, std::pair<int, int>> hotkeys;
// Read the existing config (all hotkeys) // Read the existing config (all hotkeys)
ReadHotKeyConfig( aFileName, hotkeys ); ReadHotKeyConfig( aFileName, hotkeys );
@ -396,13 +399,16 @@ void ReadHotKeyConfigIntoActions( const wxString& aFileName, std::vector<TOOL_AC
// Set each tool action hotkey to the config file hotkey if present // Set each tool action hotkey to the config file hotkey if present
for( TOOL_ACTION* action : aActions ) for( TOOL_ACTION* action : aActions )
if( hotkeys.find( action->GetName() ) != hotkeys.end() ) if( hotkeys.find( action->GetName() ) != hotkeys.end() )
action->SetHotKey( hotkeys[action->GetName()] ); {
std::pair<int, int> keys = hotkeys[action->GetName()];
action->SetHotKey( keys.first, keys.second );
}
} }
int WriteHotKeyConfig( const std::vector<TOOL_ACTION*>& aActions ) int WriteHotKeyConfig( const std::vector<TOOL_ACTION*>& aActions )
{ {
std::map<std::string, int> hotkeys; std::map<std::string, std::pair<int, int>> hotkeys;
wxFileName fn( "user" ); wxFileName fn( "user" );
fn.SetExt( HotkeyFileExtension ); fn.SetExt( HotkeyFileExtension );
@ -413,14 +419,16 @@ int WriteHotKeyConfig( const std::vector<TOOL_ACTION*>& aActions )
// Overlay the current app's hotkey definitions onto the map // Overlay the current app's hotkey definitions onto the map
for( const TOOL_ACTION* action : aActions ) for( const TOOL_ACTION* action : aActions )
hotkeys[ action->GetName() ] = action->GetHotKey(); hotkeys[ action->GetName() ] = std::pair<int, int>( action->GetHotKey(), action->GetHotKeyAlt() );
// Write entire hotkey set // Write entire hotkey set
wxFFileOutputStream outStream( fn.GetFullPath() ); wxFFileOutputStream outStream( fn.GetFullPath() );
wxTextOutputStream txtStream( outStream, wxEOL_UNIX ); wxTextOutputStream txtStream( outStream, wxEOL_UNIX );
for( const std::pair<const std::string, int>& entry : hotkeys ) for( const std::pair<const std::string, std::pair<int, int>>& entry : hotkeys )
txtStream << entry.first << "\t" << KeyNameFromKeyCode( entry.second ) << endl; txtStream << entry.first
<< "\t" << KeyNameFromKeyCode( entry.second.first )
<< "\t" << KeyNameFromKeyCode( entry.second.second ) << endl;
txtStream.Flush(); txtStream.Flush();
outStream.Close(); outStream.Close();

View File

@ -268,7 +268,7 @@ int ACTION_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate ) void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate )
{ {
static std::map<std::string, int> legacyHotKeyMap; static std::map<std::string, int> legacyHotKeyMap;
static std::map<std::string, int> userHotKeyMap; static std::map<std::string, std::pair<int, int>> userHotKeyMap;
static bool mapsInitialized = false; static bool mapsInitialized = false;
m_actionHotKeys.clear(); m_actionHotKeys.clear();
@ -285,23 +285,28 @@ void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate )
{ {
TOOL_ACTION* action = ii.second; TOOL_ACTION* action = ii.second;
int hotkey = 0; int hotkey = 0;
int alt = 0;
if( aFullUpdate ) if( aFullUpdate )
hotkey = processHotKey( action, legacyHotKeyMap, userHotKeyMap ); processHotKey( action, legacyHotKeyMap, userHotKeyMap );
else
hotkey = action->GetHotKey(); hotkey = action->GetHotKey();
alt = action->GetHotKeyAlt();
if( hotkey > 0 ) if( hotkey > 0 )
m_actionHotKeys[hotkey].push_back( action ); m_actionHotKeys[hotkey].push_back( action );
if( alt > 0 )
m_actionHotKeys[alt].push_back( action );
m_hotkeys[action->GetId()] = hotkey; m_hotkeys[action->GetId()] = hotkey;
} }
} }
int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, void ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction,
const std::map<std::string, int>& aLegacyMap, const std::map<std::string, int>& aLegacyMap,
const std::map<std::string, int>& aHotKeyMap ) const std::map<std::string, std::pair<int, int>>& aHotKeyMap )
{ {
aAction->m_hotKey = aAction->m_defaultHotKey; aAction->m_hotKey = aAction->m_defaultHotKey;
@ -309,7 +314,8 @@ int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction,
aAction->SetHotKey( aLegacyMap.at( aAction->m_legacyName ) ); aAction->SetHotKey( aLegacyMap.at( aAction->m_legacyName ) );
if( aHotKeyMap.count( aAction->m_name ) ) if( aHotKeyMap.count( aAction->m_name ) )
aAction->SetHotKey( aHotKeyMap.at( aAction->m_name ) ); {
std::pair<int, int> keys = aHotKeyMap.at( aAction->m_name );
return aAction->m_hotKey; aAction->SetHotKey( keys.first, keys.second );
}
} }

View File

@ -42,6 +42,7 @@ TOOL_ACTION::TOOL_ACTION( const std::string& aName, TOOL_ACTION_SCOPE aScope,
m_name( aName ), m_name( aName ),
m_scope( aScope ), m_scope( aScope ),
m_defaultHotKey( aDefaultHotKey ), m_defaultHotKey( aDefaultHotKey ),
m_defaultHotKeyAlt( 0 ),
m_legacyName( aLegacyHotKeyName ), m_legacyName( aLegacyHotKeyName ),
m_label( aLabel ), m_label( aLabel ),
m_tooltip( aTooltip ), m_tooltip( aTooltip ),
@ -57,6 +58,7 @@ TOOL_ACTION::TOOL_ACTION( const std::string& aName, TOOL_ACTION_SCOPE aScope,
TOOL_ACTION::TOOL_ACTION() : TOOL_ACTION::TOOL_ACTION() :
m_scope( AS_GLOBAL ), m_scope( AS_GLOBAL ),
m_defaultHotKey( 0 ), m_defaultHotKey( 0 ),
m_defaultHotKeyAlt( 0 ),
m_icon( BITMAPS::INVALID_BITMAP ), m_icon( BITMAPS::INVALID_BITMAP ),
m_id( -1 ), m_id( -1 ),
m_flags( AF_NONE ) m_flags( AF_NONE )
@ -69,6 +71,7 @@ TOOL_ACTION::TOOL_ACTION( const TOOL_ACTION_ARGS& aArgs ) :
m_name( aArgs.m_name.value_or( "" ) ), m_name( aArgs.m_name.value_or( "" ) ),
m_scope( aArgs.m_scope.value_or( AS_CONTEXT ) ), m_scope( aArgs.m_scope.value_or( AS_CONTEXT ) ),
m_defaultHotKey( aArgs.m_defaultHotKey.value_or( 0 ) ), m_defaultHotKey( aArgs.m_defaultHotKey.value_or( 0 ) ),
m_defaultHotKeyAlt( aArgs.m_defaultHotKeyAlt.value_or( 0 ) ),
m_hotKey( aArgs.m_defaultHotKey.value_or( 0 ) ), m_hotKey( aArgs.m_defaultHotKey.value_or( 0 ) ),
m_legacyName( aArgs.m_legacyName.value_or( "" ) ), m_legacyName( aArgs.m_legacyName.value_or( "" ) ),
m_label( TowxString( aArgs.m_menuText.value_or( "" ) ) ), m_label( TowxString( aArgs.m_menuText.value_or( "" ) ) ),
@ -153,9 +156,10 @@ wxString TOOL_ACTION::GetTooltip( bool aIncludeHotkey ) const
} }
void TOOL_ACTION::SetHotKey( int aKeycode ) void TOOL_ACTION::SetHotKey( int aKeycode, int aKeycodeAlt )
{ {
m_hotKey = aKeycode; m_hotKey = aKeycode;
m_hotKeyAlt = aKeycodeAlt;
} }

View File

@ -43,9 +43,11 @@
enum ID_WHKL_MENU_IDS enum ID_WHKL_MENU_IDS
{ {
ID_EDIT_HOTKEY = 2001, ID_EDIT_HOTKEY = 2001,
ID_EDIT_ALT,
ID_RESET, ID_RESET,
ID_DEFAULT, ID_DEFAULT,
ID_CLEAR ID_CLEAR,
ID_CLEAR_ALT,
}; };
@ -291,6 +293,7 @@ void WIDGET_HOTKEY_LIST::updateFromClientData()
const HOTKEY& changed_hk = hkdata->GetChangedHotkey(); const HOTKEY& changed_hk = hkdata->GetChangedHotkey();
wxString label = changed_hk.m_Actions[ 0 ]->GetLabel(); wxString label = changed_hk.m_Actions[ 0 ]->GetLabel();
wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode ); wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode );
wxString alt_text = KeyNameFromKeyCode( changed_hk.m_EditKeycodeAlt );
wxString description = changed_hk.m_Actions[ 0 ]->GetDescription(); wxString description = changed_hk.m_Actions[ 0 ]->GetDescription();
if( label.IsEmpty() ) if( label.IsEmpty() )
@ -308,13 +311,14 @@ void WIDGET_HOTKEY_LIST::updateFromClientData()
SetItemText( i, 0, label ); SetItemText( i, 0, label );
SetItemText( i, 1, key_text ); SetItemText( i, 1, key_text );
SetItemText( i, 2, description ); SetItemText( i, 2, alt_text );
SetItemText( i, 3, description );
} }
} }
} }
void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey ) void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey, bool alternate )
{ {
// See if this key code is handled in hotkeys names list // See if this key code is handled in hotkeys names list
bool exists; bool exists;
@ -323,12 +327,17 @@ void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey )
if( exists && aHotkey.m_EditKeycode != aKey ) if( exists && aHotkey.m_EditKeycode != aKey )
{ {
if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) ) if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) )
{
if( alternate )
aHotkey.m_EditKeycodeAlt = aKey;
else
aHotkey.m_EditKeycode = aKey; aHotkey.m_EditKeycode = aKey;
} }
} }
}
void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem ) void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem, int aEditId )
{ {
WIDGET_HOTKEY_CLIENT_DATA* hkdata = getExpectedHkClientData( aItem ); WIDGET_HOTKEY_CLIENT_DATA* hkdata = getExpectedHkClientData( aItem );
@ -336,7 +345,8 @@ void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem )
return; return;
wxString name = GetItemText( aItem, 0 ); wxString name = GetItemText( aItem, 0 );
wxString current_key = GetItemText( aItem, 1 ); wxString current_key =
aEditId == ID_EDIT_HOTKEY ? GetItemText( aItem, 1 ) : GetItemText( aItem, 2 );
wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( this, name, current_key ); wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( this, name, current_key );
long key = MapKeypressToKeycode( key_event ); long key = MapKeypressToKeycode( key_event );
@ -355,7 +365,7 @@ void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem )
return; return;
} }
changeHotkey( hkdata->GetChangedHotkey(), key ); changeHotkey( hkdata->GetChangedHotkey(), key, aEditId == ID_EDIT_ALT );
updateFromClientData(); updateFromClientData();
} }
} }
@ -371,11 +381,19 @@ void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
HOTKEY& changed_hk = hkdata->GetChangedHotkey(); HOTKEY& changed_hk = hkdata->GetChangedHotkey();
if( aResetId == ID_RESET ) if( aResetId == ID_RESET )
changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetHotKey() ); {
changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetHotKey(), false );
changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetHotKey(), true );
}
else if( aResetId == ID_CLEAR ) else if( aResetId == ID_CLEAR )
changeHotkey( changed_hk, 0 ); changeHotkey( changed_hk, 0, false );
else if( aResetId == ID_CLEAR_ALT )
changeHotkey( changed_hk, 0, true );
else if( aResetId == ID_DEFAULT ) else if( aResetId == ID_DEFAULT )
changeHotkey( changed_hk, changed_hk.m_Actions[ 0 ]->GetDefaultHotKey() ); {
changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetDefaultHotKey(), false );
changeHotkey( changed_hk, changed_hk.m_Actions[0]->GetDefaultHotKeyAlt(), true );
}
updateFromClientData(); updateFromClientData();
} }
@ -383,7 +401,7 @@ void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId )
void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent ) void WIDGET_HOTKEY_LIST::onActivated( wxTreeListEvent& aEvent )
{ {
editItem( aEvent.GetItem()); editItem( aEvent.GetItem(), ID_EDIT_HOTKEY );
} }
@ -400,9 +418,11 @@ void WIDGET_HOTKEY_LIST::onContextMenu( wxTreeListEvent& aEvent )
if( hkdata ) if( hkdata )
{ {
menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) ); menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) );
menu.Append( ID_EDIT_ALT, _( "Edit Alternate..." ) );
menu.Append( ID_RESET, _( "Undo Changes" ) ); menu.Append( ID_RESET, _( "Undo Changes" ) );
menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) ); menu.Append( ID_CLEAR, _( "Clear Assigned Hotkey" ) );
menu.Append( ID_DEFAULT, _( "Restore Default" ) ); menu.Append( ID_CLEAR_ALT, _( "Clear Assigned Alternate" ) );
menu.Append( ID_DEFAULT, _( "Restore Defaults" ) );
menu.Append( wxID_SEPARATOR ); menu.Append( wxID_SEPARATOR );
PopupMenu( &menu ); PopupMenu( &menu );
@ -415,11 +435,13 @@ void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent )
switch( aEvent.GetId() ) switch( aEvent.GetId() )
{ {
case ID_EDIT_HOTKEY: case ID_EDIT_HOTKEY:
editItem( m_context_menu_item ); case ID_EDIT_ALT:
editItem( m_context_menu_item, aEvent.GetId() );
break; break;
case ID_RESET: case ID_RESET:
case ID_CLEAR: case ID_CLEAR:
case ID_CLEAR_ALT:
case ID_DEFAULT: case ID_DEFAULT:
resetItem( m_context_menu_item, aEvent.GetId() ); resetItem( m_context_menu_item, aEvent.GetId() );
break; break;
@ -473,6 +495,7 @@ WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkey
AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE ); AppendColumn( command_header, 450, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE ); AppendColumn( _( "Hotkey" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
AppendColumn( _( "Alternate" ), 120, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE ); AppendColumn( _( "Description" ), 900, wxALIGN_LEFT, wxCOL_RESIZABLE | wxCOL_SORTABLE );
@ -487,7 +510,8 @@ WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkey
dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 + pad ); dv->GetColumn( 0 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 2 + pad );
dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad ); dv->GetColumn( 1 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 + pad ); dv->GetColumn( 2 )->SetMinWidth( aParent->GetTextExtent( longKey ).x + pad );
dv->GetColumn( 3 )->SetMinWidth( aParent->GetTextExtent( command_header ).x * 5 + pad );
CallAfter( [&]() CallAfter( [&]()
{ {
@ -579,6 +603,14 @@ void WIDGET_HOTKEY_LIST::updateColumnWidths()
col->SetWidth( wxCOL_WIDTH_AUTOSIZE ); col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
col->SetWidth( col->GetWidth() ); col->SetWidth( col->GetWidth() );
#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
col->SetResizeable( true );
#endif
col = GetDataView()->GetColumn( 3 );
col->SetWidth( wxCOL_WIDTH_AUTOSIZE );
col->SetWidth( col->GetWidth() );
#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 ) #if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 1, 0 )
col->SetResizeable( true ); col->SetResizeable( true );
#endif #endif

View File

@ -35,13 +35,15 @@ struct HOTKEY
{ {
std::vector<TOOL_ACTION*> m_Actions; std::vector<TOOL_ACTION*> m_Actions;
int m_EditKeycode; int m_EditKeycode;
int m_EditKeycodeAlt;
HOTKEY() : HOTKEY() :
m_EditKeycode( 0 ) m_EditKeycode( 0 )
{ } { }
HOTKEY( TOOL_ACTION* aAction ) : HOTKEY( TOOL_ACTION* aAction ) :
m_EditKeycode( aAction->GetHotKey() ) m_EditKeycode( aAction->GetHotKey() ),
m_EditKeycodeAlt( aAction->GetHotKeyAlt() )
{ {
m_Actions.push_back( aAction ); m_Actions.push_back( aAction );
} }

View File

@ -101,7 +101,8 @@ void DisplayHotkeyList( EDA_BASE_FRAME* aFrame );
* *
* If \a aFileName is empty it will read in the default hotkeys file. * If \a aFileName is empty it will read in the default hotkeys file.
*/ */
void ReadHotKeyConfig( const wxString& aFileName, std::map<std::string, int>& aHotKeys ); void ReadHotKeyConfig( const wxString& aFileName,
std::map<std::string, std::pair<int, int>>& aHotKeys );
/** /**
* Reads a hotkey config file into a list of actions * Reads a hotkey config file into a list of actions

View File

@ -180,8 +180,8 @@ public:
private: private:
// Resolve a hotkey by applying legacy and current settings over the action's // Resolve a hotkey by applying legacy and current settings over the action's
// default hotkey. // default hotkey.
int processHotKey( TOOL_ACTION* aAction, const std::map<std::string, int>& aLegacyMap, void processHotKey( TOOL_ACTION* aAction, const std::map<std::string, int>& aLegacyMap,
const std::map<std::string, int>& aHotKeyMap ); const std::map<std::string, std::pair<int, int>>& aHotKeyMap );
///< Tool manager needed to run actions ///< Tool manager needed to run actions
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;

View File

@ -97,6 +97,15 @@ public:
return *this; return *this;
} }
/**
* The default alternate hotkey to assign to the action.
*/
TOOL_ACTION_ARGS& DefaultHotkeyAlt( int aDefaultHotkeyAlt )
{
m_defaultHotKeyAlt = aDefaultHotkeyAlt;
return *this;
}
/** /**
* The legacy hotkey name from the old system. * The legacy hotkey name from the old system.
* *
@ -183,6 +192,7 @@ protected:
std::optional<int> m_uiid; std::optional<int> m_uiid;
std::optional<int> m_defaultHotKey; std::optional<int> m_defaultHotKey;
std::optional<int> m_defaultHotKeyAlt;
std::optional<std::string_view> m_legacyName; std::optional<std::string_view> m_legacyName;
std::optional<std::string_view> m_menuText; std::optional<std::string_view> m_menuText;
@ -245,12 +255,14 @@ public:
* Return the default hotkey (if any) for the action. * Return the default hotkey (if any) for the action.
*/ */
int GetDefaultHotKey() const { return m_defaultHotKey; } int GetDefaultHotKey() const { return m_defaultHotKey; }
int GetDefaultHotKeyAlt() const { return m_defaultHotKeyAlt; }
/** /**
* Return the hotkey keycode which initiates the action. * Return the hotkey keycode which initiates the action.
*/ */
int GetHotKey() const { return m_hotKey; } int GetHotKey() const { return m_hotKey; }
void SetHotKey( int aKeycode ); int GetHotKeyAlt() const { return m_hotKeyAlt; }
void SetHotKey( int aKeycode, int aKeycodeAlt = 0 );
/** /**
* Return the unique id of the TOOL_ACTION object. * Return the unique id of the TOOL_ACTION object.
@ -365,7 +377,9 @@ protected:
TOOL_ACTION_SCOPE m_scope; TOOL_ACTION_SCOPE m_scope;
const int m_defaultHotKey; // Default hot key const int m_defaultHotKey; // Default hot key
const int m_defaultHotKeyAlt; // Default hot key alternate
int m_hotKey; // The current hotkey (post-user-settings-application) int m_hotKey; // The current hotkey (post-user-settings-application)
int m_hotKeyAlt; // The alternate hotkey (post-user-settings-application)
const std::string m_legacyName; // Name for reading legacy hotkey settings const std::string m_legacyName; // Name for reading legacy hotkey settings
wxString m_label; // Menu label wxString m_label; // Menu label

View File

@ -92,7 +92,7 @@ protected:
* Method editItem * Method editItem
* Prompt the user for a new hotkey given a list item. * Prompt the user for a new hotkey given a list item.
*/ */
void editItem( wxTreeListItem aItem ); void editItem( wxTreeListItem aItem, int aEditId );
/** /**
* Method resetItem * Method resetItem
@ -171,8 +171,9 @@ private:
* *
* @param aHotkey the change-able hotkey to try to change * @param aHotkey the change-able hotkey to try to change
* @param aKey the key code to change it to * @param aKey the key code to change it to
* @param alternate Change the secondary hotkey
*/ */
void changeHotkey( HOTKEY& aHotkey, long aKey ); void changeHotkey( HOTKEY& aHotkey, long aKey, bool alternate );
/** /**
* Recalculates column widths after model has changed * Recalculates column widths after model has changed