# tilesbox — `u_pbt_tilesbox` #

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

> Panneau de tuiles groupées façon écran d'accueil : quatre tailles de tuile, couleurs, pastilles, tuiles animées, groupes repliables et réorganisation à la souris.

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

## En bref #

Userobject | `u_pbt_tilesbox`
Classes d'items | `n_pbt_tilesbox_group` (groupe) → `n_pbt_tilesbox_tile` (tuile)
Sert à | Offrir un écran d'accueil ou un lanceur de fonctions : des tuiles cliquables, lisibles de loin, rangées par thème
Options opt-in | —

## Démarrage rapide #

    // event open de la fenetre
    n_pbt_tilesbox_group lnv_grp

    // of_add_group rend le handle du groupe : on y accroche ses tuiles
    lnv_grp = uo_tuiles.of_add_group(/*group_id*/ "gestion", /*title*/ "Gestion")

    lnv_grp.of_add_tile(/*id*/ "clients",   /*label*/ "Clients",   /*icon_file*/ "mono:img\clients.svg",   /*size*/ "medium")
    lnv_grp.of_add_tile(/*id*/ "factures",  /*label*/ "Factures",  /*icon_file*/ "mono:img\factures.svg",  /*size*/ "medium")
    lnv_grp.of_add_tile(/*id*/ "stock",     /*label*/ "Stock",     /*icon_file*/ "mono:img\stock.svg",     /*size*/ "small")

    // event ue_tile_clicked de uo_tuiles : (string as_group, string as_id)
    choose case as_group + "/" + as_id
        case "gestion/clients"  ; open(w_clients)
        case "gestion/factures" ; open(w_factures)
        case "gestion/stock"    ; open(w_stock)
    end choose

## Le modèle : groupes et tuiles #

Le panneau contient des groupes, chacun avec son titre et son entête repliable. Les tuiles appartiennent à un groupe : leur identifiant n'est unique qu'à l'intérieur de ce groupe. L'accès passe donc toujours par le chemin complet, et les ajouts vivent sur le handle du groupe.

    // Chemin obligatoire : groupe puis tuile
    uo_tuiles.of_group("gestion").of_tile("factures").is_badge = "12"

Les events portent eux aussi le chemin complet (`as_group` puis `as_id`). Voir Socle commun · Les items.

## Propriétés #

