Vai al contenuto

mte.ui — costruttori di specifiche di modulo

Ogni superficie dell'interfaccia della fase 3 — ctx.docks.add_panel e ctx.settings_page.register — accetta una specifica di modulo: un semplice dizionario che descrive un albero di widget. Costruisci queste specifiche con gli ausili mte.ui.*, così da non dover scrivere il JSON a mano.

from mte.ui import (
    Column, Row, Group,
    Label, Button, Checkbox, LineEdit, NumberSpin, ComboBox, List,
)

Niente in mte.ui parla con Qt o PySide: ogni ausilio restituisce un dizionario che segue lo schema di trasmissione atteso dall'analizzatore di moduli C++ dell'host. Sentiti libero di comporli, di innestare elenchi o di generarli in modo programmatico:

from mte.ui import Column, Row, Label, Button

def make_toolbar(commands):
    return Row([Button(text=c["label"], on_click=c["id"])
                for c in commands])

form = Column([Label(text="Actions:"),
               make_toolbar(my_commands)])

La specifica viene validata lato host; tipi di controllo sconosciuti o campi obbligatori mancanti producono un errore InvalidParams che vedrai nel log.

Le etichette in una specifica di modulo non vengono tradotte

Ogni didascalia che metti in una specifica — titoli di pannello, etichette di caselle di spunta, intestazioni di gruppo — viene mostrata esattamente come l'hai scritta, qualunque sia la lingua dell'interfaccia. Sono dati che il tuo plugin invia all'editor, non stringhe che l'editor possa cercare in un catalogo di traduzione. Se il tuo plugin deve parlare più di una lingua, scegli tu le stringhe prima di chiamare register; la lingua dell'interfaccia corrente è ctx.app_settings.get_string(mte.keys.UI_LANGUAGE) (vuota significa «segui il sistema»). Lo stesso vale per il name e la description che il tuo plugin.json mostra in Preferenze ▸ Estensioni.


Disposizioni

I costruttori di disposizione prendono un elenco di dizionari figli e li dispongono verticalmente od orizzontalmente.

Column(children)

Impila i figli dall'alto verso il basso con un allungamento finale: i controlli restano alla loro altezza naturale invece di gonfiarsi per riempire un pannello alto.

Row(children)

Stessa idea, da sinistra a destra, con un allungamento orizzontale finale.

Group(children, *, title="")

Una cornice con titolo (resa come QGroupBox) che contiene una pila verticale. Usala per raggruppare visivamente controlli correlati:

Group([
    Checkbox(id="cs", label="Case sensitive", binds="settings:cs"),
    Checkbox(id="ww", label="Whole words",    binds="settings:ww"),
], title="Search options")

Le disposizioni si annidano liberamente: una Row dentro una Column dentro un Group va benissimo.


Controlli foglia

Ogni foglia accetta gli stessi quattro collegamenti condivisi tramite argomenti nominati:

Argomento Significato
id= Id stabile usato da ctx.ui.get / ctx.ui.set e (implicitamente) da binds.
binds= "settings:<key>" — rende persistente automaticamente tramite ctx.settings.
on_click= Id del comando da invocare — solo per i Button.
on_change= Id del gestore (ctx.docks.on_change(...)) — per ogni altro controllo.

Solo le foglie che espongono un «valore» supportano binds e on_change.

Label(*, text="", id=None)

Testo statico.

Button(*, text, on_click=None, id=None)

Un pulsante. Far scattare on_click invoca il comando registrato; se vuoi tenere il pulsante sincronizzato con qualcos'altro puoi impostarne il text con ctx.ui.set.

Checkbox(*, label="", default=False, id=None, binds=None, on_change=None)

Controllo booleano. default è lo stato iniziale; binds lo scavalca con il valore reso persistente, se ne esiste uno.

LineEdit(*, placeholder="", default="", id=None, binds=None, on_change=None)

Immissione di testo su una sola riga.

NumberSpin(*, default=0, min=None, max=None, step=1, id=None, binds=None, on_change=None)

Casella numerica con frecce. min e max limitano l'intervallo (entrambi facoltativi; il QSpinBox sottostante usa il proprio intervallo predefinito quando non sono impostati). step è l'incremento sulle frecce.

intervallo di int

NumberSpin si appoggia a QSpinBox, che memorizza un int (a 32 bit). I valori fuori da -2_147_483_648 … 2_147_483_647 si saturano al limite della piattaforma.

ComboBox(*, items, default="", id=None, binds=None, on_change=None)

Elenco a discesa. items è un elenco: ogni voce può essere una semplice stringa oppure un oggetto come {"value": "cpp", "label": "C++"} (oggi viene usato solo value; label è riservato a un perfezionamento futuro).

List(*, items, id=None, on_change=None)

Widget elenco a selezione singola. on_change scatta con il testo della voce appena selezionata. Nessun binds: se ti serve, rendi persistente la selezione da te.


Accesso a tempo di esecuzione

Una volta registrato il pannello, pilotalo da un comando qualsiasi:

panel_id = ctx.docks.add_panel(id="my.panel", ..., form=Column([
    LineEdit(id="needle"),
    Checkbox(id="cs"),
]))

# Read current values
needle = ctx.ui.get(panel_id, "needle")
cs     = ctx.ui.get(panel_id, "cs") == "true"

# Write values (does NOT fire on_change)
ctx.ui.set(panel_id, "needle", "hello")
ctx.ui.set(panel_id, "cs", True)

Vedi ctx.ui per la documentazione completa.


Rendere persistenti i valori

binds="settings:<key>" è il modo più breve per rendere persistente il valore di un controllo:

  • Alla costruzione del pannello, il widget legge il proprio valore iniziale da ctx.settings.get(key, <default>).
  • A ogni modifica dell'utente, il widget riscrive tramite ctx.settings.set(key, new_value).

Poiché sia i pannelli sia le pagine delle Preferenze condividono ctx.settings, due controlli con la stessa stringa binds si rispecchiano a vicenda in tempo reale. È così che il pannello e la pagina delle Preferenze di HelloPython tengono sincronizzata la casella «Loud».

Se devi rendere persistente qualcosa che il vocabolario non copre (per esempio la selezione di una List), leggi e scrivi direttamente tramite ctx.settings in una callback on_change.