refactor(tracker): Make Action have separate Doer and Enabler

This commit is contained in:
5684185+vsariola@users.noreply.github.com
2025-05-26 13:35:31 +03:00
parent d6badb97be
commit 036cb1f34d
7 changed files with 600 additions and 480 deletions

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,7 @@ func ActionIcon(gtx C, th *Theme, w *ActionClickable, icon []byte, tip string) T
for w.Clickable.Clicked(gtx) { for w.Clickable.Clicked(gtx) {
w.Action.Do() w.Action.Do()
} }
if !w.Action.Allowed() { if !w.Action.Enabled() {
ret.IconButtonStyle.Color = th.Button.Disabled.Color ret.IconButtonStyle.Color = th.Button.Disabled.Color
} }
return ret return ret
@ -119,7 +119,7 @@ func ActionButton(gtx C, th *Theme, style *ButtonStyle, w *ActionClickable, text
for w.Clickable.Clicked(gtx) { for w.Clickable.Clicked(gtx) {
w.Action.Do() w.Action.Do()
} }
if !w.Action.Allowed() { if !w.Action.Enabled() {
return Btn(th, &th.Button.Disabled, &w.Clickable, text) return Btn(th, &th.Button.Disabled, &w.Clickable, text)
} }
return Btn(th, style, &w.Clickable, text) return Btn(th, style, &w.Clickable, text)

View File

@ -92,7 +92,7 @@ func (d *Dialog) handleKeys(gtx C) {
for d.BtnCancel.Clicked(gtx) { for d.BtnCancel.Clicked(gtx) {
d.cancel.Do() d.cancel.Do()
} }
if d.alt.Allowed() { if d.alt.Enabled() {
d.handleKeysForButton(gtx, &d.BtnAlt, &d.BtnCancel, &d.BtnOk) d.handleKeysForButton(gtx, &d.BtnAlt, &d.BtnCancel, &d.BtnOk)
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnAlt) d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnAlt)
d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnAlt, &d.BtnCancel) d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnAlt, &d.BtnCancel)
@ -118,7 +118,7 @@ func (d *DialogStyle) Layout(gtx C) D {
layout.Rigid(func(gtx C) D { layout.Rigid(func(gtx C) D {
return layout.E.Layout(gtx, func(gtx C) D { return layout.E.Layout(gtx, func(gtx C) D {
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(120)) gtx.Constraints.Min.X = gtx.Dp(unit.Dp(120))
if d.dialog.alt.Allowed() { if d.dialog.alt.Enabled() {
return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx, return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx,
layout.Rigid(d.OkStyle.Layout), layout.Rigid(d.OkStyle.Layout),
layout.Rigid(d.AltStyle.Layout), layout.Rigid(d.AltStyle.Layout),

View File

@ -22,44 +22,50 @@ import (
"golang.org/x/exp/shiny/materialdesign/icons" "golang.org/x/exp/shiny/materialdesign/icons"
) )
type InstrumentEditor struct { type (
newInstrumentBtn *ActionClickable InstrumentEditor struct {
enlargeBtn *BoolClickable newInstrumentBtn *ActionClickable
deleteInstrumentBtn *ActionClickable enlargeBtn *BoolClickable
linkInstrTrackBtn *BoolClickable deleteInstrumentBtn *ActionClickable
splitInstrumentBtn *ActionClickable linkInstrTrackBtn *BoolClickable
copyInstrumentBtn *TipClickable splitInstrumentBtn *ActionClickable
saveInstrumentBtn *TipClickable copyInstrumentBtn *TipClickable
loadInstrumentBtn *TipClickable saveInstrumentBtn *TipClickable
addUnitBtn *ActionClickable loadInstrumentBtn *TipClickable
presetMenuBtn *TipClickable addUnitBtn *ActionClickable
commentExpandBtn *BoolClickable presetMenuBtn *TipClickable
soloBtn *BoolClickable commentExpandBtn *BoolClickable
muteBtn *BoolClickable soloBtn *BoolClickable
commentEditor *Editor muteBtn *BoolClickable
commentString tracker.String commentEditor *Editor
nameEditor *Editor commentString tracker.String
nameString tracker.String nameEditor *Editor
searchEditor *Editor nameString tracker.String
instrumentDragList *DragList searchEditor *Editor
unitDragList *DragList instrumentDragList *DragList
unitEditor *UnitEditor unitDragList *DragList
wasFocused bool unitEditor *UnitEditor
presetMenuItems []MenuItem wasFocused bool
presetMenu Menu presetMenuItems []MenuItem
presetMenu Menu
enlargeHint, shrinkHint string addUnit tracker.Action
addInstrumentHint string
octaveHint string enlargeHint, shrinkHint string
expandCommentHint string addInstrumentHint string
collapseCommentHint string octaveHint string
deleteInstrumentHint string expandCommentHint string
muteHint, unmuteHint string collapseCommentHint string
soloHint, unsoloHint string deleteInstrumentHint string
linkDisabledHint string muteHint, unmuteHint string
linkEnabledHint string soloHint, unsoloHint string
splitInstrumentHint string linkDisabledHint string
} linkEnabledHint string
splitInstrumentHint string
}
AddUnitThenFocus InstrumentEditor
)
func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor { func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
ret := &InstrumentEditor{ ret := &InstrumentEditor{
@ -89,7 +95,8 @@ func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
ret.presetMenuItems = append(ret.presetMenuItems, MenuItem{Text: name, IconBytes: icons.ImageAudiotrack, Doer: model.LoadPreset(index)}) ret.presetMenuItems = append(ret.presetMenuItems, MenuItem{Text: name, IconBytes: icons.ImageAudiotrack, Doer: model.LoadPreset(index)})
return true return true
}) })
ret.addUnitBtn = NewActionClickable(model.AddUnitAndThen(func() { ret.searchEditor.Focus() })) ret.addUnit = model.AddUnit(false)
ret.addUnitBtn = NewActionClickable(tracker.MakeEnabledAction(ret.AddUnitThenFocus()))
ret.enlargeHint = makeHint("Enlarge", " (%s)", "InstrEnlargedToggle") ret.enlargeHint = makeHint("Enlarge", " (%s)", "InstrEnlargedToggle")
ret.shrinkHint = makeHint("Shrink", " (%s)", "InstrEnlargedToggle") ret.shrinkHint = makeHint("Shrink", " (%s)", "InstrEnlargedToggle")
ret.addInstrumentHint = makeHint("Add\ninstrument", "\n(%s)", "AddInstrument") ret.addInstrumentHint = makeHint("Add\ninstrument", "\n(%s)", "AddInstrument")
@ -107,6 +114,15 @@ func NewInstrumentEditor(model *tracker.Model) *InstrumentEditor {
return ret return ret
} }
func (ie *InstrumentEditor) AddUnitThenFocus() tracker.Action {
return tracker.MakeAction((*AddUnitThenFocus)(ie))
}
func (a *AddUnitThenFocus) Enabled() bool { return a.addUnit.Enabled() }
func (a *AddUnitThenFocus) Do() {
a.addUnit.Do()
a.searchEditor.Focus()
}
func (ie *InstrumentEditor) Focus() { func (ie *InstrumentEditor) Focus() {
ie.unitDragList.Focus() ie.unitDragList.Focus()
} }

View File

@ -93,7 +93,7 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop() defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
var macro op.MacroOp var macro op.MacroOp
item := &items[i] item := &items[i]
if i == m.Menu.hover-1 && item.Doer.Allowed() { if i == m.Menu.hover-1 && item.Doer.Enabled() {
macro = op.Record(gtx.Ops) macro = op.Record(gtx.Ops)
} }
icon := widgetForIcon(item.IconBytes) icon := widgetForIcon(item.IconBytes)
@ -102,7 +102,7 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
textLabel := Label(m.Theme, &m.Theme.Menu.Text, item.Text) textLabel := Label(m.Theme, &m.Theme.Menu.Text, item.Text)
shortcutLabel := Label(m.Theme, &m.Theme.Menu.Text, item.ShortcutText) shortcutLabel := Label(m.Theme, &m.Theme.Menu.Text, item.ShortcutText)
shortcutLabel.Color = m.ShortCutColor shortcutLabel.Color = m.ShortCutColor
if !item.Doer.Allowed() { if !item.Doer.Enabled() {
iconColor = m.Disabled iconColor = m.Disabled
textLabel.Color = m.Disabled textLabel.Color = m.Disabled
shortcutLabel.Color = m.Disabled shortcutLabel.Color = m.Disabled
@ -122,14 +122,14 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
return shortcutInset.Layout(gtx, shortcutLabel.Layout) return shortcutInset.Layout(gtx, shortcutLabel.Layout)
}), }),
) )
if i == m.Menu.hover-1 && item.Doer.Allowed() { if i == m.Menu.hover-1 && item.Doer.Enabled() {
recording := macro.Stop() recording := macro.Stop()
paint.FillShape(gtx.Ops, m.HoverColor, clip.Rect{ paint.FillShape(gtx.Ops, m.HoverColor, clip.Rect{
Max: image.Pt(dims.Size.X, dims.Size.Y), Max: image.Pt(dims.Size.X, dims.Size.Y),
}.Op()) }.Op())
recording.Add(gtx.Ops) recording.Add(gtx.Ops)
} }
if item.Doer.Allowed() { if item.Doer.Enabled() {
rect := image.Rect(0, 0, dims.Size.X, dims.Size.Y) rect := image.Rect(0, 0, dims.Size.X, dims.Size.Y)
area := clip.Rect(rect).Push(gtx.Ops) area := clip.Rect(rect).Push(gtx.Ops)
event.Op(gtx.Ops, &m.Menu.tags[i]) event.Op(gtx.Ops, &m.Menu.tags[i])

View File

@ -332,11 +332,11 @@ func (p ParameterStyle) Layout(gtx C) D {
name, _, _, _ := p.tracker.Instruments().Item(i) name, _, _, _ := p.tracker.Instruments().Item(i)
instrItems[i].Text = name instrItems[i].Text = name
instrItems[i].IconBytes = icons.NavigationChevronRight instrItems[i].IconBytes = icons.NavigationChevronRight
instrItems[i].Doer = tracker.Allow(func() { instrItems[i].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() {
if id, ok := p.tracker.Instruments().FirstID(i); ok { if id, ok := p.tracker.Instruments().FirstID(i); ok {
tracker.Int{IntData: p.w.Parameter}.Set(id) tracker.Int{IntData: p.w.Parameter}.Set(id)
} }
}) }))
} }
var unitItems []MenuItem var unitItems []MenuItem
instrName := "<instr>" instrName := "<instr>"
@ -350,9 +350,9 @@ func (p ParameterStyle) Layout(gtx C) D {
id := unit.ID id := unit.ID
unitItems[j].Text = buildUnitLabel(j, unit) unitItems[j].Text = buildUnitLabel(j, unit)
unitItems[j].IconBytes = icons.NavigationChevronRight unitItems[j].IconBytes = icons.NavigationChevronRight
unitItems[j].Doer = tracker.Allow(func() { unitItems[j].Doer = tracker.MakeEnabledAction((tracker.DoFunc)(func() {
tracker.Int{IntData: p.w.Parameter}.Set(id) tracker.Int{IntData: p.w.Parameter}.Set(id)
}) }))
} }
} }
defer pointer.PassOp{}.Push(gtx.Ops).Pop() defer pointer.PassOp{}.Push(gtx.Ops).Pop()

