# Option

> Checkbox/radio with animated crossfade — checkbox on its own, radio in a Group.

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

# Option

`Option` is a marking control that toggles between an "on" and "off" icon with an animated crossfade, plus an optional label. **Outside a group** it behaves as a **checkbox** (independent check/uncheck); **inside a [`group`](/docs/ui/widgets/group)** it behaves as a **radio button** (mutual exclusion). The visual difference between check and radio comes from the style (`Styles.check()` vs `Styles.radio()`), not the class.

> 🟢 · **Package:** `dev.crossfly.ui` · **Extends:** `Component` (implements `Checkable`, `AlphaAnimation.Animate`) · **Style:** `OptionStyle`

## When to use
- A single checkbox or a list of independent checkboxes ("I accept the terms").
- A small group of mutually exclusive options visible at the same time (radio) via [`group`](/docs/ui/widgets/group).

## When NOT to use
- For an on/off with a switch metaphor → use [`switch`](/docs/ui/widgets/switch).
- For many exclusive options (saving space) → use [`dropdown`](/docs/ui/widgets/dropdown).

## Appearance
On/off icon (from `OptionStyle`) + optional label. The icon alignment (`iconAlignH`/`iconAlignV`) sets the side; the text takes the opposite side (`textAlignH`/`textAlignV`). The `progress` (0→1) mixes the alphas of the two icons during the transition.

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // Styles.check() / Styles.radio()

/** 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("Escolha uma opção");
      add(LAY_AUTO, saida);

      // Independent checkbox (no group)
      Option aceito = new Option("Aceito os termos").style(Styles.check().copy());
      aceito.onAction(c -> saida.setText("Termos: " + (aceito.checked ? "aceitos" : "recusados")));
      add(LAY_AUTO, aceito);

      // Radio: three exclusive options within a Group
      Group pagamento = new Group();
      Option cartao = new Option("Cartão").style(Styles.radio().copy()).group(pagamento).checked(true);
      Option boleto = new Option("Boleto").style(Styles.radio().copy()).group(pagamento);
      Option pix    = new Option("Pix").style(Styles.radio().copy()).group(pagamento);

      Component.Action mostra = c -> {
         String sel = cartao.isChecked() ? "Cartão" : boleto.isChecked() ? "Boleto" : "Pix";
         saida.setText("Pagamento: " + sel);
      };
      cartao.onAction(mostra);
      boleto.onAction(mostra);
      pix.onAction(mostra);

      add(LAY_AUTO, cartao);
      add(LAY_AUTO, boleto);
      add(LAY_AUTO, pix);
   }
}
```

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

## Basic usage
```java
Option aceito = new Option("Aceito os termos");
aceito.style(Styles.check().copy());
aceito.checked(true);                                   // checked initially
aceito.onAction(c -> System.out.println("aceito: " + aceito.checked));
container.add(LAY_AUTO, aceito);
```

## Constructors
| Constructor | Description |
|---|---|
| `Option()` | Unchecked, no label. |
| `Option(String text)` | Unchecked, with label. |

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `text(String)` | `Option` (fluent) | `null` | Sets the label. |
| `checked(boolean)` | `Option` (fluent) | `false` | Initial state **without** animation; notifies the group. |
| `setChecked(boolean)` | `void` | — | State **with** animation (crossfade); notifies the group. |
| `toggle()` | `void` | — | Toggles the state (respecting the group). |
| `checked` | `boolean` (field) | `false` | Current logical state (can be read/written directly). |
| `.group(Group)` | `Option` (fluent) | — | Associates with a [`group`](/docs/ui/widgets/group) → becomes a radio. |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `onAction(Action)` | On `onTouchUp`, **only if** `checked` changed. |

## States
- **checked / unchecked**: via `checked(boolean)` (no animation) or `setChecked(boolean)` (crossfade). The public `checked` field can also be assigned directly.
- **radio (in a group)**: `toggle()` prevents unchecking the already-selected item; checking another one automatically unchecks this one.

### Radio: three exclusive options in a Group
```java
Group g = new Group();

Option a = new Option("Opção A").style(Styles.radio().copy()).group(g).checked(true);
Option b = new Option("Opção B").style(Styles.radio().copy()).group(g);
Option c = new Option("Opção C").style(Styles.radio().copy()).group(g);

container.add(LAY_AUTO, a);
container.add(LAY_AUTO, b);
container.add(LAY_AUTO, c);
// Checking any one unchecks the others automatically.
```

## Best practices
- For radios, call `.group(g)` on **all** options and distinguish with `Styles.radio()`; for checkboxes, omit the group and use `Styles.check()`.
- Prefer `checked(boolean)` over the `checked` field for the initial state: it also adjusts `progress` and notifies the group.

## Common mistakes
- Forgetting `.group(g)` on some option: without a group they become independent checkboxes (no mutual exclusion).
- Expecting to "uncheck" a radio by clicking it: `toggle()` blocks that inside a group.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Concept (styles by state): [`concepts/`](/docs/concepts)
- Related components: [`group`](/docs/ui/widgets/group) · [`switch`](/docs/ui/widgets/switch) · [`dropdown`](/docs/ui/widgets/dropdown)
