# toolbar — `u_pbt_toolbar` #

← Référence des composants · Sommaire du guide

> Barre d'outils plate : plusieurs barres réparties sur des bandes, boutons, bascules, menus déroulants, champs de saisie, débordement automatique et déplacement à la poignée.

> ▶ Le voir en vrai — Application de démonstration, tuile Toolbar : l'aperçu, le code qui le produit et cette page, côte à côte.

## En bref #

Userobject | `u_pbt_toolbar`
Classes d'items | `n_pbt_toolbar_bar` (barre) → `n_pbt_toolbar_item` (outil)
Sert à | Remplacer une barre d'outils classique par une barre moderne, thémée, à plusieurs rangées réorganisables
Hauteur | Intrinsèque : la barre se cale toujours sur ses rangées, rien à activer — voir Hauteur automatique

## Démarrage rapide #

    // event open de la fenetre
    n_pbt_toolbar_bar lnv_bar

    // of_bar() rend la barre par defaut, toujours presente (id = MAIN_BAR)
    lnv_bar = uo_toolbar.of_bar(uo_toolbar.MAIN_BAR)

    lnv_bar.of_add_button(/*id*/ "save", /*text*/ "", /*image*/ "mono:img\save.svg", /*tooltip*/ "Enregistrer")
    lnv_bar.of_add_button(/*id*/ "find", /*text*/ "", /*image*/ "mono:img\find.svg", /*tooltip*/ "Rechercher")
    lnv_bar.of_add_separator()
    lnv_bar.of_add_button(/*id*/ "help", /*text*/ "Aide",  /*image*/ "", /*tooltip*/ "A propos")

    // event ue_clicked de uo_toolbar : (string as_bar, string as_id)
    choose case as_bar + "/" + as_id
        case "main/save" ; of_enregistrer()
        case "main/find" ; of_rechercher()
        case "main/help" ; of_aide()
    end choose

## Le modèle : barres, bandes, outils #

Une barre d'outils contient une ou plusieurs barres. Chaque barre est posée sur une bande (une rangée) et occupe une position dans cette rangée : deux barres sur la même bande se partagent la rangée, deux barres sur des bandes différentes s'empilent — exactement comme les barres d'outils Office classiques.

Les outils (boutons, bascules, menus, champs) appartiennent à une barre. Leur identifiant n'est unique qu'à l'intérieur de leur barre : l'accès passe donc toujours par le chemin complet.

    uo_toolbar.of_bar("main").of_item("save").ib_enabled = false

Les ajouts vivent eux aussi sur le handle du parent : on ajoute un outil à une barre, pas à la barre d'outils. Voir Socle commun · Les items pour le principe général.

## Propriétés #

Propriété | Type | Défaut | Rôle
--- | --- | --- | ---
`is_theme_style` | string | `fluent` | Style visuel du composant (constantes `THEME_STYLE_*`)
`is_theme_mode` | string | `light` | Variante claire ou sombre (constantes `THEME_MODE_*`)
`il_theme_accent` | long | `-1` | Couleur d'accent de ce composant (`-1` = accent du thème)
`is_tooltip` | string | `""` | Info-bulle simple affichée au survol du composant
`is_super_tooltip_title` | string | `""` | Titre de l'info-bulle enrichie (prend le pas sur `is_tooltip`)
`is_super_tooltip_text` | string | `""` | Texte de l'info-bulle enrichie (balisage riche accepté)
`is_super_tooltip_image` | string | `""` | Image de l'info-bulle enrichie
`ib_reorderable` | boolean | `false` | Permet à l'utilisateur de réorganiser les barres à la souris : les poignées de déplacement apparaissent et une barre peut être glissée vers une autre bande. Désactivé par défaut — une barre d'outils démontée par accident, c'est un appel au support. Votre code, lui, les réorganise dans tous les cas (`of_set_layout`, `of_add_bar`) : l'autorisation porte sur l'utilisateur, jamais sur l'application

### Constante #

Constante | Valeur | Rôle
--- | --- | ---
`MAIN_BAR` | `"main"` | Identifiant de la barre par défaut, toujours disponible sans avoir à la créer

## Méthodes #

