Toolbar
Toolbar is a row of controls: what is written into it lines up horizontally,
each item as wide as it needs to be, rather than taking a row of the page
each. Sticky keeps that row at the top of the page while the rest of it
scrolls under.
Usage
func Toolbar(c *tgframe.Container, conf ...*ToolbarConf) *tgframe.Container
c: Parent container.conf: Optional configuration, at most one.
// ToolbarConf is the configuration for the Toolbar component.
type ToolbarConf struct {
tgframe.Base // ID
// Sticky keeps the row at the top of the page while the rest of it
// scrolls under, on an opaque background so nothing shows through.
Sticky bool
// Justify is ToolbarJustifyStart (default), ToolbarJustifyEnd or
// ToolbarJustifyBetween. Anything else panics.
Justify string
}
The container a toolbar hands out derives its id from the toolbar's; give none and it carries none, and the components inside are still placed by position.
Justify says where the row's spare width goes:
| Value | Items sit |
|---|---|
ToolbarJustifyStart | at the start of the row, the default |
ToolbarJustifyEnd | at the end of the row |
ToolbarJustifyBetween | spread out, first and last at the edges |
A row too wide for the viewport wraps rather than pushing the page sideways, so a toolbar is as safe on a phone as a column is.
Example
bar := tgcomp.Toolbar(p.Main, &tgcomp.ToolbarConf{ID: "toolbar"})
run := tgcomp.Button(bar, "Run", &tgcomp.ButtonConf{ID: "toolbar_run"})
tgcomp.Button(bar, "Stop", &tgcomp.ButtonConf{ID: "toolbar_stop"})
modes := []string{"fast", "safe"}
mode := tgcomp.Select(bar, "Mode", modes,
(&tgcomp.SelectConf{ID: "toolbar_mode"}).SetDefault(0))
tgcomp.Text(p.Main, fmt.Sprintf("Run: %v, mode: %s", run, modes[*mode]),
&tgcomp.TextConf{ID: "toolbar_result"})
Sticky
A sticky toolbar stays at the top of the viewport while the page scrolls under it, on the page's own background and with a line under it, so what passes beneath does not show through:
bar := tgcomp.Toolbar(p.Main, &tgcomp.ToolbarConf{
ID: "sticky_toolbar",
Sticky: true,
Justify: tgcomp.ToolbarJustifyBetween,
})
tgcomp.Subtitle(bar, "Report")
tgcomp.Button(bar, "Export", &tgcomp.ButtonConf{ID: "toolbar_export"})
// Enough rows to scroll, so the row above stays put while they pass
// under it.
for i := range 40 {
tgcomp.Text(p.Main, fmt.Sprintf("row-%d", i))
}
It sticks to whatever scrolls the page, which for an app in the shell is the document. A toolbar written inside something that scrolls on its own — a dialog body — sticks to the top of that instead, and below anything that container already keeps there: a dialog's own header is sticky, so the row stops under it rather than sliding beneath it.
d := tgcomp.Dialog(p.Main, "Rows", &tgcomp.DialogConf{ID: "toolbar_dialog"})
if tgcomp.Button(p.Main, "Open", &tgcomp.ButtonConf{ID: "toolbar_dialog_open"}) {
d.Open()
}
d.With(func(c *tgframe.Container) {
bar := tgcomp.Toolbar(c, &tgcomp.ToolbarConf{
ID: "dialog_toolbar",
Sticky: true,
})
tgcomp.Button(bar, "Export", &tgcomp.ButtonConf{ID: "toolbar_dialog_export"})
// A dialog scrolls its own body, so the row sticks to the top of
// that -- below the dialog's header rather than under it.
for i := range 30 {
tgcomp.Text(c, fmt.Sprintf("dialog-row-%d", i))
}
})
Toolbar or Column?
Column is for laying a page out in parts: each column is a
share of the width, and what goes in one is a section of the page. A toolbar
is for the controls above that page — it packs them together at their natural
widths, wraps them on a narrow screen and, with Sticky, keeps them reachable
however far down the page the reader is.