Audacity 3.2.0
valnum.h
Go to the documentation of this file.
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 <[email protected]>
8// Licence: wxWindows licence
10
11#ifndef _WIDGETS_VALNUM_H_
12#define _WIDGETS_VALNUM_H_
13
14#include <memory>
15#include <wx/setup.h> // for wxUSE_* macros
16#include <wx/defs.h>
17
18#if wxUSE_VALIDATORS
19
20#include <wx/textctrl.h> // complete type needed in template function
21#include <wx/validate.h> // to inherit
22
23#include <limits>
24
26
27// Bit masks used for numeric validator styles.
28enum class NumValidatorStyle : int
29{
30 DEFAULT = 0x0,
31 THOUSANDS_SEPARATOR = 0x1,
32 ZERO_AS_BLANK = 0x2,
33 NO_TRAILING_ZEROES = 0x4,
34 ONE_TRAILING_ZERO = 0x8,
35 TWO_TRAILING_ZEROES = 0x10,
36 THREE_TRAILING_ZEROES = 0x20
37};
38
39inline NumValidatorStyle operator | (NumValidatorStyle x, NumValidatorStyle y)
40{ return NumValidatorStyle( int(x) | int(y) ); }
41
42inline int operator & (NumValidatorStyle x, NumValidatorStyle y)
43{ return int(x) & int(y); }
44
45// ----------------------------------------------------------------------------
46// Base class for all numeric validators.
47// ----------------------------------------------------------------------------
48
49class AUDACITY_DLL_API NumValidatorBase /* not final */ : public wxValidator
50{
51public:
52 // Change the validator style. Usually it's specified during construction.
53 void SetStyle(NumValidatorStyle style) { m_style = style; }
54
55 // Called when the value in the window must be validated.
56 // This function can pop up an error message.
57 bool Validate(wxWindow * parent) override;
58
59protected:
60 NumValidatorBase(NumValidatorStyle style)
61 {
62 m_style = style;
63 m_minSet = false;
64 m_maxSet = false;
65 }
66
67 NumValidatorBase(const NumValidatorBase& other) : wxValidator()
68 {
69 m_style = other.m_style;
70 m_minSet = other.m_minSet;
71 m_maxSet = other.m_maxSet;
72 }
73
74 bool HasFlag(NumValidatorStyle style) const
75 {
76 return (m_style & style) != 0;
77 }
78
79 // Get the text entry of the associated control. Normally shouldn't ever
80 // return NULL (and will assert if it does return it) but the caller should
81 // still test the return value for safety.
82 wxTextEntry *GetTextEntry() const;
83
84 // Convert NumValidatorStyle::THOUSANDS_SEPARATOR and NumValidatorStyle::NO_TRAILING_ZEROES
85 // bits of our style to the corresponding NumberFormatter::Style values.
86 int GetFormatFlags() const;
87
88 // Return true if pressing a '-' key is acceptable for the current control
89 // contents and insertion point. This is meant to be called from the
90 // derived class IsCharOk() implementation.
91 bool IsMinusOk(const wxString& val, int pos) const;
92
93 // Return the string which would result from inserting the given character
94 // at the specified position.
95 wxString GetValueAfterInsertingChar(const wxString &valArg, int pos, wxChar ch) const
96 {
97 wxString val(valArg);
98 val.insert(pos, ch);
99 return val;
100 }
101
102 bool m_minSet;
103 bool m_maxSet;
104
105private:
106 // Check whether the specified character can be inserted in the control at
107 // the given position in the string representing the current controls
108 // contents.
109 //
110 // Notice that the base class checks for '-' itself so it's never passed to
111 // this function.
112 virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0;
113
114 // NormalizeString the contents of the string if it's a valid number, return
115 // empty string otherwise.
116 virtual wxString NormalizeString(const wxString& s) const = 0;
117
118 // Do all checks to ensure this is a valid value.
119 // Returns 'true' if the control has valid value.
120 // Otherwise the cause is indicated in 'errMsg'.
121 virtual bool DoValidateNumber(TranslatableString * errMsg) const = 0;
122
123 // Event handlers.
124 void OnChar(wxKeyEvent& event);
125 void OnPaste(wxClipboardTextEvent& event);
126 void OnKillFocus(wxFocusEvent& event);
127
128
129 // Determine the current insertion point and text in the associated control.
130 void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;
131
132
133 // Combination of wxVAL_NUM_XXX values.
134 NumValidatorStyle m_style;
135
136 DECLARE_EVENT_TABLE()
137
138 DECLARE_NO_ASSIGN_CLASS(NumValidatorBase)
139};
140
141namespace Private
142{
143
144// This is a helper class used by IntegerValidator and FloatingPointValidator
145// below that implements Transfer{To,From}Window() adapted to the type of the
146// variable.
147//
148// The template argument B is the name of the base class which must derive from
149// NumValidatorBase and define LongestValueType type and {To,As}String()
150// methods i.e. basically be one of {Integer,Number}ValidatorBase classes.
151//
152// The template argument T is just the type handled by the validator that will
153// inherit from this one.
154template <class B, typename T>
155class NumValidator /* final */ : public B
156{
157public:
158 typedef B BaseValidator;
159 typedef T ValueType;
160
161 typedef typename BaseValidator::LongestValueType LongestValueType;
162
163 // FIXME-VC6: This compiler fails to compile the assert below with a
164 // nonsensical error C2248: "'LongestValueType' : cannot access protected
165 // typedef declared in class 'IntegerValidatorBase'" so just disable the
166 // check for it.
167#ifndef __VISUALC6__
168 wxCOMPILE_TIME_ASSERT
169 (
170 sizeof(ValueType) <= sizeof(LongestValueType),
171 UnsupportedType
172 );
173#endif // __VISUALC6__
174
175 void SetMin(ValueType min)
176 {
177 this->DoSetMin(min);
178 BaseValidator::m_minSet = (min != std::numeric_limits<T>::lowest());
179 }
180
181 void SetMax(ValueType max)
182 {
183 this->DoSetMax(max);
184 BaseValidator::m_maxSet = (max != std::numeric_limits<T>::max());
185 }
186
187 void SetRange(ValueType min, ValueType max)
188 {
189 SetMin(min);
190 SetMax(max);
191 }
192
193 bool TransferToWindow() override
194 {
195 if ( m_value )
196 {
197 wxTextEntry * const control = BaseValidator::GetTextEntry();
198 if ( !control )
199 return false;
200
201 control->ChangeValue(NormalizeValue(*m_value));
202 }
203
204 return true;
205 }
206
207 bool TransferFromWindow() override
208 {
209 if ( m_value )
210 {
211 wxTextEntry * const control = BaseValidator::GetTextEntry();
212 if ( !control )
213 return false;
214
215 // If window is disabled, simply return
216 if ( !this->m_validatorWindow->IsEnabled() )
217 return true;
218
219 const wxString s(control->GetValue());
220 LongestValueType value;
221 if ( s.empty() && BaseValidator::HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
222 value = 0;
223 else if ( !BaseValidator::FromString(s, &value) )
224 return false;
225
226 if ( !this->IsInRange(value) )
227 return false;
228
229 *m_value = static_cast<ValueType>(value);
230 }
231
232 return true;
233 }
234
235protected:
236 NumValidator(ValueType *value, NumValidatorStyle style)
237 : BaseValidator(style),
238 m_value(value)
239 {
240 }
241
242 // Implement NumValidatorBase virtual method which is the same for
243 // both integer and floating point numbers.
244 wxString NormalizeString(const wxString& s) const override
245 {
246 LongestValueType value;
247 return BaseValidator::FromString(s, &value) ? NormalizeValue(value)
248 : wxString();
249 }
250
251private:
252 // Just a helper which is a common part of TransferToWindow() and
253 // NormalizeString(): returns string representation of a number honouring
254 // NumValidatorStyle::ZERO_AS_BLANK flag.
255 wxString NormalizeValue(LongestValueType value) const
256 {
257 wxString s;
258 if ( value != 0 || !BaseValidator::HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
259 s = this->ToString(value);
260
261 return s;
262 }
263
264
265 ValueType * const m_value;
266
267 DECLARE_NO_ASSIGN_CLASS(NumValidator)
268};
269
270} // namespace Private
271
272// ----------------------------------------------------------------------------
273// Validators for integer numbers.
274// ----------------------------------------------------------------------------
275
276// Base class for integer numbers validator. This class contains all non
277// type-dependent code of wxIntegerValidator<> and always works with values of
278// type LongestValueType. It is not meant to be used directly, please use
279// IntegerValidator<> only instead.
280class AUDACITY_DLL_API IntegerValidatorBase /* not final */
281 : public NumValidatorBase
282{
283protected:
284 // Define the type we use here, it should be the maximal-sized integer type
285 // we support to make it possible to base IntegerValidator<> for any type
286 // on it.
287#ifdef wxLongLong_t
288 typedef wxLongLong_t LongestValueType;
289#else
290 typedef long LongestValueType;
291#endif
292
293 IntegerValidatorBase(NumValidatorStyle style)
294 : NumValidatorBase(style)
295 {
296 wxASSERT_MSG( !(style & NumValidatorStyle::NO_TRAILING_ZEROES),
297 wxT("This style doesn't make sense for integers.") );
298 wxASSERT_MSG( !(style & NumValidatorStyle::ONE_TRAILING_ZERO),
299 wxT("This style doesn't make sense for integers.") );
300 wxASSERT_MSG( !(style & NumValidatorStyle::TWO_TRAILING_ZEROES),
301 wxT("This style doesn't make sense for integers.") );
302 wxASSERT_MSG( !(style & NumValidatorStyle::THREE_TRAILING_ZEROES),
303 wxT("This style doesn't make sense for integers.") );
304 }
305
306 IntegerValidatorBase(const IntegerValidatorBase& other)
307 : NumValidatorBase(other)
308 {
309 m_min = other.m_min;
310 m_max = other.m_max;
311 }
312
313 // Provide methods for NumValidator use.
314 wxString ToString(LongestValueType value) const;
315 static bool FromString(const wxString& s, LongestValueType *value);
316
317 void DoSetMin(LongestValueType min) { m_min = min; }
318 void DoSetMax(LongestValueType max) { m_max = max; }
319
320 bool IsInRange(LongestValueType value) const
321 {
322 return m_min <= value && value <= m_max;
323 }
324
325 // Implement NumValidatorBase pure virtual method.
326 bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;
327 bool DoValidateNumber(TranslatableString * errMsg) const override;
328
329private:
330 // Minimal and maximal values accepted (inclusive).
331 LongestValueType m_min, m_max;
332
333 DECLARE_NO_ASSIGN_CLASS(IntegerValidatorBase)
334};
335
336// Validator for integer numbers. It can actually work with any integer type
337// (short, int or long and long long if supported) and their unsigned versions
338// as well.
339template <typename T>
340class IntegerValidator final
341 : public Private::NumValidator<IntegerValidatorBase, T>
342{
343public:
344 typedef T ValueType;
345
346 typedef
347 Private::NumValidator<IntegerValidatorBase, T> Base;
348
349 // Ctor for an integer validator.
350 //
351 // Sets the range appropriately for the type, including setting 0 as the
352 // minimal value for the unsigned types.
353 IntegerValidator(
354 ValueType *value = NULL,
355 NumValidatorStyle style = NumValidatorStyle::DEFAULT,
357 ValueType max = std::numeric_limits<ValueType>::max())
358 : Base(value, style)
359 {
360 this->SetRange(min, max);
361 }
362
363 // Clone is required by wxwidgets; implemented via copy constructor
364 wxObject *Clone() const override { return safenew IntegerValidator(*this); }
365
366private:
367 DECLARE_NO_ASSIGN_CLASS(IntegerValidator)
368};
369
370// Helper function for creating integer validators which allows to avoid
371// explicitly specifying the type as it deduces it from its parameter.
372template <typename T>
373inline IntegerValidator<T>
374MakeIntegerValidator(T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
375{
376 return IntegerValidator<T>(value, style);
377}
378
379// ----------------------------------------------------------------------------
380// Validators for floating point numbers.
381// ----------------------------------------------------------------------------
382
383// Similar to IntegerValidatorBase, this class is not meant to be used
384// directly, only FloatingPointValidator<> should be used in the user code.
385class AUDACITY_DLL_API FloatingPointValidatorBase /* not final */
386 : public NumValidatorBase
387{
388public:
389 // Set precision i.e. the number of digits shown (and accepted on input)
390 // after the decimal point. By default this is set to the maximal precision
391 // supported by the type handled by the validator.
392 void SetPrecision(unsigned precision) { m_precision = precision; }
393
394protected:
395 // Notice that we can't use "long double" here because it's not supported
396 // by NumberFormatter yet, so restrict ourselves to just double (and
397 // float).
398 typedef double LongestValueType;
399
400 FloatingPointValidatorBase(NumValidatorStyle style)
401 : NumValidatorBase(style)
402 {
403 }
404
405 FloatingPointValidatorBase(const FloatingPointValidatorBase& other)
406 : NumValidatorBase(other)
407 {
408 m_precision = other.m_precision;
409
410 m_min = other.m_min;
411 m_max = other.m_max;
412 }
413
414 // Provide methods for NumValidator use.
415 wxString ToString(LongestValueType value) const;
416 static bool FromString(const wxString& s, LongestValueType *value);
417
418 void DoSetMin(LongestValueType min) { m_min = min; }
419 void DoSetMax(LongestValueType max) { m_max = max; }
420
421 bool IsInRange(LongestValueType value) const
422 {
423 return m_min <= value && value <= m_max;
424 }
425
426 // Implement NumValidatorBase pure virtual method.
427 bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;
428 bool DoValidateNumber(TranslatableString * errMsg) const override;
429
430 //Checks that it doesn't have too many decimal digits.
431 bool ValidatePrecision(const wxString& s) const;
432
433private:
434 // Maximum number of decimals digits after the decimal separator.
435 unsigned m_precision;
436
437 // Minimal and maximal values accepted (inclusive).
438 LongestValueType m_min, m_max;
439
440 DECLARE_NO_ASSIGN_CLASS(FloatingPointValidatorBase)
441};
442
443// Validator for floating point numbers. It can be used with float, double or
444// long double values.
445template <typename T>
446class FloatingPointValidator final
447 : public Private::NumValidator<FloatingPointValidatorBase, T>
448{
449public:
450 typedef T ValueType;
451 typedef Private::NumValidator<FloatingPointValidatorBase, T> Base;
452
453 // Ctor using implicit (maximal) precision for this type.
454 FloatingPointValidator(ValueType *value = NULL,
455 NumValidatorStyle style = NumValidatorStyle::DEFAULT)
456 : Base(value, style)
457 {
458 DoSetMinMax();
459
460 this->SetPrecision(std::numeric_limits<ValueType>::digits10);
461 }
462
463 // Ctor specifying an explicit precision.
464 FloatingPointValidator(int precision,
465 ValueType *value = NULL,
466 NumValidatorStyle style = NumValidatorStyle::DEFAULT,
467 ValueType min = std::numeric_limits<ValueType>::lowest(),
468 ValueType max = std::numeric_limits<ValueType>::max())
469 : Base(value, style)
470 {
471 this->SetRange( min, max );
472
473 this->SetPrecision(precision);
474 }
475
476 // Clone is required by wxwidgets; implemented via copy constructor
477 wxObject *Clone() const override
478 {
479 return safenew FloatingPointValidator(*this);
480 }
481
482private:
483 void DoSetMinMax()
484 {
485 // NB: Do not use min(), it's not the smallest representable value for
486 // the floating point types but rather the smallest representable
487 // positive value.
488 this->DoSetMin( std::numeric_limits<ValueType>::lowest());
489 this->DoSetMax( std::numeric_limits<ValueType>::max());
490 }
491};
492
493// Helper similar to MakeIntValidator().
494//
495// NB: Unfortunately we can't just have a MakeNumericValidator() which would
496// return either IntegerValidator<> or FloatingPointValidator<> so we
497// do need two different functions.
498template <typename T>
499inline FloatingPointValidator<T>
500MakeFloatingPointValidator(T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
501{
502 return FloatingPointValidator<T>(value, style);
503}
504
505template <typename T>
506inline FloatingPointValidator<T>
507MakeFloatingPointValidator(int precision, T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
508{
509 return FloatingPointValidator<T>(precision, value, style);
510}
511
512// Sometimes useful for specifying max and min values for validators, when they
513// must have the same precision as the validated value
514AUDACITY_DLL_API double RoundValue(int precision, double value);
515
516#endif // wxUSE_VALIDATORS
517
518#endif // _WIDGETS_VALNUM_H_
wxT("CloseDown"))
int min(int a, int b)
#define safenew
Definition: MemoryX.h:9
UndoPush operator&(UndoPush a, UndoPush b)
Definition: UndoManager.h:146
UndoPush operator|(UndoPush a, UndoPush b)
Definition: UndoManager.h:144
Holds a msgid for the translation catalog; may also bind format arguments.
auto ToString(const std::optional< TimeSignature > &ts)
void OnPaste(const CommandContext &context)
Definition: EditMenus.cpp:526