]>
Commit | Line | Data |
---|---|---|
a54cf371 VZ |
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 | ||
6496afba VZ |
138 | // FIXME-VC6: This compiler fails to compile the assert below with a |
139 | // nonsensical error C2248: "'LongestValueType' : cannot access protected | |
140 | // typedef declared in class 'wxIntegerValidatorBase'" so just disable the | |
141 | // check for it. | |
142 | #ifndef __VISUALC6__ | |
a54cf371 VZ |
143 | wxCOMPILE_TIME_ASSERT |
144 | ( | |
145 | sizeof(ValueType) <= sizeof(LongestValueType), | |
146 | UnsupportedType | |
147 | ); | |
6496afba | 148 | #endif // __VISUALC6__ |
a54cf371 VZ |
149 | |
150 | void SetMin(ValueType min) | |
151 | { | |
152 | this->DoSetMin(min); | |
153 | } | |
154 | ||
155 | void SetMax(ValueType max) | |
156 | { | |
157 | this->DoSetMax(max); | |
158 | } | |
159 | ||
160 | void SetRange(ValueType min, ValueType max) | |
161 | { | |
162 | SetMin(min); | |
163 | SetMax(max); | |
164 | } | |
165 | ||
166 | virtual bool TransferToWindow() | |
167 | { | |
168 | if ( m_value ) | |
169 | { | |
170 | wxTextEntry * const control = BaseValidator::GetTextEntry(); | |
171 | if ( !control ) | |
172 | return false; | |
173 | ||
174 | control->SetValue(NormalizeValue(*m_value)); | |
175 | } | |
176 | ||
177 | return true; | |
178 | } | |
179 | ||
180 | virtual bool TransferFromWindow() | |
181 | { | |
182 | if ( m_value ) | |
183 | { | |
184 | wxTextEntry * const control = BaseValidator::GetTextEntry(); | |
185 | if ( !control ) | |
186 | return false; | |
187 | ||
188 | const wxString s(control->GetValue()); | |
189 | LongestValueType value; | |
190 | if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) | |
191 | value = 0; | |
192 | else if ( !BaseValidator::FromString(s, &value) ) | |
193 | return false; | |
194 | ||
df04f800 | 195 | if ( !this->IsInRange(value) ) |
a54cf371 VZ |
196 | return false; |
197 | ||
198 | *m_value = static_cast<ValueType>(value); | |
199 | } | |
200 | ||
201 | return true; | |
202 | } | |
203 | ||
204 | protected: | |
205 | wxNumValidator(ValueType *value, int style) | |
206 | : BaseValidator(style), | |
207 | m_value(value) | |
208 | { | |
209 | } | |
210 | ||
211 | // Implement wxNumValidatorBase virtual method which is the same for | |
212 | // both integer and floating point numbers. | |
213 | virtual wxString NormalizeString(const wxString& s) const | |
214 | { | |
215 | LongestValueType value; | |
216 | return BaseValidator::FromString(s, &value) ? NormalizeValue(value) | |
217 | : wxString(); | |
218 | } | |
219 | ||
220 | private: | |
221 | // Just a helper which is a common part of TransferToWindow() and | |
222 | // NormalizeString(): returns string representation of a number honouring | |
223 | // wxNUM_VAL_ZERO_AS_BLANK flag. | |
224 | wxString NormalizeValue(LongestValueType value) const | |
225 | { | |
226 | wxString s; | |
227 | if ( value != 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) | |
df04f800 | 228 | s = this->ToString(value); |
a54cf371 VZ |
229 | |
230 | return s; | |
231 | } | |
232 | ||
233 | ||
234 | ValueType * const m_value; | |
235 | ||
236 | wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator); | |
237 | }; | |
238 | ||
239 | } // namespace wxPrivate | |
240 | ||
241 | // ---------------------------------------------------------------------------- | |
242 | // Validators for integer numbers. | |
243 | // ---------------------------------------------------------------------------- | |
244 | ||
245 | // Base class for integer numbers validator. This class contains all non | |
246 | // type-dependent code of wxIntegerValidator<> and always works with values of | |
247 | // type LongestValueType. It is not meant to be used directly, please use | |
248 | // wxIntegerValidator<> only instead. | |
249 | class WXDLLIMPEXP_CORE wxIntegerValidatorBase : public wxNumValidatorBase | |
250 | { | |
251 | protected: | |
252 | // Define the type we use here, it should be the maximal-sized integer type | |
253 | // we support to make it possible to base wxIntegerValidator<> for any type | |
254 | // on it. | |
255 | #ifdef wxLongLong_t | |
256 | typedef wxLongLong_t LongestValueType; | |
257 | #else | |
258 | typedef long LongestValueType; | |
259 | #endif | |
260 | ||
261 | wxIntegerValidatorBase(int style) | |
262 | : wxNumValidatorBase(style) | |
263 | { | |
264 | wxASSERT_MSG( !(style & wxNUM_VAL_NO_TRAILING_ZEROES), | |
265 | "This style doesn't make sense for integers." ); | |
266 | } | |
267 | ||
268 | wxIntegerValidatorBase(const wxIntegerValidatorBase& other) | |
269 | : wxNumValidatorBase(other) | |
270 | { | |
271 | m_min = other.m_min; | |
272 | m_max = other.m_max; | |
273 | } | |
274 | ||
275 | // Provide methods for wxNumValidator use. | |
276 | wxString ToString(LongestValueType value) const; | |
277 | static bool FromString(const wxString& s, LongestValueType *value); | |
278 | ||
279 | void DoSetMin(LongestValueType min) { m_min = min; } | |
280 | void DoSetMax(LongestValueType max) { m_max = max; } | |
281 | ||
282 | bool IsInRange(LongestValueType value) const | |
283 | { | |
284 | return m_min <= value && value <= m_max; | |
285 | } | |
286 | ||
287 | // Implement wxNumValidatorBase pure virtual method. | |
288 | virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; | |
289 | ||
290 | private: | |
291 | // Minimal and maximal values accepted (inclusive). | |
292 | LongestValueType m_min, m_max; | |
293 | ||
294 | wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase); | |
295 | }; | |
296 | ||
297 | // Validator for integer numbers. It can actually work with any integer type | |
298 | // (short, int or long and long long if supported) and their unsigned versions | |
299 | // as well. | |
300 | template <typename T> | |
301 | class wxIntegerValidator | |
302 | : public wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> | |
303 | { | |
304 | public: | |
305 | typedef T ValueType; | |
306 | ||
307 | typedef | |
308 | wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> Base; | |
309 | ||
310 | // Ctor for an integer validator. | |
311 | // | |
312 | // Sets the range appropriately for the type, including setting 0 as the | |
313 | // minimal value for the unsigned types. | |
314 | wxIntegerValidator(ValueType *value = NULL, int style = wxNUM_VAL_DEFAULT) | |
315 | : Base(value, style) | |
316 | { | |
df04f800 SC |
317 | this->DoSetMin(std::numeric_limits<ValueType>::min()); |
318 | this->DoSetMax(std::numeric_limits<ValueType>::max()); | |
a54cf371 VZ |
319 | } |
320 | ||
321 | virtual wxObject *Clone() const { return new wxIntegerValidator(*this); } | |
322 | ||
323 | private: | |
324 | wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator); | |
325 | }; | |
326 | ||
327 | // Helper function for creating integer validators which allows to avoid | |
328 | // explicitly specifying the type as it deduces it from its parameter. | |
329 | template <typename T> | |
330 | inline wxIntegerValidator<T> | |
331 | wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT) | |
332 | { | |
333 | return wxIntegerValidator<T>(value, style); | |
334 | } | |
335 | ||
336 | // ---------------------------------------------------------------------------- | |
337 | // Validators for floating point numbers. | |
338 | // ---------------------------------------------------------------------------- | |
339 | ||
340 | // Similar to wxIntegerValidatorBase, this class is not meant to be used | |
341 | // directly, only wxFloatingPointValidator<> should be used in the user code. | |
342 | class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase : public wxNumValidatorBase | |
343 | { | |
344 | public: | |
345 | // Set precision i.e. the number of digits shown (and accepted on input) | |
346 | // after the decimal point. By default this is set to the maximal precision | |
347 | // supported by the type handled by the validator. | |
348 | void SetPrecision(unsigned precision) { m_precision = precision; } | |
349 | ||
350 | protected: | |
351 | // Notice that we can't use "long double" here because it's not supported | |
352 | // by wxNumberFormatter yet, so restrict ourselves to just double (and | |
353 | // float). | |
354 | typedef double LongestValueType; | |
355 | ||
356 | wxFloatingPointValidatorBase(int style) | |
357 | : wxNumValidatorBase(style) | |
358 | { | |
359 | } | |
360 | ||
361 | wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase& other) | |
362 | : wxNumValidatorBase(other) | |
363 | { | |
364 | m_precision = other.m_precision; | |
365 | ||
366 | m_min = other.m_min; | |
367 | m_max = other.m_max; | |
368 | } | |
369 | ||
370 | // Provide methods for wxNumValidator use. | |
371 | wxString ToString(LongestValueType value) const; | |
372 | static bool FromString(const wxString& s, LongestValueType *value); | |
373 | ||
374 | void DoSetMin(LongestValueType min) { m_min = min; } | |
375 | void DoSetMax(LongestValueType max) { m_max = max; } | |
376 | ||
377 | bool IsInRange(LongestValueType value) const | |
378 | { | |
379 | return m_min <= value && value <= m_max; | |
380 | } | |
381 | ||
382 | // Implement wxNumValidatorBase pure virtual method. | |
383 | virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; | |
384 | ||
385 | private: | |
386 | // Maximum number of decimals digits after the decimal separator. | |
387 | unsigned m_precision; | |
388 | ||
389 | // Minimal and maximal values accepted (inclusive). | |
390 | LongestValueType m_min, m_max; | |
391 | ||
392 | wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase); | |
393 | }; | |
394 | ||
395 | // Validator for floating point numbers. It can be used with float, double or | |
396 | // long double values. | |
397 | template <typename T> | |
398 | class wxFloatingPointValidator | |
399 | : public wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> | |
400 | { | |
401 | public: | |
402 | typedef T ValueType; | |
403 | typedef wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> Base; | |
404 | ||
405 | // Ctor using implicit (maximal) precision for this type. | |
406 | wxFloatingPointValidator(ValueType *value = NULL, | |
407 | int style = wxNUM_VAL_DEFAULT) | |
408 | : Base(value, style) | |
409 | { | |
410 | DoSetMinMax(); | |
411 | ||
f5f3d4ec | 412 | this->SetPrecision(std::numeric_limits<ValueType>::digits10); |
a54cf371 VZ |
413 | } |
414 | ||
415 | // Ctor specifying an explicit precision. | |
416 | wxFloatingPointValidator(int precision, | |
417 | ValueType *value = NULL, | |
418 | int style = wxNUM_VAL_DEFAULT) | |
419 | : Base(value, style) | |
420 | { | |
421 | DoSetMinMax(); | |
422 | ||
423 | this->SetPrecision(precision); | |
424 | } | |
425 | ||
426 | virtual wxObject *Clone() const | |
427 | { | |
428 | return new wxFloatingPointValidator(*this); | |
429 | } | |
430 | ||
431 | private: | |
432 | void DoSetMinMax() | |
433 | { | |
434 | // NB: Do not use min(), it's not the smallest representable value for | |
435 | // the floating point types but rather the smallest representable | |
436 | // positive value. | |
df04f800 SC |
437 | this->DoSetMin(-std::numeric_limits<ValueType>::max()); |
438 | this->DoSetMax( std::numeric_limits<ValueType>::max()); | |
a54cf371 VZ |
439 | } |
440 | }; | |
441 | ||
442 | // Helper similar to wxMakeIntValidator(). | |
443 | // | |
444 | // NB: Unfortunately we can't just have a wxMakeNumericValidator() which would | |
445 | // return either wxIntegerValidator<> or wxFloatingPointValidator<> so we | |
446 | // do need two different functions. | |
447 | template <typename T> | |
448 | inline wxFloatingPointValidator<T> | |
449 | wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT) | |
450 | { | |
451 | return wxFloatingPointValidator<T>(value, style); | |
452 | } | |
453 | ||
454 | template <typename T> | |
455 | inline wxFloatingPointValidator<T> | |
456 | wxMakeFloatingPointValidator(int precision, T *value, int style = wxNUM_VAL_DEFAULT) | |
457 | { | |
458 | return wxFloatingPointValidator<T>(precision, value, style); | |
459 | } | |
460 | ||
461 | #endif // wxUSE_VALIDATORS | |
462 | ||
463 | #endif // _WX_VALNUM_H_ |