Slide 34 of 37
The UI module
A page, served directly
proc main(): void {
view := hive.ui.column([hive.ui.pad(24), hive.ui.gap(12)], [
hive.ui.text([hive.ui.size(hive.ui.TextSize.Title()), hive.ui.heading(1)], "Hive Tour"),
hive.ui.row([hive.ui.gap(8)], [
hive.ui.input([hive.ui.placeholder("your name")], ""),
hive.ui.button([hive.ui.tone(hive.ui.Tone.Good())], "Say hi"),
]),
hive.ui.link([hive.ui.background(hive.ui.Tone.Good())], "/1", "Start →"),
])
body := hive.ui.page("Hive", view) // a whole document, served directly
echo len(body)
}
A 3D scene, in a window
type Msg { Tick }
func view(model: Int): hive.ui.View {
shapes := [
hive.ui.ground([hive.ui.paint(hive.ui.Tone.HEX("#2d5c34"))], 20.0, 20.0),
hive.ui.box(
[hive.ui.at(0.0, 0.5, -3.0), hive.ui.paint(hive.ui.Tone.HEX("#b5651d"))],
1.0, 1.0, 1.0,
),
hive.ui.sphere([hive.ui.at(2.0, 1.0, -4.0), hive.ui.paint(hive.ui.Tone.HEX("#e0c341"))], 1.0),
]
return hive.ui.scene(
[hive.ui.grow(1), hive.ui.eye(0.0, 1.6, 4.0), hive.ui.aim(0.0, 0.0), hive.ui.lens(70), hive.ui.fog(60)],
shapes,
)
}
proc update(model: Int, msg: Msg, envelope: hive.syslink.Envelope): Int {
return model
}
proc main(): void {
hive.ui.window("A 3D scene", view, update, 0)
}
Animating it, and reacting to a frame
type Msg {
Tick { ms: Int }
}
func view(angle: Float): hive.ui.View {
return hive.ui.scene(
[
hive.ui.grow(1),
hive.ui.eye(0.0, 1.5, 5.0),
hive.ui.aim(0.0, 0.0),
hive.ui.onFrame(Msg.Tick(_)),
],
[
hive.ui.ground([hive.ui.paint(hive.ui.Tone.Muted())], 10.0, 10.0),
hive.ui.box(
[hive.ui.at(0.0, 1.0, 0.0), hive.ui.turn(0.0, angle, 0.0), hive.ui.paint(hive.ui.Tone.Good())],
1.0, 1.0, 1.0,
),
],
)
}
// A scene's onFrame reports how many milliseconds the last frame took, so
// the turn this box makes is in real seconds rather than in frames — the
// same box spins at the same speed at thirty frames a second or sixty.
proc spin(angle: Float, msg: Msg, envelope: hive.syslink.Envelope): Float {
if msg is Msg.Tick(ms) {
return angle + hive.conv.itf(ms) * 0.002
}
return angle
}
proc main(): void {
hive.ui.window("A spinning box", view, spin, 0.0)
}
hive.ui builds an interface as a value: a View is a tree of widgets, and every one of them takes the same two things, its attributes and then its own payload. row and column lay out children; text, image, icon and link show something; button, input, textarea, checkbox and select ask for something; table shows a Table, and spacer, spinner, none and overlay round out the set. Attributes are just as closed a set: gap, pad, width, height, grow, align, justify and scroll lay out; size, heading, tone and background style; disabled, busy, placeholder, hint and kind describe state; and on, onDismiss, onInput, onSubmit, onChoose, onToggle, onPick and onSort carry an event, for a window rather than this kind of page. Align, Justify, TextSize, Tone, Axis, InputKind and Icon are the enumerations behind them, reached like any other library type.html(view) renders a tree as an HTML fragment, and page(title, view) as a whole document with a stylesheet already built in, light and dark alike — which is exactly what an httpServe handler can answer a request with directly, and what every screen in this tour but its code samples is. The same tree, shown instead by window(title, view, update, state), becomes a live page: update is a fold over its events, the same shape a hive.syslink handler folds over a mailbox, so a window has an address and needs no mutex of its own.A scene is the one widget that only a window can draw. box, sphere, cylinder, ground, label and line are its shapes, positioned with at and turn and coloured with paint; eye, aim, lens and fog place and dress the camera; grab and crosshair capture the mouse, and onFrame, onKeyDown, onKeyUp, onLook and onGrab are the events a scene alone reports. A served page renders a scene's box empty — there is no socket for frames to travel down — so the two examples below are shown as code only: open either in a window to actually see it.