mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
drafting
This commit is contained in:
parent
8415660416
commit
ec8c51b003
@ -115,51 +115,27 @@ func (t *TipIconButtonStyle) Layout(gtx C) D {
|
||||
return t.TipArea.Layout(gtx, t.Tooltip, t.IconButtonStyle.Layout)
|
||||
}
|
||||
|
||||
func ActionButton(gtx C, th *material.Theme, w *ActionClickable, text string) ButtonStyle {
|
||||
func ActionButton(gtx C, th *Theme, style *ButtonStyle, w *ActionClickable, text string) Button {
|
||||
for w.Clickable.Clicked(gtx) {
|
||||
w.Action.Do()
|
||||
}
|
||||
ret := Button(th, &w.Clickable, text)
|
||||
ret.Color = th.Palette.Fg
|
||||
if !w.Action.Allowed() {
|
||||
ret.Color = disabledTextColor
|
||||
return Btn(th, &th.DisabledButton, &w.Clickable, text)
|
||||
}
|
||||
ret.Background = transparent
|
||||
ret.Inset = layout.UniformInset(unit.Dp(6))
|
||||
return ret
|
||||
return Btn(th, style, &w.Clickable, text)
|
||||
}
|
||||
|
||||
func ToggleButton(gtx C, th *material.Theme, b *BoolClickable, text string) ButtonStyle {
|
||||
func ToggleButton(gtx C, th *Theme, b *BoolClickable, text string) Button {
|
||||
for b.Clickable.Clicked(gtx) {
|
||||
b.Bool.Toggle()
|
||||
}
|
||||
ret := Button(th, &b.Clickable, text)
|
||||
ret.Background = transparent
|
||||
ret.Inset = layout.UniformInset(unit.Dp(6))
|
||||
if b.Bool.Value() {
|
||||
ret.Color = th.Palette.ContrastFg
|
||||
ret.Background = th.Palette.ContrastBg
|
||||
} else {
|
||||
ret.Color = th.Palette.ContrastBg
|
||||
ret.Background = transparent
|
||||
if !b.Bool.Enabled() {
|
||||
return Btn(th, &th.DisabledButton, &b.Clickable, text)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func LowEmphasisButton(th *material.Theme, w *Clickable, text string) ButtonStyle {
|
||||
ret := Button(th, w, text)
|
||||
ret.Color = th.Palette.Fg
|
||||
ret.Background = transparent
|
||||
ret.Inset = layout.UniformInset(unit.Dp(6))
|
||||
return ret
|
||||
}
|
||||
|
||||
func HighEmphasisButton(th *material.Theme, w *Clickable, text string) ButtonStyle {
|
||||
ret := Button(th, w, text)
|
||||
ret.Color = th.Palette.ContrastFg
|
||||
ret.Background = th.Palette.Fg
|
||||
ret.Inset = layout.UniformInset(unit.Dp(6))
|
||||
return ret
|
||||
if b.Bool.Value() {
|
||||
return Btn(th, &th.FilledButton, &b.Clickable, text)
|
||||
}
|
||||
return Btn(th, &th.TextButton, &b.Clickable, text)
|
||||
}
|
||||
|
||||
// Clickable represents a clickable area.
|
||||
@ -277,7 +253,6 @@ func (b *Clickable) update(t event.Tag, gtx layout.Context) (widget.Click, bool)
|
||||
}
|
||||
|
||||
type ButtonStyle struct {
|
||||
Text string
|
||||
// Color is the text color.
|
||||
Color color.NRGBA
|
||||
Font font.Font
|
||||
@ -285,14 +260,13 @@ type ButtonStyle struct {
|
||||
Background color.NRGBA
|
||||
CornerRadius unit.Dp
|
||||
Inset layout.Inset
|
||||
Button *Clickable
|
||||
shaper *text.Shaper
|
||||
}
|
||||
|
||||
type ButtonLayoutStyle struct {
|
||||
Background color.NRGBA
|
||||
CornerRadius unit.Dp
|
||||
Button *Clickable
|
||||
type Button struct {
|
||||
Text string
|
||||
Button *Clickable
|
||||
shaper *text.Shaper
|
||||
ButtonStyle
|
||||
}
|
||||
|
||||
type IconButtonStyle struct {
|
||||
@ -307,32 +281,17 @@ type IconButtonStyle struct {
|
||||
Description string
|
||||
}
|
||||
|
||||
func Button(th *material.Theme, button *Clickable, txt string) ButtonStyle {
|
||||
b := ButtonStyle{
|
||||
Text: txt,
|
||||
Color: th.Palette.ContrastFg,
|
||||
CornerRadius: 4,
|
||||
Background: th.Palette.ContrastBg,
|
||||
TextSize: th.TextSize * 14.0 / 16.0,
|
||||
Inset: layout.Inset{
|
||||
Top: 10, Bottom: 10,
|
||||
Left: 12, Right: 12,
|
||||
},
|
||||
Button: button,
|
||||
shaper: th.Shaper,
|
||||
func Btn(th *Theme, style *ButtonStyle, button *Clickable, txt string) Button {
|
||||
b := Button{
|
||||
Text: txt,
|
||||
ButtonStyle: *style,
|
||||
Button: button,
|
||||
shaper: th.Material.Shaper,
|
||||
}
|
||||
b.Font.Typeface = th.Face
|
||||
b.Font = labelDefaultFont
|
||||
return b
|
||||
}
|
||||
|
||||
func ButtonLayout(th *material.Theme, button *Clickable) ButtonLayoutStyle {
|
||||
return ButtonLayoutStyle{
|
||||
Button: button,
|
||||
Background: th.Palette.ContrastBg,
|
||||
CornerRadius: 4,
|
||||
}
|
||||
}
|
||||
|
||||
func IconButton(th *material.Theme, button *Clickable, icon *widget.Icon, description string) IconButtonStyle {
|
||||
return IconButtonStyle{
|
||||
Background: th.Palette.ContrastBg,
|
||||
@ -345,21 +304,7 @@ func IconButton(th *material.Theme, button *Clickable, icon *widget.Icon, descri
|
||||
}
|
||||
}
|
||||
|
||||
func (b ButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
return ButtonLayoutStyle{
|
||||
Background: b.Background,
|
||||
CornerRadius: b.CornerRadius,
|
||||
Button: b.Button,
|
||||
}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
colMacro := op.Record(gtx.Ops)
|
||||
paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, b.shaper, b.Font, b.TextSize, b.Text, colMacro.Stop())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
||||
func (b Button) Layout(gtx layout.Context) layout.Dimensions {
|
||||
min := gtx.Constraints.Min
|
||||
return b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
semantic.Button.Add(gtx.Ops)
|
||||
@ -380,7 +325,13 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
||||
},
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
gtx.Constraints.Min = min
|
||||
return layout.Center.Layout(gtx, w)
|
||||
return layout.Center.Layout(gtx, func(gtx C) D {
|
||||
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
colMacro := op.Record(gtx.Ops)
|
||||
paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, b.shaper, b.Font, b.TextSize, b.Text, colMacro.Stop())
|
||||
})
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -130,7 +130,7 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
||||
|
||||
octave := func(gtx C) D {
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
numStyle := NumericUpDown(&t.Theme.Material, t.OctaveNumberInput, ie.octaveHint)
|
||||
numStyle := NumUpDown(t.Theme, t.OctaveNumberInput, ie.octaveHint)
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
return dims
|
||||
}
|
||||
@ -217,7 +217,7 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
|
||||
layout.Rigid(LabelStyle{Text: "Voices", Color: disabledTextColor, Alignment: layout.W, FontSize: t.Theme.Material.TextSize * 14.0 / 16.0, Shaper: t.Theme.Material.Shaper}.Layout),
|
||||
layout.Rigid(layout.Spacer{Width: 4}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
numStyle := NumericUpDown(&t.Theme.Material, t.InstrumentVoices, "Number of voices for this instrument")
|
||||
numStyle := NumUpDown(t.Theme, t.InstrumentVoices, "Number of voices for this instrument")
|
||||
dims := numStyle.Layout(gtx)
|
||||
return dims
|
||||
}),
|
||||
|
@ -173,7 +173,7 @@ func (tr *Tracker) layoutMenu(gtx C, title string, clickable *Clickable, menu *M
|
||||
m := PopupMenu(menu, tr.Theme.Material.Shaper)
|
||||
return func(gtx C) D {
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
titleBtn := Button(&tr.Theme.Material, clickable, title)
|
||||
titleBtn := Btn(tr.Theme, &tr.Theme.MenuButton, clickable, title)
|
||||
titleBtn.Color = white
|
||||
titleBtn.Background = transparent
|
||||
titleBtn.CornerRadius = unit.Dp(0)
|
||||
|
@ -150,22 +150,22 @@ func (te *NoteEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions {
|
||||
|
||||
func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
|
||||
return Surface{Gray: 37, Focus: te.scrollTable.Focused() || te.scrollTable.ChildFocused()}.Layout(gtx, func(gtx C) D {
|
||||
addSemitoneBtnStyle := ActionButton(gtx, &t.Theme.Material, te.AddSemitoneBtn, "+1")
|
||||
subtractSemitoneBtnStyle := ActionButton(gtx, &t.Theme.Material, te.SubtractSemitoneBtn, "-1")
|
||||
addOctaveBtnStyle := ActionButton(gtx, &t.Theme.Material, te.AddOctaveBtn, "+12")
|
||||
subtractOctaveBtnStyle := ActionButton(gtx, &t.Theme.Material, te.SubtractOctaveBtn, "-12")
|
||||
noteOffBtnStyle := ActionButton(gtx, &t.Theme.Material, te.NoteOffBtn, "Note Off")
|
||||
addSemitoneBtnStyle := ActionButton(gtx, t.Theme, &t.Theme.TextButton, te.AddSemitoneBtn, "+1")
|
||||
subtractSemitoneBtnStyle := ActionButton(gtx, t.Theme, &t.Theme.TextButton, te.SubtractSemitoneBtn, "-1")
|
||||
addOctaveBtnStyle := ActionButton(gtx, t.Theme, &t.Theme.TextButton, te.AddOctaveBtn, "+12")
|
||||
subtractOctaveBtnStyle := ActionButton(gtx, t.Theme, &t.Theme.TextButton, te.SubtractOctaveBtn, "-12")
|
||||
noteOffBtnStyle := ActionButton(gtx, t.Theme, &t.Theme.TextButton, te.NoteOffBtn, "Note Off")
|
||||
deleteTrackBtnStyle := ActionIcon(gtx, &t.Theme.Material, te.DeleteTrackBtn, icons.ActionDelete, te.deleteTrackHint)
|
||||
splitTrackBtnStyle := ActionIcon(gtx, &t.Theme.Material, te.SplitTrackBtn, icons.CommunicationCallSplit, te.splitTrackHint)
|
||||
newTrackBtnStyle := ActionIcon(gtx, &t.Theme.Material, te.NewTrackBtn, icons.ContentAdd, te.addTrackHint)
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
voiceUpDown := func(gtx C) D {
|
||||
numStyle := NumericUpDown(&t.Theme.Material, te.TrackVoices, "Track voices")
|
||||
numStyle := NumUpDown(t.Theme, te.TrackVoices, "Track voices")
|
||||
return in.Layout(gtx, numStyle.Layout)
|
||||
}
|
||||
effectBtnStyle := ToggleButton(gtx, &t.Theme.Material, te.EffectBtn, "Hex")
|
||||
effectBtnStyle := ToggleButton(gtx, t.Theme, te.EffectBtn, "Hex")
|
||||
uniqueBtnStyle := ToggleIcon(gtx, &t.Theme.Material, te.UniqueBtn, icons.ToggleStarBorder, icons.ToggleStar, te.uniqueOffTip, te.uniqueOnTip)
|
||||
midiInBtnStyle := ToggleButton(gtx, &t.Theme.Material, te.TrackMidiInBtn, "MIDI")
|
||||
midiInBtnStyle := ToggleButton(gtx, t.Theme, te.TrackMidiInBtn, "MIDI")
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D { return layout.Dimensions{Size: image.Pt(gtx.Dp(unit.Dp(12)), 0)} }),
|
||||
layout.Rigid(addSemitoneBtnStyle.Layout),
|
||||
|
@ -2,14 +2,17 @@ package gioui
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"strconv"
|
||||
|
||||
"github.com/vsariola/sointu/tracker"
|
||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||
|
||||
"gioui.org/font"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/unit"
|
||||
"gioui.org/widget"
|
||||
"gioui.org/x/component"
|
||||
|
||||
@ -30,26 +33,41 @@ type NumberInput struct {
|
||||
}
|
||||
|
||||
type NumericUpDownStyle struct {
|
||||
Theme *Theme
|
||||
TextColor color.NRGBA `yaml:",flow"`
|
||||
IconColor color.NRGBA `yaml:",flow"`
|
||||
BgColor color.NRGBA `yaml:",flow"`
|
||||
CornerRadius unit.Dp
|
||||
ButtonWidth unit.Dp
|
||||
Width unit.Dp
|
||||
Height unit.Dp
|
||||
TextSize unit.Sp
|
||||
DpPerStep unit.Dp
|
||||
}
|
||||
|
||||
type NumericUpDown struct {
|
||||
NumberInput *NumberInput
|
||||
Tooltip component.Tooltip
|
||||
Shaper *text.Shaper
|
||||
Font font.Font
|
||||
NumericUpDownStyle
|
||||
}
|
||||
|
||||
func NewNumberInput(v tracker.Int) *NumberInput {
|
||||
return &NumberInput{Int: v}
|
||||
}
|
||||
|
||||
func NumericUpDown(th *Theme, number *NumberInput, tooltip string) NumericUpDownStyle {
|
||||
return NumericUpDownStyle{
|
||||
NumberInput: number,
|
||||
Theme: th,
|
||||
Tooltip: Tooltip(&th.Material, tooltip),
|
||||
func NumUpDown(th *Theme, number *NumberInput, tooltip string) NumericUpDown {
|
||||
return NumericUpDown{
|
||||
NumberInput: number,
|
||||
Shaper: th.Material.Shaper,
|
||||
Tooltip: Tooltip(&th.Material, tooltip),
|
||||
NumericUpDownStyle: th.NumericUpDown,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) Update(gtx layout.Context) {
|
||||
func (s *NumericUpDown) Update(gtx layout.Context) {
|
||||
// handle dragging
|
||||
pxPerStep := float32(gtx.Dp(s.Theme.NumericUpDown.DpPerStep))
|
||||
pxPerStep := float32(gtx.Dp(s.DpPerStep))
|
||||
for {
|
||||
ev, ok := gtx.Event(pointer.Filter{
|
||||
Target: s.NumberInput,
|
||||
@ -84,22 +102,22 @@ func (s *NumericUpDownStyle) Update(gtx layout.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s NumericUpDownStyle) Layout(gtx C) D {
|
||||
func (s NumericUpDown) Layout(gtx C) D {
|
||||
if s.Tooltip.Text.Text != "" {
|
||||
return s.NumberInput.tipArea.Layout(gtx, s.Tooltip, s.actualLayout)
|
||||
}
|
||||
return s.actualLayout(gtx)
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) actualLayout(gtx C) D {
|
||||
func (s *NumericUpDown) actualLayout(gtx C) D {
|
||||
s.Update(gtx)
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(s.Theme.NumericUpDown.Width), gtx.Dp(s.Theme.NumericUpDown.Height)))
|
||||
width := gtx.Dp(s.Theme.NumericUpDown.ButtonWidth)
|
||||
height := gtx.Dp(s.Theme.NumericUpDown.Height)
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(s.Width), gtx.Dp(s.Height)))
|
||||
width := gtx.Dp(s.ButtonWidth)
|
||||
height := gtx.Dp(s.Height)
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, gtx.Dp(s.Theme.NumericUpDown.CornerRadius)).Push(gtx.Ops).Pop()
|
||||
paint.Fill(gtx.Ops, s.Theme.NumericUpDown.BgColor)
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, gtx.Dp(s.CornerRadius)).Push(gtx.Ops).Pop()
|
||||
paint.Fill(gtx.Ops, s.BgColor)
|
||||
event.Op(gtx.Ops, s.NumberInput) // register drag inputs, if not hitting the clicks
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
@ -113,12 +131,12 @@ func (s *NumericUpDownStyle) actualLayout(gtx C) D {
|
||||
s.NumberInput.clickDecrease.Add(gtx.Ops)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D { return widgetForIcon(icons.ContentRemove).Layout(gtx, s.Theme.NumericUpDown.IconColor) },
|
||||
func(gtx C) D { return widgetForIcon(icons.ContentRemove).Layout(gtx, s.IconColor) },
|
||||
)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
paint.ColorOp{Color: s.Theme.NumericUpDown.TextColor}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, s.Theme.Material.Shaper, s.Font, s.Theme.NumericUpDown.TextSize, strconv.Itoa(s.NumberInput.Int.Value()), op.CallOp{})
|
||||
paint.ColorOp{Color: s.TextColor}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, s.Shaper, s.Font, s.TextSize, strconv.Itoa(s.NumberInput.Int.Value()), op.CallOp{})
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(width, height))
|
||||
|
@ -2,6 +2,7 @@ package gioui
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"gioui.org/f32"
|
||||
@ -15,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
Oscilloscope struct {
|
||||
OscilloscopeState struct {
|
||||
onceBtn *BoolClickable
|
||||
wrapBtn *BoolClickable
|
||||
lengthInBeatsNumber *NumberInput
|
||||
@ -29,14 +30,21 @@ type (
|
||||
}
|
||||
|
||||
OscilloscopeStyle struct {
|
||||
Oscilloscope *Oscilloscope
|
||||
Wave tracker.RingBuffer[[2]float32]
|
||||
Theme *Theme
|
||||
CurveColors [2]color.NRGBA `yaml:",flow"`
|
||||
LimitColor color.NRGBA `yaml:",flow"`
|
||||
CursorColor color.NRGBA `yaml:",flow"`
|
||||
}
|
||||
|
||||
Oscilloscope struct {
|
||||
State *OscilloscopeState
|
||||
Wave tracker.RingBuffer[[2]float32]
|
||||
Theme *Theme
|
||||
OscilloscopeStyle
|
||||
}
|
||||
)
|
||||
|
||||
func NewOscilloscope(model *tracker.Model) *Oscilloscope {
|
||||
return &Oscilloscope{
|
||||
func NewOscilloscope(model *tracker.Model) *OscilloscopeState {
|
||||
return &OscilloscopeState{
|
||||
onceBtn: NewBoolClickable(model.SignalAnalyzer().Once().Bool()),
|
||||
wrapBtn: NewBoolClickable(model.SignalAnalyzer().Wrap().Bool()),
|
||||
lengthInBeatsNumber: NewNumberInput(model.SignalAnalyzer().LengthInBeats().Int()),
|
||||
@ -44,15 +52,15 @@ func NewOscilloscope(model *tracker.Model) *Oscilloscope {
|
||||
}
|
||||
}
|
||||
|
||||
func LineOscilloscope(s *Oscilloscope, wave tracker.RingBuffer[[2]float32], th *Theme) *OscilloscopeStyle {
|
||||
return &OscilloscopeStyle{Oscilloscope: s, Wave: wave, Theme: th}
|
||||
func Scope(s *OscilloscopeState, wave tracker.RingBuffer[[2]float32], th *Theme) *Oscilloscope {
|
||||
return &Oscilloscope{State: s, Wave: wave, Theme: th}
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) Layout(gtx C) D {
|
||||
wrapBtnStyle := ToggleButton(gtx, &s.Theme.Material, s.Oscilloscope.wrapBtn, "Wrap")
|
||||
onceBtnStyle := ToggleButton(gtx, &s.Theme.Material, s.Oscilloscope.onceBtn, "Once")
|
||||
triggerChannelStyle := NumericUpDown(&s.Theme.Material, s.Oscilloscope.triggerChannelNumber, "Trigger channel")
|
||||
lengthNumberStyle := NumericUpDown(&s.Theme.Material, s.Oscilloscope.lengthInBeatsNumber, "Buffer length in beats")
|
||||
func (s *Oscilloscope) Layout(gtx C) D {
|
||||
wrapBtnStyle := ToggleButton(gtx, s.Theme, s.State.wrapBtn, "Wrap")
|
||||
onceBtnStyle := ToggleButton(gtx, s.Theme, s.State.onceBtn, "Once")
|
||||
triggerChannelStyle := NumUpDown(s.Theme, s.State.triggerChannelNumber, "Trigger channel")
|
||||
lengthNumberStyle := NumUpDown(s.Theme, s.State.lengthInBeatsNumber, "Buffer length in beats")
|
||||
|
||||
leftSpacer := layout.Spacer{Width: unit.Dp(6), Height: unit.Dp(24)}.Layout
|
||||
rightSpacer := layout.Spacer{Width: unit.Dp(6)}.Layout
|
||||
@ -82,13 +90,13 @@ func (s *OscilloscopeStyle) Layout(gtx C) D {
|
||||
)
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) layoutWave(gtx C) D {
|
||||
func (s *Oscilloscope) layoutWave(gtx C) D {
|
||||
s.update(gtx)
|
||||
if gtx.Constraints.Max.X == 0 || gtx.Constraints.Max.Y == 0 {
|
||||
return D{}
|
||||
}
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Push(gtx.Ops).Pop()
|
||||
event.Op(gtx.Ops, s.Oscilloscope)
|
||||
event.Op(gtx.Ops, s.State)
|
||||
paint.ColorOp{Color: s.Theme.Oscilloscope.CursorColor}.Add(gtx.Ops)
|
||||
cursorX := int(s.sampleToPx(gtx, float32(s.Wave.Cursor)))
|
||||
fillRect(gtx, clip.Rect{Min: image.Pt(cursorX, 0), Max: image.Pt(cursorX+1, gtx.Constraints.Max.Y)})
|
||||
@ -134,10 +142,10 @@ func fillRect(gtx C, rect clip.Rect) {
|
||||
stack.Pop()
|
||||
}
|
||||
|
||||
func (o *OscilloscopeStyle) update(gtx C) {
|
||||
func (o *Oscilloscope) update(gtx C) {
|
||||
for {
|
||||
ev, ok := gtx.Event(pointer.Filter{
|
||||
Target: o.Oscilloscope,
|
||||
Target: o.State,
|
||||
Kinds: pointer.Scroll | pointer.Press | pointer.Drag | pointer.Release | pointer.Cancel,
|
||||
ScrollY: pointer.ScrollRange{Min: -1e6, Max: 1e6},
|
||||
})
|
||||
@ -148,58 +156,58 @@ func (o *OscilloscopeStyle) update(gtx C) {
|
||||
switch e.Kind {
|
||||
case pointer.Scroll:
|
||||
s1 := o.pxToSample(gtx, e.Position.X)
|
||||
o.Oscilloscope.xScale += min(max(-1, int(e.Scroll.Y)), 1)
|
||||
o.State.xScale += min(max(-1, int(e.Scroll.Y)), 1)
|
||||
s2 := o.pxToSample(gtx, e.Position.X)
|
||||
o.Oscilloscope.xOffset -= s1 - s2
|
||||
o.State.xOffset -= s1 - s2
|
||||
case pointer.Press:
|
||||
if e.Buttons&pointer.ButtonSecondary != 0 {
|
||||
o.Oscilloscope.xOffset = 0
|
||||
o.Oscilloscope.xScale = 0
|
||||
o.Oscilloscope.yScale = 0
|
||||
o.State.xOffset = 0
|
||||
o.State.xScale = 0
|
||||
o.State.yScale = 0
|
||||
}
|
||||
if e.Buttons&pointer.ButtonPrimary != 0 {
|
||||
o.Oscilloscope.dragging = true
|
||||
o.Oscilloscope.dragId = e.PointerID
|
||||
o.Oscilloscope.dragStartPoint = e.Position
|
||||
o.State.dragging = true
|
||||
o.State.dragId = e.PointerID
|
||||
o.State.dragStartPoint = e.Position
|
||||
}
|
||||
case pointer.Drag:
|
||||
if e.Buttons&pointer.ButtonPrimary != 0 && o.Oscilloscope.dragging && e.PointerID == o.Oscilloscope.dragId {
|
||||
deltaX := o.pxToSample(gtx, e.Position.X) - o.pxToSample(gtx, o.Oscilloscope.dragStartPoint.X)
|
||||
o.Oscilloscope.xOffset += deltaX
|
||||
if e.Buttons&pointer.ButtonPrimary != 0 && o.State.dragging && e.PointerID == o.State.dragId {
|
||||
deltaX := o.pxToSample(gtx, e.Position.X) - o.pxToSample(gtx, o.State.dragStartPoint.X)
|
||||
o.State.xOffset += deltaX
|
||||
num := o.yToAmp(gtx, e.Position.Y)
|
||||
den := o.yToAmp(gtx, o.Oscilloscope.dragStartPoint.Y)
|
||||
den := o.yToAmp(gtx, o.State.dragStartPoint.Y)
|
||||
if l := math.Abs(float64(num / den)); l > 1e-3 && l < 1e3 {
|
||||
o.Oscilloscope.yScale += math.Log(l)
|
||||
o.Oscilloscope.yScale = min(max(o.Oscilloscope.yScale, -1e3), 1e3)
|
||||
o.State.yScale += math.Log(l)
|
||||
o.State.yScale = min(max(o.State.yScale, -1e3), 1e3)
|
||||
}
|
||||
o.Oscilloscope.dragStartPoint = e.Position
|
||||
o.State.dragStartPoint = e.Position
|
||||
|
||||
}
|
||||
case pointer.Release | pointer.Cancel:
|
||||
o.Oscilloscope.dragging = false
|
||||
o.State.dragging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OscilloscopeStyle) scaleFactor() float32 {
|
||||
return float32(math.Pow(1.1, float64(o.Oscilloscope.xScale)))
|
||||
func (o *Oscilloscope) scaleFactor() float32 {
|
||||
return float32(math.Pow(1.1, float64(o.State.xScale)))
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) pxToSample(gtx C, px float32) float32 {
|
||||
return px*s.scaleFactor()*float32(len(s.Wave.Buffer))/float32(gtx.Constraints.Max.X) - s.Oscilloscope.xOffset
|
||||
func (s *Oscilloscope) pxToSample(gtx C, px float32) float32 {
|
||||
return px*s.scaleFactor()*float32(len(s.Wave.Buffer))/float32(gtx.Constraints.Max.X) - s.State.xOffset
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) sampleToPx(gtx C, sample float32) float32 {
|
||||
return (sample + s.Oscilloscope.xOffset) * float32(gtx.Constraints.Max.X) / float32(len(s.Wave.Buffer)) / s.scaleFactor()
|
||||
func (s *Oscilloscope) sampleToPx(gtx C, sample float32) float32 {
|
||||
return (sample + s.State.xOffset) * float32(gtx.Constraints.Max.X) / float32(len(s.Wave.Buffer)) / s.scaleFactor()
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) ampToY(gtx C, amp float32) float32 {
|
||||
scale := float32(math.Exp(s.Oscilloscope.yScale))
|
||||
func (s *Oscilloscope) ampToY(gtx C, amp float32) float32 {
|
||||
scale := float32(math.Exp(s.State.yScale))
|
||||
return (1 - amp*scale) / 2 * float32(gtx.Constraints.Max.Y-1)
|
||||
}
|
||||
|
||||
func (s *OscilloscopeStyle) yToAmp(gtx C, y float32) float32 {
|
||||
scale := float32(math.Exp(s.Oscilloscope.yScale))
|
||||
func (s *Oscilloscope) yToAmp(gtx C, y float32) float32 {
|
||||
scale := float32(math.Exp(s.State.yScale))
|
||||
return (1 - y/float32(gtx.Constraints.Max.Y-1)*2) / scale
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ type SongPanel struct {
|
||||
Step *NumberInput
|
||||
SongLength *NumberInput
|
||||
|
||||
Scope *Oscilloscope
|
||||
Scope *OscilloscopeState
|
||||
|
||||
MenuBar *MenuBar
|
||||
PlayBar *PlayBar
|
||||
@ -97,7 +97,7 @@ func (s *SongPanel) Layout(gtx C, t *Tracker) D {
|
||||
func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
|
||||
paint.FillShape(gtx.Ops, songSurfaceColor, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
|
||||
|
||||
scopeStyle := LineOscilloscope(t.Scope, tr.SignalAnalyzer().Waveform(), tr.Theme)
|
||||
scopeStyle := Scope(t.Scope, tr.SignalAnalyzer().Waveform(), tr.Theme)
|
||||
|
||||
var weightingTxt string
|
||||
switch tracker.WeightingType(tr.Model.DetectorWeighting().Value()) {
|
||||
@ -111,15 +111,13 @@ func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
|
||||
weightingTxt = "No weight (RMS)"
|
||||
}
|
||||
|
||||
weightingBtn := LowEmphasisButton(&tr.Theme.Material, t.WeightingTypeBtn, weightingTxt)
|
||||
weightingBtn.Color = mediumEmphasisTextColor
|
||||
weightingBtn := Btn(tr.Theme, &tr.Theme.TextButton, t.WeightingTypeBtn, weightingTxt)
|
||||
|
||||
oversamplingTxt := "Sample peak"
|
||||
if tr.Model.Oversampling().Value() {
|
||||
oversamplingTxt = "True peak"
|
||||
}
|
||||
oversamplingBtn := LowEmphasisButton(&tr.Theme.Material, t.OversamplingBtn, oversamplingTxt)
|
||||
oversamplingBtn.Color = mediumEmphasisTextColor
|
||||
oversamplingBtn := Btn(tr.Theme, &tr.Theme.TextButton, t.OversamplingBtn, oversamplingTxt)
|
||||
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
@ -130,19 +128,19 @@ func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
|
||||
func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "BPM", NumericUpDown(&tr.Theme.Material, t.BPM, "Song Length").Layout)
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "BPM", NumUpDown(tr.Theme, t.BPM, "Song Length").Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Song length", NumericUpDown(&tr.Theme.Material, t.SongLength, "Song Length").Layout)
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Song length", NumUpDown(tr.Theme, t.SongLength, "Song Length").Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Rows per pat", NumericUpDown(&tr.Theme.Material, t.RowsPerPattern, "Rows per pattern").Layout)
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Rows per pat", NumUpDown(tr.Theme, t.RowsPerPattern, "Rows per pattern").Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Rows per beat", NumericUpDown(&tr.Theme.Material, t.RowsPerBeat, "Rows per beat").Layout)
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Rows per beat", NumUpDown(tr.Theme, t.RowsPerBeat, "Rows per beat").Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Cursor step", NumericUpDown(&tr.Theme.Material, t.Step, "Cursor step").Layout)
|
||||
return layoutSongOptionRow(gtx, &tr.Theme.Material, "Cursor step", NumUpDown(tr.Theme, t.Step, "Cursor step").Layout)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
@ -15,23 +15,13 @@ import (
|
||||
)
|
||||
|
||||
type Theme struct {
|
||||
Material material.Theme
|
||||
Oscilloscope struct {
|
||||
CurveColors [2]color.NRGBA `yaml:",flow"`
|
||||
LimitColor color.NRGBA `yaml:",flow"`
|
||||
CursorColor color.NRGBA `yaml:",flow"`
|
||||
}
|
||||
NumericUpDown struct {
|
||||
TextColor color.NRGBA `yaml:",flow"`
|
||||
IconColor color.NRGBA `yaml:",flow"`
|
||||
BgColor color.NRGBA `yaml:",flow"`
|
||||
CornerRadius unit.Dp
|
||||
ButtonWidth unit.Dp
|
||||
Width unit.Dp
|
||||
Height unit.Dp
|
||||
TextSize unit.Sp
|
||||
DpPerStep unit.Dp
|
||||
}
|
||||
Material material.Theme
|
||||
FilledButton ButtonStyle
|
||||
TextButton ButtonStyle
|
||||
DisabledButton ButtonStyle
|
||||
MenuButton ButtonStyle
|
||||
Oscilloscope OscilloscopeStyle
|
||||
NumericUpDown NumericUpDownStyle
|
||||
}
|
||||
|
||||
//go:embed theme.yml
|
||||
@ -39,7 +29,10 @@ var defaultTheme []byte
|
||||
|
||||
func NewTheme() *Theme {
|
||||
var theme Theme
|
||||
yaml.Unmarshal(defaultTheme, &theme)
|
||||
err := yaml.Unmarshal(defaultTheme, &theme)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to default theme: %w", err))
|
||||
}
|
||||
str, _ := yaml.Marshal(theme)
|
||||
fmt.Printf(string(str))
|
||||
ReadCustomConfigYml("theme.yml", &theme)
|
||||
|
@ -1,23 +1,49 @@
|
||||
primarycolor: &primarycolor { r: 243, g: 187, b: 252, a: 255 }
|
||||
secondarycolor: &secondarycolor { r: 187, g: 245, b: 252, a: 255 }
|
||||
transparentcolor: &transparentcolor { r: 0, g: 0, b: 0, a: 0 }
|
||||
material:
|
||||
textsize: 16
|
||||
fingersize: 38
|
||||
palette:
|
||||
bg: &bg { r: 18, g: 18, b: 18, a: 255 }
|
||||
fg: &fg { r: 255, g: 255, b: 255, a: 255 }
|
||||
contrastbg: &contrastbg { r: 206, g: 147, b: 216, a: 255 }
|
||||
contrastbg: *primarycolor
|
||||
contrastfg: &contrastfg { r: 0, g: 0, b: 0, a: 255 }
|
||||
filledbutton:
|
||||
background: *primarycolor
|
||||
color: *contrastfg
|
||||
textsize: &buttontextsize 14
|
||||
cornerradius: &buttoncornerradius 12
|
||||
inset: &buttoninset { top: 0, bottom: 0, left: 6, right: 6 }
|
||||
textbutton:
|
||||
background: *transparentcolor
|
||||
color: *primarycolor
|
||||
textsize: *buttontextsize
|
||||
cornerradius: *buttoncornerradius
|
||||
inset: *buttoninset
|
||||
disabledbutton:
|
||||
background: { r: 53, g: 51, b: 55, a: 255 }
|
||||
color: { r: 120, g: 116, b: 121, a: 255 }
|
||||
textsize: *buttontextsize
|
||||
cornerradius: *buttoncornerradius
|
||||
inset: *buttoninset
|
||||
menubutton:
|
||||
background: *transparentcolor
|
||||
color: { r: 255, g: 255, b: 255, a: 255 }
|
||||
textsize: *buttontextsize
|
||||
cornerradius: 0
|
||||
inset: *buttoninset
|
||||
oscilloscope:
|
||||
curvecolors:
|
||||
[{ r: 206, g: 147, b: 216, a: 255 }, { r: 128, g: 222, b: 234, a: 255 }]
|
||||
curvecolors: [*primarycolor, *secondarycolor]
|
||||
limitcolor: { r: 255, g: 255, b: 255, a: 8 }
|
||||
cursorcolor: { r: 252, g: 186, b: 3, a: 255 }
|
||||
numericupdown:
|
||||
bgcolor: { r: 255, g: 255, b: 255, A: 3 }
|
||||
textcolor: *fg
|
||||
iconcolor: *contrastbg
|
||||
iconcolor: *primarycolor
|
||||
cornerradius: 4
|
||||
buttonwidth: 16
|
||||
unitsperstep: 8
|
||||
dpperstep: 8
|
||||
textsize: 14
|
||||
width: 70
|
||||
height: 20
|
||||
|
@ -299,7 +299,6 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
p.w.floatWidget.Value = (float32(p.w.Parameter.Value()) - float32(ra.Min)) / float32(ra.Max-ra.Min)
|
||||
}
|
||||
sliderStyle := material.Slider(p.Theme, &p.w.floatWidget)
|
||||
sliderStyle.Color = p.Theme.Fg
|
||||
if isSendTarget {
|
||||
sliderStyle.Color = paramIsSendTargetColor
|
||||
}
|
||||
@ -319,7 +318,6 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
p.w.boolWidget.Value = p.w.Parameter.Value() > ra.Min
|
||||
boolStyle := material.Switch(p.Theme, &p.w.boolWidget, "Toggle boolean parameter")
|
||||
boolStyle.Color.Disabled = p.Theme.Fg
|
||||
boolStyle.Color.Enabled = p.Theme.ContrastBg
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
dims := layout.Center.Layout(gtx, boolStyle.Layout)
|
||||
if p.w.boolWidget.Value {
|
||||
|
Loading…
Reference in New Issue
Block a user