mirror of
https://github.com/vsariola/sointu.git
synced 2026-04-10 08:02:59 -04:00
refactor(tracker): make Model methods return List, avoiding .List()
This commit is contained in:
parent
74beb6760c
commit
1693d7ed5e
@ -145,7 +145,7 @@ func (m *AddTrack) Do() {
|
|||||||
|
|
||||||
func (m *Model) DeleteTrack() Action { return MakeAction((*DeleteTrack)(m)) }
|
func (m *Model) DeleteTrack() Action { return MakeAction((*DeleteTrack)(m)) }
|
||||||
func (m *DeleteTrack) Enabled() bool { return len(m.d.Song.Score.Tracks) > 0 }
|
func (m *DeleteTrack) Enabled() bool { return len(m.d.Song.Score.Tracks) > 0 }
|
||||||
func (m *DeleteTrack) Do() { (*Model)(m).Tracks().List().DeleteElements(false) }
|
func (m *DeleteTrack) Do() { (*Model)(m).Tracks().DeleteElements(false) }
|
||||||
|
|
||||||
// AddInstrument
|
// AddInstrument
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ func (m *AddInstrument) Do() {
|
|||||||
|
|
||||||
func (m *Model) DeleteInstrument() Action { return MakeAction((*DeleteInstrument)(m)) }
|
func (m *Model) DeleteInstrument() Action { return MakeAction((*DeleteInstrument)(m)) }
|
||||||
func (m *DeleteInstrument) Enabled() bool { return len((*Model)(m).d.Song.Patch) > 0 }
|
func (m *DeleteInstrument) Enabled() bool { return len((*Model)(m).d.Song.Patch) > 0 }
|
||||||
func (m *DeleteInstrument) Do() { (*Model)(m).Instruments().List().DeleteElements(false) }
|
func (m *DeleteInstrument) Do() { (*Model)(m).Instruments().DeleteElements(false) }
|
||||||
|
|
||||||
// SplitTrack
|
// SplitTrack
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ func (m *DeleteUnit) Enabled() bool {
|
|||||||
}
|
}
|
||||||
func (m *DeleteUnit) Do() {
|
func (m *DeleteUnit) Do() {
|
||||||
defer (*Model)(m).change("DeleteUnitAction", PatchChange, MajorChange)()
|
defer (*Model)(m).change("DeleteUnitAction", PatchChange, MajorChange)()
|
||||||
(*Model)(m).Units().List().DeleteElements(true)
|
(*Model)(m).Units().DeleteElements(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearUnit
|
// ClearUnit
|
||||||
@ -271,7 +271,7 @@ func (m *ClearUnit) Enabled() bool {
|
|||||||
}
|
}
|
||||||
func (m *ClearUnit) Do() {
|
func (m *ClearUnit) Do() {
|
||||||
defer (*Model)(m).change("DeleteUnitAction", PatchChange, MajorChange)()
|
defer (*Model)(m).change("DeleteUnitAction", PatchChange, MajorChange)()
|
||||||
l := ((*Model)(m)).Units().List()
|
l := ((*Model)(m)).Units()
|
||||||
r := l.listRange()
|
r := l.listRange()
|
||||||
for i := r.Start; i < r.End; i++ {
|
for i := r.Start; i < r.End; i++ {
|
||||||
m.d.Song.Patch[m.d.InstrIndex].Units[i] = sointu.Unit{}
|
m.d.Song.Patch[m.d.InstrIndex].Units[i] = sointu.Unit{}
|
||||||
@ -426,7 +426,7 @@ func (m *PlaySelected) Enabled() bool { return !m.instrEnlarged }
|
|||||||
func (m *PlaySelected) Do() {
|
func (m *PlaySelected) Do() {
|
||||||
(*Model)(m).setPanic(false)
|
(*Model)(m).setPanic(false)
|
||||||
m.playing = true
|
m.playing = true
|
||||||
l := (*Model)(m).OrderRows().List()
|
l := (*Model)(m).OrderRows()
|
||||||
r := l.listRange()
|
r := l.listRange()
|
||||||
newLoop := Loop{r.Start, r.End - r.Start}
|
newLoop := Loop{r.Start, r.End - r.Start}
|
||||||
(*Model)(m).setLoop(newLoop)
|
(*Model)(m).setLoop(newLoop)
|
||||||
|
|||||||
@ -272,6 +272,7 @@ func (m *UnitSearching) SetValue(val bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.d.UnitSearchString = m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].Type
|
m.d.UnitSearchString = m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].Type
|
||||||
|
(*Model)(m).updateDerivedUnitSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnitDisabled methods
|
// UnitDisabled methods
|
||||||
@ -290,7 +291,7 @@ func (m *UnitDisabled) SetValue(val bool) {
|
|||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l := ((*Model)(m)).Units().List()
|
l := ((*Model)(m)).Units()
|
||||||
r := l.listRange()
|
r := l.listRange()
|
||||||
defer (*Model)(m).change("UnitDisabledSet", PatchChange, MajorChange)()
|
defer (*Model)(m).change("UnitDisabledSet", PatchChange, MajorChange)()
|
||||||
for i := r.Start; i < r.End; i++ {
|
for i := r.Start; i < r.End; i++ {
|
||||||
@ -315,7 +316,7 @@ func (t *LoopToggle) SetValue(val bool) {
|
|||||||
m := (*Model)(t)
|
m := (*Model)(t)
|
||||||
newLoop := Loop{}
|
newLoop := Loop{}
|
||||||
if val {
|
if val {
|
||||||
l := m.OrderRows().List()
|
l := m.OrderRows()
|
||||||
r := l.listRange()
|
r := l.listRange()
|
||||||
newLoop = Loop{r.Start, r.End - r.Start}
|
newLoop = Loop{r.Start, r.End - r.Start}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ type (
|
|||||||
tracks []derivedTrack
|
tracks []derivedTrack
|
||||||
railError RailError
|
railError RailError
|
||||||
presetSearch derivedPresetSearch
|
presetSearch derivedPresetSearch
|
||||||
|
searchResults []string
|
||||||
}
|
}
|
||||||
|
|
||||||
derivedInstrument struct {
|
derivedInstrument struct {
|
||||||
|
|||||||
@ -128,7 +128,7 @@ func (s FilledDragListStyle) Layout(gtx C, element, bg func(gtx C, i int) D) D {
|
|||||||
gtx.Execute(op.InvalidateCmd{})
|
gtx.Execute(op.InvalidateCmd{})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isMutable := s.dragList.TrackerList.ListData.(tracker.MutableListData)
|
isMutable := s.dragList.TrackerList.Mutable()
|
||||||
|
|
||||||
listElem := func(gtx C, index int) D {
|
listElem := func(gtx C, index int) D {
|
||||||
for len(s.dragList.tags) <= index {
|
for len(s.dragList.tags) <= index {
|
||||||
|
|||||||
@ -53,7 +53,7 @@ type (
|
|||||||
|
|
||||||
func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor {
|
func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor {
|
||||||
ret := &InstrumentEditor{
|
ret := &InstrumentEditor{
|
||||||
dragList: NewDragList(m.Units().List(), layout.Vertical),
|
dragList: NewDragList(m.Units(), layout.Vertical),
|
||||||
addUnitBtn: new(Clickable),
|
addUnitBtn: new(Clickable),
|
||||||
searchEditor: NewEditor(true, true, text.Start),
|
searchEditor: NewEditor(true, true, text.Start),
|
||||||
DeleteUnitBtn: new(Clickable),
|
DeleteUnitBtn: new(Clickable),
|
||||||
@ -62,8 +62,8 @@ func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor {
|
|||||||
CopyUnitBtn: new(Clickable),
|
CopyUnitBtn: new(Clickable),
|
||||||
SelectTypeBtn: new(Clickable),
|
SelectTypeBtn: new(Clickable),
|
||||||
commentEditor: NewEditor(true, true, text.Start),
|
commentEditor: NewEditor(true, true, text.Start),
|
||||||
paramTable: NewScrollTable(m.Params().Table(), m.ParamVertList().List(), m.Units().List()),
|
paramTable: NewScrollTable(m.Params().Table(), m.ParamVertList().List(), m.Units()),
|
||||||
searchList: NewDragList(m.SearchResults().List(), layout.Vertical),
|
searchList: NewDragList(m.SearchResults(), layout.Vertical),
|
||||||
searching: m.UnitSearching(),
|
searching: m.UnitSearching(),
|
||||||
}
|
}
|
||||||
ret.caser = cases.Title(language.English)
|
ret.caser = cases.Title(language.English)
|
||||||
@ -95,7 +95,7 @@ func (ul *InstrumentEditor) layoutList(gtx C) D {
|
|||||||
element := func(gtx C, i int) D {
|
element := func(gtx C, i int) D {
|
||||||
gtx.Constraints.Max.Y = gtx.Dp(20)
|
gtx.Constraints.Max.Y = gtx.Dp(20)
|
||||||
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
|
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
|
||||||
u := t.Units().Item(i)
|
u := t.Unit(i)
|
||||||
editorStyle := t.Theme.InstrumentEditor.UnitList.Name
|
editorStyle := t.Theme.InstrumentEditor.UnitList.Name
|
||||||
signalError := t.RailError()
|
signalError := t.RailError()
|
||||||
switch {
|
switch {
|
||||||
@ -169,7 +169,7 @@ func (ul *InstrumentEditor) update(gtx C) {
|
|||||||
case key.NameRightArrow:
|
case key.NameRightArrow:
|
||||||
t.PatchPanel.instrEditor.paramTable.RowTitleList.Focus()
|
t.PatchPanel.instrEditor.paramTable.RowTitleList.Focus()
|
||||||
case key.NameDeleteBackward:
|
case key.NameDeleteBackward:
|
||||||
t.Units().SetSelectedType("")
|
t.SetSelectedUnitType("")
|
||||||
t.UnitSearching().SetValue(true)
|
t.UnitSearching().SetValue(true)
|
||||||
ul.searchEditor.Focus()
|
ul.searchEditor.Focus()
|
||||||
case key.NameEnter, key.NameReturn:
|
case key.NameEnter, key.NameReturn:
|
||||||
@ -185,12 +185,12 @@ func (ul *InstrumentEditor) update(gtx C) {
|
|||||||
if str.Value() != "" {
|
if str.Value() != "" {
|
||||||
for _, n := range sointu.UnitNames {
|
for _, n := range sointu.UnitNames {
|
||||||
if strings.HasPrefix(n, str.Value()) {
|
if strings.HasPrefix(n, str.Value()) {
|
||||||
t.Units().SetSelectedType(n)
|
t.SetSelectedUnitType(n)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t.Units().SetSelectedType("")
|
t.SetSelectedUnitType("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul.dragList.Focus()
|
ul.dragList.Focus()
|
||||||
@ -202,7 +202,7 @@ func (ul *InstrumentEditor) update(gtx C) {
|
|||||||
ul.searchEditor.Focus()
|
ul.searchEditor.Focus()
|
||||||
}
|
}
|
||||||
for ul.CopyUnitBtn.Clicked(gtx) {
|
for ul.CopyUnitBtn.Clicked(gtx) {
|
||||||
if contents, ok := t.Units().List().CopyElements(); ok {
|
if contents, ok := t.Units().CopyElements(); ok {
|
||||||
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
||||||
t.Alerts().Add("Unit(s) copied to clipboard", tracker.Info)
|
t.Alerts().Add("Unit(s) copied to clipboard", tracker.Info)
|
||||||
}
|
}
|
||||||
@ -288,8 +288,8 @@ func (pe *InstrumentEditor) layoutTable(gtx C) D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pe *InstrumentEditor) ChooseUnitType(t *Tracker) {
|
func (pe *InstrumentEditor) ChooseUnitType(t *Tracker) {
|
||||||
if ut, ok := t.SearchResults().Item(pe.searchList.TrackerList.Selected()); ok {
|
if ut, ok := t.SearchResult(pe.searchList.TrackerList.Selected()); ok {
|
||||||
t.Units().SetSelectedType(ut)
|
t.SetSelectedUnitType(ut)
|
||||||
pe.paramTable.RowTitleList.Focus()
|
pe.paramTable.RowTitleList.Focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,7 +321,7 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
|||||||
if y < 0 || y >= len(pe.Parameters) {
|
if y < 0 || y >= len(pe.Parameters) {
|
||||||
return D{}
|
return D{}
|
||||||
}
|
}
|
||||||
item := t.Units().Item(y)
|
item := t.Unit(y)
|
||||||
sr := Rail(t.Theme, item.Signals)
|
sr := Rail(t.Theme, item.Signals)
|
||||||
label := Label(t.Theme, &t.Theme.UnitEditor.UnitList.Name, item.Type)
|
label := Label(t.Theme, &t.Theme.UnitEditor.UnitList.Name, item.Type)
|
||||||
switch {
|
switch {
|
||||||
@ -360,7 +360,7 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
param := t.Model.Params().Item(point)
|
param := t.Model.Params().Item(point)
|
||||||
paramStyle := Param(param, t.Theme, pe.Parameters[y][x], pe.paramTable.Table.Cursor() == point, t.Units().Item(y).Disabled)
|
paramStyle := Param(param, t.Theme, pe.Parameters[y][x], pe.paramTable.Table.Cursor() == point, t.Unit(y).Disabled)
|
||||||
paramStyle.Layout(gtx)
|
paramStyle.Layout(gtx)
|
||||||
if x == t.Model.Params().RowWidth(y) {
|
if x == t.Model.Params().RowWidth(y) {
|
||||||
if y == cursor.Y {
|
if y == cursor.Y {
|
||||||
@ -373,7 +373,7 @@ func (pe *InstrumentEditor) layoutRack(gtx C) D {
|
|||||||
return pe.commentEditor.Layout(gtx, t.UnitComment(), t.Theme, &t.Theme.InstrumentEditor.UnitComment, "---")
|
return pe.commentEditor.Layout(gtx, t.UnitComment(), t.Theme, &t.Theme.InstrumentEditor.UnitComment, "---")
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
comment := t.Units().Item(y).Comment
|
comment := t.Unit(y).Comment
|
||||||
if comment != "" {
|
if comment != "" {
|
||||||
style := t.Theme.InstrumentEditor.UnitComment.AsLabelStyle()
|
style := t.Theme.InstrumentEditor.UnitComment.AsLabelStyle()
|
||||||
label := Label(t.Theme, &style, comment)
|
label := Label(t.Theme, &style, comment)
|
||||||
@ -530,16 +530,9 @@ func (pe *InstrumentEditor) layoutFooter(gtx C) D {
|
|||||||
|
|
||||||
func (pe *InstrumentEditor) layoutUnitTypeChooser(gtx C) D {
|
func (pe *InstrumentEditor) layoutUnitTypeChooser(gtx C) D {
|
||||||
t := TrackerFromContext(gtx)
|
t := TrackerFromContext(gtx)
|
||||||
var namesArray [256]string
|
|
||||||
names := namesArray[:0]
|
|
||||||
for _, item := range t.Model.SearchResults().Iterate {
|
|
||||||
names = append(names, item)
|
|
||||||
}
|
|
||||||
element := func(gtx C, i int) D {
|
element := func(gtx C, i int) D {
|
||||||
if i < 0 || i >= len(names) {
|
name, _ := t.SearchResult(i)
|
||||||
return D{}
|
w := Label(t.Theme, &t.Theme.UnitEditor.Chooser, name)
|
||||||
}
|
|
||||||
w := Label(t.Theme, &t.Theme.UnitEditor.Chooser, names[i])
|
|
||||||
if i == pe.searchList.TrackerList.Selected() {
|
if i == pe.searchList.TrackerList.Selected() {
|
||||||
return pe.SelectTypeBtn.Layout(gtx, w.Layout)
|
return pe.SelectTypeBtn.Layout(gtx, w.Layout)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -289,7 +289,7 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
instr := t.Model.Instruments().List().Selected()
|
instr := t.Model.Instruments().Selected()
|
||||||
n := noteAsValue(t.Model.Octave().Value(), val-12)
|
n := noteAsValue(t.Model.Octave().Value(), val-12)
|
||||||
t.KeyNoteMap.Press(e.Name, tracker.NoteEvent{Channel: instr, Note: n})
|
t.KeyNoteMap.Press(e.Name, tracker.NoteEvent{Channel: instr, Note: n})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,8 +93,8 @@ func NewNoteEditor(model *tracker.Model) *NoteEditor {
|
|||||||
TrackMidiInBtn: new(Clickable),
|
TrackMidiInBtn: new(Clickable),
|
||||||
scrollTable: NewScrollTable(
|
scrollTable: NewScrollTable(
|
||||||
model.Notes().Table(),
|
model.Notes().Table(),
|
||||||
model.Tracks().List(),
|
model.Tracks(),
|
||||||
model.NoteRows().List(),
|
model.NoteRows(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
for k, a := range keyBindingMap {
|
for k, a := range keyBindingMap {
|
||||||
|
|||||||
@ -42,8 +42,8 @@ func NewOrderEditor(m *tracker.Model) *OrderEditor {
|
|||||||
return &OrderEditor{
|
return &OrderEditor{
|
||||||
scrollTable: NewScrollTable(
|
scrollTable: NewScrollTable(
|
||||||
m.Order().Table(),
|
m.Order().Table(),
|
||||||
m.Tracks().List(),
|
m.Tracks(),
|
||||||
m.OrderRows().List(),
|
m.OrderRows(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -179,7 +179,7 @@ func (it *InstrumentTools) Layout(gtx C) D {
|
|||||||
|
|
||||||
func (it *InstrumentTools) update(gtx C, tr *Tracker) {
|
func (it *InstrumentTools) update(gtx C, tr *Tracker) {
|
||||||
for it.copyInstrumentBtn.Clicked(gtx) {
|
for it.copyInstrumentBtn.Clicked(gtx) {
|
||||||
if contents, ok := tr.Instruments().List().CopyElements(); ok {
|
if contents, ok := tr.Instruments().CopyElements(); ok {
|
||||||
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
gtx.Execute(clipboard.WriteCmd{Type: "application/text", Data: io.NopCloser(bytes.NewReader(contents))})
|
||||||
tr.Alerts().Add("Instrument copied to clipboard", tracker.Info)
|
tr.Alerts().Add("Instrument copied to clipboard", tracker.Info)
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ func (it *InstrumentTools) Tags(level int, yield TagYieldFunc) bool {
|
|||||||
|
|
||||||
func MakeInstrList(model *tracker.Model) InstrumentList {
|
func MakeInstrList(model *tracker.Model) InstrumentList {
|
||||||
return InstrumentList{
|
return InstrumentList{
|
||||||
instrumentDragList: NewDragList(model.Instruments().List(), layout.Horizontal),
|
instrumentDragList: NewDragList(model.Instruments(), layout.Horizontal),
|
||||||
nameEditor: NewEditor(true, true, text.Middle),
|
nameEditor: NewEditor(true, true, text.Middle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@ func (il *InstrumentList) Layout(gtx C) D {
|
|||||||
element := func(gtx C, i int) D {
|
element := func(gtx C, i int) D {
|
||||||
grabhandle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, strconv.Itoa(i+1))
|
grabhandle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, strconv.Itoa(i+1))
|
||||||
label := func(gtx C) D {
|
label := func(gtx C) D {
|
||||||
name, level, mute, ok := (*tracker.Instruments)(t.Model).Item(i)
|
name, level, mute, ok := t.Instrument(i)
|
||||||
if !ok {
|
if !ok {
|
||||||
labelStyle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, "")
|
labelStyle := Label(t.Theme, &t.Theme.InstrumentEditor.InstrumentList.Number, "")
|
||||||
return layout.Center.Layout(gtx, labelStyle.Layout)
|
return layout.Center.Layout(gtx, labelStyle.Layout)
|
||||||
|
|||||||
428
tracker/list.go
428
tracker/list.go
@ -6,7 +6,6 @@ import (
|
|||||||
"iter"
|
"iter"
|
||||||
"math"
|
"math"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/vsariola/sointu"
|
"github.com/vsariola/sointu"
|
||||||
"github.com/vsariola/sointu/vm"
|
"github.com/vsariola/sointu/vm"
|
||||||
@ -15,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
List struct {
|
List struct {
|
||||||
ListData
|
data ListData
|
||||||
}
|
}
|
||||||
|
|
||||||
ListData interface {
|
ListData interface {
|
||||||
@ -27,49 +26,32 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
MutableListData interface {
|
MutableListData interface {
|
||||||
change(kind string, severity ChangeSeverity) func()
|
Change(kind string, severity ChangeSeverity) func()
|
||||||
cancel()
|
Cancel()
|
||||||
move(r Range, delta int) (ok bool)
|
Move(r Range, delta int) (ok bool)
|
||||||
delete(r Range) (ok bool)
|
Delete(r Range) (ok bool)
|
||||||
marshal(r Range) ([]byte, error)
|
Marshal(r Range) ([]byte, error)
|
||||||
unmarshal([]byte) (r Range, err error)
|
Unmarshal([]byte) (r Range, err error)
|
||||||
}
|
|
||||||
|
|
||||||
UnitListItem struct {
|
|
||||||
Type, Comment string
|
|
||||||
Disabled bool
|
|
||||||
Signals Rail
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Range is used to represent a range [Start,End) of integers
|
// Range is used to represent a range [Start,End) of integers
|
||||||
Range struct {
|
Range struct {
|
||||||
Start, End int
|
Start, End int
|
||||||
}
|
}
|
||||||
|
|
||||||
UnitYieldFunc func(index int, item UnitListItem) (ok bool)
|
|
||||||
UnitSearchYieldFunc func(index int, item string) (ok bool)
|
|
||||||
|
|
||||||
Instruments Model // Instruments is a list of instruments, implementing ListData & MutableListData interfaces
|
|
||||||
Units Model // Units is a list of all the units in the selected instrument, implementing ListData & MutableListData interfaces
|
|
||||||
Tracks Model // Tracks is a list of all the tracks, implementing ListData & MutableListData interfaces
|
|
||||||
OrderRows Model // OrderRows is a list of all the order rows, implementing ListData & MutableListData interfaces
|
|
||||||
NoteRows Model // NoteRows is a list of all the note rows, implementing ListData & MutableListData interfaces
|
|
||||||
SearchResults Model // SearchResults is a unmutable list of all the search results, implementing ListData interface
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model methods
|
func MakeList(data ListData) List { return List{data} }
|
||||||
|
|
||||||
func (m *Model) Instruments() *Instruments { return (*Instruments)(m) }
|
func (l List) Selected() int { return max(min(l.data.Selected(), l.data.Count()-1), 0) }
|
||||||
func (m *Model) Units() *Units { return (*Units)(m) }
|
func (l List) Selected2() int { return max(min(l.data.Selected2(), l.data.Count()-1), 0) }
|
||||||
func (m *Model) Tracks() *Tracks { return (*Tracks)(m) }
|
func (l List) SetSelected(value int) { l.data.SetSelected(max(min(value, l.data.Count()-1), 0)) }
|
||||||
func (m *Model) OrderRows() *OrderRows { return (*OrderRows)(m) }
|
func (l List) SetSelected2(value int) { l.data.SetSelected2(max(min(value, l.data.Count()-1), 0)) }
|
||||||
func (m *Model) NoteRows() *NoteRows { return (*NoteRows)(m) }
|
func (l List) Count() int { return l.data.Count() }
|
||||||
func (m *Model) SearchResults() *SearchResults { return (*SearchResults)(m) }
|
|
||||||
|
|
||||||
// MoveElements moves the selected elements in a list by delta. The list must
|
// MoveElements moves the selected elements in a list by delta. The list must
|
||||||
// implement the MutableListData interface.
|
// implement the MutableListData interface.
|
||||||
func (v List) MoveElements(delta int) bool {
|
func (v List) MoveElements(delta int) bool {
|
||||||
s, ok := v.ListData.(MutableListData)
|
s, ok := v.data.(MutableListData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -77,9 +59,9 @@ func (v List) MoveElements(delta int) bool {
|
|||||||
if delta == 0 || r.Start+delta < 0 || r.End+delta > v.Count() {
|
if delta == 0 || r.Start+delta < 0 || r.End+delta > v.Count() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer s.change("MoveElements", MajorChange)()
|
defer s.Change("MoveElements", MajorChange)()
|
||||||
if !s.move(r, delta) {
|
if !s.Move(r, delta) {
|
||||||
s.cancel()
|
s.Cancel()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
v.SetSelected(v.Selected() + delta)
|
v.SetSelected(v.Selected() + delta)
|
||||||
@ -90,7 +72,7 @@ func (v List) MoveElements(delta int) bool {
|
|||||||
// DeleteElements deletes the selected elements in a list. The list must
|
// DeleteElements deletes the selected elements in a list. The list must
|
||||||
// implement the MutableListData interface.
|
// implement the MutableListData interface.
|
||||||
func (v List) DeleteElements(backwards bool) bool {
|
func (v List) DeleteElements(backwards bool) bool {
|
||||||
d, ok := v.ListData.(MutableListData)
|
d, ok := v.data.(MutableListData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -98,9 +80,9 @@ func (v List) DeleteElements(backwards bool) bool {
|
|||||||
if r.Len() == 0 {
|
if r.Len() == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer d.change("DeleteElements", MajorChange)()
|
defer d.Change("DeleteElements", MajorChange)()
|
||||||
if !d.delete(r) {
|
if !d.Delete(r) {
|
||||||
d.cancel()
|
d.Cancel()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if backwards && r.Start > 0 {
|
if backwards && r.Start > 0 {
|
||||||
@ -115,7 +97,7 @@ func (v List) DeleteElements(backwards bool) bool {
|
|||||||
// the MutableListData interface. Returns the copied data, marshaled into byte
|
// the MutableListData interface. Returns the copied data, marshaled into byte
|
||||||
// slice, and true if successful.
|
// slice, and true if successful.
|
||||||
func (v List) CopyElements() ([]byte, bool) {
|
func (v List) CopyElements() ([]byte, bool) {
|
||||||
m, ok := v.ListData.(MutableListData)
|
m, ok := v.data.(MutableListData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@ -123,7 +105,7 @@ func (v List) CopyElements() ([]byte, bool) {
|
|||||||
if r.Len() == 0 {
|
if r.Len() == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
ret, err := m.marshal(r)
|
ret, err := m.Marshal(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@ -134,14 +116,14 @@ func (v List) CopyElements() ([]byte, bool) {
|
|||||||
// byte slice. The list must implement the MutableListData interface. Returns
|
// byte slice. The list must implement the MutableListData interface. Returns
|
||||||
// true if successful.
|
// true if successful.
|
||||||
func (v List) PasteElements(data []byte) (ok bool) {
|
func (v List) PasteElements(data []byte) (ok bool) {
|
||||||
m, ok := v.ListData.(MutableListData)
|
m, ok := v.data.(MutableListData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer m.change("PasteElements", MajorChange)()
|
defer m.Change("PasteElements", MajorChange)()
|
||||||
r, err := m.unmarshal(data)
|
r, err := m.Unmarshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.cancel()
|
m.Cancel()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
v.SetSelected(r.Start)
|
v.SetSelected(r.Start)
|
||||||
@ -149,19 +131,23 @@ func (v List) PasteElements(data []byte) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v List) Mutable() bool {
|
||||||
|
_, ok := v.data.(MutableListData)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func (v *List) listRange() (r Range) {
|
func (v *List) listRange() (r Range) {
|
||||||
r.Start = max(min(v.Selected(), v.Selected2()), 0)
|
r.Start = max(min(v.Selected(), v.Selected2()), 0)
|
||||||
r.End = min(max(v.Selected(), v.Selected2())+1, v.Count())
|
r.End = min(max(v.Selected(), v.Selected2())+1, v.Count())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instruments methods
|
// instruments is a list of instruments, implementing ListData & MutableListData interfaces
|
||||||
|
type instruments Model
|
||||||
|
|
||||||
func (v *Instruments) List() List {
|
func (m *Model) Instruments() List { return List{(*instruments)(m)} }
|
||||||
return List{v}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Instruments) Item(i int) (name string, maxLevel float32, mute bool, ok bool) {
|
func (v *Model) Instrument(i int) (name string, maxLevel float32, mute bool, ok bool) {
|
||||||
if i < 0 || i >= len(v.d.Song.Patch) {
|
if i < 0 || i >= len(v.d.Song.Patch) {
|
||||||
return "", 0, false, false
|
return "", 0, false, false
|
||||||
}
|
}
|
||||||
@ -182,37 +168,20 @@ func (v *Instruments) Item(i int) (name string, maxLevel float32, mute bool, ok
|
|||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (v *Instruments) FirstID(i int) (id int, ok bool) {
|
|
||||||
if i < 0 || i >= len(v.d.Song.Patch) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
if len(v.d.Song.Patch[i].Units) == 0 {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return v.d.Song.Patch[i].Units[0].ID, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Instruments) Selected() int {
|
func (v *instruments) Count() int { return len(v.d.Song.Patch) }
|
||||||
return max(min(v.d.InstrIndex, v.Count()-1), 0)
|
func (v *instruments) Selected() int { return v.d.InstrIndex }
|
||||||
}
|
func (v *instruments) Selected2() int { return v.d.InstrIndex2 }
|
||||||
|
func (v *instruments) SetSelected2(value int) { v.d.InstrIndex2 = value }
|
||||||
func (v *Instruments) Selected2() int {
|
func (v *instruments) SetSelected(value int) {
|
||||||
return max(min(v.d.InstrIndex2, v.Count()-1), 0)
|
v.d.InstrIndex = value
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Instruments) SetSelected(value int) {
|
|
||||||
v.d.InstrIndex = max(min(value, v.Count()-1), 0)
|
|
||||||
v.d.UnitIndex = 0
|
v.d.UnitIndex = 0
|
||||||
v.d.UnitIndex2 = 0
|
v.d.UnitIndex2 = 0
|
||||||
v.d.UnitSearching = false
|
v.d.UnitSearching = false
|
||||||
v.d.UnitSearchString = ""
|
v.d.UnitSearchString = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Instruments) SetSelected2(value int) {
|
func (v *instruments) Move(r Range, delta int) (ok bool) {
|
||||||
v.d.InstrIndex2 = max(min(value, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Instruments) move(r Range, delta int) (ok bool) {
|
|
||||||
voiceDelta := 0
|
voiceDelta := 0
|
||||||
if delta < 0 {
|
if delta < 0 {
|
||||||
voiceDelta = -VoiceRange(v.d.Song.Patch, Range{r.Start + delta, r.Start}).Len()
|
voiceDelta = -VoiceRange(v.d.Song.Patch, Range{r.Start + delta, r.Start}).Len()
|
||||||
@ -226,28 +195,24 @@ func (v *Instruments) move(r Range, delta int) (ok bool) {
|
|||||||
return (*Model)(v).sliceInstrumentsTracks(true, v.linkInstrTrack, ranges[:]...)
|
return (*Model)(v).sliceInstrumentsTracks(true, v.linkInstrTrack, ranges[:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Instruments) delete(r Range) (ok bool) {
|
func (v *instruments) Delete(r Range) (ok bool) {
|
||||||
ranges := Complement(VoiceRange(v.d.Song.Patch, r))
|
ranges := Complement(VoiceRange(v.d.Song.Patch, r))
|
||||||
return (*Model)(v).sliceInstrumentsTracks(true, v.linkInstrTrack, ranges[:]...)
|
return (*Model)(v).sliceInstrumentsTracks(true, v.linkInstrTrack, ranges[:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Instruments) change(n string, severity ChangeSeverity) func() {
|
func (v *instruments) Change(n string, severity ChangeSeverity) func() {
|
||||||
return (*Model)(v).change("Instruments."+n, SongChange, severity)
|
return (*Model)(v).change("Instruments."+n, SongChange, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Instruments) cancel() {
|
func (v *instruments) Cancel() {
|
||||||
v.changeCancel = true
|
v.changeCancel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Instruments) Count() int {
|
func (v *instruments) Marshal(r Range) ([]byte, error) {
|
||||||
return len(v.d.Song.Patch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Instruments) marshal(r Range) ([]byte, error) {
|
|
||||||
return (*Model)(v).marshalVoices(VoiceRange(v.d.Song.Patch, r))
|
return (*Model)(v).marshalVoices(VoiceRange(v.d.Song.Patch, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Instruments) unmarshal(data []byte) (r Range, err error) {
|
func (m *instruments) Unmarshal(data []byte) (r Range, err error) {
|
||||||
voiceIndex := m.d.Song.Patch.FirstVoiceForInstrument(m.d.InstrIndex)
|
voiceIndex := m.d.Song.Patch.FirstVoiceForInstrument(m.d.InstrIndex)
|
||||||
r, _, ok := (*Model)(m).unmarshalVoices(voiceIndex, data, true, m.linkInstrTrack)
|
r, _, ok := (*Model)(m).unmarshalVoices(voiceIndex, data, true, m.linkInstrTrack)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -256,13 +221,37 @@ func (m *Instruments) unmarshal(data []byte) (r Range, err error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Units methods
|
// units is a list of all the units in the selected instrument, implementing ListData & MutableListData interfaces
|
||||||
|
type (
|
||||||
|
units Model
|
||||||
|
UnitListItem struct {
|
||||||
|
Type, Comment string
|
||||||
|
Disabled bool
|
||||||
|
Signals Rail
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func (v *Units) List() List {
|
func (m *Model) Units() List { return List{(*units)(m)} }
|
||||||
return List{v}
|
|
||||||
|
func (v *Model) Unit(index int) UnitListItem {
|
||||||
|
i := v.d.InstrIndex
|
||||||
|
if i < 0 || i >= len(v.d.Song.Patch) || index < 0 || index >= (*units)(v).Count() {
|
||||||
|
return UnitListItem{}
|
||||||
|
}
|
||||||
|
unit := v.d.Song.Patch[v.d.InstrIndex].Units[index]
|
||||||
|
signals := Rail{}
|
||||||
|
if i >= 0 && i < len(v.derived.patch) && index >= 0 && index < len(v.derived.patch[i].rails) {
|
||||||
|
signals = v.derived.patch[i].rails[index]
|
||||||
|
}
|
||||||
|
return UnitListItem{
|
||||||
|
Type: unit.Type,
|
||||||
|
Comment: unit.Comment,
|
||||||
|
Disabled: unit.Disabled,
|
||||||
|
Signals: signals,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Units) SelectedType() string {
|
func (m *Model) SelectedUnitType() string {
|
||||||
if m.d.InstrIndex < 0 ||
|
if m.d.InstrIndex < 0 ||
|
||||||
m.d.InstrIndex >= len(m.d.Song.Patch) ||
|
m.d.InstrIndex >= len(m.d.Song.Patch) ||
|
||||||
m.d.UnitIndex < 0 ||
|
m.d.UnitIndex < 0 ||
|
||||||
@ -272,7 +261,7 @@ func (m *Units) SelectedType() string {
|
|||||||
return m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].Type
|
return m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Units) SetSelectedType(t string) {
|
func (m *Model) SetSelectedUnitType(t string) {
|
||||||
if m.d.InstrIndex < 0 ||
|
if m.d.InstrIndex < 0 ||
|
||||||
m.d.InstrIndex >= len(m.d.Song.Patch) {
|
m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return
|
return
|
||||||
@ -293,58 +282,28 @@ func (m *Units) SetSelectedType(t string) {
|
|||||||
if oldUnit.Type == unit.Type {
|
if oldUnit.Type == unit.Type {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer m.change("SetSelectedType", MajorChange)()
|
defer (*units)(m).Change("SetSelectedType", MajorChange)()
|
||||||
m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex] = unit
|
m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex] = unit
|
||||||
m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].ID = oldUnit.ID // keep the ID of the replaced unit
|
m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex].ID = oldUnit.ID // keep the ID of the replaced unit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) Item(index int) UnitListItem {
|
func (v *units) Selected() int { return v.d.UnitIndex }
|
||||||
i := v.d.InstrIndex
|
func (v *units) Selected2() int { return v.d.UnitIndex2 }
|
||||||
if i < 0 || i >= len(v.d.Song.Patch) || index < 0 || index >= v.Count() {
|
func (v *units) SetSelected2(value int) { v.d.UnitIndex2 = value }
|
||||||
return UnitListItem{}
|
func (m *units) SetSelected(value int) {
|
||||||
}
|
m.d.UnitIndex = value
|
||||||
unit := v.d.Song.Patch[v.d.InstrIndex].Units[index]
|
|
||||||
signals := Rail{}
|
|
||||||
if i >= 0 && i < len(v.derived.patch) && index >= 0 && index < len(v.derived.patch[i].rails) {
|
|
||||||
signals = v.derived.patch[i].rails[index]
|
|
||||||
}
|
|
||||||
return UnitListItem{
|
|
||||||
Type: unit.Type,
|
|
||||||
Comment: unit.Comment,
|
|
||||||
Disabled: unit.Disabled,
|
|
||||||
Signals: signals,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Units) Selected() int {
|
|
||||||
return max(min(v.d.UnitIndex, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Units) Selected2() int {
|
|
||||||
return max(min(v.d.UnitIndex2, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Units) SetSelected(value int) {
|
|
||||||
m := (*Model)(v)
|
|
||||||
m.d.UnitIndex = max(min(value, v.Count()-1), 0)
|
|
||||||
m.d.ParamIndex = 0
|
m.d.ParamIndex = 0
|
||||||
m.d.UnitSearching = false
|
m.d.UnitSearching = false
|
||||||
m.d.UnitSearchString = ""
|
m.d.UnitSearchString = ""
|
||||||
}
|
}
|
||||||
|
func (v *units) Count() int {
|
||||||
func (v *Units) SetSelected2(value int) {
|
if v.d.InstrIndex < 0 || v.d.InstrIndex >= len(v.d.Song.Patch) {
|
||||||
(*Model)(v).d.UnitIndex2 = max(min(value, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Units) Count() int {
|
|
||||||
m := (*Model)(v)
|
|
||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(m.d.Song.Patch[(*Model)(v).d.InstrIndex].Units)
|
return len(v.d.Song.Patch[v.d.InstrIndex].Units)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) move(r Range, delta int) (ok bool) {
|
func (v *units) Move(r Range, delta int) (ok bool) {
|
||||||
m := (*Model)(v)
|
m := (*Model)(v)
|
||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return false
|
return false
|
||||||
@ -356,7 +315,7 @@ func (v *Units) move(r Range, delta int) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) delete(r Range) (ok bool) {
|
func (v *units) Delete(r Range) (ok bool) {
|
||||||
m := (*Model)(v)
|
m := (*Model)(v)
|
||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return false
|
return false
|
||||||
@ -366,15 +325,15 @@ func (v *Units) delete(r Range) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) change(n string, severity ChangeSeverity) func() {
|
func (v *units) Change(n string, severity ChangeSeverity) func() {
|
||||||
return (*Model)(v).change("UnitListView."+n, PatchChange, severity)
|
return (*Model)(v).change("UnitListView."+n, PatchChange, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) cancel() {
|
func (v *units) Cancel() {
|
||||||
(*Model)(v).changeCancel = true
|
(*Model)(v).changeCancel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) marshal(r Range) ([]byte, error) {
|
func (v *units) Marshal(r Range) ([]byte, error) {
|
||||||
m := (*Model)(v)
|
m := (*Model)(v)
|
||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return nil, errors.New("UnitListView.marshal: no instruments")
|
return nil, errors.New("UnitListView.marshal: no instruments")
|
||||||
@ -387,7 +346,7 @@ func (v *Units) marshal(r Range) ([]byte, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Units) unmarshal(data []byte) (r Range, err error) {
|
func (v *units) Unmarshal(data []byte) (r Range, err error) {
|
||||||
m := (*Model)(v)
|
m := (*Model)(v)
|
||||||
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
if m.d.InstrIndex < 0 || m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
return Range{}, errors.New("UnitListView.unmarshal: no instruments")
|
return Range{}, errors.New("UnitListView.unmarshal: no instruments")
|
||||||
@ -409,29 +368,18 @@ func (v *Units) unmarshal(data []byte) (r Range, err error) {
|
|||||||
return Range{sel, sel + len(pastedUnits.Units)}, nil
|
return Range{sel, sel + len(pastedUnits.Units)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracks methods
|
// tracks is a list of all the tracks, implementing ListData & MutableListData interfaces
|
||||||
|
type tracks Model
|
||||||
|
|
||||||
func (v *Tracks) List() List {
|
func (m *Model) Tracks() List { return List{(*tracks)(m)} }
|
||||||
return List{v}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Tracks) Selected() int {
|
func (v *tracks) Selected() int { return v.d.Cursor.Track }
|
||||||
return max(min(v.d.Cursor.Track, v.Count()-1), 0)
|
func (v *tracks) Selected2() int { return v.d.Cursor2.Track }
|
||||||
}
|
func (v *tracks) SetSelected(value int) { v.d.Cursor.Track = value }
|
||||||
|
func (v *tracks) SetSelected2(value int) { v.d.Cursor2.Track = value }
|
||||||
|
func (v *tracks) Count() int { return len((*Model)(v).d.Song.Score.Tracks) }
|
||||||
|
|
||||||
func (v *Tracks) Selected2() int {
|
func (v *tracks) Move(r Range, delta int) (ok bool) {
|
||||||
return max(min(v.d.Cursor2.Track, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Tracks) SetSelected(value int) {
|
|
||||||
v.d.Cursor.Track = max(min(value, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Tracks) SetSelected2(value int) {
|
|
||||||
v.d.Cursor2.Track = max(min(value, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Tracks) move(r Range, delta int) (ok bool) {
|
|
||||||
voiceDelta := 0
|
voiceDelta := 0
|
||||||
if delta < 0 {
|
if delta < 0 {
|
||||||
voiceDelta = -VoiceRange(v.d.Song.Score.Tracks, Range{r.Start + delta, r.Start}).Len()
|
voiceDelta = -VoiceRange(v.d.Song.Score.Tracks, Range{r.Start + delta, r.Start}).Len()
|
||||||
@ -445,28 +393,24 @@ func (v *Tracks) move(r Range, delta int) (ok bool) {
|
|||||||
return (*Model)(v).sliceInstrumentsTracks(v.linkInstrTrack, true, ranges[:]...)
|
return (*Model)(v).sliceInstrumentsTracks(v.linkInstrTrack, true, ranges[:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Tracks) delete(r Range) (ok bool) {
|
func (v *tracks) Delete(r Range) (ok bool) {
|
||||||
ranges := Complement(VoiceRange(v.d.Song.Score.Tracks, r))
|
ranges := Complement(VoiceRange(v.d.Song.Score.Tracks, r))
|
||||||
return (*Model)(v).sliceInstrumentsTracks(v.linkInstrTrack, true, ranges[:]...)
|
return (*Model)(v).sliceInstrumentsTracks(v.linkInstrTrack, true, ranges[:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Tracks) change(n string, severity ChangeSeverity) func() {
|
func (v *tracks) Change(n string, severity ChangeSeverity) func() {
|
||||||
return (*Model)(v).change("TrackList."+n, SongChange, severity)
|
return (*Model)(v).change("TrackList."+n, SongChange, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Tracks) cancel() {
|
func (v *tracks) Cancel() {
|
||||||
v.changeCancel = true
|
v.changeCancel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Tracks) Count() int {
|
func (v *tracks) Marshal(r Range) ([]byte, error) {
|
||||||
return len((*Model)(v).d.Song.Score.Tracks)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Tracks) marshal(r Range) ([]byte, error) {
|
|
||||||
return (*Model)(v).marshalVoices(VoiceRange(v.d.Song.Score.Tracks, r))
|
return (*Model)(v).marshalVoices(VoiceRange(v.d.Song.Score.Tracks, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Tracks) unmarshal(data []byte) (r Range, err error) {
|
func (m *tracks) Unmarshal(data []byte) (r Range, err error) {
|
||||||
voiceIndex := m.d.Song.Score.FirstVoiceForTrack(m.d.Cursor.Track)
|
voiceIndex := m.d.Song.Score.FirstVoiceForTrack(m.d.Cursor.Track)
|
||||||
_, r, ok := (*Model)(m).unmarshalVoices(voiceIndex, data, m.linkInstrTrack, true)
|
_, r, ok := (*Model)(m).unmarshalVoices(voiceIndex, data, m.linkInstrTrack, true)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -475,37 +419,23 @@ func (m *Tracks) unmarshal(data []byte) (r Range, err error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderRows methods
|
// orderRows is a list of all the order rows, implementing ListData & MutableListData interfaces
|
||||||
|
type orderRows Model
|
||||||
|
|
||||||
func (v *OrderRows) List() List {
|
func (m *Model) OrderRows() List { return List{(*orderRows)(m)} }
|
||||||
return List{v}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *OrderRows) Selected() int {
|
func (v *orderRows) Count() int { return v.d.Song.Score.Length }
|
||||||
p := v.d.Cursor.OrderRow
|
func (v *orderRows) Selected() int { return v.d.Cursor.OrderRow }
|
||||||
p = max(min(p, v.Count()-1), 0)
|
func (v *orderRows) Selected2() int { return v.d.Cursor2.OrderRow }
|
||||||
return p
|
func (v *orderRows) SetSelected2(value int) { v.d.Cursor2.OrderRow = value }
|
||||||
}
|
func (v *orderRows) SetSelected(value int) {
|
||||||
|
if value != v.d.Cursor.OrderRow {
|
||||||
func (v *OrderRows) Selected2() int {
|
|
||||||
p := v.d.Cursor2.OrderRow
|
|
||||||
p = max(min(p, v.Count()-1), 0)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *OrderRows) SetSelected(value int) {
|
|
||||||
y := max(min(value, v.Count()-1), 0)
|
|
||||||
if y != v.d.Cursor.OrderRow {
|
|
||||||
v.follow = false
|
v.follow = false
|
||||||
}
|
}
|
||||||
v.d.Cursor.OrderRow = y
|
v.d.Cursor.OrderRow = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) SetSelected2(value int) {
|
func (v *orderRows) Move(r Range, delta int) (ok bool) {
|
||||||
v.d.Cursor2.OrderRow = max(min(value, v.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *OrderRows) move(r Range, delta int) (ok bool) {
|
|
||||||
swaps := r.Swaps(delta)
|
swaps := r.Swaps(delta)
|
||||||
for i, t := range v.d.Song.Score.Tracks {
|
for i, t := range v.d.Song.Score.Tracks {
|
||||||
for a, b := range swaps {
|
for a, b := range swaps {
|
||||||
@ -517,7 +447,7 @@ func (v *OrderRows) move(r Range, delta int) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) delete(r Range) (ok bool) {
|
func (v *orderRows) Delete(r Range) (ok bool) {
|
||||||
for i, t := range v.d.Song.Score.Tracks {
|
for i, t := range v.d.Song.Score.Tracks {
|
||||||
r2 := r.Intersect(Range{0, len(t.Order)})
|
r2 := r.Intersect(Range{0, len(t.Order)})
|
||||||
v.d.Song.Score.Tracks[i].Order = append(t.Order[:r2.Start], t.Order[r2.End:]...)
|
v.d.Song.Score.Tracks[i].Order = append(t.Order[:r2.Start], t.Order[r2.End:]...)
|
||||||
@ -525,23 +455,19 @@ func (v *OrderRows) delete(r Range) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) change(n string, severity ChangeSeverity) func() {
|
func (v *orderRows) Change(n string, severity ChangeSeverity) func() {
|
||||||
return (*Model)(v).change("OrderRowList."+n, ScoreChange, severity)
|
return (*Model)(v).change("OrderRowList."+n, ScoreChange, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) cancel() {
|
func (v *orderRows) Cancel() {
|
||||||
v.changeCancel = true
|
v.changeCancel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) Count() int {
|
|
||||||
return v.d.Song.Score.Length
|
|
||||||
}
|
|
||||||
|
|
||||||
type marshalOrderRows struct {
|
type marshalOrderRows struct {
|
||||||
Columns [][]int `yaml:",flow"`
|
Columns [][]int `yaml:",flow"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) marshal(r Range) ([]byte, error) {
|
func (v *orderRows) Marshal(r Range) ([]byte, error) {
|
||||||
var table marshalOrderRows
|
var table marshalOrderRows
|
||||||
for i := range v.d.Song.Score.Tracks {
|
for i := range v.d.Song.Score.Tracks {
|
||||||
table.Columns = append(table.Columns, make([]int, r.Len()))
|
table.Columns = append(table.Columns, make([]int, r.Len()))
|
||||||
@ -552,7 +478,7 @@ func (v *OrderRows) marshal(r Range) ([]byte, error) {
|
|||||||
return yaml.Marshal(table)
|
return yaml.Marshal(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *OrderRows) unmarshal(data []byte) (r Range, err error) {
|
func (v *orderRows) Unmarshal(data []byte) (r Range, err error) {
|
||||||
var table marshalOrderRows
|
var table marshalOrderRows
|
||||||
err = yaml.Unmarshal(data, &table)
|
err = yaml.Unmarshal(data, &table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -581,33 +507,23 @@ func (v *OrderRows) unmarshal(data []byte) (r Range, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoteRows methods
|
// noteRows is a list of all the note rows, implementing ListData & MutableListData interfaces
|
||||||
|
type noteRows Model
|
||||||
|
|
||||||
func (v *NoteRows) List() List {
|
func (m *Model) NoteRows() List { return List{(*noteRows)(m)} }
|
||||||
return List{v}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *NoteRows) Selected() int {
|
func (n *noteRows) Count() int { return n.d.Song.Score.Length * n.d.Song.Score.RowsPerPattern }
|
||||||
return v.d.Song.Score.SongRow(v.d.Song.Score.Clamp(v.d.Cursor.SongPos))
|
func (n *noteRows) Selected() int { return n.d.Song.Score.SongRow(n.d.Cursor.SongPos) }
|
||||||
}
|
func (n *noteRows) Selected2() int { return n.d.Song.Score.SongRow(n.d.Cursor2.SongPos) }
|
||||||
|
func (n *noteRows) SetSelected2(v int) { n.d.Cursor2.SongPos = n.d.Song.Score.SongPos(v) }
|
||||||
func (v *NoteRows) Selected2() int {
|
func (n *noteRows) SetSelected(value int) {
|
||||||
return v.d.Song.Score.SongRow(v.d.Song.Score.Clamp(v.d.Cursor2.SongPos))
|
if value != n.d.Song.Score.SongRow(n.d.Cursor.SongPos) {
|
||||||
}
|
n.follow = false
|
||||||
|
|
||||||
func (v *NoteRows) SetSelected(value int) {
|
|
||||||
if value != v.d.Song.Score.SongRow(v.d.Cursor.SongPos) {
|
|
||||||
v.follow = false
|
|
||||||
}
|
}
|
||||||
v.d.Cursor.SongPos = v.d.Song.Score.Clamp(v.d.Song.Score.SongPos(value))
|
n.d.Cursor.SongPos = n.d.Song.Score.Clamp(n.d.Song.Score.SongPos(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) SetSelected2(value int) {
|
func (v *noteRows) Move(r Range, delta int) (ok bool) {
|
||||||
v.d.Cursor2.SongPos = v.d.Song.Score.Clamp(v.d.Song.Score.SongPos(value))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *NoteRows) move(r Range, delta int) (ok bool) {
|
|
||||||
for a, b := range r.Swaps(delta) {
|
for a, b := range r.Swaps(delta) {
|
||||||
apos := v.d.Song.Score.SongPos(a)
|
apos := v.d.Song.Score.SongPos(a)
|
||||||
bpos := v.d.Song.Score.SongPos(b)
|
bpos := v.d.Song.Score.SongPos(b)
|
||||||
@ -621,7 +537,7 @@ func (v *NoteRows) move(r Range, delta int) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) delete(r Range) (ok bool) {
|
func (v *noteRows) Delete(r Range) (ok bool) {
|
||||||
for _, track := range v.d.Song.Score.Tracks {
|
for _, track := range v.d.Song.Score.Tracks {
|
||||||
for i := r.Start; i < r.End; i++ {
|
for i := r.Start; i < r.End; i++ {
|
||||||
pos := v.d.Song.Score.SongPos(i)
|
pos := v.d.Song.Score.SongPos(i)
|
||||||
@ -631,23 +547,19 @@ func (v *NoteRows) delete(r Range) (ok bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) change(n string, severity ChangeSeverity) func() {
|
func (v *noteRows) Change(n string, severity ChangeSeverity) func() {
|
||||||
return (*Model)(v).change("NoteRowList."+n, ScoreChange, severity)
|
return (*Model)(v).change("NoteRowList."+n, ScoreChange, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) cancel() {
|
func (v *noteRows) Cancel() {
|
||||||
(*Model)(v).changeCancel = true
|
(*Model)(v).changeCancel = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) Count() int {
|
|
||||||
return (*Model)(v).d.Song.Score.Length * v.d.Song.Score.RowsPerPattern
|
|
||||||
}
|
|
||||||
|
|
||||||
type marshalNoteRows struct {
|
type marshalNoteRows struct {
|
||||||
NoteRows [][]byte `yaml:",flow"`
|
NoteRows [][]byte `yaml:",flow"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) marshal(r Range) ([]byte, error) {
|
func (v *noteRows) Marshal(r Range) ([]byte, error) {
|
||||||
var table marshalNoteRows
|
var table marshalNoteRows
|
||||||
for i, track := range v.d.Song.Score.Tracks {
|
for i, track := range v.d.Song.Score.Tracks {
|
||||||
table.NoteRows = append(table.NoteRows, make([]byte, r.Len()))
|
table.NoteRows = append(table.NoteRows, make([]byte, r.Len()))
|
||||||
@ -660,7 +572,7 @@ func (v *NoteRows) marshal(r Range) ([]byte, error) {
|
|||||||
return yaml.Marshal(table)
|
return yaml.Marshal(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NoteRows) unmarshal(data []byte) (r Range, err error) {
|
func (v *noteRows) Unmarshal(data []byte) (r Range, err error) {
|
||||||
var table marshalNoteRows
|
var table marshalNoteRows
|
||||||
if err := yaml.Unmarshal(data, &table); err != nil {
|
if err := yaml.Unmarshal(data, &table); err != nil {
|
||||||
return Range{}, fmt.Errorf("NoteRowList.unmarshal: %v", err)
|
return Range{}, fmt.Errorf("NoteRowList.unmarshal: %v", err)
|
||||||
@ -683,58 +595,26 @@ func (v *NoteRows) unmarshal(data []byte) (r Range, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchResults
|
// searchResults is a unmutable list of all the search results, implementing ListData interface
|
||||||
|
type (
|
||||||
|
searchResults Model
|
||||||
|
UnitSearchYieldFunc func(index int, item string) (ok bool)
|
||||||
|
)
|
||||||
|
|
||||||
func (v *SearchResults) List() List {
|
func (m *Model) SearchResults() List { return List{(*searchResults)(m)} }
|
||||||
return List{v}
|
func (l *Model) SearchResult(i int) (name string, ok bool) {
|
||||||
}
|
if i < 0 || i >= len(l.derived.searchResults) {
|
||||||
|
|
||||||
func (l *SearchResults) Iterate(yield UnitSearchYieldFunc) {
|
|
||||||
index := 0
|
|
||||||
for _, name := range sointu.UnitNames {
|
|
||||||
if !strings.HasPrefix(name, l.d.UnitSearchString) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !yield(index, name) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
index++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) Item(index int) (name string, ok bool) {
|
|
||||||
for i, n := range l.Iterate {
|
|
||||||
if i == index {
|
|
||||||
return n, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", false
|
return "", false
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) Selected() int {
|
|
||||||
return max(min(l.d.UnitSearchIndex, l.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) Selected2() int {
|
|
||||||
return max(min(l.d.UnitSearchIndex, l.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) SetSelected(value int) {
|
|
||||||
l.d.UnitSearchIndex = max(min(value, l.Count()-1), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) SetSelected2(value int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *SearchResults) Count() (count int) {
|
|
||||||
for _, n := range sointu.UnitNames {
|
|
||||||
if strings.HasPrefix(n, l.d.UnitSearchString) {
|
|
||||||
count++
|
|
||||||
}
|
}
|
||||||
}
|
return l.derived.searchResults[i], true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *searchResults) Selected() int { return l.d.UnitSearchIndex }
|
||||||
|
func (l *searchResults) Selected2() int { return l.d.UnitSearchIndex }
|
||||||
|
func (l *searchResults) SetSelected(value int) { l.d.UnitSearchIndex = value }
|
||||||
|
func (l *searchResults) SetSelected2(value int) {}
|
||||||
|
func (l *searchResults) Count() (count int) { return len(l.derived.searchResults) }
|
||||||
|
|
||||||
func (r Range) Len() int { return r.End - r.Start }
|
func (r Range) Len() int { return r.End - r.Start }
|
||||||
|
|
||||||
func (r Range) Swaps(delta int) iter.Seq2[int, int] {
|
func (r Range) Swaps(delta int) iter.Seq2[int, int] {
|
||||||
|
|||||||
@ -216,6 +216,8 @@ func NewModel(broker *Broker, synthers []sointu.Synther, midiContext MIDIContext
|
|||||||
m.updateDeriveData(SongChange)
|
m.updateDeriveData(SongChange)
|
||||||
m.presets.load()
|
m.presets.load()
|
||||||
m.updateDerivedPresetSearch()
|
m.updateDerivedPresetSearch()
|
||||||
|
m.derived.searchResults = make([]string, 0, len(sointu.UnitNames))
|
||||||
|
m.updateDerivedUnitSearch()
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,12 +44,12 @@ func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)
|
|||||||
s.IterateInt("Step", s.model.Step(), yield, seed)
|
s.IterateInt("Step", s.model.Step(), yield, seed)
|
||||||
s.IterateInt("Octave", s.model.Octave(), yield, seed)
|
s.IterateInt("Octave", s.model.Octave(), yield, seed)
|
||||||
// Lists
|
// Lists
|
||||||
s.IterateList("Instruments", s.model.Instruments().List(), yield, seed)
|
s.IterateList("Instruments", s.model.Instruments(), yield, seed)
|
||||||
s.IterateList("Units", s.model.Units().List(), yield, seed)
|
s.IterateList("Units", s.model.Units(), yield, seed)
|
||||||
s.IterateList("Tracks", s.model.Tracks().List(), yield, seed)
|
s.IterateList("Tracks", s.model.Tracks(), yield, seed)
|
||||||
s.IterateList("OrderRows", s.model.OrderRows().List(), yield, seed)
|
s.IterateList("OrderRows", s.model.OrderRows(), yield, seed)
|
||||||
s.IterateList("NoteRows", s.model.NoteRows().List(), yield, seed)
|
s.IterateList("NoteRows", s.model.NoteRows(), yield, seed)
|
||||||
s.IterateList("UnitSearchResults", s.model.SearchResults().List(), yield, seed)
|
s.IterateList("UnitSearchResults", s.model.SearchResults(), yield, seed)
|
||||||
s.IterateList("PresetDirs", s.model.PresetDirList().List(), yield, seed)
|
s.IterateList("PresetDirs", s.model.PresetDirList().List(), yield, seed)
|
||||||
s.IterateList("PresetResults", s.model.PresetResultList().List(), yield, seed)
|
s.IterateList("PresetResults", s.model.PresetResultList().List(), yield, seed)
|
||||||
// Bools
|
// Bools
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
package tracker
|
package tracker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vsariola/sointu"
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
String struct {
|
String struct {
|
||||||
value StringValue
|
value StringValue
|
||||||
@ -67,8 +73,18 @@ func (v *UnitSearch) Value() string {
|
|||||||
func (v *UnitSearch) SetValue(value string) bool {
|
func (v *UnitSearch) SetValue(value string) bool {
|
||||||
v.d.UnitSearchString = value
|
v.d.UnitSearchString = value
|
||||||
v.d.UnitSearching = true
|
v.d.UnitSearching = true
|
||||||
|
(*Model)(v).updateDerivedUnitSearch()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
func (v *Model) updateDerivedUnitSearch() {
|
||||||
|
// update search results based on current search string
|
||||||
|
v.derived.searchResults = v.derived.searchResults[:0]
|
||||||
|
for _, name := range sointu.UnitNames {
|
||||||
|
if strings.HasPrefix(name, v.UnitSearch().Value()) {
|
||||||
|
v.derived.searchResults = append(v.derived.searchResults, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InstrumentNameString
|
// InstrumentNameString
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user