PBToolboxAI v3 ← Site

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 #

Userobjectu_pbt_breadcrumb
Item classn_pbt_breadcrumb_item (of_item(address)) · n_pbt_breadcrumb_child (of_child(address))
Used forSaying where you are in a hierarchy, and letting you climb back out of it
PrincipleYou 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.

ConstantWhat happens
OVERFLOW_COLLAPSEThe middle folds into a … that opens what it hides — the default
OVERFLOW_SCROLLLabels stay whole, the strip slides
OVERFLOW_SHRINKEvery 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 same ue_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 #

PropertyTypeDefaultRole
is_separatorstringchevronThe 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_modestringcollapseWhat gives when the path no longer fits (OVERFLOW_* constants). Under scroll, the strip follows where you are
ii_max_visibleinteger0A hard ceiling on the number of segments shown, the … not counted. 0 leaves it to the width
ib_last_clickablebooleantrueIs 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_editablebooleanfalseCan 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_dropbooleanfalseOpt-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_skipinteger0Number 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_stylestringfluentVisual style of the component (THEME_STYLE_* constants)
is_theme_modestringlightLight or dark variant (THEME_MODE_* constants)
il_theme_accentlong-1Accent color of this component (-1 = the theme accent)
is_tooltipstring""Simple tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip

Methods #

MethodRole
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 #

EventRaised 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 #

PropertyTypeDefaultRole
is_textstring""The segment's label, changeable without rebuilding the trail (rich markup accepted)
is_imagestring""The icon shown before the label (mono: and tint: prefixes accepted)
ib_enabledbooleantrueA 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_visiblebooleantrueA 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_childrenbooleanfalseFlagged: 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.

PropertyTypeDefaultRole
is_textstring""The label of the branch in the menu
is_imagestring""The icon shown before the label
ib_enabledbooleantrueA greyed branch stays in the menu and cannot be chosen — no rights on that branch
ib_visiblebooleantrueA 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 #

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.

MembersRoleDetailed in
of_count · of_keys_at · of_hasWalk what the component holds3.2 Items
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
of_is_created · of_is_ready · of_get_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · of_component_nameDriving a property by its name3.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.


← Component reference · Guide contents