mirror of
https://github.com/Luzifer/streamdeck.git
synced 2024-12-29 22:21:24 +00:00
Fix: Prevent drawing elements from previous page
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
42c0ec2f11
commit
c8a6c79369
5 changed files with 43 additions and 15 deletions
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -12,7 +13,7 @@ func init() {
|
||||||
|
|
||||||
type displayElementColor struct{}
|
type displayElementColor struct{}
|
||||||
|
|
||||||
func (d displayElementColor) Display(idx int, attributes map[string]interface{}) error {
|
func (d displayElementColor) Display(ctx context.Context, idx int, attributes map[string]interface{}) error {
|
||||||
if name, ok := attributes["color"].(string); ok {
|
if name, ok := attributes["color"].(string); ok {
|
||||||
return d.displayPredefinedColor(idx, name)
|
return d.displayPredefinedColor(idx, name)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +23,11 @@ func (d displayElementColor) Display(idx int, attributes map[string]interface{})
|
||||||
return errors.New("RGBA color definition needs 4 hex values")
|
return errors.New("RGBA color definition needs 4 hex values")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
// Page context was cancelled, do not draw
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return sd.FillColor(idx, color.RGBA{uint8(rgba[0].(int)), uint8(rgba[1].(int)), uint8(rgba[2].(int)), uint8(rgba[3].(int))})
|
return sd.FillColor(idx, color.RGBA{uint8(rgba[0].(int)), uint8(rgba[1].(int)), uint8(rgba[2].(int)), uint8(rgba[3].(int))})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
@ -30,7 +31,7 @@ type displayElementExec struct {
|
||||||
running bool
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d displayElementExec) Display(idx int, attributes map[string]interface{}) error {
|
func (d displayElementExec) Display(ctx context.Context, 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()))
|
||||||
|
@ -141,6 +142,11 @@ func (d displayElementExec) Display(idx int, attributes map[string]interface{})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
// Page context was cancelled, do not draw
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
|
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +158,7 @@ func (d displayElementExec) NeedsLoop(attributes map[string]interface{}) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *displayElementExec) StartLoopDisplay(idx int, attributes map[string]interface{}) error {
|
func (d *displayElementExec) StartLoopDisplay(ctx context.Context, idx int, attributes map[string]interface{}) error {
|
||||||
d.running = true
|
d.running = true
|
||||||
|
|
||||||
var interval = 5 * time.Second
|
var interval = 5 * time.Second
|
||||||
|
@ -166,7 +172,7 @@ func (d *displayElementExec) StartLoopDisplay(idx int, attributes map[string]int
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.Display(idx, attributes); err != nil {
|
if err := d.Display(ctx, idx, attributes); err != nil {
|
||||||
log.WithError(err).Error("Unable to refresh element")
|
log.WithError(err).Error("Unable to refresh element")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"image"
|
"image"
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
|
@ -15,7 +16,7 @@ func init() {
|
||||||
|
|
||||||
type displayElementImage struct{}
|
type displayElementImage struct{}
|
||||||
|
|
||||||
func (d displayElementImage) Display(idx int, attributes map[string]interface{}) error {
|
func (d displayElementImage) Display(ctx context.Context, idx int, attributes map[string]interface{}) error {
|
||||||
filename, ok := attributes["path"].(string)
|
filename, ok := attributes["path"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("No path attribute specified")
|
return errors.New("No path attribute specified")
|
||||||
|
@ -34,5 +35,10 @@ func (d displayElementImage) Display(idx int, attributes map[string]interface{})
|
||||||
|
|
||||||
img = autoSizeImage(img, sd.IconSize())
|
img = autoSizeImage(img, sd.IconSize())
|
||||||
|
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
// Page context was cancelled, do not draw
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
|
return errors.Wrap(sd.FillImage(idx, img), "Unable to set image")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
@ -28,10 +29,12 @@ var (
|
||||||
|
|
||||||
currentBrightness int
|
currentBrightness int
|
||||||
|
|
||||||
userConfig config
|
userConfig config
|
||||||
activePage page
|
activePage page
|
||||||
activePageName string
|
activePageCtx context.Context
|
||||||
activeLoops []refreshingDisplayElement
|
activePageCtxCancel context.CancelFunc
|
||||||
|
activePageName string
|
||||||
|
activeLoops []refreshingDisplayElement
|
||||||
|
|
||||||
sd *streamdeck.Client
|
sd *streamdeck.Client
|
||||||
|
|
||||||
|
@ -208,6 +211,11 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func togglePage(page string) error {
|
func togglePage(page string) error {
|
||||||
|
if activePageCtxCancel != nil {
|
||||||
|
// Ensure old display events are no longer executed
|
||||||
|
activePageCtxCancel()
|
||||||
|
}
|
||||||
|
|
||||||
// Reset potentially running looped elements
|
// Reset potentially running looped elements
|
||||||
for _, l := range activeLoops {
|
for _, l := range activeLoops {
|
||||||
if err := l.StopLoopDisplay(); err != nil {
|
if err := l.StopLoopDisplay(); err != nil {
|
||||||
|
@ -218,11 +226,12 @@ func togglePage(page string) error {
|
||||||
|
|
||||||
activePage = userConfig.Pages[page]
|
activePage = userConfig.Pages[page]
|
||||||
activePageName = page
|
activePageName = page
|
||||||
|
activePageCtx, activePageCtxCancel = context.WithCancel(context.Background())
|
||||||
sd.ClearAllKeys()
|
sd.ClearAllKeys()
|
||||||
|
|
||||||
for idx, kd := range activePage.Keys {
|
for idx, kd := range activePage.Keys {
|
||||||
if kd.Display.Type != "" {
|
if kd.Display.Type != "" {
|
||||||
if err := callDisplayElement(idx, kd); err != nil {
|
if err := callDisplayElement(activePageCtx, idx, kd); err != nil {
|
||||||
return errors.Wrapf(err, "Unable to execute display element on key %d", idx)
|
return errors.Wrapf(err, "Unable to execute display element on key %d", idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -13,12 +14,12 @@ type action interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type displayElement interface {
|
type displayElement interface {
|
||||||
Display(idx int, attributes map[string]interface{}) error
|
Display(ctx context.Context, idx int, attributes map[string]interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type refreshingDisplayElement interface {
|
type refreshingDisplayElement interface {
|
||||||
NeedsLoop(attributes map[string]interface{}) bool
|
NeedsLoop(attributes map[string]interface{}) bool
|
||||||
StartLoopDisplay(idx int, attributes map[string]interface{}) error
|
StartLoopDisplay(ctx context.Context, idx int, attributes map[string]interface{}) error
|
||||||
StopLoopDisplay() error
|
StopLoopDisplay() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ func callAction(a dynamicElement) error {
|
||||||
return inst.Execute(a.Attributes)
|
return inst.Execute(a.Attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func callDisplayElement(idx int, kd keyDefinition) error {
|
func callDisplayElement(ctx context.Context, idx int, kd keyDefinition) error {
|
||||||
t, ok := registeredDisplayElements[kd.Display.Type]
|
t, ok := registeredDisplayElements[kd.Display.Type]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Errorf("Unknown display type %q", kd.Display.Type)
|
return errors.Errorf("Unknown display type %q", kd.Display.Type)
|
||||||
|
@ -74,8 +75,8 @@ func callDisplayElement(idx int, kd keyDefinition) error {
|
||||||
"display_type": kd.Display.Type,
|
"display_type": kd.Display.Type,
|
||||||
}).Debug("Starting loop")
|
}).Debug("Starting loop")
|
||||||
activeLoops = append(activeLoops, inst.(refreshingDisplayElement))
|
activeLoops = append(activeLoops, inst.(refreshingDisplayElement))
|
||||||
return inst.(refreshingDisplayElement).StartLoopDisplay(idx, kd.Display.Attributes)
|
return inst.(refreshingDisplayElement).StartLoopDisplay(ctx, idx, kd.Display.Attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return inst.(displayElement).Display(idx, kd.Display.Attributes)
|
return inst.(displayElement).Display(ctx, idx, kd.Display.Attributes)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue