gui.flow
The layout engine of the Salam style standard: column, row, grid, stack and flow layouts, positioning, scrolling and right to left, with incremental relayout.
import gui.flow
gui.flow computes the rectangle of every box of a native user interface. It implements exactly the layouts of the Salam style standard and nothing else: column and row (the flex model with grow, shrink, basis, wrapping, gaps, alignment and order), grid (track lists with pixels, percent, fr, auto, minmax, repeat, fit and content sizes, explicit lines, spans and auto placement), stack (every child in one cell) and flow (children placed like words, wrapped onto lines and baseline aligned). It is not a CSS engine: there is no display, float, block formatting context, margin collapsing or table.
You build a Tree, give every box a FlowStyle, give leaves such as text and images a measure function, and call Layout with the size of the window. Then X, Y, W and H give each box relative to its parent. The package depends on nothing else in gui; gui.ui maps the style of an element to a FlowStyle.
Things to know:
- Every box is border box. Width and height include padding and border, and margins apply in every layout,
automargins included. - Lengths come resolved. em, rem, vw and vh are converted to pixels by the caller; only percent stays, because only the layout knows the reference.
- Content is not crushed.
min_widthandmin_heightdefault toAuto(): a child of a row or column does not shrink below its min content width or content height, as in a browser. Set them to 0 to allow it, or give a child an overflow other than visible. - The flow layout has no gaps. It is formatted like inline text, so space its children with margins.
- Absolute and fixed boxes keep their static position on an axis with no inset: where the parent's justify and align would place them as the only child.
- A root fills the viewport when its width or height is auto; use
Fit()to size it to its content. - Right to left mirrors rows, flow lines, grid columns, start and end.
leftandrightstay physical. - Layout is incremental. Changing a style or a measure marks the box and its ancestors;
Layoutlays out only those again and reuses cached sizes elsewhere.LayoutCallsandMeasureCallsshow the work done.
An application shell
A header, a body with a side bar and a scrolling content area, and a footer. The body has basis = 0, grows, and has min_height = 0, so its long content does not push the header and footer away (by default a child of a column is never shorter than its content); the content area scrolls instead, and ContentH tells how far. The same tree in right to left puts the side bar on the right.
import gui.flow
func show(t &: flow.Tree, name: str, id: int):
println name, t.X(id), t.Y(id), t.W(id), t.H(id)
end
func build(t &: flow.Tree, dir: int): (int, int, int, int):
app := t.Add(-1, flow.FlowStyle { direction = dir })
header := t.Add(app, flow.FlowStyle { layout = flow.LAYOUT_ROW, height = flow.Px(48.0), padding = flow.Sides(flow.Px(0.0), flow.Px(16.0), flow.Px(0.0), flow.Px(16.0)), align = flow.ALIGN_CENTER, column_gap = flow.Px(12.0) })
t.Add(header, flow.FlowStyle { width = flow.Px(32.0), height = flow.Px(32.0) })
t.Add(header, flow.FlowStyle { grow = 1.0, height = flow.Px(20.0) })
body := t.Add(app, flow.FlowStyle { layout = flow.LAYOUT_ROW, grow = 1.0, basis = flow.Px(0.0), min_height = flow.Px(0.0) })
side := t.Add(body, flow.FlowStyle { width = flow.Px(180.0), border = flow.Sides(flow.Px(0.0), flow.Px(1.0), flow.Px(0.0), flow.Px(0.0)) })
content := t.Add(body, flow.FlowStyle { grow = 1.0, padding = flow.All(flow.Px(16.0)), row_gap = flow.Px(8.0), overflow_y = flow.OVERFLOW_AUTO })
repeat 30:
t.Add(content, flow.FlowStyle { height = flow.Px(40.0), shrink = 0.0 })
end
footer := t.Add(app, flow.FlowStyle { height = flow.Px(24.0) })
ret header, side, content, footer
end
func main:
mut t := flow.NewTree()
header, side, content, footer := build(t, flow.DIR_LTR)
t.Layout(800.0, 600.0)
show(t, "header", header)
show(t, "side", side)
show(t, "content", content)
show(t, "footer", footer)
println "content scrolls by", t.ContentH(content) - t.H(content)
mut r := flow.NewTree()
_, rside, rcontent, _ := build(r, flow.DIR_RTL)
r.Layout(800.0, 600.0)
show(r, "rtl side", rside)
show(r, "rtl content", rcontent)
endText through a measure function
A leaf's measure function gets the available width and returns the size of the wrapped text. Here a one word label and a long paragraph sit in a row aligned on their baselines; the paragraph has basis = 0 and grows, so it takes the rest of the row and wraps when the window narrows. A layout with nothing changed does no work, and marking the paragraph dirty measures it once.
import gui.flow
func paragraph(t &: flow.Tree, parent: int, words: int): int:
id := t.Add(parent, flow.FlowStyle {})
t.SetMeasure(id, (_id: int, w: f64, _h: f64):
mut per := words
if w >= 0.0:
per = ((w + 4.0) / 44.0) as int
if per < 1:
per = 1
end
if per > words:
per = words
end
end
lines := (words + per - 1) / per
ret flow.Size { w = (per as f64) * 44.0 - 4.0, h = (lines as f64) * 18.0, baseline = 14.0 }
end)
ret id
end
func main:
mut t := flow.NewTree()
card := t.Add(-1, flow.FlowStyle { layout = flow.LAYOUT_ROW, align = flow.ALIGN_BASELINE, column_gap = flow.Px(12.0), padding = flow.All(flow.Px(8.0)), height = flow.Fit() })
label := paragraph(t, card, 1)
text := paragraph(t, card, 20)
mut st := t.Style(text)
st.grow = 1.0
st.basis = flow.Px(0.0)
t.SetStyle(text, st)
each width in [600.0, 300.0, 600.0]:
t.ResetCounters()
t.Layout(width, 400.0)
println "width", width, "card height", t.H(card), "text size", t.W(text), t.H(text), "label y", t.Y(label), "measures", t.MeasureCalls()
end
t.ResetCounters()
t.Layout(600.0, 400.0)
println "unchanged layout calls", t.LayoutCalls(), "measures", t.MeasureCalls()
t.MarkDirty(text)
t.Layout(600.0, 400.0)
println "text changed, layout calls", t.LayoutCalls(), "measures", t.MeasureCalls()
endTypes
Len
struct Lenpx plus pct times the reference size for a fixed one, or a keyword in kind. em, rem, vw and vh are converted to pixels before they reach the layout.| Name | Type | Description |
|---|---|---|
px | f64 = 0 | Pixels. |
pct | f64 = 0 | Fraction of the reference size, 0.5 for 50%. The reference is the parent's content width for widths, padding, margins and gaps across, and its content height for heights. |
kind | int = 0 | One of the LEN_ constants. |
import gui.flow
func show(name: str, l: flow.Len):
println name, "px", l.px, "pct", l.pct, "kind", l.kind
end
func main:
show("Px(12)", flow.Px(12.0))
show("Pct(0.5)", flow.Pct(0.5))
show("PxPct(-20, 1)", flow.PxPct(-20.0, 1.0))
show("Auto", flow.Auto())
show("Fill", flow.Fill())
show("Fit", flow.Fit())
show("MinContent", flow.MinContent())
show("MaxContent", flow.MaxContent())
show("NoLimit", flow.NoLimit())
println "kinds", flow.LEN_FIXED, flow.LEN_AUTO, flow.LEN_FILL, flow.LEN_FIT, flow.LEN_MIN_CONTENT, flow.LEN_MAX_CONTENT, flow.LEN_NONE
pad := flow.Sides(flow.Px(4.0), flow.Px(8.0), flow.Px(4.0), flow.Px(16.0))
println "sides top", pad.top.px, "end", pad.end.px, "bottom", pad.bottom.px, "start", pad.start.px
mut m := flow.All(flow.Px(10.0))
m.left = flow.Px(2.0)
m.right = flow.Auto()
println "all with physical overrides", m.top.px, m.left.px, m.right.kind
s := flow.Size { w = 120.0, h = 48.0, baseline = 12.0, last_baseline = 44.0 }
println "size", s.w, s.h, s.baseline, s.last_baseline
mut t := flow.NewTree()
root := t.Add(-1, flow.FlowStyle { padding = flow.All(flow.Pct(0.05)), align = flow.ALIGN_START })
a := t.Add(root, flow.FlowStyle { width = flow.PxPct(-20.0, 1.0), height = flow.Px(10.0) })
b := t.Add(root, flow.FlowStyle { width = flow.Fill(), height = flow.Px(10.0), margin = m })
t.Layout(200.0, 100.0)
println "a", t.X(a), t.Y(a), t.W(a), t.H(a)
println "b", t.X(b), t.Y(b), t.W(b), t.H(b)
endSize
struct Size| Name | Type | Description |
|---|---|---|
w | f64 = 0 | Content width. |
h | f64 = 0 | Content height. |
baseline | f64 = -1 | Distance from the top of the content to the first baseline, or -1 for none (the bottom edge is used then). |
last_baseline | f64 = -1 | Distance from the top of the content to the last baseline, for text of several lines; -1 means the same as baseline. A flow parent aligns its children on their last baseline. |
The example for this item is shown with the ones above: gui-flow-Lengths.salam
Edges
struct Edgesstart and end follow the direction; left and right are physical and win when set. A side that is not set is 0, or auto for an inset.| Name | Type | Description |
|---|---|---|
top | Len | Top side. |
end | Len | End side: right in left to right, left in right to left. |
bottom | Len | Bottom side. |
start | Len | Start side: left in left to right, right in right to left. |
left | Len | Left side, whatever the direction; overrides start or end. |
right | Len | Right side, whatever the direction; overrides start or end. |
The example for this item is shown with the ones above: gui-flow-Lengths.salam
Track
struct TrackTrackLen, TrackFr, TrackAuto, TrackMinMax, TrackFit or Repeat.| Name | Type | Description |
|---|---|---|
min | Len | Minimum sizing: a fixed length, auto, min content or max content. |
max | Len | Maximum sizing: a fixed length, auto, min content or max content; the limit of a fit track. |
fr | f64 = 0 | When above zero, the maximum is this many shares of the free space. |
fit | bool = false | The track is fit(max): sized to its content but no larger than max. |
count | int = 0 | Above zero: a repeat of tracks this many times; REPEAT_FILL or REPEAT_FIT: as many as fit; zero: a single track. |
tracks | Vector | The tracks of a repeat. |
import gui.flow
func show(t &: flow.Tree, name: str, id: int):
println name, t.X(id), t.Y(id), t.W(id), t.H(id)
end
func main:
mut cols := Vector {} as Vector<flow.Track>
cols.push(flow.TrackLen(flow.Px(80.0)))
cols.push(flow.TrackMinMax(flow.TrackLen(flow.Px(60.0)), flow.TrackFr(1.0)))
cols.push(flow.TrackFit(flow.Px(100.0)))
mut rows := Vector {} as Vector<flow.Track>
rows.push(flow.TrackLen(flow.Px(30.0)))
rows.push(flow.TrackAuto())
tr := cols.get(1)
println "minmax track", tr.min.px, tr.max.kind, tr.fr, tr.fit, tr.count, tr.tracks.len()
mut t := flow.NewTree()
grid := t.Add(-1, flow.FlowStyle {
layout = flow.LAYOUT_GRID,
columns = cols,
rows = rows,
auto_rows = flow.TrackLen(flow.Px(20.0)),
auto_columns = flow.TrackLen(flow.Px(40.0)),
auto_flow = flow.AUTO_FLOW_ROW,
column_gap = flow.Px(10.0),
row_gap = flow.Px(5.0)
})
header := t.Add(grid, flow.FlowStyle { column = 1, column_span = 3 })
side := t.Add(grid, flow.FlowStyle { row = 2, row_span = 2, column = 1 })
body := t.Add(grid, flow.FlowStyle { height = flow.Px(50.0) })
note := t.Add(grid, flow.FlowStyle { width = flow.Px(30.0), height = flow.Px(10.0), justify_self = flow.ALIGN_END, align_self = flow.ALIGN_CENTER })
last := t.Add(grid, flow.FlowStyle { column = -1 })
t.Layout(360.0, 400.0)
show(t, "grid", grid)
show(t, "header", header)
show(t, "side", side)
show(t, "body", body)
show(t, "note", note)
show(t, "last", last)
mut cards := Vector {} as Vector<flow.Track>
mut inner := Vector {} as Vector<flow.Track>
inner.push(flow.TrackMinMax(flow.TrackLen(flow.Px(100.0)), flow.TrackFr(1.0)))
cards.push(flow.Repeat(flow.REPEAT_FIT, inner))
mut g := flow.NewTree()
gallery := g.Add(-1, flow.FlowStyle { layout = flow.LAYOUT_GRID, columns = cards, auto_rows = flow.TrackLen(flow.Px(60.0)), column_gap = flow.Px(10.0) })
a := g.Add(gallery, flow.FlowStyle {})
b := g.Add(gallery, flow.FlowStyle {})
g.Layout(450.0, 300.0)
show(g, "card a", a)
show(g, "card b", b)
println "repeat counts", flow.REPEAT_FILL, flow.REPEAT_FIT
println "auto flow", flow.AUTO_FLOW_ROW, flow.AUTO_FLOW_COLUMN, flow.AUTO_FLOW_ROW_DENSE, flow.AUTO_FLOW_COLUMN_DENSE
endFlowStyle
struct FlowStyle| Name | Type | Description |
|---|---|---|
layout | int | How the children are laid out: one of the LAYOUT_ constants. Default column. |
row_gap | Len | Space between rows, wrapped lines and grid rows. The flow layout ignores it. |
column_gap | Len | Space between items of a row, wrapped columns and grid columns. The flow layout ignores it. |
align | int | Cross axis alignment of the children: start, center, end, stretch or baseline. Default stretch. In a grid it aligns items in their rows, in a stack vertically. |
justify | int | Main axis distribution: start, center, end, between, around or evenly. In a grid it distributes the columns, in a stack it places children horizontally. |
align_content | int | Distribution of wrapped lines, or of grid rows. Default start. |
wrap | bool = false | Row and column only: wrap children onto new lines when they do not fit. |
reverse | bool = false | Row and column only: lay the children out from the end. |
columns | Vector | Column track list of a grid. |
rows | Vector | Row track list of a grid. |
auto_columns | Track | Track for columns added past the list. Default auto. |
auto_rows | Track | Track for rows added past the list. Default auto. |
auto_flow | int | How grid items without a place are placed: one of the AUTO_FLOW_ constants. |
grow | f64 = 0 | Share of positive free space this child takes in a row or column. Default 0. |
shrink | f64 = 1 | Share of negative free space, weighted by the basis. Default 1. |
basis | Len | Starting main size before growing and shrinking; auto uses the width or height, then the content. |
align_self | int | This child's own cross axis alignment; auto uses the parent's align. |
justify_self | int | Grid and stack only: this child's horizontal alignment in its cell; auto stretches in a grid and uses the parent's justify in a stack. |
column | int = 0 | Grid column line where the item starts, 1 based. A negative number counts from the end and puts the item's end edge on that line, so -1 is the last column. 0 places it automatically. |
row | int = 0 | Grid row line, with the same rules as column. |
column_span | int = 1 | Number of columns the item covers. Default 1. |
row_span | int = 1 | Number of rows the item covers. Default 1. |
order | int = 0 | Children with a smaller order come first in rows, columns, grids and flow; equal orders keep their order. |
position | int | One of the POS_ constants. |
inset | Edges | Top, end, bottom, start, left and right offsets for absolute, fixed and sticky boxes. A side that is not set is auto. |
layer | int = 0 | Paint and hit test order among siblings, read back with Layer and PaintOrder; it does not change the layout. |
width | Len | Border box width: a length, auto, fill, fit, min content or max content. |
height | Len | Border box height, with the same kinds as width. |
min_width | Len | Smallest width. The default Auto() keeps a child of a row at least as wide as its min content (or its width, when that is smaller), unless its horizontal overflow is not visible; elsewhere it is 0. Set 0 to let a child shrink below its content. |
min_height | Len | Smallest height. The default Auto() keeps a child of a column at least as tall as its content (or its height, when that is smaller), unless its vertical overflow is not visible; elsewhere it is 0. Set 0 to let a child shrink below its content. |
max_width | Len | Largest width, or no limit. A min larger than the max wins. |
max_height | Len | Largest height, or no limit. |
aspect_ratio | f64 = 0 | Width divided by height; used when one of them is auto. 0 means none. |
padding | Edges | Space inside the border. Every box is border box: padding and border are part of the width and height. |
margin | Edges | Space outside the border; an auto side takes the free space, which centres or pushes the box. |
border | Edges | Border widths; they take space like padding. |
overflow_x | int | Horizontal overflow: one of the OVERFLOW_ constants. When one axis is not visible, visible on the other axis acts as auto. |
overflow_y | int | Vertical overflow: one of the OVERFLOW_ constants. When one axis is not visible, visible on the other axis acts as auto. |
visible | bool = true | False removes the box and its children from the layout. |
direction | int | One of the DIR_ constants. Changing it relays out the whole subtree. |
text_align | int | Alignment of the lines of a flow layout: one of the TEXT_ constants. |
import gui.flow
func show(t &: flow.Tree, name: str, id: int):
println name, t.X(id), t.Y(id), t.W(id), t.H(id)
end
func main:
mut t := flow.NewTree()
bar := t.Add(-1, flow.FlowStyle {
layout = flow.LAYOUT_ROW,
column_gap = flow.Px(8.0),
row_gap = flow.Px(4.0),
align = flow.ALIGN_CENTER,
justify = flow.ALIGN_START,
align_content = flow.ALIGN_START,
wrap = false,
reverse = false,
padding = flow.All(flow.Px(6.0)),
border = flow.All(flow.Px(1.0)),
height = flow.Px(48.0),
direction = flow.DIR_LTR
})
logo := t.Add(bar, flow.FlowStyle { width = flow.Px(32.0), aspect_ratio = 1.0 })
title := t.Add(bar, flow.FlowStyle { grow = 1.0, shrink = 1.0, basis = flow.Px(100.0), height = flow.Px(20.0), min_width = flow.Px(60.0), max_width = flow.Px(400.0) })
search := t.Add(bar, flow.FlowStyle { width = flow.Px(120.0), min_height = flow.Px(24.0), max_height = flow.NoLimit(), align_self = flow.ALIGN_STRETCH })
menu := t.Add(bar, flow.FlowStyle { width = flow.Px(24.0), height = flow.Px(24.0), order = -1 })
hidden := t.Add(bar, flow.FlowStyle { width = flow.Px(50.0), visible = false })
t.Layout(400.0, 300.0)
show(t, "bar", bar)
show(t, "logo", logo)
show(t, "title", title)
show(t, "search", search)
show(t, "menu", menu)
show(t, "hidden", hidden)
println "layouts", flow.LAYOUT_COLUMN, flow.LAYOUT_ROW, flow.LAYOUT_GRID, flow.LAYOUT_STACK, flow.LAYOUT_FLOW
println "aligns", flow.ALIGN_AUTO, flow.ALIGN_START, flow.ALIGN_CENTER, flow.ALIGN_END, flow.ALIGN_STRETCH, flow.ALIGN_BASELINE, flow.ALIGN_BETWEEN, flow.ALIGN_AROUND, flow.ALIGN_EVENLY
println "directions", flow.DIR_INHERIT, flow.DIR_LTR, flow.DIR_RTL
mut w := flow.NewTree()
list := w.Add(-1, flow.FlowStyle { layout = flow.LAYOUT_ROW, wrap = true, column_gap = flow.Px(10.0), row_gap = flow.Px(10.0), justify = flow.ALIGN_BETWEEN, align_content = flow.ALIGN_END, height = flow.Px(150.0), direction = flow.DIR_RTL })
mut cards := Vector {} as Vector<int>
repeat 5:
cards.push(w.Add(list, flow.FlowStyle { width = flow.Px(70.0), height = flow.Px(40.0) }))
end
w.Layout(250.0, 300.0)
each i, c in cards:
show(w, "card" + i, c)
end
endTree
struct Treeimport gui.flow
func main:
mut t := flow.NewTree()
root := t.Add(-1, flow.FlowStyle { row_gap = flow.Px(4.0) })
a := t.Add(root, flow.FlowStyle { height = flow.Px(20.0) })
b := t.Add(root, flow.FlowStyle {})
t.SetMeasure(b, (_id: int, w: f64, _h: f64):
mut lines := 1.0
if w >= 0.0 and w < 200.0:
lines = 2.0
end
ret flow.Size { w = 200.0, h = lines * 16.0, baseline = 12.0 }
end)
t.Layout(300.0, 200.0)
println "valid", t.Valid(b), t.Valid(42), "count", t.Count()
println "parent", t.Parent(b), "children", t.ChildCount(root), "second", t.Child(root, 1)
println "b", t.X(b), t.Y(b), t.W(b), t.H(b), "baseline", t.Baseline(b)
println "calls", t.LayoutCalls(), t.MeasureCalls()
t.ResetCounters()
t.Layout(300.0, 200.0)
println "again", t.LayoutCalls(), t.MeasureCalls(), "dirty", t.IsDirty(root)
mut st := t.Style(a)
st.height = flow.Px(30.0)
t.SetStyle(a, st)
println "after SetStyle dirty", t.IsDirty(a), t.IsDirty(root), t.IsDirty(b)
t.Layout(300.0, 200.0)
println "b moved to", t.Y(b), "calls", t.LayoutCalls()
t.MarkDirty(b)
t.Layout(150.0, 200.0)
println "narrow b", t.W(b), t.H(b)
t.ClearMeasure(b)
t.Move(b, root, 0)
t.Layout(150.0, 200.0)
println "b first", t.Child(root, 0), t.Y(a), t.H(b)
t.Remove(a)
println "removed", t.Valid(a), t.ChildCount(root)
t.Free()
println "freed", t.Count()
endAdd
func Add(parent: int, style: FlowStyle): intparent and returns its id. A parent of -1 makes a root. Ids of removed boxes are reused.The example for this item is shown with the ones above: gui-flow-Tree.salam
Valid
func Valid(id: int): boolThe example for this item is shown with the ones above: gui-flow-Tree.salam
Count
func Count(): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
Parent
func Parent(id: int): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
ChildCount
func ChildCount(id: int): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
Child
func Child(id: int, index: int): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
Style
func Style(id: int): FlowStyleThe example for this item is shown with the ones above: gui-flow-Tree.salam
SetStyle
func SetStyle(id: int, style: FlowStyle)The example for this item is shown with the ones above: gui-flow-Tree.salam
Remove
func Remove(id: int)The example for this item is shown with the ones above: gui-flow-Tree.salam
Move
func Move(id: int, parent: int, index: int)The example for this item is shown with the ones above: gui-flow-Tree.salam
SetMeasure
func SetMeasure(id: int, fn: func(int, f64, f64): Size)fn(id, width, height). Width is the available content width, -1 for no limit (max content) and 0 for min content; height is the known content height or -1. Text, images and controls are leaves.The example for this item is shown with the ones above: gui-flow-Tree.salam
ClearMeasure
func ClearMeasure(id: int)The example for this item is shown with the ones above: gui-flow-Tree.salam
MarkDirty
func MarkDirty(id: int)The example for this item is shown with the ones above: gui-flow-Tree.salam
IsDirty
func IsDirty(id: int): boolThe example for this item is shown with the ones above: gui-flow-Tree.salam
Layout
func Layout(width: f64, height: f64)The example for this item is shown with the ones above: gui-flow-Tree.salam
X
func X(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
Y
func Y(id: int): f64X.The example for this item is shown with the ones above: gui-flow-Tree.salam
W
func W(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
H
func H(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
AbsX
func AbsX(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
AbsY
func AbsY(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
Baseline
func Baseline(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
ContentW
func ContentW(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
ContentH
func ContentH(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
SetScroll
func SetScroll(id: int, x: f64, y: f64)The example for this item is shown with the ones above: gui-flow-Tree.salam
ScrollX
func ScrollX(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
ScrollY
func ScrollY(id: int): f64The example for this item is shown with the ones above: gui-flow-Tree.salam
Layer
func Layer(id: int): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
PaintOrder
func PaintOrder(id: int): Vector<int>The example for this item is shown with the ones above: gui-flow-Tree.salam
LayoutCalls
func LayoutCalls(): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
MeasureCalls
func MeasureCalls(): intThe example for this item is shown with the ones above: gui-flow-Tree.salam
ResetCounters
func ResetCounters()The example for this item is shown with the ones above: gui-flow-Tree.salam
Free
func Free()The example for this item is shown with the ones above: gui-flow-Tree.salam
Constants and variables
LEN_FIXED
const LEN_FIXED: i32 = 0Len that is a fixed length: px plus pct times the reference size.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_AUTO
const LEN_AUTO: i32 = 1Len that means auto: the layout decides, usually from the content or by stretching.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_FILL
const LEN_FILL: i32 = 2Len that fills the parent's content box minus the box's own margins.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_FIT
const LEN_FIT: i32 = 3Len that fits the content: the max content size, but no wider than the space and no narrower than the min content size.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_MIN_CONTENT
const LEN_MIN_CONTENT: i32 = 4Len that is the narrowest the content can be, for text the longest word.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_MAX_CONTENT
const LEN_MAX_CONTENT: i32 = 5Len that is the size of the content with no wrapping.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LEN_NONE
const LEN_NONE: i32 = 6Len that is not set: no limit for a max size, the default for an edge.The example for this item is shown with the ones above: gui-flow-Lengths.salam
LAYOUT_COLUMN
const LAYOUT_COLUMN: i32 = 0The example for this item is shown with the ones above: gui-flow-Row.salam
LAYOUT_ROW
const LAYOUT_ROW: i32 = 1The example for this item is shown with the ones above: gui-flow-Row.salam
LAYOUT_GRID
const LAYOUT_GRID: i32 = 2The example for this item is shown with the ones above: gui-flow-Grid.salam
LAYOUT_STACK
const LAYOUT_STACK: i32 = 3import gui.flow
func show(t &: flow.Tree, name: str, id: int):
println name, t.X(id), t.Y(id), t.W(id), t.H(id)
end
func main:
mut t := flow.NewTree()
page := t.Add(-1, flow.FlowStyle { layout = flow.LAYOUT_STACK, overflow_x = flow.OVERFLOW_HIDDEN, overflow_y = flow.OVERFLOW_SCROLL })
content := t.Add(page, flow.FlowStyle { height = flow.Px(900.0), width = flow.Fill() })
mut top := flow.FlowStyle { position = flow.POS_STICKY, height = flow.Px(40.0) }
top.inset.top = flow.Px(0.0)
bar := t.Add(content, top)
mut corner := flow.FlowStyle { position = flow.POS_ABSOLUTE, width = flow.Px(50.0), height = flow.Px(20.0), layer = 1 }
corner.inset.end = flow.Px(10.0)
corner.inset.top = flow.Px(10.0)
badge := t.Add(content, corner)
mut fab := flow.FlowStyle { position = flow.POS_FIXED, width = flow.Px(48.0), height = flow.Px(48.0), layer = 2 }
fab.inset.right = flow.Px(16.0)
fab.inset.bottom = flow.Px(16.0)
button := t.Add(content, fab)
t.Layout(300.0, 400.0)
println "content size", t.ContentW(page), t.ContentH(page)
t.SetScroll(page, 0.0, 120.0)
println "scroll", t.ScrollX(page), t.ScrollY(page)
show(t, "bar", bar)
show(t, "badge", badge)
show(t, "button", button)
println "button on screen", t.AbsX(button), t.AbsY(button)
print "paint order"
order := t.PaintOrder(content)
each id in order:
print " ", id, "layer", t.Layer(id)
end
println ""
order.free()
println "positions", flow.POS_NORMAL, flow.POS_ABSOLUTE, flow.POS_FIXED, flow.POS_STICKY
println "overflow", flow.OVERFLOW_VISIBLE, flow.OVERFLOW_HIDDEN, flow.OVERFLOW_SCROLL, flow.OVERFLOW_AUTO
mut p := flow.NewTree()
para := p.Add(-1, flow.FlowStyle { layout = flow.LAYOUT_FLOW, text_align = flow.TEXT_CENTER, width = flow.Px(100.0), height = flow.Fit() })
mut words := Vector {} as Vector<int>
repeat 4:
id := p.Add(para, flow.FlowStyle { margin = flow.Sides(flow.Px(0.0), flow.Px(2.0), flow.Px(0.0), flow.Px(2.0)) })
p.SetMeasure(id, (_id: int, _w: f64, _h: f64): ret flow.Size { w = 30.0, h = 12.0, baseline = 9.0 } end)
words.push(id)
end
p.Layout(300.0, 300.0)
each i, id in words:
show(p, "word" + i, id)
end
println "paragraph baseline", p.Baseline(para)
println "text aligns", flow.TEXT_START, flow.TEXT_CENTER, flow.TEXT_END, flow.TEXT_JUSTIFY, flow.TEXT_LEFT, flow.TEXT_RIGHT
endLAYOUT_FLOW
const LAYOUT_FLOW: i32 = 4The example for this item is shown with the ones above: gui-flow-Position.salam
ALIGN_AUTO
const ALIGN_AUTO: i32 = 0The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_START
const ALIGN_START: i32 = 1The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_CENTER
const ALIGN_CENTER: i32 = 2The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_END
const ALIGN_END: i32 = 3The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_STRETCH
const ALIGN_STRETCH: i32 = 4The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_BASELINE
const ALIGN_BASELINE: i32 = 5The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_BETWEEN
const ALIGN_BETWEEN: i32 = 6The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_AROUND
const ALIGN_AROUND: i32 = 7The example for this item is shown with the ones above: gui-flow-Row.salam
ALIGN_EVENLY
const ALIGN_EVENLY: i32 = 8The example for this item is shown with the ones above: gui-flow-Row.salam
POS_NORMAL
const POS_NORMAL: i32 = 0The example for this item is shown with the ones above: gui-flow-Position.salam
POS_ABSOLUTE
const POS_ABSOLUTE: i32 = 1The example for this item is shown with the ones above: gui-flow-Position.salam
POS_FIXED
const POS_FIXED: i32 = 2Layout. On an axis with no inset it keeps its static position, as absolute does, measured when laid out. It does not scroll.The example for this item is shown with the ones above: gui-flow-Position.salam
POS_STICKY
const POS_STICKY: i32 = 3The example for this item is shown with the ones above: gui-flow-Position.salam
OVERFLOW_VISIBLE
const OVERFLOW_VISIBLE: i32 = 0The example for this item is shown with the ones above: gui-flow-Position.salam
OVERFLOW_HIDDEN
const OVERFLOW_HIDDEN: i32 = 1SetScroll.The example for this item is shown with the ones above: gui-flow-Position.salam
OVERFLOW_SCROLL
const OVERFLOW_SCROLL: i32 = 2The example for this item is shown with the ones above: gui-flow-Position.salam
OVERFLOW_AUTO
const OVERFLOW_AUTO: i32 = 3The example for this item is shown with the ones above: gui-flow-Position.salam
DIR_INHERIT
const DIR_INHERIT: i32 = 0The example for this item is shown with the ones above: gui-flow-Row.salam
DIR_LTR
const DIR_LTR: i32 = 1The example for this item is shown with the ones above: gui-flow-Row.salam
DIR_RTL
const DIR_RTL: i32 = 2The example for this item is shown with the ones above: gui-flow-Row.salam
AUTO_FLOW_ROW
const AUTO_FLOW_ROW: i32 = 0The example for this item is shown with the ones above: gui-flow-Grid.salam
AUTO_FLOW_COLUMN
const AUTO_FLOW_COLUMN: i32 = 1The example for this item is shown with the ones above: gui-flow-Grid.salam
AUTO_FLOW_ROW_DENSE
const AUTO_FLOW_ROW_DENSE: i32 = 2The example for this item is shown with the ones above: gui-flow-Grid.salam
AUTO_FLOW_COLUMN_DENSE
const AUTO_FLOW_COLUMN_DENSE: i32 = 3The example for this item is shown with the ones above: gui-flow-Grid.salam
TEXT_START
const TEXT_START: i32 = 0The example for this item is shown with the ones above: gui-flow-Position.salam
TEXT_CENTER
const TEXT_CENTER: i32 = 1The example for this item is shown with the ones above: gui-flow-Position.salam
TEXT_END
const TEXT_END: i32 = 2The example for this item is shown with the ones above: gui-flow-Position.salam
TEXT_JUSTIFY
const TEXT_JUSTIFY: i32 = 3The example for this item is shown with the ones above: gui-flow-Position.salam
TEXT_LEFT
const TEXT_LEFT: i32 = 4The example for this item is shown with the ones above: gui-flow-Position.salam
TEXT_RIGHT
const TEXT_RIGHT: i32 = 5The example for this item is shown with the ones above: gui-flow-Position.salam
REPEAT_FILL
const REPEAT_FILL: i32 = -1Repeat: as many repetitions as fit the space.The example for this item is shown with the ones above: gui-flow-Grid.salam
REPEAT_FIT
const REPEAT_FIT: i32 = -2REPEAT_FILL, but repetitions with no item collapse to zero with their gaps.The example for this item is shown with the ones above: gui-flow-Grid.salam
Functions
Px
func Px(v: f64): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
Pct
func Pct(fraction: f64): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
PxPct
func PxPct(v: f64, fraction: f64): Len100% - 20.The example for this item is shown with the ones above: gui-flow-Lengths.salam
Auto
func Auto(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
Fill
func Fill(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
Fit
func Fit(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
MinContent
func MinContent(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
MaxContent
func MaxContent(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
NoLimit
func NoLimit(): LenThe example for this item is shown with the ones above: gui-flow-Lengths.salam
All
func All(v: Len): EdgesThe example for this item is shown with the ones above: gui-flow-Lengths.salam
Sides
func Sides(top: Len, trailing: Len, bottom: Len, leading: Len): Edgespadding = 1, 2, 3, 4.The example for this item is shown with the ones above: gui-flow-Lengths.salam
TrackLen
func TrackLen(v: Len): TrackMinContent(), MaxContent() or Auto().The example for this item is shown with the ones above: gui-flow-Grid.salam
TrackFr
func TrackFr(fr: f64): TrackThe example for this item is shown with the ones above: gui-flow-Grid.salam
TrackAuto
func TrackAuto(): TrackThe example for this item is shown with the ones above: gui-flow-Grid.salam
TrackMinMax
func TrackMinMax(lo: Track, hi: Track): Trackminmax(lo, hi): the minimum of lo and the maximum of hi, which may be fr.The example for this item is shown with the ones above: gui-flow-Grid.salam
TrackFit
func TrackFit(limit: Len): Trackfit(limit): sized to the content but no larger than the limit.The example for this item is shown with the ones above: gui-flow-Grid.salam
Repeat
func Repeat(count: int, tracks: Vector<Track>): Trackrepeat(count, tracks); count is a number, REPEAT_FILL or REPEAT_FIT.The example for this item is shown with the ones above: gui-flow-Grid.salam
NewTree
func NewTree(): TreeThe example for this item is shown with the ones above: gui-flow-Tree.salam