breadcrumb — u_pbt_breadcrumb #
← Component reference · Guide contents
Breadcrumb trail: the clickable path that tells the user where they are, and takes them back up to any level above in one click.
▶ See it live — Demo application, Breadcrumb tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_breadcrumb |
| Item class | n_pbt_breadcrumb_item (of_item(address)) · n_pbt_breadcrumb_child (of_child(address)) |
| Used for | Saying where you are in a hierarchy, and letting you climb back out of it |
| Principle | You describe the path; the folding, the menu and the layout are ours |
Quick start #
// Every time the user goes down a level
uo_crumbs.of_add_item(/*keys*/ "home", /*text*/ "H")
uo_crumbs.of_add_item(/*keys*/ "home/clients", /*text*/ "C")
uo_crumbs.of_add_item(/*keys*/ "home/clients/dupont", /*text*/ "D")
// The last one added becomes the current location, and it is clickable too
A segment is named by its address: the keys from the root, joined by / — "home/clients/dupont". A bare key is no longer enough as soon as it repeats at two levels of the same trail: the component then refuses to guess, rather than take you somewhere you never asked for.
That is exactly what ue_item_clicked hands you, and exactly what of_truncate, of_item or of_add_child take back: what you receive goes straight back in.
A click reports, it does not cut #
Clicking a segment does not shorten the trail. Going back up means leaving a screen, and leaving a screen often means saving first — which no click can decide. The component tells you what was clicked; you are the one who cuts, through of_truncate, once your checks have passed.
This is the same division of labour as the stepbar, and for the same reason. A component that moves by itself forces the application to undo a move already made, instead of simply choosing whether it happens.
Two segments never report anything: a disabled segment, a hidden one. The last one — where you are — answers like the others, until ib_last_clickable says no.
// event ue_item_clicked : (string as_keys)
// Your checks first - leaving the screen is your decision, not a click's
if not of_peut_quitter() then return
uo_crumbs.of_truncate(/*keys*/ as_keys)
of_ouvrir_ecran(as_keys)
When the path is too long #
A path is as long as the data makes it, and the width is what it is. is_overflow_mode says what gives.
| Constant | What happens |
|---|---|
OVERFLOW_COLLAPSE | The middle folds into a … that opens what it hides — the default |
OVERFLOW_SCROLL | Labels stay whole, the strip slides |
OVERFLOW_SHRINK | Every segment gives ground and ends in an ellipsis |
Neither the first segment nor the last ever folds. Losing the root loses the anchor everyone goes back to; losing the end loses where you are.
A folded segment reports exactly like the others: picking it from the
…raises the sameue_item_clicked. Being hidden by the width does not change what a segment means.
ii_max_visible sets a hard ceiling, whatever the room. Leave it at 0 — the default — to let the width decide, which is what a breadcrumb should normally follow.
The sibling menu #
of_add_child gives a segment its own drop-down: the other branches of that level. That is what saves a walk back to the root just to go down a neighbouring folder.
The chevron after the segment then becomes the button that opens them — the very separator, as in the Windows explorer: one chevron, one meaning to learn. Picking a branch raises ue_child_clicked, and here too the trail does not move by itself. On the keyboard, Down arrow on a segment opens its branches, and on the … what it hides.
uo_crumbs.of_add_child(/*keys*/ "home/clients/durand", /*text*/ "D")
uo_crumbs.of_add_child(/*keys*/ "home/clients/martin", /*text*/ "M")
Branches on demand #
Posing every branch up front does not hold on a deep tree, nor on a database. The Windows explorer reads a folder only when its chevron opens; the trail does the same: flag a segment with ib_has_children, its chevron shows at once, and opening it raises ue_children_needed. You pose the branches in that event, and the menu opens once it returns, with what the segment holds at that moment.
// The segment promises : the chevron shows, nothing is read
uo_crumbs.of_item(/*keys*/ "home/clients").ib_has_children = true
// In ue_children_needed(as_keys) : read now, then the menu opens
uo_crumbs.of_clear_children(/*keys*/ as_keys)
uo_crumbs.of_add_child(/*keys*/ as_keys + "/durand", /*text*/ "Durand SARL")
Typing the path #
With ib_editable, the empty part of the bar behaves like the address bar of the Windows explorer: a click (or F2, or of_edit) turns the trail into a text field holding the displayed address — the keys joined by /, what of_path returns. Enter raises ue_path_entered with the text as typed; Escape cancels. The trail does not move by itself, for the same reason a click does not shorten it: only your application knows what the words mean. ii_edit_skip leaves the first segments out of the field — the root that names the machine — and puts them back in front of what was typed when it is reported.
Properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_separator | string | chevron | The glyph between segments (SEPARATOR_* constants). It turns round on its own in a right-to-left language: pick a meaning, not a direction. A separator that opens branches keeps the chosen glyph: the hover and the pointer are what say it opens |
is_overflow_mode | string | collapse | What gives when the path no longer fits (OVERFLOW_* constants). Under scroll, the strip follows where you are |
ii_max_visible | integer | 0 | A hard ceiling on the number of segments shown, the … not counted. 0 leaves it to the width |
ib_last_clickable | boolean | true | Is the last segment — where you are — clickable? True by default: a trail is also how one asks to reload what is on screen, and what the click does is your application's business. Set it false when your trail only ever navigates |
ib_editable | boolean | false | Can the path be typed? True: a click on the empty part of the bar (or F2, or of_edit) turns the trail into a text field holding the displayed address; Enter raises ue_path_entered, Escape cancels. The trail never moves by itself |
ib_allow_drop | boolean | false | Opt-in: accepts files dropped from Windows Explorer on a segment. The segment under the cursor lights up during the drag, and ue_drop_files names it with the full paths |
ii_edit_skip | integer | 0 | Number of leading segments left out of the text field — a root that names the machine is not something one types. They are put back in front of what was typed when it is reported: the address stays complete |
is_theme_style | string | fluent | Visual style of the component (THEME_STYLE_* constants) |
is_theme_mode | string | light | Light or dark variant (THEME_MODE_* constants) |
il_theme_accent | long | -1 | Accent color of this component (-1 = the theme accent) |
is_tooltip | string | "" | Simple tooltip shown when hovering the component |
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
Methods #
| Method | Role |
|---|---|
of_add_item (string as_keys, string as_text) | Appends a segment at the end: it becomes the current location. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_add_item (string as_keys, string as_text, string as_image) | Same, with the icon shown before the label — third argument, as everywhere else in the library. An empty label gives an icon-only segment (the root's house). Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_insert_item (string as_keys, string as_text, integer ai_index) | Inserts at the position you choose (first position = 1). An overload takes the icon as well. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_remove_item (string as_keys) | Removes one segment; the others keep their state. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_truncate (string as_keys) | Drops everything after that segment, which becomes the current location. This is the move a breadcrumb exists for; an unknown address changes nothing. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_clear ( ) | Empties the trail. Returns 0 once applied, -2 when the component is not created |
of_add_child (string as_keys, string as_text) | Adds a sibling branch at the given address: the segment above it grows a chevron that opens them. An overload takes the icon as well. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_clear_children (string as_keys) | Removes the sibling branches of a segment; its separator becomes a plain mark again. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_remove_child (string as_keys) | Removes one sibling branch, by its own address; the last one gone, the chevron goes back to a plain separator. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_child (string as_keys) | The handle to a sibling branch — the address of_add_child took — to rename it, grey it or hide it |
of_path ( ) | The keys of the displayed path, separated by /. Read live: an application that rebuilt this string by hand would end up disagreeing with the screen |
of_edit ( ) | Opens the text field of the path — the same one a click on the empty part of the bar opens — from a menu entry or a button of your own. Needs ib_editable. Returns 0 once applied, -2 when the component is not created |
of_item (string as_keys) | The handle of one segment, to rename, grey out or hide it later |
of_set_redraw (boolean) | Groups a burst of changes into a single render. Returns 0 once applied, -2 when the component is not created |
of_save_as_png (string) · of_save_as_jpg (string) | Exports the rendering as an image. Returns 0 once the image is written, -4 when writing fails, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_item_clicked (string as_keys) | A segment was clicked — in the trail, or in the … that hides it. The trail does not shorten itself: call of_truncate once your checks have passed |
ue_item_rclicked (string as_keys) | Right-click on a segment — a context menu of your own, usually |
ue_child_clicked (string as_keys) | A sibling branch was picked in a segment's menu; as_keys is the address of the branch, ready to go straight back into of_add_item |
ue_children_needed (string as_keys) | The chevron of a segment flagged ib_has_children opens: pose its branches now (of_add_child), the menu opens once the event returns, with what the segment holds at that moment. Asked at every opening: clear and refill when the branches may have changed, do nothing when what is there still holds |
ue_path_entered (string as_path) | The user typed a path in the bar (ib_editable) and pressed Enter; as_path is the text as typed. The trail does not move by itself: check the words, then rebuild it with of_clear and of_add_item if you agree |
ue_drop_files (string as_keys, string as_files[]) | Files were dropped from the Explorer on a segment (ib_allow_drop): as_keys is the address of the segment under the cursor, empty when the drop landed beside the trail; as_files the full paths |
ue_drag_enter ( ) · ue_drag_leave ( ) | A file drag from the Explorer entered the component, or left it without dropping |
ue_auto_height (long al_height) | The bar announces the height it needs — one row, decided by the font and the theme; the userobject is already resized, move whatever sits below it |
ue_ready ( ) | The component has finished loading; everything sent before was replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component worked out its theme background; the userobject has already adopted it (backcolor) |
The trail does not navigate. It says where you are and reports what it is asked; your application is what opens the screen — the same action, triggered from a menu or from the trail, therefore goes through the same code.
Item properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_text | string | "" | The segment's label, changeable without rebuilding the trail (rich markup accepted) |
is_image | string | "" | The icon shown before the label (mono: and tint: prefixes accepted) |
ib_enabled | boolean | true | A disabled segment is greyed and reports nothing: the level exists in the path, but it cannot be gone back to (rights, a record being edited) |
ib_visible | boolean | true | A hidden segment leaves the trail, separator included — useful for a technical level the user has no business seeing. It is kept: showing it again needs no rebuild |
ib_has_children | boolean | false | Flagged: there is something under this segment. Its chevron shows with nothing behind it yet, and opening it raises ue_children_needed, where the branches are read at that moment. A segment whose branches were posed with of_add_child needs no flag |
Child properties #
Obtained through of_child(address). The menu is a native popup: a property changed while it is open shows at the next opening.
| Property | Type | Default | Role |
|---|---|---|---|
is_text | string | "" | The label of the branch in the menu |
is_image | string | "" | The icon shown before the label |
ib_enabled | boolean | true | A greyed branch stays in the menu and cannot be chosen — no rights on that branch |
ib_visible | boolean | true | A hidden branch leaves the menu without being removed; the last one hidden closes the chevron |
Examples #
Following it as the user navigates #
uo_crumbs.of_set_redraw(/*on*/ false)
uo_crumbs.of_clear()
uo_crumbs.of_add_item(/*keys*/ "home", /*text*/ "H", /*image*/ "mono:img\packimages.dll:svg/samples/folder-open")
uo_crumbs.of_insert_item(/*keys*/ "home/region", /*text*/ "R", /*index*/ 2)
uo_crumbs.of_set_redraw(/*on*/ true)
Going back up on a click #
uo_crumbs.of_truncate(/*keys*/ "home/clients")
ls_chemin = uo_crumbs.of_path()
A forbidden level, a hidden one #
// The level exists, but it cannot be gone back to
uo_crumbs.of_item(/*keys*/ "home/clients/orders").ib_enabled = false
// And this one is none of the user's business : out of the trail, separator included
uo_crumbs.of_item(/*keys*/ "home").ib_visible = false
uo_crumbs.is_separator = uo_crumbs.SEPARATOR_SLASH
uo_crumbs.is_overflow_mode = uo_crumbs.OVERFLOW_SCROLL
uo_crumbs.ii_max_visible = 4
uo_crumbs.ib_last_clickable = false
uo_crumbs.of_remove_item(/*keys*/ "home/region")
uo_crumbs.of_clear_children(/*keys*/ "home/clients")
Best practices #
- Give every segment the key of the screen it opens: your
ue_item_clickedbecomes achoose caseanyone can read, and the same code serves the menu. - Call
of_truncateinside your click handler, not before: that is what guarantees a screen is never left without your checks. - Leave
ii_max_visibleat0unless a design demands otherwise. A trail that follows the width always shows as much as fits. - Name segments with words the user recognises — the customer's name, not their id. A trail is read, not decoded.
- Only put levels in it that can really be returned to. A segment that fails every other time costs the whole trail its credibility; when a level is temporarily out of reach,
ib_enabledsays so without lying. - A breadcrumb says a place, not a progression: for "step 2 of 5", the stepbar is what you want.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_count · of_keys_at · of_has | Walk what the component holds | 3.2 Items |
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.