# 4. Temas y apariencia #

← Base común · Índice · Idioma y RTL →

## 4.1 Los temas: dos ejes #

Un tema se compone de un estilo y un modo:

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

En total, diez temas, denominados `<style>-<mode>`: `fluent-light`, `fluent-dark`, `office2007-light`, `metro-dark`…

## 4.2 El tema predeterminado de la aplicación (recomendado) #

Establezca el tema una sola vez para toda la aplicación, antes de abrir la primera ventana. Se inyecta en cada componente antes de su primera representación: ningún parpadeo de estilo claro en una aplicación oscura.

    // Event open del objeto aplicacion
    PBT_SetDefaultTheme("fluent-dark")
    PBT_SetDefaultThemeAccent(RGB(0, 120, 212))   // opcional

El cambio en caliente es posible en cualquier momento: todos los componentes ya abiertos cambian de tema al instante.

    // Conmutacion claro / oscuro desde un boton de la aplicacion
    PBT_SetDefaultTheme("fluent-light")

Función | Efecto
--- | ---
`PBT_SetDefaultTheme (string as_nom)` | Tema predeterminado del proceso (difundido a todos los componentes)
`PBT_GetDefaultTheme ( )` → string | Tema predeterminado actual
`PBT_SetDefaultThemeAccent (long al_couleur)` | Color de acento predeterminado (`-1` = acento nativo del tema)
`PBT_GetDefaultThemeAccent ( )` → long | Acento predeterminado actual

## 4.3 El tema de un componente concreto #

Un componente puede apartarse del tema predeterminado:

    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 = acento del tema

Propiedad | Tipo | Predeterminado | Función
--- | --- | --- | ---
`is_theme_style` | string | `fluent` | Estilo visual (constantes `THEME_STYLE_*`)
`is_theme_mode` | string | `light` | Variante clara u oscura (constantes `THEME_MODE_*`)
`il_theme_accent` | long | `-1` | Color de acento de este componente (`-1` = acento del tema)

Un `of_reset()` devuelve el componente al tema predeterminado del proceso.

> 💡 Lo más cuidado sigue siendo un único tema para toda la aplicación. Reserve el tema local para los casos particulares (una zona deliberadamente contrastada, una previsualización de tema).

## 4.4 Recolorear un componente, un grupo o un elemento #

Tres alcances, las mismas propiedades. Nada que nombrar, nada que adivinar.

    // El componente entero
    uo_ruban.il_theme_accent = RGB(0, 120, 90)

    // Un grupo : todo lo que contiene sigue
    uo_ruban.of_tab("accueil").of_group("presse-papiers").il_accent = RGB(0, 120, 90)

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

    // Los mismos dos, bajo el puntero
    uo_liste.of_item("supprimer").il_back_color_hover = RGB(255, 220, 220)

    // Volver al color del componente
    uo_liste.of_item("supprimer").il_text_color = -1

Propiedad | Dónde | Qué recolorea
--- | --- | ---
`il_theme_accent` | el componente | su acento y todo lo que se deriva de él: el texto legible encima, el fondo de la aplicación, el subrayado de pestaña
`il_accent` | un handle de elemento, grupo, pestaña o barra | lo que esa zona pinta con el acento, descendientes incluidos
`il_back_color` · `il_text_color` | ídem | el fondo y el texto del elemento
`il_back_color_hover` · `il_text_color_hover` | ídem | los mismos dos, bajo el puntero

`-1` restablece el color que da el componente, que a su vez viene del tema. El color de un elemento sobrevive a la reconstrucción del componente: lo lleva una regla de estilo que apunta al elemento, no una propiedad puesta en el nodo del momento. `of_reset()` lo borra todo.

`il_accent` solo repinta lo que la zona pinta con el acento — una selección, un subrayado activo, una barra de progreso. Un componente que no lo usa no mostrará nada: para «esta entrada en rojo», `il_back_color` y `il_text_color` son las herramientas adecuadas, leídas por todos los componentes con elementos.

### La fuente de toda la aplicación #

    PBT_SetDefaultFont("Segoe UI", 14)

Una sola llamada viste cada componente vivo y los creados después — la fuente se les inyecta antes de su primer dibujado. Una familia vacía o un tamaño de `0` devuelve esa mitad al tema.

## 4.5 El fondo del componente se comunica a PowerBuilder #

Cada componente pinta su fondo según el tema y luego notifica su color: el userobject adopta ese color (`backcolor`) y activa `ue_bg_color`, para que la ventana y los controles PowerBuilder vecinos se armonicen.

    // event ue_bg_color de un componente
    parent.backcolor = al_color
    st_titre.backcolor = al_color

Es lo que permite mezclar componentes PBToolboxAI y controles PowerBuilder nativos sin demarcación visible en tema oscuro.

## 4.6 Las imágenes y los iconos #

Allí donde un componente espera una ruta de imagen (icono de botón, mosaico, `[picture=…]`…), se aceptan cuatro formas:

Forma | Ejemplo | Uso
--- | --- | ---
Archivo | `img\logo.png` | Imagen tal cual (png, jpg, gif, bmp, ico, svg, webp)
Recurso de DLL | `img\packimages.dll:RIBBON` | Imagen empaquetada en una DLL de recursos
`mono:` | `mono:img\save.svg` | Color plano en el color del tema: solo cuenta la forma
`tint:` | `tint:img\logo_couleur.png` | Duotono: el relieve interno modula el color del tema

- `mono:` se utiliza para todos los glifos monocromos (iconos blancos o negros): se recolorean automáticamente tanto en claro como en oscuro.
- `tint:` armoniza un icono en color con el tema conservando sus degradados. No debe usarse nunca sobre un glifo blanco (seguiría siendo blanco).
- Sin prefijo, la imagen multicolor se deja intacta.

