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