mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 21:42:43 +00:00
fix: validate float-or-percent input ranges (#15392)
This commit is contained in:
+79
-34
@@ -11,6 +11,7 @@
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
@@ -540,51 +541,95 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
case coStrings:
|
||||
case coFloatOrPercent:
|
||||
case coFloatsOrPercents: {
|
||||
if ((m_opt.type == coFloatOrPercent || m_opt.type == coFloatsOrPercents) && !str.IsEmpty() && str.Last() != '%')
|
||||
{
|
||||
if ((m_opt.type == coFloatOrPercent || m_opt.type == coFloatsOrPercents) && !str.IsEmpty() &&
|
||||
!(m_opt.nullable && str == m_na_value)) {
|
||||
bool update_control = false;
|
||||
wxString numeric_str = str;
|
||||
double val = 0.;
|
||||
|
||||
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
|
||||
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
|
||||
// Replace the first incorrect separator in decimal number.
|
||||
if (str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
||||
set_value(str, false);
|
||||
// Orca: normalize the decimal separator and optional unit before
|
||||
// detecting the percentage suffix and parsing the numeric part.
|
||||
update_control |= numeric_str.Replace(dec_sep_alt, dec_sep, false) != 0;
|
||||
update_control |= numeric_str.Replace(" ", "", true) != 0;
|
||||
const bool has_literal_unit = numeric_str.EndsWith("mm");
|
||||
if (has_literal_unit) {
|
||||
numeric_str.RemoveLast(2);
|
||||
update_control = true;
|
||||
}
|
||||
bool is_percent = !numeric_str.IsEmpty() && numeric_str.Last() == '%';
|
||||
if (is_percent)
|
||||
numeric_str.RemoveLast();
|
||||
|
||||
|
||||
// remove space and "mm" substring, if any exists
|
||||
str.Replace(" ", "", true);
|
||||
str.Replace("m", "", true);
|
||||
|
||||
if (!str.ToDouble(&val))
|
||||
{
|
||||
if ((has_literal_unit && is_percent) || !numeric_str.ToDouble(&val) || !std::isfinite(val)) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
}
|
||||
show_error(m_parent, _L("Invalid numeric."));
|
||||
set_value(double_to_string(val), true);
|
||||
}
|
||||
else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
|
||||
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > /*1*/m_opt.max_literal)) &&
|
||||
(m_value.empty() || into_u8(str) != boost::any_cast<std::string>(m_value)))
|
||||
{
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
numeric_str = double_to_string(std::clamp(0., double(m_opt.min), double(m_opt.max)));
|
||||
is_percent = false;
|
||||
update_control = true;
|
||||
} else {
|
||||
const bool looks_like_missing_percent = !is_percent && !has_literal_unit &&
|
||||
((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
|
||||
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > m_opt.max_literal));
|
||||
// Orca: validate explicit percentages and literal values before
|
||||
// asking whether an otherwise valid literal was meant as a percentage.
|
||||
const bool out_of_range = !m_opt.is_value_valid(val);
|
||||
if (out_of_range) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
}
|
||||
show_error(m_parent, _L("Value is out of range."));
|
||||
val = std::clamp(val, double(m_opt.min), double(m_opt.max));
|
||||
// Orca: retain the inferred percent unit when clamping a
|
||||
// suspicious unitless value, so 2000 becomes 100%, not 100 mm.
|
||||
is_percent |= looks_like_missing_percent;
|
||||
numeric_str = double_to_string(val);
|
||||
update_control = true;
|
||||
} else {
|
||||
const bool value_changed = m_value.empty() || into_u8(str) != boost::any_cast<std::string>(m_value);
|
||||
if (looks_like_missing_percent && value_changed) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
|
||||
const wxString stVal = numeric_str;
|
||||
const wxString msg_text = from_u8((boost::format(_utf8(L("Is it %s%% or %s %s?"))) %
|
||||
stVal % stVal % sidetext).str());
|
||||
WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO);
|
||||
dialog.SetButtonLabel(wxID_YES, stVal + _L("%"));
|
||||
dialog.SetButtonLabel(wxID_NO, stVal + " " + _L(sidetext));
|
||||
dialog.GetSizer()->SetSizeHints(&dialog);
|
||||
dialog.Fit();
|
||||
dialog.CenterOnParent();
|
||||
is_percent = dialog.ShowModal() == wxID_YES;
|
||||
update_control = true;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
|
||||
const wxString stVal = double_to_string(val, 2);
|
||||
const wxString msg_text = from_u8((boost::format(_utf8(L("Is it %s%% or %s %s?\n"
|
||||
"YES for %s%%, \n"
|
||||
"NO for %s %s."))) %
|
||||
stVal % stVal % sidetext % stVal % stVal % sidetext)
|
||||
.str());
|
||||
WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO);
|
||||
if ((val > 100) && dialog.ShowModal() == wxID_YES) {
|
||||
set_value(from_u8((boost::format("%s%%") % stVal).str()), false /*true*/);
|
||||
str += "%%";
|
||||
} else
|
||||
set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "."
|
||||
// Orca: also enforce the literal limit after clamping an explicit mm input.
|
||||
if (!is_percent && m_opt.sidetext.rfind("mm ") != std::string::npos && val > m_opt.max_literal) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
}
|
||||
if (!out_of_range)
|
||||
show_error(m_parent, _L("Value is out of range."));
|
||||
val = m_opt.max_literal;
|
||||
numeric_str = double_to_string(val);
|
||||
update_control = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_control) {
|
||||
str = numeric_str + (is_percent ? "%" : "");
|
||||
set_value(str, true);
|
||||
}
|
||||
}
|
||||
if (m_opt.opt_key == "thumbnails") {
|
||||
|
||||
Reference in New Issue
Block a user