# Slider

> Selection of a float value within a range, continuous or in steps.

Source: https://crossfly.dev/docs/ui/widgets/slider — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Slider

`Slider` lets you choose a `float` value within a range `[min, max]` by dragging a knob. It can be **continuous** or **discrete** (with steps, via `npos`). The orientation is detected automatically: **horizontal** if `width ≥ height`, otherwise **vertical**. Tapping outside the knob smoothly animates to the tapped point; dragging updates the value continuously.

> 🟢 · **Package:** `dev.crossfly.ui` · **Extends:** `Component` · **Style:** `SliderStyle` (with a pressed variant `sliderPressed()`)

## When to use
- Continuous or approximate values: volume, brightness, ranges, zoom.
- Selection over a few discrete steps (e.g. 1 to 5) with `npos`.

## When NOT to use
- When the user needs to type an exact number → use [`textfield`](/docs/ui/widgets/textfield) in numeric mode.

## Appearance
A bar in two segments — **filled** (before the knob) and **empty** (after) — plus the knob. The coordinates of each segment (`bx1/by1/bw1/bh1`, `bx2/by2/bw2/bh2`) and of the knob (`kx/ky/ks`) are computed in layout (all `float`). The bar thickness is `thickness * fontHeight`; the knob is `knobSize * fontHeight` (from the `SliderStyle`).

## Complete example (copy, paste and run)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label saida = new Label("Volume: 50");
      add(LAY_AUTO, saida);

      // Continuous slider 0..100 starting at 50; onAction fires on every value change
      Slider volume = new Slider(0, 100, 50);
      volume.onAction(c -> saida.setText("Volume: " + (int) volume.value));
      add(LAY_AUTO, volume);
   }
}
```

> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## Basic usage
```java
Slider volume = new Slider(0, 100, 50);                 // continuous, starts at 50
volume.onAction(c -> System.out.println("valor: " + volume.value));
container.add(LAY_AUTO, volume);
```

## Constructors
| Constructor | Description |
|---|---|
| `Slider(float min, float max, float value)` | **Continuous** slider. |
| `Slider(float min, float max, float value, int npos)` | **Discrete** slider: `npos` positions (e.g. `5` → steps at 0%, 25%, 50%, 75%, 100%). |

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `value` | `float` (field) | ctor | Current value (read). |
| `min` / `max` | `float` (field) | ctor | Range limits. |
| `npos` | `int` (field) | `0` | No. of discrete positions; `0` = continuous. |
| `setValue(float)` | `void` | — | Sets the value immediately (= `setValue(v, false)`); applies `clamp` + `snap`. |
| `setValue(float, boolean animated)` | `void` | — | Sets the value with/without animation; fires `runActions()`. |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `onAction(Action)` | On every change of `value` (drag, tap animation and `setValue`). |

## States
- **dragging**: while the user drags the knob (`onPan`), `value` is updated on every movement.
- **tap-to-jump**: tapping outside the knob animates to the tapped point (`PositionAnimation`, duration `style.animationDuration`).
- **pressed**: uses its own pressed style (`sliderPressed()`).

### Discrete slider with 5 stops
```java
Slider nivel = new Slider(0, 100, 50, 5);               // steps: 0,25,50,75,100
nivel.onAction(c -> System.out.println("nível: " + nivel.value));
container.add(LAY_AUTO, nivel);

nivel.setValue(75, true);   // animates to 75 (will be snapped to the nearest step)
```

## Best practices
- Pass an initial `value` within `[min, max]`: the **constructor does not clamp** (only `setValue` does).
- To force vertical orientation, give the slider more height than width in the layout.

## Common mistakes
- Assuming a fixed orientation: it is decided in layout by the width/height ratio.
- Expecting continuous values with `npos > 0`: in discrete mode the value is always "snapped" to the step.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Concept (layout and responsiveness): [`concepts/`](/docs/concepts)
- Related components: [`progress`](/docs/ui/widgets/progress)
