# ListViewWindow

> Popup modal que envolve um ListView numa Window para seleção em janela flutuante.

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

# ListViewWindow

`ListViewWindow` envolve um [`ListView`](/docs/ui/widgets/listview) dentro de uma `Window` para comportamento de **popup modal** (seletor flutuante centralizado). Em modo `SINGLE`, o toque num item seleciona e **fecha** a janela; em `MULTIPLE`, o botão "Confirmar" fecha.

A maioria dos métodos apenas **delega** ao `ListView` interno (configuração e consulta de seleção). Use `getPanel()` se quiser o `ListView` embutido sem o popup.

> 🟡 · **Pacote:** `dev.crossfly.ui` · **Estende:** `Window` · **Estilo:** `WindowStyle` (via `selectionWindowStyle()`)

## Quando usar
- Escolha modal que interrompe o fluxo (menu de ações, seletor de item, confirmação de opções).
- Você quer centralização automática e tamanho relativo à tela sem montar a `Window` na mão.

## Quando NÃO usar
- Lista embutida numa tela (não modal) → use [`ListView`](/docs/ui/widgets/listview) direto (ou `getPanel()`).
- Milhares de itens → use [`VirtualListView`](/docs/ui/widgets/virtuallistview) dentro de uma `Window` própria.

## Aparência
Janela centralizada ocupando uma fração da tela (`widthRatio`/`heightRatio`, default `0.5`/`0.5`), contendo o `ListView` (cabeçalho + itens roláveis + botão em `MULTIPLE`). O fundo escurece conforme o `WindowStyle`/`Skin`.

## 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());

      // O ListViewWindow é uma Window (popup): abre com show(), não entra no layout.
      Button abrir = new Button("Escolher vibração");
      abrir.onAction(e -> {
         ListViewWindow pm = new ListViewWindow("Vibrar",
            new String[]{"Curto", "Longo", "Padrão"}, ListViewWindow.ItemType.SINGLE);
         pm.onConfirm(c -> System.out.println("idx = " + pm.getSelectedIndex()));
         pm.show();
      });

      add(.9f, abrir);   // o botão que abre o popup entra no layout
   }
}
```

> 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
// Popup de menu (SINGLE): tocar fecha e reporta o índice
ListViewWindow pm = new ListViewWindow("Vibrar", new String[]{"Curto", "Longo", "Padrão"},
      ListViewWindow.ItemType.SINGLE);
pm.onConfirm(c -> System.out.println("idx = " + pm.getSelectedIndex()));
pm.show();
```

## Construtores
| Construtor | Descrição |
|---|---|
| `ListViewWindow(String[] items, ItemType itemType)` | Popup sem título |
| `ListViewWindow(String title, String[] items, ItemType itemType)` | Popup com título no cabeçalho |

`ListViewWindow.ItemType` é um enum **próprio** (`SINGLE`, `MULTIPLE`) que converte internamente para `ListView.ItemType`.

## Propriedades e personalização
| Propriedade / método | Tipo | Padrão | O que faz |
|---|---|---|---|
| `size(float widthRatio, float heightRatio)` | `ListViewWindow` | `0.5, 0.5` | Tamanho do popup como fração da tela |
| `getPanel()` | `ListView` | — | Acesso ao `ListView` interno |
| `ItemFactory(ItemFactory)` | `ListViewWindow` | `null` | Fábrica de linhas customizadas (note a inicial **maiúscula**) |
| `computeIdealHeight(int)` | `int` | — | Delega a `panel.computeIdealHeight` |
| `title/confirmText/itemStyle/confirmButtonStyle/headerStyle` | `ListViewWindow` | tema | Delegações fluentes ao `ListView` |

### Consulta de seleção (delegada)
`getSelectedCount()`, `getSelectedIndex()`, `getSelectedText()`, `getSelectedIndices()`, `getSelectedTexts()`, `isSelected(int)`, `getSelectionState()`.

## Callbacks e eventos
| Callback | Quando dispara |
|---|---|
| `onConfirm(Component.Action)` | `SINGLE`: ao tocar um item (e fecha). `MULTIPLE`: ao tocar "Confirmar" (e fecha) |

## Estados
Como toda `Window`: use `show()` para exibir e `hide()` para fechar. O `ListView` interno já aponta seu `closeAction` para `this::hide`, então a seleção fecha o popup automaticamente.

### Popup com fábrica de linhas (imagem + label)
```java
Button abrir = new Button("Lista de imagens");
abrir.onAction(e -> {
   ListViewWindow w = new ListViewWindow("Imagens", labels, ListViewWindow.ItemType.SINGLE);
   w.ItemFactory((text, index) -> {
      Image img = new Image(paths[index]);
      ImageView iv = new ImageView(img, UIConstants.ImageSize.RATIO);
      Component row = new Component().style(Styles.component()
         .pressable().ingap(Gap.ofFont(.3f)).autoHeight(Relative.ofFont(3f)));
      row.setLayout(new GridLayout(Position.START, Position.CENTER));
      row.add(.22f, .78f, iv, new Label(text));
      return row;
   });
   w.show();
});
```

### Multi-seleção com tamanho customizado
```java
ListViewWindow w = new ListViewWindow("Tópicos",
      new String[]{"Java", "Kotlin", "Dart"}, ListViewWindow.ItemType.MULTIPLE)
   .size(.7f, .6f)
   .confirmText("OK");
w.onConfirm(c -> System.out.println(w.getSelectedCount() + " marcados"));
w.show();
```

## Boas práticas
- Ajuste `size(...)` para o conteúdo — muitos itens pedem `heightRatio` maior; poucos, menor.
- Para embutir a mesma lista sem popup, chame `getPanel()` e adicione o `ListView` retornado ao seu layout.

## Erros comuns
- **Confundir `ItemFactory(...)` (método, `I` maiúsculo) com o `itemFactory(...)` do `ListView`** — aqui o método fluente começa com maiúscula por convenção da classe.
- **Usar o enum errado** — em `ListViewWindow` passe `ListViewWindow.ItemType`, não `ListView.ItemType`.

## Veja também
- Guia da área: [`ui/`](/docs/ui) · Receitas: [`cookbook/`](/docs/cookbook)
- Componentes relacionados: [`ListView`](/docs/ui/widgets/listview) · [itens de lista](/docs/ui/widgets/list-items)
