diff --git a/aegisub/src/auto4_lua_dialog.cpp b/aegisub/src/auto4_lua_dialog.cpp index 7fb161f20..6db096ee3 100644 --- a/aegisub/src/auto4_lua_dialog.cpp +++ b/aegisub/src/auto4_lua_dialog.cpp @@ -328,8 +328,7 @@ namespace Automation4 { return scd; } - wxFloatingPointValidator val(4, &value, wxNUM_VAL_NO_TRAILING_ZEROES); - val.SetRange(min, max); + ::DoubleValidator val(&value, min, max); cw = new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, 0, val); cw->SetToolTip(to_wx(hint)); diff --git a/aegisub/src/dialog_dummy_video.cpp b/aegisub/src/dialog_dummy_video.cpp index 09c45fba1..d98e86037 100644 --- a/aegisub/src/dialog_dummy_video.cpp +++ b/aegisub/src/dialog_dummy_video.cpp @@ -39,6 +39,7 @@ #include "help_button.h" #include "libresrc/libresrc.h" #include "options.h" +#include "validators.h" #include "video_provider_dummy.h" namespace { @@ -68,9 +69,7 @@ wxSpinCtrl *spin_ctrl(wxWindow *parent, int min, int max, int *value) { } wxControl *spin_ctrl(wxWindow *parent, double min, double max, double *value) { - wxFloatingPointValidator val(4, value); - val.SetRange(min, max); - return new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxSize(50, -1), 0, val); + return new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxSize(50, -1), 0, DoubleValidator(value, min, max)); } wxComboBox *resolution_shortcuts(wxWindow *parent, int width, int height) { diff --git a/aegisub/src/dialog_jumpto.cpp b/aegisub/src/dialog_jumpto.cpp index e28615dd4..2b02c9c6d 100644 --- a/aegisub/src/dialog_jumpto.cpp +++ b/aegisub/src/dialog_jumpto.cpp @@ -58,7 +58,7 @@ DialogJumpTo::DialogJumpTo(agi::Context *c) auto LabelFrame = new wxStaticText(this, -1, _("Frame: ")); auto LabelTime = new wxStaticText(this, -1, _("Time: ")); - JumpFrame = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(-1,-1),wxTE_PROCESS_ENTER, NumValidator((int)jumpframe)); + JumpFrame = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(-1,-1),wxTE_PROCESS_ENTER, IntValidator((int)jumpframe)); JumpFrame->SetMaxLength(std::to_string(c->videoController->GetLength() - 1).size()); JumpTime = new TimeEdit(this, -1, c, AssTime(c->videoController->TimeAtFrame(jumpframe)).GetAssFormated(), wxSize(-1,-1)); diff --git a/aegisub/src/dialog_properties.cpp b/aegisub/src/dialog_properties.cpp index da3d58d06..a336fce85 100644 --- a/aegisub/src/dialog_properties.cpp +++ b/aegisub/src/dialog_properties.cpp @@ -78,8 +78,8 @@ DialogProperties::DialogProperties(agi::Context *c) // Resolution box wxSizer *ResSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Resolution")); - ResX = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(50,20),0,NumValidator(to_wx(c->ass->GetScriptInfo("PlayResX")))); - ResY = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(50,20),0,NumValidator(to_wx(c->ass->GetScriptInfo("PlayResY")))); + ResX = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(50,20),0,IntValidator(c->ass->GetScriptInfo("PlayResX"))); + ResY = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(50,20),0,IntValidator(c->ass->GetScriptInfo("PlayResY"))); wxStaticText *ResText = new wxStaticText(this,-1,"x"); wxButton *FromVideo = new wxButton(this,-1,_("From &video")); diff --git a/aegisub/src/dialog_style_editor.cpp b/aegisub/src/dialog_style_editor.cpp index 21c1f2cb4..b2f68c01c 100644 --- a/aegisub/src/dialog_style_editor.cpp +++ b/aegisub/src/dialog_style_editor.cpp @@ -135,8 +135,8 @@ static wxSpinCtrl *spin_ctrl(wxWindow *parent, float value, int max_value) { return new wxSpinCtrl(parent, -1, wxString::Format("%g", value), wxDefaultPosition, wxSize(60, -1), wxSP_ARROW_KEYS, 0, max_value, value); } -static wxTextCtrl *num_text_ctrl(wxWindow *parent, double value, bool allow_negative, wxSize size = wxSize(70, 20)) { - return new wxTextCtrl(parent, -1, "", wxDefaultPosition, size, 0, NumValidator(value, allow_negative)); +static wxTextCtrl *num_text_ctrl(wxWindow *parent, double *value, bool allow_negative, wxSize size = wxSize(70, 20)) { + return new wxTextCtrl(parent, -1, "", wxDefaultPosition, size, 0, DoubleValidator(value, allow_negative)); } DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Context *c, AssStyleStorage *store, std::string const& new_name, wxArrayString const& font_list) @@ -180,7 +180,7 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con // Create controls StyleName = new wxTextCtrl(this, -1, to_wx(style->name)); FontName = new wxComboBox(this, -1, to_wx(style->font), wxDefaultPosition, wxSize(150, -1), 0, 0, wxCB_DROPDOWN); - FontSize = num_text_ctrl(this, style->fontsize, false, wxSize(50, -1)); + FontSize = num_text_ctrl(this, &work->fontsize, false, wxSize(50, -1)); BoxBold = new wxCheckBox(this, -1, _("&Bold")); BoxItalic = new wxCheckBox(this, -1, _("&Italic")); BoxUnderline = new wxCheckBox(this, -1, _("&Underline")); @@ -194,13 +194,13 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con for (int i = 0; i < 3; i++) margin[i] = spin_ctrl(this, style->Margin[i], 9999); Alignment = new wxRadioBox(this, -1, _("Alignment"), wxDefaultPosition, wxDefaultSize, 9, alignValues, 3, wxRA_SPECIFY_COLS); - Outline = num_text_ctrl(this, style->outline_w, false, wxSize(50, -1)); - Shadow = num_text_ctrl(this, style->shadow_w, true, wxSize(50, -1)); + Outline = num_text_ctrl(this, &work->outline_w, false, wxSize(50, -1)); + Shadow = num_text_ctrl(this, &work->shadow_w, true, wxSize(50, -1)); OutlineType = new wxCheckBox(this, -1, _("&Opaque box")); - ScaleX = num_text_ctrl(this, style->scalex, false); - ScaleY = num_text_ctrl(this, style->scaley, false); - Angle = num_text_ctrl(this, style->angle, true); - Spacing = num_text_ctrl(this, style->spacing, true); + ScaleX = num_text_ctrl(this, &work->scalex, false); + ScaleY = num_text_ctrl(this, &work->scaley, false); + Angle = num_text_ctrl(this, &work->angle, true); + Spacing = num_text_ctrl(this, &work->spacing, true); Encoding = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize, encodingStrings, wxCB_READONLY); // Set control tooltips @@ -456,24 +456,16 @@ void DialogStyleEditor::Apply(bool apply, bool close) { } void DialogStyleEditor::UpdateWorkStyle() { - work->font = from_wx(FontName->GetValue()); - FontSize->GetValue().ToDouble(&(work->fontsize)); + TransferDataFromWindow(); - ScaleX->GetValue().ToDouble(&(work->scalex)); - ScaleY->GetValue().ToDouble(&(work->scaley)); + work->font = from_wx(FontName->GetValue()); long templ = 0; Encoding->GetValue().BeforeFirst('-').ToLong(&templ); work->encoding = templ; - Angle->GetValue().ToDouble(&(work->angle)); - Spacing->GetValue().ToDouble(&(work->spacing)); - work->borderstyle = OutlineType->IsChecked() ? 3 : 1; - Shadow->GetValue().ToDouble(&(work->shadow_w)); - Outline->GetValue().ToDouble(&(work->outline_w)); - work->alignment = ControlToAlign(Alignment->GetSelection()); for (size_t i = 0; i < 3; ++i) diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index bc13dd2f2..29d5a81cc 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -228,7 +228,7 @@ SubsEditBox::~SubsEditBox() { } wxTextCtrl *SubsEditBox::MakeMarginCtrl(wxString const& tooltip, int margin, wxString const& commit_msg) { - wxTextCtrl *ctrl = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxSize(40,-1), wxTE_CENTRE | wxTE_PROCESS_ENTER, NumValidator()); + wxTextCtrl *ctrl = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxSize(40,-1), wxTE_CENTRE | wxTE_PROCESS_ENTER, IntValidator()); ctrl->SetMaxLength(4); ctrl->SetToolTip(tooltip); middle_left_sizer->Add(ctrl, wxSizerFlags().Center()); diff --git a/aegisub/src/validators.cpp b/aegisub/src/validators.cpp index 41d9a19b7..37c442f2f 100644 --- a/aegisub/src/validators.cpp +++ b/aegisub/src/validators.cpp @@ -1,37 +1,19 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2013, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ -/// @file validators.cpp -/// @brief Various validators for wx -/// @ingroup custom_control utility -/// - #include "config.h" #include "validators.h" @@ -40,171 +22,142 @@ #include "utils.h" #include +#include #include #include -NumValidator::NumValidator(wxString val, bool isfloat, bool issigned) -: fValue(0) -, iValue(0) -, isFloat(isfloat) -, isSigned(issigned) +namespace { +std::string new_value(wxTextCtrl *ctrl, int chr) { + long from, to; + ctrl->GetSelection(&from, &to); + auto value = ctrl->GetValue(); + return from_wx(value.substr(0, from) + (wxChar)chr + value.substr(to)); +} + +wxChar decimal_separator() { + auto sep = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); + return sep.empty() ? '.' : sep[0]; +} +} + +IntValidator::IntValidator(std::string const& initial) +: allow_negative(false) { - if (isFloat) { - val.ToDouble(&fValue); - } - else { - long tLong = 0; - val.ToLong(&tLong); - iValue = tLong; - } + agi::util::try_parse(initial, &value); + Bind(wxEVT_CHAR, &IntValidator::OnChar, this); } -NumValidator::NumValidator(int val, bool issigned) -: fValue(0) -, iValue(val) -, isFloat(false) -, isSigned(issigned) +IntValidator::IntValidator(int val, bool allow_negative) +: value(val) +, allow_negative(allow_negative) { + Bind(wxEVT_CHAR, &IntValidator::OnChar, this); } -NumValidator::NumValidator(int64_t val, bool issigned) -: fValue(0) -, iValue((int)val) -, isFloat(false) -, isSigned(issigned) +IntValidator::IntValidator(IntValidator const& rgt) +: allow_negative(rgt.allow_negative) { + SetWindow(rgt.GetWindow()); + Bind(wxEVT_CHAR, &IntValidator::OnChar, this); } -NumValidator::NumValidator(double val, bool issigned) -: fValue(val) -, iValue(0) -, isFloat(true) -, isSigned(issigned) -{ -} - -NumValidator::NumValidator(const NumValidator &from) -: wxValidator() -, fValue(from.fValue) -, iValue(from.iValue) -, isFloat(from.isFloat) -, isSigned(from.isSigned) -{ - SetWindow(from.GetWindow()); -} - -BEGIN_EVENT_TABLE(NumValidator, wxValidator) - EVT_CHAR(NumValidator::OnChar) -END_EVENT_TABLE() - -wxObject* NumValidator::Clone() const { - return new NumValidator(*this); -} - -bool NumValidator::Validate(wxWindow*) { - wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow(); - wxString value = ctrl->GetValue(); - - if (!ctrl->IsEnabled()) return true; - - if (value.Length() < 1) return false; - - bool gotDecimal = false; - for (size_t i = 0; i < value.Length(); i++) { - if (!CheckCharacter(value[i], !i, true, gotDecimal)) - return false; - } +bool IntValidator::TransferToWindow() { + static_cast(GetWindow())->SetValue(std::to_wstring(value)); return true; } -bool NumValidator::CheckCharacter(int chr, bool isFirst, bool canSign, bool &gotDecimal) { - // Check sign - if (chr == '-' || chr == '+') { - return isFirst && canSign && isSigned; - } - - // Don't allow anything before a sign - if (isFirst && !canSign) return false; - - // Check decimal point - if (chr == '.' || chr == ',') { - if (!isFloat || gotDecimal) - return false; - else { - gotDecimal = true; - return true; - } - } - - // Check digit - return chr >= '0' && chr <= '9'; -} - -void NumValidator::OnChar(wxKeyEvent& event) { - wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow(); - wxString value = ctrl->GetValue(); +void IntValidator::OnChar(wxKeyEvent& event) { int chr = event.GetKeyCode(); - - // Special keys if (chr < WXK_SPACE || chr == WXK_DELETE || chr > WXK_START) { event.Skip(); return; } - // Get selection - long from,to; - ctrl->GetSelection(&from,&to); + auto ctrl = static_cast(GetWindow()); + auto str = new_value(ctrl, chr); + int parsed; + if (allow_negative && str == '-') + event.Skip(); + else if (agi::util::try_parse(str, &parsed) && (allow_negative || parsed >= 0)) + event.Skip(); + else if (!wxValidator::IsSilent()) + wxBell(); +} - // Count decimal points and signs outside selection - int decimals = 0; - int signs = 0; - wxChar curchr; - for (size_t i=0;i= (unsigned)from && i < (unsigned)to) continue; - curchr = value[i]; - if (curchr == '.' || curchr == ',') decimals++; - if (curchr == '+' || curchr == '-') signs++; - } - bool gotDecimal = decimals > 0; +DoubleValidator::DoubleValidator(double *val, bool allow_negative) +: value(val) +, min(allow_negative ? std::numeric_limits::lowest() : 0) +, max(std::numeric_limits::max()) +, decimal_sep(decimal_separator()) +{ + Bind(wxEVT_CHAR, &DoubleValidator::OnChar, this); +} - // Check character - if (!CheckCharacter(chr,!from,!signs,gotDecimal)) { - if (!wxValidator::IsSilent()) wxBell(); +DoubleValidator::DoubleValidator(double *val, double min, double max) +: value(val) +, min(min) +, max(max) +, decimal_sep(decimal_separator()) +{ + Bind(wxEVT_CHAR, &DoubleValidator::OnChar, this); +} + +DoubleValidator::DoubleValidator(DoubleValidator const& rgt) +: value(rgt.value) +, min(rgt.min) +, max(rgt.max) +, decimal_sep(rgt.decimal_sep) +{ + Bind(wxEVT_CHAR, &DoubleValidator::OnChar, this); + SetWindow(rgt.GetWindow()); +} + +void DoubleValidator::OnChar(wxKeyEvent& event) { + int chr = event.GetKeyCode(); + if (chr < WXK_SPACE || chr == WXK_DELETE || chr > WXK_START) { + event.Skip(); return; } - // OK - event.Skip(); - return; + if (chr == decimal_sep) + chr = '.'; + + auto str = new_value(static_cast(GetWindow()), chr); + if (decimal_sep != '.') + replace(begin(str), end(str), (char)decimal_sep, '.'); + + double parsed; + bool can_parse = agi::util::try_parse(str, &parsed); + if ((min < 0 && str == '-') || str == '.') + event.Skip(); + else if (can_parse && parsed >= min && parsed <= max) + event.Skip(); + else if (can_parse && min < 0 && chr == '-') // allow negating an existing value even if it results in being out of range + event.Skip(); + else if (!wxValidator::IsSilent()) + wxBell(); } -bool NumValidator::TransferToWindow() { - wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow(); - if (isFloat) - ctrl->SetValue(wxString::Format("%g",fValue)); - else - ctrl->SetValue(std::to_wstring(iValue)); - +bool DoubleValidator::TransferToWindow() { + auto str = wxString::Format("%g", *value); + if (decimal_sep != '.') + std::replace(str.begin(), str.end(), wxS('.'), decimal_sep); + if (str.find(decimal_sep) != str.npos) { + while (str.Last() == '0') + str.RemoveLast(); + } + static_cast(GetWindow())->SetValue(str); return true; } -bool NumValidator::TransferFromWindow() { - wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow(); - wxString value = ctrl->GetValue(); - +bool DoubleValidator::TransferFromWindow() { + auto ctrl = static_cast(GetWindow()); if (!Validate(ctrl)) return false; - - // Transfer - if (isFloat) { - value.ToDouble(&fValue); - } - else { - long tLong; - value.ToLong(&tLong); - iValue = tLong; - } - + auto str = from_wx(ctrl->GetValue()); + if (decimal_sep != '.') + replace(begin(str), end(str), (char)decimal_sep, '.'); + agi::util::try_parse(str, value); return true; } diff --git a/aegisub/src/validators.h b/aegisub/src/validators.h index 51bdf4bb7..5a7cfc578 100644 --- a/aegisub/src/validators.h +++ b/aegisub/src/validators.h @@ -1,37 +1,19 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2013, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ -/// @file validators.h -/// @see validators.cpp -/// @ingroup custom_control utility -/// - #include #include @@ -39,59 +21,44 @@ #include #include -/// A wx validator that only allows valid numbers -class NumValidator : public wxValidator { - double fValue; ///< Value if isFloat is true - int iValue; ///< Value if isFloat is false - bool isFloat; ///< Should decimals be allowed? - bool isSigned; ///< Can the number be negative? +class IntValidator : public wxValidator { + int value; + bool allow_negative; - /// Polymorphic copy - wxObject* Clone() const; - /// Check if the value in the passed window is valid - bool Validate(wxWindow* parent); - /// Copy the currently stored value to the associated window - bool TransferToWindow(); - /// Read the value in the associated window and validate it - bool TransferFromWindow(); - - /// Check a single character - /// @param chr Character to check - /// @param isFirst Is this the first character in the string? - /// @param canSign Can this character be a sign? - /// @param gotDecimal[in,out] Has a decimal been found? Set to true if a chr is a decimal - /// @return Is this character valid? - bool CheckCharacter(int chr,bool isFirst,bool canSign,bool &gotDecimal); - - /// wx character event handler + bool CheckCharacter(int chr, bool is_first) const; void OnChar(wxKeyEvent& event); + bool Validate(wxWindow *) override { return true; } + wxObject* Clone() const override { return new IntValidator(*this); } + bool TransferToWindow() override; + bool TransferFromWindow() override { return true; } + + IntValidator(IntValidator const& rgt); + public: - /// Constructor - /// @param val Initial value to set the associated control to - /// @param isfloat Allow floats, or just ints? - /// @param issigned Allow negative numbers? - explicit NumValidator(wxString val = wxString(), bool isfloat=false, bool issigned=false); + explicit IntValidator(std::string const& value = ""); + explicit IntValidator(int val, bool allow_negative=false); +}; - /// Constructor - /// @param val Initial value to set the associated control to - /// @param issigned Allow negative numbers? - explicit NumValidator(int val, bool issigned=false); +class DoubleValidator : public wxValidator { + double *value; + double min; + double max; + wxChar decimal_sep; - /// Constructor - /// @param val Initial value to set the associated control to - /// @param issigned Allow negative numbers? - explicit NumValidator(int64_t val, bool issigned=false); + bool Validate(wxWindow* parent) override { return true; } + bool CheckCharacter(int chr, bool is_first, bool *got_decimal) const; + void OnChar(wxKeyEvent& event); - /// Constructor - /// @param val Initial value to set the associated control to - /// @param issigned Allow negative numbers? - explicit NumValidator(double val, bool issigned=false); + DoubleValidator(DoubleValidator const& rgt); - /// Copy constructor - NumValidator(const NumValidator& from); + wxObject* Clone() const override { return new DoubleValidator(*this); } + bool TransferToWindow() override; + bool TransferFromWindow() override; - DECLARE_EVENT_TABLE() +public: + explicit DoubleValidator(double *val, bool allow_negative=false); + explicit DoubleValidator(double *val, double min, double max); }; template