1
0
Fork 0
mirror of https://github.com/Luzifer/streamdeck.git synced 2024-10-18 13:04:25 +00:00

Implement dynamic exec displays

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-11-21 23:54:27 +01:00
parent eee8f31f82
commit fcbbfc0c30
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 66 additions and 10 deletions

View file

@ -11,21 +11,25 @@ import (
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
"time"
"github.com/golang/freetype" "github.com/golang/freetype"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
func init() { func init() {
registerDisplayElement("exec", displayElementCommand{}) registerDisplayElement("exec", &displayElementExec{})
} }
type displayElementCommand struct{} type displayElementExec struct {
running bool
}
func (d displayElementCommand) Display(idx int, attributes map[string]interface{}) error { func (d displayElementExec) Display(idx int, attributes map[string]interface{}) error {
var ( var (
err error err error
img draw.Image = image.NewRGBA(image.Rect(0, 0, sd.IconSize(), sd.IconSize())) img draw.Image = image.NewRGBA(image.Rect(0, 0, sd.IconSize(), sd.IconSize()))
@ -107,7 +111,35 @@ func (d displayElementCommand) Display(idx int, attributes map[string]interface{
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image") return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
} }
func (displayElementCommand) drawText(c *freetype.Context, text string, textColor color.Color, fontsize float64, border int) error { func (d *displayElementExec) StartLoopDisplay(idx int, attributes map[string]interface{}) error {
d.running = true
var interval = 5 * time.Second
if v, ok := attributes["interval"].(int); ok {
interval = time.Duration(v) * time.Second
}
go func() {
for tick := time.NewTicker(interval); ; <-tick.C {
if !d.running {
return
}
if err := d.Display(idx, attributes); err != nil {
log.WithError(err).Error("Unable to refresh element")
}
}
}()
return nil
}
func (d *displayElementExec) StopLoopDisplay() error {
d.running = false
return nil
}
func (displayElementExec) drawText(c *freetype.Context, text string, textColor color.Color, fontsize float64, border int) error {
c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing
var ( var (
@ -140,7 +172,7 @@ func (displayElementCommand) drawText(c *freetype.Context, text string, textColo
return err return err
} }
func (displayElementCommand) getImageFromDisk(filename string) (image.Image, error) { func (displayElementExec) getImageFromDisk(filename string) (image.Image, error) {
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to open image") return nil, errors.Wrap(err, "Unable to open image")
@ -155,7 +187,7 @@ func (displayElementCommand) getImageFromDisk(filename string) (image.Image, err
return img, nil return img, nil
} }
func (displayElementCommand) loadFont() (*truetype.Font, error) { func (displayElementExec) loadFont() (*truetype.Font, error) {
fontRaw, err := ioutil.ReadFile(userConfig.RenderFont) fontRaw, err := ioutil.ReadFile(userConfig.RenderFont)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to read font file") return nil, errors.Wrap(err, "Unable to read font file")

View file

@ -25,6 +25,7 @@ var (
userConfig config userConfig config
activePage page activePage page
activeLoops []refreshingDisplayElement
sd *streamdeck.Client sd *streamdeck.Client
@ -130,6 +131,14 @@ func main() {
} }
func togglePage(page string) error { func togglePage(page string) error {
// Reset potentially running looped elements
for _, l := range activeLoops {
if err := l.StopLoopDisplay(); err != nil {
return errors.Wrap(err, "Unable to stop element refresh")
}
}
activeLoops = nil
activePage = userConfig.Pages[page] activePage = userConfig.Pages[page]
sd.ClearAllKeys() sd.ClearAllKeys()

View file

@ -15,6 +15,11 @@ type displayElement interface {
Display(idx int, attributes map[string]interface{}) error Display(idx int, attributes map[string]interface{}) error
} }
type refreshingDisplayElement interface {
StartLoopDisplay(idx int, attributes map[string]interface{}) error
StopLoopDisplay() error
}
var ( var (
registeredActions = map[string]reflect.Type{} registeredActions = map[string]reflect.Type{}
registeredActionsLock sync.Mutex registeredActionsLock sync.Mutex
@ -53,7 +58,17 @@ func callDisplayElement(idx int, kd keyDefinition) error {
return errors.Errorf("Unknown display type %q", kd.Display.Type) return errors.Errorf("Unknown display type %q", kd.Display.Type)
} }
inst := reflect.New(t).Interface().(displayElement) var inst interface{}
if t.Kind() == reflect.Ptr {
inst = reflect.New(t.Elem()).Interface()
} else {
inst = reflect.New(t).Interface()
}
return inst.Display(idx, kd.Display.Attributes) if t.Implements(reflect.TypeOf((*refreshingDisplayElement)(nil)).Elem()) {
activeLoops = append(activeLoops, inst.(refreshingDisplayElement))
return inst.(refreshingDisplayElement).StartLoopDisplay(idx, kd.Display.Attributes)
}
return inst.(displayElement).Display(idx, kd.Display.Attributes)
} }