PBToolboxAI v1 ← Site

dockcontainer — u_pbt_dockcontainer #

← Component reference · Guide contents

Visual Studio style dockable panels: drag-and-drop docking, tab stacking, resizable splitters, floating windows, auto-hide — plus saving and restoring the layout.

See it live — Demo application, Dock container tile: the preview, the code behind it and this page, side by side.


At a glance #

Userobjectu_pbt_dockcontainer
Item classn_pbt_dock_panel (one panel)
Used forGiving a PowerBuilder window the ergonomics of a modern IDE: users arrange their own panels, and the layout is still there at the next session

Just like tab, every panel hosts a real PowerBuilder control (dragobject): a userobject, a DataWindow, or another PBToolboxAI component. See Hosting real PowerBuilder controls.


Quick start #

// window open event : the panel controls are already placed on it
uo_dock.of_add_panel(/*key*/ "document", /*position*/ "", /*relative_to*/ "", &
                     /*size*/ 0, /*title*/ "Document", /*content*/ uo_editeur)

uo_dock.of_add_panel(/*key*/ "explorateur", /*position*/ uo_dock.POSITION_START, &
                     /*relative_to*/ "document", /*size*/ 260, &
                     /*title*/ "Explorer", /*content*/ uo_arbre)

uo_dock.of_add_panel(/*key*/ "proprietes", /*position*/ uo_dock.POSITION_END, &
                     /*relative_to*/ "document", /*size*/ 300, &
                     /*title*/ "Properties", /*content*/ uo_props)

// The central area : the docking cannot close, float or hide it
uo_dock.is_main = "document"

Properties #

PropertyTypeDefaultPurpose
is_mainstring""Key of the main panel: the central document area, which can neither be hidden nor floated. The panel must already exist
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

Docking positions #

The component constants feed as_position in of_add_panel and of_move_panel:

ConstantValueEffect
POSITION_START"start"The new panel docks on the reading start side of the reference panel (on the left in left-to-right writing)
POSITION_END"end"… on the reading end side
POSITION_TOP"top"… above it
POSITION_BOTTOM"bottom"… below it
POSITION_STACK"stack"The panel is stacked as a tab onto the reference panel. This is the value used when as_position is empty

Properties of a panel — n_pbt_dock_panel #

Obtained through of_item(key).

PropertyTypeDefaultPurpose
is_titlestring""Title shown on the panel tab. Accepts rich text markup
is_short_titlestring""Short form of the title, for the places where the room is scarce: the edge rail of a pinned panel (always — it is a sliver) and a stacked tab, but only once the full title no longer fits, which is measured rather than guessed. The panel header keeps the full title. "" = no short form
ib_visiblebooleantrueShows or hides this panel
ib_pinnedbooleantruetrue = pinned in place; false = the panel collapses to a strip on the edge and only slides out on hover (auto-hide)
is_header_colorstring""Header colour of this panel. Empty = the theme decides; HEADER_COLOR_ACCENT follows the theme accent (and keeps following it after a theme change, which a fixed code would not); otherwise a #rrggbb. The readable text colour comes with it
is_border_colorstring""Border colour of this panel, same grammar. It outlines the frame and the header, which each carry their own: colouring only one leaves a visible seam. It follows the panel into its fly-out
is_tooltipstring""Simple tooltip shown when hovering the item
is_super_tooltip_titlestring""Title of the item rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the item rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the item rich tooltip

Methods #

MethodPurpose
of_add_panel (string as_key, string as_position, string as_relative_to, integer ai_size, string as_title, dragobject ado_content)Adds a closable panel and hosts the control. as_relative_to = key of the panel it docks against (empty = the root); ai_size = initial size in pixels (0 = automatic)
of_add_panel (…, boolean ab_closable)Same thing, with ab_closable = false for a panel without a close button
of_select_panel (string as_key)Brings a panel to the front of its tab group
of_move_panel (string as_key, string as_target, string as_position)Rearranges from code, exactly as if the user had dragged the tab
of_move_panel (string as_key, string as_target, string as_position, integer ai_index)Same thing, giving the panel's rank inside the target stack (0 = first, -1 = last). Only a stack is an ordered list: the index is ignored for POSITION_START / END / TOP / BOTTOM
of_float_panel (string as_key)Floats the panel into a real floating window that can be moved and resized. Closing it docks the panel back (ue_panel_docked)
of_notify_panel (string as_key)Signals new content: if the panel is not visible, its tab shows a count of unseen items, cleared when the panel is selected
of_clear_notify (string as_key)Clears that counter without showing the panel. Selecting the tab was the only other way, which is wrong when your code knows the content itself is gone
of_remove_panel (string as_key)Removes the panel and returns the control to its original window
of_get_layout ( )Returns the current layout (split tree, ratios, tabs, visibility) as a string, ready to be stored in a file, a database or the registry
of_set_layout (string as_json)Restores a layout obtained from of_get_layout. The panels must have been re-created before the call; any panel missing from the layout is attached to the first group
of_item (string as_id)n_pbt_dock_panel handle of the panel (created on first access)
of_refresh_panel (string as_key)Refreshes the rendering of a panel built off-screen, without flicker
of_relayout ( )Recomputes and republishes every area so that the hosted controls are repositioned
of_reset ( )Empties the container: every hosted control is returned to its original window, the panel handles are released, and the stored layout is cleared
of_set_redraw (boolean)Groups a burst of changes into a single render
of_save_as_png (string) · of_save_as_jpg (string)Exports the rendering as an image

