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 allowEval ) :
41  m_frame( aParent ),
42  m_label( aLabel ),
43  m_value( aValue ),
44  m_unitLabel( aUnitLabel ),
45  m_eval( aParent->GetUserUnits() ),
46  m_originTransforms( aParent->GetOriginTransforms() ),
47  m_coordType( ORIGIN_TRANSFORMS::NOT_A_COORD )
48 {
49  m_units = aParent->GetUserUnits();
51  m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value );
52  m_needsEval = false;
53  m_selStart = 0;
54  m_selEnd = 0;
55 
56  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
57 
58  if( textEntry )
59  {
60  // Use ChangeValue() instead of SetValue() so we don't generate events.
61  textEntry->ChangeValue( wxT( "0" ) );
62  }
63 
65 
66  m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this );
67  m_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this );
68  Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), NULL, this );
69 
70  m_frame->Connect( UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ), nullptr, this );
71 }
72 
73 
75 {
76  m_frame->Disconnect( UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ), nullptr, this );
77 }
78 
79 
81 {
82  m_units = aUnits;
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 )
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 ) )
193  {
194  double val_min_iu = From_User_Unit( aUnits, aMin );
195  m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
197  StringFromValue( m_units, val_min_iu, true ) );
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 ) )
207  {
208  double val_max_iu = From_User_Unit( aUnits, aMax );
209  m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
211  StringFromValue( m_units, val_max_iu, true ) );
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  double value = aValue;
227  double displayValue = m_originTransforms.ToDisplay( value, m_coordType );
228  SetValue( StringFromValue( m_units, displayValue, false, m_dataType ) );
229 }
230 
231 
232 void UNIT_BINDER::SetDoubleValue( double aValue )
233 {
234  double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
235  SetValue( StringFromValue( m_units, displayValue, false, m_dataType ) );
236 }
237 
238 
239 void UNIT_BINDER::SetValue( wxString aValue )
240 {
241  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
242  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
243 
244  if( textEntry )
245  textEntry->SetValue( aValue );
246  else if( staticText )
247  staticText->SetLabel( aValue );
248 
249  if( m_allowEval )
250  m_eval.Clear();
251 
253 }
254 
255 
256 void UNIT_BINDER::ChangeValue( int aValue )
257 {
258  double value = aValue;
259  double displayValue = m_originTransforms.ToDisplay( value, m_coordType );
260  ChangeValue( StringFromValue( m_units, displayValue, false ) );
261 }
262 
263 
264 void UNIT_BINDER::ChangeValue( const wxString& aValue )
265 {
266  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
267  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
268 
269  if( textEntry )
270  textEntry->ChangeValue( aValue );
271  else if( staticText )
272  staticText->SetLabel( aValue );
273 
274  if( m_allowEval )
275  m_eval.Clear();
276 
278 }
279 
280 
281 long long int UNIT_BINDER::GetValue()
282 {
283  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
284  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
285  wxString value;
286 
287  if( textEntry )
288  {
289  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
290  value = m_eval.Result();
291  else
292  value = textEntry->GetValue();
293  }
294  else if( staticText )
295  value = staticText->GetLabel();
296  else
297  return 0;
298 
299  long long int displayValue = ValueFromString( m_units, value, m_dataType );
300  return m_originTransforms.FromDisplay( displayValue, m_coordType );
301 }
302 
303 
305 {
306  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
307  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
308  wxString value;
309 
310  if( textEntry )
311  {
312  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
313  value = m_eval.Result();
314  else
315  value = textEntry->GetValue();
316  }
317  else if( staticText )
318  value = staticText->GetLabel();
319  else
320  return 0.0;
321 
322  double displayValue = DoubleValueFromString( m_units, value, m_dataType );
323  return m_originTransforms.FromDisplay( displayValue, m_coordType );
324 }
325 
326 
328 {
329  wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_value );
330 
331  if( te )
332  return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION;
333 
334  return false;
335 }
336 
337 
339 {
340  wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_value );
341  wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_value );
342 
343  if( m_allowEval )
344  return m_eval.OriginalText();
345  else if( textEntry )
346  return textEntry->GetValue();
347  else if( staticText )
348  return staticText->GetLabel();
349  else
350  return wxEmptyString;
351 }
352 
353 
354 void UNIT_BINDER::SetLabel( const wxString& aLabel )
355 {
356  m_label->SetLabel( aLabel );
357 }
358 
359 
360 void UNIT_BINDER::Enable( bool aEnable )
361 {
362  m_label->Enable( aEnable );
363  m_value->Enable( aEnable );
364  m_unitLabel->Enable( aEnable );
365 }
366 
367 
368 void UNIT_BINDER::Show( bool aShow, bool aResize )
369 {
370  m_label->Show( aShow );
371  m_value->Show( aShow );
372  m_unitLabel->Show( aShow );
373 
374  if( aResize )
375  {
376  if( aShow )
377  {
378  m_label->SetSize( -1, -1 );
379  m_value->SetSize( -1, -1 );
380  m_unitLabel->SetSize( -1, -1 );
381  }
382  else
383  {
384  m_label->SetSize( 0, 0 );
385  m_value->SetSize( 0, 0 );
386  m_unitLabel->SetSize( 0, 0 );
387  }
388  }
389 }
390 
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:240
wxString m_errorMessage
Validation support.
Definition: unit_binder.h:193
wxString GetOriginalText() const
Function GetOriginalText Returns the pre-evaluated text (or the current text if evaluation is not sup...
ORIGIN_TRANSFORMS::COORD_TYPES_T m_coordType
Type of coordinate for display origin transforms.
Definition: unit_binder.h:208
EDA_DRAW_FRAME * m_frame
Definition: unit_binder.h:181
~UNIT_BINDER() override
Definition: unit_binder.cpp:74
void delayedFocusHandler(wxCommandEvent &aEvent)
int GetUserUnits()
Returns the currently selected user unit value for the interface.
wxWindow * m_value
Definition: unit_binder.h:185
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: eda_units.h:31
ORIGIN_TRANSFORMS & m_originTransforms
A reference to an ORIGIN_TRANSFORMS object.
Definition: unit_binder.h:205
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:198
wxString GetAbbreviatedUnitsLabel(EDA_UNITS aUnit, EDA_DATA_TYPE aType)
Get the units string for a given units type.
Definition: base_units.cpp:467
virtual int FromDisplay(int aValue, COORD_TYPES_T aCoordType)
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 valueDescriptionFromLabel(wxStaticText *aLabel)
EDA_UNITS m_units
Currently used units.
Definition: unit_binder.h:189
void Show(bool aShow, bool aResize=false)
Function Show Shows/hides the label, widget and units label.
bool Process(const wxString &aString)
#define NULL
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:444
wxStaticText * m_label
The bound widgets
Definition: unit_binder.h:184
EDA_DATA_TYPE m_dataType
Definition: unit_binder.h:190
wxStaticText * m_unitLabel
Definition: unit_binder.h:186
NUMERIC_EVALUATOR m_eval
Evaluator
Definition: unit_binder.h:196
bool m_allowEval
Definition: unit_binder.h:197
EDA_UNITS
Definition: eda_units.h:38
virtual void SetUnits(EDA_UNITS aUnits)
Function SetUnits Normally not needed (as the UNIT_BINDER inherits from the parent frame),...
Definition: unit_binder.cpp:80
void onKillFocus(wxFocusEvent &aEvent)
wxString Result() const
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED)
Function Validate Validates the control against the given range, informing the user of any errors fou...
void onSetFocus(wxFocusEvent &aEvent)
void SetLabel(const wxString &aLabel)
UNIT_BINDER(EDA_DRAW_FRAME *aParent, wxStaticText *aLabel, wxWindow *aValue, wxStaticText *aUnitLabel, bool aAllowEval=true)
Constructor.
Definition: unit_binder.cpp:38
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:201
A class to perform either relative or absolute display origin transforms for a single axis of a point...
#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...
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:220
long m_selStart
Selection start and end of the original text
Definition: unit_binder.h:201
virtual int ToDisplay(int aValue, COORD_TYPES_T aCoordType)
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.
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:333
#define INDETERMINATE_ACTION
Definition: base_units.h:49
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition: base_units.h:48
double From_User_Unit(EDA_UNITS aUnits, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:308
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.
virtual void ChangeValue(int aValue)
Function ChangeValue Changes the value (in Internal Units) for the text field, taking care of units c...