mirror of
https://github.com/Luzifer/streamdeck.git
synced 2024-12-29 22:21:24 +00:00
Implement dynamic exec displays
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
eee8f31f82
commit
fcbbfc0c30
3 changed files with 66 additions and 10 deletions
|
@ -11,21 +11,25 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/freetype"
|
||||
"github.com/golang/freetype/truetype"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
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 (
|
||||
err error
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
var (
|
||||
|
@ -140,7 +172,7 @@ func (displayElementCommand) drawText(c *freetype.Context, text string, textColo
|
|||
return err
|
||||
}
|
||||
|
||||
func (displayElementCommand) getImageFromDisk(filename string) (image.Image, error) {
|
||||
func (displayElementExec) getImageFromDisk(filename string) (image.Image, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to open image")
|
||||
|
@ -155,7 +187,7 @@ func (displayElementCommand) getImageFromDisk(filename string) (image.Image, err
|
|||
return img, nil
|
||||
}
|
||||
|
||||
func (displayElementCommand) loadFont() (*truetype.Font, error) {
|
||||
func (displayElementExec) loadFont() (*truetype.Font, error) {
|
||||
fontRaw, err := ioutil.ReadFile(userConfig.RenderFont)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to read font file")
|
||||
|
|
|
@ -25,6 +25,7 @@ var (
|
|||
|
||||
userConfig config
|
||||
activePage page
|
||||
activeLoops []refreshingDisplayElement
|
||||
|
||||
sd *streamdeck.Client
|
||||
|
||||
|
@ -130,6 +131,14 @@ func main() {
|
|||
}
|
||||
|
||||
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]
|
||||
sd.ClearAllKeys()
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ type displayElement interface {
|
|||
Display(idx int, attributes map[string]interface{}) error
|
||||
}
|
||||
|
||||
type refreshingDisplayElement interface {
|
||||
StartLoopDisplay(idx int, attributes map[string]interface{}) error
|
||||
StopLoopDisplay() error
|
||||
}
|
||||
|
||||
var (
|
||||
registeredActions = map[string]reflect.Type{}
|
||||
registeredActionsLock sync.Mutex
|
||||
|
@ -53,7 +58,17 @@ func callDisplayElement(idx int, kd keyDefinition) error {
|
|||
return errors.Errorf("Unknown display type %q", kd.Display.Type)
|
||||
}
|
||||
|
||||
inst := reflect.New(t).Interface().(displayElement)
|
||||
|
||||
return inst.Display(idx, kd.Display.Attributes)
|
||||
var inst interface{}
|
||||
if t.Kind() == reflect.Ptr {
|
||||
inst = reflect.New(t.Elem()).Interface()
|
||||
} else {
|
||||
inst = reflect.New(t).Interface()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue