37#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL
40 #include <wx/textctrl.h>
41 #include <wx/combobox.h>
44#include <wx/clipbrd.h>
45#include <wx/dataobj.h>
53BEGIN_EVENT_TABLE(NumValidatorBase, wxValidator)
54 EVT_CHAR(NumValidatorBase::OnChar)
56 EVT_KILL_FOCUS(NumValidatorBase::OnKillFocus)
59int NumValidatorBase::GetFormatFlags()
const
62 if ( m_style & NumValidatorStyle::THOUSANDS_SEPARATOR )
64 if ( m_style & NumValidatorStyle::NO_TRAILING_ZEROES )
66 if ( m_style & NumValidatorStyle::ONE_TRAILING_ZERO )
68 if ( m_style & NumValidatorStyle::TWO_TRAILING_ZEROES )
70 if ( m_style & NumValidatorStyle::THREE_TRAILING_ZEROES )
76wxTextEntry *NumValidatorBase::GetTextEntry()
const
79 if ( wxTextCtrl *text = wxDynamicCast(m_validatorWindow, wxTextCtrl) )
84 if ( wxComboBox *combo = wxDynamicCast(m_validatorWindow, wxComboBox) )
88 wxFAIL_MSG(
wxT(
"Can only be used with wxTextCtrl or wxComboBox"));
93bool NumValidatorBase::Validate(wxWindow *parent)
96 if ( !m_validatorWindow->IsEnabled() )
100 bool res = DoValidateNumber(&errmsg);
106 XO(
"Validation error"),
109 wxTextEntry *te = GetTextEntry();
113 m_validatorWindow->SetFocus();
122NumValidatorBase::GetCurrentValueAndInsertionPoint(wxString& val,
125 wxTextEntry *
const control = GetTextEntry();
129 val = control->GetValue();
130 pos = control->GetInsertionPoint();
133 control->GetSelection(&selFrom, &selTo);
135 const long selLen = selTo - selFrom;
139 val.erase(selFrom, selLen);
153bool NumValidatorBase::IsMinusOk(
const wxString& val,
int pos)
const
160 if ( !val.empty() && val[0] ==
'-' )
166void NumValidatorBase::OnChar(wxKeyEvent& event)
172 if ( !m_validatorWindow )
176 const int ch =
event.GetUnicodeKey();
177 const int c =
event.GetKeyCode();
185 const int ch =
event.GetKeyCode();
187 if ( ch > WXK_DELETE )
196 if ( c < WXK_SPACE || c == WXK_DELETE )
205 GetCurrentValueAndInsertionPoint(val, pos);
207 if ( !IsCharOk(val, pos, ch) )
209 if ( !wxValidator::IsSilent() )
221 wxTextEntry *
const control = GetTextEntry();
227 wxClipboardLocker cb;
234 wxTextDataObject data;
240 wxString toPaste = data.GetText();
243 GetCurrentValueAndInsertionPoint(val, pos);
245 for (
size_t i = 0, cnt = toPaste.length(); i < cnt; i++)
247 const wxChar ch = toPaste[i];
250 if ( IsCharOk(val, pos, ch) )
252 val = GetValueAfterInsertingChar(val, pos++, ch);
254 else if ( !wxValidator::IsSilent() )
266 wxTextCtrl *
const text = wxDynamicCast(m_validatorWindow, wxTextCtrl);
267 const bool wasModified = text ? text->IsModified() :
false;
270 control->SetValue(NormalizeString(val));
278void NumValidatorBase::OnKillFocus(wxFocusEvent& event)
280 wxTextEntry *
const control = GetTextEntry();
290 wxTextCtrl *
const text = wxDynamicCast(m_validatorWindow, wxTextCtrl);
291 const bool wasModified = text ? text->IsModified() :
false;
293 control->ChangeValue(NormalizeString(control->GetValue()));
313IntegerValidatorBase::FromString(
const wxString& s, LongestValueType *value)
319IntegerValidatorBase::IsCharOk(
const wxString& val,
int pos, wxChar ch)
const
333 return m_min < 0 && IsMinusOk(val, pos);
337 if ( ch < '0' || ch >
'9' )
356 wxTextEntry *
const control = GetTextEntry();
360 wxString s(control->GetValue());
363 s.Replace(wxString(thousandsSep), wxString());
368 if ( HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
375 *errMsg =
XO(
"Empty value");
381 LongestValueType value = 0;
382 bool res = FromString(s, &value);
384 *errMsg =
XO(
"Malformed number");
387 res = IsInRange(value);
390 *errMsg =
XO(
"Not in range %d to %d")
391 .Format( (
int) m_min, (
int) m_max );
393 if ( value > (
int) m_max )
394 control->ChangeValue( wxString::Format(
wxT(
"%d"), (
int) m_max ) );
395 else if ( value < (
int) m_min )
396 control->ChangeValue( wxString::Format(
wxT(
"%d"), (
int) m_min ) );
413FloatingPointValidatorBase::FromString(
const wxString& s,
414 LongestValueType *value)
420FloatingPointValidatorBase::IsCharOk(
const wxString& val,
428 return m_min < 0 && IsMinusOk(val, pos);
430 else if ( val[pos-1] !=
'e' && val[pos-1] !=
'E' )
435 else if ( ch ==
'+' )
439 else if ( val[pos-1] !=
'e' && val[pos-1] !=
'E' )
446 if ( ch == separator )
455 if ( pos == 0 && !val.empty() && ( val[0] ==
'-' || val[0] ==
'+' ) )
467 if( ( ch < '0' || ch >
'9' ) && ch !=
'E' && ch !=
'e' )
484 return ValidatePrecision(
str);
489 wxTextEntry *
const control = GetTextEntry();
493 wxString s(control->GetValue());
496 s.Replace(wxString(thousandsSep), wxString());
500 if ( HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
504 *errMsg =
XO(
"Empty value");
509 LongestValueType value = 0;
510 bool res = FromString(s, &value);
512 *errMsg =
XO(
"Value overflow");
515 res = ValidatePrecision(s);
517 *errMsg =
XO(
"Too many decimal digits");
520 res = IsInRange(value);
523 wxString strMin = wxString::Format(
wxT(
"%f"), m_min);
524 wxString strMax = wxString::Format(
wxT(
"%f"), m_max);
528 if (m_minSet && m_maxSet)
530 *errMsg =
XO(
"Value not in range: %s to %s")
531 .Format( strMin, strMax );
534 control->ChangeValue( strMax );
535 else if ( value < m_min )
536 control->ChangeValue( strMin );
540 *errMsg =
XO(
"Value must not be less than %s").Format( strMin );
544 *errMsg =
XO(
"Value must not be greater than %s")
554bool FloatingPointValidatorBase::ValidatePrecision(
const wxString& s)
const
565 size_t posExp = s.Lower().Find(
"e");
570 return ( (
int)(posExp - posSep) - 1 <= (
int)m_precision );
573double RoundValue(
int precision,
double value)
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Holds a msgid for the translation catalog; may also bind format arguments.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
auto ToString(const std::optional< TimeSignature > &ts)
constexpr size_t npos(-1)