Méthode | Rôle
--- | ---
`of_bar (string as_id)` → `n_pbt_toolbar_bar` | Rend le handle d'une barre (créé au premier accès)
`of_add_bar (string as_bar)` → `n_pbt_toolbar_bar` | Ajoute une barre et rend son handle
`of_add_bar (string as_bar, integer ai_band, integer ai_index)` → `n_pbt_toolbar_bar` | Ajoute une barre à une bande et à une position précises (les deux comptées à partir de 0)
`of_remove_bar (string as_id)` | Retire une barre et ses outils. Les autres gardent leur état vivant, et les bandes se resserrent derrière celle qui part. Ce n'est pas la masquer (`ib_visible` sur son handle) : masquer la garde dans le modèle, prête à revenir exactement où elle était ; retirer l'oublie
`of_get_layout ()` | Relit la disposition courante en JSON : quelle barre sur quelle bande, à quel rang, et visible ou non. À stocker, puis à rendre par `of_set_layout`
`of_set_layout (string as_layout_json)` | Restaure une disposition de barres précédemment reçue par `ue_layout_changed`
`of_clear ( )` | Supprime toutes les barres et tous les outils
`of_reset ( )` | Vide le contenu et remet les propriétés à leur défaut

### Sur une barre — `n_pbt_toolbar_bar` #

Membre | Type | Défaut | Rôle
--- | --- | --- | ---
`ii_band` | integer | `0` | Bande (rangée) qui porte la barre ; `0` = première rangée
`ii_index` | integer | `0` | Position de la barre dans sa bande
`ib_visible` | boolean | `true` | Montre ou masque une barre. Une barre masquée garde sa bande, son rang et ses items : la réafficher la remet exactement où elle était, sans rien reconstruire — c'est la différence avec `of_clear`, qui les perdrait
`of_item (string as_id)` → `n_pbt_toolbar_item` |  |  | Rend le handle d'un outil de cette barre
`of_add_button (as_id, as_text, as_image, as_tooltip)` → `n_pbt_toolbar_item` |  |  | Bouton d'action ; le clic déclenche `ue_clicked`
`of_add_toggle (as_id, as_text, as_image, as_tooltip)` → `n_pbt_toolbar_item` |  |  | Bascule à deux états ; le clic déclenche `ue_toggled`
`of_add_dropdown (as_id, as_text, as_image, as_tooltip)` → `n_pbt_toolbar_item` |  |  | Bouton à menu déroulant ; un choix déclenche `ue_menu_selected`
`of_add_label (as_id, as_text)` → `n_pbt_toolbar_item` |  |  | Libellé informatif, non cliquable
`of_add_textbox (as_id, as_text, ai_width, as_tooltip)` → `n_pbt_toolbar_item` |  |  | Champ de saisie ; Entrée ou perte du focus déclenche `ue_text_changed`. `ai_width` en pixels
`of_add_datepicker (as_id, as_date, as_tooltip)` → `n_pbt_toolbar_item` |  |  | Sélecteur de date ; un choix déclenche `ue_date_changed`. Dates au format `"aaaa-mm-jj"`
`of_add_separator ( )` |  |  | Trait vertical de séparation
`of_insert_button (as_id, as_text, as_image, as_tooltip, ai_index)` → `n_pbt_toolbar_item` |  |  | Bouton ajouté à la position choisie (premier = 0) plutôt qu'à la fin
`of_move_item (string as_id, integer ai_index)` |  |  | Déplace un outil à une autre position dans cette barre (premier = 0). Il garde son type, son menu et son état vivant : l'outil change de place, il n'est pas reconstruit. Vaut pour tous les types, donc les `of_add_*` sans `of_insert_*` insèrent en ajoutant puis en déplaçant
`of_remove_item (string as_id)` |  |  | Retire un outil de cette barre. La barre reste, et tout le reste avec elle, état vivant compris — seul l'outil nommé s'en va. Pour le faire aller et venir, `ib_visible` sur son handle le garde dans le modèle

### Sur un outil — `n_pbt_toolbar_item` #

Membre | Type | Défaut | Rôle
--- | --- | --- | ---
`ib_visible` | boolean | `true` | Montre ou masque un item. Il garde son rang dans la barre : le réafficher le remet exactement où il était, pas à la fin. À ne pas confondre avec `ib_enabled`, qui le laisse en place, grisé — masquez ce qui ne s'applique pas, grisez ce qui est momentanément indisponible
`ib_enabled` | boolean | `true` | Outil actif ou grisé
`ib_checked` | boolean | `false` | État d'une bascule (sans effet sur les autres types)
`is_text` | string | `""` | Libellé, balisage riche accepté
`is_shortcut` | string | `""` | Raccourci clavier (`"Ctrl+S"`), affiché dans l'info-bulle et actif
`of_add_menu_item (as_id, as_label, as_image)` |  |  | Entrée du menu d'un bouton déroulant
`of_add_menu_item (as_parent, as_id, as_label, as_image)` |  |  | Entrée en cascade, rangée sous une entrée existante
`of_add_menu_separator (as_id)` |  |  | Trait de séparation dans le menu

