A number field reads "2,5" as 2.5, as a numeric keypad types it in many locales; a comma beside a point or a second comma is not guessed at.
This commit is contained in:
1 parent
4c7ea34a68
commit
8b97b9ed62
5 files changed
+38
-7
No files matched your search
@@ -1155,7 +1155,7 @@ fn canvas_panel(app: &mut SolveApp, ctx: &egui::Context) {
|
|||||||
let r3 = ui.add(crate::prefs::length_drag(&mut w, &app.session.doc.units, app.preferences.length_decimals).range(0.01..=1e6));
|
let r3 = ui.add(crate::prefs::length_drag(&mut w, &app.session.doc.units, app.preferences.length_decimals).range(0.01..=1e6));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
ui.label(crate::i18n::tr_label("Angle"));
|
ui.label(crate::i18n::tr_label("Angle"));
|
||||||
let r4 = ui.add(egui::DragValue::new(&mut ang).speed(1.0).suffix(" deg"));
|
let r4 = ui.add(egui::DragValue::new(&mut ang).speed(1.0).suffix(" deg").custom_parser(crate::prefs::parse_number));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
ui.label(crate::i18n::tr_label("Opacity"));
|
ui.label(crate::i18n::tr_label("Opacity"));
|
||||||
let r5 = ui.add(egui::Slider::new(&mut op, 0.0..=1.0));
|
let r5 = ui.add(egui::Slider::new(&mut op, 0.0..=1.0));
|
||||||
@@ -1721,7 +1721,7 @@ fn occurrence_panel(app: &mut SolveApp, ui: &mut egui::Ui) {
|
|||||||
for (k, axis) in ["X angle", "Y angle", "Z angle"].iter().enumerate() {
|
for (k, axis) in ["X angle", "Y angle", "Z angle"].iter().enumerate() {
|
||||||
ui.label(*axis);
|
ui.label(*axis);
|
||||||
if let Some(v) = m.angles.get_mut(k) {
|
if let Some(v) = m.angles.get_mut(k) {
|
||||||
let response = ui.add(egui::DragValue::new(v).speed(1.0).suffix(" deg"));
|
let response = ui.add(egui::DragValue::new(v).speed(1.0).suffix(" deg").custom_parser(crate::prefs::parse_number));
|
||||||
crate::scenario::publish_handle(&format!("occurrence-move:angle:{k}"), response.rect.center());
|
crate::scenario::publish_handle(&format!("occurrence-move:angle:{k}"), response.rect.center());
|
||||||
}
|
}
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|||||||
@@ -2374,8 +2374,14 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
|||||||
for (k, (t, r)) in mids.iter_mut().enumerate() {
|
for (k, (t, r)) in mids.iter_mut().enumerate() {
|
||||||
row_label(ui, "Mid Radius");
|
row_label(ui, "Mid Radius");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::DragValue::new(t).speed(0.01).range(0.01..=0.99).fixed_decimals(2))
|
ui.add(
|
||||||
.on_hover_text(tr("Position along the edge, 0 at the start end, 1 at the other"));
|
egui::DragValue::new(t)
|
||||||
|
.speed(0.01)
|
||||||
|
.range(0.01..=0.99)
|
||||||
|
.fixed_decimals(2)
|
||||||
|
.custom_parser(crate::prefs::parse_number),
|
||||||
|
)
|
||||||
|
.on_hover_text(tr("Position along the edge, 0 at the start end, 1 at the other"));
|
||||||
enter |= field(ui, r);
|
enter |= field(ui, r);
|
||||||
if ui.small_button("×").on_hover_text(tr("Remove this point")).clicked() {
|
if ui.small_button("×").on_hover_text(tr("Remove this point")).clicked() {
|
||||||
remove = Some(k);
|
remove = Some(k);
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ pub fn rows(app: &mut SolveApp, ui: &mut egui::Ui, k: &mut Ap, inputs: &mut [Sel
|
|||||||
("appearance.dielectric_ior", "appearance:ior", &mut ior, 1.0..=3.0),
|
("appearance.dielectric_ior", "appearance:ior", &mut ior, 1.0..=3.0),
|
||||||
] {
|
] {
|
||||||
row_label(ui, app.tr(label));
|
row_label(ui, app.tr(label));
|
||||||
let response = ui.add(egui::DragValue::new(value).range(range).speed(0.01));
|
let response = ui.add(egui::DragValue::new(value).range(range).speed(0.01).custom_parser(crate::prefs::parse_number));
|
||||||
crate::scenario::publish_handle(handle, response.rect.center());
|
crate::scenario::publish_handle(handle, response.rect.center());
|
||||||
if response.changed() {
|
if response.changed() {
|
||||||
k.remove_override = false;
|
k.remove_override = false;
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ pub fn label(k: &ConstraintKind, expr: Option<&str>, driven: bool, units: &str,
|
|||||||
let plain = expr.is_none_or(|e| {
|
let plain = expr.is_none_or(|e| {
|
||||||
let e = e.trim();
|
let e = e.trim();
|
||||||
let e = ["mm", "cm", "in", "ft", "m", "deg", "rad", "°"].iter().find_map(|unit| e.strip_suffix(unit)).unwrap_or(e);
|
let e = ["mm", "cm", "in", "ft", "m", "deg", "rad", "°"].iter().find_map(|unit| e.strip_suffix(unit)).unwrap_or(e);
|
||||||
e.trim().parse::<f64>().is_ok()
|
crate::prefs::parse_number(e).is_some()
|
||||||
});
|
});
|
||||||
let text = if plain { num } else { format!("fx: {num}") };
|
let text = if plain { num } else { format!("fx: {num}") };
|
||||||
if driven { format!("({text})") } else { text }
|
if driven { format!("({text})") } else { text }
|
||||||
@@ -823,6 +823,8 @@ mod tests {
|
|||||||
let k = ConstraintKind::Length { l: 0, value: 25.0 };
|
let k = ConstraintKind::Length { l: 0, value: 25.0 };
|
||||||
assert_eq!(label(&k, Some("25 mm"), false, "mm", 2), "25.00");
|
assert_eq!(label(&k, Some("25 mm"), false, "mm", 2), "25.00");
|
||||||
assert_eq!(label(&k, Some("width * 2"), false, "mm", 2), "fx: 25.00");
|
assert_eq!(label(&k, Some("width * 2"), false, "mm", 2), "fx: 25.00");
|
||||||
|
// A value typed with a decimal comma is a plain value too (#1347).
|
||||||
|
assert_eq!(label(&ConstraintKind::Length { l: 0, value: 25.5 }, Some("25,5 mm"), false, "mm", 2), "25.50");
|
||||||
assert_eq!(label(&k, None, true, "mm", 2), "(25.00)");
|
assert_eq!(label(&k, None, true, "mm", 2), "(25.00)");
|
||||||
assert_eq!(label(&ConstraintKind::Radius { c: 0, value: 5.0 }, Some("5 mm"), false, "mm", 2), "R5.00");
|
assert_eq!(label(&ConstraintKind::Radius { c: 0, value: 5.0 }, Some("5 mm"), false, "mm", 2), "R5.00");
|
||||||
assert_eq!(label(&ConstraintKind::Diameter { c: 0, value: 10.0 }, Some("10"), false, "mm", 2), "Ø10.00");
|
assert_eq!(label(&ConstraintKind::Diameter { c: 0, value: 10.0 }, Some("10"), false, "mm", 2), "Ø10.00");
|
||||||
|
|||||||
@@ -683,6 +683,16 @@ pub fn length_number(mm: f64, units: &str, decimals: u8) -> String {
|
|||||||
format!("{:.*}", length_precision(value, units, decimals), value)
|
format!("{:.*}", length_precision(value, units, decimals), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A plain number typed into a field, with a decimal point or a decimal comma (#1347): "2.5"
|
||||||
|
/// and "2,5" are both 2.5, as a numeric keypad types either depending on the locale. Spaces are
|
||||||
|
/// ignored and "−" is a minus, as in egui's own parser. A comma beside a point ("1.234,5") or a
|
||||||
|
/// second comma is not guessed at: the text is not a number.
|
||||||
|
pub fn parse_number(text: &str) -> Option<f64> {
|
||||||
|
let t: String = text.chars().filter(|c| !c.is_whitespace()).map(|c| if c == '\u{2212}' { '-' } else { c }).collect();
|
||||||
|
let t = if !t.contains('.') && t.matches(',').count() == 1 { t.replacen(',', ".", 1) } else { t };
|
||||||
|
t.parse::<f64>().ok().filter(|v| v.is_finite())
|
||||||
|
}
|
||||||
|
|
||||||
/// Edit a millimetre value through a control expressed in the current design units.
|
/// Edit a millimetre value through a control expressed in the current design units.
|
||||||
/// Keep the stored value untouched unless the user actually changes the field.
|
/// Keep the stored value untouched unless the user actually changes the field.
|
||||||
pub fn length_drag<'a>(value: &'a mut f64, units: &str, decimals: u8) -> egui::DragValue<'a> {
|
pub fn length_drag<'a>(value: &'a mut f64, units: &str, decimals: u8) -> egui::DragValue<'a> {
|
||||||
@@ -1001,7 +1011,7 @@ fn page(app: &mut SolveApp, ui: &mut egui::Ui, t: &Tokens) {
|
|||||||
});
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
ui.label(app.tr("ui.autosave_every"));
|
ui.label(app.tr("ui.autosave_every"));
|
||||||
if ui.add(egui::DragValue::new(&mut app.autosave_minutes).range(0.0..=120.0).speed(0.5).suffix(" min")).changed() {
|
if ui.add(egui::DragValue::new(&mut app.autosave_minutes).range(0.0..=120.0).speed(0.5).suffix(" min").custom_parser(parse_number)).changed() {
|
||||||
set_autosave(app);
|
set_autosave(app);
|
||||||
}
|
}
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
@@ -1438,6 +1448,19 @@ pub fn set(app: &mut SolveApp, p: &serde_json::Value) -> Result<serde_json::Valu
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn number_fields_take_a_decimal_point_or_a_decimal_comma() {
|
||||||
|
// #1347
|
||||||
|
assert_eq!(super::parse_number("2.5"), Some(2.5));
|
||||||
|
assert_eq!(super::parse_number("2,5"), Some(2.5));
|
||||||
|
assert_eq!(super::parse_number(" -0,25 "), Some(-0.25));
|
||||||
|
assert_eq!(super::parse_number("\u{2212}1,5"), Some(-1.5));
|
||||||
|
assert_eq!(super::parse_number("12"), Some(12.0));
|
||||||
|
for bad in ["1.234,5", "1,2,3", ",", "abc", "", "inf", "NaN"] {
|
||||||
|
assert_eq!(super::parse_number(bad), None, "{bad}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Display quality (#1287) is a preference like any other: set by name, checked, saved with
|
/// Display quality (#1287) is a preference like any other: set by name, checked, saved with
|
||||||
/// the others, back to Normal with Restore Defaults.
|
/// the others, back to Normal with Restore Defaults.
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in new issue
Block a user