Events #

EventRaised when
ue_panel_selected (string as_key)A panel becomes the active panel of its group
ue_panel_closed (string as_key)The user closes a panel
ue_panel_pinned (string as_key, boolean ab_pinned)A panel is pinned (true) or unpinned into auto-hide (false)
ue_panel_floated (string as_key)A panel is floated into a floating window
ue_panel_docked (string as_key)A floating panel is docked back
ue_layout_changed (string as_json)The layout has changed (drag, resize, docking). The parameter carries the new layout, ready to be saved
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)

Keyboard #

A panel's content is a real PowerBuilder control: the keyboard there belongs to your code, as in any window. What the component takes care of is its own chrome — headers, tabs, splitters:

KeyEffect
Arrows on a tabMove to the previous / next panel of the group, and select it. A tab strip is a single tab stop
Home / End on a tabFirst / last panel of the group
Arrows on a splitterMove the separation by 2 %, along the splitter's axis only
Page Up / Page Down on a splitterThe same, in 10 % steps
EscapeCloses the sliding panel opened from an edge button

A splitter is a focusable separator that announces its position; the header buttons (float, hide, close) carry a name, and the active panel of a group is marked aria-selected. A keyboard move is reported through ue_layout_changed exactly like a mouse drag.


Examples #

An IDE-style window #

// open event : every content is a real PB control placed on the window
uo_dock.of_add_panel("document", "", "", 0, "Document", uo_editeur)
uo_dock.of_add_panel("explorateur", uo_dock.POSITION_START,   "document", 260, "Explorer", uo_arbre)
uo_dock.of_add_panel("proprietes",  uo_dock.POSITION_END,  "document", 300, "Properties",  uo_props)
uo_dock.of_add_panel("sortie",      uo_dock.POSITION_BOTTOM, "document", 200, "Output",      uo_console)

// A second panel stacked as a tab onto "proprietes"
uo_dock.of_add_panel("aide", uo_dock.POSITION_STACK, "proprietes", 0, "Help", uo_aide)

uo_dock.is_main = "document"

Remembering and restoring the user's layout #

// window close event : save what the user has arranged
string ls_disposition
ls_disposition = uo_dock.of_get_layout()
of_enregistrer_preference("dock_principal", ls_disposition)
// open event : RE-CREATE the panels first, restore afterwards
string ls_disposition

of_creer_les_panneaux()          // the of_add_panel calls above

ls_disposition = of_lire_preference("dock_principal")
if ls_disposition <> "" then uo_dock.of_set_layout(ls_disposition)

The order matters: of_set_layout creates no panel, it only rearranges the ones that already exist.

Tracking changes continuously #

// ue_layout_changed event of uo_dock : (string as_json)
// Saved right away, without waiting for the window to close.
of_enregistrer_preference("dock_principal", as_json)

Driving a panel through its handle #

n_pbt_dock_panel lnv_panneau

lnv_panneau = uo_dock.of_item("proprietes")
lnv_panneau.is_title  = "Properties (3 changed)"
lnv_panneau.ib_pinned = false        // collapses to a strip on the edge
// Hide a panel reserved for administrators
uo_dock.of_item("audit").ib_visible = gb_administrateur

Drawing attention to a background panel #

// A background task wrote to the console : signal it without stealing the focus
uo_dock.of_notify_panel("sortie")

Rearranging from code #

// Move a panel as if the user had dragged its tab
uo_dock.of_move_panel(/*key*/ "sortie", /*target*/ "document", /*position*/ "bottom")

// Stack it as a tab onto another panel
uo_dock.of_move_panel(/*key*/ "aide", /*target*/ "proprietes", /*position*/ "stack")

Floating a panel onto a second monitor #

// Native floating window : the user can drop it on another monitor
uo_dock.of_float_panel("proprietes")
// ue_panel_docked event of uo_dock : (string as_key)
// The user closed the floating window : the panel is back.
of_journaliser("Panel docked back : " + as_key)

Closing a panel cleanly #

// ue_panel_closed event of uo_dock : (string as_key)
// Also remove the panel from the container to release the hosted control.
uo_dock.of_remove_panel(as_key)

Best practices #


← Component reference · Guide contents