KiCad PCB EDA Suite
Loading...
Searching...
No Matches
hotkey_store.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <hotkey_store.h>
21#include <eda_base_frame.h>
22#include <tool/tool_manager.h>
23#include <tool/action_manager.h>
24#include <tool/tool_event.h>
25#include <tool/tool_action.h>
26#include <advanced_config.h>
27
29{
30public:
31 PSEUDO_ACTION( const wxString& aLabel, int aHotKey, int aHotKeyAlt = 0 ) :
32 TOOL_ACTION( aHotKey, aHotKeyAlt )
33 {
34 m_friendlyName = aLabel;
35 }
36};
37
39 new PSEUDO_ACTION( _( "Accept Autocomplete" ), WXK_RETURN, WXK_NUMPAD_ENTER ),
40 new PSEUDO_ACTION( _( "Cancel Autocomplete" ), WXK_ESCAPE ),
41 new PSEUDO_ACTION( _( "Toggle Checkbox" ), WXK_SPACE ),
42 new PSEUDO_ACTION( _( "Pan Left/Right" ), MD_CTRL + PSEUDO_WXK_WHEEL ),
43 new PSEUDO_ACTION( _( "Pan Up/Down" ), MD_SHIFT + PSEUDO_WXK_WHEEL ),
44 new PSEUDO_ACTION( _( "Finish Drawing" ), PSEUDO_WXK_DBLCLICK ),
45 new PSEUDO_ACTION( _( "Add to Selection" ), MD_SHIFT + PSEUDO_WXK_CLICK ),
46 new PSEUDO_ACTION( _( "Highlight Net" ), MD_CTRL + PSEUDO_WXK_CLICK ),
47 new PSEUDO_ACTION( _( "Remove from Selection" ), MD_CTRL + MD_SHIFT + PSEUDO_WXK_CLICK ),
48 new PSEUDO_ACTION( _( "Ignore Grid Snaps" ), MD_CTRL ),
49 new PSEUDO_ACTION( _( "Ignore Other Snaps" ), MD_SHIFT ),
50};
51
53#ifndef __WINDOWS__
54 new PSEUDO_ACTION( _( "Close" ), MD_CTRL + 'W' ),
55#endif
56 new PSEUDO_ACTION( _( "Quit" ), MD_CTRL + 'Q' )
57};
58
59
61{
62 wxString name( aAction->GetName() );
63 return name.BeforeFirst( '.' );
64}
65
66
68{
69 std::map<wxString, wxString> s_AppNames = {
70 { wxT( "common" ), _( "Common" ) },
71 { wxT( "kicad" ), _( "Project Manager" ) },
72 { wxT( "eeschema" ), _( "Schematic Editor" ) },
73 { wxT( "pcbnew" ), _( "PCB Editor" ) },
74 { wxT( "plEditor" ), _( "Drawing Sheet Editor" ), },
75 { wxT( "3DViewer" ), _( "3D Viewer" ) },
76 { wxT( "gerbview" ), _( "Gerber Viewer" ) }
77 };
78
79 wxString appName = GetAppName( aAction );
80
81 if( s_AppNames.count( appName ) )
82 return s_AppNames[ appName ];
83 else
84 return appName;
85}
86
87
91
92
93void HOTKEY_STORE::Init( std::vector<TOOL_ACTION*> aActionsList, bool aIncludeReadOnlyCmds )
94{
95 std::map<std::string, HOTKEY> masterMap;
96
97 for( TOOL_ACTION* action : aActionsList )
98 {
99 // Internal actions probably shouldn't be allowed hotkeys
100 if( action->GetFriendlyName().IsEmpty() )
101 continue;
102
103 if( !ADVANCED_CFG::GetCfg().m_ExtraZoneDisplayModes )
104 {
105 if( action->GetName() == "pcbnew.Control.zoneDisplayOutlines"
106 || action->GetName() == "pcbnew.Control.zoneDisplayTesselation" )
107 {
108 continue;
109 }
110 }
111
112 HOTKEY& hotkey = masterMap[ action->GetName() ];
113 hotkey.m_Actions.push_back( action );
114
115 if( !hotkey.m_EditKeycode )
116 {
117 hotkey.m_EditKeycode = action->GetHotKey();
118 hotkey.m_EditKeycodeAlt = action->GetHotKeyAlt();
119 }
120 }
121
122 wxString currentApp;
123 HOTKEY_SECTION* currentSection = nullptr;
124
125 // If a previous list was built, ensure this previous list is cleared:
126 m_hk_sections.clear();
127
128 for( const std::pair<const std::string, HOTKEY>& entry : masterMap )
129 {
130 TOOL_ACTION* entryAction = entry.second.m_Actions[ 0 ];
131 wxString entryApp = GetAppName( entryAction );
132
133 if( !currentSection || entryApp != currentApp )
134 {
135 m_hk_sections.emplace_back( HOTKEY_SECTION() );
136 currentApp = entryApp;
137 currentSection = &m_hk_sections.back();
138 currentSection->m_SectionName = GetSectionName( entryAction );
139
140 if( aIncludeReadOnlyCmds && currentApp == "common" )
141 {
143 currentSection->m_HotKeys.emplace_back( HOTKEY( command ) );
144 }
145 }
146
147 currentSection->m_HotKeys.emplace_back( HOTKEY( entry.second ) );
148 }
149
150 if( aIncludeReadOnlyCmds )
151 {
152 m_hk_sections.emplace_back( HOTKEY_SECTION() );
153 currentSection = &m_hk_sections.back();
154 currentSection->m_SectionName = _( "Gestures" );
155
156 for( TOOL_ACTION* gesture : g_gesturePseudoActions )
157 currentSection->m_HotKeys.emplace_back( HOTKEY( gesture ) );
158 }
159}
160
161
162std::vector<HOTKEY_SECTION>& HOTKEY_STORE::GetSections()
163{
164 return m_hk_sections;
165}
166
167
169{
170 for( HOTKEY_SECTION& section : m_hk_sections )
171 {
172 for( HOTKEY& hotkey : section.m_HotKeys )
173 {
174 for( TOOL_ACTION* action : hotkey.m_Actions )
175 action->SetHotKey( hotkey.m_EditKeycode, hotkey.m_EditKeycodeAlt );
176 }
177 }
178}
179
180
182{
183 for( HOTKEY_SECTION& section : m_hk_sections )
184 {
185 for( HOTKEY& hotkey : section.m_HotKeys )
186 {
187 hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetDefaultHotKey();
188 hotkey.m_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetDefaultHotKeyAlt();
189 }
190 }
191}
192
193
195{
196 for( HOTKEY_SECTION& section : m_hk_sections )
197 {
198 for( HOTKEY& hotkey : section.m_HotKeys )
199 {
200 hotkey.m_EditKeycode = hotkey.m_Actions[ 0 ]->GetHotKey();
201 hotkey.m_EditKeycodeAlt = hotkey.m_Actions[ 0 ]->GetHotKeyAlt();
202 }
203 }
204}
205
206
207bool HOTKEY_STORE::CheckKeyConflicts( TOOL_ACTION* aAction, long aKey, HOTKEY** aConflict )
208{
209 wxString sectionName = GetSectionName( aAction );
210
211 // Create a fake "TOOL_ACTION" so we can get the section name for "Common" through the API.
212 // Simply declaring a wxString with the value "Common" works, but the goal is to futureproof
213 // the code here as much as possible.
214 TOOL_ACTION commonAction( TOOL_ACTION_ARGS().Name( "common.Control.Fake" ).Scope( AS_GLOBAL ) );
215 wxString commonName = GetSectionName( &commonAction );
216
217 for( HOTKEY_SECTION& section : m_hk_sections )
218 {
219 // We can have the same hotkey in multiple sections (i.e. Kicad programs), but if a hotkey
220 // is in "Common" it can't be in any other section and vice versa.
221
222 if( !( section.m_SectionName == sectionName || section.m_SectionName == commonName ) )
223 continue;
224
225 for( HOTKEY& hotkey : section.m_HotKeys )
226 {
227 if( hotkey.m_Actions[0] == aAction )
228 continue;
229
230 if( hotkey.m_EditKeycode == aKey || hotkey.m_EditKeycodeAlt == aKey )
231 {
232 // We can use the same key for a different action if both actions are contextual and
233 // for different tools.
234 if( hotkey.m_Actions[0]->GetScope() == AS_CONTEXT &&
235 aAction->GetScope() == AS_CONTEXT &&
236 hotkey.m_Actions[0]->GetToolName() != aAction->GetToolName() )
237 {
238 continue;
239 }
240
241 *aConflict = &hotkey;
242 return true;
243 }
244 }
245 }
246
247 return false;
248}
const char * name
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool CheckKeyConflicts(TOOL_ACTION *aAction, long aKey, HOTKEY **aConflict)
Check whether the given key conflicts with anything in this store.
void ResetAllHotkeysToOriginal()
Resets every hotkey to the original values.
void ResetAllHotkeysToDefault()
Reset every hotkey in the store to the default values.
HOTKEY_STORE()
Construct a HOTKEY_STORE from a list of hotkey sections.
void Init(std::vector< TOOL_ACTION * > aActionsList, bool aIncludeReadOnlyCmds)
std::vector< HOTKEY_SECTION > & GetSections()
Get the list of sections managed by this store.
std::vector< HOTKEY_SECTION > m_hk_sections
void SaveAllHotkeys()
Persist all changes to hotkeys in the store to the underlying data structures.
static wxString GetSectionName(TOOL_ACTION *aAction)
static wxString GetAppName(TOOL_ACTION *aAction)
PSEUDO_ACTION(const wxString &aLabel, int aHotKey, int aHotKeyAlt=0)
Build up the properties of a TOOL_ACTION in an incremental manner that is static-construction safe.
Represent a single user action.
TOOL_ACTION(const TOOL_ACTION_ARGS &aArgs)
void SetHotKey(int aKeycode, int aKeycodeAlt=0)
TOOL_ACTION_SCOPE GetScope() const
std::string GetToolName() const
Return name of the tool associated with the action.
wxString m_friendlyName
User-friendly name.
const std::string & GetName() const
Return name of the action.
#define _(s)
Base window classes and related definitions.
static PSEUDO_ACTION * g_gesturePseudoActions[]
static PSEUDO_ACTION * g_standardPlatformCommands[]
#define PSEUDO_WXK_WHEEL
#define PSEUDO_WXK_DBLCLICK
#define PSEUDO_WXK_CLICK
std::vector< HOTKEY > m_HotKeys
wxString m_SectionName
int m_EditKeycodeAlt
int m_EditKeycode
std::vector< TOOL_ACTION * > m_Actions
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition tool_action.h:45
@ AS_CONTEXT
Action belongs to a particular tool (i.e. a part of a pop-up menu)
Definition tool_action.h:43
@ MD_CTRL
Definition tool_event.h:140
@ MD_SHIFT
Definition tool_event.h:139