La forma `ruta.dll:nombre` carga un recurso de una DLL de imágenes (al estilo de `packimages.dll`), abierta en solo lectura (`LOAD_LIBRARY_AS_DATAFILE`, sin ejecutar ningún código). Esto evita distribuir cientos de archivos sueltos.

### Visualización instantánea: `of_icon` #

Un pequeño glifo pasado mediante `of_icon()` se incorpora al comando (sin ninguna ida y vuelta de carga): aparece desde la primera representación, sin el parpadeo de un icono cargado a posteriori.

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

Transparente en su uso: a partir de cierto tamaño, `of_icon` devuelve la ruta de origen (la imagen se carga entonces y se guarda en caché de forma normal).

## 4.7 El texto enriquecido con etiquetas #

Cualquier etiqueta de cualquier componente acepta un marcado al estilo BBCode: título de pestaña, etiqueta de botón, texto de barra de estado, mensaje de toast, título de panel, texto de tooltip…

Las entradas de los menús integrados siguen la misma regla — menú contextual de una pestaña, lista `···` de las pestañas que ya no caben, menús de columna de una cuadrícula: la etiqueta que muestra el menú es la del control, marcado incluido.

El texto se representa mediante nodos de texto y `<span>`: no es posible ninguna inyección HTML.

Etiqueta | Efecto
--- | ---
`[b] [i] [u] [s]` / `[strike]` | Negrita, cursiva, subrayado, tachado
`[sub] [super]` | Subíndice, superíndice
`[red]…[/red]` (colores con nombre) | Color de texto (`red`, `green`, `blue`, `orange`, `teal`…)
`[accent]…[/accent]` | Color de acento del tema actual
`[color=#rrggbb]` / `[color=accent]` | Color de texto
`[bk=#rrggbb]` / `[backcolor=accent]` | Color de fondo
`[font=Consolas]` | Fuente
`[size=14]` | Tamaño absoluto, en puntos (de 6 a 200)
`[size+=30]` / `[size-=20]` | Tamaño relativo en % (20 % de forma predeterminada)
`[picture=ruta]` / `[picture=ruta,anch,alt]` | Imagen en línea
`[br]` / `[linebreak]` / `[br:3]` | Salto de línea (o n saltos)
`[separator]` | Filete horizontal
`[hyperlink=url]…[/hyperlink]` | Zona en la que se puede hacer clic: el enlace se abre siempre en el navegador del usuario, en todos los componentes. El evento `ue_hyperlink(as_url)` se emite además, en los componentes que lo exponen
`[action=id]…[/action]` | Zona en la que se puede hacer clic → evento `ue_action(as_id)`, presentada como un enlace
`[invisibleaction=id]…[/invisibleaction]` | Zona en la que se puede hacer clic → `ue_action`, sin el estilo de enlace
`[bullet]…[/bullet]` | Viñeta: elemento de lista cuyas líneas siguientes se alinean con la primera en lugar de volver bajo el marcador (sangría francesa). `[bullet=-]` cambia el marcador
`[foldarea:Título]…[/foldarea]` | Bloque plegable: encabezado en el que se puede hacer clic (`−` / `+`) sobre un contenido con sangría. El título admite etiquetas
`[foldarea-closed:Título]…[/foldarea]` | El mismo bloque, plegado al mostrarse
`[[` / `]]` | Escape: `[[b]]` muestra `[b]` sin interpretarlo

    uo_texte.is_text = "Bienvenido a [b][accent]PBToolboxAI[/accent][/b] [size-=20]v1.0[/size-=20]" &
                       + "[br]Consulte la [hyperlink=https://pbtoolboxai.net]documentación[/hyperlink]."

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

    uo_st.is_text = "La etiqueta [[b]] pone en [b]negrita[/b]"   // muestra: La etiqueta [b] pone en negrita

Mostrar un dato tal cual. Un valor procedente de su base puede contener corchetes: sería interpretado. `of_escape_markup()`, disponible en todo componente, los duplica por usted — envuelva el dato, nunca el marcado que escribe usted mismo.

    // Un dato de negocio puede contener corchetes : sin escape se INTERPRETA
    // y el texto entre corchetes desaparece.
    ls_libelle = "Saldo [neto]"
    uo_st.is_text = "Cuenta : " + ls_libelle                          // muestra : Cuenta :
    uo_st.is_text = "Cuenta : " + uo_st.of_escape_markup(ls_libelle)  // muestra : Cuenta : Saldo [neto]

Un texto sin etiquetas no tiene ningún sobrecoste (ruta rápida). Las etiquetas desconocidas se ignoran y su contenido se conserva. Un `[hyperlink]` se abre en todas partes — etiqueta, título de pestaña, panel de barra de estado, toast, cuadro de diálogo: de ello se encarga la base. El evento `ue_action`, en cambio, solo lo emiten los componentes de texto interactivos (`statictext`); en los demás, `[action]` sirve únicamente para el formato.

Solo se abren `http`, `https` y `mailto`. Una etiqueta transporta a menudo un dato venido de su base: confiar al sistema un esquema cualquiera convertiría una etiqueta en un lanzador de programas.

Un `[foldarea]` es un bloque: ocupa todo el ancho y se pliega con un clic en su encabezado, sin ida y vuelta a PowerBuilder. Los bloques se anidan y, si el componente sigue la altura de su contenido (`ib_auto_height`), esa altura se vuelve a notificar en cada pliegue. El título también es texto con etiquetas: nada se pone en negrita por usted, de eso se encarga `[foldarea:[b]Total[/b]]`.

← Base común · Índice · Idioma y RTL →