Switch to 72pt Medium Mono Atkinson Hyperlegible font
This commit is contained in:
@@ -10,6 +10,13 @@ import (
|
|||||||
"qrun/lib/streamdeck"
|
"qrun/lib/streamdeck"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var keyLabels = []string{
|
||||||
|
"1", "2", "3", "4", "5", "6", "7", "8",
|
||||||
|
"A", "B", "C", "D", "E", "F", "G", "H",
|
||||||
|
"I", "J", "K", "L", "M", "N", "O", "P",
|
||||||
|
"Q", "R", "S", "T", "U", "V", "W", "X",
|
||||||
|
}
|
||||||
|
|
||||||
var palette = []color.RGBA{
|
var palette = []color.RGBA{
|
||||||
{220, 50, 50, 255},
|
{220, 50, 50, 255},
|
||||||
{50, 180, 50, 255},
|
{50, 180, 50, 255},
|
||||||
@@ -21,29 +28,13 @@ var palette = []color.RGBA{
|
|||||||
{100, 100, 200, 255},
|
{100, 100, 200, 255},
|
||||||
}
|
}
|
||||||
|
|
||||||
func labelForKey(key int) string {
|
func drawKey(dev *streamdeck.Device, key int, active bool) {
|
||||||
row := key / streamdeck.KeyCols()
|
|
||||||
col := key % streamdeck.KeyCols()
|
col := key % streamdeck.KeyCols()
|
||||||
switch row {
|
bg := palette[col]
|
||||||
case 0:
|
if !active {
|
||||||
return fmt.Sprintf("Ch %d\nSelect", col+1)
|
bg = color.RGBA{bg.R / 3, bg.G / 3, bg.B / 3, 255}
|
||||||
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)
|
dev.SetKeyText(key, bg, color.White, keyLabels[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() {
|
||||||
@@ -59,8 +50,7 @@ func main() {
|
|||||||
dev.SetBrightness(80)
|
dev.SetBrightness(80)
|
||||||
|
|
||||||
for i := 0; i < streamdeck.KeyCount(); i++ {
|
for i := 0; i < streamdeck.KeyCount(); i++ {
|
||||||
col := i % streamdeck.KeyCols()
|
drawKey(dev, i, false)
|
||||||
drawKey(dev, i, palette[col])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
active := make([]bool, streamdeck.KeyCount())
|
active := make([]bool, streamdeck.KeyCount())
|
||||||
@@ -81,14 +71,9 @@ func main() {
|
|||||||
if !ev.Pressed {
|
if !ev.Pressed {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
col := ev.Key % streamdeck.KeyCols()
|
|
||||||
active[ev.Key] = !active[ev.Key]
|
active[ev.Key] = !active[ev.Key]
|
||||||
if active[ev.Key] {
|
drawKey(dev, ev.Key, active[ev.Key])
|
||||||
drawKeyActive(dev, ev.Key, palette[col])
|
fmt.Printf("Key %s toggled %v\n", keyLabels[ev.Key], active[ev.Key])
|
||||||
} 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
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -8,4 +8,7 @@ require (
|
|||||||
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e
|
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/ebitengine/purego v0.8.4 // indirect
|
require (
|
||||||
|
github.com/ebitengine/purego v0.8.4 // indirect
|
||||||
|
golang.org/x/text v0.28.0 // indirect
|
||||||
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -4,5 +4,7 @@ gitlab.com/gomidi/midi/v2 v2.3.22 h1:4Q20o6q4BDo7i/KGvnwASeytOlrPI7MwsS7F2hA7fOM
|
|||||||
gitlab.com/gomidi/midi/v2 v2.3.22/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
gitlab.com/gomidi/midi/v2 v2.3.22/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
||||||
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
|
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
|
||||||
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
|
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
|
||||||
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e h1:Xlg01Rbs6PVG1yOvNEmMjI+edsmua23REsPO+tyhOyU=
|
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e h1:Xlg01Rbs6PVG1yOvNEmMjI+edsmua23REsPO+tyhOyU=
|
||||||
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e/go.mod h1:focKssvBxJwZE6GrEZipSBZsUwsFkcc0ECSq/In1Kww=
|
rafaelmartins.com/p/usbhid v0.0.0-20250616003425-c818f1cb579e/go.mod h1:focKssvBxJwZE6GrEZipSBZsUwsFkcc0ECSq/In1Kww=
|
||||||
|
|||||||
BIN
lib/streamdeck/fonts/AtkinsonHyperlegible-Bold.ttf
Normal file
BIN
lib/streamdeck/fonts/AtkinsonHyperlegible-Bold.ttf
Normal file
Binary file not shown.
BIN
lib/streamdeck/fonts/AtkinsonHyperlegible-Regular.ttf
Normal file
BIN
lib/streamdeck/fonts/AtkinsonHyperlegible-Regular.ttf
Normal file
Binary file not shown.
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Bold.ttf
Normal file
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Bold.ttf
Normal file
Binary file not shown.
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Medium.ttf
Normal file
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Medium.ttf
Normal file
Binary file not shown.
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Regular.ttf
Normal file
BIN
lib/streamdeck/fonts/AtkinsonHyperlegibleMono-Regular.ttf
Normal file
Binary file not shown.
@@ -1,41 +1,94 @@
|
|||||||
package streamdeck
|
package streamdeck
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"embed"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/basicfont"
|
"golang.org/x/image/font/opentype"
|
||||||
"golang.org/x/image/math/fixed"
|
"golang.org/x/image/math/fixed"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TextImage(bg color.Color, fg color.Color, lines ...string) image.Image {
|
//go:embed fonts/*.ttf
|
||||||
img := image.NewRGBA(image.Rect(0, 0, keySize, keySize))
|
var fontFS embed.FS
|
||||||
draw.Draw(img, img.Bounds(), &image.Uniform{bg}, image.Point{}, draw.Src)
|
|
||||||
|
|
||||||
face := basicfont.Face7x13
|
var (
|
||||||
|
MonoRegular font.Face
|
||||||
|
MonoMedium font.Face
|
||||||
|
MonoBold font.Face
|
||||||
|
Regular font.Face
|
||||||
|
Bold font.Face
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
MonoRegular = loadFace("fonts/AtkinsonHyperlegibleMono-Regular.ttf", 72)
|
||||||
|
MonoMedium = loadFace("fonts/AtkinsonHyperlegibleMono-Medium.ttf", 72)
|
||||||
|
MonoBold = loadFace("fonts/AtkinsonHyperlegibleMono-Bold.ttf", 72)
|
||||||
|
Regular = loadFace("fonts/AtkinsonHyperlegible-Regular.ttf", 16)
|
||||||
|
Bold = loadFace("fonts/AtkinsonHyperlegible-Bold.ttf", 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFace(path string, size float64) font.Face {
|
||||||
|
data, err := fontFS.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("streamdeck: read font %s: %v", path, err)
|
||||||
|
}
|
||||||
|
f, err := opentype.Parse(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("streamdeck: parse font %s: %v", path, err)
|
||||||
|
}
|
||||||
|
face, err := opentype.NewFace(f, &opentype.FaceOptions{
|
||||||
|
Size: size,
|
||||||
|
DPI: 72,
|
||||||
|
Hinting: font.HintingFull,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("streamdeck: create face %s: %v", path, err)
|
||||||
|
}
|
||||||
|
return face
|
||||||
|
}
|
||||||
|
|
||||||
|
func DrawText(img *image.RGBA, face font.Face, fg color.Color, lines ...string) {
|
||||||
metrics := face.Metrics()
|
metrics := face.Metrics()
|
||||||
lineHeight := metrics.Height.Ceil()
|
lineHeight := metrics.Height.Ceil()
|
||||||
|
bounds := img.Bounds()
|
||||||
|
w := bounds.Dx()
|
||||||
|
h := bounds.Dy()
|
||||||
|
|
||||||
totalHeight := lineHeight * len(lines)
|
totalHeight := lineHeight * len(lines)
|
||||||
startY := (keySize-totalHeight)/2 + metrics.Ascent.Ceil()
|
startY := (h-totalHeight)/2 + metrics.Ascent.Ceil()
|
||||||
|
|
||||||
for i, line := range lines {
|
for i, line := range lines {
|
||||||
width := font.MeasureString(face, line).Ceil()
|
width := font.MeasureString(face, line).Ceil()
|
||||||
x := (keySize - width) / 2
|
x := (w - width) / 2
|
||||||
y := startY + i*lineHeight
|
y := startY + i*lineHeight
|
||||||
|
|
||||||
d := &font.Drawer{
|
d := &font.Drawer{
|
||||||
Dst: img,
|
Dst: img,
|
||||||
Src: &image.Uniform{fg},
|
Src: &image.Uniform{fg},
|
||||||
Face: face,
|
Face: face,
|
||||||
Dot: fixed.P(x, y),
|
Dot: fixed.P(bounds.Min.X+x, bounds.Min.Y+y),
|
||||||
}
|
}
|
||||||
d.DrawString(line)
|
d.DrawString(line)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextImage(bg color.Color, fg color.Color, lines ...string) image.Image {
|
||||||
|
return TextImageWithFace(MonoMedium, bg, fg, lines...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BoldTextImage(bg color.Color, fg color.Color, lines ...string) image.Image {
|
||||||
|
return TextImageWithFace(MonoBold, bg, fg, lines...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextImageWithFace(face font.Face, 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)
|
||||||
|
DrawText(img, face, fg, lines...)
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,3 +96,8 @@ func (d *Device) SetKeyText(key int, bg color.Color, fg color.Color, text string
|
|||||||
lines := strings.Split(text, "\n")
|
lines := strings.Split(text, "\n")
|
||||||
return d.SetKeyImage(key, TextImage(bg, fg, lines...))
|
return d.SetKeyImage(key, TextImage(bg, fg, lines...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Device) SetKeyBoldText(key int, bg color.Color, fg color.Color, text string) error {
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
return d.SetKeyImage(key, BoldTextImage(bg, fg, lines...))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user