# dockcontainer — `u_pbt_dockcontainer` #

← Referência dos componentes · Índice do guia

> Painéis acopláveis ao estilo do Visual Studio: acoplagem por arrastar e largar, empilhamento em separadores, divisores redimensionáveis, janelas flutuantes, ocultação automática — e gravação/reposição da disposição.

> ▶ Ver ao vivo — Aplicação de demonstração, mosaico Dock container: a pré-visualização, o código que o produz e esta página, lado a lado.

## Em resumo #

Userobject | `u_pbt_dockcontainer`
Classe de items | `n_pbt_dock_panel` (um painel)
Serve para | Dar a uma window PowerBuilder a ergonomia de um IDE moderno: o próprio utilizador organiza os seus painéis e a disposição é reencontrada na sessão seguinte

Tal como em tab, cada painel aloja um controlo PowerBuilder verdadeiro (`dragobject`): userobject, DataWindow ou outro componente PBToolboxAI. Ver Alojar controlos reais do PowerBuilder.

## Início rápido #

    // event open da window : os controlos de painel ja estao colocados sobre ela
    uo_dock.of_add_panel(/*chave*/ "document", /*posicao*/ "", /*relativo_a*/ "", &
                         /*tamanho*/ 0, /*titulo*/ "Document", /*conteudo*/ uo_editeur)

    uo_dock.of_add_panel(/*chave*/ "explorateur", /*posicao*/ uo_dock.POSITION_START, &
                         /*relativo_a*/ "document", /*tamanho*/ 260, &
                         /*titulo*/ "Explorador", /*conteudo*/ uo_arbre)

    uo_dock.of_add_panel(/*chave*/ "proprietes", /*posicao*/ uo_dock.POSITION_END, &
                         /*relativo_a*/ "document", /*tamanho*/ 300, &
                         /*titulo*/ "Propriedades", /*conteudo*/ uo_props)

    // A zona central : nao pode ser fechada pela acoplagem, nem flutuar, nem ser ocultada
    uo_dock.is_main = "document"

## Propriedades #

Propriedade | Tipo | Predefinição | Função
--- | --- | --- | ---
`is_main` | string | `""` | Chave do painel principal: a zona de documento central, que não pode ser ocultada nem destacada. O painel tem de existir previamente
`is_theme_style` | string | `fluent` | Estilo visual do componente (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)
`is_tooltip` | string | `""` | Tooltip simples apresentado ao passar sobre o componente
`is_super_tooltip_title` | string | `""` | Título do tooltip enriquecido (prevalece sobre `is_tooltip`)
`is_super_tooltip_text` | string | `""` | Texto do tooltip enriquecido (aceita marcação enriquecida)
`is_super_tooltip_image` | string | `""` | Imagem do tooltip enriquecido

### Posições de acoplagem #

As constantes do componente alimentam `as_position` em `of_add_panel` e `of_move_panel`:

Constante | Valor | Efeito
--- | --- | ---
`POSITION_START` | `"start"` | O novo painel acopla-se do lado do início de leitura do painel de referência (à esquerda numa escrita da esquerda para a direita)
`POSITION_END` | `"end"` | … do lado do fim de leitura
`POSITION_TOP` | `"top"` | … por cima
`POSITION_BOTTOM` | `"bottom"` | … por baixo
`POSITION_STACK` | `"stack"` | O painel é empilhado em separador sobre o painel de referência. Valor adotado se `as_position` estiver vazio

### Propriedades de um painel — `n_pbt_dock_panel` #

Obtidas através de `of_item(chave)`.

Propriedade | Tipo | Predefinição | Função
--- | --- | --- | ---
`is_title` | string | `""` | Título apresentado no separador do painel. Aceita a formatação com etiquetas
`is_short_title` | string | `""` | Forma curta do título, para os locais onde falta espaço: a calha de um painel afixado (sempre — é uma faixa estreita) e o separador de uma pilha, mas apenas quando o título completo já não cabe, o que é medido e não adivinhado. O cabeçalho do painel mantém o título completo. `""` = sem forma curta
`ib_visible` | boolean | `true` | Mostra ou oculta este painel
`ib_pinned` | boolean | `true` | `true` = fixado no lugar; `false` = o painel recolhe-se numa patilha junto ao bordo e só se expande ao passar o ponteiro por cima (ocultação automática)
`is_header_color` | string | `""` | Cor do cabeçalho deste painel. Vazio = o tema decide; `HEADER_COLOR_ACCENT` acompanha o acento do tema (e continua a acompanhá-lo após uma mudança de tema, o que um código fixo não faria); caso contrário um `#rrggbb`. A cor de texto legível é calculada
`is_border_color` | string | `""` | Cor do contorno deste painel, mesma gramática. Contorna a moldura e o cabeçalho, que têm cada um o seu: colorir apenas um deixa uma emenda visível. Acompanha o painel no seu painel deslizante
`is_tooltip` | string | `""` | Tooltip simples apresentado ao passar sobre o item
`is_super_tooltip_title` | string | `""` | Título do tooltip enriquecido do item (prevalece sobre `is_tooltip`)
`is_super_tooltip_text` | string | `""` | Texto do tooltip enriquecido do item (aceita marcação enriquecida)
`is_super_tooltip_image` | string | `""` | Imagem do tooltip enriquecido do item