Propriété | Type | Défaut | Rôle
--- | --- | --- | ---
`ib_reorderable` | boolean | `false` | Autorise l'utilisateur à déplacer les tuiles à la souris (déclenche `ue_tile_moved`)
`is_scroll` | string | `SCROLL_VERTICAL` | Sens de défilement : `SCROLL_VERTICAL` (les tuiles passent à la ligne) ou `SCROLL_HORIZONTAL` (colonnes façon écran d'accueil)
`ib_show_group_headers` | boolean | `true` | `false` masque les entêtes de groupe. Utile quand le panneau ne contient qu'un seul groupe : il n'y a rien à nommer et l'entête ne fait que manger de la hauteur. Sans entête il n'y a plus de chevron : les groupes s'affichent toujours dépliés
`ii_anim_duration` | integer | `180` | Durée en millisecondes de l'animation de repli / dépli d'un groupe ; `0` = instantané
`ii_tile_unit` | integer | `0` | Taille de base d une tuile, en pixels : chaque format (petite, moyenne, large, grande) en est un multiple, donc une valeur rend tout le tableau plus dense ou plus aéré. `0` la rend au thème
`ii_badge_size` | integer | `0` | Hauteur des pastilles de tuile en pixels, pour toute la boîte (`0` = la taille qui vient du thème). La taille de la police suit toute seule. La couleur d une pastille appartient à la tuile parce qu elle veut dire quelque chose ; sa taille, non
`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

## Méthodes #

Méthode | Rôle
--- | ---
`of_group (string as_id)` → `n_pbt_tilesbox_group` | Rend le handle d'un groupe (créé au premier accès)
`of_add_group (string as_group_id, string as_title)` → `n_pbt_tilesbox_group` | Ajoute un groupe et rend son handle
`of_remove_group (string as_id)` | Supprime un groupe et toutes ses tuiles
`of_insert_tile (string as_group, string as_id, string as_text, integer ai_index)` | Insère une tuile à une position précise dans son groupe (position comptée à partir de 0)
`of_insert_tile (string as_group, string as_id, string as_text, string as_image, string as_size, integer ai_index)` | Idem, avec l’icône et la taille (`small` / `medium` / `wide` / `large`) : une tuile est une image avec un libellé dessous, et sa taille se voit dans la grille
`of_move_tile (string as_group, string as_id, integer ai_index)` | Déplace une tuile existante à une autre position de son groupe, en conservant son état
`of_remove_tile (string as_group, string as_id)` | Supprime une seule tuile, le reste du panneau est préservé
`of_clear ( )` | Vide le panneau (groupes et tuiles)
`of_get_layout ( )` | Relit la disposition courante en JSON : groupes, tuiles, ordre et tailles. À stocker, puis à rendre par `of_set_layout`
`of_set_layout (string as_state_json)` | Restaure une disposition lue avec `of_get_layout` ou reçue par `ue_layout_changed`
`of_reset ( )` | Vide le contenu et remet les propriétés à leur défaut

### Sur un groupe — `n_pbt_tilesbox_group` #

Membre | Type | Défaut | Rôle
--- | --- | --- | ---
`is_title` | string | `""` | Titre affiché dans l'entête, balisage riche accepté
`ib_collapsed` | boolean | `false` | Groupe replié : ses tuiles sont masquées sous l'entête
`ib_enabled` | boolean | `true` | Groupe entier grisé et inerte
`ib_visible` | boolean | `true` | Groupe masqué, sans être supprimé du modèle
`of_tile (string as_id)` → `n_pbt_tilesbox_tile` |  |  | Rend le handle d'une tuile de ce groupe
`of_add_tile (as_id, as_label, as_icon_file, as_size)` → `n_pbt_tilesbox_tile` |  |  | Ajoute une tuile à ce groupe et rend son handle

### Sur une tuile — `n_pbt_tilesbox_tile` #

Membre | Type | Défaut | Rôle
--- | --- | --- | ---
`is_size` | string | `SIZE_MEDIUM` | Taille : `SIZE_SMALL`, `SIZE_MEDIUM`, `SIZE_WIDE`, `SIZE_LARGE`
`il_back_color` · `il_text_color` | long | `-1` | Fond et texte propres à la tuile, en `RGB(r,v,b)` (`-1` = ce que donne le thème)
`il_back_color_hover` · `il_text_color_hover` | long | `-1` | Les deux mêmes, mais sous le pointeur
`is_badge` | string | `""` | Pastille affichée dans l'angle de la tuile (un compteur, un état court)
`il_badge_color` | long | `0` | Fond de la pastille, en RGB PowerBuilder (`0` = la couleur qui vient du thème)
`is_live_text` | string | `""` | Texte superposé à la tuile, balisage riche accepté
`ib_enabled` | boolean | `true` | Tuile grisée et non cliquable
`ib_visible` | boolean | `true` | Tuile masquée, sans être retirée de son groupe
`of_add_live_item (string as_text)` |  |  | Ajoute une face au bandeau animé ; à partir de deux faces, la tuile les fait défiler
`of_clear_live_items ( )` |  |  | Vide le bandeau animé : la tuile cesse de défiler

Les icônes acceptent toutes les formes reconnues par la bibliothèque : chemin, `mono:`, `tint:`, ressource de DLL. Sur une grande tuile, préférez une image nette en haute définition ou un SVG.

## Les quatre tailles #

Taille | Encombrement | Usage typique
--- | --- | ---
`small` | 1 case | Raccourci secondaire ; le libellé n'est pas affiché, l'info-bulle prend le relais
`medium` | 2 × 2 cases | Taille de référence : icône et libellé
`wide` | 4 × 2 cases | Tuile allongée, idéale pour un texte animé
`large` | 4 × 4 cases | Tuile vedette de l'écran

## Événements #

Événement | Déclenché quand
--- | ---
`ue_tile_clicked (string as_group, string as_id)` | Une tuile est cliquée
`ue_tile_moved (string as_group, string as_id, string as_to_group, long al_index)` | Une tuile a été déplacée : `as_group` est le groupe d'origine, `as_to_group` le groupe d'arrivée, `al_index` la nouvelle position
`ue_group_toggled (string as_group, boolean ab_collapsed)` | Un groupe est replié ou déplié depuis son entête
`ue_tile_context (string as_group, string as_id)` | Clic droit sur une tuile
`ue_tile_resized (string as_group, string as_id, string as_size)` | La taille d'une tuile a changé ; `as_size` porte la nouvelle taille
`ue_layout_changed (string as_layout_json)` | L'arrangement a changé — l'utilisateur a déplacé ou redimensionné une tuile. Porte la disposition entière, pas seulement ce qui a bougé
`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 #

### Tailles mélangées dans un même groupe #

    n_pbt_tilesbox_group lnv_grp

    uo_tuiles.of_clear()
    lnv_grp = uo_tuiles.of_add_group(/*group_id*/ "accueil", /*title*/ "Accueil")

    lnv_grp.of_add_tile(/*id*/ "tableau", /*label*/ "Tableau de bord", /*icon_file*/ "mono:img\chart.svg",  /*size*/ "large")
    lnv_grp.of_add_tile(/*id*/ "clients", /*label*/ "Clients",         /*icon_file*/ "mono:img\users.svg",  /*size*/ "medium")
    lnv_grp.of_add_tile(/*id*/ "agenda",  /*label*/ "Agenda",          /*icon_file*/ "mono:img\cal.svg",    /*size*/ "wide")
    lnv_grp.of_add_tile(/*id*/ "aide",    /*label*/ "Aide",            /*icon_file*/ "mono:img\help.svg",   /*size*/ "small")

### Pastille, couleur et tuile animée #

    n_pbt_tilesbox_tile lnv_tuile

    // Une pastille signale un nombre d'elements en attente
    uo_tuiles.of_group("accueil").of_tile("clients").is_badge = String(ll_nouveaux)

    // Rouge quand le retard devient critique, couleur du theme sinon (0)
    if ll_nouveaux > 50 then
        uo_tuiles.of_group("accueil").of_tile("clients").il_badge_color = RGB(200, 30, 30)
    else
        uo_tuiles.of_group("accueil").of_tile("clients").il_badge_color = 0
    end if

    // Une couleur propre met une tuile en avant : fond, texte, et ce que
    // chacun devient sous le pointeur
    lnv_tuile = uo_tuiles.of_group("accueil").of_tile("tableau")
    lnv_tuile.il_back_color = RGB(0, 103, 192)
    lnv_tuile.il_back_color_hover = RGB(0, 80, 150)
    lnv_tuile.il_text_color = RGB(255, 255, 255)

    // Tuile ANIMEE : chaque face ajoutee defile a son tour sur la tuile
    lnv_tuile = uo_tuiles.of_group("accueil").of_tile("agenda")
    lnv_tuile.of_clear_live_items()
    lnv_tuile.of_add_live_item(/*text*/ "3 rendez-vous aujourd'hui")
    lnv_tuile.of_add_live_item(/*text*/ "Reunion equipe a 14h00")
    lnv_tuile.of_add_live_item(/*text*/ "2 relances en retard")

### Un texte fixe plutôt qu'un défilement #

    // is_live_text pose UN texte permanent sur la tuile (balisage riche accepte)
    uo_tuiles.of_group("accueil").of_tile("tableau").is_live_text = "[b]48[/b] commandes du jour"

### Groupes repliables #

    n_pbt_tilesbox_group lnv_admin

    lnv_admin = uo_tuiles.of_add_group(/*group_id*/ "admin", /*title*/ "Administration")
    lnv_admin.of_add_tile(/*id*/ "users",  /*label*/ "Utilisateurs", /*icon_file*/ "mono:img\users.svg", /*size*/ "medium")
    lnv_admin.of_add_tile(/*id*/ "params", /*label*/ "Parametres",   /*icon_file*/ "mono:img\gear.svg",  /*size*/ "medium")

    // Ce groupe demarre replie : l'utilisateur l'ouvre s'il en a besoin
    lnv_admin.ib_collapsed = true

    // Un groupe entier peut aussi etre grise selon les droits
    lnv_admin.ib_enabled = (is_profil = "ADMIN")

    // event ue_group_toggled de uo_tuiles
    if as_group = "admin" and not ab_collapsed then of_tracer("Ouverture du volet administration")

### Un panneau à groupe unique, sans entête #

    // Un seul groupe n'a rien a nommer : son entete ne fait que manger de la hauteur.
    // Sans entete, plus de chevron non plus : les tuiles restent toujours visibles.
    uo_tuiles.ib_show_group_headers = false
    uo_tuiles.of_add_group(/*group_id*/ "tout", /*title*/ "")

### Déplacer une tuile entre deux groupes #

Avec `ib_reorderable = true`, l'utilisateur fait glisser une tuile où il veut, y compris d'un groupe vers un autre. L'event `ue_tile_moved` livre les deux groupes et la nouvelle position.

    uo_tuiles.ib_reorderable = true    // faux par defaut : a demander

    // event ue_tile_moved de uo_tuiles
    // as_group = groupe d'origine, as_to_group = groupe d'arrivee, al_index = position
    if as_group <> as_to_group then
        of_tracer("Tuile " + as_id + " deplacee de " + as_group + " vers " + as_to_group)
    end if
    uo_tuiles.of_get_layout()    // demander la disposition pour la conserver

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

    // A l'ouverture suivante : restituer l'ecran tel que l'utilisateur l'avait range
    if is_disposition <> "" then uo_tuiles.of_set_layout(is_disposition)

Pour figer l'écran, il suffit de couper la réorganisation :

    uo_tuiles.ib_reorderable = false

### Réorganiser depuis le code #

    // Placer la tuile "aide" en tete de son groupe (positions comptees a partir de 0)
    uo_tuiles.of_move_tile(/*group*/ "accueil", /*id*/ "aide", /*index*/ 0)

    // Inserer une nouvelle tuile en deuxieme position
    uo_tuiles.of_insert_tile(/*group*/ "accueil", /*id*/ "devis", /*text*/ "Devis", /*index*/ 1)

    // Retirer une tuile sans toucher au reste
    uo_tuiles.of_remove_tile(/*group*/ "accueil", /*id*/ "aide")

### Réagir au clic droit #

    // event ue_tile_context de uo_tuiles : (as_group, as_id)
    // Retenir la tuile visee, puis ouvrir votre propre menu contextuel
    is_groupe_vise = as_group
    is_tuile_visee = as_id
    of_ouvrir_menu_tuile(PointerX(), PointerY())

## Bonnes pratiques #

- Une tuile `large` par écran suffit : c'est le point d'entrée principal, le reste doit rester lisible.
- Les tuiles `small` n'affichent pas leur libellé — renseignez systématiquement l'info-bulle de l'item.
- Réservez `il_back_color` aux tuiles qui doivent trancher : au-delà de deux ou trois couleurs, l'écran perd sa hiérarchie. Et si vous posez un fond clair, posez `il_text_color` avec — le texte du thème n'est pas garanti lisible dessus.
- Préférez `of_add_live_item` (défilement) à `is_live_text` (texte fixe) quand vous avez plusieurs informations à faire passer sur la même tuile.
- Si vous laissez la réorganisation active, conservez la disposition via `of_get_layout` / `ue_layout_changed` et rejouez `of_set_layout` à l'ouverture.
- Utilisez `ib_visible` et `ib_enabled` (groupe ou tuile) pour l'adapter aux droits de l'utilisateur, plutôt que de reconstruire le panneau.
- Quand l'espace manque pour des tuiles, préférez la navigation latérale compacte du listbar ; pour les actions fréquentes, la toolbar.

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