Files
cybercore-signer/docs/ui-troubleshooting.md
Claudecio Martins 9f1bc289ee
CI Pipeline / Build & Verify (Linux x86_64) (push) Canceled after 0s
CI Pipeline / Build & Verify (Windows) (push) Canceled after 0s
docs(ui): document native windows titlebar behavior in dark OS mode
2026-10-20 21:33:39 -03:00

7.0 KiB

UI Troubleshooting & Resolução de Estilos (JavaFX CSS)

Este documento registra a investigação da causa raiz de problemas visuais na interface gráfica do CyberCore Signer, em especial a falha de renderização de textos com cor preta (Color.BLACK) via setStyle(), a eliminação definitiva de estilos inline de cor e a transição para o tema claro unificado.


1. O Problema: Texto Renderizado em Preto (#000000) via setStyle

Sintoma

Em diálogos modais como ExitConfirmationDialog, PdfSignDialog e PdfCertificateSignDialog, chamadas como:

subtitle.setStyle("-fx-text-fill: -fx-text-secondary;");
lblDocName.setStyle("-fx-text-fill: -fx-text-primary;");
dragTip.setStyle("-fx-text-fill: -fx-text-secondary;");

resultavam em texto renderizado com a cor preta opaca (#000000), mesmo quando o token -fx-text-secondary já se encontrava definido no arquivo theme.css.


2. Investigação Técnica e Causa Raiz

2.1 Por que setStyle("-fx-text-fill: -fx-text-secondary") renderiza PRETO?

No motor de estilização do JavaFX (com.sun.javafx.css.StyleManager / CssStyleHelper):

  1. Momento da Avaliação (Timing) de Nós Fora da Árvore da Scene: Quando um nó (como um Label ou Text) é instanciado no código Java dentro do construtor de um diálogo e recebe .setStyle("-fx-text-fill: -fx-text-secondary;"), ele ainda não foi anexado ao grafo de cena (Scene).
  2. Escopo de Resolução de Lookups Ausente: Como -fx-text-secondary é uma cor pesquisada (looked-up color) definida no seletor .root da folha de estilo da aplicação, a engine de CSS do JavaFX tenta resolver essa variável subindo a cadeia de nós pais (parent chain) até alcançar .root. Como o nó está solto na memória (sem parent e sem Scene vinculada no instante da chamada), o lookup não encontra nenhuma definição válida.
  3. Mecanismo de Fallback Silencioso do Modena (Color.BLACK): O analisador do JavaFX não lança exceção ao falhar na resolução de uma cor de lookup em estilo inline. Em vez disso, seu conversor (PaintConverter / ColorConverter) assume o valor padrão de salvaguarda da especificação Modena: Color.BLACK (rgba(0, 0, 0, 1.0)).
  4. Imutabilidade e Prioridade do Estilo Inline: O estilo inline atribuído via setStyle(...) possui a especificidade mais alta na hierarquia CSS do JavaFX. O valor pré-resolvido como Color.BLACK fica gravado diretamente no cache de estilo do nó. Quando a Scene finalmente executa a passagem formal de CSS (applyCss() / layout()), a engine prioriza o estilo inline e não reavalia o lookup que falhou previamente.

2.2 Por que o problema não ocorre com Classes CSS?

Quando utilizamos classes semânticas declaradas em folha de estilo (ex.: lbl.getStyleClass().add("text-muted");):

.text-muted {
    -fx-text-fill: -fx-text-secondary;
}

A resolução da regra é postergada até que o nó pertença à hierarquia da Scene e a passagem de CSS do JavaFX seja executada. Nesse momento, o nó tem acesso direto às definições de .root, resolvendo perfeitamente o token para a cor correta da paleta (#475569).


3. Diretriz Arquitetural: Proibição de Cores em setStyle()

Fica estabelecido como regra obrigatória de desenvolvimento no cybercore-ui:

  1. setStyle() restrito exclusivamente à Geometria:

    • Permitido: dimensões dinâmicas, larguras mínimas, alturas, alinhamentos e paddings específicos de cálculo em tempo de execução (-fx-min-width, -fx-pref-width, -fx-padding, -fx-alignment).
    • Terminantemente proibido em setStyle():
      • -fx-text-fill
      • -fx-background-color
      • -fx-border-color
      • -fx-fill / -fx-stroke
      • Códigos hexadecimais (#...) ou funções cromáticas (rgb(...), rgba(...))
      • Nomes de lookups de cor (-fx-accent, -fx-color-*, etc.)
  2. Uso Obrigatório de Classes CSS Semânticas:

    Classe CSS Finalidade Propriedade Aplicada
    .text-primary Texto principal -fx-text-fill: -fx-text-primary;
    .text-secondary, .text-muted Texto auxiliar / metadados -fx-text-fill: -fx-text-secondary;
    .text-accent Destaque primário -fx-text-fill: -fx-accent;
    .text-bold Tipografia em negrito -fx-font-weight: bold;
    .text-small Texto compacto -fx-font-size: 11px;
    .text-mono Fonte monoespaçada para hashes -fx-font-family: monospace;
    .surface-box Container de superfície branca com borda -fx-background-color: -fx-color-surface;
    .toolbar-box Barra de ferramentas compacta -fx-background-color: -fx-color-surface;
    .scroll-transparent ScrollPane sem fundo cinza -fx-background-color: transparent;
    .status-ok / .status-warn / .status-error Indicadores de status Cores semânticas da paleta

4. Salvaguardas Automatizadas

O teste de arquitetura DesignTokenGuardrailTest.java atua como barreira de compilação contínua:

  • Varre todos os arquivos .java no módulo cybercore-ui e reprova automaticamente o build se qualquer chamada setStyle() contiver propriedades ou valores de cor.
  • Valida matematicamente a relação de contraste WCAG AA (mínimo de 4.5:1 para texto normal) em todas as combinações de tokens de texto sobre superfície/fundo.
  • Assegura ausência de seletores ou classes residuais de temas escuros (.theme-dark, AppTheme, isDark()).

5. Comportamento da Barra de Título Nativa no Windows (DWM em Modo Escuro)

Diagnóstico Operacional

Quando o sistema operacional Windows 10/11 está configurado no "Modo Escuro do Sistema" (Personalização > Cores > Escolher o modo: Escuro), o gerenciador de janelas do sistema operacional (Desktop Window Manager — DWM) aplica automaticamente o atributo DWMWA_USE_IMMERSIVE_DARK_MODE na moldura não-cliente da janela nativa (HWND).

Como o CyberCore Signer utiliza decoração nativa padrão (StageStyle.DECORATED) para preservar o comportamento esperado pelo usuário empresarial — incluindo cantos arredondados, atalhos de teclado nativos, suporte a múltiplos monitores com DPIs distintos e os Snap Layouts do Windows 11 — a barra de título nativa é desenhada pelo Windows em tom escuro, enquanto o conteúdo da janela exibe o tema claro unificado da aplicação.

Diretriz de Arquitetura (Não Forçar)

Em estrita conformidade com as diretrizes do projeto (Regras 2 e 23):

  1. Não forçar a barra de título: Evita-se o uso de hacks de baixo nível via JNA/JNI para sobrescrever o DWM do Windows ou janelas não decoradas (UNDECORATED), o que causaria quebra de acessibilidade e perda de recursos nativos do sistema.
  2. Harmonia Visual: A moldura do Windows atua como moldura de sistema e o conteúdo claro do CyberCore Signer permanece legível, íntegro e em total conformidade com a especificação de interface.