PBToolboxAI v4 ← Site

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:

EixoValores
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.

Mudar o tema predefinido não toca no destaque da aplicação: o definido por PBT_SetDefaultThemeAccent mantém-se, de um tema para o outro, até definir outro ou -1.

// Alternancia claro / escuro a partir de um botao da aplicacao
PBT_SetDefaultTheme("fluent-light")
FunçãoEfeito
PBT_SetDefaultTheme (string as_name)Tema predefinido do processo, difundido a todos os componentes; um nome desconhecido é recusado (-5) e o tema anterior mantém-se
PBT_GetDefaultTheme ( ) → stringTema predefinido atual
PBT_SetDefaultThemeAccent (long al_accent)Destaque da aplicação, seguido por todos os componentes — incluindo os de tema local, enquanto não tiverem o seu; -1 retira-o (cada tema retoma o seu destaque); uma cor de sistema do PowerBuilder (acima de 0xFFFFFF) é recusada (-5)
PBT_GetDefaultThemeAccent ( ) → longDestaque da aplicação, -1 se nenhum estiver definido
PBT_SetDefaultFont (string as_family, long al_size_px)Tipo de letra de toda a aplicação; tamanho em píxeis, 0 = o do tema (ver 4.4)

4.3 O tema de um componente específico #

Um componente pode afastar-se do tema da aplicação, eixo a eixo:

// So o estilo: o modo continua a ser o da aplicacao, e segue-o
uo_editor.is_theme_style = uo_editor.THEME_STYLE_OFFICE2007

// Os dois eixos: um tema totalmente local
uo_editor.is_theme_mode  = uo_editor.THEME_MODE_DARK
uo_editor.il_theme_accent = RGB(200, 60, 40)     // -1 = destaque da aplicacao

// Voltar ao tema da aplicacao: os dois eixos vazios
uo_editor.is_theme_style = ""
uo_editor.is_theme_mode  = ""
PropriedadeTipoPredefiniçãoFunção
is_theme_stylestring""Estilo visual (constantes THEME_STYLE_*). Vazio = o estilo da aplicação, seguido a cada mudança
is_theme_modestring""Variante clara ou escura (constantes THEME_MODE_*). Vazio = o modo da aplicação, seguido a cada mudança
il_theme_accentlong-1Cor de destaque deste componente. -1 = o destaque da aplicação, ou o do tema se a aplicação não definir nenhum

Um of_reset() devolve os dois eixos e o destaque à aplicação: o componente volta a seguir o seu tema e o seu destaque.

Os dois eixos são independentes: um eixo deixado vazio segue o tema da aplicação a cada mudança dele, e não só o que vigorava quando o outro eixo foi definido. Espaços e maiúsculas não contam; um valor desconhecido ("office2010", "sombre") é ignorado e o eixo mantém o seu valor. Reler is_theme_style ou is_theme_mode devolve o que o componente mostra — para um eixo vazio, o estilo e o modo da aplicação —, e il_theme_accent devolve -1 enquanto o componente não tiver destaque próprio. Um componente com tema local também segue o destaque da aplicação enquanto não tiver o seu.

💡 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_ribbon.il_theme_accent = RGB(0, 120, 90)

// Um grupo : tudo o que contem segue
uo_ribbon.of_group(/*keys*/ "home/clipboard").il_accent = RGB(0, 120, 90)

// Um item
uo_list.of_item(/*keys*/ "delete").il_text_color = RGB(200, 70, 70)
uo_list.of_item(/*keys*/ "delete").il_back_color = RGB(255, 235, 235)

// Os mesmos dois, sob o ponteiro
uo_list.of_item(/*keys*/ "delete").il_back_color_hover = RGB(255, 220, 220)

// Voltar a cor do componente
uo_list.of_item(/*keys*/ "delete").il_text_color = -1
PropriedadeOndeO que recolore
il_theme_accento componenteo seu acento e tudo o que dele deriva: a passagem do ponteiro e o clique dos botões de acento, as seleções e estados marcados tingidos, o texto legível por cima, o fundo da aplicação, o sublinhado de separador
il_accentum handle de item, grupo, separador ou barrao que essa zona pinta com o acento, descendentes incluídos
il_back_color · il_text_coloridemo fundo e o texto do item
il_back_color_hover · il_text_color_hoveridemos 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. O tamanho exprime-se em píxeis.


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_title.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:

