KiCad PCB EDA Suite
unit_binder.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) 2014-2015 CERN
5  * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Maciej Suminski <maciej.suminski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <wx/clipbrd.h>
27 #include <wx/stattext.h>
28 #include <wx/textentry.h>
29 #include <limits>
30 #include <base_units.h>
31 #include <eda_draw_frame.h>
32 #include <confirm.h>
33 
34 #include "widgets/unit_binder.h"
35 
36 wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
37 
39  wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel,
40  bool aUseMils, bool allowEval ) :
41  m_frame( aParent ),
42  m_label( aLabel ),
43  m_value( aValue ),
44  m_unitLabel( aUnitLabel ),
45  m_eval( aParent->GetUserUnits(), aUseMils )
46 {
47  m_units = aParent->GetUserUnits();
48  m_useMils = aUseMils;
50  m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value );
51  m_needsEval = false;
52  m_selStart = 0;
53  m_selEnd = 0;
54 
55  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
56 
57  if( textEntry )
58  {
59  // Use ChangeValue() instead of SetValue() so we don't generate events.
60  textEntry->ChangeValue( wxT( "0" ) );
61  }
62 
64 
65  m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this );
66  m_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this );
67  Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), NULL, this );
68 
69  m_frame->Connect( UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ), nullptr, this );
70 }
71 
72 
74 {
75  m_frame->Disconnect( UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ), nullptr, this );
76 }
77 
78 
79 void UNIT_BINDER::SetUnits( EDA_UNITS aUnits, bool aUseMils )
80 {
81  m_units = aUnits;
82  m_useMils = aUseMils;
84 }
85 
86 
88 {
89  m_dataType = aDataType;
91 }
92 
93 
94 void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent )
95 {
96  int temp = (int) GetValue();
97 
99 
100  SetValue( temp );
101 
102  aEvent.Skip();
103 }
104 
105 
106 void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
107 {
108  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
109 
110  if( m_allowEval && textEntry )
111  {
112  wxString oldStr = m_eval.OriginalText();
113 
114  if( oldStr.length() )
115  {
116  textEntry->SetValue( oldStr );
117  textEntry->SetSelection( m_selStart, m_selEnd );
118  }
119 
120  m_needsEval = true;
121  }
122 
123  aEvent.Skip();
124 }
125 
126 
127 void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
128 {
129  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
130 
131  if( m_allowEval && textEntry )
132  {
133  if( m_eval.Process( textEntry->GetValue() ) )
134  {
135  textEntry->GetSelection( &m_selStart, &m_selEnd );
136  wxString sel = textEntry->GetStringSelection();
137 
138  textEntry->ChangeValue( m_eval.Result() );
139 
140 #ifdef __WXGTK__
141  // Manually copy the selected text to the primary selection clipboard
142  if( wxTheClipboard->Open() )
143  {
144  bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
145  wxTheClipboard->UsePrimarySelection( true );
146  wxTheClipboard->SetData( new wxTextDataObject( sel ) );
147  wxTheClipboard->UsePrimarySelection( clipTarget );
148  wxTheClipboard->Close();
149  }
150 #endif
151  }
152 
153  m_needsEval = false;
154  }
155 
156  aEvent.Skip();
157 }
158 
159 
160 wxString valueDescriptionFromLabel( wxStaticText* aLabel )
161 {
162  wxString desc = aLabel->GetLabel();
163 
164  desc.EndsWith( wxT( ":" ), &desc );
165  return desc;
166 }
167 
168 
169 void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
170 {
171  if( !m_errorMessage.IsEmpty() )
172  DisplayError( m_value->GetParent(), m_errorMessage );
173 
174  m_errorMessage = wxEmptyString;
175  m_value->SetFocus();
176 }
177 
178 
179 bool UNIT_BINDER::Validate( double aMin, double aMax, EDA_UNITS aUnits, bool aUseMils )
180 {
181  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
182 
183  if( !textEntry
184  || textEntry->GetValue() == INDETERMINATE_ACTION
185  || textEntry->GetValue() == INDETERMINATE_STATE )
186  {
187  return true;
188  }
189 
190  // TODO: Validate() does not currently support m_dataType being anything other than DISTANCE
191  // Note: aMin and aMax are not always given in internal units
192  if( GetValue() < From_User_Unit( aUnits, aMin, aUseMils ) )
193  {
194  double val_min_iu = From_User_Unit( aUnits, aMin, aUseMils );
195  m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
197  StringFromValue( m_units, val_min_iu, true, m_useMils ) );
198 
199  textEntry->SelectAll();
200  // Don't focus directly; we might be inside a KillFocus event handler
201  wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
202 
203  return false;
204  }
205 
206  if( GetValue() > From_User_Unit( aUnits, aMax, aUseMils ) )
207  {
208  double val_max_iu = From_User_Unit( aUnits, aMax, aUseMils );
209  m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
211  StringFromValue( m_units, val_max_iu, true, m_useMils ) );
212 
213  textEntry->SelectAll();
214  // Don't focus directly; we might be inside a KillFocus event handler
215  wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
216 
217  return false;
218  }
219 
220  return true;
221 }
222 
223 
224 void UNIT_BINDER::SetValue( int aValue )
225 {
226  SetValue( StringFromValue( m_units, aValue, false, m_useMils, m_dataType ) );
227 }
228 
229 
230 void UNIT_BINDER::SetDoubleValue( double aValue )
231 {
232  SetValue( StringFromValue( m_units, aValue, false, m_useMils, m_dataType ) );
233 }
234 
235 
236 void UNIT_BINDER::SetValue( wxString aValue )
237 {
238  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
239  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
240 
241  if( textEntry )
242  textEntry->SetValue( aValue );
243  else if( staticText )
244  staticText->SetLabel( aValue );
245 
246  if( m_allowEval )
247  m_eval.Clear();
248 
250 }
251 
252 
253 void UNIT_BINDER::ChangeValue( int aValue )
254 {
255  ChangeValue( StringFromValue( m_units, aValue, false, m_useMils ) );
256 }
257 
258 
259 void UNIT_BINDER::ChangeValue( const wxString& aValue )
260 {
261  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
262  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
263 
264  if( textEntry )
265  textEntry->ChangeValue( aValue );
266  else if( staticText )
267  staticText->SetLabel( aValue );
268 
269  if( m_allowEval )
270  m_eval.Clear();
271 
273 }
274 
275 
276 long long int UNIT_BINDER::GetValue()
277 {
278  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
279  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
280  wxString value;
281 
282  if( textEntry )
283  {
284  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
285  value = m_eval.Result();
286  else
287  value = textEntry->GetValue();
288  }
289  else if( staticText )
290  value = staticText->GetLabel();
291  else
292  return 0;
293 
294  return ValueFromString( m_units, value, m_useMils, m_dataType );
295 }
296 
297 
299 {
300  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
301  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
302  wxString value;
303 
304  if( textEntry )
305  {
306  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
307  value = m_eval.Result();
308  else
309  value = textEntry->GetValue();
310  }
311  else if( staticText )
312  value = staticText->GetLabel();
313  else
314  return 0.0;
315 
317 }
318 
319 
321 {
322  wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_value );
323 
324  if( te )
325  return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION;
326 
327  return false;
328 }
329 
330 
332 {
333  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
334  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
335 
336  if( m_allowEval )
337  return m_eval.OriginalText();
338  else if( textEntry )
339  return textEntry->GetValue();
340  else if( staticText )
341  return staticText->GetLabel();
342  else
343  return wxEmptyString;
344 }
345 
346 
347 void UNIT_BINDER::SetLabel( const wxString& aLabel )
348 {
349  m_label->SetLabel( aLabel );
350 }
351 
352 
353 void UNIT_BINDER::Enable( bool aEnable )
354 {
355  m_label->Enable( aEnable );
356  m_value->Enable( aEnable );
357  m_unitLabel->Enable( aEnable );
358 }
359 
360 
361 void UNIT_BINDER::Show( bool aShow, bool aResize )
362 {
363  m_label->Show( aShow );
364  m_value->Show( aShow );
365  m_unitLabel->Show( aShow );
366 
367  if( aResize )
368  {
369  if( aShow )
370  {
371  m_label->SetSize( -1, -1 );
372  m_value->SetSize( -1, -1 );
373  m_unitLabel->SetSize( -1, -1 );
374  }
375  else
376  {
377  m_label->SetSize( 0, 0 );
378  m_value->SetSize( 0, 0 );
379  m_unitLabel->SetSize( 0, 0 );
380  }
381  }
382 }
383 
EDA_UNITS
Definition: common.h:198
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
wxString m_errorMessage
Validation support.
Definition: unit_binder.h:177
wxString GetOriginalText() const
Function GetOriginalText Returns the pre-evaluated text (or the current text if evaluation is not sup...
EDA_DRAW_FRAME * m_frame
Definition: unit_binder.h:164
~UNIT_BINDER() override
Definition: unit_binder.cpp:73
#define INDETERMINATE_STATE
void delayedFocusHandler(wxCommandEvent &aEvent)
int GetUserUnits()
Returns the currently selected user unit value for the interface.
wxWindow * m_value
Definition: unit_binder.h:168
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
wxString OriginalText() const
EDA_DATA_TYPE
The type of unit.
Definition: common.h:191
double From_User_Unit(EDA_UNITS aUnits, double aValue, bool aUseMils)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:321
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:346
void SetDataType(EDA_DATA_TYPE aDataType)
Used to override the datatype of the displayed property (default is DISTANCE)
Definition: unit_binder.cpp:87
bool m_needsEval
Definition: unit_binder.h:182
bool IsIndeterminate() const
Function IsIndeterminate Returns true if the control holds the indeterminate value (for instance,...
wxDEFINE_EVENT(DELAY_FOCUS, wxCommandEvent)
The base class for create windows for drawing purpose.
wxString GetAbbreviatedUnitsLabel(EDA_UNITS aUnit, bool aUseMils, EDA_DATA_TYPE aType)
Get the units string for a given units type.
Definition: base_units.cpp:495
wxString valueDescriptionFromLabel(wxStaticText *aLabel)
EDA_UNITS m_units
Currently used units.
Definition: unit_binder.h:172
void Show(bool aShow, bool aResize=false)
Function Show Shows/hides the label, widget and units label.
bool Process(const wxString &aString)
#define NULL
wxStaticText * m_label
The bound widgets
Definition: unit_binder.h:167
UNIT_BINDER(EDA_DRAW_FRAME *aParent, wxStaticText *aLabel, wxWindow *aValue, wxStaticText *aUnitLabel, bool aUseMils=false, bool aAllowEval=true)
Constructor.
Definition: unit_binder.cpp:38
EDA_DATA_TYPE m_dataType
Definition: unit_binder.h:174
wxStaticText * m_unitLabel
Definition: unit_binder.h:169
NUMERIC_EVALUATOR m_eval
Evaluator
Definition: unit_binder.h:180
bool m_useMils
Definition: unit_binder.h:173
bool m_allowEval
Definition: unit_binder.h:181
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED, bool aUseMils=false)
Function Validate Validates the control against the given range, informing the user of any errors fou...
void onKillFocus(wxFocusEvent &aEvent)
wxString Result() const
void onSetFocus(wxFocusEvent &aEvent)
void SetLabel(const wxString &aLabel)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define _(s)
Definition: 3d_actions.cpp:33
void onUnitsChanged(wxCommandEvent &aEvent)
Definition: unit_binder.cpp:94
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
#define INDETERMINATE_ACTION
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
long m_selStart
Selection start and end of the original text
Definition: unit_binder.h:185
virtual void SetDoubleValue(double aValue)
Function SetDoubleValue Sets new value (in Internal Units) for the text field, taking care of units c...
virtual double GetDoubleValue()
Function GetValue Returns the current value in Internal Units.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils, EDA_DATA_TYPE aType)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:233
void Enable(bool aEnable)
Function Enable Enables/diasables the label, widget and units label.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:471
virtual void SetUnits(EDA_UNITS aUnits, bool aUseMils=false)
Function SetUnits Normally not needed (as the UNIT_BINDER inherits from the parent frame),...
Definition: unit_binder.cpp:79
virtual void ChangeValue(int aValue)
Function ChangeValue Changes the value (in Internal Units) for the text field, taking care of units c...