# 4. Temas e aspeto #

← Base comum · Índice · Idioma e RTL →

## 4.1 Os temas: dois eixos #

Um tema compõe-se de um estilo e de um modo:

Eixo | Valores
--- | ---
Estilo (`is_theme_style`) | `fluent` · `metro` · `office` · `office2007` · `office2003`
Modo (`is_theme_mode`) | `light` · `dark`

Ou seja, dez temas, designados `<style>-<mode>`: `fluent-light`, `fluent-dark`, `office2007-light`, `metro-dark`…

## 4.2 O tema predefinido da aplicação (recomendado) #

O tema deve ser definido uma única vez para toda a aplicação, antes da abertura da primeira window. É injetado em cada componente antes do respetivo primeiro desenho: nenhum flash de estilo claro numa aplicação escura.

    // Evento open do objeto de aplicacao
    PBT_SetDefaultTheme("fluent-dark")
    PBT_SetDefaultThemeAccent(RGB(0, 120, 212))   // opcional

A alteração a quente é possível a qualquer momento: todos os componentes já abertos voltam a aplicar o tema instantaneamente.

    // Alternancia claro / escuro a partir de um botao da aplicacao
    PBT_SetDefaultTheme("fluent-light")

Função | Efeito
--- | ---
`PBT_SetDefaultTheme (string as_nom)` | Tema predefinido do processo (difundido a todos os componentes)
`PBT_GetDefaultTheme ( )` → string | Tema predefinido atual
`PBT_SetDefaultThemeAccent (long al_couleur)` | Cor de destaque predefinida (`-1` = destaque nativo do tema)
`PBT_GetDefaultThemeAccent ( )` → long | Destaque predefinido atual

## 4.3 O tema de um componente específico #

Um componente pode afastar-se do tema predefinido:

    uo_editeur.is_theme_style = uo_editeur.THEME_STYLE_OFFICE2007
    uo_editeur.is_theme_mode  = uo_editeur.THEME_MODE_DARK
    uo_editeur.il_theme_accent = RGB(200, 60, 40)     // -1 = destaque do tema

Propriedade | Tipo | Predefinição | Função
--- | --- | --- | ---
`is_theme_style` | string | `fluent` | Estilo visual (constantes `THEME_STYLE_*`)
`is_theme_mode` | string | `light` | Variante clara ou escura (constantes `THEME_MODE_*`)
`il_theme_accent` | long | `-1` | Cor de destaque deste componente (`-1` = destaque do tema)

Um `of_reset()` devolve o componente ao tema predefinido do processo.

> 💡 O resultado mais cuidado continua a ser um único tema para toda a aplicação. O tema local deve ficar reservado para casos particulares (uma zona deliberadamente contrastada, uma pré-visualização de tema).

## 4.4 Recolorir um componente, um grupo ou um item #

Três alcances, as mesmas propriedades. Nada a nomear, nada a adivinhar.

    // O componente inteiro
    uo_ruban.il_theme_accent = RGB(0, 120, 90)

    // Um grupo : tudo o que contem segue
    uo_ruban.of_tab("accueil").of_group("presse-papiers").il_accent = RGB(0, 120, 90)

    // Um item
    uo_liste.of_item("supprimer").il_text_color = RGB(200, 70, 70)
    uo_liste.of_item("supprimer").il_back_color = RGB(255, 235, 235)

    // Os mesmos dois, sob o ponteiro
    uo_liste.of_item("supprimer").il_back_color_hover = RGB(255, 220, 220)

    // Voltar a cor do componente
    uo_liste.of_item("supprimer").il_text_color = -1

Propriedade | Onde | O que recolore
--- | --- | ---
`il_theme_accent` | o componente | o seu acento e tudo o que dele deriva: o texto legível por cima, o fundo da aplicação, o sublinhado de separador
`il_accent` | um handle de item, grupo, separador ou barra | o que essa zona pinta com o acento, descendentes incluídos
`il_back_color` · `il_text_color` | idem | o fundo e o texto do item
`il_back_color_hover` · `il_text_color_hover` | idem | os mesmos dois, sob o ponteiro

