# Button

> Botão clicável que exibe texto e/ou ícone, com estado de pressionado e onAction.

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

# Button

`Button` é o componente interativo mais básico: exibe texto e/ou ícone e dispara uma ação ao ser tocado, com estado visual de pressionado (via `ButtonStyle`). Quando há texto **e** ícone, a posição relativa entre eles é controlada pelo enum [`TextPos`](/docs/reference). É também a base de outros widgets (por exemplo, `Dropdown extends Button`).

A ação é registrada com `onAction(Action)` (herdado de `Component`); o disparo ocorre no fluxo padrão de clique (`runActions()` em `onTouchUp`), não em `onTouchDown`.

> 🟢 · **Pacote:** `dev.crossfly.ui` · **Estende:** `Component` · **Estilo:** `ButtonStyle`

## Quando usar
- Qualquer ação tocável: salvar, confirmar, navegar, abrir um diálogo.
- Botão só-ícone (barra de ferramentas) ou só-texto (link/ação secundária).

## Quando NÃO usar
- Rótulo estático → use [`Label`](/docs/ui/widgets/label).
- Alternância persistente liga/desliga → use `Switch`/`Option` (ver [`ui/`](/docs/ui)).

## Aparência
Texto e/ou ícone centralizados dentro do botão. Com ambos presentes, o bloco `[ícone + gap + texto]` é centralizado em ambos os eixos; o `icongap` define o espaçamento. O posicionamento segue `TextPos`:

| `TextPos` | Layout | `isHorizontal()` |
|---|---|---|
| `NONE` | texto e ícone sobrepostos (centrados) | false |
| `TEXT_AT_LEFT` | texto à esquerda do ícone | true |
| `TEXT_AT_RIGHT` | texto à direita do ícone | true |
| `TEXT_AT_TOP` | texto acima do ícone | false |
| `TEXT_AT_BOTTOM` | texto abaixo do ícone | false |

Se `textPos == null`, o padrão é sobreposição centralizada (equivalente a `NONE`).

``

## 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 que exibe quantas vezes o botão foi tocado
      Label saida = new Label("Cliques: 0");
      add(LAY_AUTO, saida);

      // Contador mutável usado dentro do callback (array de 1 posição)
      final int[] cliques = {0};

      // Botão que incrementa o contador e atualiza o Label a cada toque
      Button botao = new Button("Clique aqui")
         .onAction(c -> saida.setText("Cliques: " + (++cliques[0])));
      add(LAY_AUTO, botao);
   }
}
```

> 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
Button b = new Button("Salvar").onAction(c -> salvar());
container.add(LAY_AUTO, b);
```

## Construtores
| Construtor | Descrição |
|---|---|
| `Button(String text)` | botão só com texto |
| `Button(Icon icon)` | botão só com ícone |
| `Button(String text, Icon icon, TextPos textPos)` | texto + ícone com posição relativa |

## Propriedades e personalização
| Propriedade / método | Tipo | Padrão | O que faz |
|---|---|---|---|
| `setText(String)` | `void` | — | troca o texto, invalida layout e chama `repaint()` |
| `icon(Icon, TextPos)` | `Button` (fluente) | — | define ícone e sua posição relativa ao texto |
| `text` / `icon` / `textPos` | campos públicos | — | conteúdo atual (podem ser lidos/atribuídos) |
| estilo `.pressable()` | — | — | habilita o realce de pressionado |
| estilo `.textAlign(Position, Position)` | `Position` | tema | alinhamento do conteúdo |
| estilo `.autoWidth(Relative)` / `.autoHeight(Relative)` | `Relative` | — | fixa o tamanho preferido |
| `getAutoWidth()` / `getAutoHeight(int)` | `int` | — | tamanhos preferidos por conteúdo |

## Callbacks e eventos
| Callback | Quando dispara |
|---|---|
| `onAction(Action)` | ao concluir o clique (touch-up), via `runActions()`. Retorna `this`, permitindo encadear (`new Button(...).onAction(...).style(...)`). |

O `Action` é `c -> { ... }`, onde `c` é o `Component` de origem; pode lançar `Exception`.

## Estados
- **pressed:** enquanto pressionado, o `ButtonStyle` aplica o estilo de pressão (com fade). Requer `pressable()` no estilo.
- **disabled:** `setEnabled(false)` aplica a aparência desabilitada e ignora toques.

### Botão com ícone à direita do texto
```java
Button proximo = new Button(
   "Próximo", new MaterialIcon(""), TextPos.TEXT_AT_RIGHT);
container.add(LAY_AUTO, proximo);
```

### Botão estilo "link" que limpa campos
```java
Button clear = new Button("Clear").style(
   Styles.theme().button(ButtonRole.LINK, State.NORMAL)
      .pressable()
      .textAlign(Position.CENTER, Position.CENTER));
clear.onAction(c -> {
   nome.clearText();
   email.clearText();
});
container.add(LAY_AUTO, clear);
```

## Boas práticas
- Sempre passe `textPos` quando o botão tem texto **e** ícone (senão ficam sobrepostos).
- Use papéis do tema (`ButtonRole.PRIMARY`/`SECONDARY`/`LINK`) para consistência visual.
- Para espaçar botões, use `Gap` ou `ingap`/`outgap`/frações do layout — o `Spacer` foi removido (ver [`spacing.md`](/docs/ui/widgets/spacing)).

## Erros comuns
- **`text` + `icon` sem `textPos`:** o resultado fica sobreposto (comportamento de `null` = `NONE`).
- **Esperar disparo em `onTouchDown`:** a ação dispara no fluxo padrão de clique (touch-up).

## Veja também
- Guia da área: [`ui/`](/docs/ui) · Receitas: [`cookbook/`](/docs/cookbook)
- Conceito (modelo de componentes / `onAction`): [`concepts/`](/docs/concepts)
- Componentes relacionados: [`Label`](/docs/ui/widgets/label) · [`ImageView`](/docs/ui/widgets/imageview)
