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  * Author: Maciej Suminski <maciej.suminski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <wx/clipbrd.h>
26 #include <wx/stattext.h>
27 #include <wx/textentry.h>
28 #include <limits>
29 #include <base_units.h>
30 #include <eda_draw_frame.h>
31 #include <confirm.h>
32 
33 #include "widgets/unit_binder.h"
34 
35 wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
36 
38  wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel,
39  bool aUseMils, bool allowEval ) :
40  m_label( aLabel ),
41  m_value( aValue ),
42  m_unitLabel( aUnitLabel ),
43  m_eval( aParent->GetUserUnits(), aUseMils )
44 {
45  // Fix the units (to the current units) for the life of the binder
46  m_units = aParent->GetUserUnits();
47  m_useMils = aUseMils;
48  m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value );
49  m_needsEval = false;
50  m_selStart = 0;
51  m_selEnd = 0;
52 
53  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
54  if( textEntry )
55  {
56  // Use ChangeValue() instead of SetValue() so we don't generate events.
57  textEntry->ChangeValue( wxT( "0" ) );
58  }
59 
61 
62  m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this );
63  m_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this );
64  Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), NULL, this );
65 }
66 
67 
68 void UNIT_BINDER::SetUnits( EDA_UNITS aUnits, bool aUseMils )
69 {
70  m_units = aUnits;
71  m_useMils = aUseMils;
73 }
74 
75 
76 void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
77 {
78  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
79 
80  if( m_allowEval && textEntry )
81  {
82  wxString oldStr = m_eval.OriginalText();
83 
84  if( oldStr.length() )
85  {
86  textEntry->SetValue( oldStr );
87  textEntry->SetSelection( m_selStart, m_selEnd );
88  }
89 
90  m_needsEval = true;
91  }
92 
93  aEvent.Skip();
94 }
95 
96 
97 void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
98 {
99  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
100 
101  if( m_allowEval && textEntry )
102  {
103  if( m_eval.Process( textEntry->GetValue() ) )
104  {
105  textEntry->GetSelection( &m_selStart, &m_selEnd );
106  wxString sel = textEntry->GetStringSelection();
107 
108  textEntry->ChangeValue( m_eval.Result() );
109 
110 #ifdef __WXGTK__
111  // Manually copy the selected text to the primary selection clipboard
112  if( wxTheClipboard->Open() )
113  {
114  bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
115  wxTheClipboard->UsePrimarySelection( true );
116  wxTheClipboard->SetData( new wxTextDataObject( sel ) );
117  wxTheClipboard->UsePrimarySelection( clipTarget );
118  wxTheClipboard->Close();
119  }
120 #endif
121  }
122 
123  m_needsEval = false;
124  }
125 
126  aEvent.Skip();
127 }
128 
129 
130 wxString valueDescriptionFromLabel( wxStaticText* aLabel )
131 {
132  wxString desc = aLabel->GetLabel();
133 
134  desc.EndsWith( wxT( ":" ), &desc );
135  return desc;
136 }
137 
138 
139 void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
140 {
141  if( !m_errorMessage.IsEmpty() )
142  DisplayError( m_value->GetParent(), m_errorMessage );
143 
144  m_errorMessage = wxEmptyString;
145  m_value->SetFocus();
146 }
147 
148 
149 bool UNIT_BINDER::Validate( long long int aMin, long long int aMax, bool setFocusOnError )
150 {
151  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
152 
153  if( !textEntry || textEntry->GetValue() == INDETERMINATE )
154  return true;
155 
156  if( GetValue() < aMin )
157  {
158  m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
160  StringFromValue( m_units, aMin, true ) );
161 
162  if( setFocusOnError )
163  {
164  textEntry->SelectAll();
165  // Don't focus directly; we might be inside a KillFocus event handler
166  wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
167  }
168 
169  return false;
170  }
171 
172  if( GetValue() > aMax )
173  {
174  m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
176  StringFromValue( m_units, aMax, true ) );
177 
178  if( setFocusOnError )
179  {
180  textEntry->SelectAll();
181  // Don't focus directly; we might be inside a KillFocus event handler
182  wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
183  }
184 
185  return false;
186  }
187 
188  return true;
189 }
190 
191 
192 void UNIT_BINDER::SetValue( int aValue )
193 {
194  SetValue( StringFromValue( m_units, aValue, false, m_useMils ) );
195 }
196 
197 
198 void UNIT_BINDER::SetDoubleValue( double aValue )
199 {
200  SetValue( StringFromValue( m_units, aValue, false, m_useMils ) );
201 }
202 
203 
204 void UNIT_BINDER::SetValue( wxString aValue )
205 {
206  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
207  auto staticText = dynamic_cast<wxStaticText*>( m_value );
208 
209  if( textEntry )
210  textEntry->SetValue( aValue );
211  else if( staticText )
212  staticText->SetLabel( aValue );
213 
214  if( m_allowEval )
215  m_eval.Clear();
216 
218 }
219 
220 
221 void UNIT_BINDER::ChangeValue( int aValue )
222 {
223  ChangeValue( StringFromValue( m_units, aValue, false, m_useMils ) );
224 }
225 
226 
227 void UNIT_BINDER::ChangeValue( wxString aValue )
228 {
229  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
230  auto staticText = dynamic_cast<wxStaticText*>( m_value );
231 
232  if( textEntry )
233  textEntry->ChangeValue( aValue );
234  else if( staticText )
235  staticText->SetLabel( aValue );
236 
237  if( m_allowEval )
238  m_eval.Clear();
239 
241 }
242 
243 
244 long long int UNIT_BINDER::GetValue()
245 {
246  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
247  auto staticText = dynamic_cast<wxStaticText*>( m_value );
248  wxString value;
249 
250  if( textEntry )
251  {
252  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
253  value = m_eval.Result();
254  else
255  value = textEntry->GetValue();
256  }
257  else if( staticText )
258  value = staticText->GetLabel();
259  else
260  return 0;
261 
262  return ValueFromString( m_units, value, m_useMils );
263 }
264 
265 
267 {
268  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
269  auto staticText = dynamic_cast<wxStaticText*>( m_value );
270  wxString value;
271 
272  if( textEntry )
273  {
274  if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
275  value = m_eval.Result();
276  else
277  value = textEntry->GetValue();
278  }
279  else if( staticText )
280  value = staticText->GetLabel();
281  else
282  return 0.0;
283 
284  return DoubleValueFromString( m_units, value, m_useMils );
285 }
286 
287 
289 {
290  auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
291 
292  if( textEntry )
293  return textEntry->GetValue() == INDETERMINATE;
294 
295  return false;
296 }
297 
298 
299 void UNIT_BINDER::SetLabel( const wxString& aLabel )
300 {
301  m_label->SetLabel( aLabel );
302 }
303 
304 
305 void UNIT_BINDER::Enable( bool aEnable )
306 {
307  m_label->Enable( aEnable );
308  m_value->Enable( aEnable );
309  m_unitLabel->Enable( aEnable );
310 }
311 
312 
313 void UNIT_BINDER::Show( bool aShow, bool aResize )
314 {
315  m_label->Show( aShow );
316  m_value->Show( aShow );
317  m_unitLabel->Show( aShow );
318 
319  if( aResize )
320  {
321  if( aShow )
322  {
323  m_label->SetSize( -1, -1 );
324  m_value->SetSize( -1, -1 );
325  m_unitLabel->SetSize( -1, -1 );
326  }
327  else
328  {
329  m_label->SetSize( 0, 0 );
330  m_value->SetSize( 0, 0 );
331  m_unitLabel->SetSize( 0, 0 );
332  }
333  }
334 }
335 
EDA_UNITS
Definition: common.h:184
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:153
void delayedFocusHandler(wxCommandEvent &aEvent)
int GetUserUnits()
Returns the currently selected user unit value for the interface.
wxWindow * m_value
Definition: unit_binder.h:145
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
wxString OriginalText() const
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:234
bool m_needsEval
Definition: unit_binder.h:158
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:467
wxString valueDescriptionFromLabel(wxStaticText *aLabel)
EDA_UNITS m_units
Currently used units.
Definition: unit_binder.h:149
void Show(bool aShow, bool aResize=false)
Function Show Shows/hides the label, widget and units label.
bool Process(const wxString &aString)
#define NULL
#define INDETERMINATE
wxStaticText * m_label
The bound widgets
Definition: unit_binder.h:144
UNIT_BINDER(EDA_DRAW_FRAME *aParent, wxStaticText *aLabel, wxWindow *aValue, wxStaticText *aUnitLabel, bool aUseMils=false, bool aAllowEval=true)
Constructor.
Definition: unit_binder.cpp:37
wxStaticText * m_unitLabel
Definition: unit_binder.h:146
NUMERIC_EVALUATOR m_eval
Evaluator
Definition: unit_binder.h:156
bool m_useMils
Definition: unit_binder.h:150
virtual bool Validate(long long int aMin, long long int aMax, bool setFocusOnError=true)
Function Validate Validates the control against the given range, informing the user of any errors fou...
bool m_allowEval
Definition: unit_binder.h:157
void onKillFocus(wxFocusEvent &aEvent)
Definition: unit_binder.cpp:97
wxString Result() const
void onSetFocus(wxFocusEvent &aEvent)
Definition: unit_binder.cpp:76
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
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.
long m_selStart
Selection start and end of the original text
Definition: unit_binder.h:161
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:444
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:331
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.
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 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:68
virtual void ChangeValue(int aValue)
Function ChangeValue Changes the value (in Internal Units) for the text field, taking care of units c...