diff --git a/common/dialogs/panel_hotkeys_editor.cpp b/common/dialogs/panel_hotkeys_editor.cpp index 3d76ee075a..90ad40bfbd 100644 --- a/common/dialogs/panel_hotkeys_editor.cpp +++ b/common/dialogs/panel_hotkeys_editor.cpp @@ -191,7 +191,7 @@ void PANEL_HOTKEYS_EDITOR::ImportHotKeys() if( filename.IsEmpty() ) return; - std::map importedHotKeys; + std::map> importedHotKeys; ReadHotKeyConfig( filename, importedHotKeys ); m_frame->SetMruPath( wxFileName( filename ).GetPath() ); @@ -201,7 +201,10 @@ void PANEL_HOTKEYS_EDITOR::ImportHotKeys() for( HOTKEY& hotkey: section.m_HotKeys ) { 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; + } } } diff --git a/common/hotkey_store.cpp b/common/hotkey_store.cpp index 1300742c9f..b3d55391ca 100644 --- a/common/hotkey_store.cpp +++ b/common/hotkey_store.cpp @@ -114,7 +114,10 @@ void HOTKEY_STORE::Init( std::vector aActionsList, bool aIncludeRe hotkey.m_Actions.push_back( action ); if( !hotkey.m_EditKeycode ) + { hotkey.m_EditKeycode = action->GetHotKey(); + hotkey.m_EditKeycodeAlt = action->GetHotKeyAlt(); + } } wxString currentApp; @@ -170,7 +173,7 @@ void HOTKEY_STORE::SaveAllHotkeys() for( HOTKEY& hotkey : section.m_HotKeys ) { 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& 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& 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 ) 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 // for different tools. diff --git a/common/hotkeys_basic.cpp b/common/hotkeys_basic.cpp index 973937db5e..07b0b187f5 100644 --- a/common/hotkeys_basic.cpp +++ b/common/hotkeys_basic.cpp @@ -348,7 +348,8 @@ void DisplayHotkeyList( EDA_BASE_FRAME* aParent ) } -void ReadHotKeyConfig( const wxString& aFileName, std::map& aHotKeys ) +void ReadHotKeyConfig( const wxString& aFileName, + std::map>& aHotKeys ) { wxString fileName = aFileName; @@ -377,18 +378,20 @@ void ReadHotKeyConfig( const wxString& aFileName, std::map& aH { wxStringTokenizer lineTokenizer( fileTokenizer.GetNextToken(), wxS( "\t" ) ); - wxString cmdName = lineTokenizer.GetNextToken(); - wxString keyName = lineTokenizer.GetNextToken(); + wxString cmdName = lineTokenizer.GetNextToken(); + wxString primary = lineTokenizer.GetNextToken(); + wxString secondary = lineTokenizer.GetNextToken(); if( !cmdName.IsEmpty() ) - aHotKeys[ cmdName.ToStdString() ] = KeyCodeFromKeyName( keyName ); + aHotKeys[cmdName.ToStdString()] = std::pair( + KeyCodeFromKeyName( primary ), KeyCodeFromKeyName( secondary ) ); } } void ReadHotKeyConfigIntoActions( const wxString& aFileName, std::vector& aActions ) { - std::map hotkeys; + std::map> hotkeys; // Read the existing config (all hotkeys) ReadHotKeyConfig( aFileName, hotkeys ); @@ -396,13 +399,16 @@ void ReadHotKeyConfigIntoActions( const wxString& aFileName, std::vectorGetName() ) != hotkeys.end() ) - action->SetHotKey( hotkeys[action->GetName()] ); + { + std::pair keys = hotkeys[action->GetName()]; + action->SetHotKey( keys.first, keys.second ); + } } int WriteHotKeyConfig( const std::vector& aActions ) { - std::map hotkeys; + std::map> hotkeys; wxFileName fn( "user" ); fn.SetExt( HotkeyFileExtension ); @@ -413,14 +419,16 @@ int WriteHotKeyConfig( const std::vector& aActions ) // Overlay the current app's hotkey definitions onto the map for( const TOOL_ACTION* action : aActions ) - hotkeys[ action->GetName() ] = action->GetHotKey(); + hotkeys[ action->GetName() ] = std::pair( action->GetHotKey(), action->GetHotKeyAlt() ); // Write entire hotkey set wxFFileOutputStream outStream( fn.GetFullPath() ); wxTextOutputStream txtStream( outStream, wxEOL_UNIX ); - for( const std::pair& entry : hotkeys ) - txtStream << entry.first << "\t" << KeyNameFromKeyCode( entry.second ) << endl; + for( const std::pair>& entry : hotkeys ) + txtStream << entry.first + << "\t" << KeyNameFromKeyCode( entry.second.first ) + << "\t" << KeyNameFromKeyCode( entry.second.second ) << endl; txtStream.Flush(); outStream.Close(); diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index 9092bc28f9..2e1e02fb05 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -268,7 +268,7 @@ int ACTION_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate ) { static std::map legacyHotKeyMap; - static std::map userHotKeyMap; + static std::map> userHotKeyMap; static bool mapsInitialized = false; m_actionHotKeys.clear(); @@ -285,23 +285,28 @@ void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate ) { TOOL_ACTION* action = ii.second; int hotkey = 0; + int alt = 0; if( aFullUpdate ) - hotkey = processHotKey( action, legacyHotKeyMap, userHotKeyMap ); - else - hotkey = action->GetHotKey(); + processHotKey( action, legacyHotKeyMap, userHotKeyMap ); + + hotkey = action->GetHotKey(); + alt = action->GetHotKeyAlt(); if( hotkey > 0 ) m_actionHotKeys[hotkey].push_back( action ); + if( alt > 0 ) + m_actionHotKeys[alt].push_back( action ); + m_hotkeys[action->GetId()] = hotkey; } } -int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, - const std::map& aLegacyMap, - const std::map& aHotKeyMap ) +void ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, + const std::map& aLegacyMap, + const std::map>& aHotKeyMap ) { aAction->m_hotKey = aAction->m_defaultHotKey; @@ -309,7 +314,8 @@ int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, aAction->SetHotKey( aLegacyMap.at( aAction->m_legacyName ) ); if( aHotKeyMap.count( aAction->m_name ) ) - aAction->SetHotKey( aHotKeyMap.at( aAction->m_name ) ); - - return aAction->m_hotKey; + { + std::pair keys = aHotKeyMap.at( aAction->m_name ); + aAction->SetHotKey( keys.first, keys.second ); + } } diff --git a/common/tool/tool_action.cpp b/common/tool/tool_action.cpp index d1af1aa5bb..f57dbf20f6 100644 --- a/common/tool/tool_action.cpp +++ b/common/tool/tool_action.cpp @@ -42,6 +42,7 @@ TOOL_ACTION::TOOL_ACTION( const std::string& aName, TOOL_ACTION_SCOPE aScope, m_name( aName ), m_scope( aScope ), m_defaultHotKey( aDefaultHotKey ), + m_defaultHotKeyAlt( 0 ), m_legacyName( aLegacyHotKeyName ), m_label( aLabel ), m_tooltip( aTooltip ), @@ -57,6 +58,7 @@ TOOL_ACTION::TOOL_ACTION( const std::string& aName, TOOL_ACTION_SCOPE aScope, TOOL_ACTION::TOOL_ACTION() : m_scope( AS_GLOBAL ), m_defaultHotKey( 0 ), + m_defaultHotKeyAlt( 0 ), m_icon( BITMAPS::INVALID_BITMAP ), m_id( -1 ), 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_scope( aArgs.m_scope.value_or( AS_CONTEXT ) ), 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_legacyName( aArgs.m_legacyName.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_hotKeyAlt = aKeycodeAlt; } diff --git a/common/widgets/widget_hotkey_list.cpp b/common/widgets/widget_hotkey_list.cpp index 9c4e0eaa60..ae61cd415e 100644 --- a/common/widgets/widget_hotkey_list.cpp +++ b/common/widgets/widget_hotkey_list.cpp @@ -43,9 +43,11 @@ enum ID_WHKL_MENU_IDS { ID_EDIT_HOTKEY = 2001, + ID_EDIT_ALT, ID_RESET, ID_DEFAULT, - ID_CLEAR + ID_CLEAR, + ID_CLEAR_ALT, }; @@ -291,6 +293,7 @@ void WIDGET_HOTKEY_LIST::updateFromClientData() const HOTKEY& changed_hk = hkdata->GetChangedHotkey(); wxString label = changed_hk.m_Actions[ 0 ]->GetLabel(); wxString key_text = KeyNameFromKeyCode( changed_hk.m_EditKeycode ); + wxString alt_text = KeyNameFromKeyCode( changed_hk.m_EditKeycodeAlt ); wxString description = changed_hk.m_Actions[ 0 ]->GetDescription(); if( label.IsEmpty() ) @@ -307,14 +310,15 @@ void WIDGET_HOTKEY_LIST::updateFromClientData() description.Replace( wxS( "\r" ), wxS( " " ) ); SetItemText( i, 0, label ); - SetItemText( i, 1, key_text); - SetItemText( i, 2, description ); + SetItemText( i, 1, key_text ); + 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 bool exists; @@ -323,12 +327,17 @@ void WIDGET_HOTKEY_LIST::changeHotkey( HOTKEY& aHotkey, long aKey ) if( exists && aHotkey.m_EditKeycode != aKey ) { if( aKey == 0 || resolveKeyConflicts( aHotkey.m_Actions[ 0 ], aKey ) ) - aHotkey.m_EditKeycode = aKey; + { + if( alternate ) + aHotkey.m_EditKeycodeAlt = aKey; + else + 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 ); @@ -336,7 +345,8 @@ void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem ) return; 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 ); long key = MapKeypressToKeycode( key_event ); @@ -355,7 +365,7 @@ void WIDGET_HOTKEY_LIST::editItem( wxTreeListItem aItem ) return; } - changeHotkey( hkdata->GetChangedHotkey(), key ); + changeHotkey( hkdata->GetChangedHotkey(), key, aEditId == ID_EDIT_ALT ); updateFromClientData(); } } @@ -371,11 +381,19 @@ void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId ) HOTKEY& changed_hk = hkdata->GetChangedHotkey(); 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 ) - 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 ) - 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(); } @@ -383,7 +401,7 @@ void WIDGET_HOTKEY_LIST::resetItem( wxTreeListItem aItem, int aResetId ) 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 ) { menu.Append( ID_EDIT_HOTKEY, _( "Edit..." ) ); + menu.Append( ID_EDIT_ALT, _( "Edit Alternate..." ) ); menu.Append( ID_RESET, _( "Undo Changes" ) ); 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 ); PopupMenu( &menu ); @@ -415,13 +435,15 @@ void WIDGET_HOTKEY_LIST::onMenu( wxCommandEvent& aEvent ) switch( aEvent.GetId() ) { case ID_EDIT_HOTKEY: - editItem( m_context_menu_item ); + case ID_EDIT_ALT: + editItem( m_context_menu_item, aEvent.GetId() ); break; case ID_RESET: case ID_CLEAR: + case ID_CLEAR_ALT: case ID_DEFAULT: - resetItem( m_context_menu_item, aEvent.GetId()); + resetItem( m_context_menu_item, aEvent.GetId() ); break; default: @@ -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( _( "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 ); @@ -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( 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( [&]() { @@ -579,6 +603,14 @@ void WIDGET_HOTKEY_LIST::updateColumnWidths() col->SetWidth( wxCOL_WIDTH_AUTOSIZE ); 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 ) col->SetResizeable( true ); #endif diff --git a/include/hotkey_store.h b/include/hotkey_store.h index 5789c21872..23c4d829d8 100644 --- a/include/hotkey_store.h +++ b/include/hotkey_store.h @@ -35,13 +35,15 @@ struct HOTKEY { std::vector m_Actions; int m_EditKeycode; + int m_EditKeycodeAlt; HOTKEY() : m_EditKeycode( 0 ) { } HOTKEY( TOOL_ACTION* aAction ) : - m_EditKeycode( aAction->GetHotKey() ) + m_EditKeycode( aAction->GetHotKey() ), + m_EditKeycodeAlt( aAction->GetHotKeyAlt() ) { m_Actions.push_back( aAction ); } @@ -111,4 +113,4 @@ private: std::vector m_hk_sections; }; -#endif // HOTKEY_STORE__H \ No newline at end of file +#endif // HOTKEY_STORE__H diff --git a/include/hotkeys_basic.h b/include/hotkeys_basic.h index 73738b6f37..0a6adc788a 100644 --- a/include/hotkeys_basic.h +++ b/include/hotkeys_basic.h @@ -101,7 +101,8 @@ void DisplayHotkeyList( EDA_BASE_FRAME* aFrame ); * * If \a aFileName is empty it will read in the default hotkeys file. */ -void ReadHotKeyConfig( const wxString& aFileName, std::map& aHotKeys ); +void ReadHotKeyConfig( const wxString& aFileName, + std::map>& aHotKeys ); /** * Reads a hotkey config file into a list of actions diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index 98f98e446f..19516019a0 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -180,8 +180,8 @@ public: private: // Resolve a hotkey by applying legacy and current settings over the action's // default hotkey. - int processHotKey( TOOL_ACTION* aAction, const std::map& aLegacyMap, - const std::map& aHotKeyMap ); + void processHotKey( TOOL_ACTION* aAction, const std::map& aLegacyMap, + const std::map>& aHotKeyMap ); ///< Tool manager needed to run actions TOOL_MANAGER* m_toolMgr; diff --git a/include/tool/tool_action.h b/include/tool/tool_action.h index 2ed31d2794..49cc1bdba2 100644 --- a/include/tool/tool_action.h +++ b/include/tool/tool_action.h @@ -97,6 +97,15 @@ public: 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. * @@ -183,6 +192,7 @@ protected: std::optional m_uiid; std::optional m_defaultHotKey; + std::optional m_defaultHotKeyAlt; std::optional m_legacyName; std::optional m_menuText; @@ -245,12 +255,14 @@ public: * Return the default hotkey (if any) for the action. */ int GetDefaultHotKey() const { return m_defaultHotKey; } + int GetDefaultHotKeyAlt() const { return m_defaultHotKeyAlt; } /** * Return the hotkey keycode which initiates the action. */ 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. @@ -364,8 +376,10 @@ protected: std::string m_name; 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_hotKeyAlt; // The alternate hotkey (post-user-settings-application) const std::string m_legacyName; // Name for reading legacy hotkey settings wxString m_label; // Menu label diff --git a/include/widgets/widget_hotkey_list.h b/include/widgets/widget_hotkey_list.h index 4201d7eda0..cb6a8a9efd 100644 --- a/include/widgets/widget_hotkey_list.h +++ b/include/widgets/widget_hotkey_list.h @@ -92,7 +92,7 @@ protected: * Method editItem * Prompt the user for a new hotkey given a list item. */ - void editItem( wxTreeListItem aItem ); + void editItem( wxTreeListItem aItem, int aEditId ); /** * Method resetItem @@ -171,8 +171,9 @@ private: * * @param aHotkey the change-able hotkey to try to change * @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