add equalizer UI in settings dialog
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package dialogs
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/dweymouth/supersonic/ui/layouts"
|
||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||
"github.com/dweymouth/supersonic/ui/util"
|
||||
)
|
||||
|
||||
type GraphicEqualizer struct {
|
||||
widget.BaseWidget
|
||||
|
||||
OnChanged func(band int, gain float64)
|
||||
|
||||
container *fyne.Container
|
||||
}
|
||||
|
||||
func NewGraphicEqualizer(bandFreqs []string, bandGains []float64) *GraphicEqualizer {
|
||||
g := &GraphicEqualizer{}
|
||||
g.ExtendBaseWidget(g)
|
||||
g.buildSliders(bandFreqs, bandGains)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GraphicEqualizer) buildSliders(bands []string, bandGains []float64) {
|
||||
rng := container.NewVBox(
|
||||
newCaptionTextSizeLabel("+12", fyne.TextAlignTrailing),
|
||||
layout.NewSpacer(),
|
||||
newCaptionTextSizeLabel("0", fyne.TextAlignTrailing),
|
||||
layout.NewSpacer(),
|
||||
newCaptionTextSizeLabel("-12", fyne.TextAlignTrailing),
|
||||
)
|
||||
bandSliders := container.New(layouts.NewGridLayoutWithColumnsAndPadding(16, -16))
|
||||
bandSliders.Add(container.NewBorder(nil, widget.NewLabel(""), nil, nil, rng))
|
||||
for i, band := range bands {
|
||||
s := newEQSlider()
|
||||
if i < len(bandGains) {
|
||||
s.SetValue(bandGains[i])
|
||||
}
|
||||
s.OnChanged = func(i int) func(float64) {
|
||||
return func(f float64) {
|
||||
if g.OnChanged != nil {
|
||||
g.OnChanged(i, f)
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
l := newCaptionTextSizeLabel(band, fyne.TextAlignCenter)
|
||||
c := container.NewBorder(nil, l, nil, nil, s)
|
||||
bandSliders.Add(c)
|
||||
}
|
||||
g.container = container.NewMax(
|
||||
container.NewBorder(nil, widget.NewLabel(""), nil, nil,
|
||||
container.NewBorder(nil, nil, util.NewHSpace(35), util.NewHSpace(5),
|
||||
container.NewVBox(
|
||||
layout.NewSpacer(),
|
||||
myTheme.NewThemedRectangle(theme.ColorNameInputBackground),
|
||||
layout.NewSpacer(),
|
||||
),
|
||||
),
|
||||
),
|
||||
bandSliders,
|
||||
)
|
||||
}
|
||||
|
||||
func newCaptionTextSizeLabel(text string, alignment fyne.TextAlign) *widget.RichText {
|
||||
l := widget.NewRichTextWithText(text)
|
||||
ts := l.Segments[0].(*widget.TextSegment)
|
||||
ts.Style.SizeName = theme.SizeNameCaptionText
|
||||
ts.Style.Alignment = alignment
|
||||
return l
|
||||
}
|
||||
|
||||
func (g *GraphicEqualizer) CreateRenderer() fyne.WidgetRenderer {
|
||||
return widget.NewSimpleRenderer(g.container)
|
||||
}
|
||||
|
||||
type eqSlider struct {
|
||||
widget.Slider
|
||||
tappedAt int64
|
||||
}
|
||||
|
||||
func newEQSlider() *eqSlider {
|
||||
s := &eqSlider{
|
||||
Slider: widget.Slider{
|
||||
Orientation: widget.Vertical,
|
||||
Min: -12,
|
||||
Max: 12,
|
||||
Step: 0.1,
|
||||
},
|
||||
}
|
||||
s.ExtendBaseWidget(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// We implement our own double tapping so that the Tapped behavior
|
||||
// can be triggered instantly.
|
||||
func (s *eqSlider) DoubleTapped(e *fyne.PointEvent) {
|
||||
s.SetValue(0)
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/dweymouth/supersonic/backend"
|
||||
@@ -35,6 +36,7 @@ type SettingsDialog struct {
|
||||
OnAudioDeviceSettingChanged func()
|
||||
OnThemeSettingChanged func()
|
||||
OnDismiss func()
|
||||
OnEqualizerSettingsChanged func()
|
||||
|
||||
config *backend.Config
|
||||
audioDevices []player.AudioDevice
|
||||
@@ -45,13 +47,20 @@ type SettingsDialog struct {
|
||||
}
|
||||
|
||||
// TODO: having this depend on the player package for the AudioDevice type is kinda gross. Refactor.
|
||||
func NewSettingsDialog(config *backend.Config, audioDeviceList []player.AudioDevice, themeFileList map[string]string, window fyne.Window) *SettingsDialog {
|
||||
func NewSettingsDialog(
|
||||
config *backend.Config,
|
||||
audioDeviceList []player.AudioDevice,
|
||||
themeFileList map[string]string,
|
||||
equalizerBands []string,
|
||||
window fyne.Window,
|
||||
) *SettingsDialog {
|
||||
s := &SettingsDialog{config: config, audioDevices: audioDeviceList, themeFiles: themeFileList}
|
||||
s.ExtendBaseWidget(s)
|
||||
|
||||
tabs := container.NewAppTabs(
|
||||
s.createGeneralTab(),
|
||||
s.createPlaybackTab(),
|
||||
s.createEqualizerTab(equalizerBands),
|
||||
s.createExperimentalTab(window),
|
||||
)
|
||||
// workaround issue where inactivated tabs don't fully update when theme setting is changed
|
||||
@@ -320,6 +329,28 @@ func (s *SettingsDialog) createPlaybackTab() *container.TabItem {
|
||||
))
|
||||
}
|
||||
|
||||
func (s *SettingsDialog) createEqualizerTab(eqBands []string) *container.TabItem {
|
||||
enabled := widget.NewCheck("Enabled", func(b bool) {
|
||||
s.config.LocalPlayback.EqualizerEnabled = b
|
||||
if s.OnEqualizerSettingsChanged != nil {
|
||||
s.OnEqualizerSettingsChanged()
|
||||
}
|
||||
})
|
||||
enabled.Checked = s.config.LocalPlayback.EqualizerEnabled
|
||||
geq := NewGraphicEqualizer(eqBands, s.config.LocalPlayback.GraphicEqualizerBands) // TODO: This should probably be an argument?
|
||||
debouncer := util.NewDebouncer(200*time.Millisecond, func() {
|
||||
if s.OnEqualizerSettingsChanged != nil {
|
||||
s.OnEqualizerSettingsChanged()
|
||||
}
|
||||
})
|
||||
geq.OnChanged = func(b int, g float64) {
|
||||
s.config.LocalPlayback.GraphicEqualizerBands[b] = g
|
||||
debouncer()
|
||||
}
|
||||
cont := container.NewBorder(container.NewHBox(enabled), nil, nil, nil, geq)
|
||||
return container.NewTabItem("Equalizer", cont)
|
||||
}
|
||||
|
||||
func (s *SettingsDialog) createExperimentalTab(window fyne.Window) *container.TabItem {
|
||||
warningLabel := widget.NewLabel("WARNING: these settings are experimental and may " +
|
||||
"make the application buggy or increase system resource use. " +
|
||||
|
||||
Reference in New Issue
Block a user