# Slider

> Seleção de um valor float num intervalo, contínuo ou em passos.

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

# Slider

`Slider` permite escolher um valor `float` dentro de um intervalo `[min, max]` arrastando um knob. Pode ser **contínuo** ou **discreto** (com passos, via `npos`). A orientação é detectada automaticamente: **horizontal** se `largura ≥ altura`, senão **vertical**. Tocar fora do knob anima suavemente até o ponto tocado; arrastar atualiza o valor continuamente.

> 🟢 · **Pacote:** `dev.crossfly.ui` · **Estende:** `Component` · **Estilo:** `SliderStyle` (com variante pressionada `sliderPressed()`)

## Quando usar
- Valores contínuos ou aproximados: volume, brilho, faixas, zoom.
- Seleção em poucos passos discretos (ex.: 1 a 5) com `npos`.

## Quando NÃO usar
- Quando o usuário precisa digitar um número exato → use [`textfield`](/docs/ui/widgets/textfield) em modo numérico.

## Aparência
Uma barra em dois segmentos — **preenchido** (antes do knob) e **vazio** (depois) — mais o knob. As coordenadas de cada segmento (`bx1/by1/bw1/bh1`, `bx2/by2/bw2/bh2`) e do knob (`kx/ky/ks`) são calculadas em layout (todos `float`). A espessura da barra é `thickness * fontHeight`; o knob é `knobSize * fontHeight` (do `SliderStyle`).

## Exemplo completo (copiar, colar e rodar)
```java
package com.exemplo;

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

/** Tela principal executável. Aponte o launcher (classname) e rode: 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);

      // Slider contínuo 0..100 iniciando em 50; onAction dispara a cada mudança de value
      Slider volume = new Slider(0, 100, 50);
      volume.onAction(c -> saida.setText("Volume: " + (int) volume.value));
      add(LAY_AUTO, volume);
   }
}
```

> Os trechos abaixo mostram **só o miolo** (o que vai dentro de `onShow()`). Para rodar, coloque-os no esqueleto `MainWindow` acima.

## Uso básico
```java
Slider volume = new Slider(0, 100, 50);                 // contínuo, inicia em 50
volume.onAction(c -> System.out.println("valor: " + volume.value));
container.add(LAY_AUTO, volume);
```

## Construtores
| Construtor | Descrição |
|---|---|
| `Slider(float min, float max, float value)` | Slider **contínuo**. |
| `Slider(float min, float max, float value, int npos)` | Slider **discreto**: `npos` posições (ex.: `5` → passos em 0%, 25%, 50%, 75%, 100%). |

## Propriedades e personalização
| Propriedade / método | Tipo | Padrão | O que faz |
|---|---|---|---|
| `value` | `float` (campo) | ctor | Valor atual (leitura). |
| `min` / `max` | `float` (campo) | ctor | Limites do intervalo. |
| `npos` | `int` (campo) | `0` | Nº de posições discretas; `0` = contínuo. |
| `setValue(float)` | `void` | — | Define o valor imediatamente (= `setValue(v, false)`); aplica `clamp` + `snap`. |
| `setValue(float, boolean animated)` | `void` | — | Define o valor com/sem animação; dispara `runActions()`. |

## Callbacks e eventos
| Callback | Quando dispara |
|---|---|
| `onAction(Action)` | A cada alteração de `value` (arrasto, animação de tap e `setValue`). |

## Estados
- **dragging**: enquanto o usuário arrasta o knob (`onPan`), `value` é atualizado a cada movimento.
- **tap-to-jump**: tocar fora do knob anima até o ponto tocado (`PositionAnimation`, duração `style.animationDuration`).
- **pressed**: usa o estilo pressionado próprio (`sliderPressed()`).

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

nivel.setValue(75, true);   // anima até 75 (será snapped ao passo mais próximo)
```

## Boas práticas
- Passe um `value` inicial dentro de `[min, max]`: o **construtor não faz clamp** (só `setValue` faz).
- Para forçar orientação vertical, dê ao slider mais altura que largura no layout.

## Erros comuns
- Assumir orientação fixa: ela é decidida no layout pela razão largura/altura.
- Esperar valores contínuos com `npos > 0`: em modo discreto o valor é sempre "snapped" ao passo.

## Veja também
- Guia da área: [`ui/`](/docs/ui) · Receitas: [`cookbook/`](/docs/cookbook)
- Conceito (layout e responsividade): [`concepts/`](/docs/concepts)
- Componentes relacionados: [`progress`](/docs/ui/widgets/progress)
