Slide 34 de 37

O módulo de UI

Uma página, servida diretamente
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)], "Tour do Hive"),
		hive.ui.row([hive.ui.gap(8)], [
			hive.ui.input([hive.ui.placeholder("seu nome")], ""),
			hive.ui.button([hive.ui.tone(hive.ui.Tone.Good())], "Dizer oi"),
		]),
		hive.ui.link([hive.ui.background(hive.ui.Tone.Good())], "/1", "Começar →"),
	])

	body := hive.ui.page("Hive", view)   // um documento inteiro, servido diretamente
	echo len(body)
}
Uma cena 3D, em uma 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("Uma cena 3D", view, update, 0)
}
Animando, e reagindo a um 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,
			),
		],
	)
}

// O onFrame de uma scene reporta quantos milissegundos o último frame levou,
// então o giro que esta caixa faz é em segundos reais, não em frames — a
// mesma caixa gira na mesma velocidade a trinta quadros por segundo ou a sessenta.
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("Uma caixa girando", view, spin, 0.0)
}
hive.ui constrói uma interface como um valor: uma View é uma árvore de widgets, e cada um deles recebe as mesmas duas coisas, seus atributos e depois sua própria carga. row e column organizam filhos; text, image, icon e link mostram algo; button, input, textarea, checkbox e select pedem algo; table mostra uma Table, e spacer, spinner, none e overlay completam o conjunto. Os atributos são um conjunto igualmente fechado: gap, pad, width, height, grow, align, justify e scroll organizam; size, heading, tone e background estilizam; disabled, busy, placeholder, hint e kind descrevem estado; e on, onDismiss, onInput, onSubmit, onChoose, onToggle, onPick e onSort carregam um evento, para uma window e não para este tipo de página. Align, Justify, TextSize, Tone, Axis, InputKind e Icon são as enumerações por trás deles, acessadas como qualquer outro tipo da biblioteca.html(view) renderiza uma árvore como um fragmento HTML, e page(title, view) como um documento inteiro com uma stylesheet já embutida, claro e escuro igualmente — que é exatamente o que um handler de httpServe pode usar para responder a uma requisição diretamente, e o que toda tela deste tour, exceto suas amostras de código, é. A mesma árvore, mostrada em vez disso por window(title, view, update, state), se torna uma página viva: update é um fold sobre seus eventos, a mesma forma que um handler de hive.syslink faz fold sobre uma caixa de mensagens, então uma window tem um endereço e não precisa de mutex próprio.Uma scene é o único widget que somente uma window consegue desenhar. box, sphere, cylinder, ground, label e line são suas formas, posicionadas com at e turn e coloridas com paint; eye, aim, lens e fog posicionam e ajustam a câmera; grab e crosshair capturam o mouse, e onFrame, onKeyDown, onKeyUp, onLook e onGrab são os eventos que somente uma scene reporta. Uma página servida renderiza a caixa de uma scene vazia — não há um socket para os frames viajarem — então os dois exemplos abaixo são mostrados apenas como código: abra qualquer um deles em uma window para realmente ver.