KiCad PCB EDA Suite
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 (C) 1992-2021 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, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <advanced_config.h>
25 #include <gestfich.h>
26 #include <hotkeys_basic.h>
27 #include <kiway_player.h>
28 #include <locale_io.h>
29 #include <panel_hotkeys_editor.h>
31 #include <tool/tool_manager.h>
33 #include <widgets/ui_common.h>
34 #include <wx/filedlg.h>
35 #include <wx/panel.h>
36 #include <wx/sizer.h>
37 #include <wx/srchctrl.h>
38 #include <wx/tokenzr.h>
39 #include <wx/txtstrm.h>
40 #include <wx/wfstream.h>
41 
42 static const wxSize default_dialog_size { 500, 350 };
43 
52 static wxSearchCtrl* CreateTextFilterBox( wxWindow* aParent, const wxString& aDescriptiveText )
53 {
54  wxSearchCtrl* search_widget = new wxSearchCtrl( aParent, wxID_ANY );
55 
56  search_widget->ShowSearchButton( false );
57  search_widget->ShowCancelButton( true );
58 
59  search_widget->SetDescriptiveText( aDescriptiveText );
60 
61 #ifdef __WXGTK__
62  // wxSearchCtrl vertical height is not calculated correctly on some GTK setups
63  // See https://gitlab.com/kicad/code/kicad/-/issues/9019
64  search_widget->SetMinSize( wxSize( -1, aParent->GetTextExtent( wxT( "qb" ) ).y + 10 ) );
65 #endif
66 
67  return search_widget;
68 }
69 
70 
72  bool aReadOnly ) :
73  RESETTABLE_PANEL( aWindow, wxID_ANY, wxDefaultPosition, default_dialog_size ),
74  m_frame( aFrame ),
75  m_readOnly( aReadOnly ),
76  m_hotkeyStore()
77 {
78  const auto margin = KIUI::GetStdMargin();
79  wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
80 
81  const int side_margins = margin * 2;
82  wxBoxSizer* bMargins = new wxBoxSizer( wxVERTICAL );
83 
84  wxSearchCtrl* filterSearch = CreateTextFilterBox( this, _( "Type filter text" ) );
85  bMargins->Add( filterSearch, 0, wxALL | wxEXPAND, margin );
86 
88  bMargins->Add( m_hotkeyListCtrl, 1, wxALL | wxEXPAND, margin );
89 
90  if( !m_readOnly )
91  installButtons( bMargins );
92 
93  mainSizer->Add( bMargins, 1, wxEXPAND | wxRIGHT | wxLEFT, side_margins );
94 
95 #ifdef __WXGTK__
96  // Work around a bug that clips the text vertically in the wxSearchCtrl on GTK
97  filterSearch->SetMinSize( wxSize( filterSearch->GetSize().x,
98  int( filterSearch->GetSize().y * 1.6 ) ) );
99 #endif
100 
101  SetSizer( mainSizer );
102  Layout();
103 
104  // Connect Events
105  filterSearch->Bind( wxEVT_COMMAND_TEXT_UPDATED, &PANEL_HOTKEYS_EDITOR::OnFilterSearch, this );
106 }
107 
108 
110 {
111  m_toolManagers.push_back( aToolMgr );
112 }
113 
114 
116 {
118 }
119 
120 
122 {
123  BUTTON_ROW_PANEL::BTN_DEF_LIST l_btn_defs = {
124  {
125  wxID_RESET,
126  _( "Undo All Changes" ),
127  _( "Undo all changes made so far in this dialog" ),
128  [this]( wxCommandEvent& )
129  {
131  }
132  },
133  {
134  wxID_ANY,
135  _( "Import Hotkeys..." ),
136  _( "Import hotkey definitions from an external file, replacing the current values" ),
137  [this]( wxCommandEvent& )
138  {
139  ImportHotKeys();
140  }
141  }
142  };
143 
144 
145  if( ADVANCED_CFG::GetCfg().m_HotkeysDumper )
146  {
147  // Add hotkeys dumper (does not need translation, it's a dev tool only)
148  l_btn_defs.push_back( {
149  wxID_ANY, wxT( "Dump Hotkeys" ), wxEmptyString,
150  [this]( wxCommandEvent& )
151  {
152  dumpHotkeys();
153  }
154  } );
155  }
156 
157  const BUTTON_ROW_PANEL::BTN_DEF_LIST r_btn_defs = {
158  };
159 
160  auto btnPanel = std::make_unique<BUTTON_ROW_PANEL>( this, l_btn_defs, r_btn_defs );
161 
162  aSizer->Add( btnPanel.release(), 0, wxEXPAND | wxTOP, KIUI::GetStdMargin() );
163 }
164 
165 
167 {
170 }
171 
172 
174 {
176  return false;
177 
178  if( m_readOnly )
179  return true;
180 
181  // save the hotkeys
182  for( TOOL_MANAGER* toolMgr : m_toolManagers )
183  WriteHotKeyConfig( toolMgr->GetActions() );
184 
185  return true;
186 }
187 
188 
189 void PANEL_HOTKEYS_EDITOR::OnFilterSearch( wxCommandEvent& aEvent )
190 {
191  const auto searchStr = aEvent.GetString();
192  m_hotkeyListCtrl->ApplyFilterString( searchStr );
193 }
194 
195 
197 {
198  wxString filename = wxFileSelector( _( "Import Hotkeys File:" ), m_frame->GetMruPath(),
199  wxEmptyString, HotkeyFileExtension,
200  HotkeyFileWildcard(), wxFD_OPEN, this );
201 
202  if( filename.IsEmpty() )
203  return;
204 
205  std::map<std::string, int> importedHotKeys;
206  ReadHotKeyConfig( filename, importedHotKeys );
207  m_frame->SetMruPath( wxFileName( filename ).GetPath() );
208 
209  // Overlay the imported hotkeys onto the hotkey store
210  for( HOTKEY_SECTION& section: m_hotkeyStore.GetSections() )
211  {
212  for( HOTKEY& hotkey: section.m_HotKeys )
213  {
214  if( importedHotKeys.count( hotkey.m_Actions[ 0 ]->GetName() ) )
215  hotkey.m_EditKeycode = importedHotKeys[ hotkey.m_Actions[ 0 ]->GetName() ];
216  }
217  }
218 
220 }
221 
222 
224 {
225  wxString filename = wxFileSelector( wxT( "Hotkeys File" ), m_frame->GetMruPath(),
226  wxEmptyString, TextFileExtension, TextFileWildcard(),
227  wxFD_SAVE, this );
228 
229  if( filename.IsEmpty() )
230  return;
231 
232  wxFileName fn( filename );
233 
234  wxFFileOutputStream fileStream( fn.GetFullPath(), "w" );
235  wxTextOutputStream stream( fileStream );
236 
237  if( !fn.IsDirWritable() || ( fn.Exists() && !fn.IsFileWritable() ) )
238  return;
239 
240  for( HOTKEY_SECTION& section : m_hotkeyStore.GetSections() )
241  {
242  stream << wxT( "=== " ) << section.m_SectionName << endl << endl;
243 
244  stream << wxT( "[width=\"100%\",options=\"header\",cols=\"20%,15%,65%\"]" ) << endl;
245  stream << wxT( "|===" ) << endl;
246  stream << _( "| Action | Default Hotkey | Description" ) << endl;
247 
248  for( HOTKEY& hk : section.m_HotKeys )
249  {
250  stream << wxT( "| " ) << hk.m_Actions[0]->GetLabel() << endl;
251 
252  if( hk.m_EditKeycode > 0 )
253  {
254  stream << wxT( " | kbd:[" ) << KeyNameFromKeyCode( hk.m_EditKeycode ) << ']'
255  << endl;
256  }
257  else
258  {
259  stream << wxT( " |" ) << endl;
260  }
261 
262  stream << wxT( " | " ) << hk.m_Actions[0]->GetDescription( false ) << endl;
263  }
264 
265  stream << wxT( "|===" ) << endl << endl;
266  }
267 
268  stream.Flush();
269  fileStream.Close();
270 }
void OnFilterSearch(wxCommandEvent &aEvent)
Handle a change in the hotkey filter text.
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.
void SetMruPath(const wxString &aPath)
static const wxSize default_dialog_size
void ImportHotKeys()
Put up a dialog allowing the user to select a hotkeys file and then overlays those hotkeys onto the c...
void ResetPanel() override
Reset the contents of this panel.
bool TransferDataToControl()
Method TransferDataToControl Load the hotkey data from the store into the control.
void ReadHotKeyConfig(const wxString &aFileName, std::map< std::string, int > &aHotKeys)
Reads a hotkey config file into a map.
void AddHotKeys(TOOL_MANAGER *aToolMgr)
int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition: ui_common.cpp:38
std::vector< TOOL_MANAGER * > m_toolManagers
EDA_BASE_FRAME * m_frame
Master controller class:
Definition: tool_manager.h:54
wxString GetMruPath() const
void installButtons(wxSizer *aSizer)
Install the button panel (global reset/default, import/export)
Definition of file extensions used in Kicad.
Functions to provide common constants and other functions to assist in making a consistent UI.
wxString HotkeyFileWildcard()
#define _(s)
void ApplyFilterString(const wxString &aFilterStr)
Method ApplyFilterString Apply a filter string to the hotkey list, selecting which hotkeys to show.
void dumpHotkeys()
Dumps all actions and their hotkeys to a text file for inclusion in documentation.
const std::string TextFileExtension
bool TransferDataFromWindow() override
std::vector< TOOL_ACTION * > m_Actions
Definition: hotkey_store.h:36
bool TransferDataToWindow() override
std::vector< HOTKEY_SECTION > & GetSections()
Get the list of sections managed by this store.
const std::string HotkeyFileExtension
The base frame for deriving all KiCad main window classes.
std::vector< BTN_DEF > BTN_DEF_LIST
A list of BTN_DEFs, used to group buttons into the left/right groups.
wxString TextFileWildcard()
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void Init(std::vector< TOOL_MANAGER * > aToolManagerList, bool aIncludeReadOnlyCmds)
PANEL_HOTKEYS_EDITOR(EDA_BASE_FRAME *aFrame, wxWindow *aWindow, bool aReadOnly)
WIDGET_HOTKEY_LIST * m_hotkeyListCtrl
int m_EditKeycode
Definition: hotkey_store.h:37
A wxPanel that is designed to be reset in a standard manner.
int WriteHotKeyConfig(const std::map< std::string, TOOL_ACTION * > &aActionMap)
Update the hotkeys config file with the hotkeys from the given actions map.
void ResetAllHotkeys(bool aResetToDefault)
Set hotkeys in the control to default or original values.
bool TransferDataFromControl()
Method TransferDataFromControl Save the hotkey data from the control.