# toaster — `n_pbt_toaster` #

← Riferimento dei componenti · Sommario della guida

> Notifiche « toast » in un angolo dello schermo: un messaggio che appare, informa e scompare senza bloccare l'utente né interrompere la sua digitazione.

> ▶ Vederlo dal vivo — Applicazione dimostrativa, riquadro Toaster: l'anteprima, il codice che lo produce e questa pagina, affiancati.

## In breve #

Oggetto | `n_pbt_toaster` — non visuale: niente da collocare nella finestra
Serve per | Confermare un'azione riuscita, segnalare un avviso o un errore, senza interrompere il lavoro in corso
Ritorno | Non bloccante: `of_show()` restituisce subito il controllo; le reazioni dell'utente tornano tramite event

Il toast è una finestra staccata: fluttua sopra la Sua applicazione (o sopra tutto lo schermo) e si chiude da solo.

    n_pbt_toaster lnv_toast

    lnv_toast = create n_pbt_toaster
    // ... configurazione ...
    destroy lnv_toast

## Avvio rapido #

    n_pbt_toaster lnv_toast

    lnv_toast = create n_pbt_toaster

    lnv_toast.ipo_owner = this                       // finestra a cui il toast si aggancia
    lnv_toast.is_kind   = lnv_toast.KIND_SUCCESS     // icona verde + bordino di successo
    lnv_toast.is_text   = "Le Sue modifiche sono state [b]salvate[/b]."
    lnv_toast.of_show()

    destroy lnv_toast

Tutto si configura tramite proprietà, poi `of_show()` — che non accetta alcun argomento — fa apparire la notifica.

## Proprietà #

Da impostare prima di `of_show`.

Proprietà | Tipo | Predefinito | Ruolo
--- | --- | --- | ---
`is_text` | string | `""` | Corpo del messaggio. Accetta il testo formattato con tag
`is_kind` | string | `KIND_INFO` | Livello: governa l'icona e il colore del bordino. Costanti `KIND_*`
`is_position` | string | `POSITION_BOTTOM_RIGHT` | Angolo di ancoraggio. Costanti `POSITION_*`
`ib_screen` | boolean | `false` | `false` = ancorato all'angolo della finestra; `true` = ancorato all'angolo dello schermo, fluttuante sopra tutto
`il_timeout` | long | `TIMEOUT_AUTO` | Durata di visualizzazione in millisecondi prima della chiusura automatica. `TIMEOUT_AUTO` (`-1`, il valore predefinito) vale 4 s per un'informazione ma fino al clic per un errore — un errore che sparisce dopo quattro secondi è un errore perduto. `TIMEOUT_UNTIL_CLICKED` (`0`) rende persistente qualunque toast; una durata esplicita viene rispettata così com'è. Finché il puntatore resta sul toast il conto alla rovescia è sospeso, e una barra mostra il tempo restante
`is_title` | string | `""` | Riga di titolo in grassetto sopra il messaggio (toast avanzato)
`is_image` | string | `""` | Immagine illustrativa a sinistra, al posto dell'icona di livello (forme accettate: percorso, `mono:`, risorsa di DLL)
`is_key` | string | `""` | Chiave del toast: rimostrare la stessa chiave aggiorna il toast già a schermo invece di aprirne un secondo. È ciò di cui ha bisogno una notifica di avanzamento («Export 3/10» poi «4/10»): chiudere e riaprire farebbe ripartire l'animazione e scomporrebbe la pila. Lasci vuoto per un toast ordinario
`il_max_visible` | long | `5` | Numero massimo di toast a schermo nello stesso angolo (da 1 a 20). Oltre, i successivi aspettano e compaiono man mano che si libera posto: un ciclo di elaborazione che emette un toast per riga impilava altrimenti le finestre fuori dallo schermo
`ipo_owner` | powerobject | — | L'oggetto visuale a cui il toast è agganciato (il suo angolo di finestra serve da riferimento)
`ipo_receiver` | powerobject | — | L'oggetto visuale che riceve gli event del toast. Lo lasci vuoto per una notifica senza ritorno

### Costanti #

Costante | Valore | Uso
--- | --- | ---
`KIND_INFO` | `"info"` | Informazione neutra
`KIND_SUCCESS` | `"success"` | Operazione riuscita
`KIND_WARNING` | `"warning"` | Avviso
`KIND_ERROR` | `"error"` | Fallimento
`POSITION_TOP_LEFT` | `"top-left"` | Angolo in alto a sinistra
`POSITION_TOP_CENTER` | `"top-center"` | In alto, centrato
`POSITION_TOP_RIGHT` | `"top-right"` | Angolo in alto a destra
`POSITION_BOTTOM_LEFT` | `"bottom-left"` | Angolo in basso a sinistra
`POSITION_BOTTOM_CENTER` | `"bottom-center"` | In basso, centrato
`POSITION_BOTTOM_RIGHT` | `"bottom-right"` | Angolo in basso a destra (predefinito)

