]> git.saurik.com Git - wxWidgets.git/blob - include/wx/valnum.h
428fe7ff8a48f73ffbf75e7a61ac1c93e8a0ea0f
[wxWidgets.git] / include / wx / valnum.h
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/valnum.h
3 // Purpose: Numeric validator classes.
4 // Author: Vadim Zeitlin based on the submission of Fulvio Senore
5 // Created: 2010-11-06
6 // Copyright: (c) 2010 wxWidgets team
7 // (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifndef _WX_VALNUM_H_
12 #define _WX_VALNUM_H_
13
14 #include "wx/defs.h"
15
16 #if wxUSE_VALIDATORS
17
18 #include "wx/validate.h"
19
20 #include <limits>
21
22 // Bit masks used for numeric validator styles.
23 enum wxNumValidatorStyle
24 {
25 wxNUM_VAL_DEFAULT = 0x0,
26 wxNUM_VAL_THOUSANDS_SEPARATOR = 0x1,
27 wxNUM_VAL_ZERO_AS_BLANK = 0x2,
28 wxNUM_VAL_NO_TRAILING_ZEROES = 0x4
29 };
30
31 // ----------------------------------------------------------------------------
32 // Base class for all numeric validators.
33 // ----------------------------------------------------------------------------
34
35 class WXDLLIMPEXP_CORE wxNumValidatorBase : public wxValidator
36 {
37 public:
38 // Change the validator style. Usually it's specified during construction.
39 void SetStyle(int style) { m_style = style; }
40
41
42 // Override base class method to not do anything but always return success:
43 // we don't need this as we do our validation on the fly here.
44 virtual bool Validate(wxWindow * WXUNUSED(parent)) { return true; }
45
46 protected:
47 wxNumValidatorBase(int style)
48 {
49 m_style = style;
50 }
51
52 wxNumValidatorBase(const wxNumValidatorBase& other)
53 {
54 m_style = other.m_style;
55 }
56
57 bool HasFlag(wxNumValidatorStyle style) const
58 {
59 return (m_style & style) != 0;
60 }
61
62 // Get the text entry of the associated control. Normally shouldn't ever
63 // return NULL (and will assert if it does return it) but the caller should
64 // still test the return value for safety.
65 wxTextEntry *GetTextEntry() const;
66
67 // Convert wxNUM_VAL_THOUSANDS_SEPARATOR and wxNUM_VAL_NO_TRAILING_ZEROES
68 // bits of our style to the corresponding wxNumberFormatter::Style values.
69 int GetFormatFlags() const;
70
71 // Return true if pressing a '-' key is acceptable for the current control
72 // contents and insertion point. This is meant to be called from the
73 // derived class IsCharOk() implementation.
74 bool IsMinusOk(const wxString& val, int pos) const;
75
76 // Return the string which would result from inserting the given character
77 // at the specified position.
78 wxString GetValueAfterInsertingChar(wxString val, int pos, wxChar ch) const
79 {
80 val.insert(pos, ch);
81 return val;
82 }
83
84 private:
85 // Check whether the specified character can be inserted in the control at
86 // the given position in the string representing the current controls
87 // contents.
88 //
89 // Notice that the base class checks for '-' itself so it's never passed to
90 // this function.
91 virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0;
92
93 // NormalizeString the contents of the string if it's a valid number, return
94 // empty string otherwise.
95 virtual wxString NormalizeString(const wxString& s) const = 0;
96
97
98 // Event handlers.
99 void OnChar(wxKeyEvent& event);
100 void OnKillFocus(wxFocusEvent& event);
101
102
103 // Determine the current insertion point and text in the associated control.
104 void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;
105
106
107 // Combination of wxVAL_NUM_XXX values.
108 int m_style;
109
110
111 wxDECLARE_EVENT_TABLE();
112
113 wxDECLARE_NO_ASSIGN_CLASS(wxNumValidatorBase);
114 };
115
116 namespace wxPrivate
117 {
118
119 // This is a helper class used by wxIntegerValidator and wxFloatingPointValidator
120 // below that implements Transfer{To,From}Window() adapted to the type of the
121 // variable.
122 //
123 // The template argument B is the name of the base class which must derive from
124 // wxNumValidatorBase and define LongestValueType type and {To,As}String()
125 // methods i.e. basically be one of wx{Integer,Number}ValidatorBase classes.
126 //
127 // The template argument T is just the type handled by the validator that will
128 // inherit from this one.
129 template <class B, typename T>
130 class wxNumValidator : public B
131 {
132 public:
133 typedef B BaseValidator;
134 typedef T ValueType;
135
136 typedef typename BaseValidator::LongestValueType LongestValueType;
137
138 wxCOMPILE_TIME_ASSERT
139 (
140 sizeof(ValueType) <= sizeof(LongestValueType),
141 UnsupportedType
142 );
143
144 void SetMin(ValueType min)
145 {
146 this->DoSetMin(min);
147 }
148
149 void SetMax(ValueType max)
150 {
151 this->DoSetMax(max);
152 }
153
154 void SetRange(ValueType min, ValueType max)
155 {
156 SetMin(min);
157 SetMax(max);
158 }
159
160 virtual bool TransferToWindow()
161 {
162 if ( m_value )
163 {
164 wxTextEntry * const control = BaseValidator::GetTextEntry();
165 if ( !control )
166 return false;
167
168 control->SetValue(NormalizeValue(*m_value));
169 }
170
171 return true;
172 }
173
174 virtual bool TransferFromWindow()
175 {
176 if ( m_value )
177 {
178 wxTextEntry * const control = BaseValidator::GetTextEntry();
179 if ( !control )
180 return false;
181
182 const wxString s(control->GetValue());
183 LongestValueType value;
184 if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
185 value = 0;
186 else if ( !BaseValidator::FromString(s, &value) )
187 return false;
188
189 if ( !IsInRange(value) )
190 return false;
191
192 *m_value = static_cast<ValueType>(value);
193 }
194
195 return true;
196 }
197
198 protected:
199 wxNumValidator(ValueType *value, int style)
200 : BaseValidator(style),
201 m_value(value)
202 {
203 }
204
205 // Implement wxNumValidatorBase virtual method which is the same for
206 // both integer and floating point numbers.
207 virtual wxString NormalizeString(const wxString& s) const
208 {
209 LongestValueType value;
210 return BaseValidator::FromString(s, &value) ? NormalizeValue(value)
211 : wxString();
212 }
213
214 private:
215 // Just a helper which is a common part of TransferToWindow() and
216 // NormalizeString(): returns string representation of a number honouring
217 // wxNUM_VAL_ZERO_AS_BLANK flag.
218 wxString NormalizeValue(LongestValueType value) const
219 {
220 wxString s;
221 if ( value != 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
222 s = ToString(value);
223
224 return s;
225 }
226
227
228 ValueType * const m_value;
229
230 wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator);
231 };
232
233 } // namespace wxPrivate
234
235 // ----------------------------------------------------------------------------
236 // Validators for integer numbers.
237 // ----------------------------------------------------------------------------
238
239 // Base class for integer numbers validator. This class contains all non
240 // type-dependent code of wxIntegerValidator<> and always works with values of
241 // type LongestValueType. It is not meant to be used directly, please use
242 // wxIntegerValidator<> only instead.
243 class WXDLLIMPEXP_CORE wxIntegerValidatorBase : public wxNumValidatorBase
244 {
245 protected:
246 // Define the type we use here, it should be the maximal-sized integer type
247 // we support to make it possible to base wxIntegerValidator<> for any type
248 // on it.
249 #ifdef wxLongLong_t
250 typedef wxLongLong_t LongestValueType;
251 #else
252 typedef long LongestValueType;
253 #endif
254
255 wxIntegerValidatorBase(int style)
256 : wxNumValidatorBase(style)
257 {
258 wxASSERT_MSG( !(style & wxNUM_VAL_NO_TRAILING_ZEROES),
259 "This style doesn't make sense for integers." );
260 }
261
262 wxIntegerValidatorBase(const wxIntegerValidatorBase& other)
263 : wxNumValidatorBase(other)
264 {
265 m_min = other.m_min;
266 m_max = other.m_max;
267 }
268
269 // Provide methods for wxNumValidator use.
270 wxString ToString(LongestValueType value) const;
271 static bool FromString(const wxString& s, LongestValueType *value);
272
273 void DoSetMin(LongestValueType min) { m_min = min; }
274 void DoSetMax(LongestValueType max) { m_max = max; }
275
276 bool IsInRange(LongestValueType value) const
277 {
278 return m_min <= value && value <= m_max;
279 }
280
281 // Implement wxNumValidatorBase pure virtual method.
282 virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const;
283
284 private:
285 // Minimal and maximal values accepted (inclusive).
286 LongestValueType m_min, m_max;
287
288 wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase);
289 };
290
291 // Validator for integer numbers. It can actually work with any integer type
292 // (short, int or long and long long if supported) and their unsigned versions
293 // as well.
294 template <typename T>
295 class wxIntegerValidator
296 : public wxPrivate::wxNumValidator<wxIntegerValidatorBase, T>
297 {
298 public:
299 typedef T ValueType;
300
301 typedef
302 wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> Base;
303
304 // Ctor for an integer validator.
305 //
306 // Sets the range appropriately for the type, including setting 0 as the
307 // minimal value for the unsigned types.
308 wxIntegerValidator(ValueType *value = NULL, int style = wxNUM_VAL_DEFAULT)
309 : Base(value, style)
310 {
311 DoSetMin(std::numeric_limits<ValueType>::min());
312 DoSetMax(std::numeric_limits<ValueType>::max());
313 }
314
315 virtual wxObject *Clone() const { return new wxIntegerValidator(*this); }
316
317 private:
318 wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator);
319 };
320
321 // Helper function for creating integer validators which allows to avoid
322 // explicitly specifying the type as it deduces it from its parameter.
323 template <typename T>
324 inline wxIntegerValidator<T>
325 wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT)
326 {
327 return wxIntegerValidator<T>(value, style);
328 }
329
330 // ----------------------------------------------------------------------------
331 // Validators for floating point numbers.
332 // ----------------------------------------------------------------------------
333
334 // Similar to wxIntegerValidatorBase, this class is not meant to be used
335 // directly, only wxFloatingPointValidator<> should be used in the user code.
336 class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase : public wxNumValidatorBase
337 {
338 public:
339 // Set precision i.e. the number of digits shown (and accepted on input)
340 // after the decimal point. By default this is set to the maximal precision
341 // supported by the type handled by the validator.
342 void SetPrecision(unsigned precision) { m_precision = precision; }
343
344 protected:
345 // Notice that we can't use "long double" here because it's not supported
346 // by wxNumberFormatter yet, so restrict ourselves to just double (and
347 // float).
348 typedef double LongestValueType;
349
350 wxFloatingPointValidatorBase(int style)
351 : wxNumValidatorBase(style)
352 {
353 }
354
355 wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase& other)
356 : wxNumValidatorBase(other)
357 {
358 m_precision = other.m_precision;
359
360 m_min = other.m_min;
361 m_max = other.m_max;
362 }
363
364 // Provide methods for wxNumValidator use.
365 wxString ToString(LongestValueType value) const;
366 static bool FromString(const wxString& s, LongestValueType *value);
367
368 void DoSetMin(LongestValueType min) { m_min = min; }
369 void DoSetMax(LongestValueType max) { m_max = max; }
370
371 bool IsInRange(LongestValueType value) const
372 {
373 return m_min <= value && value <= m_max;
374 }
375
376 // Implement wxNumValidatorBase pure virtual method.
377 virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const;
378
379 private:
380 // Maximum number of decimals digits after the decimal separator.
381 unsigned m_precision;
382
383 // Minimal and maximal values accepted (inclusive).
384 LongestValueType m_min, m_max;
385
386 wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase);
387 };
388
389 // Validator for floating point numbers. It can be used with float, double or
390 // long double values.
391 template <typename T>
392 class wxFloatingPointValidator
393 : public wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T>
394 {
395 public:
396 typedef T ValueType;
397 typedef wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> Base;
398
399 // Ctor using implicit (maximal) precision for this type.
400 wxFloatingPointValidator(ValueType *value = NULL,
401 int style = wxNUM_VAL_DEFAULT)
402 : Base(value, style)
403 {
404 DoSetMinMax();
405
406 SetPrecision(std::numeric_limits<ValueType>::digits10);
407 }
408
409 // Ctor specifying an explicit precision.
410 wxFloatingPointValidator(int precision,
411 ValueType *value = NULL,
412 int style = wxNUM_VAL_DEFAULT)
413 : Base(value, style)
414 {
415 DoSetMinMax();
416
417 this->SetPrecision(precision);
418 }
419
420 virtual wxObject *Clone() const
421 {
422 return new wxFloatingPointValidator(*this);
423 }
424
425 private:
426 void DoSetMinMax()
427 {
428 // NB: Do not use min(), it's not the smallest representable value for
429 // the floating point types but rather the smallest representable
430 // positive value.
431 DoSetMin(-std::numeric_limits<ValueType>::max());
432 DoSetMax( std::numeric_limits<ValueType>::max());
433 }
434 };
435
436 // Helper similar to wxMakeIntValidator().
437 //
438 // NB: Unfortunately we can't just have a wxMakeNumericValidator() which would
439 // return either wxIntegerValidator<> or wxFloatingPointValidator<> so we
440 // do need two different functions.
441 template <typename T>
442 inline wxFloatingPointValidator<T>
443 wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT)
444 {
445 return wxFloatingPointValidator<T>(value, style);
446 }
447
448 template <typename T>
449 inline wxFloatingPointValidator<T>
450 wxMakeFloatingPointValidator(int precision, T *value, int style = wxNUM_VAL_DEFAULT)
451 {
452 return wxFloatingPointValidator<T>(precision, value, style);
453 }
454
455 #endif // wxUSE_VALIDATORS
456
457 #endif // _WX_VALNUM_H_