This document captures design and implementation notes for Slider<T>.
For end-user usage and examples, see Slider.
INumber<T> (int, double, etc.)CellBuffer)NumberBox<T> if needed)src/XenoAtom.Terminal.UI/Controls/Slider.cssrc/XenoAtom.Terminal.UI/Styling/SliderStyle.cssrc/XenoAtom.Terminal.UI.Tests/SliderValueTests.cssamples/ControlsDemo/Demos/SliderDemo.csSlider<T> : Visual where T : struct, INumber<T> (sealed)Focusable = trueHorizontalAlignment = Align.StretchVerticalAlignment uses the Visual default (typically Align.Start)Orientation : Orientation (bindable)
default(Orientation)).Minimum : T (bindable)Maximum : T (bindable)Value : T (bindable)Step : T (bindable)LargeStep : T (bindable)SnapToStep : bool (bindable)ShowValueLabel : bool (bindable)ValueFormatter : Delegator<Func<T, string>> (bindable)
ShowValueLabel is true.ToStringValue(value) representation.ValueChanged routed event (bubble).The event is raised only when the effective (clamped/snapped) value changes.
See:
src/XenoAtom.Terminal.UI.Tests/SliderValueTests.cs for value coercion behavior.samples/ControlsDemo/Demos/SliderDemo.cs for interactive usage.The control keeps the range consistent when a bound changes:
Minimum is set and Maximum < Minimum, Maximum is set to Minimum.Maximum is set and Maximum < Minimum, Minimum is set to Maximum.After either bound changes, Value is clamped (and snapped if enabled).
To avoid propagating invalid numeric values into layout/render code:
Minimum and Maximum are coerced to finite values.
Minimum becomes 0 and Maximum becomes 1.Step and LargeStep are coerced to non-negative finite values.
0.Whenever Value is set, it is transformed as follows:
[min .. max]SnapToStep is true and Step > 0, snap to the nearest step:
t = (value - min) / stepMath.Round(t) * step + min[min .. max]The slider measures to a small fixed size (a minimal track length) and relies on alignment to stretch in layout.
min(MaxWidth, 6) by min(MaxHeight, 1)min(MaxWidth, 1) by min(MaxHeight, 6)This ensures the control remains usable with small constraints while still expanding when placed in a stretching slot.
Rendering is performed directly into the CellBuffer within Bounds.
The control renders:
The thumb index is computed from the normalized ratio:
t = (Value - Minimum) / (Maximum - Minimum)[0 .. trackLength - 1] using roundingShowValueLabel is true, the control reserves space for a value label:
TerminalTextUtility.GetWidth(...)Bounds.Width - labelCells - 1TextStyle.Dimi in [0 .. trackWidth-1]:
i == thumbIndex: write the thumb glyph with thumb stylei < thumbIndex: write active track glyph with active styleVertical orientation maps:
MinimumMaximumThe thumb is placed using a bottom-based index so that increasing values move upward.
Active track fills below the thumb (toward the bottom), matching the "filled from min" mental model.
Slider<T> currently implements its interactions directly in OnKeyDown and pointer handlers (it does not register
commands for them yet).
When enabled:
Home: set Value = MinimumEnd: set Value = MaximumPageUp: Value -= LargeStep (or Step * 2 when LargeStep <= 0)PageDown: Value += LargeStep (or Step * 2 when LargeStep <= 0)Small-step adjustments:
Left decreases, Right increasesDown decreases, Up increasesWhen enabled, wheel adjusts by Step (or by 1 when Step <= 0):
SliderStyle controls:
TrackStyle, ActiveTrackStyle, and several thumb state stylesResolved styles:
theme.BorderStyle(focused: false) by defaulttheme.Accent (or focus border / foreground fallback) and TextStyle.BoldIncrease, Decrease, SetMinimum, SetMaximum) for CommandBar discoverability.