> Perché `LEFT`/`RIGHT` qui, e `START`/`END` altrove? Il toast è una finestra di sistema posizionata in pixel dello schermo, non un contenuto che segue un senso di lettura: un angolo dello schermo non ha un « inizio ». Queste costanti restano quindi volutamente fisiche e non cambiano lato quando l'applicazione passa alla scrittura da destra a sinistra. Vedere Lingua e RTL.

## Metodi #

Metodo | Ruolo
--- | ---
`of_show ( )` → long | Visualizza la notifica costruita a partire dalle proprietà. Restituisce l'identificatore del toast (`> 0`), oppure un valore negativo in caso di errore. Non blocca
`of_close ( long al_id )` → long | Chiude un toast ancora visualizzato, indicato dall'identificatore restituito da `of_show`. Restituisce `0`, oppure `-5` se l’identificatore è vuoto o indica un toast già scomparso
`of_reset ( )` | Riporta tutte le proprietà di contenuto ai valori predefiniti e cancella i pulsanti (`ipo_owner` e `ipo_receiver` vengono conservati: sono collegamenti, non contenuto)
`of_process_events ( )` | Svuota la coda dei ritorni del toast e attiva i corrispondenti event `ue_toast_*` — vedere più avanti
`of_add_button (string as_key, string as_label {, string as_image })` → long | Aggiunge un pulsante d'azione (al massimo 3) e ne restituisce il numero. Un clic emette `ue_toast_action(id, chiave)`; `of_reset` azzera i pulsanti. Un'etichetta può contenere qualunque carattere — una virgola, un segno di uguale — senza essere tagliata

Più toast visualizzati nello stesso angolo si impilano automaticamente. Ciascuno porta una croce di chiusura; l'identificatore restituito da `of_show` permette di distinguerli negli event e di chiuderli dal Suo codice.

Il conto alla rovescia si sospende finché il puntatore è sul toast: una notifica non deve svanire sotto gli occhi di chi la legge. Una sottile barra in basso mostra il tempo restante — e quindi spiega la sua sparizione. Un clic sul corpo risponde e chiude, in entrambe le modalità di hosting.

Una notifica impostata con `il_timeout = 0` resta a schermo finché nessuno la chiude: conservi il suo identificatore per poterla rimuovere quando l'attività che annuncia è terminata.

    long ll_toast

    // Notifica persistente : restera visualizzata fino a of_close.
    inv_toaster.is_text = "Esportazione in corso..."
    inv_toaster.il_timeout = /*ms, 0 = nessuna chiusura automatica*/ 0
    ll_toast = inv_toaster.of_show()

    // ... elaborazione lunga ...

    inv_toaster.of_close(/*id*/ ll_toast)

## Event — il toast Le risponde #

Una notifica non è un semplice « visualizza e dimentica »: può dirLe che è stata cliccata, che è stato scelto un pulsante d'azione, o che si è chiusa.

Poiché il toast vive in una finestra staccata, il collegamento avviene in tre passaggi.

1. Designare l'oggetto visuale destinatario:

    inv_toaster.ipo_owner    = this
    inv_toaster.ipo_receiver = this      // questo userobject / questa finestra ricevera i ritorni

> `ipo_receiver` deve essere un oggetto visuale (finestra o userobject). Un oggetto non visuale non può ricevere notifiche di sistema.

2. Dichiarare su questo oggetto visuale un event mappato su `pbm_custom02`, che svuota la coda:

    // event ue_toast_notified, mappato su pbm_custom02
    if IsValid(inv_toaster) then inv_toaster.of_process_events()

3. Trattare gli event attivati sul toaster:

Event | Attivato quando
--- | ---
`ue_toast_clicked (string as_id)` | Viene cliccato il corpo del toast (non un pulsante)
`ue_toast_action (string as_id, string as_action)` | Viene cliccato un pulsante d'azione; `as_action` contiene la chiave passata a `of_add_button`
`ue_toast_dismissed (string as_id)` | Il toast si chiude: tempo scaduto, croce di chiusura, oppure dopo un'azione

Senza `ipo_receiver`, la notifica appare e scompare senza mai restituire nulla — è la modalità più semplice, perfetta per una semplice conferma.

## Esempi #