`-1` repõe a cor que o componente dá, ela própria vinda do tema. A cor de um item sobrevive à reconstrução do componente: é transportada por uma regra de estilo que visa o item, e não por uma propriedade colocada no nó do momento. `of_reset()` limpa tudo.

`il_accent` só repinta o que a zona pinta com o acento — uma seleção, um sublinhado ativo, uma barra de progresso. Um componente que não o usa nada mostrará: para «esta entrada a vermelho», `il_back_color` e `il_text_color` são as ferramentas certas, lidas por todos os componentes com itens.

### O tipo de letra de toda a aplicação #

    PBT_SetDefaultFont("Segoe UI", 14)

Uma só chamada veste cada componente vivo e os criados depois — o tipo de letra é-lhes injetado antes do primeiro desenho. Uma família vazia ou um tamanho de `0` devolve essa metade ao tema.

## 4.5 O fundo do componente é comunicado ao PowerBuilder #

Cada componente pinta o seu fundo de acordo com o tema e depois notifica a respetiva cor: o userobject adota essa cor (`backcolor`) e aciona `ue_bg_color`, para que a window e os controlos PowerBuilder vizinhos fiquem em harmonia.

    // evento ue_bg_color de um componente
    parent.backcolor = al_color
    st_titre.backcolor = al_color

É isto que permite misturar componentes PBToolboxAI e controlos PowerBuilder nativos sem demarcação visível em tema escuro.

## 4.6 As imagens e os ícones #

Em qualquer sítio onde um componente espera um caminho de imagem (ícone de botão, mosaico, `[picture=…]`…), são aceites quatro formas:

Forma | Exemplo | Utilização
--- | --- | ---
Ficheiro | `img\logo.png` | Imagem tal como está (png, jpg, gif, bmp, ico, svg, webp)
Recurso de DLL | `img\packimages.dll:RIBBON` | Imagem empacotada numa DLL de recursos
`mono:` | `mono:img\save.svg` | Cor uniforme à cor do tema: só a forma conta
`tint:` | `tint:img\logo_couleur.png` | Duotone: o relevo interno modula a cor do tema

- `mono:` utiliza-se para todos os glifos monocromáticos (ícones brancos ou pretos): são recoloridos automaticamente tanto em claro como em escuro.
- `tint:` harmoniza um ícone a cores com o tema, conservando os seus gradientes. Nunca deve ser utilizado num glifo branco (permaneceria branco).
- Sem prefixo, a imagem multicolor é deixada intacta.

A forma `chemin.dll:nom` carrega um recurso de uma DLL de imagens (à maneira de `packimages.dll`), aberta apenas para leitura (`LOAD_LIBRARY_AS_DATAFILE`, sem execução de qualquer código). Isto evita ter de expedir centenas de ficheiros a granel.

### Apresentação instantânea: `of_icon` #

Um pequeno glifo passado por `of_icon()` é incorporado no comando (sem qualquer ida e volta de carregamento): aparece logo no primeiro desenho, sem o piscar de um ícone carregado posteriormente.

    lnv_bar.of_add_button("save", "Guardar", uo_toolbar.of_icon("mono:img\save.svg"))

Transparente na utilização: acima de um determinado tamanho, `of_icon` devolve o caminho de origem (a imagem é então carregada e colocada em cache normalmente).

## 4.7 O texto formatado com etiquetas #

Qualquer etiqueta de qualquer componente aceita uma marcação ao estilo BBCode: título de separador, etiqueta de botão, texto de barra de estado, mensagem de toast, título de painel, texto de tooltip…

As entradas dos menus integrados seguem a mesma regra — menu de contexto de um separador, lista `···` dos separadores que já não cabem, menus de coluna de uma grelha: a etiqueta mostrada pelo menu é a do controlo, marcação incluída.

O texto é desenhado em nós de texto e em `<span>`: nenhuma injeção HTML é possível.

