KiCad PCB EDA Suite
grid_text_button_helpers.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) 2018-2020 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 <wx/combo.h>
25 #include <wx/filedlg.h>
26 #include <wx/dirdlg.h>
27 
28 #include <bitmap_types.h>
29 #include <bitmaps.h>
30 #include <kiway.h>
31 #include <kiway_player.h>
32 #include <dialog_shim.h>
33 #include <common.h>
34 #include <env_paths.h>
35 
37 #include <eda_doc.h>
38 
39 
40 //-------- Renderer ---------------------------------------------------------------------
41 // None required; just render as normal text.
42 
43 
44 
45 //-------- Editor Base Class ------------------------------------------------------------
46 //
47 // Note: this implementation is an adaptation of wxGridCellChoiceEditor
48 
49 
51 {
52  return Combo()->GetValue();
53 }
54 
55 
56 void GRID_CELL_TEXT_BUTTON::SetSize( const wxRect& aRect )
57 {
58  wxRect rect( aRect );
59  rect.Inflate( -1 );
60 
61 #if defined( __WXMAC__ )
62  rect.Inflate( 3 ); // no FOCUS_RING, even on Mac
63 #endif
64 
65  Combo()->SetSize( rect, wxSIZE_ALLOW_MINUS_ONE );
66 }
67 
68 
69 void GRID_CELL_TEXT_BUTTON::StartingKey( wxKeyEvent& event )
70 {
71  // Note: this is a copy of wxGridCellTextEditor's StartingKey()
72 
73  // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
74  // longer an appropriate way to get the character into the text control.
75  // Do it ourselves instead. We know that if we get this far that we have
76  // a valid character, so not a whole lot of testing needs to be done.
77 
78  // wxComboCtrl inherits from wxTextEntry, so can staticly cast
79  wxTextEntry* textEntry = static_cast<wxTextEntry*>( Combo() );
80  int ch;
81 
82  bool isPrintable;
83 
84 #if wxUSE_UNICODE
85  ch = event.GetUnicodeKey();
86 
87  if( ch != WXK_NONE )
88  isPrintable = true;
89  else
90 #endif // wxUSE_UNICODE
91  {
92  ch = event.GetKeyCode();
93  isPrintable = ch >= WXK_SPACE && ch < WXK_START;
94  }
95 
96  switch( ch )
97  {
98  case WXK_DELETE:
99  // Delete the initial character when starting to edit with DELETE.
100  textEntry->Remove( 0, 1 );
101  break;
102 
103  case WXK_BACK:
104  // Delete the last character when starting to edit with BACKSPACE.
105  {
106  const long pos = textEntry->GetLastPosition();
107  textEntry->Remove( pos - 1, pos );
108  }
109  break;
110 
111  default:
112  if( isPrintable )
113  textEntry->WriteText( static_cast<wxChar>( ch ) );
114  break;
115  }
116 }
117 
118 
119 void GRID_CELL_TEXT_BUTTON::BeginEdit( int aRow, int aCol, wxGrid* aGrid )
120 {
121  auto evtHandler = static_cast< wxGridCellEditorEvtHandler* >( m_control->GetEventHandler() );
122 
123  // Don't immediately end if we get a kill focus event within BeginEdit
124  evtHandler->SetInSetFocus( true );
125 
126  m_value = aGrid->GetTable()->GetValue( aRow, aCol );
127 
128  Combo()->SetValue( m_value );
129  Combo()->SetFocus();
130 }
131 
132 
133 bool GRID_CELL_TEXT_BUTTON::EndEdit( int, int, const wxGrid*, const wxString&, wxString *aNewVal )
134 {
135  const wxString value = Combo()->GetValue();
136 
137  if( value == m_value )
138  return false;
139 
140  m_value = value;
141 
142  if( aNewVal )
143  *aNewVal = value;
144 
145  return true;
146 }
147 
148 
149 void GRID_CELL_TEXT_BUTTON::ApplyEdit( int aRow, int aCol, wxGrid* aGrid )
150 {
151  aGrid->GetTable()->SetValue( aRow, aCol, m_value );
152 }
153 
154 
156 {
157  Combo()->SetValue( m_value );
158 }
159 
160 
161 #if wxUSE_VALIDATORS
162 void GRID_CELL_TEXT_BUTTON::SetValidator( const wxValidator& validator )
163 {
164  m_validator.reset( static_cast< wxValidator* >( validator.Clone() ) );
165 }
166 #endif
167 
168 
169 class TEXT_BUTTON_SYMBOL_CHOOSER : public wxComboCtrl
170 {
171 public:
172  TEXT_BUTTON_SYMBOL_CHOOSER( wxWindow* aParent, DIALOG_SHIM* aParentDlg,
173  const wxString& aPreselect ) :
174  wxComboCtrl( aParent ),
175  m_dlg( aParentDlg ),
176  m_preselect( aPreselect )
177  {
178  SetButtonBitmaps( KiBitmap( small_library_xpm ) );
179  }
180 
181 protected:
182  void DoSetPopupControl( wxComboPopup* popup ) override
183  {
184  m_popup = nullptr;
185  }
186 
187  void OnButtonClick() override
188  {
189  // pick a footprint using the footprint picker.
190  wxString compid = GetValue();
191 
192  if( compid.IsEmpty() )
193  compid = m_preselect;
194 
196 
197  if( frame->ShowModal( &compid, m_dlg ) )
198  SetValue( compid );
199 
200  frame->Destroy();
201  }
202 
204  wxString m_preselect;
205 };
206 
207 
208 void GRID_CELL_SYMBOL_ID_EDITOR::Create( wxWindow* aParent, wxWindowID aId,
209  wxEvtHandler* aEventHandler )
210 {
211  m_control = new TEXT_BUTTON_SYMBOL_CHOOSER( aParent, m_dlg, m_preselect );
212 
213  wxGridCellEditor::Create( aParent, aId, aEventHandler );
214 }
215 
216 
217 class TEXT_BUTTON_FP_CHOOSER : public wxComboCtrl
218 {
219 public:
220  TEXT_BUTTON_FP_CHOOSER( wxWindow* aParent, DIALOG_SHIM* aParentDlg,
221  const wxString& aPreselect ) :
222  wxComboCtrl( aParent ),
223  m_dlg( aParentDlg ),
224  m_preselect( aPreselect )
225  {
226  SetButtonBitmaps( KiBitmap( small_library_xpm ) );
227  }
228 
229 protected:
230  void DoSetPopupControl( wxComboPopup* popup ) override
231  {
232  m_popup = nullptr;
233  }
234 
235  void OnButtonClick() override
236  {
237  // pick a footprint using the footprint picker.
238  wxString fpid = GetValue();
239 
240  if( fpid.IsEmpty() )
241  fpid = m_preselect;
242 
244 
245  if( frame->ShowModal( &fpid, m_dlg ) )
246  SetValue( fpid );
247 
248  frame->Destroy();
249  }
250 
252  wxString m_preselect;
253 };
254 
255 
256 void GRID_CELL_FOOTPRINT_ID_EDITOR::Create( wxWindow* aParent, wxWindowID aId,
257  wxEvtHandler* aEventHandler )
258 {
259  m_control = new TEXT_BUTTON_FP_CHOOSER( aParent, m_dlg, m_preselect );
260 
261 #if wxUSE_VALIDATORS
262  // validate text in textctrl, if validator is set
263  if ( m_validator )
264  {
265  Combo()->SetValidator( *m_validator );
266  }
267 #endif
268 
269  wxGridCellEditor::Create( aParent, aId, aEventHandler );
270 }
271 
272 
273 class TEXT_BUTTON_URL : public wxComboCtrl
274 {
275 public:
276  TEXT_BUTTON_URL( wxWindow* aParent, DIALOG_SHIM* aParentDlg ) :
277  wxComboCtrl( aParent ),
278  m_dlg( aParentDlg )
279  {
280  SetButtonBitmaps( KiBitmap( www_xpm ) );
281  }
282 
283 protected:
284  void DoSetPopupControl( wxComboPopup* popup ) override
285  {
286  m_popup = nullptr;
287  }
288 
289  void OnButtonClick() override
290  {
291  wxString filename = GetValue();
292 
293  if( !filename.IsEmpty() && filename != wxT( "~" ) )
294  GetAssociatedDocument( m_dlg, GetValue(), &m_dlg->Prj() );
295  }
296 
298 };
299 
300 
301 void GRID_CELL_URL_EDITOR::Create( wxWindow* aParent, wxWindowID aId,
302  wxEvtHandler* aEventHandler )
303 {
304  m_control = new TEXT_BUTTON_URL( aParent, m_dlg );
305 
306 #if wxUSE_VALIDATORS
307  // validate text in textctrl, if validator is set
308  if ( m_validator )
309  {
310  Combo()->SetValidator( *m_validator );
311  }
312 #endif
313 
314  wxGridCellEditor::Create( aParent, aId, aEventHandler );
315 }
316 
317 
318 class TEXT_BUTTON_FILE_BROWSER : public wxComboCtrl
319 {
320 public:
321  TEXT_BUTTON_FILE_BROWSER( wxWindow* aParent, DIALOG_SHIM* aParentDlg,
322  wxString* aCurrentDir, wxString* aExt = nullptr,
323  bool aNormalize = false, wxString aNormalizeBasePath = wxEmptyString ) :
324  wxComboCtrl( aParent ),
325  m_dlg( aParentDlg ),
326  m_currentDir( aCurrentDir ),
327  m_ext( aExt ),
328  m_normalize( aNormalize ),
329  m_normalizeBasePath( aNormalizeBasePath )
330  {
331  SetButtonBitmaps( KiBitmap( folder_xpm ) );
332  }
333 
334 protected:
335  void DoSetPopupControl( wxComboPopup* popup ) override
336  {
337  m_popup = nullptr;
338  }
339 
340  void OnButtonClick() override
341  {
342  wxString path = GetValue();
343 
344  if( path.IsEmpty() )
345  path = *m_currentDir;
346  else
347  path = ExpandEnvVarSubstitutions( path, &m_dlg->Prj() );
348 
349  if( m_ext )
350  {
351  wxFileName fn( path );
352  wxFileDialog dlg( nullptr, _( "Select a File" ), fn.GetPath(), fn.GetFullName(), *m_ext,
353  wxFD_FILE_MUST_EXIST | wxFD_OPEN );
354 
355  if( dlg.ShowModal() == wxID_OK )
356  {
357  wxString filePath = dlg.GetPath();
358  wxString lastPath = dlg.GetDirectory();
359  wxString relPath = wxEmptyString;
360 
361  if( m_normalize )
362  {
363  relPath = NormalizePath( filePath, &Pgm().GetLocalEnvVariables(),
365  lastPath = NormalizePath( dlg.GetDirectory(), &Pgm().GetLocalEnvVariables(),
367  }
368 
369  if( relPath.IsEmpty() )
370  relPath = filePath;
371 
372  SetValue( relPath );
373  *m_currentDir = lastPath;
374  }
375  }
376  else
377  {
378  wxDirDialog dlg( nullptr, _( "Select Path" ), path,
379  wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
380 
381  if( dlg.ShowModal() == wxID_OK )
382  {
383  wxString filePath = dlg.GetPath();
384  wxString relPath = wxEmptyString;
385 
386  if ( m_normalize )
387  {
388  relPath = NormalizePath( filePath, &Pgm().GetLocalEnvVariables(),
390  }
391 
392  if( relPath.IsEmpty() )
393  relPath = filePath;
394 
395  SetValue( relPath );
396  *m_currentDir = relPath;
397  }
398  }
399  }
400 
402  wxString* m_currentDir;
403  wxString* m_ext;
406 };
407 
408 
409 void GRID_CELL_PATH_EDITOR::Create( wxWindow* aParent, wxWindowID aId,
410  wxEvtHandler* aEventHandler )
411 {
412  if( m_ext.IsEmpty() )
413  m_control = new TEXT_BUTTON_FILE_BROWSER( aParent, m_dlg, m_currentDir, nullptr,
415  else
416  m_control = new TEXT_BUTTON_FILE_BROWSER( aParent, m_dlg, m_currentDir, &m_ext,
418 
419 #if wxUSE_VALIDATORS
420  // validate text in textctrl, if validator is set
421  if ( m_validator )
422  {
423  Combo()->SetValidator( *m_validator );
424  }
425 #endif
426 
427  wxGridCellEditor::Create( aParent, aId, aEventHandler );
428 }
const BITMAP_OPAQUE folder_xpm[1]
Definition: folder.cpp:20
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject)
Function GetAssociatedDocument open a document (file) with the suitable browser.
Definition: eda_doc.cpp:79
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:61
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
void StartingKey(wxKeyEvent &event) override
This file is part of the common library.
void Create(wxWindow *aParent, wxWindowID aId, wxEvtHandler *aEventHandler) override
void Create(wxWindow *aParent, wxWindowID aId, wxEvtHandler *aEventHandler) override
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
TEXT_BUTTON_URL(wxWindow *aParent, DIALOG_SHIM *aParentDlg)
void DoSetPopupControl(wxComboPopup *popup) override
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:255
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
void SetSize(const wxRect &aRect) override
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:82
void BeginEdit(int aRow, int aCol, wxGrid *aGrid) override
TEXT_BUTTON_FP_CHOOSER(wxWindow *aParent, DIALOG_SHIM *aParentDlg, const wxString &aPreselect)
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:345
TEXT_BUTTON_SYMBOL_CHOOSER(wxWindow *aParent, DIALOG_SHIM *aParentDlg, const wxString &aPreselect)
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
wxComboCtrl * Combo() const
void DoSetPopupControl(wxComboPopup *popup) override
const BITMAP_OPAQUE small_library_xpm[1]
void DoSetPopupControl(wxComboPopup *popup) override
const BITMAP_OPAQUE www_xpm[1]
Definition: www.cpp:28
wxString GetValue() const override
void Create(wxWindow *aParent, wxWindowID aId, wxEvtHandler *aEventHandler) override
#define _(s)
Definition: 3d_actions.cpp:33
void ApplyEdit(int aRow, int aCol, wxGrid *aGrid) override
The common library.
void DoSetPopupControl(wxComboPopup *popup) override
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void Create(wxWindow *aParent, wxWindowID aId, wxEvtHandler *aEventHandler) override
bool EndEdit(int, int, const wxGrid *, const wxString &, wxString *aNewVal) override
virtual bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalizes a file path to an environmental variable, if possible.
Definition: env_paths.cpp:68
TEXT_BUTTON_FILE_BROWSER(wxWindow *aParent, DIALOG_SHIM *aParentDlg, wxString *aCurrentDir, wxString *aExt=nullptr, bool aNormalize=false, wxString aNormalizeBasePath=wxEmptyString)