2026-04-14 17:21:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"image/color"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"tinygo.org/x/tinydraw"
|
|
|
|
|
"tinygo.org/x/tinyfont"
|
|
|
|
|
)
|
|
|
|
|
|
2026-04-15 20:50:12 +00:00
|
|
|
var (
|
|
|
|
|
maxOpts int16
|
|
|
|
|
offset int16
|
|
|
|
|
menuX, menuY int16
|
|
|
|
|
numOpts int16
|
|
|
|
|
)
|
|
|
|
|
|
2026-04-14 17:21:59 +00:00
|
|
|
func runMenuOption(selected int16) {
|
|
|
|
|
switch menuOptions[selected] {
|
|
|
|
|
case modeBadge:
|
|
|
|
|
Badge()
|
|
|
|
|
case modeSchedule:
|
|
|
|
|
schedule(0, 0)
|
|
|
|
|
case modeAdventure:
|
|
|
|
|
adventure()
|
|
|
|
|
case modeLEDs:
|
|
|
|
|
Leds()
|
|
|
|
|
case modeAccelerometer:
|
|
|
|
|
Accel3D()
|
|
|
|
|
case modeMusic:
|
|
|
|
|
Music()
|
|
|
|
|
case modeGameSnake:
|
|
|
|
|
snakeGame.Loop()
|
|
|
|
|
case modeGameLife:
|
|
|
|
|
GameOfLife()
|
|
|
|
|
case modeGameColors:
|
|
|
|
|
ColorGame()
|
2026-04-21 19:51:05 +00:00
|
|
|
case modeGameReflex:
|
|
|
|
|
reflexGame.Loop()
|
|
|
|
|
case modeGamePacman:
|
|
|
|
|
pacmanGame.Loop()
|
2026-04-14 17:21:59 +00:00
|
|
|
case modeInfo:
|
|
|
|
|
Info()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func menu() int16 {
|
|
|
|
|
display.FillScreen(color.RGBA{0, 0, 0, 255})
|
|
|
|
|
bgColor := color.RGBA{109, 0, 140, 255}
|
|
|
|
|
display.FillScreen(bgColor)
|
|
|
|
|
|
|
|
|
|
selected := int16(0)
|
2026-04-15 20:50:12 +00:00
|
|
|
numOpts = int16(len(menuOptions))
|
2026-04-14 17:21:59 +00:00
|
|
|
|
2026-04-15 20:50:12 +00:00
|
|
|
menuX = int16(0)
|
2026-04-14 17:21:59 +00:00
|
|
|
for i := int16(0); i < numOpts; i++ {
|
|
|
|
|
w32, _ := tinyfont.LineWidth(defaultFont, options[menuOptions[i]])
|
|
|
|
|
if int16(w32) > menuX && w32 <= displayWidth {
|
|
|
|
|
menuX = int16(w32)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-15 20:50:12 +00:00
|
|
|
|
|
|
|
|
maxOpts = int16((displayHeight - 15) / menuItemSpace)
|
|
|
|
|
if numOpts > maxOpts {
|
|
|
|
|
maxOpts = (displayHeight - 30) / menuItemSpace
|
|
|
|
|
} else {
|
|
|
|
|
maxOpts = numOpts
|
2026-04-14 17:21:59 +00:00
|
|
|
}
|
2026-04-15 20:50:12 +00:00
|
|
|
offset = 0
|
2026-04-14 17:21:59 +00:00
|
|
|
|
2026-04-15 20:50:12 +00:00
|
|
|
menuX = (displayWidth - menuX) / 2
|
|
|
|
|
menuY = int16((displayHeight - ((maxOpts - 1) * menuItemSpace)) / 2)
|
|
|
|
|
menuDrawOffset()
|
|
|
|
|
tinydraw.FilledCircle(&display, menuX-2*menuCircleR, menuY-(menuCircleR/2), menuCircleR-2, color.RGBA{200, 200, 0, 255})
|
2026-04-14 17:21:59 +00:00
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
getInput()
|
2026-04-15 20:50:12 +00:00
|
|
|
if !buttonsOldState[buttonUp] && buttonsState[buttonUp] {
|
2026-04-14 17:21:59 +00:00
|
|
|
selected--
|
2026-04-15 20:50:12 +00:00
|
|
|
if selected < 0 {
|
|
|
|
|
offset = (numOpts + offset - maxOpts) % numOpts
|
|
|
|
|
selected = maxOpts - 1
|
|
|
|
|
menuDrawOffset()
|
|
|
|
|
}
|
|
|
|
|
tinydraw.FilledCircle(&display, menuX-2*menuCircleR, menuY-(menuCircleR/2)+menuItemSpace*selected, menuCircleR-2, color.RGBA{200, 200, 0, 255})
|
|
|
|
|
tinydraw.FilledCircle(&display, menuX-2*menuCircleR, menuY-(menuCircleR/2)+menuItemSpace*(selected+1), menuCircleR-2, bgColor)
|
2026-04-14 17:21:59 +00:00
|
|
|
}
|
2026-04-15 20:50:12 +00:00
|
|
|
if !buttonsOldState[buttonDown] && buttonsState[buttonDown] {
|
2026-04-14 17:21:59 +00:00
|
|
|
selected++
|
2026-04-15 20:50:12 +00:00
|
|
|
if selected >= maxOpts {
|
|
|
|
|
offset = (offset + maxOpts) % numOpts
|
|
|
|
|
selected = 0
|
|
|
|
|
menuDrawOffset()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tinydraw.FilledCircle(&display, menuX-2*menuCircleR, menuY-(menuCircleR/2)+menuItemSpace*selected, menuCircleR-2, color.RGBA{200, 200, 0, 255})
|
|
|
|
|
tinydraw.FilledCircle(&display, menuX-2*menuCircleR, menuY-(menuCircleR/2)+menuItemSpace*(selected-1), menuCircleR-2, bgColor)
|
2026-04-14 17:21:59 +00:00
|
|
|
}
|
|
|
|
|
if !buttonsOldState[buttonA] && buttonsState[buttonA] {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
|
}
|
2026-04-15 20:50:12 +00:00
|
|
|
return (selected + offset) % numOpts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func menuDrawOffset() {
|
|
|
|
|
bgColor := color.RGBA{109, 0, 140, 255}
|
|
|
|
|
display.FillScreen(bgColor)
|
|
|
|
|
|
|
|
|
|
for i := int16(0); i < maxOpts; i++ {
|
|
|
|
|
tinydraw.Circle(&display, menuX-2*menuCircleR, menuY-menuCircleR/2+menuItemSpace*i, int16(menuCircleR), color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX, menuY+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX, menuY+1+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX, menuY+2+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+1, menuY+2+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+2, menuY+2+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+2, menuY+1+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+2, menuY+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+1, menuY+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{0, 0, 0, 255})
|
|
|
|
|
tinyfont.WriteLine(&display, defaultFont, menuX+1, menuY+1+menuItemSpace*i, options[menuOptions[(offset+i)%numOpts]], color.RGBA{250, 250, 0, 255})
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 17:21:59 +00:00
|
|
|
}
|