## Métodos #

Método | Função
--- | ---
`of_add_panel (string as_key, string as_position, string as_relative_to, integer ai_size, string as_title, dragobject ado_content)` | Adiciona um painel fechável e aloja o controlo. `as_relative_to` = chave do painel contra o qual se acopla (vazio = a raiz); `ai_size` = tamanho inicial em píxeis (`0` = automático)
`of_add_panel (…, boolean ab_closable)` | Idem, com `ab_closable = false` para um painel sem botão de fecho
`of_select_panel (string as_key)` | Coloca um painel em primeiro plano no respetivo grupo de separadores
`of_move_panel (string as_key, string as_target, string as_position)` | Reorganiza a partir do código, exatamente como se o utilizador tivesse arrastado o separador
`of_move_panel (string as_key, string as_target, string as_position, integer ai_index)` | O mesmo, indicando a posição do painel na pilha do destino (0 = primeiro, `-1` = último). Só uma pilha é uma lista ordenada: o índice é ignorado para `POSITION_START` / `END` / `TOP` / `BOTTOM`
`of_float_panel (string as_key)` | Destaca o painel numa verdadeira janela flutuante deslocável e redimensionável. Ao fechá-la, o painel volta a acoplar-se (`ue_panel_docked`)
`of_notify_panel (string as_key)` | Assinala conteúdo novo: se o painel não estiver visível, o respetivo separador apresenta um contador de elementos não vistos, apagado ao selecioná-lo
`of_clear_notify (string as_key)` | Apaga esse contador sem mostrar o painel. Selecionar o separador era a única outra forma, o que é errado quando o seu código sabe que o próprio conteúdo desapareceu
`of_remove_panel (string as_key)` | Retira o painel e devolve o controlo à window de origem
`of_get_layout ( )` | Devolve a disposição atual (árvore das divisões, rácios, separadores, visibilidade) sob a forma de uma cadeia, para armazenar em ficheiro, base de dados ou registo
`of_set_layout (string as_json)` | Repõe uma disposição obtida através de `of_get_layout`. Os painéis têm de ter sido recriados antes da chamada; os que estiverem ausentes da disposição são associados ao primeiro grupo
`of_item (string as_id)` | Handle `n_pbt_dock_panel` do painel (criado no primeiro acesso)
`of_refresh_panel (string as_key)` | Atualiza a representação de um painel construído fora do ecrã, sem cintilação
`of_relayout ( )` | Recalcula e volta a publicar todas as zonas para que os controlos alojados sejam reposicionados
`of_reset ( )` | Esvazia o contentor: cada controlo alojado é devolvido à respetiva window de origem, os handles de painéis são libertados e a disposição memorizada é apagada
`of_set_redraw (boolean)` | Agrupa uma rajada de modificações numa única representação
`of_save_as_png (string)` · `of_save_as_jpg (string)` | Exporta a representação como imagem

## Eventos #

Evento | Acionado quando
--- | ---
`ue_panel_selected (string as_key)` | Um painel passa a ser o painel ativo do seu grupo
`ue_panel_closed (string as_key)` | O utilizador fecha um painel
`ue_panel_pinned (string as_key, boolean ab_pinned)` | Um painel é fixado (`true`) ou desafixado em ocultação automática (`false`)
`ue_panel_floated (string as_key)` | Um painel é destacado numa janela flutuante
`ue_panel_docked (string as_key)` | Um painel flutuante volta a ser acoplado
`ue_layout_changed (string as_json)` | A disposição foi alterada (arrastamento, redimensionamento, acoplagem). O parâmetro transporta a nova disposição, pronta a ser gravada
`ue_ready ( )` | O componente terminou o carregamento; tudo o que foi enviado antes foi reproduzido
`ue_runtime_missing ( )` | O runtime WebView2 está ausente: o componente permanece vazio
`ue_bg_color (long al_color)` | O componente calculou a cor de fundo do respetivo tema; o userobject já a adotou (`backcolor`)

## Com o teclado #

O conteúdo de um painel é um verdadeiro controlo PowerBuilder: aí o teclado pertence ao seu código, como em qualquer janela. Aquilo de que o componente trata é o seu próprio invólucro — cabeçalhos, separadores, divisores:

Tecla | Efeito
--- | ---
Setas sobre um separador | Passam ao painel anterior / seguinte do grupo e selecionam-no. Uma banda de separadores é uma única paragem de tabulação
Home / End sobre um separador | Primeiro / último painel do grupo
Setas sobre um divisor | Deslocam a separação em 2 %, apenas no eixo do divisor
Page Up / Page Down sobre um divisor | O mesmo, em passos de 10 %
Esc | Fecha o painel deslizante aberto a partir de um botão de margem