Les images acceptent toutes les formes reconnues par la bibliothèque : chemin, `mono:`, `tint:`, ressource de DLL.

## Événements #

Événement | Déclenché quand
--- | ---
`ue_clicked (string as_bar, string as_id)` | Un bouton est cliqué (ou déclenché par son raccourci)
`ue_toggled (string as_bar, string as_id, boolean ab_checked)` | Une bascule change d'état ; `ab_checked` porte le nouvel état
`ue_menu_selected (string as_bar, string as_dropdown, string as_id)` | Une entrée de menu déroulant est choisie
`ue_text_changed (string as_bar, string as_id, string as_text)` | Un champ de saisie est validé (Entrée ou perte du focus)
`ue_date_changed (string as_bar, string as_id, string as_date)` | Une date est choisie (`"aaaa-mm-jj"`)
`ue_bar_reordered (string as_id, integer ai_band, integer ai_index)` | L'utilisateur a fait glisser une barre par sa poignée vers une autre bande ou un autre rang (demande `ib_reorderable`). Dit quelle barre a bougé et où elle atterrit, là où `ue_layout_changed` porte l'arrangement entier. Bande et rang partent de 1
`ue_layout_changed (string as_layout_json)` | L'arrangement a changé — l'utilisateur a fait glisser une barre à la poignée, ou votre propre code en a déplacé ou masqué une. Porte la disposition entière, pas seulement ce qui a bougé
`ue_auto_height (long al_height)` | La hauteur idéale a changé et la barre s'y est ajustée — toujours actif : le nombre de rangées dicte la hauteur
`ue_ready ( )` | Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué
`ue_runtime_missing ( )` | Le runtime WebView2 est absent : le composant reste vide
`ue_bg_color (long al_color)` | Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (`backcolor`)

## Exemples #

### Bascules pré-cochées et outil grisé #

    n_pbt_toolbar_bar lnv_bar
    lnv_bar = uo_toolbar.of_bar(uo_toolbar.MAIN_BAR)

    lnv_bar.of_add_toggle(/*id*/ "bold",   /*text*/ "", /*image*/ "mono:img\bold.svg",   /*tooltip*/ "Gras")
    lnv_bar.of_add_toggle(/*id*/ "italic", /*text*/ "", /*image*/ "mono:img\italic.svg", /*tooltip*/ "Italique")
    lnv_bar.of_add_separator()
    lnv_bar.of_add_button(/*id*/ "undo",   /*text*/ "", /*image*/ "mono:img\undo.svg",   /*tooltip*/ "Annuler")

    // Chaque outil se pilote par son handle, obtenu depuis SA barre
    lnv_bar.of_item("bold").ib_checked = true    // bascule pre-cochee
    lnv_bar.of_item("undo").ib_enabled = false   // rien a annuler pour l'instant

    // event ue_toggled de uo_toolbar
    if as_id = "bold" then of_appliquer_gras(ab_checked)

### Menu déroulant en cascade #

    n_pbt_toolbar_bar  lnv_bar
    n_pbt_toolbar_item lnv_menu

    lnv_bar = uo_toolbar.of_bar(uo_toolbar.MAIN_BAR)

    // Le menu se remplit par le handle rendu par of_add_dropdown
    lnv_menu = lnv_bar.of_add_dropdown(/*id*/ "export", /*text*/ "Exporter", &
                                       /*image*/ "mono:img\save.svg", /*tooltip*/ "Exporter le dossier")
    lnv_menu.of_add_menu_item(/*id*/ "exp_pdf", /*label*/ "PDF",  /*image*/ "")
    lnv_menu.of_add_menu_item(/*id*/ "exp_csv", /*label*/ "CSV",  /*image*/ "")
    lnv_menu.of_add_menu_separator(/*id*/ "sep1")

    // Sous-menu : on cite l'entree parente en premier argument
    lnv_menu.of_add_menu_item(/*id*/ "exp_img", /*label*/ "Image...", /*image*/ "")
    lnv_menu.of_add_menu_item(/*parent*/ "exp_img", /*id*/ "exp_png", /*label*/ "PNG", /*image*/ "")
    lnv_menu.of_add_menu_item(/*parent*/ "exp_img", /*id*/ "exp_jpg", /*label*/ "JPEG", /*image*/ "")

    // event ue_menu_selected de uo_toolbar : (as_bar, as_dropdown, as_id)
    if as_dropdown = "export" then of_exporter(as_id)