View File

@ -143,22 +143,22 @@ func NumPresets() int {
// LoadPreset loads a preset from the list of instrument presets. The index // LoadPreset loads a preset from the list of instrument presets. The index
// should be within the range of 0 to NumPresets()-1. // should be within the range of 0 to NumPresets()-1.
func (m *Model) LoadPreset(index int) Action { func (m *Model) LoadPreset(index int) Action {
return Action{do: func() { return MakeEnabledAction(LoadPreset{Index: index, Model: m})
defer m.change("LoadPreset", PatchChange, MajorChange)() }
if m.d.InstrIndex < 0 { func (m LoadPreset) Do() {
m.d.InstrIndex = 0 defer m.change("LoadPreset", PatchChange, MajorChange)()
} if m.d.InstrIndex < 0 {
m.d.InstrIndex2 = m.d.InstrIndex m.d.InstrIndex = 0
for m.d.InstrIndex >= len(m.d.Song.Patch) { }
m.d.Song.Patch = append(m.d.Song.Patch, defaultInstrument.Copy()) m.d.InstrIndex2 = m.d.InstrIndex
} for m.d.InstrIndex >= len(m.d.Song.Patch) {
newInstr := instrumentPresets[index].Copy() m.d.Song.Patch = append(m.d.Song.Patch, defaultInstrument.Copy())
(*Model)(m).assignUnitIDs(newInstr.Units) }
m.d.Song.Patch[m.d.InstrIndex] = newInstr newInstr := instrumentPresets[m.Index].Copy()
}, allowed: func() bool { m.Model.assignUnitIDs(newInstr.Units)
return true m.d.Song.Patch[m.d.InstrIndex] = newInstr
}}
} }
type instrumentPresetsSlice []sointu.Instrument type instrumentPresetsSlice []sointu.Instrument