# Button

> Botón clicable que muestra texto y/o icono, con estado de presionado y onAction.

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

# Button

`Button` es el componente interactivo más básico: muestra texto y/o icono y dispara una acción al ser tocado, con estado visual de presionado (vía `ButtonStyle`). Cuando hay texto **e** icono, la posición relativa entre ellos se controla mediante el enum [`TextPos`](/docs/reference). Es también la base de otros widgets (por ejemplo, `Dropdown extends Button`).

La acción se registra con `onAction(Action)` (heredado de `Component`); el disparo ocurre en el flujo estándar de clic (`runActions()` en `onTouchUp`), no en `onTouchDown`.

> 🟢 · **Paquete:** `dev.crossfly.ui` · **Extiende:** `Component` · **Estilo:** `ButtonStyle`

## Cuándo usar
- Cualquier acción tocable: guardar, confirmar, navegar, abrir un diálogo.
- Botón solo-icono (barra de herramientas) o solo-texto (enlace/acción secundaria).

## Cuándo NO usar
- Etiqueta estática → usa [`Label`](/docs/ui/widgets/label).
- Alternancia persistente activar/desactivar → usa `Switch`/`Option` (ver [`ui/`](/docs/ui)).

## Apariencia
Texto y/o icono centrados dentro del botón. Con ambos presentes, el bloque `[icono + gap + texto]` se centra en ambos ejes; `icongap` define el espaciado. La posición sigue `TextPos`:

| `TextPos` | Layout | `isHorizontal()` |
|---|---|---|
| `NONE` | texto e icono superpuestos (centrados) | false |
| `TEXT_AT_LEFT` | texto a la izquierda del icono | true |
| `TEXT_AT_RIGHT` | texto a la derecha del icono | true |
| `TEXT_AT_TOP` | texto encima del icono | false |
| `TEXT_AT_BOTTOM` | texto debajo del icono | false |

Si `textPos == null`, el valor por defecto es superposición centrada (equivalente a `NONE`).

``

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // Label que muestra cuántas veces se tocó el botón
      Label saida = new Label("Cliques: 0");
      add(LAY_AUTO, saida);

      // Contador mutable usado dentro del callback (array de 1 posición)
      final int[] cliques = {0};

      // Botón que incrementa el contador y actualiza el Label en cada toque
      Button botao = new Button("Clique aqui")
         .onAction(c -> saida.setText("Cliques: " + (++cliques[0])));
      add(LAY_AUTO, botao);
   }
}
```

> Los fragmentos siguientes muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutarlos, colócalos en el esqueleto `MainWindow` de arriba.

## Uso básico
```java
Button b = new Button("Salvar").onAction(c -> salvar());
container.add(LAY_AUTO, b);
```

## Constructores
| Constructor | Descripción |
|---|---|
| `Button(String text)` | botón solo con texto |
| `Button(Icon icon)` | botón solo con icono |
| `Button(String text, Icon icon, TextPos textPos)` | texto + icono con posición relativa |

## Propiedades y personalización
| Propiedad / método | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `setText(String)` | `void` | — | cambia el texto, invalida el layout y llama a `repaint()` |
| `icon(Icon, TextPos)` | `Button` (fluido) | — | define el icono y su posición relativa al texto |
| `text` / `icon` / `textPos` | campos públicos | — | contenido actual (pueden leerse/asignarse) |
| estilo `.pressable()` | — | — | habilita el realce de presionado |
| estilo `.textAlign(Position, Position)` | `Position` | tema | alineación del contenido |
| estilo `.autoWidth(Relative)` / `.autoHeight(Relative)` | `Relative` | — | fija el tamaño preferido |
| `getAutoWidth()` / `getAutoHeight(int)` | `int` | — | tamaños preferidos por contenido |

## Callbacks y eventos
| Callback | Cuándo se dispara |
|---|---|
| `onAction(Action)` | al completar el clic (touch-up), vía `runActions()`. Devuelve `this`, permitiendo encadenar (`new Button(...).onAction(...).style(...)`). |

El `Action` es `c -> { ... }`, donde `c` es el `Component` de origen; puede lanzar `Exception`.

## Estados
- **pressed:** mientras está presionado, el `ButtonStyle` aplica el estilo de presión (con fade). Requiere `pressable()` en el estilo.
- **disabled:** `setEnabled(false)` aplica la apariencia deshabilitada e ignora los toques.

### Botón con icono a la derecha del texto
```java
Button proximo = new Button(
   "Próximo", new MaterialIcon(""), TextPos.TEXT_AT_RIGHT);
container.add(LAY_AUTO, proximo);
```

### Botón estilo "enlace" que limpia 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);
```

## Buenas prácticas
- Pasa siempre `textPos` cuando el botón tiene texto **e** icono (si no, quedan superpuestos).
- Usa roles del tema (`ButtonRole.PRIMARY`/`SECONDARY`/`LINK`) para consistencia visual.
- Para espaciar botones, usa `Gap` o `ingap`/`outgap`/fracciones del layout — el `Spacer` fue eliminado (ver [`spacing.md`](/docs/ui/widgets/spacing)).

## Errores comunes
- **`text` + `icon` sin `textPos`:** el resultado queda superpuesto (comportamiento de `null` = `NONE`).
- **Esperar disparo en `onTouchDown`:** la acción se dispara en el flujo estándar de clic (touch-up).

## Ver también
- Guía del área: [`ui/`](/docs/ui) · Recetas: [`cookbook/`](/docs/cookbook)
- Concepto (modelo de componentes / `onAction`): [`concepts/`](/docs/concepts)
- Componentes relacionados: [`Label`](/docs/ui/widgets/label) · [`ImageView`](/docs/ui/widgets/imageview)
