Add text rendering for Stream Deck buttons with toggle demo

This commit is contained in:
Ian Gulliver
2026-02-11 19:23:25 -08:00
parent c9bed33c75
commit b4d147b07e
2 changed files with 95 additions and 13 deletions

View File

@@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"image/color" "image/color"
"math/rand/v2"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
@@ -11,6 +10,42 @@ import (
"qrun/lib/streamdeck" "qrun/lib/streamdeck"
) )
var palette = []color.RGBA{
{220, 50, 50, 255},
{50, 180, 50, 255},
{50, 100, 220, 255},
{220, 160, 30, 255},
{180, 50, 180, 255},
{50, 180, 180, 255},
{220, 120, 50, 255},
{100, 100, 200, 255},
}
func labelForKey(key int) string {
row := key / streamdeck.KeyCols()
col := key % streamdeck.KeyCols()
switch row {
case 0:
return fmt.Sprintf("Ch %d\nSelect", col+1)
case 1:
return fmt.Sprintf("Ch %d\nMute", col+1)
case 2:
return fmt.Sprintf("Ch %d\nSolo", col+1)
case 3:
return fmt.Sprintf("Ch %d\nRec", col+1)
}
return fmt.Sprintf("Key %d", key)
}
func drawKey(dev *streamdeck.Device, key int, bg color.RGBA) {
dim := color.RGBA{bg.R / 3, bg.G / 3, bg.B / 3, 255}
dev.SetKeyText(key, dim, color.White, labelForKey(key))
}
func drawKeyActive(dev *streamdeck.Device, key int, bg color.RGBA) {
dev.SetKeyText(key, bg, color.White, labelForKey(key))
}
func main() { func main() {
dev, err := streamdeck.Open() dev, err := streamdeck.Open()
if err != nil { if err != nil {
@@ -24,12 +59,12 @@ func main() {
dev.SetBrightness(80) dev.SetBrightness(80)
for i := 0; i < streamdeck.KeyCount(); i++ { for i := 0; i < streamdeck.KeyCount(); i++ {
r := uint8(rand.IntN(256)) col := i % streamdeck.KeyCols()
g := uint8(rand.IntN(256)) drawKey(dev, i, palette[col])
b := uint8(rand.IntN(256))
dev.SetKeyColor(i, color.RGBA{r, g, b, 255})
} }
active := make([]bool, streamdeck.KeyCount())
keys := make(chan streamdeck.KeyEvent, 64) keys := make(chan streamdeck.KeyEvent, 64)
go func() { go func() {
if err := dev.ReadKeys(keys); err != nil { if err := dev.ReadKeys(keys); err != nil {
@@ -43,15 +78,17 @@ func main() {
for { for {
select { select {
case ev := <-keys: case ev := <-keys:
if ev.Pressed { if !ev.Pressed {
fmt.Printf("Key %d pressed\n", ev.Key) continue
r := uint8(rand.IntN(256))
g := uint8(rand.IntN(256))
b := uint8(rand.IntN(256))
dev.SetKeyColor(ev.Key, color.RGBA{r, g, b, 255})
} else {
fmt.Printf("Key %d released\n", ev.Key)
} }
col := ev.Key % streamdeck.KeyCols()
active[ev.Key] = !active[ev.Key]
if active[ev.Key] {
drawKeyActive(dev, ev.Key, palette[col])
} else {
drawKey(dev, ev.Key, palette[col])
}
fmt.Printf("Key %d toggled %v\n", ev.Key, active[ev.Key])
case <-sig: case <-sig:
fmt.Println() fmt.Println()
return return

45
lib/streamdeck/text.go Normal file
View File

@@ -0,0 +1,45 @@
package streamdeck
import (
"image"
"image/color"
"image/draw"
"strings"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
)
func TextImage(bg color.Color, fg color.Color, lines ...string) image.Image {
img := image.NewRGBA(image.Rect(0, 0, keySize, keySize))
draw.Draw(img, img.Bounds(), &image.Uniform{bg}, image.Point{}, draw.Src)
face := basicfont.Face7x13
metrics := face.Metrics()
lineHeight := metrics.Height.Ceil()
totalHeight := lineHeight * len(lines)
startY := (keySize-totalHeight)/2 + metrics.Ascent.Ceil()
for i, line := range lines {
width := font.MeasureString(face, line).Ceil()
x := (keySize - width) / 2
y := startY + i*lineHeight
d := &font.Drawer{
Dst: img,
Src: &image.Uniform{fg},
Face: face,
Dot: fixed.P(x, y),
}
d.DrawString(line)
}
return img
}
func (d *Device) SetKeyText(key int, bg color.Color, fg color.Color, text string) error {
lines := strings.Split(text, "\n")
return d.SetKeyImage(key, TextImage(bg, fg, lines...))
}