This commit is contained in:
5684185+vsariola@users.noreply.github.com
2025-10-15 23:12:43 +03:00
parent e5a2fbec51
commit 0bd652dcbb
8 changed files with 212 additions and 14 deletions

View File

@ -33,9 +33,10 @@ type (
// corresponding part of the model changes.
derivedModelData struct {
// map Unit by ID, other entities by their respective index
patch []derivedInstrument
tracks []derivedTrack
railError RailError
patch []derivedInstrument
tracks []derivedTrack
railError RailError
presetSearch derivedPresetSearch
}
derivedInstrument struct {

View File

@ -66,7 +66,13 @@ func (e *Editor) Layout(gtx C, str tracker.String, th *Theme, style *EditorStyle
// just consume all events if the user did not consume them
}
if e.widgetEditor.Text() != str.Value() {
line, col := e.widgetEditor.CaretPos()
// if the user has moved the caret, put it in the end
e.widgetEditor.SetText(str.Value())
if line > 0 || col > 0 {
l := len(e.widgetEditor.Text())
e.widgetEditor.SetCaret(l, l)
}
}
me := material.Editor(&th.Material, &e.widgetEditor, hint)
me.Font = style.Font

View File

@ -0,0 +1,55 @@
package gioui
import (
"gioui.org/layout"
"gioui.org/text"
"gioui.org/unit"
"github.com/vsariola/sointu/tracker"
)
type (
InstrumentPresets struct {
searchEditor *Editor
gmDlsBtn *Clickable
userPresetsBtn *Clickable
builtinPresetsBtn *Clickable
clearSearchBtn *Clickable
dirList *DragList
resultList *DragList
}
)
func NewInstrumentPresets(m *tracker.Model) *InstrumentPresets {
return &InstrumentPresets{
searchEditor: NewEditor(false, false, text.Start),
gmDlsBtn: new(Clickable),
clearSearchBtn: new(Clickable),
userPresetsBtn: new(Clickable),
builtinPresetsBtn: new(Clickable),
dirList: NewDragList(m.Instruments().List(), layout.Vertical),
resultList: NewDragList(m.Instruments().List(), layout.Vertical),
}
}
func (ip *InstrumentPresets) layout(gtx C) D {
// 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")
// layout
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return layout.UniformInset(unit.Dp(4)).Layout(gtx, func(gtx C) D {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Flexed(1, func(gtx C) D {
return ip.searchEditor.Layout(gtx, tr.Model.PresetSearchString(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Search presets")
}),
layout.Rigid(userPresetsFilterBtn.Layout),
layout.Rigid(builtinPresetsFilterBtn.Layout),
layout.Rigid(gmDlsBtn.Layout),
)
})
}),
)
}

View File

