Build a counter
In this tutorial you’ll build a counter app from an empty file, one small step at a time. Each step runs, so you can see what every line does.
You’ll learn: windows, labels, buttons, state, and how the screen updates itself.
Step 0: An empty project
Make a folder called counter with an empty file main.nf inside:
mkdir counter
touch counter/main.nf
Open counter/main.nf in your editor. Then start nf dev in a terminal and leave it
running:
nf dev counter
The file is empty, so for now nf dev reports an error and waits. Each time you save,
it checks your code and updates the window, so you’ll see every step below appear as you
save it. (Prefer to run each step yourself? Use nf run counter after each one.)
Step 1: A window
Every Nifty app needs at least one window. Type this:
window("Counter") {
}
Save. You get an empty window titled Counter.
window(...)is an element: a built-in piece of UI."Counter"is the window’s title.- The
{ }after it holds what goes inside the window. It’s empty for now.
Step 2: Some text
Put a label inside the window:
window("Counter") {
label("Hello!")
}
Save. The window now says Hello!
Step 3: A size
The window is bigger than it needs to be. Give it a size in points, a screen unit that looks the same size on any display:
window("Counter", width: 320, height: 200) {
label("Hello!")
}
width: 320 is a named argument: you say which setting you mean, then its value.
Named arguments always come after the unnamed ones like "Counter".
Step 4: Remember a number
Now the important part. Add a line at the very top:
state count = 0
window("Counter", width: 320, height: 200) {
label("Clicked {count} times")
}
state count = 0makes a piece of state calledcountthat starts at0. State is the data your app remembers while it runs.- Inside the text,
{count}is replaced by the value ofcount. This is called interpolation. You can put any expression in the braces, like{count * 2}.
Save: Clicked 0 times.
Step 5: A button
Add a button under the label. Because there are now two things in the window, wrap
them in a column, which stacks things top to bottom:
state count = 0
window("Counter", width: 320, height: 200) {
column() {
label("Clicked {count} times")
button("+") { count += 1 }
}
}
Save and click + a few times. The number goes up!
Look at what you didn’t write. There’s no “when the button is clicked, find the label and change its text” code. You only said:
- the label shows
count, and - the button adds 1 to
count.
Nifty connects the two. When count changes, every part of the screen that uses
count updates. (Curious how? See How the UI stays up to date.)
Watch out: elements always need parentheses, even with nothing inside them. Write
column() { … }, notcolumn { … }.
Step 6: A minus button
Put the two buttons side by side in a row:
state count = 0
window("Counter", width: 320, height: 200) {
column() {
label("Clicked {count} times")
row() {
button("−") { count -= 1 }
button("+") { count += 1 }
}
}
}
count -= 1 means “take 1 away from count”. There are also *= and /=.
Step 7: Make it look nice
Finally, add some spacing, center everything, use a big title style for the number, and make + the main button:
state count = 0
window("Counter", width: 320, height: 200) {
column(spacing: 12, align: .center, justify: .center) {
label("Clicked {count} times", style: .title)
row(spacing: 8) {
button("−") { count -= 1 }
button("+", style: .primary) { count += 1 }
}
}
}
What’s new:
| Setting | What it does |
|---|---|
spacing: 12 | 12 points of space between children. |
align: .center | Centers children across the column (left to right). |
justify: .center | Centers children along the column (top to bottom). |
style: .title | Big, bold title text. |
style: .primary | Makes the button the main action: it’s drawn in the system’s accent color, and pressing Return clicks it. |
The values that start with a dot, like .center, are options. Each setting has its
own small list of options; the UI elements reference lists
them all.
You did it
That’s the same counter nf create gives you. Some things to try on your own:
-
Add a Reset button that sets
count = 0. -
Show a second label with
"Doubled: {count * 2}". -
Show a message only when the count is high:
if count >= 10 { label("That's a lot of clicks!", style: .caption, color: .warning) } -
Turn it into a real Mac app with
nf build counter. See Share your app.
Ready for more? Build a todo list next.