Etiqueta | Efeito
--- | ---
`[b] [i] [u] [s]` / `[strike]` | Negrito, itálico, sublinhado, rasurado
`[sub] [super]` | Índice inferior, índice superior
`[red]…[/red]` (cores nomeadas) | Cor de texto (`red`, `green`, `blue`, `orange`, `teal`…)
`[accent]…[/accent]` | Cor de destaque do tema atual
`[color=#rrggbb]` / `[color=accent]` | Cor de texto
`[bk=#rrggbb]` / `[backcolor=accent]` | Cor de fundo
`[font=Consolas]` | Tipo de letra
`[size=14]` | Tamanho absoluto, em pontos (6 a 200)
`[size+=30]` / `[size-=20]` | Tamanho relativo em % (20 % por predefinição)
`[picture=chemin]` / `[picture=chemin,larg,haut]` | Imagem em linha
`[br]` / `[linebreak]` / `[br:3]` | Quebra de linha (ou n quebras)
`[separator]` | Filete horizontal
`[hyperlink=url]…[/hyperlink]` | Zona clicável: a ligação abre sempre no navegador do utilizador, em todos os componentes. O evento `ue_hyperlink(as_url)` é emitido além disso, nos componentes que o expõem
`[action=id]…[/action]` | Zona clicável → evento `ue_action(as_id)`, apresentada como uma ligação
`[invisibleaction=id]…[/invisibleaction]` | Zona clicável → `ue_action`, sem o estilo de ligação
`[bullet]…[/bullet]` | Marcador: item de lista cujas linhas seguintes se alinham pela primeira em vez de voltarem sob o marcador (recuo pendente). `[bullet=-]` altera o marcador
`[foldarea:Título]…[/foldarea]` | Bloco recolhível: cabeçalho clicável (`−` / `+`) sobre um conteúdo indentado. O título aceita etiquetas
`[foldarea-closed:Título]…[/foldarea]` | O mesmo bloco, recolhido ao ser apresentado
`[[` / `]]` | Escape: `[[b]]` apresenta `[b]` sem o interpretar

    uo_texte.is_text = "Bem-vindo ao [b][accent]PBToolboxAI[/accent][/b] [size-=20]v1.0[/size-=20]" &
                       + "[br]Consulte a [hyperlink=https://pbtoolboxai.net]documentação[/hyperlink]."

    uo_tab.of_add_page("clients", "[b]Clientes[/b] [size-=20](128)[/size-=20]", uo_clients)

    uo_st.is_text = "A etiqueta [[b]] coloca a [b]negrito[/b]"   // apresenta : A etiqueta [b] coloca a negrito

Apresentar um dado tal como está. Um valor vindo da sua base pode conter parênteses retos: seria interpretado. `of_escape_markup()`, disponível em qualquer componente, duplica-os por si — envolva o dado, nunca a marcação que escreve você mesmo.

    // Um dado de negocio pode conter parenteses retos : sem escape e
    // INTERPRETADO e o texto entre parenteses desaparece.
    ls_libelle = "Saldo [liquido]"
    uo_st.is_text = "Conta : " + ls_libelle                          // mostra : Conta :
    uo_st.is_text = "Conta : " + uo_st.of_escape_markup(ls_libelle)  // mostra : Conta : Saldo [liquido]

Um texto sem etiquetas não tem qualquer custo adicional (caminho rápido). As etiquetas desconhecidas são ignoradas e o respetivo conteúdo conservado. Uma `[hyperlink]` abre em toda a parte — rótulo, título de separador, painel da barra de estado, toast, caixa de diálogo: é a base que trata disso. O evento `ue_action`, esse, só é emitido pelos componentes de texto interativos (`statictext`); nos restantes, `[action]` serve apenas para formatação.

Só `http`, `https` e `mailto` são abertos. Um rótulo transporta muitas vezes um dado vindo da sua base: confiar ao sistema um esquema qualquer transformaria um rótulo num lançador de programas.

Um `[foldarea]` é um bloco: ocupa toda a largura e recolhe com um clique no seu cabeçalho, sem ida e volta ao PowerBuilder. Os blocos aninham-se e, se o componente seguir a altura do seu conteúdo (`ib_auto_height`), essa altura é notificada de novo a cada recolha. O título é igualmente texto com etiquetas: nada é colocado a negrito por si, `[foldarea:[b]Total[/b]]` trata disso.

← Base comum · Índice · Idioma e RTL →