mirror of
https://github.com/vsariola/sointu.git
synced 2026-04-06 06:02:53 -04:00
refactor(tracker): group Model methods, with each group in one source file
This commit is contained in:
parent
b93304adab
commit
86ca3fb300
@ -53,7 +53,7 @@ type (
|
||||
|
||||
func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor {
|
||||
ret := &InstrumentEditor{
|
||||
dragList: NewDragList(m.Units(), layout.Vertical),
|
||||
dragList: NewDragList(m.Unit().List(), layout.Vertical),
|
||||
addUnitBtn: new(Clickable),
|
||||
searchEditor: NewEditor(true, true, text.Start),
|
||||
DeleteUnitBtn: new(Clickable),
|
||||
@ -62,9 +62,9 @@ func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor {
|
||||
CopyUnitBtn: new(Clickable),
|
||||
SelectTypeBtn: new(Clickable),
|
||||
commentEditor: NewEditor(true, true, text.Start),
|
||||
paramTable: NewScrollTable(m.Params().Table(), m.ParamVertList().List(), m.Units()),
|
||||
searchList: NewDragList(m.SearchResults(), layout.Vertical),
|
||||
searching: m.UnitSearching(),
|
||||
paramTable: NewScrollTable(m.Params().Table(), m.Params().Columns(), m.Unit().List()),
|
||||
searchList: NewDragList(m.Unit().SearchResults(), layout.Vertical),
|
||||
searching: m.Unit().Searching(),
|
||||
}
|
||||
ret.caser = cases.Title(language.English)
|
||||
ret.copyHint = makeHint("Copy unit", " (%s)", "Copy")
|
||||
@ -95,9 +95,9 @@ func (ul *InstrumentEditor) layoutList(gtx C) D {
|
||||
element := func(gtx C, i int) D {
|
||||
gtx.Constraints.Max.Y = gtx.Dp(20)
|
||||
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
|
||||
u := t.Unit(i)
|
||||
u := t.Unit().Item(i)
|
||||
editorStyle := t.Theme.InstrumentEditor.UnitList.Name
|
||||
signalError := t.RailError()
|
||||
signalError := t.Unit().RailError()
|
||||
switch {
|
||||
case u.Disabled:
|
||||
editorStyle = t.Theme.InstrumentEditor.UnitList.NameDisabled
|
||||
@ -107,7 +107,7 @@ func (ul *InstrumentEditor) layoutList(gtx C) D {
|
||||
unitName := func(gtx C) D {
|
||||
if i == ul.dragList.TrackerList.Selected() {
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
return ul.searchEditor.Layout(gtx, t.Model.UnitSearch(), t.Theme, &editorStyle, "---")
|
||||
return ul.searchEditor.Layout(gtx, t.Model.Unit().SearchTerm(), t.Theme, &editorStyle, "---")
|
||||
} else {
|
||||
text := u.Type
|
||||
if text == "" {
|
||||
@ -169,40 +169,40 @@ func (ul *InstrumentEditor) update(gtx C) {
|
||||
case key.NameRightArrow:
|
||||
t.PatchPanel.instrEditor.paramTable.RowTitleList.Focus()
|
||||
case key.NameDeleteBackward:
|
||||
t.SetSelectedUnitType("")
|
||||
t.UnitSearching().SetValue(true)
|
||||
t.Unit().SetType("")
|
||||
t.Unit().Searching().SetValue(true)
|
||||
ul.searchEditor.Focus()
|
||||
case key.NameEnter, key.NameReturn:
|
||||
t.Model.AddUnit(e.Modifiers.Contain(key.ModCtrl)).Do()
|
||||
t.UnitSearching().SetValue(true)
|
||||
t.Model.Unit().Add(e.Modifiers.Contain(key.ModCtrl)).Do()
|
||||
t.Unit().Searching().SetValue(true)
|
||||
ul.searchEditor.Focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
str := t.Model.UnitSearch()
|
||||
str := t.Model.Unit().SearchTerm()
|
||||
for ev := ul.searchEditor.Update(gtx, str); ev != EditorEventNone; ev = ul.searchEditor.Update(gtx, str) {
|
||||
if ev == EditorEventSubmit {
|
||||
if str.Value() != "" {
|
||||
for _, n := range sointu.UnitNames {
|
||||
if strings.HasPrefix(n, str.Value()) {
|
||||
t.SetSelectedUnitType(n)
|
||||
t.Unit().SetType(n)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.SetSelectedUnitType("")
|
||||
t.Unit().SetType("")
|
||||
}
|
||||
}
|
||||
ul.dragList.Focus()
|
||||
t.UnitSearching().SetValue(false)
|
||||
t.Unit().Searching().SetValue(false)
|
||||
}
|
||||
for ul.addUnitBtn.Clicked(gtx) {
|
||||
t.AddUnit(false).Do()
|
||||
t.UnitSearching().SetValue(true)
|
||||
t.Unit().Add(false).Do()
|
||||
t.Unit().Searching().SetValue(true)
|
||||
ul.searchEditor.Focus()
|
||||
}
|
||||
for ul.CopyUnitBtn.Clicked(gtx) {
|
||||
if contents, ok := t.Units().CopyElements(); ok {
|
||||
if contents, ok := t.Unit().List().CopyElements(); ok {
|
||||
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
||||
t.Alerts().Add("Unit(s) copied to clipboard", tracker.Info)
|
||||
}
|
||||
@ -211,9 +211,9 @@ func (ul *InstrumentEditor) update(gtx C) {
|
||||
ul.ChooseUnitType(t)
|
||||
}
|
||||
for ul.ClearUnitBtn.Clicked(gtx) {
|
||||
t.ClearUnit().Do()
|
||||
t.UnitSearch().SetValue("")
|
||||
t.UnitSearching().SetValue(true)
|
||||
t.Unit().Clear().Do()
|
||||
t.Unit().SearchTerm().SetValue("")
|
||||
t.Unit().Searching().SetValue(true)
|
||||
ul.searchList.Focus()
|
||||
}
|
||||
for {
|
||||
@ -228,7 +228,7 @@ func (ul *InstrumentEditor) update(gtx C) {
|
||||
if e, ok := e.(key.Event); ok && e.State == key.Press {
|
||||
switch e.Name {
|
||||
case key.NameEscape:
|
||||
t.UnitSearching().SetValue(false)
|
||||
t.Unit().Searching().SetValue(false)
|
||||
ul.paramTable.RowTitleList.Focus()
|
||||
case key.NameEnter, key.NameReturn:
|
||||
ul.ChooseUnitType(t)
|
||||
@ -288,8 +288,8 @@ func (pe *InstrumentEditor) layoutTable(gtx C) D {
|
||||
}
|
||||
|
||||
func (pe *InstrumentEditor) ChooseUnitType(t *Tracker) {
|
||||
if ut, ok := t.SearchResult(pe.searchList.TrackerList.Selected()); ok {
|
||||
t.SetSelectedUnitType(ut)
|
||||
if ut, ok := t.Unit().SearchResult(pe.searchList.TrackerList.Selected()); ok {
|
||||
t.Unit().SetType(ut)
|
||||
pe.paramTable.RowTitleList.Focus()
|
||||
}
|
||||
}
|
||||
@ -305,9 +305,9 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
||||
cellWidth := gtx.Dp(t.Theme.UnitEditor.Width)
|
||||
cellHeight := gtx.Dp(t.Theme.UnitEditor.Height)
|
||||
rowTitleLabelWidth := gtx.Dp(t.Theme.UnitEditor.UnitList.LabelWidth)
|
||||
rowTitleSignalWidth := gtx.Dp(t.Theme.SignalRail.SignalWidth) * t.RailWidth()
|
||||
rowTitleSignalWidth := gtx.Dp(t.Theme.SignalRail.SignalWidth) * t.Unit().RailWidth()
|
||||
rowTitleWidth := rowTitleLabelWidth + rowTitleSignalWidth
|
||||
signalError := t.RailError()
|
||||
signalError := t.Unit().RailError()
|
||||
columnTitleHeight := gtx.Dp(0)
|
||||
for i := range pe.Parameters {
|
||||
for len(pe.Parameters[i]) < width {
|
||||
@ -321,7 +321,7 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
||||
if y < 0 || y >= len(pe.Parameters) {
|
||||
return D{}
|
||||
}
|
||||
item := t.Unit(y)
|
||||
item := t.Unit().Item(y)
|
||||
sr := Rail(t.Theme, item.Signals)
|
||||
label := Label(t.Theme, &t.Theme.UnitEditor.UnitList.Name, item.Type)
|
||||
switch {
|
||||
@ -360,20 +360,20 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
||||
}
|
||||
|
||||
param := t.Model.Params().Item(point)
|
||||
paramStyle := Param(param, t.Theme, pe.Parameters[y][x], pe.paramTable.Table.Cursor() == point, t.Unit(y).Disabled)
|
||||
paramStyle := Param(param, t.Theme, pe.Parameters[y][x], pe.paramTable.Table.Cursor() == point, t.Unit().Item(y).Disabled)
|
||||
paramStyle.Layout(gtx)
|
||||
if x == t.Model.Params().RowWidth(y) {
|
||||
if y == cursor.Y {
|
||||
return layout.W.Layout(gtx, func(gtx C) D {
|
||||
for pe.commentEditor.Update(gtx, t.UnitComment()) != EditorEventNone {
|
||||
for pe.commentEditor.Update(gtx, t.Unit().Comment()) != EditorEventNone {
|
||||
t.FocusPrev(gtx, false)
|
||||
}
|
||||
gtx.Constraints.Max.X = 1e6
|
||||
gtx.Constraints.Min.Y = 0
|
||||
return pe.commentEditor.Layout(gtx, t.UnitComment(), t.Theme, &t.Theme.InstrumentEditor.UnitComment, "---")
|
||||
return pe.commentEditor.Layout(gtx, t.Unit().Comment(), t.Theme, &t.Theme.InstrumentEditor.UnitComment, "---")
|
||||
})
|
||||
} else {
|
||||
comment := t.Unit(y).Comment
|
||||
comment := t.Unit().Item(y).Comment
|
||||
if comment != "" {
|
||||
style := t.Theme.InstrumentEditor.UnitComment.AsLabelStyle()
|
||||
label := Label(t.Theme, &style, comment)
|
||||
@ -408,7 +408,7 @@ func (pe *InstrumentEditor) drawSignals(gtx C, rowTitleWidth int) {
|
||||
gtx.Constraints.Max = gtx.Constraints.Max.Sub(p)
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Max}).Push(gtx.Ops).Pop()
|
||||
defer op.Offset(image.Pt(-colP.Offset, -rowP.Offset)).Push(gtx.Ops).Pop()
|
||||
for wire := range t.Wires {
|
||||
for wire := range t.Params().Wires {
|
||||
clr := t.Theme.UnitEditor.WireColor
|
||||
if wire.Highlight {
|
||||
clr = t.Theme.UnitEditor.WireHighlight
|
||||
@ -516,9 +516,9 @@ func mulVec(a, b f32.Point) f32.Point {
|
||||
|
||||
func (pe *InstrumentEditor) layoutFooter(gtx C) D {
|
||||
t := TrackerFromContext(gtx)
|
||||
deleteUnitBtn := ActionIconBtn(t.DeleteUnit(), t.Theme, pe.DeleteUnitBtn, icons.ActionDelete, "Delete unit (Ctrl+Backspace)")
|
||||
deleteUnitBtn := ActionIconBtn(t.Unit().Delete(), t.Theme, pe.DeleteUnitBtn, icons.ActionDelete, "Delete unit (Ctrl+Backspace)")
|
||||
copyUnitBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, pe.CopyUnitBtn, icons.ContentContentCopy, pe.copyHint)
|
||||
disableUnitBtn := ToggleIconBtn(t.UnitDisabled(), t.Theme, pe.DisableUnitBtn, icons.AVVolumeUp, icons.AVVolumeOff, pe.disableUnitHint, pe.enableUnitHint)
|
||||
disableUnitBtn := ToggleIconBtn(t.Unit().Disabled(), t.Theme, pe.DisableUnitBtn, icons.AVVolumeUp, icons.AVVolumeOff, pe.disableUnitHint, pe.enableUnitHint)
|
||||
clearUnitBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, pe.ClearUnitBtn, icons.ContentClear, "Clear unit")
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(deleteUnitBtn.Layout),
|
||||
@ -531,7 +531,7 @@ func (pe *InstrumentEditor) layoutFooter(gtx C) D {
|
||||
func (pe *InstrumentEditor) layoutUnitTypeChooser(gtx C) D {
|
||||
t := TrackerFromContext(gtx)
|
||||
element := func(gtx C, i int) D {
|
||||
name, _ := t.SearchResult(i)
|
||||
name, _ := t.Unit().SearchResult(i)
|
||||
w := Label(t.Theme, &t.Theme.UnitEditor.Chooser, name)
|
||||
if i == pe.searchList.TrackerList.Selected() {
|
||||
return pe.SelectTypeBtn.Layout(gtx, w.Layout)
|
||||
|
||||
@ -36,8 +36,8 @@ func NewInstrumentPresets(m *tracker.Model) *InstrumentPresets {
|
||||
builtinPresetsBtn: new(Clickable),
|
||||
saveUserPreset: new(Clickable),
|
||||
deleteUserPreset: new(Clickable),
|
||||
dirList: NewDragList(m.PresetDirList().List(), layout.Vertical),
|
||||
resultList: NewDragList(m.PresetResultList().List(), layout.Vertical),
|
||||
dirList: NewDragList(m.Preset().DirList(), layout.Vertical),
|
||||
resultList: NewDragList(m.Preset().SearchResultList(), layout.Vertical),
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,13 +88,13 @@ func (ip *InstrumentPresets) layout(gtx C) D {
|
||||
ip.update(gtx)
|
||||
// get tracker from values
|
||||
tr := TrackerFromContext(gtx)
|
||||
gmDlsBtn := ToggleBtn(tr.NoGmDls(), tr.Theme, ip.gmDlsBtn, "No gm.dls", "Exclude presets using gm.dls")
|
||||
userPresetsFilterBtn := ToggleBtn(tr.UserPresetFilter(), tr.Theme, ip.userPresetsBtn, "User", "Show only user presets")
|
||||
builtinPresetsFilterBtn := ToggleBtn(tr.BuiltinPresetsFilter(), tr.Theme, ip.builtinPresetsBtn, "Builtin", "Show only builtin presets")
|
||||
saveUserPresetBtn := ActionIconBtn(tr.SaveAsUserPreset(), tr.Theme, ip.saveUserPreset, icons.ContentSave, "Save instrument as user preset")
|
||||
deleteUserPresetBtn := ActionIconBtn(tr.TryDeleteUserPreset(), tr.Theme, ip.deleteUserPreset, icons.ActionDelete, "Delete user preset")
|
||||
gmDlsBtn := ToggleBtn(tr.Preset().NoGmDls(), tr.Theme, ip.gmDlsBtn, "No gm.dls", "Exclude presets using gm.dls")
|
||||
userPresetsFilterBtn := ToggleBtn(tr.Preset().UserFilter(), tr.Theme, ip.userPresetsBtn, "User", "Show only user presets")
|
||||
builtinPresetsFilterBtn := ToggleBtn(tr.Preset().BuiltinFilter(), tr.Theme, ip.builtinPresetsBtn, "Builtin", "Show only builtin presets")
|
||||
saveUserPresetBtn := ActionIconBtn(tr.Preset().Save(), tr.Theme, ip.saveUserPreset, icons.ContentSave, "Save instrument as user preset")
|
||||
deleteUserPresetBtn := ActionIconBtn(tr.Preset().Delete(), tr.Theme, ip.deleteUserPreset, icons.ActionDelete, "Delete user preset")
|
||||
dirElem := func(gtx C, i int) D {
|
||||
return Label(tr.Theme, &tr.Theme.InstrumentEditor.Presets.Directory, tr.Model.PresetDirList().Value(i)).Layout(gtx)
|
||||
return Label(tr.Theme, &tr.Theme.InstrumentEditor.Presets.Directory, tr.Model.Preset().Dir(i)).Layout(gtx)
|
||||
}
|
||||
dirs := func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(140), gtx.Constraints.Max.Y))
|
||||
@ -108,7 +108,7 @@ func (ip *InstrumentPresets) layout(gtx C) D {
|
||||
}
|
||||
resultElem := func(gtx C, i int) D {
|
||||
gtx.Constraints.Min.X = gtx.Constraints.Max.X
|
||||
n, d, u := tr.Model.PresetResultList().Value(i)
|
||||
n, d, u := tr.Model.Preset().SearchResult(i)
|
||||
if u {
|
||||
ln := Label(tr.Theme, &tr.Theme.InstrumentEditor.Presets.Results.User, n)
|
||||
ld := Label(tr.Theme, &tr.Theme.InstrumentEditor.Presets.Results.UserDir, d)
|
||||
@ -121,7 +121,7 @@ func (ip *InstrumentPresets) layout(gtx C) D {
|
||||
return Label(tr.Theme, &tr.Theme.InstrumentEditor.Presets.Results.Builtin, n).Layout(gtx)
|
||||
}
|
||||
floatButtons := func(gtx C) D {
|
||||
if tr.Model.DeleteUserPreset().Enabled() {
|
||||
if tr.Model.Preset().Delete().Enabled() {
|
||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||
layout.Rigid(deleteUserPresetBtn.Layout),
|
||||
layout.Rigid(saveUserPresetBtn.Layout),
|
||||
@ -189,10 +189,10 @@ func (ip *InstrumentPresets) layoutSearch(gtx C) D {
|
||||
})
|
||||
}
|
||||
ed := func(gtx C) D {
|
||||
return ip.searchEditor.Layout(gtx, tr.Model.PresetSearchString(), tr.Theme, &tr.Theme.InstrumentEditor.UnitComment, "Search presets")
|
||||
return ip.searchEditor.Layout(gtx, tr.Preset().SearchTerm(), tr.Theme, &tr.Theme.InstrumentEditor.UnitComment, "Search presets")
|
||||
}
|
||||
clr := func(gtx C) D {
|
||||
btn := ActionIconBtn(tr.ClearPresetSearch(), tr.Theme, ip.clearSearchBtn, icons.ContentClear, "Clear search")
|
||||
btn := ActionIconBtn(tr.Preset().ClearSearch(), tr.Theme, ip.clearSearchBtn, icons.ContentClear, "Clear search")
|
||||
return btn.Layout(gtx)
|
||||
}
|
||||
w := func(gtx C) D {
|
||||
|
||||
@ -58,20 +58,20 @@ func (ip *InstrumentProperties) layout(gtx C) D {
|
||||
// get tracker from values
|
||||
tr := TrackerFromContext(gtx)
|
||||
voiceLine := func(gtx C) D {
|
||||
splitInstrumentBtn := ActionIconBtn(tr.SplitInstrument(), tr.Theme, ip.splitInstrumentBtn, icons.CommunicationCallSplit, ip.splitInstrumentHint)
|
||||
splitInstrumentBtn := ActionIconBtn(tr.Instrument().Split(), tr.Theme, ip.splitInstrumentBtn, icons.CommunicationCallSplit, ip.splitInstrumentHint)
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
instrumentVoices := NumUpDown(tr.Model.InstrumentVoices(), tr.Theme, ip.voices, "Number of voices for this instrument")
|
||||
instrumentVoices := NumUpDown(tr.Model.Instrument().Voices(), tr.Theme, ip.voices, "Number of voices for this instrument")
|
||||
return instrumentVoices.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(splitInstrumentBtn.Layout),
|
||||
)
|
||||
}
|
||||
|
||||
thread1btn := ToggleIconBtn(tr.Thread1(), tr.Theme, ip.threadBtns[0], icons.ImageCropSquare, icons.ImageFilter1, "Do not render instrument on thread 1", "Render instrument on thread 1")
|
||||
thread2btn := ToggleIconBtn(tr.Thread2(), tr.Theme, ip.threadBtns[1], icons.ImageCropSquare, icons.ImageFilter2, "Do not render instrument on thread 2", "Render instrument on thread 2")
|
||||
thread3btn := ToggleIconBtn(tr.Thread3(), tr.Theme, ip.threadBtns[2], icons.ImageCropSquare, icons.ImageFilter3, "Do not render instrument on thread 3", "Render instrument on thread 3")
|
||||
thread4btn := ToggleIconBtn(tr.Thread4(), tr.Theme, ip.threadBtns[3], icons.ImageCropSquare, icons.ImageFilter4, "Do not render instrument on thread 4", "Render instrument on thread 4")
|
||||
thread1btn := ToggleIconBtn(tr.Instrument().Thread1(), tr.Theme, ip.threadBtns[0], icons.ImageCropSquare, icons.ImageFilter1, "Do not render instrument on thread 1", "Render instrument on thread 1")
|
||||
thread2btn := ToggleIconBtn(tr.Instrument().Thread2(), tr.Theme, ip.threadBtns[1], icons.ImageCropSquare, icons.ImageFilter2, "Do not render instrument on thread 2", "Render instrument on thread 2")
|
||||
thread3btn := ToggleIconBtn(tr.Instrument().Thread3(), tr.Theme, ip.threadBtns[2], icons.ImageCropSquare, icons.ImageFilter3, "Do not render instrument on thread 3", "Render instrument on thread 3")
|
||||
thread4btn := ToggleIconBtn(tr.Instrument().Thread4(), tr.Theme, ip.threadBtns[3], icons.ImageCropSquare, icons.ImageFilter4, "Do not render instrument on thread 4", "Render instrument on thread 4")
|
||||
|
||||
threadbtnline := func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
@ -86,21 +86,21 @@ func (ip *InstrumentProperties) layout(gtx C) D {
|
||||
switch index {
|
||||
case 0:
|
||||
return layoutInstrumentPropertyLine(gtx, "Name", func(gtx C) D {
|
||||
return ip.nameEditor.Layout(gtx, tr.InstrumentName(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Instr")
|
||||
return ip.nameEditor.Layout(gtx, tr.Instrument().Name(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Instr")
|
||||
})
|
||||
case 2:
|
||||
return layoutInstrumentPropertyLine(gtx, "Voices", voiceLine)
|
||||
case 4:
|
||||
muteBtn := ToggleIconBtn(tr.Mute(), tr.Theme, ip.muteBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.muteHint, ip.unmuteHint)
|
||||
muteBtn := ToggleIconBtn(tr.Instrument().Mute(), tr.Theme, ip.muteBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.muteHint, ip.unmuteHint)
|
||||
return layoutInstrumentPropertyLine(gtx, "Mute", muteBtn.Layout)
|
||||
case 6:
|
||||
soloBtn := ToggleIconBtn(tr.Solo(), tr.Theme, ip.soloBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.soloHint, ip.unsoloHint)
|
||||
soloBtn := ToggleIconBtn(tr.Instrument().Solo(), tr.Theme, ip.soloBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.soloHint, ip.unsoloHint)
|
||||
return layoutInstrumentPropertyLine(gtx, "Solo", soloBtn.Layout)
|
||||
case 8:
|
||||
return layoutInstrumentPropertyLine(gtx, "Thread", threadbtnline)
|
||||
case 10:
|
||||
return layout.UniformInset(unit.Dp(6)).Layout(gtx, func(gtx C) D {
|
||||
return ip.commentEditor.Layout(gtx, tr.InstrumentComment(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Comment")
|
||||
return ip.commentEditor.Layout(gtx, tr.Instrument().Comment(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Comment")
|
||||
})
|
||||
default: // odd valued list items are dividers
|
||||
px := max(gtx.Dp(unit.Dp(1)), 1)
|
||||
|
||||
@ -102,93 +102,93 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
|
||||
switch action {
|
||||
// Actions
|
||||
case "AddTrack":
|
||||
t.AddTrack().Do()
|
||||
t.Track().Add().Do()
|
||||
case "DeleteTrack":
|
||||
t.DeleteTrack().Do()
|
||||
t.Track().Delete().Do()
|
||||
case "AddInstrument":
|
||||
t.AddInstrument().Do()
|
||||
t.Instrument().Add().Do()
|
||||
case "DeleteInstrument":
|
||||
t.DeleteInstrument().Do()
|
||||
t.Instrument().Delete().Do()
|
||||
case "AddUnitAfter":
|
||||
t.AddUnit(false).Do()
|
||||
t.Unit().Add(false).Do()
|
||||
case "AddUnitBefore":
|
||||
t.AddUnit(true).Do()
|
||||
t.Unit().Add(true).Do()
|
||||
case "DeleteUnit":
|
||||
t.DeleteUnit().Do()
|
||||
t.Unit().Delete().Do()
|
||||
case "ClearUnit":
|
||||
t.ClearUnit().Do()
|
||||
t.Unit().Clear().Do()
|
||||
case "Undo":
|
||||
t.Undo().Do()
|
||||
t.History().Undo().Do()
|
||||
case "Redo":
|
||||
t.Redo().Do()
|
||||
t.History().Redo().Do()
|
||||
case "AddSemitone":
|
||||
t.AddSemitone().Do()
|
||||
t.Note().AddSemitone().Do()
|
||||
case "SubtractSemitone":
|
||||
t.SubtractSemitone().Do()
|
||||
t.Note().SubtractSemitone().Do()
|
||||
case "AddOctave":
|
||||
t.AddOctave().Do()
|
||||
t.Note().AddOctave().Do()
|
||||
case "SubtractOctave":
|
||||
t.SubtractOctave().Do()
|
||||
t.Note().SubtractOctave().Do()
|
||||
case "EditNoteOff":
|
||||
t.EditNoteOff().Do()
|
||||
t.Note().NoteOff().Do()
|
||||
case "RemoveUnused":
|
||||
t.RemoveUnused().Do()
|
||||
t.Order().RemoveUnusedPatterns().Do()
|
||||
case "PlayCurrentPosFollow":
|
||||
t.Follow().SetValue(true)
|
||||
t.PlayCurrentPos().Do()
|
||||
t.Play().IsFollowing().SetValue(true)
|
||||
t.Play().FromCurrentPos().Do()
|
||||
case "PlayCurrentPosUnfollow":
|
||||
t.Follow().SetValue(false)
|
||||
t.PlayCurrentPos().Do()
|
||||
t.Play().IsFollowing().SetValue(false)
|
||||
t.Play().FromCurrentPos().Do()
|
||||
case "PlaySongStartFollow":
|
||||
t.Follow().SetValue(true)
|
||||
t.PlaySongStart().Do()
|
||||
t.Play().IsFollowing().SetValue(true)
|
||||
t.Play().FromBeginning().Do()
|
||||
case "PlaySongStartUnfollow":
|
||||
t.Follow().SetValue(false)
|
||||
t.PlaySongStart().Do()
|
||||
t.Play().IsFollowing().SetValue(false)
|
||||
t.Play().FromBeginning().Do()
|
||||
case "PlaySelectedFollow":
|
||||
t.Follow().SetValue(true)
|
||||
t.PlaySelected().Do()
|
||||
t.Play().IsFollowing().SetValue(true)
|
||||
t.Play().FromSelected().Do()
|
||||
case "PlaySelectedUnfollow":
|
||||
t.Follow().SetValue(false)
|
||||
t.PlaySelected().Do()
|
||||
t.Play().IsFollowing().SetValue(false)
|
||||
t.Play().FromSelected().Do()
|
||||
case "PlayLoopFollow":
|
||||
t.Follow().SetValue(true)
|
||||
t.PlayFromLoopStart().Do()
|
||||
t.Play().IsFollowing().SetValue(true)
|
||||
t.Play().FromLoopBeginning().Do()
|
||||
case "PlayLoopUnfollow":
|
||||
t.Follow().SetValue(false)
|
||||
t.PlayFromLoopStart().Do()
|
||||
t.Play().IsFollowing().SetValue(false)
|
||||
t.Play().FromLoopBeginning().Do()
|
||||
case "StopPlaying":
|
||||
t.StopPlaying().Do()
|
||||
t.Play().Stop().Do()
|
||||
case "AddOrderRowBefore":
|
||||
t.AddOrderRow(true).Do()
|
||||
t.Order().AddRow(true).Do()
|
||||
case "AddOrderRowAfter":
|
||||
t.AddOrderRow(false).Do()
|
||||
t.Order().AddRow(false).Do()
|
||||
case "DeleteOrderRowBackwards":
|
||||
t.DeleteOrderRow(true).Do()
|
||||
t.Order().DeleteRow(true).Do()
|
||||
case "DeleteOrderRowForwards":
|
||||
t.DeleteOrderRow(false).Do()
|
||||
t.Order().DeleteRow(false).Do()
|
||||
case "NewSong":
|
||||
t.NewSong().Do()
|
||||
t.Song().New().Do()
|
||||
case "OpenSong":
|
||||
t.OpenSong().Do()
|
||||
t.Song().Open().Do()
|
||||
case "Quit":
|
||||
if canQuit {
|
||||
t.RequestQuit().Do()
|
||||
}
|
||||
case "SaveSong":
|
||||
t.SaveSong().Do()
|
||||
t.Song().Save().Do()
|
||||
case "SaveSongAs":
|
||||
t.SaveSongAs().Do()
|
||||
t.Song().SaveAs().Do()
|
||||
case "ExportWav":
|
||||
t.Export().Do()
|
||||
t.Song().Export().Do()
|
||||
case "ExportFloat":
|
||||
t.ExportFloat().Do()
|
||||
t.Song().ExportFloat().Do()
|
||||
case "ExportInt16":
|
||||
t.ExportInt16().Do()
|
||||
t.Song().ExportInt16().Do()
|
||||
case "SplitTrack":
|
||||
t.SplitTrack().Do()
|
||||
t.Track().Split().Do()
|
||||
case "SplitInstrument":
|
||||
t.SplitInstrument().Do()
|
||||
t.Instrument().Split().Do()
|
||||
case "ShowManual":
|
||||
t.ShowManual().Do()
|
||||
case "AskHelp":
|
||||
@ -199,72 +199,72 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
|
||||
t.ShowLicense().Do()
|
||||
// Booleans
|
||||
case "PanicToggle":
|
||||
t.Panic().Toggle()
|
||||
t.Play().Panicked().Toggle()
|
||||
case "RecordingToggle":
|
||||
t.IsRecording().Toggle()
|
||||
t.Play().IsRecording().Toggle()
|
||||
case "PlayingToggleFollow":
|
||||
t.Follow().SetValue(true)
|
||||
t.Playing().Toggle()
|
||||
t.Play().IsFollowing().SetValue(true)
|
||||
t.Play().Started().Toggle()
|
||||
case "PlayingToggleUnfollow":
|
||||
t.Follow().SetValue(false)
|
||||
t.Playing().Toggle()
|
||||
t.Play().IsFollowing().SetValue(false)
|
||||
t.Play().Started().Toggle()
|
||||
case "InstrEnlargedToggle":
|
||||
t.InstrEnlarged().Toggle()
|
||||
t.Play().TrackerHidden().Toggle()
|
||||
case "LinkInstrTrackToggle":
|
||||
t.LinkInstrTrack().Toggle()
|
||||
t.Track().LinkInstrument().Toggle()
|
||||
case "FollowToggle":
|
||||
t.Follow().Toggle()
|
||||
t.Play().IsFollowing().Toggle()
|
||||
case "UnitDisabledToggle":
|
||||
t.UnitDisabled().Toggle()
|
||||
t.Unit().Disabled().Toggle()
|
||||
case "LoopToggle":
|
||||
t.LoopToggle().Toggle()
|
||||
t.Play().IsLooping().Toggle()
|
||||
case "UniquePatternsToggle":
|
||||
t.UniquePatterns().Toggle()
|
||||
t.Note().UniquePatterns().Toggle()
|
||||
case "MuteToggle":
|
||||
t.Mute().Toggle()
|
||||
t.Instrument().Mute().Toggle()
|
||||
case "SoloToggle":
|
||||
t.Solo().Toggle()
|
||||
t.Instrument().Solo().Toggle()
|
||||
// Integers
|
||||
case "InstrumentVoicesAdd":
|
||||
t.Model.InstrumentVoices().Add(1)
|
||||
t.Instrument().Voices().Add(1)
|
||||
case "InstrumentVoicesSubtract":
|
||||
t.Model.InstrumentVoices().Add(-1)
|
||||
t.Instrument().Voices().Add(-1)
|
||||
case "TrackVoicesAdd":
|
||||
t.TrackVoices().Add(1)
|
||||
t.Track().Voices().Add(1)
|
||||
case "TrackVoicesSubtract":
|
||||
t.TrackVoices().Add(-1)
|
||||
t.Track().Voices().Add(-1)
|
||||
case "SongLengthAdd":
|
||||
t.SongLength().Add(1)
|
||||
t.Song().Length().Add(1)
|
||||
case "SongLengthSubtract":
|
||||
t.SongLength().Add(-1)
|
||||
t.Song().Length().Add(-1)
|
||||
case "BPMAdd":
|
||||
t.BPM().Add(1)
|
||||
t.Song().BPM().Add(1)
|
||||
case "BPMSubtract":
|
||||
t.BPM().Add(-1)
|
||||
t.Song().BPM().Add(-1)
|
||||
case "RowsPerPatternAdd":
|
||||
t.RowsPerPattern().Add(1)
|
||||
t.Song().RowsPerPattern().Add(1)
|
||||
case "RowsPerPatternSubtract":
|
||||
t.RowsPerPattern().Add(-1)
|
||||
t.Song().RowsPerPattern().Add(-1)
|
||||
case "RowsPerBeatAdd":
|
||||
t.RowsPerBeat().Add(1)
|
||||
t.Song().RowsPerBeat().Add(1)
|
||||
case "RowsPerBeatSubtract":
|
||||
t.RowsPerBeat().Add(-1)
|
||||
t.Song().RowsPerBeat().Add(-1)
|
||||
case "StepAdd":
|
||||
t.Step().Add(1)
|
||||
t.Note().Step().Add(1)
|
||||
case "StepSubtract":
|
||||
t.Step().Add(-1)
|
||||
t.Note().Step().Add(-1)
|
||||
case "OctaveAdd":
|
||||
t.Octave().Add(1)
|
||||
t.Note().Octave().Add(1)
|
||||
case "OctaveSubtract":
|
||||
t.Octave().Add(-1)
|
||||
t.Note().Octave().Add(-1)
|
||||
// Other miscellaneous
|
||||
case "Paste":
|
||||
gtx.Execute(clipboard.ReadCmd{Tag: t})
|
||||
case "OrderEditorFocus":
|
||||
t.InstrEnlarged().SetValue(false)
|
||||
t.Play().TrackerHidden().SetValue(false)
|
||||
gtx.Execute(key.FocusCmd{Tag: t.OrderEditor.scrollTable})
|
||||
case "TrackEditorFocus":
|
||||
t.InstrEnlarged().SetValue(false)
|
||||
t.Play().TrackerHidden().SetValue(false)
|
||||
gtx.Execute(key.FocusCmd{Tag: t.TrackEditor.scrollTable})
|
||||
case "InstrumentListFocus":
|
||||
gtx.Execute(key.FocusCmd{Tag: t.PatchPanel.instrList.instrumentDragList})
|
||||
@ -289,8 +289,8 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
instr := t.Model.Instruments().Selected()
|
||||
n := noteAsValue(t.Model.Octave().Value(), val-12)
|
||||
instr := t.Model.Instrument().List().Selected()
|
||||
n := noteAsValue(t.Model.Note().Octave().Value(), val-12)
|
||||
t.KeyNoteMap.Press(e.Name, tracker.NoteEvent{Channel: instr, Note: n})
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,9 +92,9 @@ func NewNoteEditor(model *tracker.Model) *NoteEditor {
|
||||
UniqueBtn: new(Clickable),
|
||||
TrackMidiInBtn: new(Clickable),
|
||||
scrollTable: NewScrollTable(
|
||||
model.Notes().Table(),
|
||||
model.Tracks(),
|
||||
model.NoteRows(),
|
||||
model.Note().Table(),
|
||||
model.Track().List(),
|
||||
model.Note().RowList(),
|
||||
),
|
||||
}
|
||||
for k, a := range keyBindingMap {
|
||||
@ -137,10 +137,10 @@ func (te *NoteEditor) Layout(gtx layout.Context) layout.Dimensions {
|
||||
for gtx.Focused(te.scrollTable) && len(t.noteEvents) > 0 {
|
||||
ev := t.noteEvents[0]
|
||||
ev.IsTrack = true
|
||||
ev.Channel = t.Model.Notes().Cursor().X
|
||||
ev.Channel = t.Model.Note().Cursor().X
|
||||
ev.Source = te
|
||||
if ev.On {
|
||||
t.Model.Notes().Input(ev.Note)
|
||||
t.Model.Note().Input(ev.Note)
|
||||
}
|
||||
copy(t.noteEvents, t.noteEvents[1:])
|
||||
t.noteEvents = t.noteEvents[:len(t.noteEvents)-1]
|
||||
@ -163,22 +163,22 @@ func (te *NoteEditor) Layout(gtx layout.Context) layout.Dimensions {
|
||||
|
||||
func (te *NoteEditor) layoutButtons(gtx C, t *Tracker) D {
|
||||
return Surface{Height: 4, Focus: te.scrollTable.TreeFocused(gtx)}.Layout(gtx, func(gtx C) D {
|
||||
addSemitoneBtn := ActionBtn(t.AddSemitone(), t.Theme, te.AddSemitoneBtn, "+1", "Add semitone")
|
||||
subtractSemitoneBtn := ActionBtn(t.SubtractSemitone(), t.Theme, te.SubtractSemitoneBtn, "-1", "Subtract semitone")
|
||||
addOctaveBtn := ActionBtn(t.AddOctave(), t.Theme, te.AddOctaveBtn, "+12", "Add octave")
|
||||
subtractOctaveBtn := ActionBtn(t.SubtractOctave(), t.Theme, te.SubtractOctaveBtn, "-12", "Subtract octave")
|
||||
noteOffBtn := ActionBtn(t.EditNoteOff(), t.Theme, te.NoteOffBtn, "Note Off", "")
|
||||
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")
|
||||
addSemitoneBtn := ActionBtn(t.Note().AddSemitone(), t.Theme, te.AddSemitoneBtn, "+1", "Add semitone")
|
||||
subtractSemitoneBtn := ActionBtn(t.Note().SubtractSemitone(), t.Theme, te.SubtractSemitoneBtn, "-1", "Subtract semitone")
|
||||
addOctaveBtn := ActionBtn(t.Note().AddOctave(), t.Theme, te.AddOctaveBtn, "+12", "Add octave")
|
||||
subtractOctaveBtn := ActionBtn(t.Note().SubtractOctave(), t.Theme, te.SubtractOctaveBtn, "-12", "Subtract octave")
|
||||
noteOffBtn := ActionBtn(t.Note().NoteOff(), t.Theme, te.NoteOffBtn, "Note Off", "")
|
||||
deleteTrackBtn := ActionIconBtn(t.Track().Delete(), t.Theme, te.DeleteTrackBtn, icons.ActionDelete, te.deleteTrackHint)
|
||||
splitTrackBtn := ActionIconBtn(t.Track().Split(), t.Theme, te.SplitTrackBtn, icons.CommunicationCallSplit, te.splitTrackHint)
|
||||
newTrackBtn := ActionIconBtn(t.Track().Add(), t.Theme, te.NewTrackBtn, icons.ContentAdd, te.addTrackHint)
|
||||
trackVoices := NumUpDown(t.Model.Track().Voices(), t.Theme, te.TrackVoices, "Track voices")
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
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)
|
||||
midiInBtn := ToggleBtn(t.TrackMidiIn(), t.Theme, te.TrackMidiInBtn, "MIDI", "Input notes from MIDI keyboard")
|
||||
effectBtn := ToggleBtn(t.Track().Effect(), t.Theme, te.EffectBtn, "Hex", "Input notes as hex values")
|
||||
uniqueBtn := ToggleIconBtn(t.Note().UniquePatterns(), t.Theme, te.UniqueBtn, icons.ToggleStarBorder, icons.ToggleStar, te.uniqueOffTip, te.uniqueOnTip)
|
||||
midiInBtn := ToggleBtn(t.MIDI().InputtingNotes(), t.Theme, te.TrackMidiInBtn, "MIDI", "Input notes from MIDI keyboard")
|
||||
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(addSemitoneBtn.Layout),
|
||||
@ -220,13 +220,13 @@ var notes = []string{
|
||||
func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
|
||||
|
||||
beatMarkerDensity := t.RowsPerBeat().Value()
|
||||
beatMarkerDensity := t.Song().RowsPerBeat().Value()
|
||||
switch beatMarkerDensity {
|
||||
case 0, 1, 2:
|
||||
beatMarkerDensity = 4
|
||||
}
|
||||
|
||||
playSongRow := t.PlaySongRow()
|
||||
playSongRow := t.Play().SongRow()
|
||||
pxWidth := gtx.Dp(trackColWidth)
|
||||
pxHeight := gtx.Dp(trackRowHeight)
|
||||
pxPatMarkWidth := gtx.Dp(trackPatMarkWidth)
|
||||
@ -235,7 +235,7 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
colTitle := func(gtx C, i int) D {
|
||||
h := gtx.Dp(trackColTitleHeight)
|
||||
gtx.Constraints = layout.Exact(image.Pt(pxWidth, h))
|
||||
Label(t.Theme, &t.Theme.NoteEditor.TrackTitle, t.Model.TrackTitle(i)).Layout(gtx)
|
||||
Label(t.Theme, &t.Theme.NoteEditor.TrackTitle, t.Model.Track().Item(i).Title).Layout(gtx)
|
||||
return D{Size: image.Pt(pxWidth, h)}
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
} else if mod(j, beatMarkerDensity) == 0 {
|
||||
paint.FillShape(gtx.Ops, t.Theme.NoteEditor.OneBeat, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, pxHeight)}.Op())
|
||||
}
|
||||
if t.Model.Playing().Value() && j == playSongRow {
|
||||
if t.Model.Play().Started().Value() && j == playSongRow {
|
||||
paint.FillShape(gtx.Ops, t.Theme.NoteEditor.Play, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, pxHeight)}.Op())
|
||||
}
|
||||
return D{}
|
||||
@ -256,14 +256,14 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
patternRowOp := colorOp(gtx, t.Theme.NoteEditor.PatternRow.Color)
|
||||
|
||||
rowTitle := func(gtx C, j int) D {
|
||||
rpp := max(t.RowsPerPattern().Value(), 1)
|
||||
rpp := max(t.Song().RowsPerPattern().Value(), 1)
|
||||
pat := j / rpp
|
||||
row := j % rpp
|
||||
w := pxPatMarkWidth + pxRowMarkWidth
|
||||
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
||||
if row == 0 {
|
||||
op := orderRowOp
|
||||
if l := t.Loop(); pat >= l.Start && pat < l.Start+l.Length {
|
||||
if l := t.Play().Loop(); pat >= l.Start && pat < l.Start+l.Length {
|
||||
op = loopColorOp
|
||||
}
|
||||
widget.Label{}.Layout(gtx, t.Theme.Material.Shaper, t.Theme.NoteEditor.OrderRow.Font, t.Theme.NoteEditor.OrderRow.TextSize, hexStr[pat&255], op)
|
||||
@ -276,7 +276,7 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
cursor := te.scrollTable.Table.Cursor()
|
||||
drawSelection := cursor != te.scrollTable.Table.Cursor2()
|
||||
selection := te.scrollTable.Table.Range()
|
||||
hasTrackMidiIn := t.Model.TrackMidiIn().Value()
|
||||
hasTrackMidiIn := t.MIDI().InputtingNotes().Value()
|
||||
|
||||
patternNoOp := colorOp(gtx, t.Theme.NoteEditor.PatternNo.Color)
|
||||
uniqueOp := colorOp(gtx, t.Theme.NoteEditor.Unique.Color)
|
||||
@ -305,7 +305,7 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
}
|
||||
|
||||
// draw the pattern marker
|
||||
rpp := max(t.RowsPerPattern().Value(), 1)
|
||||
rpp := max(t.Song().RowsPerPattern().Value(), 1)
|
||||
pat := y / rpp
|
||||
row := y % rpp
|
||||
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
||||
@ -313,13 +313,13 @@ func (te *NoteEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
if row == 0 { // draw the pattern marker
|
||||
widget.Label{}.Layout(gtx, t.Theme.Material.Shaper, t.Theme.NoteEditor.PatternNo.Font, t.Theme.NoteEditor.PatternNo.TextSize, patternIndexToString(s), patternNoOp)
|
||||
}
|
||||
if row == 1 && t.Model.PatternUnique(x, s) { // draw a * if the pattern is unique
|
||||
if row == 1 && t.Order().PatternUnique(x, s) { // draw a * if the pattern is unique
|
||||
widget.Label{}.Layout(gtx, t.Theme.Material.Shaper, t.Theme.NoteEditor.Unique.Font, t.Theme.NoteEditor.Unique.TextSize, "*", uniqueOp)
|
||||
}
|
||||
op := noteOp
|
||||
val := noteName[byte(t.Model.Notes().Value(tracker.Point{X: x, Y: y}))]
|
||||
if t.Model.Notes().Effect(x) {
|
||||
val = noteHex[byte(t.Model.Notes().Value(tracker.Point{X: x, Y: y}))]
|
||||
val := noteName[byte(t.Model.Note().At(tracker.Point{X: x, Y: y}))]
|
||||
if t.Model.Track().Item(x).Effect {
|
||||
val = noteHex[byte(t.Model.Note().At(tracker.Point{X: x, Y: y}))]
|
||||
}
|
||||
widget.Label{Alignment: text.Middle}.Layout(gtx, t.Theme.Material.Shaper, t.Theme.NoteEditor.Note.Font, t.Theme.NoteEditor.Note.TextSize, val, op)
|
||||
return D{Size: image.Pt(pxWidth, pxHeight)}
|
||||
@ -347,9 +347,9 @@ func colorOp(gtx C, c color.NRGBA) op.CallOp {
|
||||
func (te *NoteEditor) paintColumnCell(gtx C, x int, t *Tracker, c color.NRGBA) {
|
||||
cw := gtx.Constraints.Min.X
|
||||
cx := 0
|
||||
if t.Model.Notes().Effect(x) {
|
||||
if t.Model.Track().Item(x).Effect {
|
||||
cw /= 2
|
||||
if t.Model.Notes().LowNibble() {
|
||||
if t.Model.Note().LowNibble() {
|
||||
cx += cw
|
||||
}
|
||||
}
|
||||
@ -373,9 +373,9 @@ func noteAsValue(octave, note int) byte {
|
||||
|
||||
func (te *NoteEditor) command(t *Tracker, e key.Event) {
|
||||
var n byte
|
||||
if t.Model.Notes().Effect(te.scrollTable.Table.Cursor().X) {
|
||||
if t.Model.Track().Item(te.scrollTable.Table.Cursor().X).Effect {
|
||||
if nibbleValue, err := strconv.ParseInt(string(e.Name), 16, 8); err == nil {
|
||||
ev := t.Model.Notes().InputNibble(byte(nibbleValue))
|
||||
ev := t.Model.Note().InputNibble(byte(nibbleValue))
|
||||
t.KeyNoteMap.Press(e.Name, ev)
|
||||
}
|
||||
} else {
|
||||
@ -384,7 +384,7 @@ func (te *NoteEditor) command(t *Tracker, e key.Event) {
|
||||
return
|
||||
}
|
||||
if action == "NoteOff" {
|
||||
ev := t.Model.Notes().Input(0)
|
||||
ev := t.Model.Note().Input(0)
|
||||
t.KeyNoteMap.Press(e.Name, ev)
|
||||
return
|
||||
}
|
||||
@ -393,8 +393,8 @@ func (te *NoteEditor) command(t *Tracker, e key.Event) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n = noteAsValue(t.Octave().Value(), val-12)
|
||||
ev := t.Model.Notes().Input(n)
|
||||
n = noteAsValue(t.Note().Octave().Value(), val-12)
|
||||
ev := t.Model.Note().Input(n)
|
||||
t.KeyNoteMap.Press(e.Name, ev)
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,8 +42,8 @@ func NewOrderEditor(m *tracker.Model) *OrderEditor {
|
||||
return &OrderEditor{
|
||||
scrollTable: NewScrollTable(
|
||||
m.Order().Table(),
|
||||
m.Tracks(),
|
||||
m.OrderRows(),
|
||||
m.Track().List(),
|
||||
m.Order().RowList(),
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -67,12 +67,12 @@ func (oe *OrderEditor) Layout(gtx C) D {
|
||||
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
||||
defer op.Affine(f32.Affine2D{}.Rotate(f32.Pt(0, 0), -90*math.Pi/180).Offset(f32.Point{X: 0, Y: float32(h)})).Push(gtx.Ops).Pop()
|
||||
gtx.Constraints = layout.Exact(image.Pt(1e6, 1e6))
|
||||
Label(t.Theme, &t.Theme.OrderEditor.TrackTitle, t.Model.TrackTitle(i)).Layout(gtx)
|
||||
Label(t.Theme, &t.Theme.OrderEditor.TrackTitle, t.Model.Track().Item(i).Title).Layout(gtx)
|
||||
return D{Size: image.Pt(gtx.Dp(patternCellWidth), h)}
|
||||
}
|
||||
|
||||
rowTitleBg := func(gtx C, j int) D {
|
||||
if t.Model.Playing().Value() && j == t.PlayPosition().OrderRow {
|
||||
if t.Model.Play().Started().Value() && j == t.Play().Position().OrderRow {
|
||||
paint.FillShape(gtx.Ops, t.Theme.OrderEditor.Play, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, gtx.Dp(patternCellHeight))}.Op())
|
||||
}
|
||||
return D{}
|
||||
@ -84,7 +84,7 @@ func (oe *OrderEditor) Layout(gtx C) D {
|
||||
rowTitle := func(gtx C, j int) D {
|
||||
w := gtx.Dp(unit.Dp(30))
|
||||
callOp := rowMarkerPatternTextColorOp
|
||||
if l := t.Loop(); j >= l.Start && j < l.Start+l.Length {
|
||||
if l := t.Play().Loop(); j >= l.Start && j < l.Start+l.Length {
|
||||
callOp = loopMarkerColorOp
|
||||
}
|
||||
defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
||||
@ -184,14 +184,14 @@ func (oe *OrderEditor) command(t *Tracker, e key.Event) {
|
||||
switch e.Name {
|
||||
case key.NameDeleteBackward:
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.Model.DeleteOrderRow(true).Do()
|
||||
t.Model.Order().DeleteRow(true).Do()
|
||||
}
|
||||
case key.NameDeleteForward:
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.Model.DeleteOrderRow(false).Do()
|
||||
t.Model.Order().DeleteRow(false).Do()
|
||||
}
|
||||
case key.NameReturn:
|
||||
t.Model.AddOrderRow(e.Modifiers.Contain(key.ModShortcut)).Do()
|
||||
t.Model.Order().AddRow(e.Modifiers.Contain(key.ModShortcut)).Do()
|
||||
}
|
||||
if iv, err := strconv.Atoi(string(e.Name)); err == nil {
|
||||
t.Model.Order().SetValue(oe.scrollTable.Table.Cursor(), iv)
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
|
||||
"gioui.org/layout"
|
||||
"gioui.org/unit"
|
||||
"github.com/vsariola/sointu/tracker"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -20,12 +19,11 @@ type (
|
||||
|
||||
Oscilloscope struct {
|
||||
Theme *Theme
|
||||
Model *tracker.ScopeModel
|
||||
State *OscilloscopeState
|
||||
}
|
||||
)
|
||||
|
||||
func NewOscilloscope(model *tracker.Model) *OscilloscopeState {
|
||||
func NewOscilloscope() *OscilloscopeState {
|
||||
return &OscilloscopeState{
|
||||
plot: NewPlot(plotRange{0, 1}, plotRange{-1, 1}, 0),
|
||||
onceBtn: new(Clickable),
|
||||
@ -35,10 +33,9 @@ func NewOscilloscope(model *tracker.Model) *OscilloscopeState {
|
||||
}
|
||||
}
|
||||
|
||||
func Scope(th *Theme, m *tracker.ScopeModel, st *OscilloscopeState) Oscilloscope {
|
||||
func Scope(th *Theme, st *OscilloscopeState) Oscilloscope {
|
||||
return Oscilloscope{
|
||||
Theme: th,
|
||||
Model: m,
|
||||
State: st,
|
||||
}
|
||||
}
|
||||
@ -48,15 +45,15 @@ func (s *Oscilloscope) Layout(gtx C) D {
|
||||
leftSpacer := layout.Spacer{Width: unit.Dp(6), Height: unit.Dp(24)}.Layout
|
||||
rightSpacer := layout.Spacer{Width: unit.Dp(6)}.Layout
|
||||
|
||||
triggerChannel := NumUpDown(s.Model.TriggerChannel(), s.Theme, s.State.triggerChannelNumber, "Trigger channel")
|
||||
lengthInBeats := NumUpDown(s.Model.LengthInBeats(), s.Theme, s.State.lengthInBeatsNumber, "Buffer length in beats")
|
||||
triggerChannel := NumUpDown(t.Scope().TriggerChannel(), s.Theme, s.State.triggerChannelNumber, "Trigger channel")
|
||||
lengthInBeats := NumUpDown(t.Scope().LengthInBeats(), s.Theme, s.State.lengthInBeatsNumber, "Buffer length in beats")
|
||||
|
||||
onceBtn := ToggleBtn(s.Model.Once(), s.Theme, s.State.onceBtn, "Once", "Trigger once on next event")
|
||||
wrapBtn := ToggleBtn(s.Model.Wrap(), s.Theme, s.State.wrapBtn, "Wrap", "Wrap buffer when full")
|
||||
onceBtn := ToggleBtn(t.Scope().Once(), s.Theme, s.State.onceBtn, "Once", "Trigger once on next event")
|
||||
wrapBtn := ToggleBtn(t.Scope().Wrap(), s.Theme, s.State.wrapBtn, "Wrap", "Wrap buffer when full")
|
||||
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
w := s.Model.Waveform()
|
||||
w := t.Scope().Waveform()
|
||||
cx := float32(w.Cursor) / float32(len(w.Buffer))
|
||||
|
||||
data := func(chn int, xr plotRange) (yr plotRange, ok bool) {
|
||||
@ -65,9 +62,10 @@ func (s *Oscilloscope) Layout(gtx C) D {
|
||||
if x1 > x2 {
|
||||
return plotRange{}, false
|
||||
}
|
||||
step := max((x2-x1)/1000, 1) // if the range is too large, sample only ~ 1000 points
|
||||
y1 := float32(math.Inf(-1))
|
||||
y2 := float32(math.Inf(+1))
|
||||
for i := x1; i <= x2; i++ {
|
||||
for i := x1; i <= x2; i += step {
|
||||
sample := w.Buffer[i][chn]
|
||||
y1 = max(y1, sample)
|
||||
y2 = min(y2, sample)
|
||||
@ -75,9 +73,9 @@ func (s *Oscilloscope) Layout(gtx C) D {
|
||||
return plotRange{-y1, -y2}, true
|
||||
}
|
||||
|
||||
rpb := max(t.Model.RowsPerBeat().Value(), 1)
|
||||
rpb := max(t.Song().RowsPerBeat().Value(), 1)
|
||||
xticks := func(r plotRange, count int, yield func(pos float32, label string)) {
|
||||
l := s.Model.LengthInBeats().Value() * rpb
|
||||
l := t.Scope().LengthInBeats().Value() * rpb
|
||||
a := max(int(math.Ceil(float64(r.a*float32(l)))), 0)
|
||||
b := min(int(math.Floor(float64(r.b*float32(l)))), l)
|
||||
step := 1
|
||||
|
||||
@ -128,9 +128,9 @@ func (p ParamWidget) Layout(gtx C) D {
|
||||
title := Label(p.Theme, &p.Theme.UnitEditor.Name, p.Parameter.Name())
|
||||
t := TrackerFromContext(gtx)
|
||||
widget := func(gtx C) D {
|
||||
if port, ok := p.Parameter.Port(); t.IsChoosingSendTarget() && ok {
|
||||
if port, ok := p.Parameter.Port(); t.Params().IsChoosingSendTarget() && ok {
|
||||
for p.State.clickable.Clicked(gtx) {
|
||||
t.ChooseSendTarget(p.Parameter.UnitID(), port).Do()
|
||||
t.Params().ChooseSendTarget(p.Parameter.UnitID(), port).Do()
|
||||
}
|
||||
k := Port(p.Theme, p.State)
|
||||
return k.Layout(gtx)
|
||||
@ -144,7 +144,7 @@ func (p ParamWidget) Layout(gtx C) D {
|
||||
return s.Layout(gtx)
|
||||
case tracker.IDParameter:
|
||||
for p.State.clickable.Clicked(gtx) {
|
||||
t.ChooseSendSource(p.Parameter.UnitID()).Do()
|
||||
t.Params().ChooseSendSource(p.Parameter.UnitID()).Do()
|
||||
}
|
||||
btn := Btn(t.Theme, &t.Theme.Button.Text, &p.State.clickable, "Set", p.Parameter.Hint().Label)
|
||||
if p.Disabled {
|
||||
|
||||
@ -75,9 +75,9 @@ func (pp *PatchPanel) Layout(gtx C) D {
|
||||
tr := TrackerFromContext(gtx)
|
||||
bottom := func(gtx C) D {
|
||||
switch {
|
||||
case tr.InstrComment().Value():
|
||||
case tr.Instrument().Tab().Value() == int(tracker.InstrumentCommentTab):
|
||||
return pp.instrProps.layout(gtx)
|
||||
case tr.InstrPresets().Value():
|
||||
case tr.Instrument().Tab().Value() == int(tracker.InstrumentPresetsTab):
|
||||
return pp.instrPresets.layout(gtx)
|
||||
default: // editor
|
||||
return pp.instrEditor.layout(gtx)
|
||||
@ -92,9 +92,9 @@ func (pp *PatchPanel) Layout(gtx C) D {
|
||||
|
||||
func (pp *PatchPanel) BottomTags(level int, yield TagYieldFunc) bool {
|
||||
switch {
|
||||
case pp.InstrComment().Value():
|
||||
case pp.Instrument().Tab().Value() == int(tracker.InstrumentCommentTab):
|
||||
return pp.instrProps.Tags(level, yield)
|
||||
case pp.InstrPresets().Value():
|
||||
case pp.Instrument().Tab().Value() == int(tracker.InstrumentPresetsTab):
|
||||
return pp.instrPresets.Tags(level, yield)
|
||||
default: // editor
|
||||
return pp.instrEditor.Tags(level, yield)
|
||||
@ -143,18 +143,18 @@ func MakeInstrumentTools(m *tracker.Model) InstrumentTools {
|
||||
func (it *InstrumentTools) Layout(gtx C) D {
|
||||
t := TrackerFromContext(gtx)
|
||||
it.update(gtx, t)
|
||||
editorBtn := TabBtn(t.Model.InstrEditor(), t.Theme, it.EditorTab, "Editor", "")
|
||||
presetsBtn := TabBtn(t.Model.InstrPresets(), t.Theme, it.PresetsTab, "Presets", "")
|
||||
commentBtn := TabBtn(t.Model.InstrComment(), t.Theme, it.CommentTab, "Properties", "")
|
||||
octave := NumUpDown(t.Model.Octave(), t.Theme, t.OctaveNumberInput, "Octave")
|
||||
linkInstrTrackBtn := ToggleIconBtn(t.Model.LinkInstrTrack(), t.Theme, it.linkInstrTrackBtn, icons.NotificationSyncDisabled, icons.NotificationSync, it.linkDisabledHint, it.linkEnabledHint)
|
||||
instrEnlargedBtn := ToggleIconBtn(t.Model.InstrEnlarged(), t.Theme, it.enlargeBtn, icons.NavigationFullscreen, icons.NavigationFullscreenExit, it.enlargeHint, it.shrinkHint)
|
||||
addInstrumentBtn := ActionIconBtn(t.Model.AddInstrument(), t.Theme, it.newInstrumentBtn, icons.ContentAdd, it.addInstrumentHint)
|
||||
editorBtn := TabBtn(tracker.MakeBool((*editorTab)(t.Model)), t.Theme, it.EditorTab, "Editor", "")
|
||||
presetsBtn := TabBtn(tracker.MakeBool((*presetsTab)(t.Model)), t.Theme, it.PresetsTab, "Presets", "")
|
||||
commentBtn := TabBtn(tracker.MakeBool((*commentTab)(t.Model)), t.Theme, it.CommentTab, "Properties", "")
|
||||
octave := NumUpDown(t.Note().Octave(), t.Theme, t.OctaveNumberInput, "Octave")
|
||||
linkInstrTrackBtn := ToggleIconBtn(t.Track().LinkInstrument(), t.Theme, it.linkInstrTrackBtn, icons.NotificationSyncDisabled, icons.NotificationSync, it.linkDisabledHint, it.linkEnabledHint)
|
||||
instrEnlargedBtn := ToggleIconBtn(t.Play().TrackerHidden(), t.Theme, it.enlargeBtn, icons.NavigationFullscreen, icons.NavigationFullscreenExit, it.enlargeHint, it.shrinkHint)
|
||||
addInstrumentBtn := ActionIconBtn(t.Model.Instrument().Add(), t.Theme, it.newInstrumentBtn, icons.ContentAdd, it.addInstrumentHint)
|
||||
|
||||
saveInstrumentBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, it.saveInstrumentBtn, icons.ContentSave, "Save instrument")
|
||||
loadInstrumentBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, it.loadInstrumentBtn, icons.FileFolderOpen, "Load instrument")
|
||||
copyInstrumentBtn := IconBtn(t.Theme, &t.Theme.IconButton.Enabled, it.copyInstrumentBtn, icons.ContentContentCopy, "Copy instrument")
|
||||
deleteInstrumentBtn := ActionIconBtn(t.DeleteInstrument(), t.Theme, it.deleteInstrumentBtn, icons.ActionDelete, it.deleteInstrumentHint)
|
||||
deleteInstrumentBtn := ActionIconBtn(t.Instrument().Delete(), t.Theme, it.deleteInstrumentBtn, icons.ActionDelete, it.deleteInstrumentHint)
|
||||
btns := func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(layout.Spacer{Width: 6}.Layout),
|
||||
@ -177,26 +177,58 @@ func (it *InstrumentTools) Layout(gtx C) D {
|
||||
return Surface{Height: 4, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, btns)
|
||||
}
|
||||
|
||||
type (
|
||||
editorTab tracker.Model
|
||||
presetsTab tracker.Model
|
||||
commentTab tracker.Model
|
||||
)
|
||||
|
||||
func (e *editorTab) Value() bool {
|
||||
return (*tracker.Model)(e).Instrument().Tab().Value() == int(tracker.InstrumentEditorTab)
|
||||
}
|
||||
func (e *editorTab) SetValue(val bool) {
|
||||
if val {
|
||||
(*tracker.Model)(e).Instrument().Tab().SetValue(int(tracker.InstrumentEditorTab))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *presetsTab) Value() bool {
|
||||
return (*tracker.Model)(p).Instrument().Tab().Value() == int(tracker.InstrumentPresetsTab)
|
||||
}
|
||||
func (p *presetsTab) SetValue(val bool) {
|
||||
if val {
|
||||
(*tracker.Model)(p).Instrument().Tab().SetValue(int(tracker.InstrumentPresetsTab))
|
||||
}
|
||||
}
|
||||
func (c *commentTab) Value() bool {
|
||||
return (*tracker.Model)(c).Instrument().Tab().Value() == int(tracker.InstrumentCommentTab)
|
||||
}
|
||||
func (c *commentTab) SetValue(val bool) {
|
||||
if val {
|
||||
(*tracker.Model)(c).Instrument().Tab().SetValue(int(tracker.InstrumentCommentTab))
|
||||
}
|
||||
}
|
||||
|
||||
func (it *InstrumentTools) update(gtx C, tr *Tracker) {
|
||||
for it.copyInstrumentBtn.Clicked(gtx) {
|
||||
if contents, ok := tr.Instruments().CopyElements(); ok {
|
||||
if contents, ok := tr.Instrument().List().CopyElements(); ok {
|
||||
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
||||
tr.Alerts().Add("Instrument copied to clipboard", tracker.Info)
|
||||
}
|
||||
}
|
||||
for it.saveInstrumentBtn.Clicked(gtx) {
|
||||
writer, err := tr.Explorer.CreateFile(tr.InstrumentName().Value() + ".yml")
|
||||
writer, err := tr.Explorer.CreateFile(tr.Instrument().Name().Value() + ".yml")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tr.SaveInstrument(writer)
|
||||
tr.Instrument().Write(writer)
|
||||
}
|
||||
for it.loadInstrumentBtn.Clicked(gtx) {
|
||||
reader, err := tr.Explorer.ChooseFile(".yml", ".json", ".4ki", ".4kp")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tr.LoadInstrument(reader)
|
||||
tr.Instrument().Read(reader)
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +240,7 @@ func (it *InstrumentTools) Tags(level int, yield TagYieldFunc) bool {
|
||||
|
||||
func MakeInstrList(model *tracker.Model) InstrumentList {
|
||||
return InstrumentList{
|
||||
instrumentDragList: NewDragList(model.Instruments(), layout.Horizontal),
|
||||
instrumentDragList: NewDragList(model.Instrument().List(), layout.Horizontal),
|
||||
nameEditor: NewEditor(true, true, text.Middle),
|
||||
}
|
||||
}
|
||||
@ -221,7 +253,7 @@ func (il *InstrumentList) Layout(gtx C) D {
|
||||
element := func(gtx C, i int) D {
|
||||
grabhandle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, strconv.Itoa(i+1))
|
||||
label := func(gtx C) D {
|
||||
name, level, mute, ok := t.Instrument(i)
|
||||
name, level, mute, ok := t.Instrument().Item(i)
|
||||
if !ok {
|
||||
labelStyle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, "")
|
||||
return layout.Center.Layout(gtx, labelStyle.Layout)
|
||||
@ -233,12 +265,12 @@ func (il *InstrumentList) Layout(gtx C) D {
|
||||
s.Color = color.NRGBA{R: 255, G: k, B: 255, A: 255}
|
||||
}
|
||||
if i == il.instrumentDragList.TrackerList.Selected() {
|
||||
for il.nameEditor.Update(gtx, t.InstrumentName()) != EditorEventNone {
|
||||
for il.nameEditor.Update(gtx, t.Instrument().Name()) != EditorEventNone {
|
||||
il.instrumentDragList.Focus()
|
||||
}
|
||||
return layout.Center.Layout(gtx, func(gtx C) D {
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
return il.nameEditor.Layout(gtx, t.InstrumentName(), t.Theme, &s, "Instr")
|
||||
return il.nameEditor.Layout(gtx, t.Instrument().Name(), t.Theme, &s, "Instr")
|
||||
})
|
||||
}
|
||||
if name == "" {
|
||||
@ -280,9 +312,9 @@ func (il *InstrumentList) update(gtx C, t *Tracker) {
|
||||
case key.NameDownArrow:
|
||||
var tagged Tagged
|
||||
switch {
|
||||
case t.InstrComment().Value():
|
||||
case t.Instrument().Tab().Value() == int(tracker.InstrumentCommentTab):
|
||||
tagged = &t.PatchPanel.instrProps
|
||||
case t.InstrPresets().Value():
|
||||
case t.Instrument().Tab().Value() == int(tracker.InstrumentPresetsTab):
|
||||
tagged = &t.PatchPanel.instrPresets
|
||||
default: // editor
|
||||
tagged = &t.PatchPanel.instrEditor
|
||||
|
||||
@ -61,7 +61,7 @@ func NewSongPanel(tr *Tracker) *SongPanel {
|
||||
RowsPerBeat: NewNumericUpDownState(),
|
||||
Step: NewNumericUpDownState(),
|
||||
SongLength: NewNumericUpDownState(),
|
||||
Scope: NewOscilloscope(tr.Model),
|
||||
Scope: NewOscilloscope(),
|
||||
MenuBar: NewMenuBar(tr),
|
||||
PlayBar: NewPlayBar(),
|
||||
|
||||
@ -88,14 +88,14 @@ func NewSongPanel(tr *Tracker) *SongPanel {
|
||||
|
||||
func (s *SongPanel) Update(gtx C, t *Tracker) {
|
||||
for s.WeightingTypeBtn.Clicked(gtx) {
|
||||
t.Model.DetectorWeighting().SetValue((t.DetectorWeighting().Value() + 1) % int(tracker.NumWeightingTypes))
|
||||
t.Model.Detector().Weighting().SetValue((t.Detector().Weighting().Value() + 1) % int(tracker.NumWeightingTypes))
|
||||
}
|
||||
for s.OversamplingBtn.Clicked(gtx) {
|
||||
t.Model.Oversampling().SetValue(!t.Oversampling().Value())
|
||||
t.Model.Detector().Oversampling().SetValue(!t.Detector().Oversampling().Value())
|
||||
}
|
||||
for s.SynthBtn.Clicked(gtx) {
|
||||
r := t.Model.SyntherIndex().Range()
|
||||
t.Model.SyntherIndex().SetValue((t.SyntherIndex().Value()+1)%(r.Max-r.Min+1) + r.Min)
|
||||
r := t.Model.Play().SyntherIndex().Range()
|
||||
t.Model.Play().SyntherIndex().SetValue((t.Play().SyntherIndex().Value()+1)%(r.Max-r.Min+1) + r.Min)
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
paint.FillShape(gtx.Ops, tr.Theme.SongPanel.Bg, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
|
||||
|
||||
var weightingTxt string
|
||||
switch tracker.WeightingType(tr.Model.DetectorWeighting().Value()) {
|
||||
switch tracker.WeightingType(tr.Model.Detector().Weighting().Value()) {
|
||||
case tracker.KWeighting:
|
||||
weightingTxt = "K-weight (LUFS)"
|
||||
case tracker.AWeighting:
|
||||
@ -128,14 +128,14 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
weightingBtn := Btn(tr.Theme, &tr.Theme.Button.Text, t.WeightingTypeBtn, weightingTxt, "")
|
||||
|
||||
oversamplingTxt := "Sample peak"
|
||||
if tr.Model.Oversampling().Value() {
|
||||
if tr.Model.Detector().Oversampling().Value() {
|
||||
oversamplingTxt = "True peak"
|
||||
}
|
||||
oversamplingBtn := Btn(tr.Theme, &tr.Theme.Button.Text, t.OversamplingBtn, oversamplingTxt, "")
|
||||
|
||||
cpuSmallLabel := func(gtx C) D {
|
||||
var a [vm.MAX_THREADS]sointu.CPULoad
|
||||
c := tr.Model.CPULoad(a[:])
|
||||
c := tr.Play().CPULoad(a[:])
|
||||
if c < 1 {
|
||||
return D{}
|
||||
}
|
||||
@ -150,7 +150,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
cpuEnlargedWidget := func(gtx C) D {
|
||||
var sb strings.Builder
|
||||
var a [vm.MAX_THREADS]sointu.CPULoad
|
||||
c := tr.Model.CPULoad(a[:])
|
||||
c := tr.Play().CPULoad(a[:])
|
||||
high := false
|
||||
for i := range c {
|
||||
if i > 0 {
|
||||
@ -169,35 +169,35 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
return cpuLabel.Layout(gtx)
|
||||
}
|
||||
|
||||
synthBtn := Btn(tr.Theme, &tr.Theme.Button.Text, t.SynthBtn, tr.Model.SyntherName(), "")
|
||||
synthBtn := Btn(tr.Theme, &tr.Theme.Button.Text, t.SynthBtn, tr.Model.Play().SyntherName(), "")
|
||||
|
||||
listItem := func(gtx C, index int) D {
|
||||
switch index {
|
||||
case 0:
|
||||
return t.SongSettingsExpander.Layout(gtx, tr.Theme, "Song",
|
||||
func(gtx C) D {
|
||||
return Label(tr.Theme, &tr.Theme.SongPanel.RowHeader, strconv.Itoa(tr.BPM().Value())+" BPM").Layout(gtx)
|
||||
return Label(tr.Theme, &tr.Theme.SongPanel.RowHeader, strconv.Itoa(tr.Song().BPM().Value())+" BPM").Layout(gtx)
|
||||
},
|
||||
func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
bpm := NumUpDown(tr.BPM(), tr.Theme, t.BPM, "BPM")
|
||||
bpm := NumUpDown(tr.Song().BPM(), tr.Theme, t.BPM, "BPM")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "BPM", bpm.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
songLength := NumUpDown(tr.SongLength(), tr.Theme, t.SongLength, "Song length")
|
||||
songLength := NumUpDown(tr.Song().Length(), tr.Theme, t.SongLength, "Song length")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Song length", songLength.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
rowsPerPattern := NumUpDown(tr.RowsPerPattern(), tr.Theme, t.RowsPerPattern, "Rows per pattern")
|
||||
rowsPerPattern := NumUpDown(tr.Song().RowsPerPattern(), tr.Theme, t.RowsPerPattern, "Rows per pattern")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per pat", rowsPerPattern.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
rowsPerBeat := NumUpDown(tr.RowsPerBeat(), tr.Theme, t.RowsPerBeat, "Rows per beat")
|
||||
rowsPerBeat := NumUpDown(tr.Song().RowsPerBeat(), tr.Theme, t.RowsPerBeat, "Rows per beat")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Rows per beat", rowsPerBeat.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
step := NumUpDown(tr.Step(), tr.Theme, t.Step, "Cursor step")
|
||||
step := NumUpDown(tr.Note().Step(), tr.Theme, t.Step, "Cursor step")
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Cursor step", step.Layout)
|
||||
}),
|
||||
)
|
||||
@ -214,25 +214,25 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
case 2:
|
||||
return t.LoudnessExpander.Layout(gtx, tr.Theme, "Loudness",
|
||||
func(gtx C) D {
|
||||
loudness := tr.Model.DetectorResult().Loudness[tracker.LoudnessShortTerm]
|
||||
loudness := tr.Model.Detector().Result().Loudness[tracker.LoudnessShortTerm]
|
||||
return dbLabel(tr.Theme, loudness).Layout(gtx)
|
||||
},
|
||||
func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical, Alignment: layout.End}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Momentary", dbLabel(tr.Theme, tr.Model.DetectorResult().Loudness[tracker.LoudnessMomentary]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Momentary", dbLabel(tr.Theme, tr.Model.Detector().Result().Loudness[tracker.LoudnessMomentary]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term", dbLabel(tr.Theme, tr.Model.DetectorResult().Loudness[tracker.LoudnessShortTerm]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term", dbLabel(tr.Theme, tr.Model.Detector().Result().Loudness[tracker.LoudnessShortTerm]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated", dbLabel(tr.Theme, tr.Model.DetectorResult().Loudness[tracker.LoudnessIntegrated]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated", dbLabel(tr.Theme, tr.Model.Detector().Result().Loudness[tracker.LoudnessIntegrated]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Max. momentary", dbLabel(tr.Theme, tr.Model.DetectorResult().Loudness[tracker.LoudnessMaxMomentary]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Max. momentary", dbLabel(tr.Theme, tr.Model.Detector().Result().Loudness[tracker.LoudnessMaxMomentary]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Max. short term", dbLabel(tr.Theme, tr.Model.DetectorResult().Loudness[tracker.LoudnessMaxShortTerm]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Max. short term", dbLabel(tr.Theme, tr.Model.Detector().Result().Loudness[tracker.LoudnessMaxShortTerm]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints.Min.X = 0
|
||||
@ -244,23 +244,23 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
case 3:
|
||||
return t.PeakExpander.Layout(gtx, tr.Theme, "Peaks",
|
||||
func(gtx C) D {
|
||||
maxPeak := max(tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][0], tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][1])
|
||||
maxPeak := max(tr.Model.Detector().Result().Peaks[tracker.PeakShortTerm][0], tr.Model.Detector().Result().Peaks[tracker.PeakShortTerm][1])
|
||||
return dbLabel(tr.Theme, maxPeak).Layout(gtx)
|
||||
},
|
||||
func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical, Alignment: layout.End}.Layout(gtx,
|
||||
// no need to show momentary peak, it does not have too much meaning
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term L", dbLabel(tr.Theme, tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][0]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term L", dbLabel(tr.Theme, tr.Model.Detector().Result().Peaks[tracker.PeakShortTerm][0]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term R", dbLabel(tr.Theme, tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][1]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Short term R", dbLabel(tr.Theme, tr.Model.Detector().Result().Peaks[tracker.PeakShortTerm][1]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated L", dbLabel(tr.Theme, tr.Model.DetectorResult().Peaks[tracker.PeakIntegrated][0]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated L", dbLabel(tr.Theme, tr.Model.Detector().Result().Peaks[tracker.PeakIntegrated][0]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated R", dbLabel(tr.Theme, tr.Model.DetectorResult().Peaks[tracker.PeakIntegrated][1]).Layout)
|
||||
return layoutSongOptionRow(gtx, tr.Theme, "Integrated R", dbLabel(tr.Theme, tr.Model.Detector().Result().Peaks[tracker.PeakIntegrated][1]).Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints.Min.X = 0
|
||||
@ -270,7 +270,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
},
|
||||
)
|
||||
case 4:
|
||||
scope := Scope(tr.Theme, tr.Model.SignalAnalyzer(), t.Scope)
|
||||
scope := Scope(tr.Theme, t.Scope)
|
||||
scopeScaleBar := func(gtx C) D {
|
||||
return t.ScopeScaleBar.Layout(gtx, scope.Layout)
|
||||
}
|
||||
@ -289,7 +289,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
gtx.Constraints.Min = gtx.Constraints.Max
|
||||
dims := t.List.Layout(gtx, 7, listItem)
|
||||
t.ScrollBar.Layout(gtx, &tr.Theme.SongPanel.ScrollBar, 7, &t.List.Position)
|
||||
tr.SpecAnEnabled().SetValue(t.SpectrumExpander.Expanded)
|
||||
tr.Spectrum().Enabled().SetValue(t.SpectrumExpander.Expanded)
|
||||
return dims
|
||||
}
|
||||
|
||||
@ -478,9 +478,9 @@ func NewMenuBar(tr *Tracker) *MenuBar {
|
||||
PanicBtn: new(Clickable),
|
||||
panicHint: makeHint("Panic", " (%s)", "PanicToggle"),
|
||||
}
|
||||
for input := range tr.MIDI.InputDevices {
|
||||
for input := range tr.MIDI().InputDevices {
|
||||
ret.midiMenuItems = append(ret.midiMenuItems,
|
||||
MenuItem(tr.SelectMidiInput(input), input, "", icons.ImageControlPoint),
|
||||
MenuItem(tr.MIDI().Open(input), input, "", icons.ImageControlPoint),
|
||||
)
|
||||
}
|
||||
return ret
|
||||
@ -495,11 +495,11 @@ func (t *MenuBar) Layout(gtx C) D {
|
||||
fileBtn := MenuBtn(tr.Theme, &t.MenuStates[0], &t.Clickables[0], "File")
|
||||
fileFC := layout.Rigid(func(gtx C) D {
|
||||
items := [...]ActionMenuItem{
|
||||
MenuItem(tr.NewSong(), "New Song", keyActionMap["NewSong"], icons.ContentClear),
|
||||
MenuItem(tr.OpenSong(), "Open Song", keyActionMap["OpenSong"], icons.FileFolder),
|
||||
MenuItem(tr.SaveSong(), "Save Song", keyActionMap["SaveSong"], icons.ContentSave),
|
||||
MenuItem(tr.SaveSongAs(), "Save Song As...", keyActionMap["SaveSongAs"], icons.ContentSave),
|
||||
MenuItem(tr.Export(), "Export Wav...", keyActionMap["ExportWav"], icons.ImageAudiotrack),
|
||||
MenuItem(tr.Song().New(), "New Song", keyActionMap["NewSong"], icons.ContentClear),
|
||||
MenuItem(tr.Song().Open(), "Open Song", keyActionMap["OpenSong"], icons.FileFolder),
|
||||
MenuItem(tr.Song().Save(), "Save Song", keyActionMap["SaveSong"], icons.ContentSave),
|
||||
MenuItem(tr.Song().SaveAs(), "Save Song As...", keyActionMap["SaveSongAs"], icons.ContentSave),
|
||||
MenuItem(tr.Song().Export(), "Export Wav...", keyActionMap["ExportWav"], icons.ImageAudiotrack),
|
||||
MenuItem(tr.RequestQuit(), "Quit", keyActionMap["Quit"], icons.ActionExitToApp),
|
||||
}
|
||||
if !canQuit {
|
||||
@ -510,9 +510,9 @@ func (t *MenuBar) Layout(gtx C) D {
|
||||
editBtn := MenuBtn(tr.Theme, &t.MenuStates[1], &t.Clickables[1], "Edit")
|
||||
editFC := layout.Rigid(func(gtx C) D {
|
||||
return editBtn.Layout(gtx,
|
||||
MenuItem(tr.Undo(), "Undo", keyActionMap["Undo"], icons.ContentUndo),
|
||||
MenuItem(tr.Redo(), "Redo", keyActionMap["Redo"], icons.ContentRedo),
|
||||
MenuItem(tr.RemoveUnused(), "Remove unused data", keyActionMap["RemoveUnused"], icons.ImageCrop),
|
||||
MenuItem(tr.History().Undo(), "Undo", keyActionMap["Undo"], icons.ContentUndo),
|
||||
MenuItem(tr.History().Redo(), "Redo", keyActionMap["Redo"], icons.ContentRedo),
|
||||
MenuItem(tr.Order().RemoveUnusedPatterns(), "Remove unused data", keyActionMap["RemoveUnused"], icons.ImageCrop),
|
||||
)
|
||||
})
|
||||
midiBtn := MenuBtn(tr.Theme, &t.MenuStates[2], &t.Clickables[2], "MIDI")
|
||||
@ -527,8 +527,8 @@ func (t *MenuBar) Layout(gtx C) D {
|
||||
MenuItem(tr.ReportBug(), "Report bug", keyActionMap["ReportBug"], icons.ActionBugReport),
|
||||
MenuItem(tr.ShowLicense(), "License", keyActionMap["ShowLicense"], icons.ActionCopyright))
|
||||
})
|
||||
panicBtn := ToggleIconBtn(tr.Panic(), tr.Theme, t.PanicBtn, icons.AlertErrorOutline, icons.AlertError, t.panicHint, t.panicHint)
|
||||
if tr.Panic().Value() {
|
||||
panicBtn := ToggleIconBtn(tr.Play().Panicked(), tr.Theme, t.PanicBtn, icons.AlertErrorOutline, icons.AlertError, t.panicHint, t.panicHint)
|
||||
if tr.Play().Panicked().Value() {
|
||||
panicBtn.Style = &tr.Theme.IconButton.Error
|
||||
}
|
||||
panicFC := layout.Flexed(1, func(gtx C) D { return layout.E.Layout(gtx, panicBtn.Layout) })
|
||||
@ -574,11 +574,11 @@ func NewPlayBar() *PlayBar {
|
||||
|
||||
func (pb *PlayBar) Layout(gtx C) D {
|
||||
tr := TrackerFromContext(gtx)
|
||||
playBtn := ToggleIconBtn(tr.Playing(), tr.Theme, pb.PlayingBtn, icons.AVPlayArrow, icons.AVStop, pb.playHint, pb.stopHint)
|
||||
rewindBtn := ActionIconBtn(tr.PlaySongStart(), tr.Theme, pb.RewindBtn, icons.AVFastRewind, pb.rewindHint)
|
||||
recordBtn := ToggleIconBtn(tr.IsRecording(), tr.Theme, pb.RecordBtn, icons.AVFiberManualRecord, icons.AVFiberSmartRecord, pb.recordHint, pb.stopRecordHint)
|
||||
followBtn := ToggleIconBtn(tr.Follow(), tr.Theme, pb.FollowBtn, icons.ActionSpeakerNotesOff, icons.ActionSpeakerNotes, pb.followOffHint, pb.followOnHint)
|
||||
loopBtn := ToggleIconBtn(tr.LoopToggle(), tr.Theme, pb.LoopBtn, icons.NavigationArrowForward, icons.AVLoop, pb.loopOffHint, pb.loopOnHint)
|
||||
playBtn := ToggleIconBtn(tr.Play().Started(), tr.Theme, pb.PlayingBtn, icons.AVPlayArrow, icons.AVStop, pb.playHint, pb.stopHint)
|
||||
rewindBtn := ActionIconBtn(tr.Play().FromBeginning(), tr.Theme, pb.RewindBtn, icons.AVFastRewind, pb.rewindHint)
|
||||
recordBtn := ToggleIconBtn(tr.Play().IsRecording(), tr.Theme, pb.RecordBtn, icons.AVFiberManualRecord, icons.AVFiberSmartRecord, pb.recordHint, pb.stopRecordHint)
|
||||
followBtn := ToggleIconBtn(tr.Play().IsFollowing(), tr.Theme, pb.FollowBtn, icons.ActionSpeakerNotesOff, icons.ActionSpeakerNotes, pb.followOffHint, pb.followOnHint)
|
||||
loopBtn := ToggleIconBtn(tr.Play().IsLooping(), tr.Theme, pb.LoopBtn, icons.NavigationArrowForward, icons.AVLoop, pb.loopOffHint, pb.loopOnHint)
|
||||
|
||||
return Surface{Height: 4}.Layout(gtx, func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
|
||||
@ -40,29 +40,29 @@ func (s *SpectrumState) Layout(gtx C) D {
|
||||
rightSpacer := layout.Spacer{Width: unit.Dp(6)}.Layout
|
||||
|
||||
var chnModeTxt string = "???"
|
||||
switch tracker.SpecChnMode(t.Model.SpecAnChannelsInt().Value()) {
|
||||
switch tracker.SpecChnMode(t.Model.Spectrum().Channels().Value()) {
|
||||
case tracker.SpecChnModeSum:
|
||||
chnModeTxt = "Sum"
|
||||
case tracker.SpecChnModeSeparate:
|
||||
chnModeTxt = "Separate"
|
||||
}
|
||||
|
||||
resolution := NumUpDown(t.Model.SpecAnResolution(), t.Theme, s.resolutionNumber, "Resolution")
|
||||
resolution := NumUpDown(t.Model.Spectrum().Resolution(), t.Theme, s.resolutionNumber, "Resolution")
|
||||
chnModeBtn := Btn(t.Theme, &t.Theme.Button.Text, s.chnModeBtn, chnModeTxt, "Channel mode")
|
||||
speed := NumUpDown(t.Model.SpecAnSpeed(), t.Theme, s.speed, "Speed")
|
||||
speed := NumUpDown(t.Model.Spectrum().Speed(), t.Theme, s.speed, "Speed")
|
||||
|
||||
numchns := 0
|
||||
speclen := len(t.Model.Spectrum()[0])
|
||||
speclen := len(t.Model.Spectrum().Result()[0])
|
||||
if speclen > 0 {
|
||||
numchns = 1
|
||||
if len(t.Model.Spectrum()[1]) == speclen {
|
||||
if len(t.Model.Spectrum().Result()[1]) == speclen {
|
||||
numchns = 2
|
||||
}
|
||||
}
|
||||
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
biquad, biquadok := t.Model.BiquadCoeffs()
|
||||
biquad, biquadok := t.Model.Spectrum().BiquadCoeffs()
|
||||
data := func(chn int, xr plotRange) (yr plotRange, ok bool) {
|
||||
if chn == 2 {
|
||||
if xr.a >= 0 {
|
||||
@ -88,16 +88,16 @@ func (s *SpectrumState) Layout(gtx C) D {
|
||||
y2 := float32(math.Inf(+1))
|
||||
switch {
|
||||
case x2 <= x1+1 && x2 < speclen-1: // perform smoothstep interpolation when we are overlapping only a few bins
|
||||
l := t.Model.Spectrum()[chn][x1]
|
||||
r := t.Model.Spectrum()[chn][x1+1]
|
||||
l := t.Model.Spectrum().Result()[chn][x1]
|
||||
r := t.Model.Spectrum().Result()[chn][x1+1]
|
||||
y1 = smoothInterpolate(l, r, float32(f1))
|
||||
l = t.Model.Spectrum()[chn][x2]
|
||||
r = t.Model.Spectrum()[chn][x2+1]
|
||||
l = t.Model.Spectrum().Result()[chn][x2]
|
||||
r = t.Model.Spectrum().Result()[chn][x2+1]
|
||||
y2 = smoothInterpolate(l, r, float32(f2))
|
||||
y1, y2 = max(y1, y2), min(y1, y2)
|
||||
default:
|
||||
for i := x1; i <= x2; i++ {
|
||||
sample := t.Model.Spectrum()[chn][i]
|
||||
sample := t.Model.Spectrum().Result()[chn][i]
|
||||
y1 = max(y1, sample)
|
||||
y2 = min(y2, sample)
|
||||
}
|
||||
@ -210,8 +210,8 @@ func nextPowerOfTwo(v int) int {
|
||||
func (s *SpectrumState) Update(gtx C) {
|
||||
t := TrackerFromContext(gtx)
|
||||
for s.chnModeBtn.Clicked(gtx) {
|
||||
t.Model.SpecAnChannelsInt().SetValue((t.SpecAnChannelsInt().Value() + 1) % int(tracker.NumSpecChnModes))
|
||||
t.Model.Spectrum().Channels().SetValue((t.Model.Spectrum().Channels().Value() + 1) % int(tracker.NumSpecChnModes))
|
||||
}
|
||||
s.resolutionNumber.Update(gtx, t.Model.SpecAnResolution())
|
||||
s.speed.Update(gtx, t.Model.SpecAnSpeed())
|
||||
s.resolutionNumber.Update(gtx, t.Model.Spectrum().Resolution())
|
||||
s.speed.Update(gtx, t.Model.Spectrum().Speed())
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ func NewTracker(model *tracker.Model) *Tracker {
|
||||
|
||||
Model: model,
|
||||
|
||||
filePathString: model.FilePath(),
|
||||
filePathString: model.Song().FilePath(),
|
||||
}
|
||||
t.SongPanel = NewSongPanel(t)
|
||||
t.KeyNoteMap = MakeKeyboard[key.Name](model.Broker())
|
||||
@ -185,12 +185,12 @@ func (t *Tracker) Main() {
|
||||
}
|
||||
acks <- struct{}{}
|
||||
case <-recoveryTicker.C:
|
||||
t.SaveRecovery()
|
||||
t.History().SaveRecovery()
|
||||
}
|
||||
}
|
||||
}
|
||||
recoveryTicker.Stop()
|
||||
t.SaveRecovery()
|
||||
t.History().SaveRecovery()
|
||||
close(t.Broker().FinishedGUI)
|
||||
}
|
||||
|
||||
@ -226,7 +226,7 @@ func (t *Tracker) Layout(gtx layout.Context) {
|
||||
paint.Fill(gtx.Ops, t.Theme.Material.Bg)
|
||||
event.Op(gtx.Ops, t) // area for capturing scroll events
|
||||
|
||||
if t.InstrEnlarged().Value() {
|
||||
if t.Play().TrackerHidden().Value() {
|
||||
t.layoutTop(gtx)
|
||||
} else {
|
||||
t.VerticalSplit.Layout(gtx,
|
||||
@ -263,14 +263,14 @@ func (t *Tracker) Layout(gtx layout.Context) {
|
||||
case key.Event:
|
||||
t.KeyEvent(e, gtx)
|
||||
case transfer.DataEvent:
|
||||
t.ReadSong(e.Open())
|
||||
t.Song().Read(e.Open())
|
||||
}
|
||||
}
|
||||
// if no-one else handled the note events, we handle them here
|
||||
for len(t.noteEvents) > 0 {
|
||||
ev := t.noteEvents[0]
|
||||
ev.IsTrack = false
|
||||
ev.Channel = t.Model.Instruments().Selected()
|
||||
ev.Channel = t.Model.Instrument().List().Selected()
|
||||
ev.Source = t
|
||||
copy(t.noteEvents, t.noteEvents[1:])
|
||||
t.noteEvents = t.noteEvents[:len(t.noteEvents)-1]
|
||||
@ -285,49 +285,49 @@ func (t *Tracker) showDialog(gtx C) {
|
||||
switch t.Dialog() {
|
||||
case tracker.NewSongChanges, tracker.OpenSongChanges, tracker.QuitChanges:
|
||||
dialog := MakeDialog(t.Theme, t.DialogState, "Save changes to song?", "Your changes will be lost if you don't save them.",
|
||||
DialogBtn("Save", t.SaveSong()),
|
||||
DialogBtn("Don't save", t.DiscardSong()),
|
||||
DialogBtn("Cancel", t.Cancel()),
|
||||
DialogBtn("Save", t.Song().Save()),
|
||||
DialogBtn("Don't save", t.Song().Discard()),
|
||||
DialogBtn("Cancel", t.CancelDialog()),
|
||||
)
|
||||
dialog.Layout(gtx)
|
||||
case tracker.Export:
|
||||
dialog := MakeDialog(t.Theme, t.DialogState, "Export format", "Choose the sample format for the exported .wav file.",
|
||||
DialogBtn("Int16", t.ExportInt16()),
|
||||
DialogBtn("Float32", t.ExportFloat()),
|
||||
DialogBtn("Cancel", t.Cancel()),
|
||||
DialogBtn("Int16", t.Song().ExportInt16()),
|
||||
DialogBtn("Float32", t.Song().ExportFloat()),
|
||||
DialogBtn("Cancel", t.CancelDialog()),
|
||||
)
|
||||
dialog.Layout(gtx)
|
||||
case tracker.OpenSongOpenExplorer:
|
||||
t.explorerChooseFile(t.ReadSong, ".yml", ".json")
|
||||
t.explorerChooseFile(t.Song().Read, ".yml", ".json")
|
||||
case tracker.NewSongSaveExplorer, tracker.OpenSongSaveExplorer, tracker.QuitSaveExplorer, tracker.SaveAsExplorer:
|
||||
filename := t.filePathString.Value()
|
||||
if filename == "" {
|
||||
filename = "song.yml"
|
||||
}
|
||||
t.explorerCreateFile(t.WriteSong, filename)
|
||||
t.explorerCreateFile(t.Song().Write, filename)
|
||||
case tracker.ExportFloatExplorer, tracker.ExportInt16Explorer:
|
||||
filename := "song.wav"
|
||||
if p := t.filePathString.Value(); p != "" {
|
||||
filename = p[:len(p)-len(filepath.Ext(p))] + ".wav"
|
||||
}
|
||||
t.explorerCreateFile(func(wc io.WriteCloser) {
|
||||
t.WriteWav(wc, t.Dialog() == tracker.ExportInt16Explorer)
|
||||
t.Song().WriteWav(wc, t.Dialog() == tracker.ExportInt16Explorer)
|
||||
}, filename)
|
||||
case tracker.License:
|
||||
dialog := MakeDialog(t.Theme, t.DialogState, "License", sointu.License,
|
||||
DialogBtn("Close", t.Cancel()),
|
||||
DialogBtn("Close", t.CancelDialog()),
|
||||
)
|
||||
dialog.Layout(gtx)
|
||||
case tracker.DeleteUserPresetDialog:
|
||||
dialog := MakeDialog(t.Theme, t.DialogState, "Delete user preset?", "Are you sure you want to delete the selected user preset?\nThis action cannot be undone.",
|
||||
DialogBtn("Delete", t.DeleteUserPreset()),
|
||||
DialogBtn("Cancel", t.Cancel()),
|
||||
DialogBtn("Delete", t.Preset().ConfirmDelete()),
|
||||
DialogBtn("Cancel", t.CancelDialog()),
|
||||
)
|
||||
dialog.Layout(gtx)
|
||||
case tracker.OverwriteUserPresetDialog:
|
||||
dialog := MakeDialog(t.Theme, t.DialogState, "Overwrite user preset?", "Are you sure you want to overwrite the existing user preset with the same name?",
|
||||
DialogBtn("Save", t.OverwriteUserPreset()),
|
||||
DialogBtn("Cancel", t.Cancel()),
|
||||
DialogBtn("Save", t.Preset().Overwrite()),
|
||||
DialogBtn("Cancel", t.CancelDialog()),
|
||||
)
|
||||
dialog.Layout(gtx)
|
||||
}
|
||||
@ -342,7 +342,7 @@ func (t *Tracker) explorerChooseFile(success func(io.ReadCloser), extensions ...
|
||||
if err == nil {
|
||||
success(file)
|
||||
} else {
|
||||
t.Cancel().Do()
|
||||
t.CancelDialog().Do()
|
||||
if err != explorer.ErrUserDecline {
|
||||
t.Alerts().Add(err.Error(), tracker.Error)
|
||||
}
|
||||
@ -360,7 +360,7 @@ func (t *Tracker) explorerCreateFile(success func(io.WriteCloser), filename stri
|
||||
if err == nil {
|
||||
success(file)
|
||||
} else {
|
||||
t.Cancel().Do()
|
||||
t.CancelDialog().Do()
|
||||
if err != explorer.ErrUserDecline {
|
||||
t.Alerts().Add(err.Error(), tracker.Error)
|
||||
}
|
||||
@ -416,7 +416,7 @@ func (t *Tracker) openUrl(url string) {
|
||||
|
||||
func (t *Tracker) Tags(curLevel int, yield TagYieldFunc) bool {
|
||||
ret := t.PatchPanel.Tags(curLevel+1, yield)
|
||||
if !t.InstrEnlarged().Value() {
|
||||
if !t.Play().TrackerHidden().Value() {
|
||||
ret = ret && t.OrderEditor.Tags(curLevel+1, yield) &&
|
||||
t.TrackEditor.Tags(curLevel+1, yield)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user