358 lines
9 KiB
Go
358 lines
9 KiB
Go
package main
|
|
|
|
import (
|
|
_ "embed"
|
|
"image/color"
|
|
"strconv"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"tinygo.org/x/tinydraw"
|
|
"tinygo.org/x/tinyfont"
|
|
"tinygo.org/x/tinyfont/freesans"
|
|
"tinygo.org/x/tinyfont/gophers"
|
|
|
|
qrcode "github.com/skip2/go-qrcode"
|
|
)
|
|
|
|
const (
|
|
logoDisplayTime = 10 * time.Second
|
|
)
|
|
|
|
var rainbow []color.RGBA
|
|
var quit bool
|
|
var selectedScreen uint8
|
|
|
|
//go:embed logo.bin
|
|
var badgeLogo string
|
|
|
|
func Badge() {
|
|
quit = false
|
|
selectedScreen = 0
|
|
display.FillScreen(colorBlack)
|
|
|
|
rainbow = make([]color.RGBA, 256)
|
|
for i := 0; i < 256; i++ {
|
|
rainbow[i] = getRainbowRGB(uint8(i))
|
|
}
|
|
|
|
for {
|
|
switch selectedScreen {
|
|
case 7: // last +1
|
|
selectedScreen = 0
|
|
fallthrough
|
|
case 0:
|
|
//showLogoBin()
|
|
selectedScreen++
|
|
if quit {
|
|
break
|
|
}
|
|
case 1:
|
|
//logopurpleHardware()
|
|
selectedScreen++
|
|
if quit {
|
|
break
|
|
}
|
|
case 2:
|
|
myNameIsRainbow(YourName)
|
|
if quit {
|
|
break
|
|
}
|
|
case 3:
|
|
blinkyRainbow(YourTitleA1, YourTitleA2)
|
|
if quit {
|
|
break
|
|
}
|
|
case 4:
|
|
scroll(YourMarqueeTop, YourMarqueeMiddle, YourMarqueeBottom)
|
|
if quit {
|
|
break
|
|
}
|
|
case 5:
|
|
QR(YourQRText)
|
|
if quit {
|
|
break
|
|
}
|
|
case 255: // max
|
|
selectedScreen = 6 // last one
|
|
fallthrough
|
|
case 6:
|
|
blinkyRainbow(YourTitleB1, YourTitleB2)
|
|
if quit {
|
|
break
|
|
}
|
|
default:
|
|
selectedScreen = 0
|
|
}
|
|
if quit {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func myNameIs(name string) {
|
|
display.FillScreen(colorWhite)
|
|
|
|
// black corners detail
|
|
display.FillRectangle(0, 0, cornerRadius, cornerRadius, colorBlack)
|
|
display.FillRectangle(0, displayHeight-cornerRadius, cornerRadius, cornerRadius, colorBlack)
|
|
display.FillRectangle(displayWidth-cornerRadius, 0, cornerRadius, cornerRadius, colorBlack)
|
|
display.FillRectangle(displayWidth-cornerRadius, displayHeight-cornerRadius, cornerRadius, cornerRadius, colorBlack)
|
|
|
|
// round corners
|
|
tinydraw.FilledCircle(&display, cornerRadius, cornerRadius, cornerRadius, colorRed)
|
|
tinydraw.FilledCircle(&display, displayWidth-cornerRadius-1, cornerRadius, cornerRadius, colorRed)
|
|
tinydraw.FilledCircle(&display, cornerRadius, displayHeight-cornerRadius-1, cornerRadius, colorRed)
|
|
tinydraw.FilledCircle(&display, displayWidth-cornerRadius-1, displayHeight-cornerRadius-1, cornerRadius, colorRed)
|
|
|
|
// top band
|
|
display.FillRectangle(cornerRadius, 0, displayWidth-2*cornerRadius-1, cornerRadius, colorRed)
|
|
display.FillRectangle(0, cornerRadius, displayWidth, int16(topBandHeight), colorRed)
|
|
|
|
// bottom band
|
|
display.FillRectangle(cornerRadius, displayHeight-cornerRadius-1, displayWidth-2*cornerRadius-1, cornerRadius+1, colorRed)
|
|
display.FillRectangle(0, displayHeight-int16(bottomBandHeight)-cornerRadius-1, displayWidth, int16(bottomBandHeight), colorRed)
|
|
|
|
// top text
|
|
if displayWidth >= 320 {
|
|
// gopherbadge: HELLO + my name is
|
|
w32, _ := tinyfont.LineWidth(&freesans.Bold18pt7b, "HELLO")
|
|
tinyfont.WriteLine(&display, &freesans.Bold18pt7b, (displayWidth-int16(w32))/2, int16(helloY), "HELLO", colorWhite)
|
|
w32, _ = tinyfont.LineWidth(&freesans.Oblique9pt7b, "my name is")
|
|
tinyfont.WriteLine(&display, &freesans.Oblique9pt7b, (displayWidth-int16(w32))/2, int16(myNameIsY), "my name is", colorWhite)
|
|
} else {
|
|
// pybadge: my NAME is
|
|
w32, _ := tinyfont.LineWidth(&freesans.Regular12pt7b, "my NAME is")
|
|
tinyfont.WriteLine(&display, &freesans.Regular12pt7b, (displayWidth-int16(w32))/2, int16(myNameIsY), "my NAME is", colorWhite)
|
|
}
|
|
|
|
writeLine(name, colorBlack, displayWidth/2, 6*displayHeight/10, displayWidth, true)
|
|
|
|
// gophers
|
|
if displayWidth >= 320 {
|
|
tinyfont.WriteLineColors(&display, &gophers.Regular58pt, displayWidth-int16(gophersX), int16(gophersY), "BE", []color.RGBA{getRainbowRGB(100), getRainbowRGB(200)})
|
|
} else {
|
|
tinyfont.WriteLineColors(&display, &gophers.Regular32pt, displayWidth-int16(gophersX), int16(gophersY), "BE", []color.RGBA{getRainbowRGB(100), getRainbowRGB(200)})
|
|
}
|
|
}
|
|
|
|
func myNameIsRainbow(name string) {
|
|
myNameIs(name)
|
|
|
|
for i := 0; i < 230; i++ {
|
|
writeLine(name, rainbow[i], displayWidth/2, 6*displayHeight/10, displayWidth, true)
|
|
i += 2
|
|
|
|
getInput()
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func blinkyRainbow(topline, bottomline string) {
|
|
display.FillScreen(colorWhite)
|
|
|
|
// calculate the width of the text so we could center them later
|
|
for i := int16(0); i < 20; i++ {
|
|
|
|
writeLine(topline, getRainbowRGB(uint8(i*12)), displayWidth/2, 4*displayHeight/10, displayWidth, true)
|
|
writeLine(bottomline, getRainbowRGB(uint8(i*12)), displayWidth/2, 8*displayHeight/10, displayWidth, true)
|
|
|
|
getInput()
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func scroll(topline, middleline, bottomline string) {
|
|
display.FillScreen(colorWhite)
|
|
|
|
writeLine(topline, getRainbowRGB(200), displayWidth/2, 3*displayHeight/10, displayWidth, true)
|
|
writeLine(middleline, getRainbowRGB(80), displayWidth/2, 55*displayHeight/100, displayWidth, true)
|
|
writeLine(bottomline, getRainbowRGB(120), displayWidth/2, 8*displayHeight/10, displayWidth, true)
|
|
|
|
display.SetScrollArea(0, 0)
|
|
defer func() {
|
|
display.SetScroll(0)
|
|
display.StopScroll()
|
|
}()
|
|
|
|
for k := 0; k < 4; k++ {
|
|
for i := int16(displayWidth - 1); i >= 0; i-- {
|
|
getInput()
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
|
|
display.SetScroll(i)
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func logopurpleHardware() {
|
|
bgColor := color.RGBA{109, 0, 140, 255}
|
|
white := color.RGBA{255, 255, 255, 255}
|
|
display.FillScreen(bgColor)
|
|
|
|
if displayWidth >= 320 {
|
|
// Full logo for gopherbadge
|
|
display.FillRectangle(6, 166, 308, 21, white)
|
|
|
|
tinydraw.FilledCircle(&display, 282, 130, 9, white)
|
|
tinydraw.Line(&display, 259, 110, 298, 149, bgColor)
|
|
tinydraw.Line(&display, 260, 110, 299, 149, bgColor)
|
|
tinydraw.Line(&display, 261, 110, 300, 149, bgColor)
|
|
tinydraw.Line(&display, 262, 110, 301, 149, bgColor)
|
|
tinydraw.Line(&display, 263, 110, 302, 149, bgColor)
|
|
tinydraw.Line(&display, 264, 110, 303, 149, bgColor)
|
|
tinydraw.Line(&display, 265, 110, 304, 149, bgColor)
|
|
|
|
display.FillRectangle(250, 98, 11, 63, white)
|
|
display.FillRectangle(250, 98, 44, 11, white)
|
|
|
|
display.FillRectangle(270, 150, 44, 11, white)
|
|
display.FillRectangle(303, 98, 11, 63, white)
|
|
|
|
tinyfont.WriteLine(&display, &freesans.Regular18pt7b, 6, 109, "purple", white)
|
|
tinyfont.WriteLine(&display, &freesans.Regular18pt7b, 6, 153, "Hardware by", white)
|
|
} else {
|
|
// Simplified logo for pybadge
|
|
tinyfont.WriteLine(&display, &freesans.Bold9pt7b, 10, 60, "purple", white)
|
|
tinyfont.WriteLine(&display, &freesans.Bold9pt7b, 10, 80, "Hardware", white)
|
|
}
|
|
|
|
refreshIntervals := uint8(7)
|
|
displayTime := logoDisplayTime / 3
|
|
|
|
for i := uint8(0); i < refreshIntervals; i++ {
|
|
time.Sleep(displayTime / time.Duration(refreshIntervals))
|
|
getInput()
|
|
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func getRainbowRGB(i uint8) color.RGBA {
|
|
if i < 85 {
|
|
return color.RGBA{i * 3, 255 - i*3, 0, 255}
|
|
} else if i < 170 {
|
|
i -= 85
|
|
return color.RGBA{255 - i*3, 0, i * 3, 255}
|
|
}
|
|
i -= 170
|
|
return color.RGBA{0, i * 3, 255 - i*3, 255}
|
|
}
|
|
|
|
func showLogoBin() {
|
|
row := make([]color.RGBA, displayWidth)
|
|
unsafeBadgeLogo := unsafe.Slice(unsafe.StringData(badgeLogo), len(badgeLogo))
|
|
for i := 0; i < displayHeight; i++ {
|
|
for j := 0; j < displayWidth; j++ {
|
|
values, err := strconv.ParseUint(string(unsafeBadgeLogo[6*(displayWidth*i+j):6*(displayWidth*i+j+1)]), 16, 32)
|
|
|
|
if err != nil {
|
|
println(err)
|
|
}
|
|
|
|
row[j] = color.RGBA{
|
|
R: uint8(values >> 16),
|
|
G: uint8((values >> 8) & 0xFF),
|
|
B: uint8(values & 0xFF),
|
|
A: 255,
|
|
}
|
|
}
|
|
display.FillRectangleWithBuffer(0, int16(i), displayWidth, 1, row)
|
|
}
|
|
|
|
refreshIntervals := uint8(20)
|
|
|
|
for i := uint8(0); i < refreshIntervals; i++ {
|
|
time.Sleep(logoDisplayTime / time.Duration(refreshIntervals))
|
|
getInput()
|
|
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func QR(msg string) {
|
|
qr, err := qrcode.New(msg, qrcode.Medium)
|
|
if err != nil {
|
|
println(err, 123)
|
|
}
|
|
|
|
qrbytes := qr.Bitmap()
|
|
size := int16(len(qrbytes))
|
|
|
|
factor := int16(displayHeight / len(qrbytes))
|
|
|
|
bx := (displayWidth - size*factor) / 2
|
|
by := (displayHeight - size*factor) / 2
|
|
display.FillScreen(color.RGBA{109, 0, 140, 255})
|
|
for y := int16(0); y < size; y++ {
|
|
for x := int16(0); x < size; x++ {
|
|
if qrbytes[y][x] {
|
|
display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colorBlack)
|
|
} else {
|
|
display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colorWhite)
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshIntervals := uint8(20)
|
|
|
|
for i := uint8(0); i < refreshIntervals; i++ {
|
|
time.Sleep(logoDisplayTime / time.Duration(refreshIntervals))
|
|
getInput()
|
|
|
|
if goBack() {
|
|
quit = true
|
|
return
|
|
}
|
|
}
|
|
|
|
selectedScreen++
|
|
}
|
|
|
|
func getFontWidthSize(text string) (w32 uint32, size byte) {
|
|
w32, _ = tinyfont.LineWidth(&freesans.Bold24pt7b, text)
|
|
size = 24
|
|
if w32 < uint32(FontWidthThreshold) {
|
|
size = 24
|
|
} else {
|
|
w32, _ = tinyfont.LineWidth(&freesans.Bold18pt7b, text)
|
|
if w32 < uint32(FontWidthThreshold) {
|
|
size = 18
|
|
} else {
|
|
w32, _ = tinyfont.LineWidth(&freesans.Bold12pt7b, text)
|
|
if w32 < uint32(FontWidthThreshold) {
|
|
size = 12
|
|
} else {
|
|
w32, _ = tinyfont.LineWidth(&freesans.Bold9pt7b, text)
|
|
size = 9
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|