11. Migrar da 3.0 para a 4.0 #
← Migrar da 2.0 para a 3.0 · Índice · Notas de versão →
A 4.0 retira dois métodos dos trinta e dois componentes da 3.0 — of_set_data da tabela cruzada, renomeado of_from_datastore (11.33), e of_transform de n_pbt_xml, que sai com o XSLT (11.31) — e muda assinaturas que o compilador lhe mostra linha a linha: três propriedades renomeadas (id_minimum e id_maximum da barra de progresso, 11.6; il_doc_line do editor de código, 11.28), argumentos de evento acrescentados ou renomeados (ue_tile_moved, 11.6; ue_failed do cliente REST, 11.6, e do vídeo, 11.26; ue_error da imagem, 11.25; ue_cell_double_clicked, 11.33; ue_closed da paleta de comandos, 11.36; ue_toast_clicked, ue_toast_action e ue_toast_dismissed do toaster, 11.38), of_count e of_keys_at em long (11.34) e métodos que passam a devolver um código (of_refresh, of_select, of_show, of_scroll_to_end, of_set_header…). A 11.6 alinha ainda duas contagens, um evento e o caminho da árvore JSON com o resto da biblioteca: é aí, com as secções citadas, que há código que compilava a retocar. O que muda concentra-se no friso (ribbon), que foi revisto por completo. Duas mudanças pedem para reler o código: a pergunta colocada antes de um mosaico de galeria (11.1) e os handles libertados por uma remoção (11.2). As outras corrigem comportamentos que pode ter contornado (11.3) — entre eles o clique direito num item, que passa a produzir um só evento em todos os componentes, e o trilho de navegação (breadcrumb), cujos endereços e recusas foram revistos. Seguem-se o gerador n_pbt_menu2ribbon (11.4) e o que foi acrescentado (11.5). A barra lateral (listbar) segue também a regra do 11.1: a sua pergunta antes de uma seleção passa a ser opcional. Os separadores (tab) seguem a mesma regra: as suas duas perguntas, antes de uma mudança de separador e antes de um fecho, passam a ser opcionais (11.1). Por fim, os temas seguem a aplicação (11.7): o destaque da aplicação sobrevive a uma mudança de tema, e um eixo de tema deixado vazio segue o da aplicação. A revisão de segurança de crypto (11.8) fecha uma confusão de algoritmo dos tokens JWT, substitui vários silêncios por uma recusa que diz a sua razão e fixa a regra dos caminhos relativos dos ficheiros.
A revisão completa de 28/09/2026 releu cada componente entregue; o que muda tem uma secção por componente: restclient (11.9), speechout (11.10), statictext e o texto rico (11.11), breadcrumb (11.12), buttonbar e o teclado de janela (11.13), button (11.14), menubar (11.15), ribbon (11.16), toolbar (11.17), statusbar (11.18), dockcontainer (11.19), tab (11.20), listbar (11.21), tilesbox (11.22), stepbar (11.23), progressbar (11.24), picture (11.25), video (11.26), pdfviewer (11.27), codeeditor (11.28), jsontree e xmltree (11.29, 11.30), xml (11.31), json (11.32), crosstab (11.33), shellexplorer (11.35), commandpalette (11.36), radialmenu (11.37), toaster (11.38) e messagebox (11.39); a base comum tem duas secções, 11.34 e 11.40. Uma regra atravessa-as, a do PowerBuilder (SelectTab lança SelectionChanged): uma mudança pedida pelo seu código lança o mesmo evento que um gesto do utilizador, e faz a pergunta do veto se a ativou; o método devolve -4 se recusar. Vale para uma seleção (of_select_*), uma abertura ou um recolhimento (of_expand, of_collapse, of_open), um zoom, um ecrã inteiro, um capítulo; nada é lançado quando nada muda, e of_reset continua em silêncio. Definir um VALOR (uma marca, um texto, um volume, um filtro) continua em silêncio, como SetItem. ue_layout_changed é lançado nos dois casos: diz que uma disposição a guardar mudou.
11.1 As perguntas antes de uma mudança passam a ser opcionais #
Na 3.0 o friso colocava por omissão a pergunta ue_gallery_selection_changing antes de reter um mosaico: ib_veto_gallery valia true. Na 4.0 vale false, como todo o evento cancelável da biblioteca: cada pergunta custa uma ida e volta ao PowerBuilder, e só uma aplicação que responde deve pagá-la. Uma aplicação que não programava o evento não vê nenhuma diferença. Novo: of_select_gallery_item lança ue_gallery_selection_changed como um clique e, com a pergunta ativada, também a faz; uma recusa fá-lo devolver -4, o mosaico não muda.
// 4.0 : the question is only asked on request. If your ue_gallery_selection_changing
// returns false for some tiles, switch it on where the ribbon is built.
uo_ribbon.ib_veto_gallery = true
A receita: procure ue_gallery_selection_changing nos descendentes do friso; onde estiver programado, acrescente ib_veto_gallery = true à construção. Onde escrevia ib_veto_gallery = false para desligar a pergunta, a linha deixa de servir e pode sair.
A barra lateral (listbar): ib_veto_selection #
Mesma regra: na 3.0 a listbar colocava por omissão ue_selection_changing antes de cada mudança de seleção (ib_veto_selection valia true). Na 4.0 vale false. Se programava ue_selection_changing para recusar uma mudança, defina ib_veto_selection = true: sem isso, o evento deixa de ser disparado e a seleção muda sem lhe perguntar. Ativada, a pergunta é feita também para uma seleção pedida pelo seu código (of_select_item, of_clear_selection), como na 3.0; uma recusa faz-lhes agora devolver -4, e a seleção não se move. ue_selection_changed dispara como antes.
// 4.0 : the listbar only asks on request. If your ue_selection_changing
// returns false (unsaved changes), switch the question on where the bar is built.
uo_nav.ib_veto_selection = true
A receita: procure ue_selection_changing nos descendentes de u_pbt_listbar; onde devolver false, acrescente ib_veto_selection = true à construção. Onde escrevia ib_veto_selection = false para desligar a pergunta, a linha deixa de servir e pode sair.
Os separadores (tab): ib_veto_selection e ib_veto_close #
Mesma regra, duas perguntas: na 3.0 o componente tab colocava por omissão ue_selection_changing antes de cada mudança de separador e ue_tab_closing antes de cada fecho (ib_veto_selection e ib_veto_close valiam true). Na 4.0 ambos valem false. Se programava ue_selection_changing ou ue_tab_closing para recusar, defina ib_veto_selection = true ou ib_veto_close = true: sem isso, o evento deixa de ser disparado e o separador muda ou fecha sem lhe perguntar. Ativada, a pergunta é feita também para of_select_page, como na 3.0, mas antes de o separador mudar: uma recusa fá-lo devolver -4 e nada se move; um acordo muda o separador de imediato, ue_selection_changed dispara como antes, e of_selected_key() relido logo a seguir já devolve a nova chave.
// 4.0 : the tab only asks on request. If your ue_selection_changing or
// ue_tab_closing returns false (unsaved changes), switch the questions on.
uo_tabs.ib_veto_selection = true
uo_tabs.ib_veto_close = true
A receita: procure ue_selection_changing e ue_tab_closing nos descendentes de u_pbt_tab; onde um devolver false, acrescente a linha correspondente à construção. Onde escrevia = false para desligar uma pergunta, a linha deixa de servir e pode sair.
11.2 As adições dizem o que recusam, as remoções libertam os seus handles #
Na 3.0, uma adição que o friso ignorava — uma chave já ocupada, uma entrada de menu sob um simples botão — devolvia na mesma 0, e nada aparecia. Na 4.0 devolve -5, e o código do envio (-2 se o componente não estiver criado) em vez de um 0 fixo. E uma remoção liberta os handles do que sai: uma variável que guardava o handle de um controlo removido deixa de ser válida.
| O quê | 3.0 | 4.0 |
|---|---|---|
| Acrescentar uma chave já ocupada (separador, grupo, controlo) | 0, ignorada | -5 |
| Entrada de menu, escolha de combo ou mosaico sob um controlo de outra natureza | 0, ignorada | -5 |
of_add_tab, of_insert_tab, of_add_group, of_add_contextual_*, of_add_qat num componente não criado | 0 | -2 |
Um handle guardado após of_remove_tab, of_remove_group, of_remove_item ou of_clear | ficava em memória até à destruição do friso | libertado: IsValid() devolve false |
// 4.0 : after a removal or of_clear, ask the component for the handle again
uo_ribbon.of_clear()
uo_ribbon.of_add_tab(/*key*/ "home", /*title*/ "Home")
uo_ribbon.of_add_group(/*keys*/ "home/clip", /*title*/ "Clipboard")
uo_ribbon.of_add_button(/*keys*/ "home/clip/paste", /*label*/ "Paste", /*image*/ "")
uo_ribbon.of_item(/*keys*/ "home/clip/paste").ib_enabled = false
A receita: não guarde um handle para lá de uma remoção ou de um of_clear — volte a pedi-lo com of_tab, of_group, of_item ou of_menu_item, o que não custa nada. Onde um erro de construção lhe importe, verifique o código devolvido pela adição.
11.3 Outros comportamentos que pode notar #
Quando a janela é estreita, o friso recolhe os grupos num botão que abre um painel. É desse painel que vêm as diferenças mais visíveis:
| O quê | 3.0 | 4.0 | |
|---|---|---|---|
| Botão, ou parte principal de um split, clicado no painel de um grupo recolhido | ue_menu_selected("", false) | ue_clicked(endereço) | |
| Entrada de menu escolhida nesse painel | endereço incompleto | endereço completo, cascata incluída | |
| Controlo desativado, ou entrada oculta, nesse painel | respondia / era mostrada | não responde / não é mostrada | |
| Split grande reduzido por falta de espaço | um clique só abria o menu | duas partes: o comando e a seta do menu | |
Entrada de menu com a chave do seu controlo (home/clip/paste/paste) | ue_clicked("home/clip/paste") | ue_menu_selected("home/clip/paste/paste", …) | |
of_menu_item("…/exp/pdf") quando uma cascata também contém pdf | podia visar …/exp/more/pdf | visa a entrada que o endereço nomeia | |
as_from_keys de ue_gallery_selection_changed sem mosaico anterior | o endereço da galeria | "" | |
Reler um handle da barra de acesso rápido, il_color de um seletor de cor, ii_visible_items, is_keytip de um separador, il_color de um grupo contextual, of_count() de uma galeria | vazio, -1 ou 0 | o valor no ecrã | |
of_keys_at de uma combo | "home/font/cb/cb:Arial" | "home/font/cb/Arial": a chave de uma escolha é a sua etiqueta | |
of_ctx_group(k).il_color quando um separador também tem a chave k | coloria o separador | colore apenas o banner | |
Cores de item (il_back_color…) e is_tooltip de um separador ou de um grupo | sem efeito | aplicadas; a dica de um grupo aparece no seu título | |
of_remove_item("save") num botão da barra de acesso rápido | -5 | o botão é removido | |
of_add_app_menu_separator("saveas/s1") | uma linha na raiz do menu | a linha no submenu de saveas; uma chave sem / não muda | |
of_clear() enquanto um separador estava ativo | nenhum evento | ue_selection_changed("") | |
Spinner com passo decimal (0.1) | 0.30000000000000004 | 0.3 | |
| Atalho Alt (keytip) num controlo desativado, friso minimizado | o friso ficava aberto | fecha-se, nada é executado | |
| toolbar: combo, spinner ou galeria desativados no painel do chevron | respondiam | não respondem | |
Todos: clique direito num item (ue_item_rclicked, ue_panel_rclicked, ue_row_rclicked…) | a página enviava também o evento do componente, que nenhum componente com itens transmitia ao PowerBuilder | um só evento, o do item; um ue_rclicked de componente, onde existe, só é levantado fora dos itens | |
Todos: largar ficheiros (ib_allow_drop) | ue_drag_leave e depois ue_drop_files; caminhos cortados a 260 caracteres | só ue_drop_files, caminhos completos; of_reset retira o destino de largar | |
breadcrumb: of_path() com um segmento escondido, ou na versão de demonstração | as chaves mostradas: o escondido saltado, os primeiros segmentos cortados | o endereço completo do local actual: of_truncate(of_path()) acerta; o campo de escrita parte do mesmo | |
breadcrumb: of_keys_at(n); of_has("computer/C:") | a chave simples; procurava entre os ramos do menu | o endereço do segmento; procura entre os segmentos | |
breadcrumb: ler um handle de endereço profundo, of_item("a/b/c").is_text | lia só o último nível: vazio numa chave repetida | o segmento desse endereço | |
breadcrumb: of_truncate, of_remove_item, of_clear_children, of_remove_child num endereço desconhecido ou numa chave simples repetida; of_add_child sob um segmento ausente ou num ramo já ocupado; of_add_item de um endereço que iria parar a outro sítio | 0, ignorado (ou só a última chave retida) | -5 | |
breadcrumb: um handle guardado após of_clear, of_remove_item, of_truncate, of_clear_children ou of_remove_child | ficava em memória | libertado: IsValid() devolve false | |
| breadcrumb: campo de escrita deixado sem alterações, ou janela mudada (Alt+Tab) durante a escrita | ue_path_entered levantado | nada; o que foi escrito mantém-se ao mudar de janela | |
breadcrumb: segmento desactivado; Enter num segmento | o seu chevron abria-se e recebia um largar; Enter premia também o botão predefinido da janela | totalmente inerte; Enter só clica no segmento | |
buttonbar: Enter enquanto outro botão da barra tem o foco do teclado | acionava o botão predefinido (is_default) | aciona o botão com o foco, como o Windows; o predefinido é acionado quando nenhum botão da barra tem o foco | |
buttonbar: botão predefinido ou cancelar desativado ou oculto; is_shortcut de um botão desativado ou oculto | Enter, Esc ou Alt+letra engolidos sem efeito, mesmo num controlo PowerBuilder da janela | a tecla fica com a janela | |
buttonbar: is_shortcut de várias letras ("Save") | Alt+S só funcionava se a barra tivesse o foco | Alt+S funciona de qualquer ponto da janela (a primeira letra, como documentado) | |
buttonbar: of_add_button / of_insert_button numa chave já usada ou que contém / ou uma barra vertical; of_remove_button / of_move_button numa chave desconhecida | 0, ignorado | -5 | |
buttonbar: of_remove_button, of_clear_buttons | o atalho Alt+letra, as cores e a tooltip do botão ficavam (um botão recriado com a mesma chave recuperava-os); o handle ficava em memória | saem com o botão; o handle é libertado: IsValid() devolve false | |
codeeditor: reler is_text de um texto em CRLF | em LF (em CRLF só se o editor estava dobrado): is_text = ls_original era falso | com os finais de linha recebidos, dobrado ou não | |
codeeditor: reler is_syntax após SYNTAX_CSHARP, SYNTAX_CPP, SYNTAX_JAVA, SYNTAX_XML | a gramática usada ("c", "html") | o valor escrito | |
codeeditor: of_insert_text só de leitura ou dobrado | inserido só de leitura; recusado dobrado, mas 0 | -4, nada é inserido | |
codeeditor: ii_doc_line | só uma faixa, muitas vezes fora da vista, ausente na mudança de linha; um integer | a linha vem para o meio da vista (uma região dobrada que a esconde abre-se), faixa também na mudança de linha; cursor e seleção intactos; um long — renomeado il_doc_line na 4.0 (secção 11.28) | |
codeeditor: #regionopen com ib_folding | reescrito #region no texto (is_text, e depois da dobragem) | nunca é tocado; só a vista dobrada mostra #region | |
codeeditor: ue_find_result | duas vezes por of_find, a cada tecla e (0, 0) ao fechar a barra; lançado mesmo com ib_search_enabled = false | uma vez por pesquisa ou passo; ao escrever se a contagem mudar; nunca ao fechar; of_find sem efeito com a pesquisa desativada | |
codeeditor: ue_caret_changed | mudo durante a escrita; dobrado, a linha APRESENTADA | lançado também durante a escrita; dobrado, a linha da calha | |
codeeditor: Ctrl+Z depois de Enter ou Tab; Enter / Tab dobrado | o histórico de anulação era apagado; dobrado, a tecla alterava a vista e perdia-se depois | cada tecla anula-se; dobrado, a tecla não tem efeito | |
codeeditor: ib_folding = true com ib_line_numbers = false | as regiões ficavam fechadas, sem marcador para as abrir | uma calha estreita mantém os marcadores | |
commandpalette: of_add_command numa chave já usada ou que contém / ou uma barra vertical; of_remove_command numa chave desconhecida | 0 (uma chave usada dava dois comandos gémeos) | -5 | |
commandpalette: of_open / of_register_shortcut sem ipo_owner nem ipo_receiver | 0, e nenhum evento chegava nunca | -5 | |
| commandpalette: o atalho premido enquanto a paleta está aberta | sem efeito | fecha a paleta | |
| commandpalette: um objeto paleta destruído (página ou janela fechada) | o seu atalho ficava registado e engolia a tecla na janela, sem qualquer evento | o atalho sai com o objeto, e uma paleta que tinha aberto fecha-se | |
commandpalette: atalho mostrado numa linha, num teclado não latino, com um algarismo e Shift, Ctrl+Space, Ctrl+Up, Ctrl+Del, ou uma tecla F sozinha | não respondia; Win + a letra lançava o comando cujo atalho era essa única letra | responde: a tecla física, lida como a DLL a lê; Win nunca é um modificador | |
commandpalette: um comando cujo atalho é Ctrl+C, Ctrl+V, Ctrl+Z ou Ctrl+A, durante a escrita | o comando partia em vez da cópia, da colagem… | a caixa de pesquisa mantém estas quatro teclas | |
commandpalette: of_reset | mantinha is_recent, uma paleta aberta e o atalho já registado | esvazia-os, fecha-a e repõe o atalho registado em SHORTCUT_DEFAULT | |
commandpalette: pbm_custom02 da janela ipo_owner | disparado a cada evento da paleta | nunca: só um ipo_receiver definido o continua a receber | |
Todos: reler um valor de texto longo (is_text de um script grande) | cada vez mais lento com o tamanho (vários segundos); cortado sem aviso para lá de um milhão de caracteres | proporcional ao tamanho; inteiro | |
n_pbt_utils.of_dir_has_subfolders | contava as pastas escondidas, de sistema e as junções; ilegível para lá de 260 caracteres | ignora-as, como o Explorador (a sobrecarga ab_include_hidden conta-as); lê caminhos longos | |
crosstab: separador de milhares de of_set_value_format | valia para TODAS as medidas; "," não reconhecido ($1 234 em francês) | definição DESTA medida; ",", ".", " " reconhecidos; "" = predefinição do menu Opções | |
crosstab: of_set_member_filter(campo, "") | nenhum membro mantido: tabela vazia | remove o filtro, como of_set_member_order("") | |
crosstab: is_show, is_conditional_formatting, of_set_value_format antes de of_add_value_field | perdidos sem aviso | guardados, relidos tal como definidos, aplicados quando o campo entra em Valores | |
| crosstab: ordenar uma coluna ou recolher um grupo com o rato | nenhum evento | ue_layout_changed, como tudo o que of_get_layout guarda | |
crosstab: datas de um DataStore num posto não francês (3/15/2025, 15.03.2025) | agrupadas num mês errado ou vazio; datas ordenadas só pelo ano | o mês certo; a coluna relida como aaaa-mm-dd, ordenada no tempo | |
| crosstab: números mostrados em alemão, italiano, espanhol, português | à americana (1,234.5) | na língua de apresentação (1.234,5 em alemão) | |
crosstab: of_export_csv | números com ponto (1436.5), lidos como texto por um Excel francês; um rótulo =… executava-se na abertura | separador decimal da língua de apresentação; um apóstrofo antes de = + - @ | |
crosstab: of_export_xlsx | totais e subtotais ocultos exportados na mesma; total no topo ignorado; símbolo « antes » passado para depois | a tabela tal como no ecrã | |
| crosstab: « Adicionar aos valores » do menu de um campo já em Valores | substituía os seus valores | acrescenta um valor, como o arrastar | |
| crosstab: « Remover » do menu de um campo filtrado | o filtro ficava ativo, invisível | o filtro sai com o campo | |
crosstab: AGG_DISTINCT_COUNT numa coluna com células vazias | o vazio contava como um valor | ignorado, como no Excel | |
| crosstab: fórmula que cita uma medida calculada | aceite, valia 0 | recusada através de ue_calc_field_error; as suas mensagens estão em inglês | |
crosstab: ue_layout_changed com uma chaveta num membro; ad_value de ue_cell_double_clicked | disposição truncada; valor 0 se um campo em linhas se chama value, expoente perdido | lidas inteiras | |
crosstab: ib_enabled = false, pelo teclado | Enter abria o menu de um chip, Ctrl+C copiava | mudo | |
| crosstab: teclado | o foco voltava ao topo da página após cada ação; nenhuma forma de mover um campo | o foco fica no elemento acionado; o menu de um chip desloca-o (outra zona, esquerda, direita) | |
| crosstab: tema escuro | negativos e setas de ícones pouco legíveis; célula da escala de cores selecionada ilegível | uma paleta própria no modo escuro | |
crypto: of_jwt_sign com JWT_EDDSA | o cabeçalho dizia "alg":"EDDSA", que as outras bibliotecas (jose, PyJWT, jjwt) recusam | "alg":"EdDSA", o nome registado; um token 3.0 continua a verificar-se | |
crypto: of_generate_keypair de um tipo ou tamanho desconhecido ("ec_p256", 1024) | 0 e um par RSA 2048, sem uma palavra | -5, ambos os PEM vazios, is_last_error nomeia as KEY_* admitidas | |
crypto: of_hash_file("SHA-256", …); algoritmo desconhecido | vazio, e is_last_error dizia « ficheiro ilegível » de um ficheiro perfeito | o nome lê-se como of_hash o lê (SHA-256 = HASH_SHA256); um algoritmo desconhecido é dito como tal, à parte de um ficheiro ilegível | |
crypto: of_base64_encode_file de um ficheiro grande demais (mais de 64 MB em 32 bits, 512 MB em 64 bits); de um ficheiro ausente em demo | « ficheiro ilegível »; « limite da demo » | « grande demais para este processo »; « ficheiro ilegível » — is_last_error dá a verdadeira razão | |
crypto: is_last_error após uma chamada nativa bem-sucedida (of_crc32, of_hash em MD5, of_hash_file…) | guardava o erro da chamada anterior | vazio | |
crypto: chave HMAC vazia; exp/nbf não numérico de um JWT; of_password_verify de um valor com mais de 10 000 000 rondas; of_random_password de um conjunto desconhecido | erro obscuro do motor; token válido para sempre; minutos de cálculo; CHARSET_ALL tomado sem uma palavra | recusados de imediato, is_last_error diz porquê | |
crypto: of_base64_decode_to_file("", caminho) | -5 | 0, um ficheiro vazio | |
dockcontainer: of_add_panel com um as_relative_to desconhecido, um controlo já alojado, uma chave com / ou uma barra vertical, ou POSITION_STACK sobre o painel principal | 0: o painel acoplava-se à raiz, o controlo era alojado duas vezes, ou o painel empilhado sobre o principal ficava invisível | -5, e o controlo não é tocado | |
dockcontainer: of_move_panel para um destino desconhecido, ou POSITION_STACK sobre o painel principal | 0: o painel ia para a raiz, ou nada se mexia | -5 | |
dockcontainer: of_remove_panel, of_reset | o controlo voltava à sua window oculto, na posição e com o tamanho do dock | volta ao seu lugar, com o seu tamanho e com a visibilidade que tinha antes de of_add_panel | |
dockcontainer: is_main definido antes de of_add_panel; is_main = ""; is_main de um painel empilhado | ignorado em silêncio; nada era transmitido; os vizinhos de pilha ficavam invisíveis | guardado e aplicado ao adicionar o painel; o painel principal é retirado; sai da sua pilha, os outros continuam visíveis | |
dockcontainer: of_set_layout de uma disposição que não conhece nenhum dos painéis, ou de um texto que não é uma disposição | o dock esvaziava-se, ou a mensagem inteira era rejeitada; 0 | os painéis ficam, arrumados ao lado dos outros (nunca sobre o principal); -5 para um texto que não é uma disposição | |
dockcontainer: ue_layout_changed | disparado só ao arrastar, redimensionar e acoplar: uma disposição gravada neste evento esquecia um painel fechado ou o separador ativo | também disparado quando um painel é fechado, ocultado, selecionado ou renomeado, e quando o painel principal muda | |
| dockcontainer: clique no separador (ou cabeçalho) do painel já ativo | ue_panel_selected a cada clique | nada: o evento indica uma MUDANÇA de painel ativo | |
dockcontainer: painel desafixado (ib_pinned = false) | a sua patilha só abria com um clique (a doc dizia « ao passar o ponteiro ») | abre ao passar o ponteiro (400 ms) ou com um clique; aberta ao passar o ponteiro, recolhe-se quando o rato a deixa | |
| dockcontainer: controlo PB padrão (MultiLineEdit, botão…) num painel flutuante | as suas notificações (modified, clicked, cores) deixavam de chegar | chegam como quando está acoplado | |
dockcontainer: ocultar um painel flutuante (ib_visible = false) | a sua janela ficava aberta | fecha-se; ao voltar a ser mostrado, o painel regressa acoplado ao seu lugar | |
| dockcontainer: janela flutuante | a sua área útil era mais pequena do que o painel (barra de título descontada), podia sair do ecrã, e um título com etiquetas mostrava-as | a área útil tem o tamanho do painel, a janela fica no ecrã, o título é texto simples | |
| dockcontainer: divisor pelo teclado | a primeira seta fazia-o saltar para 50 % | parte da sua posição apresentada | |
json: valor nulo dado a of_set_number, of_add_number, of_set_boolean, of_add_boolean, ou valor nulo ou vazio dado a of_set_raw / of_add_raw | todo o documento ficava nulo (of_text devolvia null) ou deixava de ser JSON; um booleano nulo escrevia-se false | escreve-se null, o resto do documento fica intacto | |
json: escrever num documento CARREGADO cuja chave se escreve "k" : v ou com um carácter escapado, seguido de uma quebra de linha, ou cuja raiz é um array; of_set_members nesse documento | a chave era acrescentada em duplicado (a releitura devolvia o valor antigo), a escrita devolvia -4 sem razão, ou o documento era substituído pelo fragmento | o valor é substituído ou acrescentado como num documento construído; of_set_members devolve -4 se a raiz não for um objeto | |
json: of_set_*("items/1/qty", …) — uma chave NOVA num objeto situado num array | -4 | 0: a chave é acrescentada ao primeiro elemento; um array atravessa-se por um índice existente, só se cria uma chave de objeto | |
json: caminho com um segmento vazio (/name, a//b, a/) | eram criadas chaves chamadas ""; of_remove podia retirar outro valor | -5, nada é escrito; um leitor responde "ausente" | |
json: of_load de um número mal escrito (-, 01, +1, .5, 1., 1e) | 0, e of_is_valid verdadeiro | -4, como qualquer JSON inválido | |
json: of_get_number de um número com expoente (1e-7, 2.5E+3) ou com mais de 9 casas decimais | expoente ignorado (2.5E+3 lido 2,5), casas decimais cortadas a 9 | expoente resolvido, 17 algarismos significativos mantidos | |
| json: ler ou modificar um documento grande (uma resposta de API de 80 KB, 2000 linhas) | segundos por chamada (20 s para of_count), a aplicação parecia bloqueada | um tempo proporcional ao tamanho; ler as linhas uma a uma (rows/1, rows/2…) ou percorrer as chaves com of_name já não recomeça do início | |
listbar: of_add_section / of_insert_section com uma chave ocupada ou que contém / ou uma barra vertical; of_add_item / of_insert_item com um endereço ocupado ou sob uma secção que a barra não adicionou; of_remove_item, of_move_item, of_select_item, of_remove_section, of_move_section com um endereço desconhecido | 0, ignorado; uma entrada sob uma secção desconhecida aparecia sob a última secção | -5; of_add_section devolve também -2 quando o componente não está criado | |
listbar: um handle mantido após of_remove_item, of_remove_section ou of_clear | ficava em memória | libertado: IsValid() devolve false | |
listbar: retirar ou esvaziar o que tem a seleção (of_remove_item, of_remove_section, of_clear) | a seleção desaparecia sem evento; após of_clear, of_selected_key ainda devolvia a antiga | ue_selection_changed(antiga, "") | |
listbar: ue_layout_changed | mudo ao recolher uma secção e ao retirar uma entrada; disparado ao entrar na calha | disparado ao recolher (clique ou ib_collapsed de uma secção) e ao retirar; já não para a calha, que não faz parte da disposição | |
listbar: calha (ib_collapsed = true) | as entradas de uma secção recolhida desapareciam; uma entrada sem ícone mostrava um quadrado vazio; of_reset deixava a barra estreita | todas as entradas, um filete entre secções, a inicial de uma entrada sem ícone, a etiqueta ao passar o rato; of_reset devolve à barra a sua largura | |
listbar: is_image de uma secção; uma cor definida na secção k quando uma entrada também tem a chave k | sem efeito; a entrada também ficava com a cor | o ícone é desenhado antes do título; só a secção fica com a cor | |
| listbar: teclado | após uma mudança de etiqueta ou uma seleção, as setas deixavam de responder; sem seleção a barra ficava fora da tabulação; os títulos de secção só se recolhiam com o rato | o foco fica na entrada; uma paragem de tabulação; os títulos alcançam-se com as setas e recolhem-se com Enter ou Espaço | |
listbar: entrada desativada (ib_enabled = false); ib_auto_width numa barra expandida | etiqueta esbatida, pouco legível em temas claros; comunicava a largura já dada | a cor « desativado » do tema; a largura que a linha mais longa pede | |
listbar: arrastar uma entrada (ib_reorderable) | botão largado fora da janela: a entrada continuava a seguir o rato; o clique final podia selecionar a entrada largada | o gesto termina quando o rato volta; o fim de um arrasto não seleciona nada | |
menubar: ue_menu_opening | levantado ao lado do menu pendente: o que mudava (esbater Colar…) só se via na abertura seguinte | o menu pendente espera que o evento regresse: a mudança vê-se nesta abertura | |
menubar: of_item, of_remove_item numa entrada cuja chave também existe noutra cascata (file/export/pdf, file/print/pdf) | podiam atingir a outra entrada (a primeira encontrada); o atalho mostrado numa disparava a outra | atingem a entrada que o endereço nomeia; uma chave sozinha já não procura nas cascatas | |
menubar: of_add_menu, of_add_item, of_add_separator numa chave já ocupada, com / ou uma barra vertical, ou sob um menu ou um pai desconhecidos; of_remove_item / of_remove_menu de um endereço desconhecido | 0; uma entrada com o pai mal escrito ia para a raiz do menu, uma chave ocupada dava entradas gémeas | -5 | |
menubar: um handle ou um atalho após of_remove_item, of_remove_menu ou of_clear | o handle ficava em memória; o atalho continuava armado e engolia a tecla, que já não chegava à aplicação | handle libertado: IsValid() devolve false; atalho desarmado | |
| menubar: entrada esbatida, oculta ou retirada enquanto o seu menu pendente está aberto; atalho de uma entrada sob uma cascata esbatida | o clique ou a tecla ainda levantavam ue_item_selected | nada | |
menubar: cores de item (il_back_color…) de um menu ou de uma entrada; is_tooltip de um menu | sem efeito; uma cor relia-se -1 | aplicadas: no título do menu, na entrada do menu pendente; a dica de um menu aparece no seu título, uma entrada do menu pendente não mostra nenhuma | |
| menubar: teclado | as setas ficavam bloqueadas num menu esbatido; em RTL, esquerda e direita trocadas; Alt+letra de um menu oculto escondia a mesma letra de outro menu; após Alt+letra e uma escolha, o Alt seguinte desligava | os menus esbatidos são saltados; as setas seguem o sentido da escrita; só um menu visível responde à sua letra; o Alt seguinte volta a acender a barra | |
menubar: uma cascata cujas entradas estão todas ocultas; of_count("file"), of_keys_at | escolhia-se como um comando (file/export); os separadores eram contados (__sep0) | esbatida; só as entradas são contadas | |
menubar: of_item("file") — um endereço de um nível | relia o menu, e escrevia numa entrada «file» que não existe | não designa nada: use of_menu("file") | |
Todo o texto lido de um componente ou de um JSON: escapes \b e \f | ficavam escritos tal como estavam | descodificados (retrocesso, avanço de página) | |
| messagebox: uma caixa que não pôde abrir (runtime WebView2 ausente, motor não pronto) | of_show e os atalhos (of_info…) devolviam 0, como um fecho: of_info fazia crer que uma caixa tinha aparecido | -4 (-6 se faltar o runtime), o motivo por of_get_last_error(); of_choose e of_prompt devolvem "" e of_get_last_error di-lo. Um teste = 1 para «confirmado» continua certo | |
messagebox: Esc ou Alt+F4 enquanto um botão de cancelamento ainda está em contagem decrescente (of_add_button_timed) | fechavam a caixa (0) | não fazem nada até ao fim da espera: serve para obrigar a ler | |
| messagebox: o texto da mensagem e da instrução | não se selecionava; premir sobre ele movia a caixa | seleciona-se e copia-se (Ctrl+C copia a seleção, ou a caixa inteira sem seleção); a caixa move-se pelo título, pelo ícone, pelas margens | |
messagebox: uma entrada com mais de cerca de 900 caracteres (of_prompt, ib_input) | voltava vazia, como um cancelamento | volta inteira | |
messagebox: al_hwnd = 0, uma caixa aberta a partir de outra, uma caixa movida e depois aumentada | todo o ambiente de trabalho era desativado; a janela voltava a ficar ativa enquanto a primeira caixa ainda esperava; a caixa voltava ao centro | sem proprietário nada é desativado; a janela continua desativada enquanto uma caixa espera por ela; a caixa mantém o seu lugar | |
progressbar: intervalo vazio ou invertido (id_maximum = 0 e depois id_value = 0) | 0 % qualquer que seja o valor | 100 % assim que o valor atinge o máximo (um lote vazio está terminado), 0 % antes | |
| progressbar: a percentagem apresentada, o anel | arredondada ao mais próximo (99,5 % mostrava «100%»); anel fixo em 128 px; em espera, o anel girava com o arco do valor (vazio a 0: nada se mexia) | arredondada para baixo: 100 % significa terminado; o anel acompanha o tamanho do controlo; em espera gira um arco fixo; se o Windows pedir menos animações, a espera pulsa | |
Qualquer propriedade double relida (id_value…) num computador com vírgula decimal | a parte decimal era mal lida (0,5 não se relia como 0,5) | relida exatamente, qualquer que seja o separador do computador | |
speechout: um novo of_speak (ou of_close) durante uma leitura | a leitura cortada não levantava nenhum ue_stopped | toda a leitura começada termina com um ue_stopped | |
speechout: il_timeout_ms = 0 | cortava a leitura síncrona ao fim de 5 s | sem limite (24 horas no máximo) | |
| speechout: uma voz que não pôde ser criada (runtime WebView2 ausente, página recusada) | of_speak, of_speak_from, of_pause, of_resume, of_enqueue, of_clear_queue devolviam -1, of_open o código bruto da DLL | -2 (componente não criado, como em todo o lado), is_last_error diz porquê; -4 se a página não respondeu | |
speechout: of_speak_sync chamado a partir de um evento levantado durante outro of_speak_sync | cortava a leitura da chamada exterior, que devolvia 0 mesmo assim | recusado: -4, is_last_error = "already speaking synchronously" | |
speechout: of_speak_from para além da última frase | 0, nada era lido | -5 | |
speechout: of_is_speaking() logo após of_speak | false enquanto a lista de vozes não tinha chegado | true desde of_speak | |
speechout: of_pick_voice("", género), ou lista de vozes ilegível | escolhia na língua da página; uma falha esvaziava is_voice | "" = is_lang; uma falha mantém is_voice e preenche is_last_error | |
speechout: of_voice_used, of_duration, of_spoken_text logo após mudar is_lang ou o dicionário | podiam responder com as definições anteriores | respondem com as definições acabadas de pôr | |
| speechout: erro de script na página da voz | silencioso | ue_error("script error: …") | |
statictext: il_back_color com ii_corner_radius | o fundo preenchia todo o retângulo, só o traço do contorno era arredondado | o fundo acompanha o arredondamento; fora dos cantos, a cor do objeto sobre o qual o bloco está, que o userobject também assume | |
statictext: is_marquee_direction com leitura da direita para a esquerda | invertido: MARQUEE_START deslizava para o fim, "left" para a direita | MARQUEE_START desliza para o início da leitura; "left" / "right" continuam físicos | |
statictext: reler il_back_color, ii_marquee_speed, is_marquee_direction, ib_marquee_overflow_only, ib_marquee_pause_on_hover, is_font_family | -1, 0, "", false fosse qual fosse o valor; uma família com espaço entre aspas | o valor atribuído | |
statictext: ii_marquee_speed = 0 | mantinha a velocidade anterior | velocidade predefinida (60) | |
statictext: of_reset depois de um contorno | cor e espessura mantidas: o contorno seguinte herdava-as | apagadas | |
statictext: ib_track_mouse, componente desativado durante a passagem do rato | ue_mouse_leave nunca levantado | ue_mouse_leave levantado à saída | |
statictext: deslizamento (ib_marquee) | um [foldarea] deixava de recolher depois; com ib_marquee_overflow_only, uma mudança de ALTURA recomeçava do início; com ib_wrap = false, um ue_text_overflow(true) errado | corrigido: o texto já não é copiado, só uma LARGURA realmente nova é medida de novo, e o deslizamento mostra todo o texto | |
statictext: ib_hover_effect e ligações sob o rato num tema escuro | escurecidos (contraste reduzido) | clareados | |
Texto rico: [symbol=clock] | mostrado tal como está | um glifo monocromático; um nome desconhecido continua a ser texto | |
statusbar: of_add_panel / of_insert_panel com uma chave ocupada ou que contém / ou uma barra vertical; of_move_panel, of_remove_panel, of_clear_menu, of_add_menu_separator com um painel desconhecido; of_add_menu_item / of_insert_menu_item sob um painel desconhecido ou com uma entrada ocupada; of_remove_menu_item, of_move_menu_item com um endereço desconhecido | 0, ignorado | -5 | |
statusbar: of_insert_panel(…, 0) | acrescentado no fim da barra | em primeiro, como qualquer posição (0 ou menos = em primeiro) | |
statusbar: um separador (of_add_sep) em of_count, of_keys_at e nas posições de of_insert_panel / of_move_panel | contado como um painel de chave vazia | ignorado: uma posição conta painéis | |
statusbar: um separador entre dois painéis ALIGN_END | desenhado no fim do grupo de início | entre os dois: abre o grupo do painel que o segue | |
| statusbar: clique direito num painel não clicável | nenhum evento | ue_panel_rclicked (um painel desativado permanece mudo) | |
statusbar: of_panel(k).ii_progress lido num painel sem barra | 0, como uma barra a 0 % | -1 | |
statusbar: of_menu_item("k"), um endereço de um só nível | escrevia no painel k (ib_enabled acinzentava-o) | não designa nada: não escreve em lado nenhum, relê-se vazio | |
statusbar: cores e dica de um painel após of_clear, e depois um painel acrescentado com a mesma chave | retomados pelo novo painel | esquecidos: o painel começa limpo | |
statusbar: is_state num tema escuro; painel desativado | cores do tema claro, pouco legíveis; acinzentado por transparência, fundo perdido ao passar o rato | uma paleta escura legível; acinzentado pela cor do tema, fundo mantido | |
| statusbar: um painel cujas entradas de lista estão todas ocultas | mão e seta, clique sem efeito | um painel normal, clicável ou não conforme ib_clickable | |
| statusbar, toolbar: setas Esquerda / Direita em leitura da direita para a esquerda (RTL) | ao contrário: Direita ia para a esquerda do ecrã | no sentido do ecrã, como o separador e o friso | |
stepbar: definir ii_current | nada era lançado | ue_step_changed quando a barra se move, como a documentação prometia | |
| stepbar: retirar, inserir ou deslocar uma etapa antes da etapa atual | a etapa atual mudava sem aviso (era uma posição) | a mesma etapa continua atual; se for ela a retirada, a barra passa à seguinte alcançável e lança ue_step_changed | |
stepbar: ii_current definido antes das etapas; of_clear_steps | reposto na primeira etapa; a etapa atual sobrevivia ao esvaziamento | guardado e aplicado assim que a etapa existe; o esvaziamento recomeça na primeira etapa | |
stepbar: of_add_step / of_insert_step com uma chave ocupada ou que contém / ou uma barra vertical; of_move_step, of_remove_step com uma chave desconhecida | 0, ignorado | -5 | |
stepbar: of_insert_step(…, 0) | acrescentado no fim da barra | inserido no início, como toda posição da biblioteca (of_add_step acrescenta no fim) | |
| stepbar: setas esquerda / direita numa língua da direita para a esquerda | a seta direita ia para a etapa seguinte, desenhada à esquerda | invertidas: a seta esquerda vai para a etapa seguinte | |
tab: of_add_page / of_insert_page com uma chave que contém / ou uma barra vertical; um envio falhado | 0; a página ficava alojada e a sua chave ocupada | -5; um envio falhado devolve o seu código, a página volta à sua janela e a chave fica livre | |
tab: of_select_page de uma página oculta, desativada ou além do limite da demonstração | 0, e a página aparecia sob uma barra sem separador ativo | -5, nada se move | |
tab: cruz, atalho (is_shortcut), «Fechar todos / os outros / à direita» num separador desativado ou oculto | o separador ativava-se ou fechava, e o PB libertava a sua página | sem efeito: um separador que não se pode ver nem alcançar não se ativa nem fecha | |
| tab: o separador ativo é fechado, retirado ou ocultado | o seguinte ou o primeiro assumia, mesmo oculto ou desativado; o as_from_key de ue_selection_changed vinha vazio | assume o vizinho selecionável (direita, senão esquerda); as_from_key nomeia o separador realmente abandonado, mesmo desaparecido | |
| tab: nenhum separador visível (todos ocultos, ou uma disposição que os oculta) | a página do antigo separador ficava visível, sem evento | a página é ocultada e é lançado ue_selection_changed(antigo, ""); mostrar de novo um separador seleciona-o | |
tab: um handle mantido após of_remove_page ou um fecho; o seu atalho | ficavam; uma página reaberta com a mesma chave recuperava cor, tooltip e o antigo atalho | libertados: IsValid() devolve false, a página volta nova | |
tab: of_set_layout com um texto que não é JSON | 0, e a mensagem saía partida | -5, nada é enviado | |
| tab: teclado na barra de separadores | Enter perdia o foco; as setas paravam nos separadores desativados ou em excesso; nem Cima/Baixo em barra vertical nem inversão na escrita da direita para a esquerda | o foco fica no separador; as setas seguem o eixo da barra e saltam o que não responde; Delete fecha um separador que se pode fechar | |
| tab: texto de um separador desativado; tooltip de um separador com título truncado | esbatido em bloco (ilegível ao passar o rato em office2007 escuro); o nome completo nativo ocultava o seu tooltip | texto na cor desativada do tema, legível; o seu tooltip tem prioridade | |
tilesbox: of_get_layout | devolvia sempre "": uma disposição guardada nunca era restaurada | a disposição inteira, o mesmo texto que ue_layout_changed; guarda também o tamanho e a visibilidade de cada mosaico e a visibilidade de cada grupo | |
tilesbox: of_set_layout que nomeia um mosaico sob outro grupo que não o seu; um texto que não seja JSON | o primeiro mosaico com essa chave, em qualquer grupo, era deslocado para lá; 0 | um mosaico reencontra-se pelo seu grupo e pela sua chave: a entrada é ignorada; -5 perante um texto que não seja JSON | |
tilesbox: of_add_group com uma chave já tomada; of_add_tile / of_insert_tile com uma chave tomada ou sob um grupo nunca adicionado; uma chave vazia, ou com / ou ` | ` | 0; um grupo adicionado de novo era renomeado, um mosaico sob um grupo desconhecido criava-o com a sua chave | -5, nada é adicionado: adicione primeiro o grupo com of_add_group |
tilesbox: of_move_tile, of_remove_tile, of_add_live_item, of_clear_live_items num mosaico inexistente; of_remove_group num grupo inexistente | 0 | -5 | |
tilesbox: um handle guardado após of_remove_tile, of_remove_group, of_clear, ou um mosaico arrastado para outro grupo | ficava em memória; um mosaico recriado no mesmo endereço retomava as cores e a dica do antigo, um mosaico arrastado perdia-as | o handle é libertado (volte a pedi-lo com of_tile / of_group); cores e dica acompanham o mosaico arrastado e partem com o que é removido | |
statusbar, stepbar, crosstab: um handle guardado após of_remove_panel, of_remove_menu_item, of_clear_menu, of_clear (statusbar), of_remove_step, of_clear_steps (stepbar), of_remove_calc_field ou of_remove_calc_measure (crosstab) | ficava em memória até à destruição do componente | libertado: IsValid() devolve false; volte a pedi-lo com of_panel, of_menu_item, of_step ou of_field | |
Todos os componentes com itens: reler il_back_color_hover / il_text_color_hover de um item nunca colorido | 0, o preto | -1, «a cor do tema», como as outras três cores do item | |
tilesbox: reler ib_enabled / ib_visible de um grupo, ou ii_badge_size | false, false, 0 fosse o que fosse definido | o valor em vigor | |
tilesbox: grupo desativado (ib_enabled = false) | o seu cabeçalho ainda o recolhia (clique, Enter) e lançava ue_group_toggled; um mosaico arrastado podia cair nele | inerte: nem recolher, nem evento, nem largar | |
tilesbox: cores de item (il_back_color, il_text_color, il_accent…) definidas num grupo | sem efeito; a cor de um grupo a podia pintar um mosaico a de outro grupo | pintam o cabeçalho do grupo (fundo, título, passagem do rato, filete de destaque), nunca os seus mosaicos | |
tilesbox: of_tile(""), ou um endereço com um ou três níveis | definir uma propriedade parava a aplicação («Array boundary exceeded») ou escrevia no grupo | um handle inerte: não escreve nada e lê-se vazio | |
| tilesbox: teclado e leitor de ecrã | o foco perdia-se a cada atualização vinda do PB (um emblema) e o menu de tamanho fechava-se; menu de tamanho só com o rato; em RTL, setas ao contrário; rótulos lidos com as suas etiquetas | foco e menu mantidos; menu de tamanho pelo teclado (setas, Enter, Esc); setas no sentido de leitura; texto simples | |
toaster: il_max_visible | predefinição 5, enviada por CADA toaster: um toaster que tinha definido 10 voltava a 5 assim que outro mostrava um toast | predefinição 0 = nada é enviado; o limite é COMUM à aplicação e prevalece o último valor definido (5 enquanto ninguém o definir) | |
toaster: of_show de um toast que espera lugar | devolvia 0: o toast não podia ser fechado por of_close, e os seus eventos traziam um id nunca recebido; fila cheia (200): 0 também, toast perdido sem aviso | um identificador verdadeiro, de imediato; of_close retira-o da fila; fila cheia: -4 | |
toaster: dois toasts sem is_key com um botão da mesma chave | o segundo SUBSTITUÍA o primeiro (a chave do botão era tomada pela do toast) e of_show devolvia o id do primeiro | dois toasts, dois identificadores; só is_key atualiza no lugar | |
| toaster: eventos de vários toasters | arquivados por WINDOW: dois toasters ancorados à mesma window roubavam os eventos um ao outro, e os de um toaster destruído iam para o seguinte | cada toaster recebe os dos SEUS toasts; um toaster destruído já não recebe nada, os seus toasts ficam no ecrã, mudos | |
toaster: pbm_custom02 da window ipo_owner | a window de ancoragem recebia um pbm_custom02 em cada evento de toast, mesmo sem ipo_receiver | só uma window definida em ipo_receiver o recebe; se tinha mapeado pbm_custom02 da sua window para os toasts, defina ipo_receiver, ou melhor, retire esse código: os eventos chegam sozinhos | |
| toaster: apresentação | um toast ficava parado quando a sua window se movia; um toast com mais de 800 px (um longo rasto de erro) NUNCA aparecia; largura não escalada (180 px a 200 %); atualizar um toast sobrevoado reiniciava toda a pilha | segue a sua window; o texto desloca-se dentro do toast limitado; largura à escala do ecrã; a pilha mantém-se em pausa sob o ponteiro | |
toolbar: adições, of_add_separator, of_move_item, of_remove_* com uma chave ocupada, com / ou ` | `, uma barra desconhecida ou um endereço desconhecido | 0, ignorado — um erro de escrita no nome de uma barra criava uma barra fantasma | -5; só main não precisa de of_add_bar |
toolbar: of_clear, of_remove_bar, of_remove_item | os handles ficavam, os atalhos continuavam ativos, e uma ferramenta recriada com a mesma chave recuperava as cores da anterior | handles libertados, atalhos desativados, cores e tooltips esquecidos; volte a pedir um handle depois de uma remoção | |
toolbar: of_item num endereço de três níveis (uma entrada de menu) | agia sobre a FERRAMENTA da barra que tinha o nome da entrada | não designa nada; uma entrada controla-se com of_menu_item(endereço) | |
| toolbar: entrada escolhida num pendente recolhido na seta | ue_menu_selected sem o pai da cascata, sob outro pendente, ou vazio | o endereço completo, como na barra | |
toolbar: ii_index de uma barra | nunca deslocava uma barra para a direita | a barra toma a posição pedida | |
toolbar: of_add_bar(chave, banda, posição) numa posição já ocupada, ou uma banda para lá das outras | ordem indefinida; a banda relia-se tal como dada (5 para a segunda fila) | insere-se antes da barra que ocupava a posição; as bandas cerram fileiras | |
toolbar: of_count, of_keys_at de uma barra, posição de of_move_item | contavam os separadores, com uma chave vazia | só as ferramentas: um separador não tem chave nem posição | |
| toolbar: Enter numa caixa de texto | validava o campo E premia o botão predefinido da janela | valida só o campo; Escape repõe o texto validado | |
toolbar: is_shortcut relido; ii_band / ii_index de uma barra desconhecida | ctrl+s (normalizado); 1 | Ctrl+S, tal como escrito; 0 | |
toolbar: cor ou tooltip definido numa BARRA (of_bar) | sem efeito, ou pintava a ferramenta com o mesmo nome | aplicado à barra, e só a ela | |
| toolbar: atalho de uma ferramenta oculta ou para lá do limite da demonstração | engolia a tecla | a tecla vai para a ferramenta seguinte com o mesmo atalho | |
webbrowser: uma página que não carrega (anfitrião desconhecido, rede, certificado, of_stop) | acionava ue_load_completed, como um sucesso | aciona ue_load_failed(as_url, al_status) em vez disso | |
webbrowser: palavras em is_address («fatura 2026») | saíam como https://fatura 2026 e depois nenhuma navegação acontecia | recusadas com ue_error, o seguinte carrega; uma pesquisa se is_search_url estiver definido | |
webbrowser: um caminho de disco (C:\temp\x.html) ou //anfitrião/x em is_address | precedido de https://, portanto não encontrado | file:///C:/temp/x.html; https://anfitrião/x; javascript: recusado | |
webbrowser: is_address relido após seguir uma ligação ou Anterior | o último endereço definido | a página apresentada | |
webbrowser: of_go_back, of_go_forward, of_stop logo após is_address | podiam passar ANTES do endereço; of_stop deixava recomeçar as páginas em espera | são executados pela ordem escrita; of_stop também abandona as páginas em espera | |
webbrowser: of_save_as_png, of_save_as_jpg, of_print_to_pdf, of_print | capturavam ou imprimiam a barra de endereço | o site apresentado | |
webbrowser: ligação target=_blank, window.open após um clique | nada acontecia | a página abre-se na vista, ue_new_window indica-o | |
webbrowser: resposta de of_execute_javascript com mais de 4.095 caracteres | cortada sem aviso | inteira | |
| webbrowser: F5, Ctrl+R, Ctrl+roda na barra de endereço | recarregavam ou ampliavam a própria barra | sem efeito na barra; ativos no site | |
webbrowser: clique direito num campo de texto com ib_context_menu | Anterior / Seguinte / Recarregar | Cortar / Copiar / Colar | |
webbrowser: Tab ou of_focus_webview sem barra de endereço; ficheiro largado no site com ib_allow_drop | foco perdido numa barra de 0 px; ficheiro aberto pelo navegador | o foco vai para o site, Tab sai dele para a sua janela; ue_drop_files | |
pdfviewer: is_source relido, e as_source de ue_load_completed | o endereço interno /_file/?p=… | o que escreveu (doc\notice.pdf) | |
| pdfviewer: ficheiro ausente, não é um PDF, site inacessível ou que recusa a moldura | ue_load_completed numa página de erro, ou nenhum evento | ue_load_failed(as_source, as_reason) (constantes REASON_*), o visualizador permanece vazio | |
pdfviewer: http://, data: de um tipo diferente de PDF, página web em https:// | apresentados (ou moldura vazia para http://) | recusados: ue_load_failed com REASON_INSECURE ou REASON_NOT_PDF | |
pdfviewer: um # em is_source | cortava o caminho (Orçamento #12.pdf não encontrado); o fragmento de um URL misturava-se com ii_page / ii_zoom | um # faz parte do nome do ficheiro; o fragmento de um URL é ignorado, página e zoom passam pelas propriedades | |
pdfviewer: ii_page definido antes de is_source | perdido: o documento abria na página 1 | conservado para esse documento; sem página definida desde o último is_source, um novo documento abre na página 1 | |
pdfviewer: PDF regenerado no mesmo caminho e depois of_refresh; PDF de 32 MB ou mais; caminho com mais de 260 caracteres | a versão antiga durante 5 minutos; nada; não encontrado | o ficheiro tal como está no disco; apresentado (servido por partes); apresentado | |
pdfviewer: ligação seguida no documento; of_print | o site substituía o documento, sem retorno; imprimia a página que enquadra o documento | o documento permanece, ue_link_clicked(as_url) dá-lhe o endereço; of_print imprime o documento (-4 sem documento) | |
picture, button, tilesbox: il_badge_color | 0 = a cor do tema; o preto era inatingível; não definido, relia-se 0 | -1 = não definido (a cor do tema), como qualquer outra cor; 0 é o preto. Substitua il_badge_color = 0 por -1 | |
picture: id_zoom definido antes de ib_zoomable | relia-se como definido, enquanto a imagem ficava enquadrada | ignorado: id_zoom fica em 1.0 enquanto ib_zoomable for falso; defina primeiro ib_zoomable | |
picture: ib_mirror numa imagem rodada um quarto de volta; is_align / is_valign com uma rotação | inversão vertical no ecrã; o posicionamento rodava com a imagem | espelho e posicionamento leem-se no ecrã, seja qual for a rotação | |
| picture: arrastar a imagem ampliada; roda; imagem desativada (statictext desativado também) | ue_clicked a cada deslocação; zoom para o centro, a imagem podia sair da moldura; os ficheiros largados continuavam aceites | nenhum clique após uma deslocação; zoom para o ponteiro, a imagem cobre sempre a moldura; desativada, recusa qualquer largada; ue_error indica a origem | |
xml: uma leitura (of_get_value, of_count, of_is_valid…) ou uma alteração depois de uma construção | agia sobre o último documento CARREGADO, ou sobre nada | o documento construído é carregado e torna-se O documento; o of_start_element seguinte começa um novo | |
xml: of_load falhado (vazio, malformado), of_start_element depois de um carregamento | o documento anterior continuava legível e alterável (of_is_valid verdadeiro); um documento construído a meio ficava em of_xml | nada fica | |
xml: of_xml, of_pretty, of_get_values de um documento grande | cortado sem aviso para lá de alguns MB | inteiro | |
xml: of_get_value de um XPath de valor (count(//line), sum(//@qty)) | vazio | o valor como texto (3, true) | |
| xml: um XPath cujo prefixo é declarado abaixo da raiz (resposta SOAP) | vazio sem of_register_namespace | resolvido | |
xml: is_last_error depois de um XPath inválido, de uma página que não responde, de uma recusa; códigos de of_register_namespace / of_clear_namespaces | vazio, ou «no node matched» fosse qual fosse a causa; as alterações devolviam -4 quando faltava a página; sempre 0; uma página sem resposta devolvia o texto null | a verdadeira razão; -2 quando a página não responde; um URI vazio é recusado (-5); vazio em vez de null | |
xml: of_pretty | perdia CDATA, comentários, instruções de processamento e a declaração XML, e alterava o texto misto | tudo é mantido; um elemento que contém texto fica numa linha | |
| xml: construção — quebra de linha ou tabulação num atributo, CR num texto, carácter de controlo, nome inválido | relidos alterados; documento malformado; nome escrito tal como está | relidos idênticos; carácter de controlo retirado; nome recusado (is_last_error), o elemento fica de fora | |
xml: um documento que contém um elemento <parsererror>; mensagem de um XML malformado | recusado como malformado; mensagem enquadrada por «This page contains the following errors» | carregado; só a linha de erro | |
xml: of_remove de nós aninhados, da raiz, de um atributo; of_set_value("/"); of_add_child sob um atributo | contava duas vezes; esvaziava o documento; o atributo ficava; 0 sem efeito; «parent not found» | a contagem real; a raiz fica (0 e is_last_error); o atributo é retirado; -4; «the node cannot have children» | |
xml: of_close e depois uma leitura; ipo_owner definido depois da primeira leitura | o documento carregado perdia-se; ignorado até of_close | o documento é mantido e recarregado; transmitido na leitura seguinte | |
temas metro-light e metro-dark: texto sobre a cor de destaque | branco sobre o azul #25a0da nos dois temas (cabeçalhos de painel, separador ativo, botão da aplicação do friso, mosaicos): pouco legível | metro-light: a cor de destaque passa ao azul mais profundo #1b76a1, texto sempre branco; metro-dark: a cor de destaque mantém-se #25a0da, o texto por cima passa a quase preto (#1b1b1b) | |
temas office-dark, office2003-dark, office2003-light, office2007-light: cores de destaque e de cabeçalho | no modo escuro, a cor de destaque lia-se mal na página (marcador de passo, emblema), tal como o texto branco sobre o destaque sob o rato e sobre os cabeçalhos de coluna do crosstab; no modo claro, o topo dos degradês do botão da aplicação e dos cabeçalhos de painel era demasiado pálido para texto branco | office-dark: destaque #1178d1, sob o rato #0f6cbd; office2003-dark: destaque #4574cb, sob o rato #2f5aa8; cabeçalhos do crosstab mais escuros sob o rato e nos totais; office2003-light e office2007-light: início do degradê mais profundo (#3e73cf, #4275c5), cabeçalhos de painel de office2007-light mais opacos. Texto sempre branco, pelo menos 4,5:1 | |
texto sobre uma cor escolhida pela aplicação (il_accent, cor de um item, cabeçalho de painel, emblema) | branco até uma cor bastante clara: um azul médio como #25a0da recebia texto branco a 2,95:1 | branco ou quase preto (#1b1b1b), o que se ler melhor (relação de contraste WCAG): #25a0da recebe agora texto escuro | |
jsontree: of_clear | esvaziava a árvore E repunha ib_wrap e ib_search_enabled nos seus valores por omissão | esvazia só a árvore; as definições ficam (é of_reset que repõe tudo) | |
jsontree: is_json = "" | levantava ue_error «Invalid JSON» | esvazia a árvore sem erro, como a documentação prometia | |
jsontree: números e chaves mostrados, is_json relido | reescritos pelo motor: 12345678901234567890 mostrado 12345678901234567000, 1.10 → 1.1, a primeira de duas chaves idênticas perdida; is_json relia-se compactado, e vazio depois de um JSON inválido | tal como recebidos, as duas chaves incluídas; is_json relê-se exatamente como foi definido | |
jsontree: of_match_count, al_count de ue_search_result | contavam LINHAS; duas ocorrências numa linha eram ambas «atuais» | contam OCORRÊNCIAS, só uma é atual e of_search_next passa de uma à outra | |
| jsontree: blocos abertos por uma pesquisa | TODOS os que continham uma correspondência, de vez: pesquisar «e» abria o documento inteiro | só os que escondem a ocorrência ATUAL; of_clear_search devolve as dobras de antes da pesquisa | |
jsontree: of_select_path | uma linha escondida num bloco dobrado ficava invisível; um caminho desconhecido devolvia 0 | os blocos que a escondem abrem-se; um caminho desconhecido devolve -5 e a seleção não se move | |
| jsontree: dobrar o bloco que contém a seleção | a seleção ficava invisível, e a seta seguinte recomeçava do topo | a seleção passa para o bloco dobrado; num gesto do utilizador, ue_selection_changed di-lo | |
xmltree: of_clear | esvaziava a árvore E repunha ib_wrap e ib_search_enabled nos valores predefinidos | só esvazia a árvore; as definições ficam (é of_reset que repõe tudo) | |
xmltree: is_xml = "" | levantava ue_error «Invalid XML» e mostrava um erro vermelho | esvazia a árvore sem erro, como a documentação prometia | |
xmltree: is_xml relu | reserializado pelo motor: aspas alteradas, quebras de linha perdidas, vazio depois de um XML inválido | relê-se tal como foi definido, mesmo um texto inválido | |
| xmltree: ce qui s'affiche | um CDATA era invisível (o elemento aparecia vazio), faltavam comentários, instruções de processamento e declaração, o texto de um conteúdo misto era colado antes dos filhos, um texto perdia os seus espaços, um valor de atributo com aspas era mostrado tal qual | cada nó no seu lugar, pela ordem do documento; a linha continua a ser XML (aspa escolhida ou ", , &, <); os espaços significativos ficam | |
xmltree: of_match_count, al_count de ue_search_result | contavam LINHAS; uma correspondência entre dois pedaços (id="4152") era contada sem ser realçada | contam OCORRÊNCIAS, cada uma realçada, só uma é a atual | |
| xmltree: éléments ouverts par une recherche | TODOS os que continham uma correspondência, de vez | só os que escondem a ocorrência ATUAL; of_clear_search devolve as dobras de antes da pesquisa | |
xmltree: of_select_path | uma linha escondida num elemento dobrado ficava invisível; um caminho desconhecido devolvia 0 | os elementos que a escondem abrem-se; um caminho desconhecido devolve -5 e a seleção não se move | |
xmltree: ue_selection_changed | levantado também sem alteração (Fim na última linha); dobrar o elemento que continha a seleção tornava-a invisível, em silêncio | levantado só quando a seleção muda; ao dobrar, a seleção passa para o elemento dobrado e o evento di-lo | |
xmltree: ue_error | o texto bruto da página de erro do motor; um elemento <parsererror> do documento passava por um erro | só a linha do erro («error on line N at column M: …»); um <parsererror> do documento é um elemento como outro qualquer | |
| restclient: cookies de um pedido síncrono | nenhum guardado: cada of_get / of_post abria a sua própria sessão; ib_keep_cookies só valia para o assíncrono | uma sessão por objeto, comum ao síncrono e ao assíncrono: um início de sessão síncrono mantém-no ligado para as chamadas seguintes | |
restclient: ib_keep_cookies alterado após o primeiro pedido | sem efeito até of_close | aplicado de imediato; a false, os cookies já guardados são esquecidos | |
| restclient: redirecionamento para outro anfitrião ou porta | só caíam Authorization, Cookie e a autenticação Basic: uma chave de API (X-Api-Key…) ia para o terceiro | nenhum cabeçalho definido com of_set_header segue, só fica Content-Type | |
restclient: of_set_bearer("") após of_set_basic; of_set_basic e depois of_set_bearer; of_set_basic("", "") | a palavra-passe Basic continuava a partir; dois Authorization ao mesmo tempo; Basic Og== enviado | uma só autenticação de cada vez: cada uma substitui a outra, um token ou utilizador vazio retira-a | |
restclient: HEAD, ou resposta 204 / 304 que anuncia um tamanho | -4 «connection lost», e repetida em assíncrono | o estado (200, 304…) | |
restclient: corpo com um byte inválido; charset=iso-8859-1 ou utf-16 | todo o corpo relido em Windows-1252; charset ignorado | só o byte inválido se torna um carácter de substituição; o charset anunciado é lido | |
| restclient: corpo de texto de várias centenas de MB | guardado três vezes em memória: um processo de 32 bits podia morrer | -4 «body too large : use of_download» acima de 64 MB | |
| restclient: cem pedidos assíncronos lançados de uma vez | cem fios em paralelo | seis no máximo ao mesmo tempo, os seguintes esperam a sua vez | |
| restclient: um pedido assíncrono enviado mais vezes do que a cada 50 ms (um temporizador de telemetria) | nenhuma resposta entregue enquanto o fluxo durava | as respostas chegam à medida que vêm | |
restclient: of_cancel de um id desconhecido; de um pedido cuja resposta chegou | -1; 0 (mas era ue_response que chegava) | -5; -4, tarde demais | |
restclient: of_response_text() após of_download; após um of_download(url, "") | o número de bytes escritos; a resposta anterior | vazio: esse corpo está no ficheiro; vazio | |
restclient: ler uma resposta assíncrona durante ue_progress | uma memória em escrita: falha possível | vazio, of_status(id) = 0 enquanto o pedido decorre | |
video: mudar de filme (is_source, of_play(source)) | o segmento, as legendas, marcadores e capítulos do filme anterior ficavam | partem com ele (definidos antes de qualquer filme, esperam pelo primeiro); um filme da lista guarda as suas legendas. Defina-os depois de is_source | |
video: of_go_chapter, of_next_chapter, of_previous_chapter | levantavam ue_seeked; of_go_chapter além do número de capítulos devolvia 0 sem fazer nada | ue_seeked e ue_chapter_changed, como um clique na barra; -5 | |
video: of_add_source com um is_source definido | a lista nunca arrancava, of_next ia para o primeiro filme | a primeira entrada carrega logo (exceto se o filme definido estiver A TOCAR: a lista segue-o no fim) | |
video: ue_started após of_stop ou o fim do filme, depois of_play | nunca: uma vez por fonte | a cada nova reprodução (não ao retomar uma pausa) | |
video: of_play num filme em erro; of_reset; ii_rate no filme seguinte | «a tocar» para sempre, sem evento; o filme anterior ficava carregado (of_duration, of_capture); regresso à velocidade normal | ue_failed de novo; o filme é descarregado; a velocidade mantém-se | |
video: of_capture para um ficheiro que não se pode escrever; para «\x» ou «C:x» | -4 (a doc dizia -5); escritos conforme a pasta atual | -4, e não fica nenhum ficheiro truncado; -5: dê um caminho completo | |
| video: ecrã inteiro e depois Alt+Tab para outra aplicação | o filme ficava acima de tudo | a outra aplicação passa à frente; voltar à sua põe de novo o filme acima de tudo | |
| pdfviewer: um clique simples numa ligação do PDF | nada: só Ctrl+clique levantava ue_link_clicked | ue_link_clicked(url), o documento continua visível | |
webbrowser: uma página data: (is_address = "data:text/html,…") | mostrada, mas nenhum ue_load_completed | ue_load_completed com o endereço pedido | |
webbrowser: uma nova janela pedida pelo site para file:, data: ou mailto: | aberta na vista, ue_new_window lançado | recusada: ue_error, sem ue_new_window; só se abrem http e https | |
| webbrowser: um site que pede a câmara, o microfone, a localização, as notificações | aviso do navegador ao utilizador, resposta memorizada | recusado a menos que ue_permission_requested devolva true; nada é memorizado | |
| webbrowser: cookies, sessões e armazenamento dos sites | no perfil partilhado com os componentes | num perfil de navegação próprio: uma sessão iniciada na 3.0 não é retomada (voltar a entrar uma vez); of_clear_browsing_data apaga-a | |
webbrowser: is_search_url sem %s, sem http(s):// ou em javascript: | aceite: cada pesquisa falhava ou perdia o texto escrito | recusado: ue_error, o motor em vigor mantém-se | |
webbrowser: gestion/ ou [::1]/x em is_address | «não é um endereço» (ou uma pesquisa) | https://gestion/, https://[::1]/x; a palavra sozinha continua a ser texto | |
webbrowser: clique direito sobre uma seleção, um link, uma imagem com ib_context_menu | só Anterior / Seguinte / Recarregar | além disso: Copiar, Abrir link, Copiar endereço do link, Copiar imagem | |
tab: separador fechável desativado (ib_enabled = false) | a cruz desaparecia mas o seu espaço ficava vazio | nem cruz nem espaço vazio: o separador tem a largura de um não fechável | |
video: of_chapters num título que contém ` | ` ou uma tabulação | partido em dois capítulos | lido tal como é |
video: um .srt em Windows-1252 ou UTF-16 | acentos ilegíveis; nenhuma legenda | lido corretamente | |
commandpalette: of_open sem runtime WebView2; toaster: of_show sem runtime | -1 | -6, como a caixa de mensagem | |
crypto, xml, restclient: of_open quando a página ou o cliente não pode ser criado | o código bruto da DLL (-1, -3…) | -2, e is_last_error diz porquê |
Se tinha contornado algum destes defeitos — por exemplo tratando ue_menu_selected com um endereço vazio para apanhar os cliques de um grupo recolhido —, retire o contorno: o evento documentado passa a chegar.
11.4 O gerador n_pbt_menu2ribbon #
Na 3.0, o código escrito por n_pbt_menu2ribbon usava métodos de handle que já não existiam: não compilava sem retoques. Na 4.0 escreve a API atual — cada adição pelo seu endereço, a partir do componente —, retoma os submenus a qualquer profundidade, mantém os itens desativados e marcados, e o seu encaminhador cobre ue_clicked, ue_toggled e ue_menu_selected. As chaves mudam: cada uma passa a ser o ClassName do item de menu (m_fichier/g1/m_ouvrir) em vez do caminho com pontos (m_principal.m_fichier.m_ouvrir).
A receita: um friso já construído à mão, ou a partir de código gerado e depois corrigido, não tem nada a mudar. Para recomeçar a partir do gerador, volte a executá-lo e cole também o novo encaminhador: o antigo lia chaves com pontos.
11.5 O que foi acrescentado #
Nada do que se segue pede para alterar o seu código. Os novos componentes da 4.0 são apresentados nas notas de versão.
| Objeto | Acrescentado |
|---|---|
| ribbon | of_add_menu_separator aceita o endereço de uma entrada: a linha vai para a cascata por baixo dela |
| ribbon | of_add_menu_item e of_add_menu_check aceitam uma cascata de qualquer profundidade, e cada nível é comandado por of_menu_item(endereço) |
| menubar | of_add_separator aceita o endereço de uma entrada (file/export): a linha vai para a sua cascata; of_menu(...) leva as cores (il_accent, il_back_color…) e a dica do título |
| crosstab | of_set_label_filter(as_field, as_type, as_a, as_b) sobre texto (LABEL_CONTAINS, LABEL_BEGINS, LABEL_ENDS) e as constantes LABEL_GT, LABEL_LT, LABEL_BETWEEN: a forma com dois double só podia passar um número |
| crypto | KEYFORMAT_TEXT, KEYFORMAT_HEX, KEYFORMAT_BASE64 e uma sobrecarga de of_hmac, of_jwt_sign e of_jwt_verify que os aceita (uma chave em BYTES: segredo fornecido codificado, AWS SigV4); uma entropia opcional para of_protect e of_unprotect |
| crypto | of_hmac_verify (um HMAC recebido — webhook — comparado em tempo constante); of_jwt_header e uma sobrecarga de of_jwt_sign que acrescenta membros ao cabeçalho (kid); of_totp_verify(…, ref al_step), o passo aceite, para recusar um código já usado; il_password_hash_rounds |
| messagebox | of_get_last_error(): porque é que a última caixa não pôde abrir (cadeia vazia se abriu) |
| n_pbt_utils | of_dir_has_subfolders(as_dir, ab_include_hidden): a mesma pergunta, contando também as pastas escondidas, de sistema e as junções |
| n_pbt_utils | of_dw_date_order(): a ordem pela qual um DataWindow escreve uma data neste posto (dmy, mdy, ymd) |
| speechout | of_is_paused(): verdadeiro enquanto a leitura está em pausa |
| Texto rico | a etiqueta [symbol=nome]: dezoito glifos monocromáticos que seguem a cor do texto (capítulo 4) |
| toolbar | of_menu_item(endereço) → n_pbt_toolbar_menu_item: cada entrada de menu pendente tem o seu estado (ib_enabled, ib_visible, ib_checked, is_text, is_shortcut), designada pelo seu endereço completo |
| toolbar | is_date num seletor de data; of_clear_menu; of_remove_item de uma entrada de menu; of_add_menu_separator numa entrada (cascata); cascatas de qualquer profundidade |
| pdfviewer | ue_load_failed(as_source, as_reason) e as constantes REASON_*; ue_link_clicked(as_url); os endereços file:///; ib_allow_save e ib_allow_print: os comandos Guardar e Imprimir da barra do leitor |
| picture | is_alt_text (texto alternativo lido por um leitor de ecrã); um teclado para o zoom: +, -, 0 e as setas para se deslocar; n_pbt_utils.of_json_get_str_array |
| webbrowser | is_search_url (motor de pesquisa para palavras que não são um endereço); ib_veto_new_window e ue_new_window; ib_veto_downloads e ue_download_starting; ue_load_failed; ue_error; of_show_html; of_clear_browsing_data e ib_private; ib_veto_navigation e ue_navigating; is_title e ue_title_changed; ue_permission_requested e as constantes PERMISSION_*; as constantes LOADSTATUS_* de ue_load_failed; F5, Ctrl+R, Alt+setas e Esc na barra de endereço |
| jsontree | of_selected_text devolve o valor DESCODIFICADO da folha selecionada (uma cadeia sem aspas nem escapes); of_has_selection distingue a raiz, cujo caminho é "", de «nada selecionado»; o teclado salta as chavetas de fecho (já não são selecionadas) |
| xmltree | cada atributo é um alvo: um clique dá o seu caminho (/order/@id), of_select_path seleciona-o, of_selected_value devolve o seu valor; um documento grande só desenha as linhas no ecrã (8 000 elementos irmãos: 12 s → 0,15 s, uma seta em poucos ms) |
| video | ue_muted_changed(ab_on): o utilizador cortou ou repôs o som (o altifalante da barra, a tecla M), como o volume e a velocidade já tinham o seu evento |
| ribbon | of_remove_menu_item, of_clear_menu, of_remove_combo_item, of_clear_combo, of_remove_gallery_item, of_remove_app_menu_item, of_remove_contextual_group: as remoções sob um controlo — uma lista «Ficheiros recentes» atualiza-se sem recriar o controlo |
| ribbon | of_app_menu_item(endereço): o handle de uma entrada do menu da aplicação (is_label, is_image, ib_enabled, ib_checked, ib_visible); of_app_menu_item("") percorre o menu |
| ribbon | teclas de acesso rápido de várias letras (is_keytip = "FP"), escritas uma após a outra; nomes acessíveis (barra de acesso rápido, mosaicos) para leitores de ecrã |
| toolbar | of_add_split_button: um botão dividido (ação + menu); is_group: alternadores exclusivos (alinhamento); is_image numa ferramenta e numa entrada de menu; ue_item_rclicked(endereço): o clique direito numa ferramenta |
11.6 Nomes e contagens alinhados com o resto da biblioteca #
Sete sítios falavam de maneira diferente do resto da biblioteca. A 4.0 alinha-os em vez de manter a diferença: dois nomes mudam — o compilador mostra-lhe cada linha a retocar —, o caminho devolvido pela árvore JSON passa a ser o de n_pbt_json, o da árvore XML sob um espaço de nomes predefinido um XPath que funciona, duas contagens passam a começar em 1, como toda a posição do produto, e um evento ambiente passa a ser opcional. São as únicas alterações da 4.0 que pedem para retocar código que compilava.
| O quê | 3.0 | 4.0 |
|---|---|---|
| progressbar: limites da escala | il_minimum, il_maximum, long | id_minimum, id_maximum, double: uma escala 0..1 ou um número de bytes acima de 2 GB é válido; o prefixo diz o tipo |
| json: índice de array num caminho | a partir de 0: lines/0 é a primeira linha | a partir de 1: lines/1 é a primeira linha; lines/0 não designa nada — uma leitura dá-o como ausente, uma escrita devolve -5 |
jsontree: caminho de um nó (ue_node_clicked, ue_selection_changed, of_selected_path, of_select_path) | níveis unidos por um ponto, índice de array a partir de 0: lines.0.sku — um dialeto que n_pbt_json não lia | o caminho de n_pbt_json: níveis unidos por /, índice a partir de 1 (lines/1/sku), "" para a raiz — para passar tal como está a of_get_string sobre o mesmo texto |
xmltree: caminho de um elemento sob um espaço de nomes PREDEFINIDO (xmlns="urn:…") | /Envelope/Body — um XPath que não encontra nada | /*[local-name()='Envelope']/*[local-name()='Body'] — para passar tal como está a n_pbt_xml.of_get_value; um elemento sem espaço de nomes ou com prefixo mantém o seu caminho |
toolbar: band e index da disposição (of_get_layout, of_set_layout, ue_layout_changed) | a partir de 0, uma cadeia dita «opaca» enquanto ii_band, ii_index e ue_bar_reordered contavam a partir de 1 | a partir de 1, como ii_band, ii_index e ue_bar_reordered; uma ida e volta leitura → restauro devolve a mesma cadeia |
statictext: ue_cycle | levantado em cada ciclo do deslizamento, sem subscrição — e também por uma animação dentro do texto | um evento ambiente, logo opcional: levantado só quando ib_track_cycle = true, como ue_mouse_enter com ib_track_mouse; só a cada passagem completa do texto |
tilesbox: 2.º argumento de ue_tile_moved | as_to_keys, embora transporte UMA chave: o grupo de destino | as_to_key: o nome diz o que transporta, como em todo o lado (as_key = um nível, as_keys = um endereço) |
restclient: ue_failed | ue_failed (long al_id, string as_error) | ue_failed (long al_id, long al_code, string as_error): -4 falha, -5 URL ou ficheiro — já não é preciso analisar o texto |
restclient: of_json_value | uma chave, primeira ocorrência a qualquer profundidade; só um valor de texto — um número devolvia o nome da chave seguinte | um caminho n_pbt_json ("json/customer", "items/1/qty"), qualquer valor: "4152", "true". Uma chave aninhada nomeia-se com os seus pais |
A receita: (1) recompile — o compilador assinala il_minimum, il_maximum e as_to_keys: renomeie-os id_minimum, id_maximum e as_to_key; (2) procure os caminhos json que apontam para um array e some 1 a cada índice — um ciclo for i = 0 to n - 1 sobre "lines/" + String(i) passa a for i = 1 to n; (3) uma disposição de toolbar guardada pela 3.0 conta a partir de 0: some 1 a band e a index de cada barra antes de a passar a of_set_layout, ou deixe o utilizador reorganizar uma vez — relida tal como está, juntaria as suas duas primeiras bandas; (4) onde ue_cycle estiver programado, defina ib_track_cycle = true na construção; (5) onde lia um caminho da árvore JSON (ue_node_clicked, of_selected_path) ou dava um (of_select_path), substitua os pontos por / e some 1 a cada índice de array — lines.0.sku passa a lines/1/sku, que vai tal como está para n_pbt_json.of_get_string.
11.7 Os temas seguem a aplicação #
A revisão dos temas fez cada componente cumprir a regra que o capítulo 4 já anunciava: a aplicação decide o tema e o destaque, um componente só se afasta deles naquilo que lhe é pedido. Nenhum método é renomeado; o que muda vê-se no ecrã, ao reler as propriedades e em dois códigos de retorno.
| O quê | 3.0 | 4.0 |
|---|---|---|
PBT_SetDefaultTheme | mudar de tema apagava o destaque definido por PBT_SetDefaultThemeAccent — mesmo ao voltar a definir o mesmo tema — e achatava o fundo em gradiente de office2007 e office2003 | o destaque da aplicação mantém-se de um tema para o outro; cada tema mantém o seu fundo |
PBT_GetDefaultThemeAccent | o destaque do tema quando a aplicação não tinha definido nenhum | -1 enquanto a aplicação não tiver definido um destaque |
| códigos de retorno nativos | PBT_SetDefaultTheme com um nome desconhecido devolvia 0 e deixava sem tema os componentes seguintes; PBT_SetDefaultThemeAccent com uma cor de sistema do PowerBuilder pintava-a de preto | -5 nos dois casos; o tema ou o destaque anterior mantém-se |
| um eixo de tema definido sozinho | congelava o outro eixo no tema da aplicação do momento | o eixo vazio segue o tema da aplicação a cada mudança dele; os dois eixos vazios = o tema da aplicação, por inteiro |
is_theme_style · is_theme_mode · il_theme_accent | reliam-se "", "" e -1, fosse o que fosse definido | o estilo e o modo mostrados, e o destaque próprio do componente (-1 se não tiver) |
um valor de eixo desconhecido ("office2010") ou mal escrito (" Metro ") | o componente perdia o seu tema e deixava de ouvir o da aplicação até ao of_reset() | espaços e maiúsculas ignorados; um valor desconhecido é ignorado e o eixo mantém o seu valor |
| destaque de um componente com tema local | mantinha o destaque do seu tema, mesmo quando a aplicação definia um | segue o destaque da aplicação enquanto não tiver o seu |
| um destaque personalizado | só o destaque mudava: passagem e clique dos botões de destaque, seleções tingidas, botões marcados do friso mantinham o destaque do tema | tudo o que deriva do destaque o segue |
tilesbox : il_badge_color | 0 e -1 = a cor do tema; relido 0 sem cor definida; o preto era inatingível | -1 = a cor do tema (relido -1); 0 é o preto, como em todas as cores |
uma cor de sistema do PowerBuilder (ButtonFace…) em il_theme_accent | pintada de preto | contada como -1: o destaque da aplicação |
webbrowser · pdfviewer | o conteúdo de terceiros seguia o modo claro/escuro do Windows, e um retângulo branco precedia a sua primeira apresentação | segue o tema predefinido da aplicação, sobre o fundo do tema (4.11) |
| acento de office-dark e office2003-dark | um azul escuro, legível a 3:1 quando coloria um texto (ligações, [accent]) | um azul mais claro (#479ef5, #7ea1e8), com um texto escuro por cima |
datagrid: linhas entre as linhas | ausentes em oito temas de dez | presentes nos dez temas, na cor da grelha do tema |
| alto contraste do Windows | os ícones monocromáticos e os anéis desenhados como sombra desapareciam | suportado (4.10) |
A receita: (1) se voltava a definir o destaque depois de cada PBT_SetDefaultTheme, já não é necessário — e se contava com uma mudança de tema para apagar o destaque, chame PBT_SetDefaultThemeAccent(-1); (2) teste o código de retorno de PBT_SetDefaultTheme quando o nome vem de uma entrada ou de um ficheiro; (3) onde definia os dois eixos em cada componente para seguir a aplicação, deixe-os vazios; (4) um mosaico cujo emblema voltava «ao tema» com il_badge_color = 0 escreve-se agora -1.
11.8 crypto: o que a segurança agora recusa, e para onde vão os caminhos relativos #
A revisão de segurança de crypto fecha uma porta real — um JWT forjado com a chave PÚBLICA passava quando faltava o algoritmo — e substitui vários silêncios por uma recusa que diz a sua razão. Nenhum método é retirado; uma assinatura ECDSA muda de forma, e os caminhos relativos dos ficheiros seguem uma só regra.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_jwt_verify, of_jwt_sign | um algoritmo VAZIO valia JWT_HS256, e uma chave PEM era aceite como segredo HS256: verificado com a chave PÚBLICA como segredo, um token forjado passava; o algoritmo do cabeçalho comparava-se sem maiúsculas, um cabeçalho crit era ignorado | o algoritmo é OBRIGATÓRIO e comparado EXATAMENTE; uma chave PEM nunca é um segredo HMAC (of_hmac também); crit é recusado — cadeia vazia e is_last_error |
of_jwt_sign | um exp dado nos claims era substituído em silêncio pela duração al_expires_seconds | ambos ao mesmo tempo são recusados: fique com um ou outro |
of_encrypt, of_decrypt | uma palavra-passe VAZIA cifrava — qualquer um relia o valor | recusada, como of_encrypt_file já fazia; of_password_hash("") continua permitido |
il_pbkdf2_rounds | um valor fora de 1.000 a 10.000.000 voltava em silêncio a 100.000 | a chamada é RECUSADA: cadeia vazia para um texto, -5 para um ficheiro, e is_last_error diz os limites |
of_password_hash | il_pbkdf2_rounds (100.000 rondas) | il_password_hash_rounds, 600.000 por omissão (o número da OWASP); os valores já guardados levam as suas rondas e continuam a verificar-se |
of_base64_decode, of_base64url_decode, of_hex_decode, of_decrypt… | bytes que não são um texto (um PDF, uma imagem) voltavam como caracteres de substituição, sem erro | cadeia vazia e is_last_error, que remete para of_base64_decode_to_file ou of_decrypt_file |
of_sign (chave EC) | uma assinatura IEEE-P1363 (64 bytes), que o openssl dgst e o Java recusam | uma assinatura DER; of_verify lê as duas formas, uma assinatura já guardada continua a verificar-se; o JWT ES256 continua em P1363 |
of_totp_code, of_totp_verify | um carácter não base32 no segredo (um 0 digitado por um O) era retirado em silêncio: OUTRO segredo, códigos que nunca coincidiam | recusado (espaços e = tolerados) |
of_encrypt_file | «qualquer que seja o tamanho» | até 64 GB, o limite de um contentor AES-GCM: além disso, -7 |
caminhos relativos: n_pbt_crypto, u_pbt_zip, of_capture do leitor de vídeo | lidos na pasta ATUAL (que muda após um DirList ou uma caixa de ficheiros), escritos ao lado do EXE (no IDE: a pasta do PowerBuilder) | LIDOS na pasta atual, depois na pasta em que a aplicação arrancou, depois ao lado do EXE; ESCRITOS na pasta em que a aplicação arrancou — a mesma no IDE e compilada |
A receita: (1) passe SEMPRE o algoritmo de um JWT como constante (n_pbt_crypto.JWT_RS256), nunca lido do token nem de um INI a que possa faltar; (2) se um servidor verificava as suas assinaturas EC em P1363 (.NET VerifyData por omissão), converta-as ou verifique-as em DER (DSASignatureFormat.Rfc3279DerSequence); (3) um il_pbkdf2_rounds definido fora dos limites tem de voltar para entre 1.000 e 10.000.000; (4) um ficheiro que um caminho relativo escrevia ao lado do EXE está agora na pasta de arranque da aplicação — dê um caminho completo se quiser outro.
11.9 restclient: cabeçalhos que dizem a sua recusa, redirecionamentos que mantêm o pedido #
A revisão de restclient substitui duas perdas silenciosas — uma alteração nunca feita atrás de um redirecionamento, uma autenticação nunca enviada atrás de um cabeçalho mal formado — pelo comportamento certo ou por uma recusa que diz a sua razão. Nenhum método é retirado; três passam a funções, chegam duas propriedades, e a autenticação Windows só parte se a pedir. Um ponto vale para os cinco componentes não visuais que lançam eventos: um erro no seu código de evento passa a ver-se.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_set_header, of_set_bearer, of_set_basic | sub-rotinas: nada era devolvido, um valor mal formado era guardado tal como estava | funções long: 0, ou -5 e nada muda — nome vazio, nome com um espaço, dois pontos ou um carácter de controlo, valor com uma quebra de linha; um valor vazio retira o cabeçalho |
| um pedido com um cabeçalho mal formado | partia SEM NENHUM cabeçalho — Authorization incluído —, sem erro | -5, e is_last_error = «invalid header: <nome>»; nada parte |
| redirecionamento 301 / 302 de um PUT, PATCH ou DELETE | seguia em GET sem corpo: a alteração nunca era feita, e a chamada devolvia 200 | método e corpo mantidos; só um POST passa a GET; um 303 segue em GET sem corpo (exceto HEAD) |
| uma ligação reutilizada (a de um redirecionamento) que o servidor fecha no mesmo instante | -4 e «request failed: 12152», de vez em quando | o pedido é reenviado UMA vez, corpo incluído, numa ligação nova: o servidor não tinha respondido nada |
of_response_text ( ), of_response_headers ( ), of_response_header, of_json_value | a última resposta síncrona do PROCESSO: um segundo n_pbt_restclient substituía-a | a do OBJETO; of_close esquece-a |
| corpo lido como texto, aplicação de 32 bits | limitado a 64 MB | limitado a 16 MB (64 MB em 64 bits): além disso, -4 «body too large» — leia-o com of_download |
of_get_async, of_request_async… com um URL ou um cabeçalho inválido | um id de pedido, depois um ue_failed | -5 de imediato, nenhum evento se segue; is_last_error diz porquê («invalid URL: …») |
| autenticação Windows (Negotiate / NTLM) | o sistema respondia sozinho ao desafio de um servidor da intranet com as credenciais da sessão | desativada por predefinição: as credenciais não vão para nenhum servidor sem ib_windows_auth = true (propriedade nova); is_client_certificate (nova) define um certificado de cliente |
of_cancel (long al_id), of_status (long al_id), of_response_text (long al_id)… | o id de um pedido de OUTRO objeto atingia esse pedido | só os pedidos do objeto: of_cancel devolve -5 e não cancela nada, os leitores devolvem 0 / "" |
of_status (long al_id) em ue_failed | podia devolver 200: o estado de uma resposta recebida e depois perdida | 0 para qualquer pedido falhado |
ue_failed | -4 falha, -5 URL ou ficheiro | -4 falha, -5 ficheiro ou certificado de cliente, -6 pedido de intervalo recusado em demo |
erro de execução num evento da aplicação — restclient, speechout, soundplayer, toaster, commandpalette | engolido sem uma palavra, e os eventos seguintes deixavam de ser entregues | chega ao evento SystemError da aplicação como qualquer erro de script; os eventos seguintes são entregues |
il_max_retries | repetia também uma falha que se repete de forma idêntica (demasiados redirecionamentos, redirecionamento inválido ou HTTPS → HTTP, TLS, ficheiro impossível de escrever) | essas falhas já não são repetidas; 429, 503 e uma falha de rede continuam a sê-lo |
| URL e caminhos | o fragmento #… ia para o servidor; uma Location relativa ?page=2 perdia o último segmento; um caminho relativo de of_download seguia a pasta atual do momento | o fragmento já não é enviado; Location resolvida como um navegador o faz (RFC 3986); um caminho relativo é resolvido na chamada, na pasta atual da aplicação no carregamento da biblioteca |
A receita: (1) teste o que of_set_header, of_set_bearer e of_set_basic devolvem quando o valor vem de uma introdução, de um INI ou de uma base de dados — uma chamada que ignora o retorno continua a compilar, mas o -5 é agora o único vestígio de um cabeçalho recusado; (2) uma API de intranet com autenticação Windows que respondia 200 responde agora 401: defina ib_windows_auth = true NESSE cliente; (3) uma aplicação de 32 bits que lê como texto um corpo com mais de 16 MB passa a of_download; (4) se partilhava um id de pedido entre dois objetos, leia a resposta no objeto que o enviou; (5) um erro que agora aparece em SystemError a partir de ue_response ou ue_failed já existia: era engolido.
11.10 speechout: definições vivas, uma destruição silenciosa #
A revisão de speechout cumpre duas promessas que a documentação fazia e o código não — uma definição alterada durante uma leitura vale para a frase seguinte, of_speak_from para além do texto devolve -5 — e retira um evento levantado no momento errado. Nenhum método é retirado. Acrescentados: of_add_abbreviation, of_clear_abbreviations, o evento ue_mark e duas etiquetas, [mark=nome] e [rate=150]…[/rate].
| O quê | 3.0 | 4.0 |
|---|---|---|
of_speak_from (al_index) | para além do texto, a leitura em curso era CORTADA, nada recomeçava, e o retorno era 0 | -5, e a leitura em curso continua |
ii_rate, ii_pitch, ii_volume, is_lang, is_voice | alterados durante uma leitura, tomados só na leitura SEGUINTE (a documentação prometia a frase seguinte) | propriedades vivas: a frase seguinte toma-as |
ue_voice_fallback | mudo quando só faltava a REGIÃO (pedia-se fr-CA, voz fr-FR) | levantado; as etiquetas de idioma comparam-se sem maiúsculas, e fr_FR vale fr-FR |
destroy (n_pbt_speechout) | durante uma leitura, levantava ue_stopped — numa janela já meio destruída | nenhum evento; of_close() continua a levantar ue_stopped |
of_sentence_count, of_count | a contagem do texto lido da vez ANTERIOR (0 antes de qualquer leitura) | a contagem de is_text tal como está |
of_pause, of_resume, of_clear_queue | criavam a voz quando não existia; uma pausa durante a espera das vozes perdia-se | 0 sem criar nada, -4 se a página não respondeu; a pausa mantém-se até of_resume |
ue_sentence (al_index) | uma abreviatura (Mr., Dr., e.g.), um endereço soletrado ou uma versão cortavam a frase; um texto sem ponto era uma só frase | já não cortam; uma frase com mais de 250 caracteres é cortada: os números de frase podem mudar |
[pause=ms] | ignorada no FIM do texto | um silêncio após a última frase, antes de ue_stopped |
A receita: (1) teste o -5 de of_speak_from quando o índice vem de um clique; (2) se o seu ue_stopped fazia algo ao fechar a janela, chame você mesmo of_close() no seu close — a destruição já não o levanta; (3) não guarde números de frase de uma versão para a outra: tire-os de ue_sentence, como a documentação sempre disse.
11.11 statictext e texto formatado: uma marcação lida da esquerda para a direita #
A revisão de statictext corrigiu sobretudo o texto com etiquetas comum (4.7): estas linhas valem para o rótulo de qualquer componente — título de separador, painel da barra de estado, toast, caixa de diálogo. Nenhum método é retirado. Acrescentado: of_refresh_parent_color(), e as zonas [action], [hyperlink] e os cabeçalhos de [foldarea] de um statictext alcançam-se pelo teclado (Tab, depois Enter ou Espaço).
| O quê | 3.0 | 4.0 |
|---|---|---|
of_escape_markup (une donnée collée à une balise) | um ] escapado logo após uma etiqueta formava par com o ] da etiqueta: "[b]" + of_escape_markup("] fim") + "[/b]" mostrava [b]] fim sem negrito | o dado é mostrado tal como está, e a formatação à volta mantém-se |
[/b], [/i]… | uma etiqueta de fecho fechava a ÚLTIMA etiqueta aberta, fosse qual fosse: [b]A[i]B[/b]C deixava C a negrito; [/br] também fechava algo | uma etiqueta de fecho só fecha a sua (os estilos abertos dentro continuam); uma etiqueta de fecho sem abertura, ou a de uma etiqueta auto-fechada, é ignorada |
[picture=…] | cortada na primeira vírgula: um data URI (o que of_icon() devolve) ou um nome de ficheiro com vírgula não aparecia | as dimensões leem-se no fim do valor: ambos aparecem |
[picture=\\server\share\x.png] | a imagem era lida na partilha de rede | recusada: uma imagem da marcação nunca vai buscar uma partilha de rede. Deve passar por of_icon(), que a incorpora, ou por um picture |
[hyperlink=HTTPS://…] | um esquema em maiúsculas não era aberto | aberto: o esquema lê-se sem distinguir maiúsculas; a lista continua http, https, mailto |
ii_padding | 0 = a margem do tema: um rótulo nunca podia alinhar-se com o bordo de um campo vizinho | -1 = a margem do tema (nova predefinição), 0 = nenhuma margem |
ue_clicked, ue_double_clicked | levantados ao dobrar um [foldarea] (três eventos para um duplo clique), e ao soltar o rato depois de uma seleção de texto | já não são levantados: dobrar é uma questão de leitura |
[foldarea:… [action=…]] | levantava ue_action E dobrava o bloco | só ue_action, o bloco fica como está |
ii_line_spacing, is_marquee_direction | um valor fora de 50-400 era ignorado e relido 0; um sentido desconhecido ("UP") deslocava-se para o início mas relia-se tal como estava escrito | levado ao limite mais próximo, relido tal como aplicado; um sentido desconhecido vale e relê-se MARQUEE_START |
of_scroll_to_end | não devolvia nada | devolve 0, ou -2 se o componente não estiver criado |
A receita: (1) um ii_padding = 0 escrito para dizer «a margem do tema» passa a -1 — ou desaparece; (2) uma imagem da marcação guardada numa partilha de rede passa por of_icon(); (3) um ue_clicked que reagia ao dobrar de uma secção deixa de ser chamado: o dobrar não se programa.
11.12 breadcrumb: o que cede quando o caminho não cabe, e sair do campo #
A segunda revisão do trilho de navegação (breadcrumb) corrigiu o dobrar pela largura, o modo OVERFLOW_SHRINK e o que um segmento leva consigo. Nenhum método é retirado. Uma linha vale para todos os menus nativos da biblioteca: a pesquisa por escrita.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_edit() sans / without ib_editable | devolve 0, nada se abre | devolve -4 |
| sair do campo do caminho para outro controlo da aplicação | o campo ficava aberto, o texto a meio, e nada era comunicado | um texto alterado é validado: ue_path_entered; passar para outra aplicação continua a manter o que foi escrito |
OVERFLOW_SHRINK | todas as etiquetas limitadas a 12 caracteres, mesmo com espaço; o local actual cortado a direito no bordo da barra | nada é cortado enquanto houver espaço; o meio cede primeiro, até uma letra e …, o primeiro segmento e o local actual por último |
OVERFLOW_COLLAPSE | a etiqueta do local actual podia ser encurtada antes de o meio se dobrar | o meio dobra-se primeiro; o local actual só é encurtado em último recurso |
of_insert_item(…, ai_index) | os handles dos segmentos deslocados designavam outro segmento, as suas cores e tooltips ficavam no endereço antigo | os seus handles são libertados, as suas cores e tooltips seguem-nos; um segmento retirado (of_clear, of_truncate, of_remove_item) leva os seus |
of_item("b").il_back_color / of_item("a/b").il_back_color | dois valores para o mesmo segmento | um só: a chave única e o endereço designam o mesmo segmento |
OVERFLOW_SCROLL, roda do rato | sem efeito | faz deslizar a faixa |
| os menus nativos (ramos do trilho, friso, barra de menus, barra de ferramentas, menu de contexto): uma letra escrita | não fazia nada, exceto mnemónicas | as letras escritas no mesmo segundo saltam para a primeira entrada que começa assim («Win»), como no explorador; um menu com mais de 500 entradas só desenha o que se vê |
A receita: (1) um of_edit() cujo 0 testava sem ter definido ib_editable devolve agora -4; (2) um ue_path_entered pode chegar quando o utilizador clica noutro sítio da janela — é o mesmo texto que com Enter; (3) depois de um of_insert_item a meio do trilho, volte a pedir os handles dos segmentos que se seguem.
11.13 buttonbar e teclado da janela: a tecla vai para o componente do foco #
A segunda revisão da barra de botões (buttonbar) tocou no teclado da janela, partilhado por todos os componentes que respondem ao Enter, ao Esc, a uma letra Alt ou a um atalho registado (button, buttonbar e os atalhos de of_register_shortcut de todos os componentes). Nenhum método é retirado; um é acrescentado, of_focus_button.
| O quê | 3.0 | 4.0 |
|---|---|---|
| dois componentes da mesma janela respondem ao Enter, ao Esc ou ao mesmo atalho (duas folhas MDI, dois painéis) | recebia-a o primeiro criado, mesmo na outra folha | o mais próximo do foco (mesma folha, mesmo painel); em empate, nenhum: a tecla fica com a janela |
Enter num CommandButton PB com o foco, ou numa DropDownListBox aberta; Esc numa lista aberta | acionava o botão predefinido / cancelar do componente | fica com o controlo, como numa caixa de diálogo do Windows |
of_register_shortcut(chord, key) num botão da barra, depois o botão desativado e reativado, ou a sua letra is_shortcut alterada | o atalho era apagado | mantido: a letra Alt e o atalho da aplicação já não se tocam |
| a letra Alt de um botão perante um atalho explícito da mesma tecla | ganhava o primeiro registado | ganha o atalho explícito; as letras só são consultadas depois |
of_clear_shortcuts() | apagava também o is_shortcut de um button | só apaga os atalhos da aplicação |
buttonbar: of_register_shortcut(chord) sem chave, ou com uma chave que não nomeia nenhum botão | devolvia 0 e engolia a tecla sem acionar nada | devolve -5 |
buttonbar: remover o botão de is_default / is_cancel, ou esvaziar a barra | a propriedade mantinha a chave; um botão acrescentado de novo com essa chave voltava a ser o predefinido | esvaziada: o papel sai com o seu botão |
| buttonbar: outro botão da barra tem o foco | o acento ficava em is_default enquanto o Enter acionava o botão com o foco | o botão com o foco tem o aspeto predefinido; is_default relido fica inalterado |
buttonbar: um ii_padding_x negativo | voltava a 12 | o recuo do tema, como ii_padding_y e ii_gap |
| buttonbar: a linha separadora entre botões | desenhada a meio do espaço, mesmo quando os botões não se tocavam | só entre botões juntos (ii_gap = 0), e do lado certo na leitura da direita para a esquerda |
A receita: (1) numa barra, dê um atalho a UM botão — of_register_shortcut("Ctrl+S", "save") — a forma sem chave devolve -5; (2) depois de remover e voltar a acrescentar o botão predefinido, volte a definir is_default; (3) para pôr o foco num botão preciso («Não» em vez de «Sim»), chame of_focus_button("no").
11.14 button: um botão esbatido larga a tecla, e Alt+letra responde #
A revisão do botão (button, obsoleto a favor de buttonbar mas ainda entregue e corrigido) muda o que faz no teclado e o que as suas propriedades releem. Nenhum método é retirado nem acrescentado.
| O quê | 3.0 | 4.0 |
|---|---|---|
um botão esbatido com ib_default, ib_cancel ou is_shortcut (ib_enabled = false) | retinha o Enter, o Esc ou o seu atalho em toda a janela: a tecla perdia-se | devolve a tecla à janela (um CommandButton PB predefinido, um SingleLineEdit recebem-na); reativado, retoma-a |
o & de is_text (&Guardar) | sublinhava a letra, nada mais | Alt + a letra aciona o botão onde quer que esteja o foco na janela, depois dos atalhos explícitos, nunca esbatido; uma barra de menus PB que usa a mesma letra perde-a |
| Enter ou Espaço mantidos no botão com o foco | uma rajada de ue_clicked; o Espaço disparava ao premir | um único ue_clicked; o Espaço dispara ao largar, como no Windows |
um is_shortcut que a janela não sabe acionar ("Win+S", "Ctrl+Entrée", "Ctrl+Pause") | relia-se tal e qual; "Win+S" disparava o botão com um S simples | recusado: relê-se "". Os nomes das teclas escrevem-se em inglês (Enter, Esc, Del) |
is_shortcut com um tooltip | o atalho não aparecia em lado nenhum | acrescentado ao tooltip (ao título de um enriquecido): «Guardar (Ctrl+S)» |
of_register_shortcut("F5") no botão, depois ib_default, ib_cancel ou is_shortcut alterados | o F5 era apagado | o F5 e o is_shortcut respondem os dois |
is_text, is_image, is_style, ii_badge, il_badge_color, ii_badge_size, ii_image_size lidos depois de of_reset() | o valor antigo, embora o ecrã estivesse reposto | o seu valor predefinido ("", "standard", 0, -1) |
| um botão esbatido e a tecla Tab | recebia o foco | é saltado |
uma etiqueta feita só de uma imagem ([picture=…]), ou um & numa etiqueta | a etiqueta desaparecia, ou a marca era partida | apresentados como escritos |
A receita: escreva os nomes das teclas de is_shortcut em inglês ("Ctrl+Enter") e releia a propriedade em caso de dúvida: "" significa recusado. Se esbatia um botão predefinido para «desativar o Enter», nada a mudar: é o que acontece agora.
11.15 menubar: uma barra de menus que devolve o foco, e Alt+letra de qualquer lado #
A revisão da barra de menus (menubar) muda o que faz com o foco e o teclado, e o que fazem todos os menus nativos em escrita da direita para a esquerda. Nenhum método é retirado nem muda de assinatura.
| O quê | 3.0 | 4.0 |
|---|---|---|
um clique na barra e depois uma escolha (Editar > Colar) | a barra ficava com o foco: GetFocus() em ue_item_selected já não nomeava o campo, a colagem perdia-se | o foco volta ao controlo anterior antes de ue_item_selected partir; o mesmo com Esc e com um clique fora |
Alt+F mantido, ou F10, com o foco num campo | nada: só Alt tocado e depois F abria File | Alt+F abre File a partir de qualquer controlo, F10 faz o que Alt faz; um Alt+F registado pela sua aplicação mantém a prioridade, e um menu PowerBuilder nativo na mesma letra perde-a |
Ctrl++, Ctrl+-, Ctrl+,, Alt+Left, Ctrl+Space, Ctrl+Tab, Ctrl+Backspace (todos os componentes com atalhos) | mostrados, mas nada partia de um controlo PB; o button recusava-os ("") | disparados esteja onde estiver o foco; estas teclas exigem Ctrl ou Alt (sozinhas, continuam a ser navegação) |
em RTL, os menus pendentes de todos os menus nativos (barra de menus, friso, barra de ferramentas, breadcrumb, menu de contexto…) | alinhados à esquerda, cascatas à direita, chevron ›, Esquerda fechava | o menu pendente fica alinhado à direita sob o título, uma cascata abre-se à esquerda (chevron ‹): Esquerda abre, Direita fecha |
| um clique no título de um menu já aberto | fechava-o e depois reabria-o (um segundo ue_menu_opening) | fecha-o, como no Windows |
um is_shortcut posto numa entrada que abre uma cascata | mostrado, e levantava ue_item_selected("file/export"), um endereço que nenhum clique produz | nem mostrado nem disparado: um atalho vai numa folha |
| uma barra cujos menus estão todos ocultos ou esbatidos, ao lado de um friso | tomava Alt para nada: as keytips do friso já não apareciam | devolve Alt ao friso enquanto nenhum título for alcançável |
dois títulos com a mesma letra (&Ficheiro, &Favoritos) | Alt+F abria sempre o primeiro | na barra, a faixa passa de um para o outro, Enter abre |
| uma entrada retirada e depois acrescentada no mesmo endereço (uma lista de ficheiros recentes) | retomava as cores e a dica da desaparecida | nasce sem cor (il_back_color relido -1); o mesmo após of_remove_menu e of_clear |
uma letra acentuada ou não latina num menu pendente (&Édition) | sublinhada, mas nenhuma tecla a alcançava | tecla-se como no teclado |
| a tecla Tab na barra | uma paragem por título | uma só paragem para toda a barra; as setas passam de um título ao outro |
| novo | — | is_image (o ícone de uma entrada, mudado a quente), is_group (entradas de opção), ue_menu_closed(as_key) (um menu pendente fechado sem escolha) |
A receita: em ue_item_selected, trabalhe sobre GetFocus() ou sobre o DataWindow em edição como com um menu PowerBuilder; ponha um & em cada título; se a sua aplicação usava Alt+letra para outra coisa, registe-o (of_register_shortcut): mantém a prioridade.
11.16 ribbon: uma escolha que se mantém, menus que ficam abertos, recusas que se dizem #
A segunda revisão da faixa (ribbon) corrige o que o utilizador via — uma escolha de tipo de letra desfeita, um menu que se fechava sob o ponteiro — e aplica à faixa a regra da biblioteca: uma adição ou remoção impossível devolve -5. Nenhum método é retirado nem muda de assinatura.
| O quê | 3.0 | 4.0 |
|---|---|---|
| ribbon: uma escolha na lista de uma caixa de combinação e depois a saída do campo | ue_combo_changed duas vezes — a escolha, depois o texto escrito antes, que a sobrepunha; is_text relia o texto escrito | um único ue_combo_changed, a escolha; o campo mostra-a de imediato, mesmo numa caixa não editável |
ribbon: Enter ou Escape numa caixa de combinação, num contador, ou num botão da faixa com o foco | iam também para o botão predefinido ou de cancelamento da janela | ficam na faixa; Escape num campo repõe o texto de antes da escrita |
| ribbon: um menu aberto enquanto a aplicação atualiza a faixa (outro controlo ocultado, um separador renomeado, um mosaico acrescentado) | fechava-se, e a escolha feita nele não acionava nenhum evento | fica aberto; só se fecha se o seu próprio controlo desaparecer, for ocultado ou desativado |
ribbon: is_app_button reescrito («File» → «Ficheiro»); is_app_button = "" | o menu da aplicação era esvaziado; uma cadeia vazia mostrava «File» | o menu fica; uma cadeia vazia retira o botão e o seu menu |
ribbon: of_select_tab de um separador desconhecido ou oculto | 0 | -5, nada muda |
ribbon: acrescentar uma entrada de menu, um mosaico, uma escolha de caixa de combinação, um botão de acesso rápido, uma entrada do menu da aplicação ou um grupo contextual com uma chave já usada; uma chave com uma barra vertical ou a começar por __; um pai desconhecido (separador, cabeçalho, escolha, entrada sem botão da aplicação, separador sob um grupo contextual ausente) | 0: um duplicado, ou nada (um separador contextual sem faixa) | -5 |
ribbon: of_remove_tab, of_remove_group, of_remove_item, of_select_gallery_item num endereço desconhecido; of_open num botão de acesso rápido | 0, sem efeito | -5. of_open("separador/grupo") abre o painel de um grupo recolhido |
ribbon: um handle of_qat_item mantido depois de of_remove_item do seu botão | continuava válido e designava um botão desaparecido | libertado: IsValid() devolve false |
| ribbon: teclas de acesso rápido — dois controlos com a mesma letra, um deles oculto; um controlo de um grupo recolhido | o oculto roubava a letra e nada era executado; a letra de um grupo recolhido não fazia nada; uma tecla de duas letras nunca respondia | só responde um controlo visível e ativo; a letra abre o painel do grupo recolhido; "FP" escreve-se letra a letra |
| ribbon: setas do teclado num botão dividido, seletor de cor, caixa de combinação ou galeria desativados | paravam neles, sem nada poder fazer | saltam-nos; Baixo num botão pendente ou dividido abre o seu menu |
A receita: (1) ue_selection_changed e ue_minimized são lançados também quando o seu código chama of_select_tab ou define ib_minimized, como num clique: se chamava o seu tratamento logo atrás, retire essa chamada, correria duas vezes; (2) teste o -5 das adições se a sua construção puder repetir uma chave; (3) um is_app_button = "" que queria dizer «File» escreve-se agora is_app_button = "File". As remoções sob um controlo e o handle de uma entrada do menu da aplicação estão na tabela 11.5.
11.17 toolbar: uma regra de atalhos, uma só dica, recusas que se dizem #
A segunda revisão da barra de ferramentas (toolbar) alinha os seus atalhos com os da janela e torna visível o que era escrito sem efeito. Nenhum método é retirado nem muda de assinatura; surgem dois códigos de retorno (-5).
| O quê | 3.0 | 4.0 |
|---|---|---|
uma ferramenta com is_shortcut = "Delete" (uma tecla sozinha) e um campo na barra | Delete no campo despoletava a ferramenta e não apagava nada; fora da barra, nada | uma tecla sozinha nunca é um atalho: é preciso Ctrl ou Alt, ou de F1 a F24 — a regra da janela |
| uma tecla de atalho mantida premida (todos os componentes) | a ação repetia-se: um alternador piscava | uma ação por pressão |
of_register_shortcut(acorde, chave) herdado, numa toolbar | não despoletava nada, e a tecla era engolida | recebe o endereço da ferramenta ou da entrada ("main/save"), -5 caso contrário; a forma de um argumento devolve -5; of_clear_shortcuts também esvazia is_shortcut |
| o atalho de um campo, de um seletor de data, de uma etiqueta | engolia a tecla sem fazer nada | o campo recebe o cursor (Ctrl+F numa pesquisa), o seletor abre o seu calendário; uma etiqueta não aceita nenhum |
a dica dada ao acrescentar (of_add_button(…, tooltip)) | etiquetas mostradas à letra; duas bolhas ao mesmo tempo se is_tooltip fosse posto depois | uma só dica com tema, texto rico, o atalho no fim; is_tooltip substitui-a e relê-se |
of_add_bar(MAIN_BAR) depois de uma primeira ferramenta em main | devolvia 0 sem fazer nada | -5: para a posicionar, acrescente main antes de qualquer ferramenta |
of_set_layout de um texto que não é JSON | devolvia 0 | -5 |
ue_layout_changed | ausente quando acrescentar uma barra empurrava outra; despoletado ao mostrar uma barra já visível | despoletado no primeiro caso, já não no segundo |
| separadores, menu pendente ou cascata cujas entradas estão todas ocultas | traços órfãos; o menu pendente e a cascata ficavam ativos e mudos | nenhum traço no início, no fim ou duplicado; são desenhados a cinzento |
| um clique direito na barra | nenhum evento, ue_rclicked incluído | ue_item_rclicked(endereço) numa ferramenta, ue_rclicked fora de qualquer ferramenta — nunca os dois |
as cores de uma entrada de menu (of_menu_item(…).il_back_color) | escritas e relidas, nunca desenhadas | desenhadas no menu |
toolbar: ue_rclicked, ue_mouse_enter, ue_mouse_leave | documentados, mas nunca lançados | lançados: um clique direito na barra fora de qualquer ferramenta, a entrada e a saída do rato |
A receita: (1) um atalho de ferramenta numa tecla sozinha (fora F1 a F24) leva Ctrl ou Alt; (2) numa toolbar, of_register_shortcut recebe o endereço da ferramenta ou da entrada; (3) para posicionar a barra main, chame of_add_bar(MAIN_BAR, banda, posição) antes da sua primeira ferramenta.
11.18 statusbar: uma pega que redimensiona, uma mensagem que não substitui o texto #
A segunda revisão da barra de estado (statusbar) dá à pega de redimensionamento o seu verdadeiro papel e faz de cada chave vazia ou desconhecida uma recusa. Nenhum método é retirado nem muda de assinatura; of_flash_panel ganha um código de retorno (-5).
| O quê | 3.0 | 4.0 |
|---|---|---|
ib_show_resize_grip = true, depois arrastar a pega | um desenho: nada se mexe | a janela redimensiona-se pelo canto (inferior esquerdo em RTL); a pega não é desenhada numa janela maximizada ou sem rebordo redimensionável |
of_flash_panel numa chave que a barra nunca recebeu, ou num endereço | 0, nada é mostrado | -5 |
of_panel(k).is_text relido durante um of_flash_panel | a mensagem | o texto do painel (a mensagem passa por cima) |
of_panel(""), of_panel("a/b"): escrita e releitura | escrevia nos painéis sem chave e nos separadores | não designa nada: não escreve em lado nenhum, relê-se vazio |
is_state fora das constantes STATE_* ("Error", "very bad") | relido tal como está, sem cor; um valor com um espaço provocava um erro de script | as maiúsculas são ignoradas ("Error" = erro); qualquer outro valor equivale a « nenhum estado » e relê-se vazio |
ii_progress = 150 e depois relido | 150 (desenhado a 100 %) | 100, o que está desenhado |
| um painel desativado com um estado | mantinha a cor do estado: parecia ativo | a cinzento, marca de estado incluída |
um painel retirado, esvaziado (of_clear, of_clear_menu), desativado ou ocultado enquanto a sua lista está aberta | a lista ficava aberta, e uma escolha acionava ue_panel_menu_clicked | a lista fecha-se, nada é acionado (o mesmo para uma entrada que ficou a cinzento ou oculta) |
| duplo clique num painel com lista pendente | ue_panel_double_clicked além da lista aberta | só a lista |
| Seta para cima / baixo num painel com lista pendente que tem o foco | passava ao painel vizinho | abre a lista (as setas Esquerda / Direita continuam a deslocar) |
| uma lista pendente feita apenas de separadores | seta e lista vazia | sem lista: o painel continua a ser o que ib_clickable diz |
A receita: (1) defina ib_show_resize_grip numa barra de estado colocada no fundo de uma janela redimensionável; (2) teste o retorno de of_flash_panel como o dos outros métodos com chave; (3) dê uma chave a cada painel que quiser reler ou modificar.
11.19 dockcontainer: um of_select_panel que encontra o painel, janelas flutuantes que se lembram #
A segunda revisão do contentor de painéis (dockcontainer) dá a of_select_panel um efeito sobre um painel recolhido ou flutuante, e faz a disposição lembrar-se das janelas flutuantes. Nenhum método é retirado nem muda de assinatura.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_select_panel de um painel recolhido, flutuante ou oculto | 0, nada se vê | recolhido: o seu painel deslizante abre-se; flutuante: a sua janela passa para a frente; oculto: -5 |
of_float_panel do painel principal ou de um painel oculto | 0, nada acontece | -5 |
of_move_panel que empilha o painel PRINCIPAL | 0, e o seu vizinho desaparece sem separador | -5, nada se mexe |
as_position desconhecida (of_add_panel, of_move_panel) | 0, o painel acopla-se em baixo | -5, o controlo não é tocado |
disposição (of_get_layout, ue_layout_changed, of_set_layout) e painéis FLUTUANTES | esquecidos: um painel destacado voltava acoplado; deslocar a sua janela não disparava nada | guardados com o lugar da sua janela, reabertos ao repor (trazidos de volta para um ecrã); deslocar ou redimensionar a janela dispara ue_layout_changed |
of_set_layout de uma disposição sem painel principal | o painel principal atual é retirado | é mantido |
is_title de um painel adicionado sem título | a sua chave; um título dado depois ao painel principal não fazia aparecer o seu cabeçalho | "" (o separador continua a mostrar a chave); o cabeçalho do principal segue o seu título |
A receita: (1) ue_panel_selected, ue_panel_floated e ue_panel_pinned são lançados também após of_select_panel, of_float_panel e ib_pinned, como num gesto: se chamava o seu tratamento logo atrás, retire essa chamada, correria duas vezes; (2) teste o -5 de of_move_panel, of_float_panel e of_select_panel; (3) uma disposição gravada antes da 4.0 repõe-se tal como está, os seus painéis continuam acoplados.
11.20 tab: códigos de retorno honestos, um clique direito que volta à aplicação #
A segunda revisão dos separadores (tab) faz of_add_page e of_select_page dizerem o que recusam, anuncia a disposição quando o seu código oculta um separador, e devolve o clique direito à aplicação quando o menu integrado está desligado. Nenhum método é retirado nem muda de assinatura; é acrescentado um evento.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_add_page de um controlo já alojado (por este separador com outra chave, ou por outro componente) | 0, e um separador sem nada por trás | -5, nada é acrescentado |
of_select_page de um separador recusado quando nenhum está ativo (todos ocultos) | 0 | -5 |
Ocultar ou voltar a mostrar um separador pelo seu código (ib_visible) | nenhum ue_layout_changed | ue_layout_changed disparado com a disposição inteira, como para of_move_page: é o aviso de que a disposição a guardar mudou |
Clique direito num separador com ib_context_menu = false | nada | o separador é selecionado e depois é disparado ue_tab_rclicked(as_key) (novo): abra aí o seu menu |
Voltar ao separador atual enquanto ue_selection_changing espera a sua resposta | uma resposta «sim» ativava mesmo assim o outro separador | a pergunta é anulada: vence o último gesto do utilizador |
Um separador desativado ou oculto enquanto ue_tab_closing espera a sua resposta | fechava mesmo assim | permanece aberto |
| Fechar pelo teclado (Delete) o separador que tem o foco | o foco saía da barra, as setas deixavam de responder | o foco passa para o separador que ficou ativo |
A receita: (1) teste o -5 de of_add_page (uma página só se aloja uma vez) e de of_select_page; (2) se grava a disposição em ue_layout_changed, nada a fazer — passa a seguir também os seus ib_visible; (3) onde ib_context_menu = false deixava o clique direito sem resposta, programe ue_tab_rclicked.
11.21 listbar: uma entrada oculta nunca selecionada, uma disposição verificada #
A segunda revisão da barra de navegação (listbar) faz of_select_item recusar uma entrada oculta e of_set_layout um texto que não é uma disposição, e acrescenta uma pastilha de contador, as teclas Esquerda / Direita e o clique direito numa entrada. Nenhum método é retirado nem muda de assinatura.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_select_item de uma entrada oculta (ib_visible = false) | 0, uma seleção invisível | -5, a seleção não se move; ocultar a entrada já selecionada mantém-na selecionada |
of_set_layout de um texto que não é um objeto JSON (ficheiro truncado) | 0, nada é aplicado | -5, nada é enviado |
| Secção recolhida numa disposição reposta, acrescentada mais tarde | nasce recolhida | nasce expandida: o recolhimento só vale para uma secção presente |
| Secção com título vazio | as suas entradas coladas às de cima; recolhível, sem nada para a reabrir | um espaço (um filete no trilho) separa-a; nunca se recolhe |
Novo: is_badge (entrada), ue_item_rclicked(as_keys), Esquerda / Direita e salto por letra | — | uma pastilha de contador, o clique direito numa entrada (um só evento, a entrada não é selecionada), o recolhimento pelo teclado |
A receita: (1) ue_selection_changed é lançado também após um of_select_item do seu código (abrir a página inicial no arranque, por exemplo), como num clique: se abria a página logo atrás, deixe isso ao evento, senão abriria duas vezes; (2) teste o -5 de of_select_item se ocultar entradas, e o de of_set_layout se a disposição vier de um ficheiro; (3) uma secção sem título já não se recolhe: dê-lhe um título se tiver de se recolher.
11.22 tilesbox: um título que já não cria grupos, a reorganização pelo teclado #
A segunda revisão do painel de mosaicos (tilesbox) impede o título de um grupo de criar esse grupo, faz of_add_live_item recusar um texto vazio, dá uma única paragem de tabulação por grupo e acrescenta a reorganização pelo teclado. Nenhum método é retirado nem muda de assinatura. il_badge_color segue agora a regra de todas as cores (veja a linha picture, button, tilesbox mais acima).
| O quê | 3.0 | 4.0 | |
|---|---|---|---|
of_group(chave).is_title num grupo nunca adicionado | criava um grupo visível que não se podia encher nem retirar (exceto com of_clear) | não escreve nada: só of_add_group cria um grupo; uma chave vazia, ou com / ou ` | `, dá um handle inerte |
of_add_live_item com um texto vazio | 0, e o texto fixo is_live_text era apagado | -5, nada muda | |
of_tile(endereço).of_count() | 0 | o número de faces postas por of_add_live_item | |
Reorganizar (ib_reorderable = true) | só com o rato | também pelo teclado: Ctrl+Esquerda/Direita no grupo (sentido de leitura), Ctrl+Cima/Baixo para o grupo vizinho; os mesmos ue_tile_moved e ue_layout_changed | |
| Tecla Tab | parava em cada mosaico; uma seta para um bordo sem vizinho saltava para o mosaico anterior ou seguinte do documento | uma paragem por grupo (o último mosaico com foco), as setas percorrem os mosaicos; no bordo, o foco fica | |
| Mosaico desativado ou oculto enquanto é arrastado | deslocado ao largar, ue_tile_moved disparado | o arrasto é abandonado, nada se move | |
ib_collapsed de um grupo definido pelo seu código | nenhum evento | ue_group_toggled, como um clique no cabeçalho (nada quando o grupo já está nesse estado) |
A receita: (1) crie um grupo com of_add_group antes de mudar o seu título; (2) teste o -5 de of_add_live_item se o texto de uma face puder estar vazio; (3) o que fazia em ue_tile_moved vale agora também para um deslocamento pelo teclado.
11.23 stepbar: «tudo concluído» ancorado na última etapa, etapas retiradas que já não deixam nada #
A segunda revisão da barra de etapas (stepbar) torna «tudo concluído» coerente com a regra da etapa atual (uma identidade, não uma posição), faz uma etapa retirada levar o que lhe pertencia e corrige quatro defeitos de apresentação. Nenhuma assinatura muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
of_add_step quando a barra está em «tudo concluído» | a etapa adicionada aparecia concluída (visto); ii_current passava a n + 2 sem evento | adicionada depois da última etapa de então, torna-se a etapa atual e ue_step_changed é lançado; inserida antes, nada muda |
of_step(chave).is_state numa chave que não designa nenhuma etapa | guardado e depois aplicado à etapa adicionada mais tarde com esse nome | ignorado; uma etapa adicionada nasce com o seu estado calculado |
Cores e dica de uma etapa retirada (of_remove_step, of_clear_steps) | voltavam na próxima etapa adicionada com a mesma chave | partem com a etapa |
Barra compactada (OVERFLOW_AUTO) cuja etapa atual está forçada em erro | nenhum rótulo; uma etapa forçada a STATE_CURRENT ganhava o seu | o rótulo fica na etapa atual (a posição de ii_current), seja qual for o seu estado |
OVERFLOW_SHRINK | rótulos em várias linhas, palavras longas cortadas sem «…» | uma linha por rótulo, terminada em «…» |
POSITION_BOTTOM com uma segunda linha (is_description) | acima do rótulo, colada a ele | sob o rótulo, acima do marcador |
Passar o rato sobre uma etapa desativada ou fora de alcance (il_back_color_hover, il_text_color_hover) | a cor ao passar acendia | nada acende: a etapa não responderá ao clique |
A receita: se o seu código adiciona uma etapa depois de definir «tudo concluído» (ii_current = of_count() + 1) e quer que a barra continue assim, volte a definir ii_current = of_count() + 1 após a adição. Se reconstrói a barra com as mesmas chaves, volte a definir as cores e dicas desejadas: já não sobrevivem à retirada.
11.24 progressbar: uma barra que cabe no seu controlo, uma etiqueta que segue o idioma #
A segunda revisão da barra de progresso (progressbar) faz com que caiba onde estava uma HProgressBar, só envia ao componente os valores que mudam o desenho, escreve a percentagem no idioma de apresentação e acrescenta is_label_format (uma etiqueta sua) e is_state (pausa, erro). Nenhuma assinatura muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
| Barra linear num controlo baixo ou largo | margem de 12 px, 640 px de largura no máximo: abaixo de 24 px de altura aparecia uma barra de deslocamento e a barra ficava cortada | margem de 2 px, toda a largura; a pista (14 px) e a etiqueta encolhem com a altura |
Etiqueta da percentagem (ib_label) | «50%» em todos os idiomas | no idioma de apresentação: «50 %» em francês |
of_set_property("value", "12,5"), ou um texto que não é um número | enviado tal como estava: o comando perdia-se sem dizer nada; um minimum inválido bloqueava a escala até ao próximo of_reset | «12,5» é lido 12.5; um texto que não é um número (nem true/false para um booleano) é ignorado |
id_value relido | o valor que o componente tinha recebido; cada atribuição era uma ida e volta com ele | o último valor atribuído pela aplicação; o componente só recebe os que mudam o desenho (uma décima de ponto percentual) |
of_reset() numa barra cheia | a barra descia a zero deslizando | volta a zero de uma vez |
A receita: (1) se calculava uma percentagem à mão, defina id_maximum e atribua o valor bruto, em cada linha se quiser; (2) se um teste automático lia a etiqueta, conte com o formato do idioma de apresentação; (3) para mostrar uma pausa ou um erro, prefira is_state a uma cor escolhida com il_color.
11.25 picture: uma atribuição relê o ficheiro, uma falha diz o motivo #
A segunda revisão da imagem (picture) faz com que releia o disco em cada atribuição, como o Picture nativo, dá a ue_error um segundo argumento que diz porque falta a imagem, recusa um endereço http:// em vez de falhar sem motivo e só emite um ue_clicked num duplo clique. ue_error é a única assinatura que muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
| picture: duplo clique na imagem | dois ue_clicked e depois ue_double_clicked | um só ue_clicked e depois ue_double_clicked — como o Picture nativo |
picture: ue_error | ue_error (string as_message): só a mensagem | ue_error (string as_message, string as_reason): as_reason é uma das constantes REASON_* (não encontrado, demasiado grande, http recusado, formato não apresentado, outro). O seu script do evento recebe o argumento por si; uma chamada event ue_error(…) escrita no seu código passa agora dois |
picture: is_source = "http://…" | tentado em https pelo motor; num servidor sem TLS, uma falha sem motivo | recusado logo à partida: glifo de erro e ue_error com REASON_INSECURE. Descarregue primeiro a imagem (n_pbt_restclient.of_download) e apresente o ficheiro |
picture: o mesmo caminho atribuído de novo depois de reescrever o ficheiro; mono: ou tint: em is_source; uma imagem .avif | a imagem antiga; o glifo de erro; não encontrada | o ficheiro relido, como o Picture nativo; o glifo recolorido pelo tema; apresentada |
| picture: imagem ampliada mais pequena do que a moldura (faixas); roda horizontal, painel tátil; botão direito premido | saía da moldura ao arrastar; um passo de zoom por evento, afastamento num deslocamento horizontal; a imagem deslocava-se | fica onde is_align e is_valign a colocam; zoom proporcional ao gesto, nada num deslocamento horizontal; só o botão esquerdo desloca |
A receita: (1) se um script abria uma ficha em ue_clicked e outra ação em ue_double_clicked, nada a fazer — o duplo clique já não reabre a ficha; (2) substitua qualquer análise do texto de as_message por um teste de as_reason; (3) uma imagem de um servidor de intranet em http descarrega-se primeiro (n_pbt_restclient.of_download para uma pasta temporária) e depois apresenta-se pelo seu caminho; (4) se acrescentava um ?v= ao caminho para forçar a releitura de uma imagem reescrita, retire-o: voltar a atribuir basta.
11.26 video: legendas e formatos que se reproduzem, uma falha que diz o motivo #
A segunda revisão do leitor (video) dá a ue_failed um segundo argumento que diz porquê um filme não toca, recusa um endereço http://, reproduz .mkv e .mov, carrega as legendas dadas por URL, e põe o filme em pausa quando o componente fica oculto. ue_failed é a única assinatura que muda.
| O quê | 3.0 | 4.0 | |
|---|---|---|---|
video: ue_failed | ue_failed (string as_message) | ue_failed (string as_message, string as_reason) — as_reason é uma constante REASON_* | |
video: uma fonte http:// | falhava como « não encontrado » | recusada de imediato, REASON_INSECURE; só https se reproduz | |
video: um .mkv, um .mov | .mkv « não encontrado », .mov recusado pelo nome | servidos e reproduzidos quando o motor os descodifica; .avi, .wmv, .flv continuam recusados (REASON_FORMAT) | |
| video: uma legenda dada por URL | nunca aparecia, sem dizer nada | descarregada pelo componente (o servidor tem de autorizar CORS); uma recusa lança ue_subtitles_failed | |
video: of_add_subtitles duas vezes para o mesmo idioma | substituía a faixa em silêncio, 0 | -5 (também para um idioma com / ou ` | ); of_remove_subtitles` primeiro |
| video: o componente oculto durante a reprodução | o filme continuava, com som | em pausa, ue_paused, e espera por of_play (ib_pause_when_hidden, verdadeiro por omissão) | |
| video: arrastar o volume na barra | um ue_volume_changed por píxel | um só, ao largar | |
video: of_capture para um .jpg | um PNG com um nome .jpg | um JPEG; a sobrecarga of_capture(as_path, al_max_width) reduz a imagem | |
video: of_get_last_error após uma falha de of_capture | o erro anterior da biblioteca | o motivo DESTA falha (pasta ausente, caminho vazio…) | |
video: Escape em ecrã inteiro, ib_enabled = false | sem efeito (só Alt+F4 saía) | sai do ecrã inteiro |
A receita: (1) acrescente as_reason ao seu script de ue_failed e teste-o em vez do texto da mensagem; (2) um filme ou uma legenda de um servidor intranet em http descarrega-se primeiro (n_pbt_restclient.of_download para uma pasta temporária), depois reproduz-se pelo seu caminho; (3) ue_fullscreen_changed, ue_pip_changed, ue_source_changed e ue_chapter_changed são lançados também após as suas próprias chamadas (of_fullscreen, of_pip, of_next, of_seek…), como num gesto: se o seu código chamava o próprio tratamento logo atrás, retire essa chamada, correria duas vezes; (4) uma parede de ecrãs que tem de tocar oculta define ib_pause_when_hidden = false; (5) para substituir a faixa de um idioma, of_remove_subtitles e depois of_add_subtitles.
11.27 pdfviewer: of_refresh diz o que faz, nada é transferido sem o seu conhecimento #
A segunda revisão do visualizador (pdfviewer) dá um código de retorno a of_refresh — e, para que o mesmo nome tenha o mesmo sentido, também aos de webbrowser e shellexplorer —, comunica todas as ligações do documento e recusa o que nunca será apresentado em vez de deixar à espera. Nenhuma assinatura de evento muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
pdfviewer · webbrowser · shellexplorer: of_refresh | subroutine | long: 0 uma vez pedido, -4 sem documento ou página (pdfviewer, webbrowser), -2 se o componente não estiver criado |
pdfviewer: of_refresh após uma recusa (http://…) | não fazia nada, sem evento | a recusa é repetida: ue_load_failed |
pdfviewer: um endereço data: com mais de 2 MB de caracteres | nunca apresentado, nenhum evento | ue_load_failed com REASON_TOO_LARGE, de imediato |
| pdfviewer: um PDF remoto enviado «como transferência» | ue_load_failed, mas o ficheiro ia para Transferências | ue_load_failed com REASON_REFUSED, nada é transferido |
pdfviewer: ue_link_clicked numa ligação mailto:, file: ou relativa | nunca acionado (só http e https); uma ligação relativa chegava como endereço interno | acionado para qualquer ligação; as_url é um mailto:… tal como está, ou um caminho em disco para um ficheiro local |
pdfviewer: of_print_to_pdf | escrevia a página à volta do leitor, não o documento | -4, nada é escrito: copie o ficheiro de is_source |
pdfviewer: file://localhost/C:/…, file:////servidor/partilha/… | um caminho errado, não encontrado | C:\… e \\servidor\partilha\… |
pdfviewer: o foco dado ao componente (Tab, of_focus_webview) | ficava na página: as teclas não deslocavam o documento | passa para o documento: PageDown, setas, Home / End deslocam-no |
A receita: (1) uma chamada uo_pdf.of_refresh() compila tal como está; teste o retorno se quiser saber que não havia nada a reler; (2) um documento com mais de 1,5 MB mantido em memória escreve-se num ficheiro temporário e depois apresenta-se pelo seu caminho; (3) em ue_link_clicked, espere também um mailto: e um caminho em disco, não só um endereço web; (4) para copiar o documento apresentado, copie o ficheiro de is_source em vez de of_print_to_pdf.
11.28 codeeditor: uma pesquisa que se vê, um «ir para» que desloca o cursor, substituir #
A segunda revisão do editor de código (codeeditor) traz para o ecrã o que a pesquisa encontra, mantém o cursor do utilizador durante uma pesquisa, muda o nome de ii_doc_line e acrescenta o que se espera de um editor de scripts: substituir, controlar o cursor, saber se é preciso guardar, mostrar um erro na calha. Nenhuma assinatura de evento muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
codeeditor: ii_doc_line | um long com o prefixo de integer | il_doc_line: mude-lhe o nome; uma linha para lá do fim já não marca nada (relê-se tal como foi escrita) |
codeeditor: of_find com ib_search_enabled = false | 0, sem pesquisar nada | -4 |
codeeditor: of_find("") | relançava a pesquisa anterior | esvazia o campo e apaga os realces, sem ue_find_result |
codeeditor: of_find, Enter na barra | a ocorrência ficava muitas vezes fora da vista; o cursor ia para ela | a ocorrência é trazida para o ecrã; a pesquisa parte do cursor, que só se move ao fechar a barra (Esc) |
codeeditor: of_insert_text com a barra de pesquisa aberta | substituía a ocorrência encontrada, fora da vista, e esvaziava o histórico de Ctrl+Z | insere no cursor do utilizador, trazido para o ecrã; Ctrl+Z anula-o |
codeeditor: um novo is_text | mantinha o deslocamento do documento anterior; um texto só com CR relia-se em LF | apresenta-se a partir da primeira linha e apaga os marcadores; só CR relê-se em CR (uma mistura em CRLF) |
codeeditor: ib_current_line com ib_wrap | nenhuma faixa | a faixa cobre toda a linha do cursor |
| codeeditor: novidades | — | substituir (of_replace, of_replace_all, Ctrl+H) e opções de pesquisa (ib_find_match_case, ib_find_whole_word, ib_find_regex, F3); cursor e seleção (il_caret_line, il_caret_column, of_select_range, of_selected_text, of_line_count); ib_modified; marcadores na calha (of_add_marker, of_remove_marker, of_clear_markers, of_marker_count) |
A receita: (1) substitua ii_doc_line por il_doc_line; (2) teste o -4 de of_find se a pesquisa puder estar desativada; (3) para «ir para a linha» de um erro deslocando o cursor, defina il_caret_line (e of_add_marker para o mostrar) — il_doc_line apenas marca; (4) se seguia ue_caret_changed para saber onde um excerto foi inserido, leia il_caret_line depois de of_insert_text; (5) um botão Guardar pode seguir ib_modified, que repõe a false depois de guardar.
11.29 jsontree e xmltree: o teclado fica com a árvore, uma pesquisa que já não move a seleção #
A segunda revisão da árvore JSON (jsontree) incidiu sobre o motor que partilha com a árvore XML (xmltree): o que se segue vale para as duas, salvo indicação. Nenhuma assinatura muda; a árvore JSON ganha of_expand_path, of_collapse_path, of_is_expanded, of_copy e o evento ue_node_toggled, levantado por um gesto do utilizador como por of_expand_path e of_collapse_path.
| O quê | 3.0 | 4.0 |
|---|---|---|
| jsontree, xmltree: Enter numa folha | passada à janela: o seu botão predefinido disparava | fica com a árvore, levanta ue_node_clicked como um clique; sem seleção, nada |
| jsontree, xmltree: Esc com a caixa de pesquisa aberta | disparava o botão Cancelar da janela | fecha primeiro a caixa; com a caixa fechada, Esc volta à janela |
jsontree, xmltree: linhas de fecho (}, ], </x>) | alcançadas pelas setas (ue_selection_changed de um bloco já anunciado); um clique levava a vista de volta à abertura | saltadas pelo teclado; um clique seleciona o bloco sem mover a vista |
| jsontree, xmltree: seta direita numa folha | descia uma linha | não faz nada, como numa árvore |
| jsontree, xmltree: uma pesquisa durante uma seleção | of_search_next ou Esc podiam dobrar a linha escolhida e mover a seleção sem evento | a linha selecionada continua visível e selecionada: of_selected_path não muda |
jsontree: a mensagem de ue_error | metade traduzido, metade inglês («JSON inválido : Unexpected end of JSON (line 1, column 6)») | inteiramente na língua de apresentação, linha e coluna incluídas: não compare o seu texto |
| jsontree, xmltree: um documento com mais de 1 500 000 linhas | mostrado, mas o seu fim fora de alcance, sem dizer nada | recusado: uma mensagem na árvore e ue_error |
| jsontree: Ctrl+C na árvore | não copiava nada, e seguia como atalho da janela | copia a seleção (como of_copy); sem seleção, o atalho continua a ser da janela |
A receita: (1) se uma janela contava com Enter na árvore para disparar o seu botão predefinido, acrescente esse passo em ue_node_clicked; (2) deixe de procurar uma chave vazia em ue_selection_changed (uma linha de fecho já não é selecionada); (3) não analise o texto de ue_error: segue a língua; (4) para restabelecer as dobras de um utilizador, leia of_is_expanded e reponha-as com of_expand_path / of_collapse_path.
11.30 xmltree: cada linha tem o seu XPath, qualquer XPath seleciona #
A segunda revisão da árvore XML (xmltree) retoma tudo o que a secção anterior diz do motor partilhado. Acrescenta o que é próprio do XML: um caminho que designa SEMPRE o nó da linha, legível tal como está por n_pbt_xml. Nenhuma assinatura muda; a árvore XML ganha of_selected_xml, of_copy, of_expand_path, of_collapse_path, of_is_expanded e o evento ue_node_toggled.
| O quê | 3.0 | 4.0 |
|---|---|---|
| xmltree: caminho de uma linha de texto, de comentário ou de instrução de processamento | o do seu elemento (enquanto of_selected_value dava o seu próprio texto); "" antes da raiz | o seu: /r/text()[2], /r/comment()[1], /r/processing-instruction('x')[1], /comment()[1] — n_pbt_xml.of_get_value lê aí o mesmo valor |
| xmltree: elemento cujo prefixo é redeclarado com outro URI, ou com um irmão do mesmo nome noutro espaço de nomes | um caminho que não encontrava nada, ou OUTRO nó | *[local-name()='x' and namespace-uri()='urn:…'], que designa exatamente esse nó |
xmltree : of_select_path | só a forma exata que a árvore escreve, senão -5 | qualquer XPath (//line[@sku='A'], /r/a[1]…): é selecionado o primeiro nó encontrado, of_selected_path dá depois o caminho da árvore |
xmltree: a mensagem de ue_error | « XML inválido : error on line 1 at column 11: … »; a árvore ficava vazia | « XML inválido : linha 1, coluna 11 (…) », na língua de apresentação; a árvore mostra a fonte, com a linha errada marcada |
xmltree: <?xml-stylesheet?> sem declaração XML | mostrado duas vezes | uma só linha |
n_pbt_xml: um XPath com @xml:lang | recusado (prefixo xml desconhecido), valor vazio | lido: o prefixo xml está ligado de raiz, como exige a norma |
| xmltree: Seta direita numa etiqueta com atributos | os atributos só se alcançavam com o rato | percorre os atributos um a um (Seta esquerda volta), um ue_selection_changed por passo, depois desce |
| xmltree: Ctrl+C, dobrar por caminho | nada; Ctrl+C ia para a janela como atalho | of_selected_xml, of_copy e Ctrl+C (o XML da seleção), of_expand_path, of_collapse_path, of_is_expanded (qualquer XPath), ue_node_toggled (um gesto, ou of_expand_path / of_collapse_path) |
A receita: (1) se subia de uma linha de texto ou de comentário ao seu elemento por of_selected_path, pegue no pai do caminho (o que precede a última /); (2) não analise o texto de ue_error: segue a língua; (3) um caminho guardado na 3.0 sob espaços de nomes misturados reencontra-se dando-o a of_select_path, que agora aceita qualquer XPath, e relendo depois of_selected_path.
11.31 xml: recusas que se dizem, espaços de nomes que se mantêm #
A segunda revisão de n_pbt_xml não muda nenhuma assinatura. Faz of_remove seguir os códigos da biblioteca, recusa uma leitura enquanto um documento construído tiver um elemento aberto, e faz os espaços de nomes manterem-se: o que um mutador escreve relê-se no espaço certo, ou é recusado dizendo-o.
| O quê | 3.0 | 4.0 |
|---|---|---|
xml: of_remove(""), of_remove sem documento carregado, página que não responde | 0, como «nada retirado» | -5; -4; -2 — a contagem (>= 0) só quando a remoção foi tentada |
xml: uma leitura (of_exists, of_count, of_get_value, of_is_valid…) ou uma alteração enquanto um elemento construído ainda está aberto | o documento era carregado tal como estava, e o resto da construção começava um NOVO documento: o que vinha antes perdia-se sem erro | recusada: -4, vazio ou false, e is_last_error = «the document is still being built : close its elements first»; nada se perde (of_xml e of_pretty continuam disponíveis) |
xml: of_add_xml sob um elemento com espaço de nomes por omissão, ou com o prefixo do alvo (<s:Item/> sob s:Body) | o fragmento ficava fora do espaço de nomes (xmlns=''), invisível para o XPath que servira para o acrescentar; o prefixo do alvo era recusado (-4) | o fragmento herda os espaços de nomes em vigor no seu alvo, como of_add_child |
xml: of_set_attr / of_add_child com um nome com prefixo (xsi:type, p:item) | 0, um atributo fora do espaço de nomes que o XPath não encontrava; com um prefixo não declarado, um documento que já não se recarregava | no espaço de nomes do prefixo (declarado no nó, ou ligado por of_register_namespace); -4 e «undeclared prefix : xsi» se não estiver ligado em lado nenhum |
xml: of_pretty depois de um of_add_child sob um pai com prefixo (s:Body) | <Item> sem prefixo: relido, fora do espaço de nomes | <s:Item>, como em of_xml |
xml: of_element_attr duas vezes com o mesmo nome; um nome :x, x: ou a:b:c | dois atributos (documento malformado); nome aceite (um documento que não carrega) | um só atributo, com o segundo valor; nome recusado (is_last_error), o elemento fica de fora |
xml: of_transform | aplica uma folha XSLT ao documento carregado | retirado: o XSLT já não existe no motor (o Chromium retira-o); transforme no servidor ou em PowerScript |
A receita: (1) um of_remove testado com = 0 (nada retirado) continua a funcionar; teste < 0 (nada pôde ser tentado); (2) se lia um documento DURANTE a construção (um of_exists para controlar, um of_count para numerar), feche primeiro os seus elementos, ou conte você mesmo; (3) um fragmento de of_add_xml já não tem de redeclarar o espaço de nomes do seu alvo: o que escrevia xmlns='' para sair dele ainda pode; (4) teste o retorno de of_set_attr / of_add_child com um nome com prefixo, e declare o prefixo (ou ligue-o por of_register_namespace).
11.32 json: um array que se constrói depressa, números que mantêm os algarismos, um texto vazio que se diz vazio #
A segunda revisão de n_pbt_json não retira nem altera nenhuma assinatura. Acrescenta as sobrecargas decimal e longlong de of_set_number e of_add_number, e os leitores of_get_decimal e of_get_longlong. Construir um array com of_add_* já não percorre o array inteiro a cada acrescento: 2 000 linhas constroem-se numa fração de segundo em vez de vários minutos. Duas regras ficam agora escritas na documentação, sem mudar: uma cadeia nula escreve-se "" (para um null JSON, of_set_raw(path, "null")), e uma chave escrita duas vezes lê-se na sua PRIMEIRA ocorrência.
| O quê | 3.0 | 4.0 |
|---|---|---|
json: of_load de um texto feito de brancos (quebra de linha, tabulação) | -4, como um texto mal formado | -5, como um texto vazio |
json: of_load de um texto precedido de um BOM (ficheiro UTF-8 com BOM) | -4 | 0, o BOM é ignorado |
json: of_load de um documento aninhado em mais de 512 níveis | 0 — e um texto muito profundo podia parar a aplicação | -4, a aplicação continua viva |
json: of_set_number / of_add_number de um decimal (ou de um literal como 690.50) | convertido em double: uns quinze algarismos, um cêntimo podia perder-se | sobrecarga decimal: todos os algarismos, zeros finais retirados (690.5); um longlong também tem a sua |
json: of_get_number de um expoente com zeros iniciais (1E-0000005) | 0, ou um valor enorme | o valor certo (0.00001) |
todos os componentes: \u seguido de quatro caracteres que não são hexadecimais, numa cadeia lida | os quatro caracteres desapareciam | mantidos tal como estão, como um escape desconhecido |
A receita: (1) se testava of_load(...) = -4 para reconhecer um ficheiro vazio, teste < 0; (2) um montante decimal passado a of_set_number escreve-se agora com todos os algarismos, sem mudar nada no seu código; (3) um identificador com mais de 15 algarismos relê-se com of_get_longlong, um montante com of_get_decimal, já não com of_get_number.
11.33 crosstab: of_from_datastore, recusas que se dizem, o valor apresentado no duplo clique #
A segunda revisão do crosstab renomeia of_set_data para of_from_datastore, o nome do datagrid e do scheduler, que leem um DataStore da mesma forma (mesmos argumentos, mesmos códigos). Qualquer adição, filtro ou formato que nomeie um campo desconhecido devolve agora -5 em vez de 0. A tabela só desenha as colunas visíveis: um código de cliente ou uma data diária postos em Colunas já não bloqueiam o ecrã. Novidades: is_thousands, CF_ICONS, as constantes VALUEFILTER_* e DATE_*.
| O quê | 3.0 | 4.0 |
|---|---|---|
| crosstab: alimentar a partir de um DataStore | of_set_data(ds) | of_from_datastore(ds), mesmos códigos |
| crosstab: um campo desconhecido (gralha) passado a uma adição, um filtro, um formato, uma ordem, um agrupamento de datas | 0, nada acontece | -5 |
crosstab: um tipo de filtro, uma agregação, uma parte de data fora da lista; uma medida calculada em Linhas; of_set_value_filter numa posição sem medida | 0; a posição deslizava para a última medida | -5 |
crosstab: of_set_layout de um texto que não é JSON; of_remove_calc_field / of_remove_calc_measure de um nome desconhecido | 0 | -5 |
crosstab: ad_value de ue_cell_double_clicked | o agregado bruto (400 sob « 80,0 % »), 0 para uma célula vazia | o valor apresentado (0.8), NULL para uma célula vazia; um membro vazio vale null nos tuplos |
| crosstab: o mesmo campo em Linhas (ou Colunas, Filtros) E em Valores | dependia da ordem das chamadas: o valor desaparecia; Remover numa dimensão retirava tudo | permitido em todo o lado; adicionar ou mover uma dimensão mantém os valores, Remover só retira o chip visado |
| crosstab: um membro vazio (NULL, texto vazio); um texto com tabulação ou quebra de linha no DataStore | « null » ou uma linha sem rótulo; linhas fantasma, colunas desfasadas | um único membro (vazio), em último; o texto fica na sua linha |
crosstab: is_label após um novo of_from_datastore; is_label = "" | perdido; um chip sem texto | mantido; "" repõe o cabeçalho do DataWindow |
| crosstab: Ctrl+C no modo de demonstração | ue_copy levantado, área de transferência escrita | recusado como uma exportação, a grelha di-lo |
crosstab: of_collapse_all; filtro de membros da grelha; of_export_xlsx acima de 16 384 colunas; exportações em VALUES_ROWS | só as linhas; aplicado a cada caixa; um ficheiro ilegível; as medidas lado a lado | linhas e colunas; aplicado com OK (no máximo 10 000 membros listados); recusado, ue_xlsx_saved diz porquê; como no ecrã |
A receita: (1) substitua of_set_data por of_from_datastore; (2) se ignorava o código devolvido por of_add_*_field ou por um filtro, verifique < 0 — uma gralha finalmente vê-se; (3) em ue_cell_double_clicked, teste IsNull(ad_value) antes de calcular, e leia ad_value como o valor apresentado (uma parte, não uma soma, num modo « % »).
11.34 Base comum: of_count e of_keys_at contam em long #
of_count devolvia um integer e of_keys_at recebia uma posição integer — em todos os componentes, nos seus handles e nos objetos não visuais que os têm (commandpalette, messagebox, speechout, toaster). Para lá de 32 767 elementos a contagem transbordava: um calendário (scheduler) alimentado por um DataStore de 40 000 linhas deixava de se contar, e as suas últimas linhas não se percorriam. As quatro assinaturas são agora long: long of_count ( ), long of_count ( string as_keys ), string of_keys_at ( long al_index ), string of_keys_at ( string as_keys, long al_index ).
A receita: uma chamada não muda. Uma variável integer que recebe of_count() continua certa até 32 767: declare-a long. Um descendente que redefinia of_count ou of_keys_at adota a nova assinatura — o compilador mostra-lhe a linha.
11.35 shellexplorer: uma actualização que mantém o estado, cada linha por si #
A revisão do explorador da shell mantém os seus eventos: of_select, of_expand e of_collapse lançam-nos como um clique, como na 3.0. of_refresh e ib_show_files já não fecham a árvore. Novidades: is_file_filter (os ficheiros mostrados), ib_show_hidden (os itens ocultos, por predefinição a definição do Explorador), ib_enabled e of_refresh(caminho), que relê um só ramo.
| O quê | 3.0 | 4.0 |
|---|---|---|
shellexplorer: of_refresh(), ou ib_show_files alterado | a árvore fechava-se, a selecção desaparecia sem evento | os ramos abertos e a selecção voltam, encontrados pelo seu caminho; uma selecção que já não existe dispara ue_selected("", "") |
shellexplorer: of_expand, of_select, of_collapse de um caminho vazio | 0 | -5 |
shellexplorer: of_expand de um ficheiro ou de uma pasta sem filhos | nada | ue_path_not_found(…, "expand", "not a branch") |
shellexplorer: of_keys_at(caminho, i) | caminho/filho, que nada sabia reler | o caminho do filho, inteiro: volta a of_has, of_select, of_expand |
| shellexplorer: a mesma pasta em dois níveis (a Música do Ambiente de trabalho e a da pasta do utilizador) | um clique, um chevron ou um duplo clique numa agia sobre a outra | cada linha responde por si |
| shellexplorer: ficheiros e pastas ocultos | nunca mostrados | mostrados conforme a definição do Explorador do posto, ou ib_show_hidden |
| shellexplorer: um ramo numa partilha que não responde | «…» para sempre, mesmo fechada e reaberta | ue_error «… : timeout» ao fim de 30 segundos; o ramo volta a ser pedido ao reabrir |
A receita: (1) ue_selected e ue_expanded são lançados também após um of_select ou um of_expand do seu código, uma vez alcançada a pasta (um caminho ainda por ler chega um pouco mais tarde): faça o seu trabalho no evento, não logo atrás da chamada, ou releia of_selected_key() quando a selecção tiver chegado; (2) em ue_selected, trate as_path = "" (a selecção desapareceu); (3) teste -5 num caminho vazio; (4) defina ib_show_hidden = false se os seus utilizadores nunca devem ver itens ocultos, diga o que disser o Explorador deles.
11.36 commandpalette: cada objeto só mexe na sua paleta, um fecho que se anuncia sempre, a língua da aplicação #
Só há uma paleta no ecrã de cada vez: quando um segundo objeto paleta abre a sua, substitui a primeira. Um objeto passa a responder só pela sua paleta e pelo seu atalho. ue_opened e ue_closed continuam a ser disparados em of_open / of_close: dizem o ciclo de vida da janela, não um gesto (mesma regra que os leitores de áudio e vídeo). Novidades: of_insert_command (um comando numa posição escolhida), of_anchor_under (a paleta sob um controlo, em píxeis de ecrã), e no handle is_group, is_hint, is_keywords, is_icon.
| O quê | 3.0 | 4.0 |
|---|---|---|
commandpalette: ue_closed | sem argumento; nada de nada quando a paleta morria antes de aparecer (fechada ou substituída logo, janela recusada) | ue_closed(string as_reason) segue cada of_open que devolveu 0: "", cancelled, failed ou blocked |
commandpalette: of_is_open, of_close, of_reset, destruir um objeto cuja paleta foi substituída pela de outro | respondiam VERDADEIRO pela paleta do outro, e fechavam-na | só respondem pela sua paleta: FALSO, e nada é fechado |
| commandpalette: destruir (ou repor) um objeto cujo atalho foi retomado por outro objeto paleta da mesma janela | retirava o atalho do outro: a tecla já não respondia em lado nenhum | o atalho do outro fica |
commandpalette: of_register_shortcut de uma tecla que o gancho não nomeia (ctrl+ù, win+k, space sem modificador) | 0 («posto»), e a tecla nunca fazia nada | -5; o atalho anterior mantém-se |
commandpalette: of_register_shortcut com is_shortcut vazio e nenhum atalho posto | 0 | 2 |
commandpalette: of_add_command de uma chave que contém uma vírgula | 0 — e is_recent relia-a como dois comandos | -5 |
| commandpalette: um grupo declarado em várias vezes (File, Edit, depois File) | dois cabeçalhos «File» | um só, no lugar da sua primeira aparição; a ordem dos comandos mantém-se no grupo |
| commandpalette: a pesquisa e os acentos | preferences não encontrava «Préférences» | os acentos não contam |
| commandpalette: a língua | a paleta falava inglês fosse qual fosse PBT_SetLanguage | a língua da aplicação; um is_placeholder definido por si não é traduzido |
| commandpalette: o atalho mostrado numa linha, teclado AZERTY; AltGr na pesquisa | Ctrl+A lia-se Ctrl+Q; escrever € (AltGr+E) lançava o comando mostrado como Ctrl+Alt+E | a tecla é lida como a DLL a nomeia; um carácter escrito nunca é um atalho |
commandpalette: um atalho posto sem ipo_owner (toda a aplicação) antes do atalho de uma janela, na mesma tecla | ganhava também nessa janela | o atalho da janela passa primeiro |
commandpalette: POSITION_ABSOLUTE | um comando de chave x ou y levava a paleta para a borda do ecrã; com dois ecrãs ia para o da janela | il_x / il_y mantêm-se, no ecrã do ponto pedido |
commandpalette: inv_pump | variável interna que ficou pública | protegida: não faz parte da API, nada a ler nem a escrever |
commandpalette: um comando cujo texto cita __license | a paleta não abria (-5) | abre: só uma palavra reservada escrita como chave continua recusada |
A receita: (1) se o seu código dispara ele próprio ue_closed(), passe-lhe um motivo (""); um script que apenas o recebe compila tal como está; (2) se esperava ue_opened após of_open, trate também ue_closed("cancelled"), "failed", "blocked"; (3) teste 2 e -5 no retorno de of_register_shortcut; (4) renomeie uma chave de comando que contenha uma vírgula.
11.37 radialmenu: uma chave simples que acerta, uma roda aberta que segue a aplicação, um rótulo que se lê #
A roda é desenhada uma vez, e a aplicação continua a correr enquanto está no ecrã: o que mudar entretanto passa a contar. O cubo já não escreve nada (não o fazia desde a 3.0, dissesse a documentação o que dissesse): é o ramo apontado que mostra o rótulo inteiro.
| O quê | 3.0 | 4.0 |
|---|---|---|
radialmenu: of_item com uma chave simples (of_item("csv")) | mudava o rótulo e o estado do único ramo que a levava, mas as suas cores não eram desenhadas, e o manípulo sobrevivia à remoção do pai | é resolvida no endereço completo (import/csv): mesmo manípulo, cores incluídas, libertado com o pai. Ambígua ou desconhecida: o manípulo não muda nada |
| radialmenu: um manípulo sobre um endereço ainda não adicionado | uma cor definida através dele coloria o ramo adicionado depois nesse endereço, mesmo após of_clear | não escreve nada; of_clear esquece todas as cores |
radialmenu: of_show | não devolvia nada | devolve um long: 0, ou -2 se o componente não estiver criado |
radialmenu: of_show(-1, -1) | abria a roda no cursor | abre-a no ponto (-1, -1), como qualquer coordenada negativa; no cursor é of_show() |
| radialmenu: um ramo retirado, esvaziado, desativado ou ocultado enquanto a roda está aberta | ainda se escolhia: ue_item_selected para um ramo desaparecido | já não se escolhe: ue_dismissed; of_clear, of_remove_item e of_reset fecham a roda aberta |
| radialmenu: clique direito noutro sítio enquanto a roda está aberta | a nova roda substituía a antiga sem ue_dismissed | ue_dismissed para a antiga, depois a nova roda |
| radialmenu: rótulo longo ou vazio | cortado a duas linhas e legível em lado nenhum; vazio, uma fatia sem nada | o ramo apontado mostra-o inteiro; vazio, mostra-se a chave |
| radialmenu: leitura da direita para a esquerda | a coroa girava no sentido horário, ← subia | a coroa gira no outro sentido, ← e → trocam de papel |
A receita: (1) of_show devolve um long: uma chamada simples compila tal como está; (2) substitua of_show(-1, -1) por of_show(); (3) se desfazia em ue_dismissed o que definia ao abrir, nada a fazer: agora chega também quando uma roda substitui outra; (4) um manípulo obtido com uma chave levada por dois ramos já não muda nada: dê o endereço.
11.38 toaster: eventos que dizem que toast, recusas que se dizem, um toast que espera ser visto #
Os três eventos do toast mudam de assinatura, of_add_button devolve um código, e um toast já não se perde quando a aplicação está minimizada.
| O quê | 3.0 | 4.0 |
|---|---|---|
toaster: ue_toast_clicked, ue_toast_action, ue_toast_dismissed | (string as_key …): as_key transportava o identificador do toast, como texto | (long al_id, string as_key …): al_id é o número devolvido por of_show, as_key o is_key do toast (vazio sem chave) |
toaster: of_add_button | devolvia o número de botões; uma chave já ocupada, uma chave vazia e um quarto botão passavam sem uma palavra | devolve 0; -5 sem acrescentar nada para uma chave vazia, já ocupada, que contém / ou uma barra vertical, ou um quarto botão. O número lê-se com of_count() |
toaster: of_show com uma definição fora dos limites | mostrava na mesma: um tipo desconhecido como informação, um canto desconhecido em cima à esquerda | devolve -5 e nada mostra: is_kind, is_position ou is_sound fora das suas constantes, il_max_visible fora de 0 a 20, il_timeout abaixo de TIMEOUT_AUTO |
toaster: a mesma is_key mostrada por dois toasters | o segundo substituía o toast do primeiro e ficava com os seus eventos; uma atualização mantinha o canto de origem | cada toaster tem o seu; uma atualização retoma também o canto, a fixação ao ecrã e a window de fixação |
| toaster: o som | um som de sistema em cada toast, informação e sucesso incluídos; nenhum para um toast saído da fila de espera | is_sound: SOUND_AUTO (predefinição) = apenas erro e aviso, SOUND_ALWAYS, SOUND_NEVER; reproduzido quando o toast é pedido, mesmo que espere o seu lugar |
toaster: toasts fixados ao ecrã a partir de duas windows, ou sem ipo_owner | ficavam exatamente uns sobre os outros; o limite contava-se por window | uma só pilha por monitor e por canto, e il_max_visible conta por monitor |
| toaster: um toast fixado a uma window minimizada | ia para -32 000 px e apagava-se sem ter sido visto | espera: não é apresentado e a contagem decrescente não corre até a window regressar |
| toaster: um toast que chega enquanto a pilha está sob o ponteiro | descontava o seu tempo e podia sair durante a leitura | nasce em pausa, como os outros |
toaster: PBT_SetLanguage, PBT_SetDefaultTheme, PBT_SetDefaultThemeAccent, PBT_SetDefaultFont, PBT_SetFlowDirection enquanto um toast está apresentado | não o alcançavam; o tamanho da letra ficava em 11 pt | seguem-no de imediato, tamanho da letra incluído |
| toaster: o texto de um toast | não se selecionava; agarrar a barra de deslocamento de um texto longo podia responder e fechar | seleciona-se e copia-se (clique direito, Copiar); a seleção e a barra de deslocamento já não fecham o toast |
toaster: il_button_count | variável pública | privada: leia o número de botões com of_count() |
toaster: um toast cujo texto cita __license | não era mostrado | é mostrado: só uma palavra reservada escrita como chave continua recusada |
toaster: of_close de um toast visível | nenhum evento | ue_toast_dismissed, como a sua cruz; um toast ainda em espera, nunca visto, não lança nada |
A receita: (1) acrescente long al_id como primeiro argumento dos seus ue_toast_clicked, ue_toast_action e ue_toast_dismissed, e substitua Long(as_key) por al_id; as_key é agora a chave do toast; (2) se lia o retorno de of_add_button como um número de botões, leia of_count(); (3) para manter um som numa informação ou num sucesso, defina is_sound = SOUND_ALWAYS.
11.39 messagebox: um campo obrigatório vazio nunca é validado, escolhas com chaves únicas #
Mudam cinco comportamentos; nenhuma assinatura.
| O quê | 3.0 | 4.0 | |
|---|---|---|---|
messagebox: ib_input_required e um botão predefinido com contagem decrescente (of_add_button_timed) | o clique automático validava a caixa com o campo vazio (of_show devolvia o botão, of_input_value uma cadeia vazia) | a contagem decrescente esgota-se sem clicar; o botão espera que o campo seja preenchido | |
| messagebox: Esc ou Alt+F4 num botão ao mesmo tempo predefinido e de cancelamento, campo obrigatório vazio | devolvia 1, como um clique nesse botão | devolve 0: fechada sem escolha | |
messagebox: of_add_choice | aceitava uma chave já usada, ou que contém / ou ` | ` | devolve -5 e não adiciona nada |
messagebox: of_choose sem nenhuma escolha | mostrava uma caixa com um único botão Cancelar | não mostra nada: cadeia vazia, e of_get_last_error diz «no choice to show» | |
messagebox: os botões das caixas prontas (of_info, of_confirm, of_yes_no, of_prompt…) quando a aplicação não definiu nenhuma língua | «Ok» | «OK», a palavra do catálogo inglês («Cancel», «Yes», «No» para os outros) |
A receita: (1) um campo obrigatório valida-se agora à mão — se contava com o clique automático para avançar, dê ao campo um valor predefinido (is_input_value); (2) dê a cada escolha uma chave única, sem / nem |, e teste -5 se as suas chaves vierem de dados.
11.40 Base comum: a língua anunciada por predefinição, os números decimais de qualquer posto #
Duas correções da base comum, válidas para todos os componentes; nenhuma assinatura muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
a língua anunciada por um componente (<html lang>) | o francês, enquanto a aplicação não escolhesse língua | o inglês, a língua predefinida dos componentes; a língua escolhida pela aplicação substitui-a sempre |
um número decimal dado a uma propriedade (id_*) | só a vírgula decimal era convertida: num posto cujo separador decimal é outro carácter, o valor não chegava | o separador decimal do posto, seja ele qual for, é convertido |
A receita: nada a mudar. Uma aplicação que escolhe a sua língua continua a vê-la aplicada; um leitor de ecrã que lia em francês um componente de uma aplicação inglesa passa a lê-lo em inglês.
11.41 Teclado, foco e espaço: o que os testes da 4.0 corrigiram #
Comportamentos vistos ao usar os componentes numa aplicação real; nenhuma assinatura muda, acrescenta-se um método.
| O quê | 3.0 | 4.0 |
|---|---|---|
Enter sobre um CommandButton PowerBuilder com o foco | nada (a tecla perdia-se) | o botão é premido (clicked), como numa caixa de diálogo do Windows; o botão predefinido de uma barra não |
Um componente desativado (ib_enabled = false) | Tab parava nele | sai da ordem de tabulação; reativado (ou of_reset), retoma o seu lugar |
Um atalho Ctrl sobre um carácter sem tecla própria (AZERTY: - na tecla 6, + com Shift) | Ctrl+- nunca encontrava o seu atalho | depois da tecla, o carácter da disposição ativa: Ctrl+-, Ctrl++, Ctrl+,, Ctrl+. funcionam em qualquer teclado |
| Escrever num menu aberto (pesquisa, letras sublinhadas) | uma tecla da fila de cima dava o seu algarismo (AZERTY: - chegava como 6) | o carácter da disposição; uma letra sublinhada &1 continua a responder à tecla 1 |
O calendário do seletor de data (toolbar) | só com o rato | também com o teclado: setas (dia, semana), Page Up/Down (mês), Home/End, Enter escolhe, Esc fecha |
| Alt com duas faixas (ou barras de menus) na mesma janela, sem subjanela entre elas | o primeiro criado | o mais próximo do foco no ecrã |
breadcrumb numa barra muito estreita | o primeiro segmento nunca cedia: o local atual reduzia-se a nada, o trilho transbordava | depois do meio, o local atual cede até uma letra e «…», depois o primeiro segmento; nada sai da barra |
menubar: uma escolha feita com o rato no menu pendente | o foco ficava na barra (Editar > Colar não colava em lado nenhum) | o foco volta ao controlo que o tinha |
ribbon: escrever numa caixa de combinação e depois escolher na sua lista | dois ue_combo_changed: o texto escrito, depois a escolha | um só, a escolha |
toolbar: is_text = "" definido em ue_text_changed, o foco no campo | o texto antigo voltava, com um segundo evento | o campo fica vazio |
| O foco devolvido a um componente após uma janela da biblioteca (paleta de comandos) | a página, sem elemento: o cursor do editor de código tinha desaparecido | o elemento que o tinha |
Um rótulo com letra sublinhada (&File) da direita para a esquerda | letras fora de ordem («ileF») | a palavra lê-se pela ordem |
n_pbt_utils.of_dir_folders(as_dir, ref as_names[]) | DirList numa ListBox: 4,5 s para 30 000 pastas, e a pasta atual da aplicação mudava | novo: as subpastas tal como o Explorador as mostra, ordenadas, numa passagem; -4 ilegível, -5 caminho vazio |
breadcrumb: of_add_children(as_keys, as_child_keys[], as_texts[]) | um ramo de cada vez (of_add_child): 30 000 subpastas abriam o menu em mais de 20 s | novo: todo um nível numa chamada |
A receita: nada a mudar. Uma aplicação cujo CommandButton com o foco devia ignorar Enter desativa-o (Enabled = false) ou retira-lhe o foco; para uma pasta volumosa, substitua o ciclo de of_add_child por um único of_add_children.
11.42 Dados e teclado: o que o segundo lote de testes da 4.0 corrigiu #
Comportamentos vistos ao usar os componentes de dados numa aplicação real; nenhuma assinatura muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
| Enter ou Esc premidas num componente que não as toma | perdidas: o CommandButton PowerBuilder Default ou Cancel não disparava | a tecla volta à janela PowerBuilder, como promete o capítulo 6.4: Esc prime o botão Cancel, Enter o botão Default |
PBT_SetLanguage seguido logo de uma ordem ao componente | o texto de um evento lançado por essa ordem (ue_error de xmltree) ficava na língua anterior | a língua vale a partir da ordem seguinte |
jsontree, xmltree: o foco dado ao componente (of_focus_webview, a tecla Tab) | ficava na página: as setas e Enter não iam a lado nenhum | a árvore toma-o; F3 e Shift+F3 passam à ocorrência seguinte ou anterior da pesquisa |
xmltree: um erro assinalado DEPOIS do último carácter da sua linha | nenhuma coluna sublinhada | o fim da linha é marcado (↵) |
codeeditor com quebra de linha (ib_wrap) | a faixa il_doc_line podia ficar uma fila acima, no fim da linha anterior | as faixas cobrem todas as filas da sua linha e seguem o redimensionamento |
codeeditor: « Substituir tudo » e of_replace_all num texto longo | vários segundos quando o foco estava no editor; além disso, of_replace_all podia devolver 0 | instantâneo, e o número de substituições é devolvido; Ctrl+H com uma pesquisa vazia põe o cursor em « Procurar » |
crosstab: « Adicionar às colunas » (ou linhas, filtros) a partir do menu de um chip, pelo teclado | o foco perdia-se; só Enter abria o menu de um chip | o foco segue o chip para a sua nova zona; Shift+F10 e a tecla Menu também abrem o seu menu |
json: milhares de of_add_* seguidos | quase um segundo para 2 000 linhas | algumas dezenas de milissegundos; o documento é o mesmo |
A receita: nada a mudar. Uma aplicação que tratava ela própria Esc premida num componente (um atalho registado com of_register_shortcut) mantém-no: um atalho vem antes da janela.
11.43 Conteúdo e média: o que o terceiro lote de testes da 4.0 corrigiu #
Comportamentos vistos ao usar os componentes de conteúdo e média numa aplicação real; nenhuma assinatura muda.
| O quê | 3.0 | 4.0 |
|---|---|---|
speechout: of_speak e depois of_pause no mesmo script | ue_started e a primeira ue_sentence chegavam antes de ue_paused: a voz era anunciada como iniciada | ue_started é lançado quando a voz começa realmente a falar; uma pausa posta antes retém-na: nada é dito nem anunciado até of_resume |
speechout: uma língua sem voz exata no computador (fr-CA onde só há fr-FR) | ue_started anunciava a língua pedida (fr-CA) | ue_started anuncia a língua realmente lida (fr-FR), depois de ue_voice_fallback |
webbrowser: Tab depois do último controlo da barra de endereços | o foco saía do componente para a janela PowerBuilder | o foco entra no site, como num navegador; Shift+Tab a partir do site volta à barra |
webbrowser: ib_private = true posto quando a navegação já é privada | sem efeito: o site voltava a encontrar o que tinha guardado na sessão privada | de cada vez uma sessão privada nova e vazia |
video em ecrã inteiro: uma caixa modal da aplicação (um MessageBox em ue_ended) | escondida sob o filme, que lhe retirava o teclado: a aplicação parecia bloqueada | o filme cede: a caixa passa à frente e recebe o teclado; ao fechá-la, o filme retoma o ecrã e Esc sai dele |
tilesbox: uma seta no limite, ao lado de um mosaico mais pequeno | Seta para cima num mosaico grande da primeira fila saltava para o lado, para o pequeno vizinho | só conta um mosaico inteiramente para lá do limite: no limite, o foco fica onde está |
dockcontainer: il_back_color / il_text_color de um painel empilhado | perdidas assim que o seu separador ficava ativo (tomava o acento do tema) | o separador ativo mantém as cores do painel, como a sua lingueta na calha |
progressbar: id_value posto em cada volta de um ciclo longo | cerca de 2,5 s para 20 000 linhas | bem menos de um segundo; a barra continua a avançar durante o ciclo |
A receita: nada a mudar. Uma aplicação que contava com ue_started para saber que of_speak tinha sido aceite lê antes o seu código de retorno (0); a que compara a língua de ue_started com is_lang fica agora também a saber da substituição por essa diferença, além de ue_voice_fallback.
11.44 Dados: ler uma célula, ordenar e pesquisar com mais precisão (json, jsontree, xmltree, crosstab) #
Estes acréscimos da 4.0 não retiram nenhuma assinatura. Dois mudam o que vê sem que tenha escrito nada: Ctrl+C do crosstab copia agora os cabeçalhos, e ue_cell_double_clicked recebe mais um argumento.
| O quê | 3.0 | 4.0 |
|---|---|---|
crosstab: ue_cell_double_clicked | ( string as_row_tuple_json, string as_col_tuple_json, double ad_value ) | ( string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, double ad_value ): ai_measure é a posição do valor clicado duas vezes em Valores, a partir de 1; com os dois tuplos, é o endereço que of_get_cell_value relê |
crosstab: Ctrl+C sobre células | só os números | os cabeçalhos com elas: os nomes das colunas numa primeira linha, o membro de cada linha (o seu caminho, «North / Boston») numa primeira coluna; ib_copy_headers = false dá só os números |
crosstab: of_remove_field, of_get_cell_value | — | novos: retirar um campo de todas as zonas sem reconstruir a disposição; ler o valor de uma célula pelos seus tuplos e pela posição da sua medida |
json: of_get_array, of_pretty (long al_indent) | — | novos: todos os elementos de um array numa chamada; uma indentação em espaços, ou o documento compacto numa linha com 0 |
jsontree, xmltree: a pesquisa | sempre sem distinguir maiúsculas, e dentro das palavras | ib_find_match_case e ib_find_whole_word, como o codeeditor, com os botões Aa e ab da caixa de pesquisa; por predefinição, a pesquisa continua a ser a da 3.0 |
A receita: um script de ue_cell_double_clicked não tem nada a mudar, o argumento acrescenta-se antes do valor. Uma aplicação que cola o resultado de Ctrl+C num processamento que só espera números define ib_copy_headers = false.
11.45 Navegação e contentores: separadores pelo teclado, painéis com um duplo clique (tab, dockcontainer, ribbon, stepbar, listbar) #
Estes acréscimos da 4.0 não retiram nenhuma assinatura. Três gestos mudam o que um utilizador vê sem que tenha escrito nada: o clique do meio e Ctrl+Tab num tab, e o duplo clique num painel de dockcontainer ou na barra de título da sua janela flutuante.
| O quê | 3.0 | 4.0 |
|---|---|---|
tab: clique do meio num separador | nada | fecha um separador que se pode fechar, pelo mesmo caminho que a sua cruz: ue_tab_closing se ib_veto_close = true, depois ue_tab_closed; um separador que não se pode fechar, ou desativado, não faz nada |
tab: Ctrl+Tab, Ctrl+Shift+Tab, Ctrl+Page Down / Page Up | nada | o separador seguinte ou anterior que pode ficar ativo, em ciclo, esteja o teclado na banda ou numa página alojada (um controlo PowerBuilder, outro componente); é um gesto: ue_selection_changing se ib_veto_selection = true, depois ue_selection_changed. A partir de um controlo fora do tab, a tecla fica com a janela |
dockcontainer: duplo clique num cabeçalho ou num separador; na barra de título de uma janela flutuante | nada; a janela flutuante maximizava-se | destaca o painel numa janela flutuante (ue_panel_floated); na barra de título dessa janela, volta a acoplá-lo no seu lugar (ue_panel_docked), como a sua cruz |
dockcontainer: clique direito num cabeçalho ou num separador | nada | um menu Destacar, Fechar, Fechar os outros (os outros painéis que se podem fechar do mesmo grupo); cada fecho faz a sua própria pergunta |
dockcontainer: ib_veto_close, ue_panel_closing, of_close_panel, n_pbt_dock_panel.ib_closable | — | novos: a pergunta antes do fecho de um painel (opcional, false por predefinição), o fecho pelo código (-4 se o recusar, -5 para o painel principal ou um painel que não se pode fechar), e a possibilidade de fechar mudada em direto |
ribbon: n_pbt_ribbon_item.is_image, id_min, id_max, id_step | fixados na adição | a imagem de um controlo e o intervalo de um contador mudam em direto e releem-se; o valor de um contador é trazido para o novo intervalo sem lançar ue_value_changed, como id_value |
stepbar: STATE_WARNING, STATE_SKIPPED, NAV_VISITED | — | novos: um passo concluído com um aviso (marca âmbar), um passo ignorado (anel tracejado), e um modo em que qualquer passo já alcançado continua clicável, também para a frente depois de um recuo |
listbar: n_pbt_listbar_section.ib_pinned | — | novo: uma secção fixada no fundo da barra (Definições, Ajuda), que continua visível quando a barra se desloca, também no carril; a disposição gravada mantém a ordem das secções |
A receita: nada a mudar. Numa página de tab, Ctrl+Tab muda agora de separador mesmo quando o foco está num controlo da página, como numa folha de propriedades do Windows. Para maximizar uma janela flutuante do dockcontainer, o seu botão Maximizar continua lá.
11.46 Menus: o chevron da barra de menus, uma lista pendente na barra de ferramentas, dez mil comandos (menubar, toolbar, commandpalette) #
Estes acréscimos da 4.0 não retiram nenhuma assinatura. Muda um comportamento por predefinição: uma barra de menus demasiado estreita já não quebra a linha, recolhe os seus últimos títulos num chevron. E of_open de uma paleta de comandos já não recusa abrir sem ipo_owner nem ipo_receiver.
| O quê | 3.0 | 4.0 |
|---|---|---|
menubar: uma barra demasiado estreita para os seus títulos | quebrava a linha: a sua altura acompanhava as filas, ue_auto_height a cada mudança de largura | fica numa só linha: os títulos que não cabem, a partir do fim, passam para o menu de um chevron (as suas entradas em cascata, Alt + a sua letra abre-os a partir do chevron, as setas param nele como num título, à esquerda em RTL); a altura deixa de mudar. ib_wrap = true repõe o comportamento anterior |
menubar: ib_track_hover, ue_item_hover, of_add_header, n_pbt_menubar_menu.is_align | — | novos: a entrada apontada de um menu, para o texto de ajuda de uma barra de estado (opcional, false por predefinição; um endereço vazio ao fechar), cabeçalhos de secção num menu, e um menu no fim da barra (ALIGN_END, Ajuda) |
toolbar: of_add_combo, of_add_combo_item, of_remove_combo_item, of_clear_combo, ue_combo_changed, n_pbt_toolbar_item.ib_editable | — | novos: uma lista pendente na barra, editável ou não, que continua funcional recolhida no chevron; o seu evento tem o nome e o sentido do do friso |
commandpalette: duas paletas no mesmo ipo_owner | partilhavam a sua fila de eventos (uma podia receber o ue_closed da outra), e a segunda retomava o atalho da primeira | cada uma os seus eventos e o seu atalho; o mesmo atalho registado pela segunda passa para ela (1). of_open e of_register_shortcut já não devolvem -5 sem ipo_owner nem ipo_receiver: os eventos chegam sempre |
commandpalette: milhares de comandos | cada linha desenhada: a abertura e a escrita ficavam lentas | só as linhas visíveis são desenhadas: 10 000 comandos abrem-se e filtram-se sem espera |
| Atalhos de toda a biblioteca: AltGr + uma tecla que escreve um carácter (o euro de um teclado francês) | lançava o atalho Ctrl+Alt dessa tecla, também num campo PowerBuilder | o carácter é escrito, nenhum atalho é lançado; AltGr sozinho já não dá o teclado a uma barra de menus ou a um friso |
A receita: uma barra de menus cuja altura variável era desejada define ib_wrap = true; uma aplicação que reposicionava os seus controlos em ue_auto_height a cada redimensionamento já não tem nada a fazer depois do primeiro. Um atalho da aplicação em Ctrl+Alt + uma letra que o teclado do utilizador escreve com AltGr já não é lançado enquanto escreve: escolha outra tecla.
11.47 Conteúdo e media: um registo linha a linha, o tamanho real de uma imagem, um filme que espera (statictext, picture, video) #
Estes acréscimos da 4.0 não retiram nenhuma assinatura nem mudam nenhum valor por omissão. Dois comportamentos ficam mais precisos: o zoom de uma imagem pode passar o seu limite para atingir o tamanho real, e um filme de um URL reproduzido sem rede di-lo.
| O quê | 3.0 | 4.0 |
|---|---|---|
statictext: of_append_text, ib_follow_end | — | novos: um registo escrito linha a linha — só a linha acrescentada segue para o componente — e, como opção, a vista que fica em baixo enquanto o leitor não subir |
statictext: ib_auto_width, ue_auto_width | — | novos: o userobject assume a largura do seu texto (opcional, false por omissão), como ib_auto_height faz para a altura |
picture: id_max_zoom, a tecla 1 | o zoom parava em 8.0 vezes o enquadramento, acontecesse o que acontecesse: uma digitalização grande mostrada pequena nunca se lia píxel a píxel | o limite ajusta-se (id_max_zoom, 8.0 por omissão); a tecla 1 mostra o tamanho real, e o limite sobe até ele quando pede mais |
video: ue_buffering, of_is_buffering | um filme que esperava pelos seus dados ficava parado sem dizer nada | um anel na cor de destaque do tema roda sobre a imagem, e ue_buffering(true) e depois ue_buffering(false) enquadram a espera |
video: um filme de um URL enquanto o posto não tem rede | «este ficheiro não foi encontrado ou não pode ser reproduzido», ue_failed com REASON_UNSUPPORTED | «sem ligação de rede» sobre a imagem, ue_failed com REASON_NETWORK |
A receita: nada a mudar. Um registo que reescrevia is_text a cada linha passa para of_append_text; um código que testava REASON_UNSUPPORTED para um filme de um URL sem rede testa REASON_NETWORK.
11.48 Revisão de 03/10/2026: uma disposição reposta é anunciada, uma exportação para um caminho relativo cai no sítio certo (toolbar, crosstab) #
Nenhuma assinatura muda. Dois comportamentos alinham-se com a regra da biblioteca: qualquer mudança da disposição é anunciada, e um caminho relativo de escrita resolve-se como nas outras exportações.
| O quê | 3.0 | 4.0 |
|---|---|---|
toolbar: of_set_layout | nenhum evento | emite ue_layout_changed, como o dockcontainer e o datagrid: qualquer mudança da disposição é anunciada, venha do utilizador ou do seu código |
crosstab: of_export_csv, of_export_xlsx para um caminho relativo | escrito na pasta atual do momento — que um DirList ou uma caixa de ficheiros podiam ter mudado; ue_csv_saved / ue_xlsx_saved devolviam o caminho tal como dado | escrito na pasta onde a aplicação arrancou, como as outras exportações nativas; o evento devolve o caminho completo; um caminho que depende da pasta atual de uma unidade (\x, C:x) é recusado |
A receita: uma aplicação que guarda a disposição em ue_layout_changed volta a guardar o mesmo valor depois de of_set_layout — sem consequências. Uma exportação que contava com a pasta atual do momento indica um caminho completo.