Pular para conteúdo

mte.ui — construtores de especificação de formulário

Toda superfície de interface da fase 3 — ctx.docks.add_panel e ctx.settings_page.register — recebe uma especificação de formulário: um dicionário simples descrevendo uma árvore de widgets. Construa essas especificações com os auxiliares mte.ui.*, para não precisar escrever o JSON à mão.

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

Nada em mte.ui conversa com o Qt ou o PySide — cada auxiliar devolve um dicionário seguindo o esquema de canal que o analisador de formulários em C++ do host espera. Fique à vontade para compô-los, emendar listas ou gerá-los programaticamente:

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)])

A especificação é validada do lado do host; tipos de controle desconhecidos ou campos obrigatórios ausentes produzem um erro InvalidParams que você verá no log.

Os rótulos de uma especificação de formulário não são traduzidos

Todo rótulo que você põe em uma especificação — títulos de painel, rótulos de caixas de seleção, títulos de grupo — é exibido exatamente como você o escreveu, seja qual for o idioma da interface. Eles são dados que o seu plugin envia ao editor, não cadeias que o editor possa procurar em um catálogo de tradução. Se o seu plugin deve falar mais de um idioma, escolha as cadeias você mesmo antes de chamar register; o idioma atual da interface é ctx.app_settings.get_string(mte.keys.UI_LANGUAGE) (vazio significa "seguir o sistema"). O mesmo vale para o name e a description que o seu plugin.json exibe em Preferências ▸ Plug-ins.


Layouts

Os construtores de layout recebem uma lista de dicionários filhos e os dispõem vertical ou horizontalmente.

Column(children)

Empilha os filhos de cima para baixo com um esticamento ao final — os controles ficam na altura natural deles, em vez de inflarem para preencher um painel alto.

Row(children)

Mesma ideia, da esquerda para a direita, com um esticamento horizontal ao final.

Group(children, *, title="")

Uma moldura com título (renderizada como QGroupBox) contendo uma pilha vertical. Use-a para agrupar visualmente controles relacionados:

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

Os layouts se aninham livremente — uma Row dentro de uma Column dentro de um Group funciona.


Controles folha

Toda folha aceita as mesmas quatro ligações compartilhadas por argumentos nomeados:

Argumento Significado
id= Id estável usado por ctx.ui.get / ctx.ui.set e (implicitamente) por binds.
binds= "settings:<key>" — persiste automaticamente por ctx.settings.
on_click= Id de comando a invocar — apenas em Botões.
on_change= Id de manipulador (ctx.docks.on_change(...)) — em todos os outros controles.

Apenas as folhas que expõem um "valor" suportam binds e on_change.

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

Texto estático.

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

Um botão. Disparar on_click invoca o comando registrado; se você quiser manter o botão em sincronia com outra coisa, pode usar ctx.ui.set no text dele.

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

Controle booleano. default é o estado inicial; binds o substitui pelo valor persistido, se houver um.

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

Entrada de texto de uma linha.

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

Caixa numérica com setas. min e max limitam o intervalo (ambos opcionais; o QSpinBox subjacente usa o intervalo padrão dele quando não definidos). step é o incremento das setas.

Intervalo de int

O NumberSpin se apoia no QSpinBox, que armazena um int (32 bits). Valores fora de -2_147_483_648 … 2_147_483_647 saturam no limite da plataforma.

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

Lista suspensa. items é uma lista — cada entrada pode ser uma cadeia simples, ou um objeto como {"value": "cpp", "label": "C++"} (apenas value é usado hoje; label está reservado para um refinamento futuro).

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

Widget de lista com seleção única. on_change dispara com o texto do item recém-selecionado. Sem binds — persista a seleção você mesmo se precisar.


Acesso em tempo de execução

Uma vez registrado o painel, comande-o a partir de qualquer comando:

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)

Veja ctx.ui para a referência completa.


Persistindo valores

binds="settings:<key>" é a forma mais curta de persistir o valor de um controle:

  • Na construção do painel, o widget lê o valor inicial de ctx.settings.get(key, <default>).
  • A cada edição do usuário, o widget grava de volta por ctx.settings.set(chave, novo_valor).

Como painéis e páginas de Preferências compartilham ctx.settings, dois controles com a mesma cadeia binds se espelham em tempo real. É assim que o painel e a página de Preferências do HelloPython mantêm a caixa de seleção "Loud" em sincronia.

Se você precisa persistir algo que o vocabulário não cobre (por exemplo, a seleção de uma List), leia e grave diretamente por ctx.settings em uma retrochamada on_change.