# Cómo dejar que el usuario elija una ubicación en el mapa

> Abrir un mapa con pin arrastrable y GPS para que el usuario confirme una coordenada (LatLon) vía LocationPicker.

Source: https://crossfly.dev/es/docs/cookbook/device/escolher-local-no-mapa — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo dejar que el usuario elija una ubicación en el mapa

**Propósito.** Abrir una pantalla de mapa (Google) con **pin arrastrable** y rastreo GPS, para que el
usuario confirme una posición. El resultado es un `LatLon` entregado por callback.

## APIs usadas
- `LocationPicker(RunnableWith<LatLon> onCapture, double minPdop, boolean canDragPin, boolean highPrecision, boolean streetview)` — constructor completo (es la firma real de la fuente).
  - `onCapture` — callback llamado con el `LatLon` confirmado (puede ser `null`).
  - `minPdop` — PDOP mínimo aceptable; el botón de confirmar queda oculto hasta que el fix alcance esa precisión (en el escritorio siempre está habilitado).
  - `canDragPin` — `true` para permitir arrastrar el pin a una posición personalizada.
  - `highPrecision` — `true` para GPS de alta precisión.
  - `streetview` — `true` para habilitar street view en el mapa.
- `LatLon getAnswer()` — posición confirmada, o `null` si se canceló.
- Estáticos configurables: `LocationPicker.defaultZoom`, `Instrucoes`, `GpsLocation`, `CustomLocation`, `Precision`, `Meters`.

> **Divergencia vs. la descripción del pedido.** El `LocationPicker` **no** usa `show(onAnswer)` para el
> resultado: la coordenada llega por el `RunnableWith<LatLon> onCapture` pasado en el **constructor**
> (y también queda en `getAnswer()`). El `onCapture` solo se llama cuando el usuario **confirma** con una
> posición no nula. Internamente el picker ejecuta su **propio** `GPSThread` (clase interna) y ya
> despacha las actualizaciones vía `Component.onUI(...)`, así que tu callback se ejecuta en el paint thread.

## Ejemplo completo (copiar, pegar y ejecutar)

```java
package com.exemplo;

import dev.crossfly.ui.*;                   // Window, Button, Label
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.ui.picker.*;            // LocationPicker
import dev.crossfly.map.*;                  // LatLon
import dev.crossfly.util.*;                 // RunnableWith

/** 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 resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Escolher no mapa");
      acao.onAction(c ->
      {
         RunnableWith<LatLon> aoConfirmar = coord ->
         {
            // Ya llega en la paint thread (el picker usa Component.onUI internamente)
            resultado.setText("Lat " + coord.lat + " / Lon " + coord.lon);
         };

         LocationPicker picker = new LocationPicker(
            aoConfirmar,   // callback con el LatLon confirmado
            30.0,          // minPdop: habilita confirmar cuando la precisión <= 30m
            true,          // canDragPin: el usuario puede arrastrar el pin
            true,          // highPrecision
            false);        // streetview
         picker.show();
      });
      add(LAY_AUTO, acao);
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo

```java
// verificado en la fuente: LocationPicker.java (constructor líneas 129-141, onCapture/closeWith, getAnswer)
import dev.crossfly.ui.picker.*;           // LocationPicker
import dev.crossfly.map.*;                 // LatLon
import dev.crossfly.util.*;                // RunnableWith

RunnableWith<LatLon> aoConfirmar = coord -> {
   // Ya llega en la paint thread (el picker usa Component.onUI internamente)
   double lat = coord.lat, lon = coord.lon;
   salvarLocal(lat, lon);
};

LocationPicker picker = new LocationPicker(
   aoConfirmar,   // callback con el LatLon confirmado
   30.0,          // minPdop: habilita confirmar cuando la precisión <= 30m
   true,          // canDragPin: el usuario puede arrastrar el pin
   true,          // highPrecision
   false);        // streetview
picker.show();

// Alternativa: leer el resultado después con getAnswer() (null si se canceló)
```

## Profundiza
- Guía de ubicación: [Location & GPS](/docs/data-and-services/device-location-gps) · Widget: [LocationPicker](/docs/ui/widgets/locationpicker)
- Receta hermana: [obter-gps.md](/docs/cookbook/device/obter-gps)
