Fix scrolling and keep lists clear of the scrollbar

Scroll kept its position as an int, so wheel and trackpad deltas were
truncated: small ones were lost in one direction and a wheel notch moved
one unit. It now keeps a fractional position, scrolls 24 units a notch,
sizes and places its thumb consistently, and the thumb can be dragged or
the track clicked. PanelScreen's scrollWidth and scrollContentWidth keep
every scrolling list clear of the bar.

Sliders read a float step from its text, so 0.1 no longer shows 17
decimals, and show at most three; number boxes show at most three too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-27 17:54:12 +02:00
co-authored by claude
parent 33c09b6922
commit 351507d60d
8 changed files with 152 additions and 88 deletions
@@ -1,5 +1,8 @@
package org.saturnclient.ui.components.inputs;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.saturnclient.config.ConfigManager;
import org.saturnclient.config.property.FloatProperty;
import org.saturnclient.ui.elements.Field;
@@ -11,7 +14,16 @@ public class FloatInput extends Input {
this.width = 96;
this.height = Field.HEIGHT;
this.prop = prop;
this.text = String.valueOf(prop.value);
this.text = format(prop.value);
}
/**
* The value with at most three decimals and no trailing zeros, since floats
* like 1.2000000476837158 can't be stored exactly.
*/
private static String format(float value) {
return new BigDecimal(Float.toString(value)).setScale(3, RoundingMode.HALF_UP).stripTrailingZeros()
.toPlainString();
}
@Override
@@ -51,7 +63,7 @@ public class FloatInput extends Input {
@Override
public void checkReset() {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.text = format(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
@@ -23,6 +23,7 @@ public class Slider extends Element {
private static final int KNOB = 16;
private static final int VALUE_WIDTH = 72;
private static final int VALUE_GAP = 14;
private static final int MAX_DECIMALS = 3;
private final double min, max, step;
private final int decimals;
@@ -32,25 +33,28 @@ public class Slider extends Element {
private boolean dragging = false;
private Slider(double min, double max, double step, String unit, DoubleSupplier value, DoubleConsumer onChange) {
/**
* @param step as text, so a float step like 0.1 isn't read as 0.10000000149
*/
private Slider(double min, double max, String step, String unit, DoubleSupplier value, DoubleConsumer onChange) {
this.min = min;
this.max = max;
this.step = step;
this.step = Double.parseDouble(step);
this.unit = unit;
this.value = value;
this.onChange = onChange;
this.decimals = Math.max(0, BigDecimal.valueOf(step).stripTrailingZeros().scale());
this.decimals = Math.min(MAX_DECIMALS, Math.max(0, new BigDecimal(step).stripTrailingZeros().scale()));
this.width = 280;
this.height = Field.HEIGHT;
}
public static Slider of(IntProperty prop) {
return new Slider(prop.min, prop.max, prop.step, prop.unit, () -> prop.value,
return new Slider(prop.min, prop.max, Integer.toString(prop.step), prop.unit, () -> prop.value,
v -> prop.value = (int) Math.round(v));
}
public static Slider of(FloatProperty prop) {
return new Slider(prop.min, prop.max, prop.step, prop.unit, () -> prop.value,
return new Slider(prop.min, prop.max, Float.toString(prop.step), prop.unit, () -> prop.value,
v -> prop.value = (float) v);
}