### I quattro livelli #

    inv_toaster.of_reset()
    inv_toaster.is_kind = inv_toaster.KIND_INFO
    inv_toaster.is_text = "Operazione terminata."
    inv_toaster.of_show()

    inv_toaster.of_reset()
    inv_toaster.is_kind = inv_toaster.KIND_SUCCESS
    inv_toaster.is_text = "Le Sue modifiche sono state [b]salvate[/b]."
    inv_toaster.of_show()

    inv_toaster.of_reset()
    inv_toaster.is_kind    = inv_toaster.KIND_WARNING
    inv_toaster.il_timeout = 5000                        // un po' piu lungo
    inv_toaster.is_text    = "Spazio su disco insufficiente sull'unità C:."
    inv_toaster.of_show()

    inv_toaster.of_reset()
    inv_toaster.is_kind    = inv_toaster.KIND_ERROR
    inv_toaster.il_timeout = 6000
    inv_toaster.is_text    = "Impossibile contattare il server."
    inv_toaster.of_show()

### Scegliere l'angolo, nella finestra o sullo schermo #

    // Ancorato all'angolo in alto a destra della FINESTRA (predefinito : segue l'applicazione)
    inv_toaster.is_position = inv_toaster.POSITION_TOP_RIGHT
    inv_toaster.ib_screen   = false
    inv_toaster.is_text     = "Ancorato all'angolo della finestra."
    inv_toaster.of_show()

    // Staccato : ancorato all'angolo dello SCHERMO, visibile anche se la finestra e ridotta a icona
    inv_toaster.is_position = inv_toaster.POSITION_TOP_RIGHT
    inv_toaster.ib_screen   = true
    inv_toaster.is_text     = "Elaborazione notturna terminata."
    inv_toaster.of_show()

### Toast avanzato: titolo, immagine e durata #

    inv_toaster.of_reset()

    inv_toaster.is_title    = "Backup completato"
    inv_toaster.is_text     = "1 240 file copiati in [b]\\server\backup[/b]."
    inv_toaster.is_image    = "mono:img\backup.svg"
    inv_toaster.il_timeout  = 8000                    // resta 8 secondi
    inv_toaster.of_show()

### Notifica con pulsanti d'azione #

    // event open : collegare il ritorno una volta per tutte
    inv_toaster.ipo_owner    = this
    inv_toaster.ipo_receiver = this

    // Proporre due azioni ; timeout 0 = il toast attende la decisione dell'utente
    inv_toaster.of_reset()

    inv_toaster.is_title   = "Aggiornamento disponibile"
    inv_toaster.is_text    = "La versione 2.0 è pronta per essere installata."
    inv_toaster.il_timeout = 0
    inv_toaster.of_add_button(/*chiave*/ "installer", /*etichetta*/ "Installa")
    inv_toaster.of_add_button(/*chiave*/ "plus_tard", /*etichetta*/ "Piu tardi")
    inv_toaster.of_show()

    // event ue_toast_notified della finestra, mappato su pbm_custom02
    if IsValid(inv_toaster) then inv_toaster.of_process_events()

    // event ue_toast_action di inv_toaster : (string as_id, string as_action)
    choose case as_action
        case "installer" ; of_lancer_mise_a_jour()
        case "plus_tard" ; of_reporter(1)
    end choose

### Reagire al clic sul messaggio #

    // event ue_toast_clicked di inv_toaster : (string as_id)
    // L'utente ha cliccato il corpo del toast : aprire la schermata interessata
    Open(w_journal_import)

### Notificare da un'elaborazione lunga #

    // Fine di un'importazione : informare senza bloccare la schermata di digitazione
    inv_toaster.of_reset()

    if ll_erreurs = 0 then
        inv_toaster.is_kind = inv_toaster.KIND_SUCCESS
        inv_toaster.is_text = "Importazione terminata : [b]" + String(ll_lignes) + " righe[/b] integrate."
    else
        inv_toaster.is_kind    = inv_toaster.KIND_ERROR
        inv_toaster.il_timeout = 0                    // un errore deve essere letto
        inv_toaster.is_text    = "Importazione interrotta : " + String(ll_erreurs) + " errori."
    end if

    inv_toaster.of_show()

## Buone pratiche #

- Un'istanza persistente per finestra (variabile di istanza creata all'apertura) invece di una creazione/distruzione a ogni messaggio: il collegamento `ipo_receiver` resta in essere e i ritorni arrivano.
- Chiami `of_reset()` prima di ogni notifica: senza di esso il titolo, l'immagine o i pulsanti della precedente restano impostati.
- Riservi `il_timeout = 0` ai messaggi che esigono una decisione (errore bloccante, azione proposta): un toast che non se ne va da solo finisce per infastidire.
- Usi `ib_screen = true` soltanto per ciò che deve restare visibile quando l'applicazione è in secondo piano (fine di un'elaborazione lunga, attività notturna).
- Un toast è un messaggio transitorio: se serve assolutamente una risposta prima di continuare, usi messagebox, che blocca e restituisce la scelta.
- Per uno stato permanente invece di una notifica, preferisca statusbar.

← Riferimento dei componenti · Sommario della guida