KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_hotkeys_editor.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 <advanced_config.h>
21#include <gestfich.h>
22#include <hotkeys_basic.h>
23#include <kiway_player.h>
26#include <tool/tool_manager.h>
28#include <widgets/ui_common.h>
29#include <wx/filedlg.h>
30#include <wx/sizer.h>
31#include <wx/srchctrl.h>
32#include <wx/txtstrm.h>
33#include <wx/wfstream.h>
34
35
44static wxSearchCtrl* CreateTextFilterBox( wxWindow* aParent, const wxString& aDescriptiveText )
45{
46 wxSearchCtrl* search_widget = new wxSearchCtrl( aParent, wxID_ANY );
47
48 search_widget->ShowSearchButton( false );
49 search_widget->ShowCancelButton( true );
50
51 search_widget->SetDescriptiveText( aDescriptiveText );
52
53#ifdef __WXGTK__
54 // wxSearchCtrl vertical height is not calculated correctly on some GTK setups
55 // See https://gitlab.com/kicad/code/kicad/-/issues/9019
56 search_widget->SetMinSize( wxSize( -1, aParent->GetTextExtent( wxT( "qb" ) ).y + 10 ) );
57#endif
58
59 return search_widget;
60}
61
62
63PANEL_HOTKEYS_EDITOR::PANEL_HOTKEYS_EDITOR( EDA_BASE_FRAME* aFrame, wxWindow* aWindow, bool readOnly ) :
64 RESETTABLE_PANEL( aWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize ),
65 m_frame( aFrame ),
67{
68 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
69 wxBoxSizer* bMargins = new wxBoxSizer( wxVERTICAL );
70
71 m_filterSearch = CreateTextFilterBox( this, _( "Type filter text" ) );
72 bMargins->Add( m_filterSearch, 0, wxEXPAND | wxTOP | wxRIGHT, 5 );
73
74 m_hotkeyListCtrl = new WIDGET_HOTKEY_LIST( this, m_hotkeyStore, readOnly );
75 bMargins->Add( m_hotkeyListCtrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 );
76
77 m_bottomSizer = new wxBoxSizer( wxHORIZONTAL );
79
80 bMargins->Add( m_bottomSizer, 0, wxEXPAND, 5 );
81 mainSizer->Add( bMargins, 1, wxEXPAND, 0 );
82
83#ifdef __WXGTK__
84
85 // It appears that this may have been fixed in wxWidgets 3.2.3.
86#if wxVERSION_NUMBER < 3203
87
88 // Work around a bug that clips the text vertically in the wxSearchCtrl on GTK
89 m_filterSearch->SetMinSize(
90 wxSize( m_filterSearch->GetSize().x, int( m_filterSearch->GetSize().y * 1.6 ) ) );
91#endif
92
93#endif
94
95 SetSizer( mainSizer );
96 Layout();
97 mainSizer->Fit( this );
98
99 // Connect Events
100 m_filterSearch->Bind( wxEVT_COMMAND_TEXT_UPDATED, &PANEL_HOTKEYS_EDITOR::OnFilterSearch, this );
101}
102
103
105{
106 m_filterSearch->Unbind( wxEVT_COMMAND_TEXT_UPDATED, &PANEL_HOTKEYS_EDITOR::OnFilterSearch,
107 this );
108}
109
110
112{
113 m_hotkeyListCtrl->ResetAllHotkeys( true );
114}
115
116
118{
119 BUTTON_ROW_PANEL::BTN_DEF_LIST l_btn_defs = {
120 {
121 wxID_RESET,
122 _( "Undo All Changes" ),
123 _( "Undo all changes made so far in this dialog" ),
124 [this]( wxCommandEvent& )
125 {
126 m_hotkeyListCtrl->ResetAllHotkeys( false );
127 }
128 },
129 {
130 wxID_ANY,
131 _( "Import Hotkeys..." ),
132 _( "Import hotkey definitions from an external file, replacing the current values" ),
133 [this]( wxCommandEvent& )
134 {
136 }
137 }
138 };
139
140 if( ADVANCED_CFG::GetCfg().m_HotkeysDumper )
141 {
142 // Add hotkeys dumper (does not need translation, it's a dev tool only)
143 l_btn_defs.push_back( {
144 wxID_ANY, wxT( "Dump Hotkeys" ), wxEmptyString,
145 [this]( wxCommandEvent& )
146 {
147 dumpHotkeys();
148 }
149 } );
150 }
151
152 const BUTTON_ROW_PANEL::BTN_DEF_LIST r_btn_defs = {
153 };
154
155 auto btnPanel = std::make_unique<BUTTON_ROW_PANEL>( this, l_btn_defs, r_btn_defs );
156
157 aSizer->Add( btnPanel.release(), 1, wxEXPAND | wxALL, KIUI::GetStdMargin() );
158}
159
160
162{
163 m_hotkeyStore.Init( m_actions, true );
164
165 if( !m_hotkeyListCtrl->TransferDataToControl() )
166 return false;
167
168 // we may have loaded a query from the saved dialog state, so make sure to run it
169 if( !m_filterSearch->IsEmpty() )
170 m_hotkeyListCtrl->ApplyFilterString( m_filterSearch->GetValue() );
171
172 return true;
173}
174
175
177{
178 if( !m_hotkeyListCtrl->TransferDataFromControl() )
179 return false;
180
182
183 return true;
184}
185
186
187void PANEL_HOTKEYS_EDITOR::OnFilterSearch( wxCommandEvent& aEvent )
188{
189 const auto searchStr = aEvent.GetString();
190 m_hotkeyListCtrl->ApplyFilterString( searchStr );
191}
192
193
195{
196 wxString filename = wxFileSelector( _( "Import Hotkeys File:" ), m_frame->GetMruPath(),
197 wxEmptyString, FILEEXT::HotkeyFileExtension,
198 FILEEXT::HotkeyFileWildcard(), wxFD_OPEN,
199 wxGetTopLevelParent( this ) );
200
201 if( filename.IsEmpty() )
202 return;
203
204 std::map<std::string, std::pair<int, int>> importedHotKeys;
205 ReadHotKeyConfig( filename, importedHotKeys );
206 m_frame->SetMruPath( wxFileName( filename ).GetPath() );
207
208 // Overlay the imported hotkeys onto the hotkey store
209 for( HOTKEY_SECTION& section: m_hotkeyStore.GetSections() )
210 {
211 for( HOTKEY& hotkey: section.m_HotKeys )
212 {
213 if( importedHotKeys.count( hotkey.m_Actions[ 0 ]->GetName() ) )
214 {
215 hotkey.m_EditKeycode = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ].first;
216 hotkey.m_EditKeycodeAlt = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ].second;
217 }
218 }
219 }
220
221 m_hotkeyListCtrl->TransferDataToControl();
222}
223
224
226{
227 wxString filename = wxFileSelector( wxT( "Hotkeys File" ), m_frame->GetMruPath(),
228 wxEmptyString, FILEEXT::TextFileExtension,
230 wxFD_SAVE, wxGetTopLevelParent( this ) );
231
232 if( filename.IsEmpty() )
233 return;
234
235 wxFileName fn( filename );
236
237 wxFFileOutputStream fileStream( fn.GetFullPath(), "w" );
238 wxTextOutputStream stream( fileStream );
239
240 if( !fn.IsDirWritable() || ( fn.Exists() && !fn.IsFileWritable() ) )
241 return;
242
243 for( HOTKEY_SECTION& section : m_hotkeyStore.GetSections() )
244 {
245 stream << wxT( "=== " ) << section.m_SectionName << endl << endl;
246
247 stream << wxT( "[width=\"100%\",options=\"header\",cols=\"20%,15%,65%\"]" ) << endl;
248 stream << wxT( "|===" ) << endl;
249 stream << _( "| Action | Default Hotkey | Description" ) << endl;
250
251 for( HOTKEY& hk : section.m_HotKeys )
252 {
253 stream << wxT( "| " ) << hk.m_Actions[0]->GetFriendlyName() << endl;
254
255 if( hk.m_EditKeycode > 0 )
256 {
257 stream << wxT( " | kbd:[" ) << KeyNameFromKeyCode( hk.m_EditKeycode ) << ']'
258 << endl;
259 }
260 else
261 {
262 stream << wxT( " |" ) << endl;
263 }
264
265 stream << wxT( " | " ) << hk.m_Actions[0]->GetDescription() << endl;
266 }
267
268 stream << wxT( "|===" ) << endl << endl;
269 }
270
271 stream.Flush();
272 fileStream.Close();
273}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
std::vector< BTN_DEF > BTN_DEF_LIST
A list of BTN_DEFs, used to group buttons into the left/right groups.
The base frame for deriving all KiCad main window classes.
PANEL_HOTKEYS_EDITOR(EDA_BASE_FRAME *aFrame, wxWindow *aWindow, bool readOnly)
void OnFilterSearch(wxCommandEvent &aEvent)
Handle a change in the hotkey filter text.
void ResetPanel() override
Reset the contents of this panel.
std::vector< TOOL_ACTION * > m_actions
void installButtons(wxSizer *aSizer)
Install the button panel (global reset/default, import/export)
WIDGET_HOTKEY_LIST * m_hotkeyListCtrl
bool TransferDataToWindow() override
void ImportHotKeys()
Put up a dialog allowing the user to select a hotkeys file and then overlays those hotkeys onto the c...
void dumpHotkeys()
Dump all actions and their hotkeys to a text file for inclusion in documentation.
bool TransferDataFromWindow() override
RESETTABLE_PANEL(wxWindow *aParent, wxWindowID aId=wxID_ANY, const wxPoint &aPos=wxDefaultPosition, const wxSize &aSize=wxSize(-1,-1), long aStyle=wxTAB_TRAVERSAL, const wxString &aName=wxEmptyString)
#define _(s)
static const std::string TextFileExtension
static const std::string HotkeyFileExtension
static wxString HotkeyFileWildcard()
static wxString TextFileWildcard()
void ReadHotKeyConfig(const wxString &aFileName, std::map< std::string, std::pair< int, int > > &aHotKeys)
Read a hotkey config file into a map.
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
int WriteHotKeyConfig(const std::vector< TOOL_ACTION * > &aActions)
Update the hotkeys config file with the hotkeys from the given actions map.
KICOMMON_API int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition ui_common.cpp:49
static wxSearchCtrl * CreateTextFilterBox(wxWindow *aParent, const wxString &aDescriptiveText)
Helper function to add a filter box to a panel, with some sensible defaults for that purpose.
int m_EditKeycodeAlt
int m_EditKeycode
std::vector< TOOL_ACTION * > m_Actions
Functions to provide common constants and other functions to assist in making a consistent UI.
Definition of file extensions used in Kicad.