### Champ de recherche et sélecteur de date #

    n_pbt_toolbar_bar lnv_bar
    lnv_bar = uo_toolbar.of_bar(uo_toolbar.MAIN_BAR)

    lnv_bar.of_add_button(/*id*/ "save", /*text*/ "", /*image*/ "mono:img\save.svg", /*tooltip*/ "Enregistrer")
    lnv_bar.of_item("save").is_shortcut = "Ctrl+S"    // raccourci actif et affiche
    lnv_bar.of_add_separator()

    // 160 px de large ; la saisie remonte a la validation
    lnv_bar.of_add_textbox(/*id*/ "search", /*text*/ "", /*width*/ 160, /*tooltip*/ "Rechercher (Entree pour valider)")

    lnv_bar.of_add_label(/*id*/ "lbl_due", /*text*/ "Echeance :")
    lnv_bar.of_add_datepicker(/*id*/ "due", /*date*/ "2026-07-11", /*tooltip*/ "Date d'echeance")

    // event ue_text_changed de uo_toolbar
    if as_id = "search" then of_filtrer(as_text)

    // event ue_date_changed de uo_toolbar : as_date au format "aaaa-mm-jj"
    if as_id = "due" then id_echeance = Date(as_date)

### Deux barres et disposition mémorisée #

L'utilisateur peut saisir une barre par sa poignée (à gauche de la barre) et la déplacer sur une autre bande ou à une autre position. Conservez la disposition à la fermeture, restituez-la à l'ouverture.

    n_pbt_toolbar_bar lnv_std, lnv_fmt

    lnv_std = uo_toolbar.of_bar(uo_toolbar.MAIN_BAR)
    lnv_std.of_add_button(/*id*/ "new",  /*text*/ "Nouveau", /*image*/ "", /*tooltip*/ "")
    lnv_std.of_add_button(/*id*/ "open", /*text*/ "Ouvrir",  /*image*/ "", /*tooltip*/ "")

    // Seconde barre, posee sur la bande 1 (deuxieme rangee), en premiere position
    lnv_fmt = uo_toolbar.of_add_bar(/*bar*/ "format", /*band*/ 1, /*index*/ 0)
    lnv_fmt.of_add_toggle(/*id*/ "bold", /*text*/ "G", /*image*/ "", /*tooltip*/ "Gras")

    // On peut aussi replacer une barre a tout moment par ses proprietes
    uo_toolbar.of_bar("format").ii_band  = 0
    uo_toolbar.of_bar("format").ii_index = 1    // deuxieme barre de la premiere rangee

    // event ue_layout_changed de uo_toolbar : conserver la disposition choisie
    is_disposition = as_layout_json

    // A l'ouverture suivante : restituer ce que l'utilisateur avait arrange
    if is_disposition <> "" then uo_toolbar.of_set_layout(is_disposition)

### Débordement : « Plus d'outils » #

Quand la largeur ne suffit plus, les outils qui ne tiennent pas sont repliés dans un menu Plus d'outils signalé par un chevron en fin de barre. C'est automatique, il n'y a rien à programmer : les outils repliés restent cliquables et déclenchent les mêmes events. Un champ replié — zone de saisie ou sélecteur de date — reste un vrai champ : on y tape, on y choisit une date, et l'event part comme si l'outil était resté dans la barre.

### Hauteur automatique #

Rien à activer : le nombre de rangées (`of_set_layout`) dicte la hauteur, la barre s'y ajuste seule et vous prévient.

    // event ue_auto_height de uo_toolbar
    uo_contenu.y      = uo_toolbar.y + al_height
    uo_contenu.height = parent.workspaceheight() - uo_contenu.y

Voir Socle commun.

## Bonnes pratiques #

- Servez-vous de `MAIN_BAR` tant qu'une seule barre suffit : elle existe déjà, inutile de l'ajouter.
- Rangez toujours un outil par son chemin — `of_bar(...).of_item(...)` — et non par son seul identifiant : c'est ce qui rend les identifiants réutilisables d'une barre à l'autre.
- Groupez les outils apparentés avec `of_add_separator()` plutôt que par des barres supplémentaires.
- Sur les boutons à icône seule, renseignez toujours l'info-bulle : c'est le seul libellé dont dispose l'utilisateur.
- Si vous laissez l'utilisateur réorganiser les barres, mémorisez `ue_layout_changed` et rejouez `of_set_layout` à l'ouverture, sinon l'effort est perdu à chaque lancement.
- Appelez `of_reset()` avant de reconstruire entièrement la barre d'outils pour un autre contexte.
- Quand les commandes deviennent trop nombreuses pour une barre, passez au ribbon, organisé par onglets et groupes.

← Référence des composants · Sommaire du guide