diff --git a/ImGui.Widgets/ValueSlider.cs b/ImGui.Widgets/ValueSlider.cs index 2b3bd0ba..b0d2aa44 100644 --- a/ImGui.Widgets/ValueSlider.cs +++ b/ImGui.Widgets/ValueSlider.cs @@ -259,7 +259,10 @@ private static bool Drag(ValueSliderState state, ref double value, Spec spec, fl private static bool SetValue(ref double value, double target, double min, double max, bool isInteger) { - double next = Math.Clamp(isInteger ? Math.Round(target, MidpointRounding.AwayFromZero) : target, min, max); + // The value is stored as a float or an int, so it is compared as one: a drag held as a double + // that a float cannot hold exactly would otherwise read as a fresh change on every held frame. + double stored = isInteger ? Math.Round(target, MidpointRounding.AwayFromZero) : (float)target; + double next = Math.Clamp(stored, min, max); if (IsSameValue(next, value)) { return false; diff --git a/tests/ImGui.Widgets.UITests/ValueSliderTests.cs b/tests/ImGui.Widgets.UITests/ValueSliderTests.cs index 52d82062..cc887f00 100644 --- a/tests/ImGui.Widgets.UITests/ValueSliderTests.cs +++ b/tests/ImGui.Widgets.UITests/ValueSliderTests.cs @@ -344,6 +344,42 @@ public void ValueSlider_APrefixIsDrawnButNotTyped() Assert.AreEqual(30f, value, "A typed value with the prefix in front was not read."); } + [TestMethod] + public void ValueSlider_AHeldPointerThatStopsReportsNoChange() + { + // 0..1 over 200 px, so a 7 px drag lands on 0.035, which a float cannot hold exactly. + float fraction = 0.5f; + int changes = 0; + Start(() => + { + ImGui.PushItemWidth(FrameWidth); + if (ImGuiWidgets.ValueSlider(Label, ref fraction, 0f, 1f)) + { + changes++; + } + + ImGui.PopItemWidth(); + }); + + Rectangle rect = RectOf(Label); + float x = rect.MinX + (FrameWidth / 2f); + float y = rect.MinY + (rect.Height / 2f); + Harness.Mouse.MoveTo(x, y); + Step(); + HarnessMouse.Down(0); + Step(); + Harness.Mouse.MoveTo(x + 7f, y); + Step(2); + + Assert.AreNotEqual(0.5f, fraction, "The drag did not move the value."); + changes = 0; + Step(5); + HarnessMouse.Up(0); + Step(); + + Assert.AreEqual(0, changes, "The slider reported a change on frames the held pointer did not move."); + } + [TestMethod] public void ValueSlider_ReportsTheFrameItChangedOn() {