Rewrite NumValidator
Split int validating and double validating into two separate classes. Make double parsing, validating and stringifying locale-aware. This is far more complicated than it needs to be due to that Aegisub's locale handling is a total mess. Use DoubleValidator rather than wxFloatingPointValidator, because the latter doesn't work with Aegisub's locale mess (on OS X it uses the C locale for some things, and the locale reported by CoreFoundation for others). Closes #1568.
This commit is contained in:
parent
3691849bac
commit
ebd01c50c9
8 changed files with 172 additions and 262 deletions
|
@ -328,8 +328,7 @@ namespace Automation4 {
|
|||
return scd;
|
||||
}
|
||||
|
||||
wxFloatingPointValidator<double> 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));
|
||||
|
|
|
@ -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<double> 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) {
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -1,37 +1,19 @@
|
|||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// 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 <libaegisub/exception.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
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<wxTextCtrl *>(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);
|
||||
|
||||
// Count decimal points and signs outside selection
|
||||
int decimals = 0;
|
||||
int signs = 0;
|
||||
wxChar curchr;
|
||||
for (size_t i=0;i<value.Length();i++) {
|
||||
if (i >= (unsigned)from && i < (unsigned)to) continue;
|
||||
curchr = value[i];
|
||||
if (curchr == '.' || curchr == ',') decimals++;
|
||||
if (curchr == '+' || curchr == '-') signs++;
|
||||
}
|
||||
bool gotDecimal = decimals > 0;
|
||||
|
||||
// Check character
|
||||
if (!CheckCharacter(chr,!from,!signs,gotDecimal)) {
|
||||
if (!wxValidator::IsSilent()) wxBell();
|
||||
return;
|
||||
auto ctrl = static_cast<wxTextCtrl *>(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();
|
||||
}
|
||||
|
||||
// OK
|
||||
DoubleValidator::DoubleValidator(double *val, bool allow_negative)
|
||||
: value(val)
|
||||
, min(allow_negative ? std::numeric_limits<double>::lowest() : 0)
|
||||
, max(std::numeric_limits<double>::max())
|
||||
, decimal_sep(decimal_separator())
|
||||
{
|
||||
Bind(wxEVT_CHAR, &DoubleValidator::OnChar, this);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool NumValidator::TransferToWindow() {
|
||||
wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow();
|
||||
if (isFloat)
|
||||
ctrl->SetValue(wxString::Format("%g",fValue));
|
||||
else
|
||||
ctrl->SetValue(std::to_wstring(iValue));
|
||||
if (chr == decimal_sep)
|
||||
chr = '.';
|
||||
|
||||
auto str = new_value(static_cast<wxTextCtrl *>(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 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<wxTextCtrl *>(GetWindow())->SetValue(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NumValidator::TransferFromWindow() {
|
||||
wxTextCtrl *ctrl = (wxTextCtrl*) GetWindow();
|
||||
wxString value = ctrl->GetValue();
|
||||
|
||||
bool DoubleValidator::TransferFromWindow() {
|
||||
auto ctrl = static_cast<wxTextCtrl *>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,37 +1,19 @@
|
|||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// 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 <libaegisub/exception.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -39,59 +21,44 @@
|
|||
#include <wx/radiobox.h>
|
||||
#include <wx/validate.h>
|
||||
|
||||
/// 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<typename T>
|
||||
|
|
Loading…
Reference in a new issue