From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 37ACC1FF13C for ; Thu, 19 Mar 2026 18:05:01 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 6A3A7742C; Thu, 19 Mar 2026 18:05:16 +0100 (CET) From: Christoph Heiss To: yew-devel@lists.proxmox.com Subject: [RFC PATCH yew-widget-toolkit 1/2] widget: form: number: round floats to nearest step value Date: Thu, 19 Mar 2026 18:04:17 +0100 Message-ID: <20260319170432.1533393-2-c.heiss@proxmox.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260319170432.1533393-1-c.heiss@proxmox.com> References: <20260319170432.1533393-1-c.heiss@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1773939839663 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.054 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: ZQKWPXE6OMCIHIQUBEINDE55O2UZTT2B X-Message-ID-Hash: ZQKWPXE6OMCIHIQUBEINDE55O2UZTT2B X-MailFrom: c.heiss@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Yew framework devel list at Proxmox List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: E.g. previously, for an input like Number::new() .name("some-float") .min(0.) .step(0.1) .submit_empty(false) .value(0.2) and pressing the "range-up" button on the input would result in 0.30000000000000004 - which is rather undesirable. Fix it by multiplying, rounding and then dividing the number again by some fixed multiplier - in this case, 100_000 was chosen. Should cover all realistic cases, as it handles up to five fractional digits, which for UI purposes should (hopefully!) be plenty enough. And if really needed, could be increased. Signed-off-by: Christoph Heiss --- Marked RFC as it may not be necessarily the *best* solution, but by far the *simplest*. Happy about other solution suggestions, of course. I also considered other solutions like e.g. doing the rounding (implicitly) when formatting the number as string above with `dom::format_float()` - but that solution seemed more like papering over the symptoms than fixing the root cause. src/widget/form/number.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/widget/form/number.rs b/src/widget/form/number.rs index e5c849c..6db7063 100644 --- a/src/widget/form/number.rs +++ b/src/widget/form/number.rs @@ -68,10 +68,14 @@ impl NumberTypeInfo for f64 { crate::dom::format_float(*self) } fn step_up(&self, step: Option) -> Self { - self + step.unwrap_or(1.0) + // Do a little dance here to round to the nearest step value, by multiplying, + // rounding to the nearest integer and dividing again + ((self + step.unwrap_or(1.0)) * 1e5).round() / 1e5 } fn step_down(&self, step: Option) -> Self { - self - step.unwrap_or(1.0) + // Do a little dance here to round to the nearest step value, by multiplying, + // rounding to the nearest integer and dividing again + ((self - step.unwrap_or(1.0)) * 1e5).round() / 1e5 } fn clamp_value(&self, min: Option, max: Option) -> Self { self.clamp(min.unwrap_or(f64::MIN), max.unwrap_or(f64::MAX)) -- 2.53.0