mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-19 05:24:48 -04:00
refactor(tracker/gioui): avoid heap escapes in NumericUpDown
This commit is contained in:
parent
db2ccf977d
commit
31007515b5
@ -142,9 +142,8 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
||||
|
||||
octave := func(gtx C) D {
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
return in.Layout(gtx, func(gtx C) D {
|
||||
return t.OctaveNumberInput.Layout(gtx, t.Octave(), t.Theme, &t.Theme.NumericUpDown, "Octave")
|
||||
})
|
||||
octave := NumUpDown(t.Model.Octave(), t.Theme, t.OctaveNumberInput, "Octave")
|
||||
return in.Layout(gtx, octave.Layout)
|
||||
}
|
||||
|
||||
ret := layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
@ -223,15 +222,14 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
|
||||
loadInstrumentBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, ie.loadInstrumentBtn, icons.FileFolderOpen, "Load instrument")
|
||||
copyInstrumentBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, ie.copyInstrumentBtn, icons.ContentContentCopy, "Copy instrument")
|
||||
deleteInstrumentBtn := ActionIconBtn(t.DeleteInstrument(), t.Theme, ie.deleteInstrumentBtn, icons.ActionDelete, ie.deleteInstrumentHint)
|
||||
instrumentVoices := NumUpDown(t.Model.InstrumentVoices(), t.Theme, t.InstrumentVoices, "Number of voices for this instrument")
|
||||
|
||||
header := func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(layout.Spacer{Width: 6}.Layout),
|
||||
layout.Rigid(Label(t.Theme, &t.Theme.InstrumentEditor.Voices, "Voices").Layout),
|
||||
layout.Rigid(layout.Spacer{Width: 4}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return t.InstrumentVoices.Layout(gtx, t.Model.InstrumentVoices(), t.Theme, &t.Theme.NumericUpDown, "Number of voices for this instrument")
|
||||
}),
|
||||
layout.Rigid(instrumentVoices.Layout),
|
||||
layout.Rigid(splitInstrumentBtn.Layout),
|
||||
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
|
||||
layout.Rigid(commentExpandedBtn.Layout),
|
||||
|
@ -51,7 +51,7 @@ func init() {
|
||||
}
|
||||
|
||||
type NoteEditor struct {
|
||||
TrackVoices *NumericUpDown
|
||||
TrackVoices *NumericUpDownState
|
||||
NewTrackBtn *Clickable
|
||||
DeleteTrackBtn *Clickable
|
||||
SplitTrackBtn *Clickable
|
||||
@ -76,7 +76,7 @@ type NoteEditor struct {
|
||||
|
||||
func NewNoteEditor(model *tracker.Model) *NoteEditor {
|
||||
ret := &NoteEditor{
|
||||
TrackVoices: NewNumericUpDown(),
|
||||
TrackVoices: NewNumericUpDownState(),
|
||||
NewTrackBtn: new(Clickable),
|
||||
DeleteTrackBtn: new(Clickable),
|
||||
SplitTrackBtn: new(Clickable),
|
||||
@ -172,11 +172,10 @@ func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
|
||||
deleteTrackBtn := ActionIconBtn(t.DeleteTrack(), t.Theme, te.DeleteTrackBtn, icons.ActionDelete, te.deleteTrackHint)
|
||||
splitTrackBtn := ActionIconBtn(t.SplitTrack(), t.Theme, te.SplitTrackBtn, icons.CommunicationCallSplit, te.splitTrackHint)
|
||||
newTrackBtn := ActionIconBtn(t.AddTrack(), t.Theme, te.NewTrackBtn, icons.ContentAdd, te.addTrackHint)
|
||||
trackVoices := NumUpDown(t.Model.TrackVoices(), t.Theme, te.TrackVoices, "Track voices")
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
voiceUpDown := func(gtx C) D {
|
||||
return in.Layout(gtx, func(gtx C) D {
|
||||
return te.TrackVoices.Layout(gtx, t.Model.TrackVoices(), t.Theme, &t.Theme.NumericUpDown, "Track voices")
|
||||
})
|
||||
trackVoicesInsetted := func(gtx C) D {
|
||||
return in.Layout(gtx, trackVoices.Layout)
|
||||
}
|
||||
effectBtn := ToggleBtn(t.Effect(), t.Theme, te.EffectBtn, "Hex", "Input notes as hex values")
|
||||
uniqueBtn := ToggleIconBtn(t.UniquePatterns(), t.Theme, te.UniqueBtn, icons.ToggleStarBorder, icons.ToggleStar, te.uniqueOffTip, te.uniqueOnTip)
|
||||
@ -193,7 +192,7 @@ func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
|
||||
layout.Rigid(layout.Spacer{Width: 10}.Layout),
|
||||
layout.Rigid(Label(t.Theme, &t.Theme.NoteEditor.Header, "Voices").Layout),
|
||||
layout.Rigid(layout.Spacer{Width: 4}.Layout),
|
||||
layout.Rigid(voiceUpDown),
|
||||
layout.Rigid(trackVoicesInsetted),
|
||||
layout.Rigid(splitTrackBtn.Layout),
|
||||
layout.Rigid(midiInBtn.Layout),
|
||||
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
|
||||
|
@ -23,33 +23,53 @@ import (
|
||||
"gioui.org/text"
|
||||
)
|
||||
|
||||
type NumericUpDown struct {
|
||||
DpPerStep unit.Dp
|
||||
type (
|
||||
NumericUpDownState struct {
|
||||
DpPerStep unit.Dp
|
||||
|
||||
dragStartValue int
|
||||
dragStartXY float32
|
||||
clickDecrease gesture.Click
|
||||
clickIncrease gesture.Click
|
||||
tipArea component.TipArea
|
||||
dragStartValue int
|
||||
dragStartXY float32
|
||||
clickDecrease gesture.Click
|
||||
clickIncrease gesture.Click
|
||||
tipArea component.TipArea
|
||||
}
|
||||
|
||||
NumericUpDownStyle 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
|
||||
Font font.Font
|
||||
}
|
||||
|
||||
NumericUpDown struct {
|
||||
Int tracker.Int
|
||||
Theme *Theme
|
||||
State *NumericUpDownState
|
||||
Style *NumericUpDownStyle
|
||||
Tip string
|
||||
}
|
||||
)
|
||||
|
||||
func NewNumericUpDownState() *NumericUpDownState {
|
||||
return &NumericUpDownState{DpPerStep: unit.Dp(8)}
|
||||
}
|
||||
|
||||
type NumericUpDownStyle 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
|
||||
Font font.Font
|
||||
func NumUpDown(v tracker.Int, th *Theme, n *NumericUpDownState, tip string) NumericUpDown {
|
||||
return NumericUpDown{
|
||||
Int: v,
|
||||
Theme: th,
|
||||
State: n,
|
||||
Style: &th.NumericUpDown,
|
||||
Tip: tip,
|
||||
}
|
||||
}
|
||||
|
||||
func NewNumericUpDown() *NumericUpDown {
|
||||
return &NumericUpDown{DpPerStep: unit.Dp(8)}
|
||||
}
|
||||
|
||||
func (s *NumericUpDown) Update(gtx layout.Context, v tracker.Int) {
|
||||
func (s *NumericUpDownState) Update(gtx layout.Context, v tracker.Int) {
|
||||
// handle dragging
|
||||
pxPerStep := float32(gtx.Dp(s.DpPerStep))
|
||||
for {
|
||||
@ -86,31 +106,23 @@ func (s *NumericUpDown) Update(gtx layout.Context, v tracker.Int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NumericUpDown) Widget(v tracker.Int, th *Theme, st *NumericUpDownStyle, tooltip string) func(gtx C) D {
|
||||
return func(gtx C) D {
|
||||
return s.Layout(gtx, v, th, st, tooltip)
|
||||
func (n *NumericUpDown) Layout(gtx C) D {
|
||||
n.State.Update(gtx, n.Int)
|
||||
if n.Tip != "" {
|
||||
return n.State.tipArea.Layout(gtx, Tooltip(n.Theme, n.Tip), n.actualLayout)
|
||||
}
|
||||
return n.actualLayout(gtx)
|
||||
}
|
||||
|
||||
func (s *NumericUpDown) Layout(gtx C, v tracker.Int, th *Theme, st *NumericUpDownStyle, tooltip string) D {
|
||||
s.Update(gtx, v)
|
||||
if tooltip != "" {
|
||||
return s.tipArea.Layout(gtx, Tooltip(th, tooltip), func(gtx C) D {
|
||||
return s.actualLayout(gtx, v, th, st)
|
||||
})
|
||||
}
|
||||
return s.actualLayout(gtx, v, th, st)
|
||||
}
|
||||
|
||||
func (s *NumericUpDown) actualLayout(gtx C, v tracker.Int, th *Theme, st *NumericUpDownStyle) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(st.Width), gtx.Dp(st.Height)))
|
||||
width := gtx.Dp(st.ButtonWidth)
|
||||
height := gtx.Dp(st.Height)
|
||||
func (n *NumericUpDown) actualLayout(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(n.Style.Width), gtx.Dp(n.Style.Height)))
|
||||
width := gtx.Dp(n.Style.ButtonWidth)
|
||||
height := gtx.Dp(n.Style.Height)
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, gtx.Dp(st.CornerRadius)).Push(gtx.Ops).Pop()
|
||||
paint.Fill(gtx.Ops, st.BgColor)
|
||||
event.Op(gtx.Ops, s) // register drag inputs, if not hitting the clicks
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, gtx.Dp(n.Style.CornerRadius)).Push(gtx.Ops).Pop()
|
||||
paint.Fill(gtx.Ops, n.Style.BgColor)
|
||||
event.Op(gtx.Ops, n.State) // register drag inputs, if not hitting the clicks
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D {
|
||||
@ -120,25 +132,25 @@ func (s *NumericUpDown) actualLayout(gtx C, v tracker.Int, th *Theme, st *Numeri
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||
s.clickDecrease.Add(gtx.Ops)
|
||||
n.State.clickDecrease.Add(gtx.Ops)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D { return th.Icon(icons.ContentRemove).Layout(gtx, st.IconColor) },
|
||||
func(gtx C) D { return n.Theme.Icon(icons.ContentRemove).Layout(gtx, n.Style.IconColor) },
|
||||
)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
paint.ColorOp{Color: st.TextColor}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, th.Material.Shaper, st.Font, st.TextSize, strconv.Itoa(v.Value()), op.CallOp{})
|
||||
paint.ColorOp{Color: n.Style.TextColor}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, n.Theme.Material.Shaper, n.Style.Font, n.Style.TextSize, strconv.Itoa(n.Int.Value()), op.CallOp{})
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(width, height))
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||
s.clickIncrease.Add(gtx.Ops)
|
||||
n.State.clickIncrease.Add(gtx.Ops)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D { return th.Icon(icons.ContentAdd).Layout(gtx, st.IconColor) },
|
||||
func(gtx C) D { return n.Theme.Icon(icons.ContentAdd).Layout(gtx, n.Style.IconColor) },
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
@ -19,8 +19,8 @@ type (
|
||||
OscilloscopeState struct {
|
||||
onceBtn *Clickable
|
||||
wrapBtn *Clickable
|
||||
lengthInBeatsNumber *NumericUpDown
|
||||
triggerChannelNumber *NumericUpDown
|
||||
lengthInBeatsNumber *NumericUpDownState
|
||||
triggerChannelNumber *NumericUpDownState
|
||||
xScale int
|
||||
xOffset float32
|
||||
yScale float64
|
||||
@ -40,8 +40,8 @@ func NewOscilloscope(model *tracker.Model) *OscilloscopeState {
|
||||
return &OscilloscopeState{
|
||||
onceBtn: new(Clickable),
|
||||
wrapBtn: new(Clickable),
|
||||
lengthInBeatsNumber: NewNumericUpDown(),
|
||||
triggerChannelNumber: NewNumericUpDown(),
|
||||
lengthInBeatsNumber: NewNumericUpDownState(),
|
||||
triggerChannelNumber: NewNumericUpDownState(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,9 @@ func (s *OscilloscopeState) Layout(gtx C, vtrig, vlen tracker.Int, once, wrap tr
|
||||
leftSpacer := layout.Spacer{Width: unit.Dp(6), Height: unit.Dp(24)}.Layout
|
||||
rightSpacer := layout.Spacer{Width: unit.Dp(6)}.Layout
|
||||
|
||||
triggerChannel := NumUpDown(vtrig, th, s.triggerChannelNumber, "Trigger channel")
|
||||
lengthInBeats := NumUpDown(vlen, th, s.lengthInBeatsNumber, "Buffer length in beats")
|
||||
|
||||
onceBtn := ToggleBtn(once, th, s.onceBtn, "Once", "Trigger once on next event")
|
||||
wrapBtn := ToggleBtn(wrap, th, s.wrapBtn, "Wrap", "Wrap buffer when full")
|
||||
|
||||
@ -60,9 +63,7 @@ func (s *OscilloscopeState) Layout(gtx C, vtrig, vlen tracker.Int, once, wrap tr
|
||||
layout.Rigid(Label(th, &th.SongPanel.RowHeader, "Trigger").Layout),
|
||||
layout.Flexed(1, func(gtx C) D { return D{Size: gtx.Constraints.Min} }),
|
||||
layout.Rigid(onceBtn.Layout),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return s.triggerChannelNumber.Layout(gtx, vtrig, th, &th.NumericUpDown, "Trigger channel")
|
||||
}),
|
||||
layout.Rigid(triggerChannel.Layout),
|
||||
layout.Rigid(rightSpacer),
|
||||
)
|
||||
}),
|
||||
@ -72,9 +73,7 @@ func (s *OscilloscopeState) Layout(gtx C, vtrig, vlen tracker.Int, once, wrap tr
|
||||
layout.Rigid(Label(th, &th.SongPanel.RowHeader, "Buffer").Layout),
|
||||
layout.Flexed(1, func(gtx C) D { return D{Size: gtx.Constraints.Min} }),
|
||||
layout.Rigid(wrapBtn.Layout),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return s.lengthInBeatsNumber.Layout(gtx, vlen, th, &th.NumericUpDown, "Buffer length in beats")
|
||||
}),
|
||||
layout.Rigid(lengthInBeats.Layout),
|
||||
layout.Rigid(rightSpacer),
|
||||
)
|
||||
}),
|
||||
|
@ -25,11 +25,11 @@ type SongPanel struct {
|
||||
WeightingTypeBtn *Clickable
|
||||
OversamplingBtn *Clickable
|
||||
|
||||
BPM *NumericUpDown
|
||||
RowsPerPattern *NumericUpDown
|
||||
RowsPerBeat *NumericUpDown
|
||||
Step *NumericUpDown
|
||||
SongLength *NumericUpDown
|
||||
BPM *NumericUpDownState
|
||||
RowsPerPattern *NumericUpDownState
|
||||
RowsPerBeat *NumericUpDownState
|
||||
Step *NumericUpDownState
|
||||
SongLength *NumericUpDownState
|
||||
|
||||
Scope *OscilloscopeState
|
||||
|
||||
@ -39,11 +39,11 @@ type SongPanel struct {
|
||||
|
||||
func NewSongPanel(model *tracker.Model) *SongPanel {
|
||||
ret := &SongPanel{
|
||||
BPM: NewNumericUpDown(),
|
||||
RowsPerPattern: NewNumericUpDown(),
|
||||
RowsPerBeat: NewNumericUpDown(),
|
||||
Step: NewNumericUpDown(),
|
||||
SongLength: NewNumericUpDown(),
|
||||
BPM: NewNumericUpDownState(),
|
||||
RowsPerPattern: NewNumericUpDownState(),
|
||||
RowsPerBeat: NewNumericUpDownState(),
|
||||
Step: NewNumericUpDownState(),
|
||||
SongLength: NewNumericUpDownState(),
|
||||
Scope: NewOscilloscope(model),
|
||||
MenuBar: NewMenuBar(model),
|
||||
PlayBar: NewPlayBar(),
|
||||
@ -115,19 +115,24 @@ 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, "BPM", t.BPM.Widget(tr.Model.BPM(), tr.Theme, &tr.Theme.NumericUpDown, "BPM"))
|
||||
bpm := NumUpDown(tr.BPM(), tr.Theme, t.BPM, "BPM")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "BPM", bpm.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Song length", t.SongLength.Widget(tr.Model.SongLength(), tr.Theme, &tr.Theme.NumericUpDown, "Song length"))
|
||||
songLength := NumUpDown(tr.SongLength(), tr.Theme, t.SongLength, "Song length")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Song length", songLength.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per pat", t.RowsPerPattern.Widget(tr.Model.RowsPerPattern(), tr.Theme, &tr.Theme.NumericUpDown, "Rows per pattern"))
|
||||
rowsPerPattern := NumUpDown(tr.RowsPerPattern(), tr.Theme, t.RowsPerPattern, "Rows per pattern")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per pat", rowsPerPattern.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per beat", t.RowsPerBeat.Widget(tr.Model.RowsPerBeat(), tr.Theme, &tr.Theme.NumericUpDown, "Rows per beat"))
|
||||
rowsPerBeat := NumUpDown(tr.RowsPerBeat(), tr.Theme, t.RowsPerBeat, "Rows per beat")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per beat", rowsPerBeat.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Cursor step", t.Step.Widget(tr.Model.Step(), tr.Theme, &tr.Theme.NumericUpDown, "Cursor step"))
|
||||
step := NumUpDown(tr.Step(), tr.Theme, t.Step, "Cursor step")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Cursor step", step.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
cpuload := tr.Model.CPULoad()
|
||||
|
@ -28,8 +28,8 @@ var canQuit = true // set to false in init() if plugin tag is enabled
|
||||
type (
|
||||
Tracker struct {
|
||||
Theme *Theme
|
||||
OctaveNumberInput *NumericUpDown
|
||||
InstrumentVoices *NumericUpDown
|
||||
OctaveNumberInput *NumericUpDownState
|
||||
InstrumentVoices *NumericUpDownState
|
||||
TopHorizontalSplit *Split
|
||||
BottomHorizontalSplit *Split
|
||||
VerticalSplit *Split
|
||||
@ -70,8 +70,8 @@ var ZoomFactors = []float32{.25, 1. / 3, .5, 2. / 3, .75, .8, 1, 1.1, 1.25, 1.5,
|
||||
|
||||
func NewTracker(model *tracker.Model) *Tracker {
|
||||
t := &Tracker{
|
||||
OctaveNumberInput: NewNumericUpDown(),
|
||||
InstrumentVoices: NewNumericUpDown(),
|
||||
OctaveNumberInput: NewNumericUpDownState(),
|
||||
InstrumentVoices: NewNumericUpDownState(),
|
||||
|
||||
TopHorizontalSplit: &Split{Ratio: -.5, MinSize1: 180, MinSize2: 180},
|
||||
BottomHorizontalSplit: &Split{Ratio: -.6, MinSize1: 180, MinSize2: 180},
|
||||
|
Reference in New Issue
Block a user