@ -20,11 +20,12 @@ import (
type (
PatchPanel struct {
instrList InstrumentList
tools InstrumentTools
unitList UnitList
unitEditor UnitEditor
instrProps InstrumentProperties
instrList InstrumentList
tools InstrumentTools
unitList UnitList
unitEditor UnitEditor
instrProps InstrumentProperties
instrPresets InstrumentPresets
}
InstrumentList struct {
@ -66,11 +67,12 @@ type (
func NewPatchPanel(model *tracker.Model) *PatchPanel {
return &PatchPanel{
instrList: MakeInstrList(model),
tools: MakeInstrumentTools(model),
unitList: MakeUnitList(model),
unitEditor: *NewUnitEditor(model),
instrProps: *NewInstrumentProperties(),
instrList: MakeInstrList(model),
tools: MakeInstrumentTools(model),
unitList: MakeUnitList(model),
unitEditor: *NewUnitEditor(model),
instrProps: *NewInstrumentProperties(),
instrPresets: *NewInstrumentPresets(model),
}
}
@ -81,7 +83,7 @@ func (pp *PatchPanel) Layout(gtx C) D {
case tr.InstrComment().Value():
return pp.instrProps.layout(gtx)
case tr.InstrPresets().Value():
return pp.instrProps.layout(gtx)
return pp.instrPresets.layout(gtx)
default: // editor
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(pp.unitList.Layout),

View File

@ -37,6 +37,7 @@ type (
ChangedSinceRecovery bool
SendSource int
InstrumentTab InstrumentTab
PresetSearchString string
}
Model struct {

View File

@ -32,8 +32,141 @@ type (
Index int
*Model
}
PresetSearchString Model
NoGmDlsFilter Model
BuiltinPresetsFilter Model
UserPresetsFilter Model
PresetDirectory Model
PresetKind Model
derivedPresetSearch struct {
directory string
noGmDls bool
kind PresetKindEnum
}
PresetKindEnum int
)
const (
BuiltinPresets PresetKindEnum = -1
AllPresets PresetKindEnum = 0
UserPresets PresetKindEnum = 1
)
func (m *Model) updateDerivedPresetSearch() {
// parse filters from the search string. in: dir, gmdls: yes/no, kind: builtin/user/all
search := strings.TrimSpace(m.d.PresetSearchString)
lower := strings.ToLower(search)
parts := strings.Fields(lower)
// parse parts to see if they contain :
m.derived.presetSearch.noGmDls = false
m.derived.presetSearch.directory = ""
m.derived.presetSearch.kind = AllPresets
for _, part := range parts {
if strings.HasPrefix(part, "in:") && len(part) > 3 {
m.derived.presetSearch.directory = strings.TrimSpace(part[3:])
} else if strings.HasPrefix(part, "gmdls:") && len(part) > 6 {
val := strings.TrimSpace(part[6:])
m.derived.presetSearch.noGmDls = val == "no"
} else if strings.HasPrefix(part, "kind:") && len(part) > 5 {
val := strings.TrimSpace(part[5:])
switch val {
case "builtin":
m.derived.presetSearch.kind = BuiltinPresets
case "user":
m.derived.presetSearch.kind = UserPresets
default:
m.derived.presetSearch.kind = AllPresets
}
}
}
}
func (m *Model) PresetSearchString() String { return MakeString((*PresetSearchString)(m)) }
func (m *PresetSearchString) Value() string { return m.d.PresetSearchString }
func (m *PresetSearchString) SetValue(value string) bool {
if m.d.PresetSearchString == value {
return false
}
m.d.PresetSearchString = value
(*Model)(m).updateDerivedPresetSearch()
return true
}
func (m *Model) NoGmDls() Bool { return MakeBool((*NoGmDlsFilter)(m)) }
func (m *NoGmDlsFilter) Value() bool { return m.derived.presetSearch.noGmDls }
func (m *NoGmDlsFilter) SetValue(val bool) {
if m.derived.presetSearch.noGmDls == val {
return
}
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "gmdls:")
if val {
m.d.PresetSearchString = "gmdls:no " + m.d.PresetSearchString
}
(*Model)(m).updateDerivedPresetSearch()
}
func (m *NoGmDlsFilter) Enabled() bool { return true }
func (m *Model) UserPresetFilter() Bool { return MakeBool((*UserPresetsFilter)(m)) }
func (m *UserPresetsFilter) Value() bool { return m.derived.presetSearch.kind == UserPresets }
func (m *UserPresetsFilter) SetValue(val bool) {
if (m.derived.presetSearch.kind == UserPresets) == val {
return
}
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "kind:")
if val {
m.d.PresetSearchString = "kind:user " + m.d.PresetSearchString
}
(*Model)(m).updateDerivedPresetSearch()
}
func (m *UserPresetsFilter) Enabled() bool { return true }
func (m *Model) BuiltinPresetsFilter() Bool { return MakeBool((*BuiltinPresetsFilter)(m)) }
func (m *BuiltinPresetsFilter) Value() bool { return m.derived.presetSearch.kind == BuiltinPresets }
func (m *BuiltinPresetsFilter) SetValue(val bool) {
if (m.derived.presetSearch.kind == BuiltinPresets) == val {
return
}
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "kind:")
if val {
m.d.PresetSearchString = "kind:builtin " + m.d.PresetSearchString
}
(*Model)(m).updateDerivedPresetSearch()
}
func (m *BuiltinPresetsFilter) Enabled() bool { return true }
func (m *Model) PresetKind() Int { return MakeInt((*PresetKind)(m)) }
func (m *PresetKind) Value() int { return int(m.derived.presetSearch.kind) }
func (m *PresetKind) SetValue(val int) bool {
if int(m.derived.presetSearch.kind) == val {
return false
}
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "kind:")
switch PresetKindEnum(val) {
case BuiltinPresets:
m.d.PresetSearchString = "kind:builtin " + m.d.PresetSearchString
case UserPresets:
m.d.PresetSearchString = "kind:user " + m.d.PresetSearchString
}
(*Model)(m).updateDerivedPresetSearch()
return true
}
func (m *PresetKind) Enabled() bool { return true }
func (m *PresetKind) Range() IntRange { return IntRange{Min: -1, Max: 1} }
func removeFilters(str string, prefix string) string {
parts := strings.Fields(str)
newParts := make([]string, 0, len(parts))
for _, part := range parts {
if !strings.HasPrefix(strings.ToLower(part), prefix) {
newParts = append(newParts, part)
}
}
return strings.Join(newParts, " ")
}
// gmDlsEntryMap is a reverse map, to find the index of the GmDlsEntry in the
// GmDlsEntries list based on the sample offset. Do not modify during runtime.
var gmDlsEntryMap = make(map[vm.SampleOffset]int)