ribbon — u_pbt_ribbon #
← Component reference · Guide contents
Office-style ribbon: tabs, groups, twelve types of rich controls, application menu, quick access toolbar, banner-headed contextual tabs and keytips.
▶ See it live — Demo application, Ribbon tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_ribbon |
| Item classes | n_pbt_ribbon_tab (tab), n_pbt_ribbon_group (group), n_pbt_ribbon_item (control), n_pbt_ribbon_menu_item (menu entry), n_pbt_ribbon_ctx_group (contextual tab group) |
| Used for | Replacing a menu bar and its toolbars with a modern command interface that is readable and clearly structured |
| Height | Intrinsic: the ribbon always fits itself to its content, nothing to enable — see Automatic height |
| Demo mode limit | 2 tabs maximum — see demo mode |
The golden rule: everything goes through the path #
The ribbon is a four-level hierarchy: tab → group → control → menu entry. There are no global identifiers for you to manage: every object is reached through the path that leads to it, and every addition is made on the parent handle.
// Read or drive a control : the full path, always
uo_ribbon.of_item(/*keys*/ "home/clipboard/paste").ib_enabled = false
Two practical, comfortable consequences: two different groups can use the same control identifier without clashing, and events hand you the full path — you always know where the click came from.
Quick start #
// open event of the window
// A tab
uo_ribbon.of_add_tab(/*key*/ "home", /*title*/ "Home")
// A group: one big button and two small ones
uo_ribbon.of_add_group(/*keys*/ "home/clipboard", /*title*/ "Clipboard")
uo_ribbon.of_add_big_button(/*keys*/ "home/clipboard/paste", /*label*/ "Paste", /*image*/ "mono:img\paste.svg")
uo_ribbon.of_add_button(/*keys*/ "home/clipboard/cut", /*label*/ "Cut", /*image*/ "mono:img\cut.svg")
uo_ribbon.of_add_button(/*keys*/ "home/clipboard/copy", /*label*/ "Copy", /*image*/ "mono:img\copy.svg")
// Show the tab
uo_ribbon.of_select_tab(/*key*/ "home")
// ue_clicked event of uo_ribbon : (string as_keys)
choose case as_keys
case "home/clipboard/paste" ; of_paste()
case "home/clipboard/cut" ; of_cut()
case "home/clipboard/copy" ; of_copy()
end choose
Properties #
| Property | Type | Default | Purpose |
|---|---|---|---|
is_app_button | string | "" | Caption of the application button, top left, which opens the application menu. Renaming it keeps its menu; an empty string takes the button away, with its menu. The entries of the application menu need the button first |
ib_minimized | boolean | false | true collapses the ribbon down to its tab headers alone; clicking a tab unfolds it temporarily. Set by code, it raises ue_minimized like the user's gesture — nothing when the ribbon already is in that state; ue_size_changed reports the new height |
ib_veto_gallery | boolean | false | Ask before a gallery tile is picked — by the user or by of_select_gallery_item (raises ue_gallery_selection_changing, which can refuse; a refused of_select_gallery_item returns -4). Off by default, like every cancelable event: each question costs a round trip to PowerBuilder (~35 ms). Set it to true when your application answers |
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) |
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 |
Constant — ACCENT_LIGHT (-1): pass it as the color of a contextual tab or group so that it follows the theme accent, lightened, instead of a fixed color.
Properties of a tab — n_pbt_ribbon_tab #
Obtained through of_tab("tab"), they can be changed on the fly.
| Property | Type | Default | Purpose |
|---|---|---|---|
ib_visible | boolean | true | false hides the tab without removing it — the very mechanism behind contextual tabs |
is_title | string | "" | Title of the tab. Set by of_add_tab; writing here changes it, reading tells what the tab shows |
is_keytip | string | "" | Key tip shown after pressing Alt ("H" for Home). One letter or several ("FP", as in Office), typed one after the other; Backspace takes the last one back. Letters and digits only |
Properties of a group — n_pbt_ribbon_group #
Obtained through of_group("tab/group").
| Property | Type | Default | Purpose |
|---|---|---|---|
ib_visible | boolean | true | false hides the group and all its controls |
is_title | string | "" | Caption under the group. Set by of_add_group; writing here changes it |
ib_launcher | boolean | false | Displays the small arrow at the bottom right of the group — the dialog launcher (raises ue_launcher). The arrow lives in the group title bar, and a group the ribbon had to fold for lack of room keeps it in the very same place — it also travels into the panel the folded group opens. |
Color picker mode constants: COLORMODE_PALETTE (swatch palette, the default mode) and COLORMODE_OPEN (full palette with confirmation).
Properties of a control — n_pbt_ribbon_item #
Obtained through of_item("tab/group/control"). They apply to every type of control; the properties that make no sense for a given type are simply ignored.
| Property | Type | Default | Purpose |
|---|---|---|---|
is_label | string | "" | Label of the control. Accepts rich text markup |
is_image | string | "" | Image of the control (button, large button, split button, drop-down button, check box, color picker, Quick Access Toolbar button), with the same prefixes as when it was added (mono:, tint:). "" removes it. Read live |
ib_enabled | boolean | true | false grays out the control and blocks its activation |
ib_checked | boolean | false | Pressed state of a toggle, or checked state of a check box |
ib_visible | boolean | true | false hides the control; its neighbors close the gap |
is_text | string | "" | Text typed or selected in a drop-down |
id_value | double | 0 | Numeric value of a spinner |
id_min | double | 0 | Spinner only: low bound of the range, which can be changed at any time. The value is brought back into the new range at once, silently (no ue_value_changed, like id_value written from code). On any other control, no effect and reads 0 |
id_max | double | 0 | Spinner only: high bound of the range, which can be changed at any time; the value is brought back into the range silently, as with id_min. On any other control, no effect and reads 0 |
id_step | double | 0 | Spinner only: step of the arrows and of the Up / Down keys, which can be changed at any time. A step of 0 or less is ignored. On any other control, no effect and reads 0 |
il_color | long | -1 | Current color of a color picker |
ii_visible_items | integer | 3 | Gallery only: number of tiles the collapsed strip shows at once. The others stay reachable through the arrows, or in the expanded grid |
is_keytip | string | "" | Key tip of the control, shown after Alt and the tab's letter. One letter or several ("FP", as in Office), typed one after the other; Backspace takes the last one back. Letters and digits only. A control of a folded group keeps its key tip: it opens the group's panel |
is_tooltip | string | "" | Simple tooltip shown when hovering the item |
is_super_tooltip_title | string | "" | Title of the item rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the item rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the item rich tooltip |
Properties of a menu entry — n_pbt_ribbon_menu_item #
Obtained through of_menu_item("tab/group/control/entry").
| Property | Type | Default | Purpose |
|---|---|---|---|
is_image | string | "" | Image of the menu entry. An empty string takes it away |
of_is_separator ( ) → boolean | — | — | Is the entry a separator line? Read only: what an entry is was decided when it was added |
of_is_header ( ) → boolean | — | — | Is the entry a non-clickable header? Read only, same reason |
of_is_checkable ( ) → boolean | — | — | Does the entry carry a check mark? Read only; ib_checked says whether it is on |
ib_enabled | boolean | true | false grays out the entry |
ib_visible | boolean | true | false takes the entry out of the menu at its next opening — cascade included — without removing it |
ib_checked | boolean | false | Check mark of an entry created by of_add_menu_check |
Properties of an application menu entry — n_pbt_ribbon_app_menu_item #
Obtained through of_app_menu_item("recent/a.txt"). They change on the fly: the menu takes them at its next opening.
| Property | Type | Default | Purpose |
|---|---|---|---|
is_label | string | "" | Text of the entry |
is_image | string | "" | Image of the entry. An empty string takes it away |
ib_enabled | boolean | true | false greys the entry: shown, never chosen — Save while there is nothing to save |
ib_checked | boolean | false | Check mark in front of the entry |
ib_visible | boolean | true | false takes the entry out of the menu at its next opening — submenu included — without removing it |
of_is_separator ( ) → boolean | — | — | Is the entry a separator line? Read only |
of_keys_at (long al_index) → string | — | — | The address of the entry at rank ai_index (from 1) under this one — or at the first level for of_app_menu_item("") —, "" past the end: the address of_app_menu_item and of_remove_app_menu_item take |
The twelve types of controls #
They are all added at a group's address — "home/clipboard" — and return 0 (-5 on an invalid argument, -2 when the component is not created); a menu or a list is then filled at the control's address.
| Group method | Control obtained | Event |
|---|---|---|
of_add_big_button (string as_keys, string as_label, string as_image) → long | Full-height big button, icon above the label. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_clicked |
of_add_big_split (string as_keys, string as_label, string as_image) → long | Big split button: the upper part acts, the arrow opens the menu. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_clicked · ue_menu_selected |
of_add_big_dropdown (string as_keys, string as_label, string as_image) → long | Big button with a drop-down menu. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_menu_selected |
of_add_button (string as_keys, string as_label, string as_image) → long | Small button (stacked in columns of three). Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_clicked |
of_add_toggle (string as_keys, string as_label, string as_image) → long | Small toggle that stays pressed. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_toggled |
of_add_dropdown (string as_keys, string as_label, string as_image) → long | Small button with a drop-down menu. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_menu_selected |
of_add_checkbox (string as_keys, string as_label) → long | Check box. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_toggled |
of_add_separator (string as_keys) → long | Vertical separator between two blocks of controls. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | — |
of_add_combo (string as_keys, integer ai_width_px, boolean ab_editable) → long | Drop-down, editable or not. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_combo_changed |
of_add_spinner (string as_keys, integer ai_width_px, double ad_min, double ad_max, double ad_step, double ad_value) → long | Numeric spinner with arrows. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_value_changed |
of_add_colorpicker (string as_keys, string as_label, string as_image, long al_color) → long | Split color button: clicking reapplies, the arrow opens the swatch palette. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created | ue_clicked · ue_color_changed |
of_add_gallery (string as_keys, integer ai_width_px, integer ai_tile_w, integer ai_tile_h) → long | Scrolling strip of illustrated tiles | ue_gallery_selection_changed |
of_add_colorpicker accepts a fifth argument as_mode: COLORMODE_PALETTE (swatch palette) or COLORMODE_OPEN (full palette with OK and Cancel buttons).
Methods #
Building the ribbon #
| Method | Purpose |
|---|---|
of_add_tab (string as_key, string as_title) | Adds a tab and returns 0 (-5 on an invalid argument, -2 when the component is not created): groups are then added at its address |
of_insert_tab (string as_key, string as_title, integer ai_index) | Adds a tab at the position you choose (1 = first) instead of at the end, and returns 0 (-5 on an invalid argument, -2 when the component is not created) like of_add_tab. An id already taken is refused |
of_tab (string as_key) | Handle of an existing tab (created on first access) |
of_add_group (string as_keys, string as_title) | Adds a titled group to a tab — "home/clipboard" — and returns 0 (-5 on an invalid argument, -2 when the component is not created) |
of_group (string as_keys) | Handle of an existing group, by its address |
of_item (string as_keys) | Handle of an existing control, by its address — "home/clipboard/paste" |
of_select_tab (string as_key) | Activates a tab, like a click on it: ue_selection_changed follows (right after your script, from the event queue; nothing when the tab is already active), and of_selected_key reads it back at once. Unlike a click, it does not unfold a folded ribbon. Returns 0 once applied, -5 for an unknown or hidden tab, -2 when the component is not created |
of_selected_key ( ) | Key of the active tab, "" if none. Read live from the component: right from ue_selection_changed, or just after of_select_tab, it already names the new tab |
of_remove_group (string as_keys) | Removes a group and all its controls, by its address; the handles of what leaves are freed. Returns 0 once applied, -5 when no group lives at that address, -2 when the component is not created |
of_remove_item (string as_keys) | Removes a control by its address (tab/group/control), or a Quick Access Toolbar button by its key alone; its handle is freed. Returns 0 once applied, -5 when nothing of the kind lives at that address, -2 when the component is not created |
of_remove_tab (string as_key) | Removes a tab and all its content; the handles of what leaves are freed. Returns 0 once applied, -5 when no tab carries that key, -2 when the component is not created |
of_clear ( ) | Empties the ribbon completely: tabs, groups, controls, quick access toolbar, application menu. Returns 0 once applied, -2 when the component is not created |
Filling menus and lists #
All these methods are called on the component, with the address of the control (tab/group/control) — the entry, the choice or the tile as a fourth level.
| Method | Purpose |
|---|---|
of_add_menu_item (string as_keys, string as_label, string as_image) | Entry of the menu of a drop-down or split button: tab/group/control/entry, one more level per cascade. Returns 0 once applied, -5 on a wrong address, a parent that is neither a drop-down nor an entry, or a key already taken in that menu, -2 when the component is not created |
of_add_menu_check (string as_keys, string as_label) · (id, label, image) | Checkable entry: clicking toggles its state and reports it in ue_menu_selected. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_add_menu_header (string as_keys, string as_label) | Non-clickable title line, to break up a long menu. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_add_menu_separator (string as_keys) | Separator line in a menu: as_keys names the control for its own menu, or an entry for the cascade under it. Returns 0 once applied, -5 on an invalid argument (empty key, wrong address), -2 when the component is not created |
of_remove_menu_item (string as_keys) | Removes one entry of a menu, its cascade with it (tab/group/control/entry, deeper for a cascaded entry); its handles are freed. Returns 0 once applied, -5 when no entry lives at that address, -2 when the component is not created |
of_clear_menu (string as_keys) | Empties the menu of a drop-down or split button (tab/group/control): a “Recent files” list is rebuilt entry by entry, without recreating the control. Returns 0 once applied, -5 when the address is neither a drop-down nor a split button, -2 when the component is not created |
of_menu_item (string as_keys) | Handle of a menu entry, to gray it out or check it on the fly |
of_add_combo_item (string as_keys, string as_label) | Adds a choice to the list of a combo box; a choice is keyed by its label. Returns 0 once applied, -5 when the address is not a combo box, or on a label already in the list, empty, or holding / or a vertical bar, -2 when the component is not created |
of_remove_combo_item (string as_keys) | Removes one choice of a combo box: tab/group/combo/label. Returns 0 once applied, -5 when the combo has no such choice, -2 when the component is not created |
of_clear_combo (string as_keys) | Empties the list of a combo box (tab/group/combo); its text stays. Returns 0 once applied, -5 when the address is not a combo box, -2 when the component is not created |
of_add_gallery_item (string as_keys, string as_image, string as_label) | Adds a tile to a gallery (tab/group/gallery/tile); its label is also its name for a screen reader. Returns 0 once applied, -5 on a wrong address, a third level that is not a gallery, or a tile already taken, -2 when the component is not created |
of_remove_gallery_item (string as_keys) | Removes one tile of a gallery (tab/group/gallery/tile). When the selected tile leaves, nothing is selected any more. Returns 0 once applied, -5 when there is no such tile, -2 when the component is not created |
of_select_gallery_item (string as_keys) | Selects a gallery tile from code, by its four-level address, like a pick: with ib_veto_gallery on, ue_gallery_selection_changing is asked first; then ue_gallery_selection_changed follows. The tile already selected: nothing is asked nor raised. Returns 0 once applied (or already selected), -4 when your ue_gallery_selection_changing refused (the tile stays), -5 for any other depth or a tile of_add_gallery_item never added, -2 when the component is not created |
of_open (string as_keys) | Opens from code the menu, list or palette of the control at that address (tab/group/control); the address of a group (tab/group) opens its panel when a too-narrow window folded it. Returns 0 once applied, -5 for an address that names neither a control nor a group (a Quick Access Toolbar button has no menu to open), -2 when the component is not created |
Application menu and quick access toolbar #
| Method | Purpose |
|---|---|
of_add_app_menu_item (string as_keys, string as_label, string as_image) | Entry of the application menu (the one opened by the is_app_button button), by its address: recent at the root, recent/a.txt in the submenu of recent. Returns 0 once applied, -5 on an invalid key (empty, / or a vertical bar in a level, starting with __), a key already taken, an unknown parent entry, or without an application button, -2 when the component is not created |
of_add_app_menu_separator (string as_keys) | Separator line in the application menu. as_keys is its address, like an entry's: s1 at the root, saveas/s1 in the submenu of saveas; an empty address gets a key of its own. Returns 0 once applied, -5 on a key already taken, an unknown parent entry, or without an application button, -2 when the component is not created |
of_remove_app_menu_item (string as_keys) | Removes one entry (or separator line) of the application menu by its address, its submenu with it; its handles are freed. Returns 0 once applied, -5 when there is no such entry, -2 when the component is not created |
of_app_menu_item (string as_keys) | Handle of an entry of the application menu (save, recent/a.txt), to grey, check, hide or rename it on the fly — see below. of_app_menu_item("") stands for the menu itself: of_count and of_keys_at walk its first level |
of_add_qat (string as_key, string as_image, string as_tooltip) | Quick Access Toolbar button, above the tabs; its tooltip is also its name for a screen reader. Returns 0 once applied, -5 on an invalid key (empty, / or a vertical bar in a level, starting with __) or a key already in the bar, -2 when the component is not created |
of_qat_item (string as_key) | Handle of a quick access button, to gray it out or hide it on the fly |
Contextual tabs #
| Method | Purpose |
|---|---|
of_add_contextual_tab (string as_key, string as_title, long al_color) | Standalone contextual tab: created hidden, marked with a coloured stripe. Pass ACCENT_LIGHT to follow the theme accent. Returns 0 once applied, -5 on an invalid key (empty, / or a vertical bar in a level, starting with __) or a key already taken, -2 when the component is not created |
of_add_contextual_group (string as_key, string as_title) · (id, title, al_color) | Contextual tab group: a coloured titled banner crowns its tabs. Returns 0 once applied, -5 on an invalid key (empty, / or a vertical bar in a level, starting with __) or a key already taken (its colour changes through of_ctx_group(key).il_color), -2 when the component is not created |
of_ctx_group (string as_key) | Retrieves the handle of an existing contextual group, by its key — its properties are set on it |
of_remove_contextual_group (string as_key) | Removes a contextual tab group and the tabs it crowns — they belong to it; their handles are freed. Returns 0 once applied, -5 when of_add_contextual_group never created that group, -2 when the component is not created |
of_add_contextual_tab (string as_key, string as_title, string as_group_key) | Adds a tab under a contextual group: created hidden, crowned by the group's coloured banner. Returns 0 once applied, -5 on an invalid key or one already taken, or a group of_add_contextual_group never created, -2 when the component is not created |
il_color (property) | On a contextual group handle: recolors the banner on the fly (ACCENT_LIGHT to go back to the accent) |
Shared #
| Method | Purpose |
|---|---|
of_reset ( ) | Empties the ribbon and returns it to its brand-new state, properties included. Returns 0 once applied, -2 when the component is not created |
of_set_redraw (boolean) | Groups a burst of changes into a single rendering. Returns 0 once applied, -2 when the component is not created |
of_preload_icons (string as_icons[]) | Warms up a batch of icons at startup: a tab opened later displays its own instantly. 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 #
Every control event carries the full path: you never need an identifier that is unique across the whole application.
| Event | Raised when |
|---|---|
ue_clicked (string as_keys) | The user clicks a button, a big button, the main part of a split button or a Quick Access Toolbar button — in the ribbon, in the panel of a folded group, or through its key tip. as_keys is the address tab/group/control, or the key alone for a Quick Access Toolbar button |
ue_toggled (string as_keys, boolean ab_checked) | The user switches a toggle button or a check box (in the ribbon or the panel of a folded group); ab_checked carries the new state. Writing ib_checked from code raises nothing |
ue_menu_selected (string as_keys, boolean ab_checked) | The user chooses an entry of the menu of a drop-down or split button. as_keys is its full address: tab, group, owning control, then the entry — one more level per cascade. A checkable entry flips first, and ab_checked carries its new state. A greyed or hidden entry cannot be chosen |
ue_combo_changed (string as_keys, string as_text) | The user commits the text of a combo box: a choice in its list, Enter in the field, or leaving the field after typing. Escape drops the typing and raises nothing; writing is_text from code raises nothing either |
ue_value_changed (string as_keys, double ad_value) | The user changes a spinner's value: its arrows, Up / Down in the field, Enter or leaving the field after typing (Escape drops it). ad_value is the new value, kept within the spinner's range. Writing id_value from code raises nothing |
ue_color_changed (string as_keys, long al_color) | The user picks a colour (palette or picker), or clicks the main part of a colour picker to apply its current colour again; al_color is the PowerBuilder colour. Writing il_color from code raises nothing |
ue_gallery_selection_changed (string as_from_keys, string as_keys) | A gallery tile has been picked — by the user or by of_select_gallery_item (an order of your code raises it too). Same arguments as ue_gallery_selection_changing: the question and its outcome read the same way, and as_from_keys is the tile left |
ue_gallery_selection_changing (string as_from_keys, string as_keys) → boolean | Cancelable, raised before the tile is picked. Raised only when ib_veto_gallery = true. as_from_keys is the current tile. Asked for of_select_gallery_item too. Return false to keep it (a style the document cannot take yet): of_select_gallery_item then returns -4 |
ue_launcher (string as_keys) | The user clicks the launcher arrow of a group (also from the panel of a folded group): as_keys is the group's address tab/group — open your options window |
ue_selection_changed (string as_keys) | Another tab comes forward: a click, the mouse wheel over the ribbon, a key tip, or of_select_tab (an order of your code raises it too). as_keys is the tab's key — empty when none is left, after the active tab was hidden or removed |
ue_app_button ( ) | The application button is clicked |
ue_app_menu_selected (string as_keys) | The user chooses an entry of the application menu: as_keys is its address (saveas/as_pdf). A greyed or hidden entry cannot be chosen |
ue_minimized (boolean ab_minimized) | The ribbon folds or unfolds: the chevron at the end of the tab row, a double-click on a tab, or ib_minimized set by your code (an order raises it too); ue_size_changed reports the new height in every case |
ue_size_changed (long al_height, boolean ab_minimized) | The ribbon's height changed on its own: folded, unfolded, a contextual tab shown, a narrower window dropping a row. Unlike ue_auto_height — which only speaks when the component sizes itself — this one fires whether auto-height is on or off: it is pure information, for laying out what sits underneath |
ue_keytips (boolean ab_on, integer ai_level) | The keytips appear (true) or disappear (false). ai_level tells how far the navigation has gone: 1 = the tabs are lettered, 2 = the commands of the current tab are, 0 = no keytip left |
ue_auto_height (long al_height) | The ribbon reports its ideal height and has just adjusted to it — always active: a ribbon's height is intrinsic |
ue_ready ( ) | The component has finished loading; everything sent beforehand has been replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component has computed its theme background color; the userobject has already adopted it (backcolor) |
Examples #
A complete ribbon, from the application menu to the groups #
// open event : the whole build is grouped into a single rendering
// Freeze the drawing, and name the application button
uo_ribbon.of_set_redraw(/*on*/ false)
uo_ribbon.is_app_button = "File"
// Application menu, with a cascade under "Save as"
uo_ribbon.of_add_app_menu_item(/*keys*/ "new", /*label*/ "New", /*image*/ "mono:img\new.svg")
uo_ribbon.of_add_app_menu_item(/*keys*/ "open", /*label*/ "Open...", /*image*/ "mono:img\open.svg")
uo_ribbon.of_add_app_menu_item(/*keys*/ "save_as", /*label*/ "Save as", /*image*/ "mono:img\saveas.svg")
uo_ribbon.of_add_app_menu_item(/*keys*/ "save_as/as_pdf", /*label*/ "PDF document", /*image*/ "")
uo_ribbon.of_add_app_menu_item(/*keys*/ "save_as/as_csv", /*label*/ "CSV file", /*image*/ "")
uo_ribbon.of_add_app_menu_separator(/*keys*/ "sep1")
uo_ribbon.of_add_app_menu_item(/*keys*/ "quit", /*label*/ "Exit", /*image*/ "mono:img\exit.svg")
// Quick access toolbar, above the tabs
uo_ribbon.of_add_qat(/*key*/ "qat_save", /*image*/ "mono:img\save.svg", /*tooltip*/ "Save")
uo_ribbon.of_add_qat(/*key*/ "qat_undo", /*image*/ "mono:img\undo.svg", /*tooltip*/ "Undo")
// Home tab
uo_ribbon.of_add_tab(/*key*/ "home", /*title*/ "Home")
uo_ribbon.of_tab(/*key*/ "home").is_keytip = "H"
// A group: a split button with its menu, then two small buttons
uo_ribbon.of_add_group(/*keys*/ "home/clipboard", /*title*/ "Clipboard")
uo_ribbon.of_add_big_split(/*keys*/ "home/clipboard/paste", /*label*/ "Paste", /*image*/ "mono:img\paste.svg")
uo_ribbon.of_add_menu_item(/*keys*/ "home/clipboard/paste/paste_text", /*label*/ "Paste without formatting", /*image*/ "")
uo_ribbon.of_add_menu_item(/*keys*/ "home/clipboard/paste/paste_link", /*label*/ "Paste as link", /*image*/ "")
uo_ribbon.of_add_button(/*keys*/ "home/clipboard/cut", /*label*/ "Cut", /*image*/ "mono:img\cut.svg")
uo_ribbon.of_add_button(/*keys*/ "home/clipboard/copy", /*label*/ "Copy", /*image*/ "mono:img\copy.svg")
uo_ribbon.of_group(/*keys*/ "home/clipboard").ib_launcher = true // options arrow at the bottom right
// Draw everything at once, then show the tab
uo_ribbon.of_set_redraw(/*on*/ true)
uo_ribbon.of_select_tab(/*key*/ "home")
A single click router #
// ue_clicked event of uo_ribbon : (string as_keys)
// The full path arrives with the event : a single router is enough,
// and two groups can reuse the same identifier without getting in the way.
choose case as_keys
case "clipboard/cut" ; of_cut()
case "clipboard/copy" ; of_copy()
case "clipboard/paste" ; of_paste()
case "font/bold" ; of_toggle_bold()
end choose
Driving the state of controls according to permissions #
// Always through the path : tab > group > control
uo_ribbon.of_item(/*keys*/ "home/clipboard/paste").ib_enabled = of_clipboard_has_data()
uo_ribbon.of_item(/*keys*/ "home/tools/brush").ib_checked = true
uo_ribbon.of_tab(/*key*/ "admin").ib_visible = gb_administrator
// Gray out an entry INSIDE a drop-down menu (level 4)
uo_ribbon.of_item(/*keys*/ "home/clipboard/paste") &
.of_menu_item(/*keys*/ "paste_link").ib_enabled = false
Banner-headed contextual tabs #
The Office principle: tabs that appear only when the selection warrants them, topped by a colored titled banner.
// open event : we prepare the contextual group, hidden by default
// Without a color, the banner follows the theme accent ; RGB(...) to force it
uo_ribbon.of_add_contextual_group(/*key*/ "img", /*title*/ "Picture Tools", &
/*color*/ RGB(/*red*/ 224, /*green*/ 32, /*blue*/ 96))
uo_ribbon.of_add_contextual_tab(/*key*/ "format", /*title*/ "Format", /*group_key*/ "img")
uo_ribbon.of_add_group(/*keys*/ "format/adjust", /*title*/ "Adjust")
uo_ribbon.of_add_big_button(/*keys*/ "format/adjust/crop", /*label*/ "Crop", /*image*/ "mono:img\crop.svg")
uo_ribbon.of_add_button(/*keys*/ "format/adjust/rotate", /*label*/ "Rotate", /*image*/ "mono:img\rotate.svg")
// When a picture is selected : we reveal the tab and activate it
uo_ribbon.of_tab(/*key*/ "format").ib_visible = true
uo_ribbon.of_select_tab(/*key*/ "format")
// When it is deselected : we hide it, the banner goes away with it
uo_ribbon.of_tab(/*key*/ "format").ib_visible = false
Drop-down, spinner, color picker and gallery #
// A new group in the tab
uo_ribbon.of_add_group(/*keys*/ "home/font", /*title*/ "Font")
// Editable drop-down : we fill it through its handle
uo_ribbon.of_add_combo(/*keys*/ "home/font/font_name", /*width_px*/ 140, /*editable*/ true)
uo_ribbon.of_add_combo_item(/*keys*/ "home/font/font_name", /*label*/ "Segoe UI")
uo_ribbon.of_add_combo_item(/*keys*/ "home/font/font_name", /*label*/ "Arial")
uo_ribbon.of_add_combo_item(/*keys*/ "home/font/font_name", /*label*/ "Calibri")
uo_ribbon.of_item(/*keys*/ "home/font/font_name").is_text = "Segoe UI"
// Numeric spinner : min, max, step, initial value
uo_ribbon.of_add_spinner(/*keys*/ "home/font/size", /*width_px*/ 70, /*min*/ 6, /*max*/ 96, &
/*step*/ 1, /*value*/ 11)
// Color picker in full palette mode (with OK / Cancel)
uo_ribbon.of_add_colorpicker(/*keys*/ "home/font/color", /*label*/ "Color", &
/*image*/ "mono:img\font-color.svg", &
/*color*/ RGB(/*red*/ 0, /*green*/ 0, /*blue*/ 0), &
/*mode*/ u_pbt_ribbon.COLORMODE_OPEN)
// Style gallery : scrolling illustrated tiles
uo_ribbon.of_add_gallery(/*keys*/ "home/font/styles", /*width_px*/ 220, &
/*tile_w*/ 64, /*tile_h*/ 48)
uo_ribbon.of_add_gallery_item(/*keys*/ "home/font/styles/st_normal", /*image*/ "img\style-normal.png", /*label*/ "Normal")
uo_ribbon.of_add_gallery_item(/*keys*/ "home/font/styles/st_title", /*image*/ "img\style-titre.png", /*label*/ "Title")
uo_ribbon.of_add_gallery_item(/*keys*/ "home/font/styles/st_note", /*image*/ "img\style-note.png", /*label*/ "Note")
uo_ribbon.of_add_gallery_item(/*keys*/ "home/font/styles/st_code", /*image*/ "img\style-code.png", /*label*/ "Code")
// The collapsed strip shows 4 thumbnails at a time ; the others stay
// reachable through the arrows, or in the expanded grid.
uo_ribbon.of_item(/*keys*/ "home/font/styles").ii_visible_items = 4
// The style selected at start
uo_ribbon.of_select_gallery_item(/*keys*/ "home/font/styles/st_normal")
// ue_value_changed event of uo_ribbon : (string as_keys, double ad_value)
n_pbt_utils lnv_utils // autoinstantiate : nothing to create, nothing to destroy
if lnv_utils.of_leaf(/*keys*/ as_keys) = "size" then of_apply_size(ad_value)
The range and the step of a spinner can be changed afterwards through id_min, id_max and id_step on its handle: the value is brought back into the new range at once, without raising ue_value_changed. Its image, like that of any control, changes through is_image.
// The largest size depends on the chosen font : 96, then 400 in steps of 2
uo_ribbon.of_item(/*keys*/ "home/font/size").id_max = 400
uo_ribbon.of_item(/*keys*/ "home/font/size").id_step = 2
// ue_color_changed event of uo_ribbon : (string as_keys, long al_color)
n_pbt_utils lnv_utils // autoinstantiate : nothing to create, nothing to destroy
if lnv_utils.of_leaf(/*keys*/ as_keys) = "color" then of_apply_color(al_color)
Refusing the choice of a gallery thumbnail #
// The question is only asked on request: this line switches it on, and
// ue_gallery_selection_changing then decides on every tile.
uo_ribbon.ib_veto_gallery = true
// ue_gallery_selection_changing event of uo_ribbon :
// (string as_from_keys, string as_keys)
// Returning FALSE keeps the current thumbnail (as_from_keys).
n_pbt_utils lnv_utils // autoinstantiate : nothing to create, nothing to destroy
if lnv_utils.of_leaf(/*keys*/ as_keys) = "st_code" and not of_document_supports_code() then
MessageBox("Style", "This document cannot take the Code style.")
return false
end if
return true
The dialog launcher #
// The small arrow at the bottom right of the group
uo_ribbon.of_group(/*keys*/ "home/font").ib_launcher = true
// ue_launcher event of uo_ribbon : (string as_keys)
// The path identifies the group : we open the matching options window.
n_pbt_utils lnv_utils // autoinstantiate : nothing to create, nothing to destroy
choose case lnv_utils.of_leaf(/*keys*/ as_keys)
case "font" ; open(w_font_options)
case "clipboard" ; open(w_paste_options)
end choose
Keytips: driving the ribbon from the keyboard #
// Alt displays the letters ; Alt then H then C triggers "copy"
uo_ribbon.of_tab(/*key*/ "home").is_keytip = "H"
uo_ribbon.of_item(/*keys*/ "home/clipboard/copy").is_keytip = "C"
uo_ribbon.of_item(/*keys*/ "home/clipboard/cut").is_keytip = "X"
Pressing Alt wherever the focus sits in the window hands over to the ribbon: it takes the keyboard focus and raises its letters. You have nothing to wire — it is enough that at least one keytip is declared. Escape, a second Alt or picking a command return the focus to the control the user had left. A key tip may have several letters ("FP", as in Office): the user types them one after the other, the badges that no longer start with what was typed step aside, and Backspace brings them back. A control of a folded group keeps its key tip: it opens the group's panel.
ue_keytips warns you at every state change, and gives you the current level:
// ue_keytips event of uo_ribbon : (boolean ab_on, integer ai_level)
// The keyboard is driving the ribbon: clear the status bar hint, which talks
// about the mouse, and put it back when the letters drop.
if ab_on then
uo_statusbar.of_item(/*keys*/ "main").is_text = "Type a letter (level " + String(ai_level) + ")"
else
uo_statusbar.of_item(/*keys*/ "main").is_text = ""
end if
Rich tooltips on a control #
// The super tooltip of the Paste button: a title, a text, an image
lnv_item = uo_ribbon.of_item(/*keys*/ "home/clipboard/paste")
lnv_item.is_super_tooltip_title = "Paste (Ctrl+V)"
lnv_item.is_super_tooltip_text = "Inserts the contents of the clipboard." &
+ "[br][br][size-=15]Use the arrow to paste without formatting.[/size-=15]"
lnv_item.is_super_tooltip_image = "img\paste.png"
These four properties are exactly the same as on any other item of the library. For a one-line tooltip, is_tooltip alone is enough.
Automatic height #
The ribbon sizes itself: there is nothing to enable. It notifies you on every height change (collapsing, contextual tab, theme change) so that you can reposition whatever sits below.
// ue_auto_height event of uo_ribbon : (long al_height)
// The ribbon has already resized itself : we reposition what sits below.
uo_content.y = uo_ribbon.y + uo_ribbon.height
uo_content.height = this.height - uo_content.y
Collapsing the ribbon to save space #
// Start with the ribbon folded: only the tab headers show
uo_ribbon.ib_minimized = true
// ue_minimized event of uo_ribbon : (boolean ab_minimized)
// We remember the user preference for the next time the window opens.
of_save_preference("ribbon_collapsed", ab_minimized)
Starting over from an empty ribbon #
// of_reset empties tabs, groups, controls, quick access toolbar and menu
uo_ribbon.of_reset()
uo_ribbon.of_add_tab(/*key*/ "home", /*title*/ "Home")
From an existing PowerBuilder menu #
A PowerBuilder application has already described its commands once: in its menu. Labels, shortcuts, images, separators, sub-menus, tooltips — it is all there. n_pbt_menu2ribbon reads that menu back through RTTI and writes the PowerScript that builds the matching ribbon.
// Once, by hand : the generator WRITES code, it does not run in production.
// Paste its result into the open event of your window.
n_pbt_menu2ribbon lnv_gen
string ls_code
// Generate the code from the menu
lnv_gen = create n_pbt_menu2ribbon
ls_code = lnv_gen.of_generate(/*menu*/ m_principal, /*ribbon_var*/ "uo_ribbon")
destroy lnv_gen
// Copy it, ready to paste
ClipBoard(ls_code)
The conversion is deterministic: no AI, no network call, nothing that leaves the machine. Each generated key is the ClassName of the menu item (m_fichier, m_ouvrir): the address the ribbon reports (m_fichier/g1/m_ouvrir) therefore leads back to the item, and the router written at the end of the code fires its Clicked from ue_clicked, ue_toggled and ue_menu_selected - your existing code runs as it is. Submenus are carried over at any depth, a hidden item is left out, a greyed one stays greyed, a checked one becomes a toggle or a checkable entry that starts checked.
The generated code is a starting point to review, not a deliverable: a menu is a list, a ribbon is a layout. Group things, choose your big buttons, drop what does not deserve to be permanently on show. Sample 9 of the ribbon page in the demo application shows a complete result.
Best practices #
- Wrap the whole build in
of_set_redraw(false)/of_set_redraw(true): a complete ribbon is then drawn in one go, without flickering. - Every add returns a code:
0, or-5for a wrong address, a parent of the wrong nature or a key already taken. Test it where a build error matters to you; to drive a control afterwards,of_item(address)returns its handle. - Call
of_preload_iconsat startup: without it, the first display of a tab that has never been opened shows a brief delay before its icons appear. - An identifier only needs to be unique within its group. Take advantage of that to name your controls simply (
copy,paste) rather than with prefixes. - Reserve contextual tabs for commands that make no sense out of context: a grayed-out permanent tab is more restful than a tab that appears and disappears.
- The question before a tile is off by default: switch it on with
ib_veto_gallery = trueonly ifue_gallery_selection_changingmust be able to refuse, since every question costs a round trip to PowerBuilder. - One dialog launcher per group at most, and only if the group really has advanced options to offer.
- To rebuild an entire ribbon, prefer
of_clear()(orof_reset()) over a series ofof_remove_tabcalls: one command, and every handle handed out is freed at once. - For a lighter command bar, without tabs or groups, see toolbar; for side navigation, listbar.
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.