FormaExemploUtilização
Ficheiroimg\logo.pngImagem tal como está (png, jpg, gif, bmp, ico, svg, webp)
Recurso de DLLimg\packimages.dll:RIBBONImagem empacotada numa DLL de recursos
mono:mono:img\save.svgCor uniforme à cor do tema: só a forma conta
tint:tint:img\logo_couleur.pngDuotone: o relevo interno modula a cor do tema

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.

n_pbt_utils lnv_utils   // autoinstantiate : nada a criar, nada a destruir

uo_toolbar.of_add_button(/*keys*/ "main/save", /*text*/ "Guardar", /*image*/ lnv_utils.of_icon(/*path*/ "mono:img\save.svg"), /*tooltip*/ "Guardar")

Para um lote de ícones conhecido de antemão, of_preload_icons() aquece a cache de uma só vez, no arranque: a primeira pintura deixa de esperar.

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.

EtiquetaEfeito
[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. Aceita também o que of_icon() devolve (um data URI); as dimensões leem-se no fim do valor. Um caminho de rede é aí recusado (ver abaixo)
[symbol=nome]Símbolo integrado, monocromático, desenhado na cor do texto que o rodeia (segue o tema, a passagem do rato, um [accent]) — nenhum ficheiro a distribuir: clock, location, person, people, calendar, repeat, lock, bell, phone, mail, video, note, tag, link, check, star, info, warning. Um nome desconhecido aparece tal como está
[br] / [linebreak] / [br:3]Quebra de linha (ou n quebras)
[gap=N]Quebra de linha seguida de um espaço de N % de linha: [gap=100] vale [br][br], [gap=50] meia linha vazia
[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_key), 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_text.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(/*key*/ "clients", /*title*/ "[b]Clientes[/b] [size-=20](128)[/size-=20]", /*page*/ 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 uma etiqueta conhecida — [b], [red], [picture=…]: seria interpretado (uma palavra desconhecida entre parênteses retos é mostrada tal como está escrita). of_escape_markup(), função de n_pbt_utils, duplica-os por si — envolva o dado, nunca a marcação que escreve você mesmo.

n_pbt_utils lnv_utils   // autoinstantiate : nada a criar, nada a destruir
// Um dado de negocio pode conter uma etiqueta CONHECIDA : sem escape e
// INTERPRETADA -- o [b] desaparece e o resto passa a negrito.
ls_label = "Desconto [b]VIP"
uo_st.is_text = "Cliente : " + ls_label                          // mostra : Cliente : Desconto VIP (VIP a negrito)
uo_st.is_text = "Cliente : " + lnv_utils.of_escape_markup(/*text*/ ls_label)  // mostra : Cliente : Desconto [b]VIP

Um texto sem etiquetas não tem qualquer custo adicional (caminho rápido). Uma etiqueta desconhecida é mostrada tal como está escrita (Saldo [liquido] continua Saldo [liquido]). Uma etiqueta de fecho só fecha a sua, e uma etiqueta de fecho sem abertura é ignorada. 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, seja qual for a caixa das letras (HTTPS:// também). 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. Pela mesma razão, uma imagem da marcação nunca vai buscar uma partilha de rede ([picture=\\servidor\partilha\x.png] é recusada): um comentário não escapado abriria de outro modo uma sessão de rede para uma máquina qualquer só por ser apresentado. Uma imagem de rede num texto passa por of_icon(), que a incorpora; is_picture e os ícones dos componentes mantêm o acesso à rede.

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 →

4.8 As animações e a definição do posto #

O Windows oferece uma definição de acessibilidade — Definições > Acessibilidade > Efeitos visuais > Efeitos de animação — e os componentes respeitam-na: quando está desligada, nenhum fotograma-chave e nenhuma transição são reproduzidos. O gráfico chega ao seu lugar, não vai até lá.

É o comportamento certo por omissão, e não se discute: quem pediu menos movimento ao seu sistema queria isso mesmo. ib_animated = true não muda nada.

Uma aplicação pode ainda assim insistir:

// Declarar uma vez : Function long PBT_SetAnimationPolicy (long al_policy)
//                    Library "pbtoolboxai.dll"
PBT_SetAnimationPolicy(1)   // 1 = animar sempre, 0 = respeitar o posto (omissao)

A chamada vale para todo o processo e pode ser feita a qualquer momento: os componentes vivos seguem-na de imediato, os seguintes recebem-na ao abrir.

Ponha 1 só com uma razão verdadeira — um quiosque, um painel de parede, uma demonstração cujo ofício é justamente mostrar estas animações. Numa aplicação de gestão, deixe o valor por omissão.


4.9 Compor o aspeto da sua aplicação #

A biblioteca entrega dez temas e não permite que uma aplicação defina um décimo primeiro: o vocabulário de tokens é interno e assim permanece. O que oferece em vez disso são três alavancas, que se combinam — é assim que se obtêm «as nossas cores» sem escrever um tema.

// 1. A BASE: o tema entregue mais proximo do objetivo.
PBT_SetDefaultTheme("office-light")

// 2. O REALCE: UMA cor veste todos os componentes, incluindo os
//    criados depois, e tudo o que o tema dele deriva.
PBT_SetDefaultThemeAccent(RGB(0, 105, 92))

// 3. O TIPO DE LETRA de toda a aplicacao, numa chamada.
PBT_SetDefaultFont("Segoe UI Semibold", 0)

Coloque estas três linhas no evento open do objeto aplicação: chegam a cada componente antes do seu primeiro desenho, portanto sem qualquer cintilação.

AlavancaAlcanceO que muda
PBT_SetDefaultThemeo processoestilo e modo: formas, arredondamentos, espessuras, toda a paleta
PBT_SetDefaultThemeAccento processoo realce e o que o tema dele deriva — passagem e clique dos botões de realce, seleção, texto legível por cima, sublinhado do separador; incluindo os componentes de tema local, e sobrevive a uma mudança de tema
PBT_SetDefaultFonto processofamília e tamanho; uma família vazia ou um tamanho 0 devolve essa metade ao tema
il_theme_accentum componenteo seu próprio realce, quando uma janela se deve distinguir
il_back_color · il_text_colorum itemuma entrada precisa, a vermelho porque elimina (ver 4.4)

O que isto não permite #

Redefinir a paleta completa — os cinzentos de superfície, as margens, o raio dos cantos — não é oferecido. Um tema é um conjunto coerente de umas sessenta valores que se respondem: abrir metade produziria combinações ilegíveis que ninguém teria verificado. Se a sua identidade exigir mais do que estas três alavancas, escreva-nos: mais um tema dentro da biblioteca é uma opção, o seu tema dentro do seu código não é.

Na aplicação de demonstração: friso Home > Aspeto > Estilo > Corporate (composed). A entrada combina estas três alavancas — nada reservado a nós — com duas diferenças: o tema é office-light ou office-dark conforme o botão claro/escuro do friso, e o tipo de letra é definido em 16 píxeis. O código é wf_apply_style, na janela w_demo_home.


4.10 O alto contraste do Windows #

Quando o utilizador ativa um tema de Alto contraste do Windows, o motor substitui as cores da página pelas do sistema, seja qual for o tema da biblioteca. Os componentes têm isso em conta: os ícones monocromáticos (mono:, tint:) tomam a cor do texto do sistema — a do texto realçado numa linha selecionada —, os anéis de foco e as marcas desenhadas como sombra recebem um contorno real, e o que tem significado pela sua cor (um ponto de estado, uma cor escolhida pela aplicação) mantém-na. Nada a fazer do lado da aplicação: nem propriedade, nem chamada.


4.11 O conteúdo de terceiros: navegador web e visualizador PDF #

webbrowser e pdfviewer mostram um conteúdo que a biblioteca não desenha: um site, ou o visualizador PDF do motor. Esse conteúdo não conhece os temas da biblioteca, mas lê a preferência clara ou escura que o navegador lhe anuncia, como um site lê a do Windows. Essa preferência segue o tema predefinido da aplicação (PBT_SetDefaultTheme) — não o modo do Windows, nem o tema local de um componente: uma aplicação em fluent-dark mostra a versão escura de um site que a ofereça, e o visualizador PDF nas suas cores escuras. Antes de a página de terceiros ter desenhado, a zona toma o fundo do tema em vez de um retângulo branco.