You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							249 lines
						
					
					
						
							8.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							249 lines
						
					
					
						
							8.0 KiB
						
					
					
				
								/*
							 | 
						|
								 * This program source code file is part of KICAD, a free EDA CAD application.
							 | 
						|
								 *
							 | 
						|
								 * Copyright (C) 1992-2019 Kicad Developers, see AUTHORS.txt for contributors.
							 | 
						|
								 *
							 | 
						|
								 * 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>
							 | 
						|
								#include <eda_base_frame.h>
							 | 
						|
								#include <tool/tool_manager.h>
							 | 
						|
								#include <tool/action_manager.h>
							 | 
						|
								#include <tool/tool_event.h>
							 | 
						|
								#include <tool/tool_action.h>
							 | 
						|
								#include <advanced_config.h>
							 | 
						|
								
							 | 
						|
								class PSEUDO_ACTION : public TOOL_ACTION
							 | 
						|
								{
							 | 
						|
								public:
							 | 
						|
								    PSEUDO_ACTION( const wxString& aLabel, int aHotKey )
							 | 
						|
								    {
							 | 
						|
								        m_friendlyName = aLabel;
							 | 
						|
								        m_hotKey = aHotKey;
							 | 
						|
								    }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								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 ),
							 | 
						|
								    new PSEUDO_ACTION( _( "Highlight Net" ), MD_CTRL + PSEUDO_WXK_CLICK ),
							 | 
						|
								    new PSEUDO_ACTION( _( "Remove from Selection" ), MD_SHIFT + MD_CTRL + PSEUDO_WXK_CLICK ),
							 | 
						|
								    new PSEUDO_ACTION( _( "Ignore Grid Snaps" ), MD_CTRL ),
							 | 
						|
								    new PSEUDO_ACTION( _( "Ignore Other Snaps" ), MD_SHIFT ),
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								static PSEUDO_ACTION* g_standardPlatformCommands[] = {
							 | 
						|
								#ifndef __WINDOWS__
							 | 
						|
								    new PSEUDO_ACTION( _( "Close" ), MD_CTRL + 'W' ),
							 | 
						|
								#endif
							 | 
						|
								    new PSEUDO_ACTION( _( "Quit" ), MD_CTRL + 'Q' )
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								wxString HOTKEY_STORE::GetAppName( TOOL_ACTION* aAction )
							 | 
						|
								{
							 | 
						|
								    wxString name( aAction->GetName() );
							 | 
						|
								    return name.BeforeFirst( '.' );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								wxString HOTKEY_STORE::GetSectionName( TOOL_ACTION* aAction )
							 | 
						|
								{
							 | 
						|
								    std::map<wxString, wxString> s_AppNames = {
							 | 
						|
								            { wxT( "common" ),   _( "Common" ) },
							 | 
						|
								            { wxT( "kicad" ),    _( "Project Manager" ) },
							 | 
						|
								            { wxT( "eeschema" ), _( "Schematic Editor" ) },
							 | 
						|
								            { wxT( "pcbnew" ),   _( "PCB Editor" ) },
							 | 
						|
								            { wxT( "plEditor" ), _( "Drawing Sheet Editor" ), },
							 | 
						|
								            { wxT( "3DViewer" ), _( "3D Viewer" ) },
							 | 
						|
								            { wxT( "gerbview" ), _( "Gerber Viewer" ) }
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    wxString appName = GetAppName( aAction );
							 | 
						|
								
							 | 
						|
								    if( s_AppNames.count( appName ) )
							 | 
						|
								        return s_AppNames[ appName ];
							 | 
						|
								    else
							 | 
						|
								        return appName;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								HOTKEY_STORE::HOTKEY_STORE()
							 | 
						|
								{
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void HOTKEY_STORE::Init( std::vector<TOOL_ACTION*> aActionsList, bool aIncludeReadOnlyCmds )
							 | 
						|
								{
							 | 
						|
								    std::map<std::string, HOTKEY> masterMap;
							 | 
						|
								
							 | 
						|
								    for( TOOL_ACTION* action : aActionsList )
							 | 
						|
								    {
							 | 
						|
								        // Internal actions probably shouldn't be allowed hotkeys
							 | 
						|
								        if( action->GetFriendlyName().IsEmpty() )
							 | 
						|
								            continue;
							 | 
						|
								
							 | 
						|
								        if( !ADVANCED_CFG::GetCfg().m_ExtraZoneDisplayModes )
							 | 
						|
								        {
							 | 
						|
								            if( action->GetName() == "pcbnew.Control.zoneDisplayOutlines"
							 | 
						|
								                    || action->GetName() == "pcbnew.Control.zoneDisplayTesselation" )
							 | 
						|
								            {
							 | 
						|
								                continue;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        HOTKEY& hotkey = masterMap[ action->GetName() ];
							 | 
						|
								        hotkey.m_Actions.push_back( action );
							 | 
						|
								
							 | 
						|
								        if( !hotkey.m_EditKeycode )
							 | 
						|
								        {
							 | 
						|
								            hotkey.m_EditKeycode = action->GetHotKey();
							 | 
						|
								            hotkey.m_EditKeycodeAlt = action->GetHotKeyAlt();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    wxString        currentApp;
							 | 
						|
								    HOTKEY_SECTION* currentSection = nullptr;
							 | 
						|
								
							 | 
						|
								    // If a previous list was built, ensure this previous list is cleared:
							 | 
						|
								    m_hk_sections.clear();
							 | 
						|
								
							 | 
						|
								    for( const std::pair<const std::string, HOTKEY>& entry : masterMap )
							 | 
						|
								    {
							 | 
						|
								        TOOL_ACTION* entryAction = entry.second.m_Actions[ 0 ];
							 | 
						|
								        wxString     entryApp = GetAppName( entryAction );
							 | 
						|
								
							 | 
						|
								        if( !currentSection || entryApp != currentApp )
							 | 
						|
								        {
							 | 
						|
								            m_hk_sections.emplace_back( HOTKEY_SECTION() );
							 | 
						|
								            currentApp = entryApp;
							 | 
						|
								            currentSection = &m_hk_sections.back();
							 | 
						|
								            currentSection->m_SectionName = GetSectionName( entryAction );
							 | 
						|
								
							 | 
						|
								            if( aIncludeReadOnlyCmds && currentApp == "common" )
							 | 
						|
								            {
							 | 
						|
								                for( TOOL_ACTION* command : g_standardPlatformCommands )
							 | 
						|
								                    currentSection->m_HotKeys.emplace_back( HOTKEY( command ) );
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        currentSection->m_HotKeys.emplace_back( HOTKEY( entry.second ) );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if( aIncludeReadOnlyCmds )
							 | 
						|
								    {
							 | 
						|
								        m_hk_sections.emplace_back( HOTKEY_SECTION() );
							 | 
						|
								        currentSection = &m_hk_sections.back();
							 | 
						|
								        currentSection->m_SectionName = _( "Gestures" );
							 | 
						|
								
							 | 
						|
								        for( TOOL_ACTION* gesture : g_gesturePseudoActions )
							 | 
						|
								            currentSection->m_HotKeys.emplace_back( HOTKEY( gesture ) );
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								std::vector<HOTKEY_SECTION>& HOTKEY_STORE::GetSections()
							 | 
						|
								{
							 | 
						|
								    return m_hk_sections;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void HOTKEY_STORE::SaveAllHotkeys()
							 | 
						|
								{
							 | 
						|
								    for( HOTKEY_SECTION& section : m_hk_sections )
							 | 
						|
								    {
							 | 
						|
								        for( HOTKEY& hotkey : section.m_HotKeys )
							 | 
						|
								        {
							 | 
						|
								            for( TOOL_ACTION* action : hotkey.m_Actions )
							 | 
						|
								                action->SetHotKey( hotkey.m_EditKeycode, hotkey.m_EditKeycodeAlt );
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								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_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetDefaultHotKeyAlt();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								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_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetHotKeyAlt();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								bool HOTKEY_STORE::CheckKeyConflicts( TOOL_ACTION* aAction, long aKey, HOTKEY** aConflict )
							 | 
						|
								{
							 | 
						|
								    wxString sectionName = GetSectionName( aAction );
							 | 
						|
								
							 | 
						|
								    // 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.
							 | 
						|
								    TOOL_ACTION commonAction( TOOL_ACTION_ARGS().Name( "common.Control.Fake" ).Scope( AS_GLOBAL ) );
							 | 
						|
								    wxString    commonName = GetSectionName( &commonAction );
							 | 
						|
								
							 | 
						|
								    for( HOTKEY_SECTION& section : m_hk_sections )
							 | 
						|
								    {
							 | 
						|
								        // 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 ) )
							 | 
						|
								            continue;
							 | 
						|
								
							 | 
						|
								        for( HOTKEY& hotkey : section.m_HotKeys )
							 | 
						|
								        {
							 | 
						|
								            if( hotkey.m_Actions[0] == aAction )
							 | 
						|
								                continue;
							 | 
						|
								
							 | 
						|
								            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.
							 | 
						|
								                if( hotkey.m_Actions[0]->GetScope() == AS_CONTEXT &&
							 | 
						|
								                    aAction->GetScope() == AS_CONTEXT &&
							 | 
						|
								                    hotkey.m_Actions[0]->GetToolName() != aAction->GetToolName() )
							 | 
						|
								                {
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                *aConflict = &hotkey;
							 | 
						|
								                return true;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return false;
							 | 
						|
								}
							 |