Solutions
Solutions to the exercises. Each solution is also a complete project in the examples folder of the CrowdWare books repository.
Your First App
Project: examples/first-app-solution
app.sml – a second button below the first:
Button {
id: btnReset
text: "Reset"
}
app.sms – one more handler:
on btnReset.clicked() {
clicks = 0
greeting.text = "Hello, Forge!"
}
And the title, for example:
title: "Adam's First Forge App"
Because clicks lives at the top of the script, both handlers see the same counter. Press Say hello twice, then Reset, then Say hello again – the label says Hello for the 1. time!
Nodes, Properties and Values
Project: examples/business-card-solution
app.sml – a second hidden label, and the bar at 100 without its text:
Label {
id: secret2
text: "Favourite place: the sea"
color: "#9DB8F2"
visible: false
}
// How much coffee is left today, in percent
ProgressBar { id: coffee value: 100 showPercentage: false }
app.sms – one handler switches on both:
on btnMore.clicked() {
secret.visible = true
secret2.visible = true
}
showPercentage: false hides the number but keeps the bar. With value: 100 the bar is full – and without the text it becomes a thin line, because the text was what made it tall.
Layout
Project: examples/keypad-solution
Window {
id: mainWindow
title: "Keypad"
size: 300, 400
VBoxContainer {
anchors: left | top | right | bottom
padding: 12, 12, 12, 12
spacing: 8
Label { id: display text: "0" fontSize: 32 align: right }
GridContainer {
columns: 3
spacing: 6
sizeFlagsVertical: expandFill
Button { text: "7" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "8" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "9" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "4" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "5" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "6" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "1" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "2" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "3" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "C" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "0" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
Button { text: "=" sizeFlagsHorizontal: expandFill sizeFlagsVertical: expandFill }
}
}
}

Two things make the keypad fill the window. The GridContainer asks the outer VBoxContainer for all free height (sizeFlagsVertical: expandFill). And every button asks the grid for free space in both directions. Without the flags on the buttons, the grid would grow, but the buttons would stay small in the top-left of their cells.
Resources and Themes
Project: examples/welcome-solution
strings-es.sml – a new file, with every name of strings.sml:
Strings {
windowTitle: "Bienvenido"
headline: "Bienvenido a Forge"
intro: "Este texto viene de strings-es.sml."
btnLight: "Claro"
btnDark: "Oscuro"
btnSepia: "Sepia"
themeChanged: "Tema cambiado"
notThere: "Ahora viene de strings-es.sml"
}
strings.sml and strings-de.sml get the two new names too:
btnSepia: "Sepia"
notThere: "Now it comes from strings.sml"
btnSepia: "Sepia"
notThere: "Jetzt kommt er aus strings-de.sml"
theme.sepia.sml – the third set of colours, same names as the others:
Colors {
brand: "#7A3E12"
surface: "#E9D8B4"
text: "#3B2A1A"
}
app.sml – the third button, and the label without its fallback:
Label { id: missing text: @Strings.notThere color: @Colors.text }
Button { id: btnSepia text: @Strings.btnSepia }
app.sms – one more handler:
on btnSepia.clicked() {
ui.setTheme("sepia")
log.info(i18n.tr("themeChanged"))
}

Not one line of app.sml names a language or a colour. A fourth language or a fourth theme would again be one new file and, for the theme, one button.
