Pinball dot-matrix clock animation thingy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

158 lines
3.0 KiB

package text
import (
"fmt"
"image"
"image/color"
"os"
"strings"
"sync/atomic"
"syscall"
"maze.io/matrix/driver"
"github.com/gdamore/tcell"
)
func init() {
driver.Register("text", New)
}
type Matrix struct {
Title string
screen tcell.Screen
width int
height int
pixels int
render int64
colors []tcell.Color
}
func New(config *driver.Config) (driver.Matrix, error) {
return newDriver(config)
}
func newDriver(config *driver.Config) (*Matrix, error) {
screen, err := tcell.NewTerminfoScreen()
if err != nil {
return nil, err
}
if err = screen.Init(); err != nil {
return nil, err
}
go handleEvents(screen)
screen.DisableMouse()
screen.HideCursor()
w, h := config.Geometry()
return &Matrix{
screen: screen,
width: w,
height: h,
pixels: w * h,
colors: make([]tcell.Color, w*h),
}, nil
}
func handleEvents(screen tcell.Screen) {
for {
event := screen.PollEvent()
switch event := event.(type) {
case *tcell.EventKey:
switch event.Key() {
case tcell.KeyEsc, tcell.KeyCtrlC:
screen.Fini()
syscall.Kill(os.Getpid(), syscall.SIGKILL)
return
case tcell.KeyCtrlL:
screen.Show()
screen.Sync()
}
case *tcell.EventResize:
screen.Sync()
}
}
}
func (m *Matrix) Close() error {
return syscall.Kill(os.Getpid(), syscall.SIGKILL)
}
func (Matrix) Name() string {
return "test matrix"
}
func (m *Matrix) Bounds() image.Rectangle {
return image.Rect(0, 0, m.width, m.height)
}
// Swap buffers.
func (m *Matrix) Swap(leds []driver.Color) (prev []driver.Color, err error) {
return
}
func (m *Matrix) Render() error {
var (
call = atomic.AddInt64(&m.render, 1)
info = fmt.Sprintf("text matrix %dx%d frame %d", m.width, m.height, call)
style = tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorBlue)
)
if m.Title != "" {
info += fmt.Sprintf(": %s", m.Title)
}
info += strings.Repeat(" ", m.width-len(info))
m.screen.SetCell(0, 0, style, []rune(info)...)
m.screen.Show()
return nil
}
func (m *Matrix) At(x, y int) color.Color {
if !image.Pt(x, y).In(m.Bounds()) {
return color.Transparent
}
return toColor(m.colors[y*m.width+x])
}
func toColor(c tcell.Color) color.Color {
r, g, b := c.RGB()
return color.RGBA{
R: uint8(r),
G: uint8(g),
B: uint8(b),
A: 0xff,
}
}
func (Matrix) ColorDepth() int {
return 24
}
func (m *Matrix) ColorModel() color.Model {
return driver.ColorModel
}
func (m *Matrix) Set(x, y int, c color.Color) {
if !image.Pt(x, y).In(m.Bounds()) {
return
}
r, g, b, _ := c.RGBA()
o := y*m.width + x
m.colors[o] = tcell.NewRGBColor(int32(r), int32(g), int32(b))
var style tcell.Style
if y&1 == 0 { // even row, add next row
style = style.Foreground(m.colors[o]).Background(m.colors[o+m.width])
} else { // odd row, add previous row
style = style.Background(m.colors[o]).Foreground(m.colors[o-m.width])
}
if fg, bg, _ := style.Decompose(); fg == bg {
m.screen.SetCell(x, 1+(y/2), style, ' ')
} else {
m.screen.SetCell(x, 1+(y/2), style, '▀')
}
}
var _ driver.Matrix = (*Matrix)(nil)