Um divisor é um `separator` focável que anuncia a sua posição; os botões do cabeçalho (destacar, ocultar, fechar) têm um nome, e o painel ativo de um grupo está marcado com `aria-selected`. Uma deslocação com o teclado é comunicada em `ue_layout_changed` exatamente como um arrastamento com o rato.

## Exemplos #

### Uma window ao estilo de um IDE #

    // event open : cada conteudo e um controlo PB verdadeiro colocado sobre a window
    uo_dock.of_add_panel("document", "", "", 0, "Document", uo_editeur)
    uo_dock.of_add_panel("explorateur", uo_dock.POSITION_START,   "document", 260, "Explorador", uo_arbre)
    uo_dock.of_add_panel("proprietes",  uo_dock.POSITION_END,  "document", 300, "Propriedades",  uo_props)
    uo_dock.of_add_panel("sortie",      uo_dock.POSITION_BOTTOM, "document", 200, "Saida",      uo_console)

    // Um segundo painel empilhado em separador sobre "proprietes"
    uo_dock.of_add_panel("aide", uo_dock.POSITION_STACK, "proprietes", 0, "Ajuda", uo_aide)

    uo_dock.is_main = "document"

### Memorizar e repor a disposição do utilizador #

    // event close da window : gravar aquilo que o utilizador organizou
    string ls_disposition
    ls_disposition = uo_dock.of_get_layout()
    of_enregistrer_preference("dock_principal", ls_disposition)

    // event open : RECRIAR primeiro os paineis, repor a disposicao depois
    string ls_disposition

    of_creer_les_panneaux()          // os of_add_panel acima

    ls_disposition = of_lire_preference("dock_principal")
    if ls_disposition <> "" then uo_dock.of_set_layout(ls_disposition)

> A ordem é imperativa: `of_set_layout` não cria nenhum painel, limita-se a recolocar os que já existem.

### Acompanhar as alterações continuamente #

    // event ue_layout_changed de uo_dock : (string as_json)
    // Gravacao imediata, sem esperar pelo fecho da window.
    of_enregistrer_preference("dock_principal", as_json)

### Comandar um painel através do respetivo handle #

    n_pbt_dock_panel lnv_panneau

    lnv_panneau = uo_dock.of_item("proprietes")
    lnv_panneau.is_title  = "Propriedades (3 modificadas)"
    lnv_panneau.ib_pinned = false        // recolhe-se numa patilha junto ao bordo

    // Ocultar um painel reservado aos administradores
    uo_dock.of_item("audit").ib_visible = gb_administrateur

### Chamar a atenção para um painel em segundo plano #

    // Um processamento em segundo plano escreveu na consola : assinalar sem roubar o foco
    uo_dock.of_notify_panel("sortie")

### Reorganizar a partir do código #

    // Deslocar um painel como se o utilizador tivesse arrastado o seu separador
    uo_dock.of_move_panel(/*chave*/ "sortie", /*destino*/ "document", /*posicao*/ "bottom")

    // Empilha-lo em separador sobre outro painel
    uo_dock.of_move_panel(/*chave*/ "aide", /*destino*/ "proprietes", /*posicao*/ "stack")

### Destacar um painel para um segundo ecrã #

    // Janela flutuante nativa : o utilizador pode coloca-la noutro ecra
    uo_dock.of_float_panel("proprietes")

    // event ue_panel_docked de uo_dock : (string as_key)
    // O utilizador voltou a fechar a janela flutuante : o painel regressou.
    of_journaliser("Painel novamente acoplado: " + as_key)

### Fechar corretamente um painel #

    // event ue_panel_closed de uo_dock : (string as_key)
    // Retirar tambem o painel do contentor para libertar o controlo alojado.
    uo_dock.of_remove_panel(as_key)

## Boas práticas #

- Designar sempre um painel principal com `is_main`: sem zona central, o utilizador pode ocultar tudo e ficar perante uma window vazia.
- Gravar a disposição em `ue_layout_changed` em vez de o fazer apenas no fecho: assim, um encerramento anormal não perde nada.
- `of_set_layout` vem depois dos `of_add_panel`, nunca antes.
- Utilizar `of_notify_panel` para os processamentos em segundo plano: é menos intrusivo do que uma caixa de diálogo e a informação permanece visível.
- Um controlo alojado é uma janela nativa: desenha-se por cima da camada web, e nenhum efeito visual do componente passa por cima dele.
- `of_reset()` antes de qualquer reconstrução: sem ele, os controlos anteriormente alojados permanecem reparentados no contentor esvaziado e a reutilização de uma chave falha.
- Para simples páginas exclusivas, sem acoplagem nem flutuação, tab é mais leve.

← Referência dos componentes · Índice do guia