Skip to content

Commit

Permalink
Allow for non-string config map values
Browse files Browse the repository at this point in the history
  • Loading branch information
muesli committed Jun 7, 2021
1 parent 8afd3e2 commit 90850ae
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 81 deletions.
52 changes: 49 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package main

import (
"bytes"
"fmt"
"io/ioutil"
"reflect"
"strconv"

"github.com/BurntSushi/toml"
)
Expand All @@ -26,9 +29,9 @@ type ActionConfig struct {

// WidgetConfig describes configuration data for widgets.
type WidgetConfig struct {
ID string `toml:"id,omitempty"`
Interval uint `toml:"interval,omitempty"`
Config map[string]string `toml:"config,omitempty"`
ID string `toml:"id,omitempty"`
Interval uint `toml:"interval,omitempty"`
Config map[string]interface{} `toml:"config,omitempty"`
}

// KeyConfig holds the entire configuration for a single key.
Expand Down Expand Up @@ -71,3 +74,46 @@ func (c DeckConfig) Save(filename string) error {

return ioutil.WriteFile(filename, b.Bytes(), 0600)
}

func ConfigValue(v interface{}, dst interface{}) error {
switch d := dst.(type) {
case *string:
switch vt := v.(type) {
case string:
*d = vt
default:
return fmt.Errorf("unhandled type %+v for string conversion", reflect.TypeOf(vt))
}

case *int64:
switch vt := v.(type) {
case int64:
*d = vt
case float64:
*d = int64(vt)
case string:
x, _ := strconv.ParseInt(vt, 0, 64)
*d = int64(x)
default:
return fmt.Errorf("unhandled type %+v for uint8 conversion", reflect.TypeOf(vt))
}

case *float64:
switch vt := v.(type) {
case int64:
*d = float64(vt)
case float64:
*d = vt
case string:
x, _ := strconv.ParseFloat(vt, 64)
*d = float64(x)
default:
return fmt.Errorf("unhandled type %+v for float64 conversion", reflect.TypeOf(vt))
}

default:
return fmt.Errorf("unhandled dst type %+v", reflect.TypeOf(dst))
}

return nil
}
5 changes: 4 additions & 1 deletion deck.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ func LoadDeck(dev *streamdeck.Device, base string, deck string) (*Deck, error) {

var w Widget
if k, found := keyMap[i]; found {
w = NewWidget(k, bg)
w, err = NewWidget(k, bg)
if err != nil {
return nil, err
}
} else {
w = NewBaseWidget(i, nil, nil, bg)
}
Expand Down
13 changes: 7 additions & 6 deletions decks/main.deck
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
id = "top"
[keys.widget.config]
mode = "memory"
fillColor = "#a69bd6"

[[keys]]
index = 3
Expand All @@ -37,6 +36,7 @@
[keys.widget.config]
icon = "assets/volume-low.png"
label = "Lower Vol"
fontsize = 8
[keys.action]
keycode = "VolumeDown"

Expand All @@ -47,6 +47,7 @@
[keys.widget.config]
icon = "assets/volume-high.png"
label = "Raise Vol"
fontsize = 8
[keys.action]
keycode = "VolumeUp"

Expand Down Expand Up @@ -87,32 +88,32 @@
[keys.widget]
id = "recentWindow"
[keys.widget.config]
window = "1"
window = 1

[[keys]]
index = 11
[keys.widget]
id = "recentWindow"
[keys.widget.config]
window = "2"
window = 2

[[keys]]
index = 12
[keys.widget]
id = "recentWindow"
[keys.widget.config]
window = "3"
window = 3

[[keys]]
index = 13
[keys.widget]
id = "recentWindow"
[keys.widget.config]
window = "4"
window = 4

[[keys]]
index = 14
[keys.widget]
id = "recentWindow"
[keys.widget.config]
window = "5"
window = 5
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e h1:PzJMNfFQx+QO9hrC1GwZ4BoPGeNGhfeQEgcQFArEjPk=
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
Expand Down
64 changes: 17 additions & 47 deletions widget.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package main

import (
"fmt"
"image"
"image/color"
"image/draw"
"log"
"os"
"strconv"
"time"

"github.com/golang/freetype"
Expand Down Expand Up @@ -82,67 +82,37 @@ func NewBaseWidget(index uint8, action, actionHold *ActionConfig, bg image.Image
}

// NewWidget initializes a widget.
func NewWidget(kc KeyConfig, bg image.Image) Widget {
func NewWidget(kc KeyConfig, bg image.Image) (Widget, error) {
bw := NewBaseWidget(kc.Index, kc.Action, kc.ActionHold, bg)
wc := kc.Widget

switch wc.ID {
switch kc.Widget.ID {
case "button":
bw.setInterval(wc.Interval, 0)
return &ButtonWidget{
BaseWidget: *bw,
icon: wc.Config["icon"],
label: wc.Config["label"],
}
return NewButtonWidget(*bw, kc.Widget)

case "clock":
bw.setInterval(wc.Interval, 1000)
return &TimeWidget{
BaseWidget: *bw,
format: "%H;%i;%s",
font: "bold;regular;thin",
}
kc.Widget.Config = make(map[string]interface{})
kc.Widget.Config["format"] = "%H;%i;%s"
kc.Widget.Config["font"] = "bold;regular;thin"
return NewTimeWidget(*bw, kc.Widget)

case "date":
bw.setInterval(wc.Interval, 1000)
return &TimeWidget{
BaseWidget: *bw,
format: "%l;%d;%M",
font: "regular;bold;regular",
}
kc.Widget.Config = make(map[string]interface{})
kc.Widget.Config["format"] = "%l;%d;%M"
kc.Widget.Config["font"] = "regular;bold;regular"
return NewTimeWidget(*bw, kc.Widget)

case "time":
bw.setInterval(wc.Interval, 1000)
return &TimeWidget{
BaseWidget: *bw,
format: wc.Config["format"],
font: wc.Config["font"],
}
return NewTimeWidget(*bw, kc.Widget)

case "recentWindow":
i, err := strconv.ParseUint(wc.Config["window"], 10, 64)
if err != nil {
log.Fatal(err)
}
return &RecentWindowWidget{
BaseWidget: *bw,
window: uint8(i),
}
return NewRecentWindowWidget(*bw, kc.Widget)

case "top":
bw.setInterval(wc.Interval, 500)
return &TopWidget{
BaseWidget: *bw,
mode: wc.Config["mode"],
fillColor: wc.Config["fillColor"],
}

default:
// unknown widget ID
log.Println("Unknown widget with ID:", wc.ID)
return NewTopWidget(*bw, kc.Widget)
}

return nil
// unknown widget ID
return nil, fmt.Errorf("Unknown widget with ID %s", kc.Widget.ID)
}

// renders the widget including its background image.
Expand Down
17 changes: 17 additions & 0 deletions widget_button.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ type ButtonWidget struct {
fontsize float64
}

func NewButtonWidget(bw BaseWidget, opts WidgetConfig) (*ButtonWidget, error) {
bw.setInterval(opts.Interval, 0)

var icon, label string
ConfigValue(opts.Config["icon"], &icon)
ConfigValue(opts.Config["label"], &label)
var fontsize float64
ConfigValue(opts.Config["fontsize"], &fontsize)

return &ButtonWidget{
BaseWidget: bw,
icon: icon,
label: label,
fontsize: fontsize,
}, nil
}

// Update renders the widget.
func (w *ButtonWidget) Update(dev *streamdeck.Device) error {
size := int(dev.Pixels)
Expand Down
12 changes: 12 additions & 0 deletions widget_recent_window.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ type RecentWindowWidget struct {
lastClass string
}

func NewRecentWindowWidget(bw BaseWidget, opts WidgetConfig) (*RecentWindowWidget, error) {
var window int64
if err := ConfigValue(opts.Config["window"], &window); err != nil {
return nil, err
}

return &RecentWindowWidget{
BaseWidget: bw,
window: uint8(window),
}, nil
}

// RequiresUpdate returns true when the widget wants to be repainted.
func (w *RecentWindowWidget) RequiresUpdate() bool {
if int(w.window) < len(recentWindows) {
Expand Down
56 changes: 35 additions & 21 deletions widget_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,18 @@ type TimeWidget struct {
font string
}

func formatTime(t time.Time, format string) string {
tm := map[string]string{
"%Y": "2006",
"%y": "06",
"%F": "January",
"%M": "Jan",
"%m": "01",
"%l": "Monday",
"%D": "Mon",
"%d": "02",
"%h": "03",
"%H": "15",
"%i": "04",
"%s": "05",
"%a": "PM",
"%t": "MST",
}
func NewTimeWidget(bw BaseWidget, opts WidgetConfig) (*TimeWidget, error) {
bw.setInterval(opts.Interval, 500)

for k, v := range tm {
format = strings.ReplaceAll(format, k, v)
}
var format, font string
ConfigValue(opts.Config["format"], &format)
ConfigValue(opts.Config["font"], &font)

return t.Format(format)
return &TimeWidget{
BaseWidget: bw,
format: format,
font: font,
}, nil
}

// Update renders the widget.
Expand Down Expand Up @@ -75,3 +64,28 @@ func (w *TimeWidget) Update(dev *streamdeck.Device) error {

return w.render(dev, img)
}

func formatTime(t time.Time, format string) string {
tm := map[string]string{
"%Y": "2006",
"%y": "06",
"%F": "January",
"%M": "Jan",
"%m": "01",
"%l": "Monday",
"%D": "Mon",
"%d": "02",
"%h": "03",
"%H": "15",
"%i": "04",
"%s": "05",
"%a": "PM",
"%t": "MST",
}

for k, v := range tm {
format = strings.ReplaceAll(format, k, v)
}

return t.Format(format)
}
Loading

0 comments on commit 90850ae

Please sign in to comment.