# 6. Funcionalidades transversais #

← Idioma e RTL · Índice · FAQ →

Este capítulo reúne os serviços disponíveis seja qual for o componente: tooltips, alojamento de controlos PowerBuilder, arrastar e largar a partir do Explorador, focus de teclado, exportação de imagem e os objetos utilitários não visuais.

## 6.1 Tooltips simples e enriquecidos #

### Tooltip do componente #

    uo_bouton.is_tooltip = "Guardar o processo (Ctrl+S)"

O texto aceita a formatação com etiquetas: `[b]`, `[br]`, `[color=…]`, `[picture=…]`…

### Super tooltip (título + texto + imagem) #

Para uma ajuda contextual ao estilo do friso do Office:

    uo_bouton.is_super_tooltip_title = "Guardar"
    uo_bouton.is_super_tooltip_text  = "Escreve as alterações no servidor." &
                                       + "[br][br][size-=15]Atalho: Ctrl+S[/size-=15]"
    uo_bouton.is_super_tooltip_image = "img\help_save.png"

As três propriedades são independentes: um título isolado, ou um título + texto sem imagem, são válidos. Assim que uma propriedade `is_super_tooltip_*` é definida, prevalece sobre `is_tooltip`.

### Tooltip de um item #

Todas as classes de item (`n_pbt_item` e os seus descendentes) possuem as mesmas quatro propriedades:

    uo_toolbar.of_bar("main").of_item("save").is_tooltip = "Guardar"

    uo_tab.of_item("clients").is_super_tooltip_title = "Clientes"
    uo_tab.of_item("clients").is_super_tooltip_text  = "128 fichas, última sincronização às 09:12"

### Comportamento #

- O tooltip é uma janela nativa com tema, idêntica em todos os componentes (não está limitada pelas fronteiras do webview).
- Não é apresentado se a aplicação não tiver o focus: passar o rato sobre uma window em segundo plano não desencadeia nada.
- Desaparece ao mudar para outra aplicação e, o mais tardar, ao fim de 10 segundos.
- `of_reset()` elimina os tooltips definidos na instância e nos seus items.

## 6.2 Alojar controlos reais do PowerBuilder #

Os componentes contentores não apresentam HTML em vez dos ecrãs da aplicação: acolhem verdadeiros controlos PowerBuilder (userobjects, DataWindows, grupos de controlos), reparentados como janelas Win32 filhas. Os ecrãs existentes são reutilizados tal como estão.

    // Separadores: cada pagina e um userobject PB
    uo_tab.of_add_page("clients",   "Clientes",  uo_page_clients)
    uo_tab.of_add_page("factures",  "Faturas",   uo_page_factures, /*fechavel*/ true)

    // Paineis acoplaveis: idem
    uo_dock.is_main = "doc"                       // zona central
    uo_dock.of_add_panel("doc",      uo_dock.POSITION_STACK, "", 0,   "Documento",  uo_editeur)
    uo_dock.of_add_panel("explorer", uo_dock.POSITION_START, "", 240, "Explorador", uo_arbre)
    uo_dock.of_add_panel("props",    uo_dock.POSITION_END,   "", 260, "Propriedades", uo_props)

O que é assegurado pela biblioteca:

- o posicionamento e o redimensionamento do controlo alojado quando o separador ou o painel muda de tamanho;
- a apresentação / ocultação na mudança de separador ou de painel ativo;
- os painéis flutuantes, acoplados ou ocultados automaticamente (dockcontainer);
- a destruição correta ao fechar a window.

> ⚠️ Um controlo alojado é uma janela nativa: desenha-se por cima da camada web. Isso é intencional (a DataWindow mantém-se nítida e rápida), mas significa que nenhum efeito web — sombra, transparência, animação — pode passar por cima dele.

## 6.3 Receber ficheiros a partir do Explorador do Windows #

Um componente pode tornar-se alvo de largada para ficheiros arrastados a partir do Explorador. A biblioteca instala um alvo de largada nativo: são recebidos os caminhos completos, o que uma largada HTML não permite.

    uo_editeur.ib_allow_drop = true

    // event ue_drop_files de uo_editeur: (string as_files[])
    long ll_i

    for ll_i = 1 to UpperBound(as_files)
        of_ouvrir_fichier(as_files[ll_i])
    next

Evento | Acionado quando
--- | ---
`ue_drag_enter ( )` | Um arrastamento de ficheiros entra no componente
`ue_drag_leave ( )` | Sai sem largar
`ue_drop_files (string as_files[])` | Os ficheiros são largados — caminhos completos

O próprio componente fornece o retorno visual de passagem (realce da zona de largada). Publicado pelos componentes onde a largada faz sentido: `statictext`, `codeeditor`.

## 6.4 Teclado e focus #

Um componente PBToolboxAI participa na navegação por teclado da window como um controlo nativo:

- a tecla Tab alcança-o na ordem de tabulação da window;
- as teclas (setas, Enter, Escape, introdução) são tratadas pelo componente que tem o focus;
- os atalhos de window (Enter = botão predefinido, Escape = cancelar) continuam a funcionar mesmo quando o focus está num componente.

Para dar explicitamente o focus ao conteúdo de um componente (por exemplo, depois de abrir um painel de pesquisa):

    uo_editeur.of_focus_webview()

## 6.5 Exportar a representação como imagem #

Recordatório da base comum: qualquer componente é exportado tal como está apresentado.

    uo_pivot.of_save_as_png("C:\temp\tableau.png")
    uo_pivot.of_save_as_jpg("C:\temp\tableau.jpg")

Útil para anexar um gráfico a uma mensagem de correio eletrónico, alimentar um relatório ou registar um incidente do utilizador.

## 6.6 Caixas de diálogo e notificações #

Dois serviços sem controlo a colocar na window:

    // Caixa de dialogo modal com tema (retorno sincrono)
    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox
    lnv_mb.is_title   = "Eliminação"
    lnv_mb.is_message = "Eliminar definitivamente [b]12 processos[/b]?"
    lnv_mb.is_icon    = lnv_mb.ICON_QUESTION
    lnv_mb.of_add_button("Eliminar", /*predefinido*/ false, /*cancelamento*/ false)
    lnv_mb.of_add_button("Cancelar", /*predefinido*/ true,  /*cancelamento*/ true)

    if lnv_mb.of_show(Handle(this)) = 1 then of_supprimer()
    destroy lnv_mb

    // Notificacao "toast" no canto do ecra, nao bloqueante
    n_pbt_toaster lnv_toast

    lnv_toast = create n_pbt_toaster
    lnv_toast.is_title = "Importação concluída"
    lnv_toast.is_text  = "1 240 linhas integradas."
    lnv_toast.is_kind  = lnv_toast.KIND_SUCCESS
    lnv_toast.of_show()
    destroy lnv_toast

Detalhes completos: messagebox e toaster.

## 6.7 Objetos utilitários não visuais #

Fornecidos na mesma PBL, sem webview nem representação: são simples invólucros em torno da DLL. Devem ser criados, utilizados e destruídos.

### Codificação Base64 — `u_pbt_base64` #

    u_pbt_base64 lnv_b64
    string ls_encode

    lnv_b64 = create u_pbt_base64
    ls_encode = lnv_b64.of_encode("Bom dia")      // texto -> UTF-8 -> Base64
    ls_texte  = lnv_b64.of_decode(ls_encode)     // "" se a entrada for invalida
    destroy lnv_b64

### Impressões digitais — `u_pbt_hash` #

    u_pbt_hash lnv_hash

    lnv_hash = create u_pbt_hash
    ls_empreinte = lnv_hash.of_sha256("palavra-passe")           // hexa minusculo
    ls_fichier   = lnv_hash.of_file("SHA256", "C:\livraison.zip")
    destroy lnv_hash

Método | Função
--- | ---
`of_string (string as_algo, string as_texte)` | Impressão digital de uma cadeia — `MD5`, `SHA1`, `SHA256`, `SHA384`, `SHA512`
`of_file (string as_algo, string as_chemin)` | Impressão digital do conteúdo de um ficheiro (`""` se ilegível)
`of_md5` · `of_sha1` · `of_sha256` · `of_sha512` | Atalhos

### Expressões regulares — `u_pbt_regex` #

Sintaxe ECMAScript, ausente do PowerScript.

    u_pbt_regex lnv_re
    string ls_trouves[]

    lnv_re = create u_pbt_regex

    if lnv_re.of_is_match("^[\w.]+@[\w.]+\.\w{2,}$", ls_email) then …

    ls_annee = lnv_re.of_match("(\d{4})-(\d{2})-(\d{2})", ls_date, /*grupo*/ 1)
    ls_propre = lnv_re.of_replace("\s+", ls_saisie, " ")
    ll_nb = lnv_re.of_match_all("[A-Z]{2}\d{6}", ls_texte, ls_trouves)

    destroy lnv_re

Método | Função
--- | ---
`of_is_match (motivo, texto [, ab_ignore_case | al_flags])` | O texto corresponde?
`of_match (motivo, texto, ai_groupe [, al_flags])` | Primeira correspondência (`0` = tudo, `1..` = grupo de captura)
`of_match_all (motivo, texto [, ai_groupe, al_flags], ref as_res[])` | Todas as correspondências; devolve o número
`of_replace (motivo, texto, substituição)` | Substitui todas as ocorrências (`$1`… permitidos)

Opções combináveis: `FLAG_IGNORE_CASE` (1), `FLAG_SINGLELINE` (2, o `.` atravessa as mudanças de linha).

### Identificadores únicos — `u_pbt_guid` #

    u_pbt_guid lnv_guid

    lnv_guid = create u_pbt_guid
    ls_id = lnv_guid.of_new()          // 1b4e28ba-2fa1-11d2-883f-0016d3cca427
    ls_id = lnv_guid.of_new_braces()   // {1b4e28ba-...}
    ls_id = lnv_guid.of_new_plain()    // 1b4e28ba2fa111d2883f0016d3cca427
    destroy lnv_guid

### Arquivos ZIP — `u_pbt_zip` #

    u_pbt_zip lnv_zip

    lnv_zip = create u_pbt_zip
    lnv_zip.of_compress("C:\temp\livraison.zip", "C:\appli\export")   // ficheiro OU pasta
    lnv_zip.of_extract("C:\temp\livraison.zip",  "C:\appli\import")   // pasta criada se ausente
    destroy lnv_zip

Ambos os métodos devolvem um `boolean`.

## 6.8 Informações sobre a biblioteca #

    // Versao da DLL
    string ls_version

    ls_version = Space(32)
    PBT_GetVersion(ls_version, 32)

Função global | Função
--- | ---
`PBT_GetVersion (ref string, long)` | Versão da biblioteca
`PBT_CheckRuntime (ref string, long)` | Versão do runtime WebView2 instalado (`≤ 0` = ausente)
`PBT_GetLastErrorMessage (ref string, long)` | Última mensagem de erro do processo
`PBT_LicenseStatus ( )` | Estado da licença — ver Licença

## 6.9 Imprimir #

Qualquer componente sabe imprimir-se, tal como é apresentado, sem DataWindow intermédia.

    // Silencioso: um PDF em disco, nada para clicar
    uo_grille.of_print_to_pdf("C:\etats\ventes.pdf")

    // Horizontal, para uma grelha larga
    uo_grille.of_print_to_pdf(/*fichier*/ "C:\etats\ventes.pdf", /*paysage*/ true)

    // Com caixa de dialogo: o utilizador escolhe a impressora e ve a pre-visualizacao
    uo_grille.of_print()

    // Diretamente a caixa de dialogo de impressao do sistema
    uo_grille.of_print(/*dialogue systeme*/ true)

Método | Função
--- | ---
`of_print_to_pdf (string as_path)` · `of_print_to_pdf (string, boolean ab_landscape)` | Escreve um PDF sem apresentar nada. Só devolve o controlo depois de o ficheiro estar escrito (`0` = feito)
`of_print ( )` · `of_print (boolean ab_system_dialog)` | Abre a caixa de diálogo de impressão. Devolve o controlo assim que a caixa está aberta: o que o utilizador fizer com ela é consigo

> ⚠️ Imprime-se o que está RENDERIZADO. Uma grelha virtualizada só imprime as linhas que detém: para um relatório completo, passe primeiro por uma disposição que as apresente todas (paginação), ou exporte os dados em vez da representação.

O código de retorno `-6` indica um runtime WebView2 demasiado antigo para imprimir (1.0.1108 para o PDF, 1.0.1587 para a caixa de diálogo). Todo o resto segue os códigos de retorno comuns.

← Idioma e RTL · Índice · FAQ →