2018-09-26 14:26:26 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KICAD, a free EDA CAD application.
|
|
|
|
*
|
2019-06-09 21:57:23 +00:00
|
|
|
* Copyright (C) 1992-2019 Kicad Developers, see AUTHORS.txt for contributors.
|
2018-09-26 14:26:26 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <hotkey_store.h>
|
2019-06-14 10:55:54 +00:00
|
|
|
#include <eda_base_frame.h>
|
2019-06-09 21:57:23 +00:00
|
|
|
#include <tool/tool_manager.h>
|
2019-06-12 10:22:23 +00:00
|
|
|
#include <tool/action_manager.h>
|
2019-06-12 14:39:47 +00:00
|
|
|
#include <tool/tool_event.h>
|
2019-06-09 21:57:23 +00:00
|
|
|
#include <tool/tool_action.h>
|
2021-07-26 17:56:11 +00:00
|
|
|
#include <advanced_config.h>
|
2019-06-09 21:57:23 +00:00
|
|
|
|
2021-05-11 22:15:01 +00:00
|
|
|
class PSEUDO_ACTION : public TOOL_ACTION
|
2019-06-12 14:39:47 +00:00
|
|
|
{
|
|
|
|
public:
|
2021-05-11 22:15:01 +00:00
|
|
|
PSEUDO_ACTION( const wxString& aLabel, int aHotKey )
|
2019-06-12 14:39:47 +00:00
|
|
|
{
|
|
|
|
m_label = aLabel;
|
|
|
|
m_hotKey = aHotKey;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-05-11 22:15:01 +00:00
|
|
|
static PSEUDO_ACTION* g_gesturePseudoActions[] = {
|
|
|
|
new PSEUDO_ACTION( _( "Pan Left/Right" ), MD_CTRL + PSEUDO_WXK_WHEEL ),
|
|
|
|
new PSEUDO_ACTION( _( "Pan Up/Down" ), MD_SHIFT + PSEUDO_WXK_WHEEL ),
|
|
|
|
new PSEUDO_ACTION( _( "Finish Drawing" ), PSEUDO_WXK_DBLCLICK ),
|
|
|
|
new PSEUDO_ACTION( _( "Add to Selection" ), MD_SHIFT + PSEUDO_WXK_CLICK ),
|
2021-12-13 15:16:33 +00:00
|
|
|
new PSEUDO_ACTION( _( "Highlight Net" ), MD_CTRL + PSEUDO_WXK_CLICK ),
|
|
|
|
new PSEUDO_ACTION( _( "Remove from Selection" ), MD_SHIFT + MD_CTRL + PSEUDO_WXK_CLICK ),
|
2021-05-11 22:15:01 +00:00
|
|
|
new PSEUDO_ACTION( _( "Ignore Grid Snaps" ), MD_CTRL ),
|
|
|
|
new PSEUDO_ACTION( _( "Ignore Other Snaps" ), MD_SHIFT ),
|
|
|
|
};
|
|
|
|
|
|
|
|
static PSEUDO_ACTION* g_standardPlatformCommands[] = {
|
2021-07-04 22:21:53 +00:00
|
|
|
#ifndef __WINDOWS__
|
2021-05-11 22:15:01 +00:00
|
|
|
new PSEUDO_ACTION( _( "Close" ), MD_CTRL + 'W' ),
|
2021-07-04 22:21:53 +00:00
|
|
|
#endif
|
2021-05-11 22:15:01 +00:00
|
|
|
new PSEUDO_ACTION( _( "Quit" ), MD_CTRL + 'Q' )
|
2019-06-12 14:39:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
wxString HOTKEY_STORE::GetAppName( TOOL_ACTION* aAction )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-09 21:57:23 +00:00
|
|
|
wxString name( aAction->GetName() );
|
|
|
|
return name.BeforeFirst( '.' );
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
wxString HOTKEY_STORE::GetSectionName( TOOL_ACTION* aAction )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-09 21:57:23 +00:00
|
|
|
std::map<wxString, wxString> s_AppNames = {
|
|
|
|
{ wxT( "common" ), _( "Common" ) },
|
2020-07-15 12:53:39 +00:00
|
|
|
{ wxT( "kicad" ), _( "Project Manager" ) },
|
2021-02-18 15:49:35 +00:00
|
|
|
{ wxT( "eeschema" ), _( "Schematic Editor" ) },
|
|
|
|
{ wxT( "pcbnew" ), _( "PCB Editor" ) },
|
2021-02-22 16:37:43 +00:00
|
|
|
{ wxT( "plEditor" ), _( "Drawing Sheet Editor" ), },
|
2019-06-10 22:17:45 +00:00
|
|
|
{ wxT( "3DViewer" ), _( "3D Viewer" ) }
|
2019-06-09 21:57:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
wxString appName = GetAppName( aAction );
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
if( s_AppNames.count( appName ) )
|
|
|
|
return s_AppNames[ appName ];
|
|
|
|
else
|
2019-06-12 14:39:47 +00:00
|
|
|
return appName;
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
HOTKEY_STORE::HOTKEY_STORE()
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-11 22:15:01 +00:00
|
|
|
void HOTKEY_STORE::Init( std::vector<TOOL_MANAGER*> aToolManagerList, bool aIncludeReadOnlyCmds )
|
2018-09-27 14:48:52 +00:00
|
|
|
{
|
2019-06-09 21:57:23 +00:00
|
|
|
m_toolManagers = std::move( aToolManagerList );
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
// Collect all action maps into a single master map. This will re-group everything
|
2019-06-14 10:55:54 +00:00
|
|
|
// and collect duplicates together
|
|
|
|
std::map<std::string, HOTKEY> masterMap;
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
for( TOOL_MANAGER* toolMgr : m_toolManagers )
|
2018-09-27 14:48:52 +00:00
|
|
|
{
|
2021-05-11 22:15:01 +00:00
|
|
|
for( const std::pair<const std::string, TOOL_ACTION*>& entry : toolMgr->GetActions() )
|
2019-06-09 21:57:23 +00:00
|
|
|
{
|
|
|
|
// Internal actions probably shouldn't be allowed hotkeys
|
2019-06-10 14:23:37 +00:00
|
|
|
if( entry.second->GetLabel().IsEmpty() )
|
2019-06-09 21:57:23 +00:00
|
|
|
continue;
|
2019-06-14 10:55:54 +00:00
|
|
|
|
2021-07-26 17:56:11 +00:00
|
|
|
if( !ADVANCED_CFG::GetCfg().m_ExtraZoneDisplayModes )
|
|
|
|
{
|
|
|
|
if( entry.second->GetName() == "pcbnew.Control.zoneDisplayOutlines"
|
|
|
|
|| entry.second->GetName() == "pcbnew.Control.zoneDisplayTesselation" )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 10:55:54 +00:00
|
|
|
HOTKEY& hotkey = masterMap[ entry.first ];
|
|
|
|
hotkey.m_Actions.push_back( entry.second );
|
|
|
|
hotkey.m_EditKeycode = entry.second->GetHotKey();
|
2019-06-09 21:57:23 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
wxString currentApp;
|
|
|
|
HOTKEY_SECTION* currentSection = nullptr;
|
2018-09-27 14:48:52 +00:00
|
|
|
|
2019-07-16 16:29:50 +00:00
|
|
|
// If a previous list was built, ensure this previous list is cleared:
|
|
|
|
m_hk_sections.clear();
|
|
|
|
|
2021-05-11 22:15:01 +00:00
|
|
|
for( const std::pair<const std::string, HOTKEY>& entry : masterMap )
|
2019-06-09 21:57:23 +00:00
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
TOOL_ACTION* entryAction = entry.second.m_Actions[ 0 ];
|
|
|
|
wxString entryApp = GetAppName( entryAction );
|
2019-06-12 14:39:47 +00:00
|
|
|
|
2020-01-11 21:14:09 +00:00
|
|
|
if( !currentSection || entryApp != currentApp )
|
2018-09-27 14:48:52 +00:00
|
|
|
{
|
2019-06-09 21:57:23 +00:00
|
|
|
m_hk_sections.emplace_back( HOTKEY_SECTION() );
|
2019-06-14 10:55:54 +00:00
|
|
|
currentApp = entryApp;
|
2019-06-09 21:57:23 +00:00
|
|
|
currentSection = &m_hk_sections.back();
|
2019-06-14 10:55:54 +00:00
|
|
|
currentSection->m_SectionName = GetSectionName( entryAction );
|
2021-05-11 22:15:01 +00:00
|
|
|
|
|
|
|
if( aIncludeReadOnlyCmds && currentApp == "common" )
|
|
|
|
{
|
|
|
|
for( TOOL_ACTION* command : g_standardPlatformCommands )
|
|
|
|
currentSection->m_HotKeys.emplace_back( HOTKEY( command ) );
|
|
|
|
}
|
2018-09-27 14:48:52 +00:00
|
|
|
}
|
2019-06-09 21:57:23 +00:00
|
|
|
|
2019-06-12 14:39:47 +00:00
|
|
|
currentSection->m_HotKeys.emplace_back( HOTKEY( entry.second ) );
|
2018-09-27 14:48:52 +00:00
|
|
|
}
|
2019-06-12 14:39:47 +00:00
|
|
|
|
2021-05-11 22:15:01 +00:00
|
|
|
if( aIncludeReadOnlyCmds )
|
2019-06-14 14:20:25 +00:00
|
|
|
{
|
|
|
|
m_hk_sections.emplace_back( HOTKEY_SECTION() );
|
|
|
|
currentSection = &m_hk_sections.back();
|
|
|
|
currentSection->m_SectionName = _( "Gestures" );
|
2019-06-12 14:39:47 +00:00
|
|
|
|
2019-06-14 14:20:25 +00:00
|
|
|
for( TOOL_ACTION* gesture : g_gesturePseudoActions )
|
|
|
|
currentSection->m_HotKeys.emplace_back( HOTKEY( gesture ) );
|
|
|
|
}
|
2019-06-09 21:57:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 14:48:52 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
std::vector<HOTKEY_SECTION>& HOTKEY_STORE::GetSections()
|
|
|
|
{
|
|
|
|
return m_hk_sections;
|
2018-09-27 14:48:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-26 14:26:26 +00:00
|
|
|
void HOTKEY_STORE::SaveAllHotkeys()
|
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY_SECTION& section : m_hk_sections )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY& hotkey : section.m_HotKeys )
|
|
|
|
{
|
|
|
|
for( TOOL_ACTION* action : hotkey.m_Actions )
|
|
|
|
action->SetHotKey( hotkey.m_EditKeycode );
|
|
|
|
}
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HOTKEY_STORE::ResetAllHotkeysToDefault()
|
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY_SECTION& section : m_hk_sections )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY& hotkey : section.m_HotKeys )
|
|
|
|
hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetDefaultHotKey();
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HOTKEY_STORE::ResetAllHotkeysToOriginal()
|
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY_SECTION& section : m_hk_sections )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-14 10:55:54 +00:00
|
|
|
for( HOTKEY& hotkey : section.m_HotKeys )
|
|
|
|
hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetHotKey();
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
bool HOTKEY_STORE::CheckKeyConflicts( TOOL_ACTION* aAction, long aKey, HOTKEY** aConflict )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2019-06-09 21:57:23 +00:00
|
|
|
wxString sectionName = GetSectionName( aAction );
|
2018-09-26 14:26:26 +00:00
|
|
|
|
2020-11-30 03:15:28 +00:00
|
|
|
// Create a fake "TOOL_ACTION" so we can get the section name for "Common" through the API.
|
|
|
|
// Simply declaring a wxString with the value "Common" works, but the goal is to futureproof
|
|
|
|
// the code here as much as possible.
|
2021-03-08 02:59:07 +00:00
|
|
|
TOOL_ACTION commonAction( "common.Control.Fake", AS_GLOBAL, 0, "", "", "" );
|
2020-11-30 03:15:28 +00:00
|
|
|
wxString commonName = GetSectionName( &commonAction );
|
|
|
|
|
|
|
|
for( HOTKEY_SECTION& section : m_hk_sections )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2020-11-30 03:15:28 +00:00
|
|
|
// We can have the same hotkey in multiple sections (i.e. Kicad programs), but if a hotkey
|
|
|
|
// is in "Common" it can't be in any other section and vice versa.
|
|
|
|
|
|
|
|
if( !( section.m_SectionName == sectionName || section.m_SectionName == commonName ) )
|
2018-09-26 14:26:26 +00:00
|
|
|
continue;
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2020-11-30 03:15:28 +00:00
|
|
|
for( HOTKEY& hotkey : section.m_HotKeys )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2020-11-30 03:15:28 +00:00
|
|
|
if( hotkey.m_Actions[0] == aAction )
|
2019-06-09 21:57:23 +00:00
|
|
|
continue;
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
if( hotkey.m_EditKeycode == aKey )
|
2018-09-26 14:26:26 +00:00
|
|
|
{
|
2021-05-30 18:12:03 +00:00
|
|
|
// We can use the same key for a different action if both actions are contextual and
|
|
|
|
// for different tools.
|
|
|
|
if( hotkey.m_Actions[0]->GetScope() == AS_CONTEXT &&
|
|
|
|
aAction->GetScope() == AS_CONTEXT &&
|
|
|
|
hotkey.m_Actions[0]->GetToolName() != aAction->GetToolName() )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
*aConflict = &hotkey;
|
|
|
|
return true;
|
2018-09-26 14:26:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-16 16:29:50 +00:00
|
|
|
|
2019-06-09 21:57:23 +00:00
|
|
|
return false;
|
2021-03-08 02:59:07 +00:00
|
|
|
}
|