# Como centralizar a navegação num controller

> Encapsular push/pop da pilha do EventsProcessor num controller próprio, para navegação testável e desacoplada.

Source: https://crossfly.dev/pt/docs/cookbook/nav/controller-de-navegacao — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Como centralizar a navegação num controller

**Propósito.** Espalhar `new X().show()` e `hide()` pelas telas acopla a UI ao grafo de navegação. Um **controller** concentra push/pop, dá um ponto único para logging/guardas e permite "fechar até a raiz". Ele apenas orquestra a pilha real do `EventsProcessor`.

## APIs usadas
- `Window.show()` / `Window.hide()` — push/pop na pilha (o controller apenas delega a eles).
- `EventsProcessor.topWindow()` — método **estático** que retorna a janela do topo (`instance.windows.peek()`).
- `EventsProcessor.instance.getLastWindow()` — método de **instância**; retorna o topo real da pilha (ou `null` se vazia). Use quando precisar checar se há algo empilhado sem lançar exceção.

> Nomes confirmados na fonte de `EventsProcessor`: `topWindow()` (estático) e `getLastWindow()` (instância). `topWindow()` faz `windows.peek()` e lança se a pilha estiver vazia; `getLastWindow()` retorna `null` nesse caso — prefira este para verificações defensivas.

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

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

/** Tela principal executável: usa o controller Nav para empilhar/desempilhar telas. */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(new Label("Tela raiz"));
      add(new Button("Abrir detalhe").onAction(e -> Nav.push(new OutraTela())));  // push via controller
   }
}

/** Tela empilhada: fecha via controller (pop). */
class OutraTela extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(new Label("Detalhe"));
      add(new Button("Voltar").onAction(e -> Nav.pop()));  // pop via controller
   }
}

/** Controller: fachada fina sobre a pilha real do EventsProcessor. */
final class Nav
{
   private Nav() {}

   /** push: empilha e exibe. */
   public static void push(Window w)
   {
      w.show();
   }

   /** pop: fecha a janela do topo, se houver. */
   public static void pop()
   {
      Window top = EventsProcessor.instance.getLastWindow();  // null-safe
      if (top != null)
         top.hide();
   }

   /** janela atualmente no topo (pode ser null). */
   public static Window current()
   {
      return EventsProcessor.instance.getLastWindow();
   }
}
```

> O trecho abaixo mostra **só o miolo**. Para rodar, coloque-o no esqueleto `MainWindow` acima.

## Trecho mínimo
```java
// verificado na fonte: EventsProcessor.topWindow() (static) e instance.getLastWindow() (retorna null se vazia)
public final class Nav
{
   private Nav() {}

   /** push: empilha e exibe. */
   public static void push(Window w)
   {
      w.show();
   }

   /** pop: fecha a janela do topo, se houver. */
   public static void pop()
   {
      Window top = EventsProcessor.instance.getLastWindow();  // null-safe
      if (top != null)
         top.hide();
   }

   /** pop repetido até sobrar apenas 1 janela (a raiz). */
   public static void popToRoot()
   {
      Window top;
      // enquanto houver mais de uma janela empilhada, some com o topo
      while ((top = EventsProcessor.instance.getLastWindow()) != null
             && top != EventsProcessor.topWindow()) { top.hide(); }
      // (para "voltar à raiz", cada hide() desempilha uma; ajuste o critério de parada à sua app)
   }

   /** janela atualmente no topo (pode ser null). */
   public static Window current()
   {
      return EventsProcessor.instance.getLastWindow();
   }
}

// uso nas telas:
Nav.push(new DetalheTela());
// ...
Nav.pop();
```

Boas práticas:

- **Não** reimplemente a pilha: o `EventsProcessor` já é a fonte da verdade. O controller é uma fachada fina sobre `show()`/`hide()`.
- Guardas de navegação (ex.: "há alterações não salvas?") ficam naturais aqui: cheque antes de `pop()` e, se preciso, dispare um `Alert` de confirmação.
- Cuidado com `topWindow()` quando a pilha pode estar vazia — ele faz `peek()` e lança. Para código defensivo use `getLastWindow()`.

## Aprofunde-se
- [A pilha de janelas](/docs/ui/navigation/the-window-stack) · [Navegar entre telas](/docs/ui/navigation/navigate-between-screens)
- Receita irmã: [Abrir e fechar uma tela](/docs/cookbook/nav/abrir-tela)
