diff --git a/tracker/gioui/instrument_editor.go b/tracker/gioui/instrument_editor.go index 58ade67..e8f7485 100644 --- a/tracker/gioui/instrument_editor.go +++ b/tracker/gioui/instrument_editor.go @@ -28,18 +28,11 @@ import ( type ( InstrumentEditor struct { - unitList UnitList - unitEditor UnitEditor - } - - UnitList struct { dragList *DragList searchEditor *Editor addUnitBtn *Clickable addUnitAction tracker.Action - } - UnitEditor struct { paramTable *ScrollTable searchList *DragList Parameters [][]*ParamState @@ -59,43 +52,51 @@ type ( } ) -func MakeInstrumentEditor(model *tracker.Model) InstrumentEditor { - return InstrumentEditor{ - unitList: MakeUnitList(model), - unitEditor: *NewUnitEditor(model), - } -} - -func (ie *InstrumentEditor) layout(gtx C) D { - return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, - layout.Rigid(ie.unitList.Layout), - layout.Flexed(1, ie.unitEditor.Layout), - ) -} - -func (ie *InstrumentEditor) Tags(level int, yield TagYieldFunc) bool { - return ie.unitList.Tags(level, yield) && - ie.unitEditor.Tags(level, yield) -} - -// UnitList methods - -func MakeUnitList(m *tracker.Model) UnitList { - ret := UnitList{ - dragList: NewDragList(m.Units().List(), layout.Vertical), - addUnitBtn: new(Clickable), - searchEditor: NewEditor(true, true, text.Start), +func NewInstrumentEditor(m *tracker.Model) *InstrumentEditor { + ret := &InstrumentEditor{ + dragList: NewDragList(m.Units().List(), layout.Vertical), + addUnitBtn: new(Clickable), + searchEditor: NewEditor(true, true, text.Start), + DeleteUnitBtn: new(Clickable), + ClearUnitBtn: new(Clickable), + DisableUnitBtn: new(Clickable), + CopyUnitBtn: new(Clickable), + SelectTypeBtn: new(Clickable), + commentEditor: NewEditor(true, true, text.Start), + paramTable: NewScrollTable(m.Params().Table(), m.ParamVertList().List(), m.Units().List()), + searchList: NewDragList(m.SearchResults().List(), layout.Vertical), + searching: m.UnitSearching(), } ret.addUnitAction = tracker.MakeEnabledAction(tracker.DoFunc(func() { m.AddUnit(false).Do() ret.searchEditor.Focus() })) + ret.caser = cases.Title(language.English) + ret.copyHint = makeHint("Copy unit", " (%s)", "Copy") + ret.disableUnitHint = makeHint("Disable unit", " (%s)", "UnitDisabledToggle") + ret.enableUnitHint = makeHint("Enable unit", " (%s)", "UnitDisabledToggle") return ret + } -func (ul *UnitList) Layout(gtx C) D { +func (ie *InstrumentEditor) layout(gtx C) D { + ie.update(gtx) + return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, + layout.Rigid(ie.layoutList), + layout.Flexed(1, ie.layoutTable), + ) +} + +func (ie *InstrumentEditor) Tags(level int, yield TagYieldFunc) bool { + ret := yield(level, ie.dragList) && yield(level+1, &ie.searchEditor.widgetEditor) + if ie.searching.Value() { + ret = ret && yield(level, ie.searchList) && yield(level+1, &ie.commentEditor.widgetEditor) + } + return ret && yield(level+1, ie.paramTable.RowTitleList) && yield(level, ie.paramTable) && yield(level+1, &ie.commentEditor.widgetEditor) +} + +func (ul *InstrumentEditor) layoutList(gtx C) D { t := TrackerFromContext(gtx) - ul.update(gtx, t) element := func(gtx C, i int) D { gtx.Constraints.Max.Y = gtx.Dp(20) gtx.Constraints.Min.Y = gtx.Constraints.Max.Y @@ -153,18 +154,17 @@ func (ul *UnitList) Layout(gtx C) D { return Surface{Gray: 30, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, surface) } -func (ul *UnitList) update(gtx C, t *Tracker) { - for ul.addUnitBtn.Clicked(gtx) { - ul.addUnitAction.Do() - t.UnitSearching().SetValue(true) - ul.searchEditor.Focus() - } +func (ul *InstrumentEditor) update(gtx C) { + t := TrackerFromContext(gtx) for { event, ok := gtx.Event( key.Filter{Focus: ul.dragList, Name: key.NameRightArrow}, key.Filter{Focus: ul.dragList, Name: key.NameEnter, Optional: key.ModCtrl}, key.Filter{Focus: ul.dragList, Name: key.NameReturn, Optional: key.ModCtrl}, key.Filter{Focus: ul.dragList, Name: key.NameDeleteBackward}, + key.Filter{Focus: ul.paramTable.RowTitleList, Name: key.NameEnter, Optional: key.ModCtrl}, + key.Filter{Focus: ul.paramTable.RowTitleList, Name: key.NameReturn, Optional: key.ModCtrl}, + key.Filter{Focus: ul.paramTable.RowTitleList, Name: key.NameDeleteBackward}, ) if !ok { break @@ -172,7 +172,7 @@ func (ul *UnitList) update(gtx C, t *Tracker) { if e, ok := event.(key.Event); ok && e.State == key.Press { switch e.Name { case key.NameRightArrow: - t.PatchPanel.instrEditor.unitEditor.paramTable.RowTitleList.Focus() + t.PatchPanel.instrEditor.paramTable.RowTitleList.Focus() case key.NameDeleteBackward: t.Units().SetSelectedType("") t.UnitSearching().SetValue(true) @@ -201,74 +201,34 @@ func (ul *UnitList) update(gtx C, t *Tracker) { ul.dragList.Focus() t.UnitSearching().SetValue(false) } -} - -func (ul *UnitList) Tags(curLevel int, yield TagYieldFunc) bool { - return yield(curLevel, ul.dragList) && yield(curLevel+1, &ul.searchEditor.widgetEditor) -} - -func NewUnitEditor(m *tracker.Model) *UnitEditor { - ret := &UnitEditor{ - DeleteUnitBtn: new(Clickable), - ClearUnitBtn: new(Clickable), - DisableUnitBtn: new(Clickable), - CopyUnitBtn: new(Clickable), - SelectTypeBtn: new(Clickable), - commentEditor: NewEditor(true, true, text.Start), - paramTable: NewScrollTable(m.Params().Table(), m.ParamVertList().List(), m.Units().List()), - searchList: NewDragList(m.SearchResults().List(), layout.Vertical), - searching: m.UnitSearching(), + for ul.addUnitBtn.Clicked(gtx) { + ul.addUnitAction.Do() + t.UnitSearching().SetValue(true) + ul.searchEditor.Focus() } - ret.caser = cases.Title(language.English) - ret.copyHint = makeHint("Copy unit", " (%s)", "Copy") - ret.disableUnitHint = makeHint("Disable unit", " (%s)", "UnitDisabledToggle") - ret.enableUnitHint = makeHint("Enable unit", " (%s)", "UnitDisabledToggle") - return ret -} - -func (pe *UnitEditor) Layout(gtx C) D { - t := TrackerFromContext(gtx) - pe.update(gtx, t) - editorFunc := pe.layoutRack - if pe.showingChooser() { - editorFunc = pe.layoutUnitTypeChooser - } - return Surface{Gray: 24, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Flexed(1, editorFunc), - layout.Rigid(pe.layoutFooter), - ) - }) -} - -func (pe *UnitEditor) showingChooser() bool { - return pe.searching.Value() -} - -func (pe *UnitEditor) update(gtx C, t *Tracker) { - for pe.CopyUnitBtn.Clicked(gtx) { + for ul.CopyUnitBtn.Clicked(gtx) { if contents, ok := t.Units().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) } } - for pe.SelectTypeBtn.Clicked(gtx) { - pe.ChooseUnitType(t) + for ul.SelectTypeBtn.Clicked(gtx) { + ul.ChooseUnitType(t) } - for pe.commentEditor.Update(gtx, t.UnitComment()) != EditorEventNone { + for ul.commentEditor.Update(gtx, t.UnitComment()) != EditorEventNone { t.FocusPrev(gtx, false) } - for pe.ClearUnitBtn.Clicked(gtx) { + for ul.ClearUnitBtn.Clicked(gtx) { t.ClearUnit().Do() t.UnitSearch().SetValue("") t.UnitSearching().SetValue(true) - pe.searchList.Focus() + ul.searchList.Focus() } for { e, ok := gtx.Event( - key.Filter{Focus: pe.searchList, Name: key.NameEnter}, - key.Filter{Focus: pe.searchList, Name: key.NameReturn}, - key.Filter{Focus: pe.searchList, Name: key.NameEscape}, + key.Filter{Focus: ul.searchList, Name: key.NameEnter}, + key.Filter{Focus: ul.searchList, Name: key.NameReturn}, + key.Filter{Focus: ul.searchList, Name: key.NameEscape}, ) if !ok { break @@ -277,18 +237,18 @@ func (pe *UnitEditor) update(gtx C, t *Tracker) { switch e.Name { case key.NameEscape: t.UnitSearching().SetValue(false) - pe.paramTable.RowTitleList.Focus() + ul.paramTable.RowTitleList.Focus() case key.NameEnter, key.NameReturn: - pe.ChooseUnitType(t) + ul.ChooseUnitType(t) } } } for { e, ok := gtx.Event( - key.Filter{Focus: pe.paramTable, Name: key.NameLeftArrow, Required: key.ModShift, Optional: key.ModShortcut}, - key.Filter{Focus: pe.paramTable, Name: key.NameRightArrow, Required: key.ModShift, Optional: key.ModShortcut}, - key.Filter{Focus: pe.paramTable, Name: key.NameDeleteBackward}, - key.Filter{Focus: pe.paramTable, Name: key.NameDeleteForward}, + key.Filter{Focus: ul.paramTable, Name: key.NameLeftArrow, Required: key.ModShift, Optional: key.ModShortcut}, + key.Filter{Focus: ul.paramTable, Name: key.NameRightArrow, Required: key.ModShift, Optional: key.ModShortcut}, + key.Filter{Focus: ul.paramTable, Name: key.NameDeleteBackward}, + key.Filter{Focus: ul.paramTable, Name: key.NameDeleteForward}, ) if !ok { break @@ -303,50 +263,46 @@ func (pe *UnitEditor) update(gtx C, t *Tracker) { t.Model.Params().Table().Clear() } c := t.Model.Params().Cursor() - if c.X >= 0 && c.Y >= 0 && c.Y < len(pe.Parameters) && c.X < len(pe.Parameters[c.Y]) { - ta := &pe.Parameters[c.Y][c.X].tipArea + if c.X >= 0 && c.Y >= 0 && c.Y < len(ul.Parameters) && c.X < len(ul.Parameters[c.Y]) { + ta := &ul.Parameters[c.Y][c.X].tipArea ta.Appear(gtx.Now) ta.Exit.SetTarget(gtx.Now.Add(ta.ExitDuration)) } } } for { - e, ok := gtx.Event( - key.Filter{Focus: pe.paramTable.RowTitleList, Name: key.NameEnter}, - key.Filter{Focus: pe.paramTable.RowTitleList, Name: key.NameReturn}, - key.Filter{Focus: pe.paramTable.RowTitleList, Name: key.NameLeftArrow}, - key.Filter{Focus: pe.paramTable.RowTitleList, Name: key.NameDeleteBackward}, - ) + e, ok := gtx.Event(key.Filter{Focus: ul.paramTable.RowTitleList, Name: key.NameLeftArrow}) if !ok { break } - if e, ok := e.(key.Event); ok && e.State == key.Press { - switch e.Name { - case key.NameLeftArrow: - t.PatchPanel.instrEditor.unitList.dragList.Focus() - case key.NameDeleteBackward: - t.ClearUnit().Do() - t.UnitSearch().SetValue("") - t.UnitSearching().SetValue(true) - pe.searchList.Focus() - case key.NameEnter, key.NameReturn: - t.Model.AddUnit(e.Modifiers.Contain(key.ModCtrl)).Do() - t.UnitSearch().SetValue("") - t.UnitSearching().SetValue(true) - pe.searchList.Focus() - } + if e, ok := e.(key.Event); ok && e.State == key.Press && e.Name == key.NameLeftArrow { + t.PatchPanel.instrEditor.dragList.Focus() } } } -func (pe *UnitEditor) ChooseUnitType(t *Tracker) { +func (pe *InstrumentEditor) layoutTable(gtx C) D { + t := TrackerFromContext(gtx) + editorFunc := pe.layoutRack + if pe.searching.Value() { + editorFunc = pe.layoutUnitTypeChooser + } + return Surface{Gray: 24, Focus: t.PatchPanel.TreeFocused(gtx)}.Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Flexed(1, editorFunc), + layout.Rigid(pe.layoutFooter), + ) + }) +} + +func (pe *InstrumentEditor) ChooseUnitType(t *Tracker) { if ut, ok := t.SearchResults().Item(pe.searchList.TrackerList.Selected()); ok { t.Units().SetSelectedType(ut) pe.paramTable.RowTitleList.Focus() } } -func (pe *UnitEditor) layoutRack(gtx C) D { +func (pe *InstrumentEditor) layoutRack(gtx C) D { defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop() t := TrackerFromContext(gtx) // create enough parameter widget to match the number of parameters @@ -436,7 +392,7 @@ func (pe *UnitEditor) layoutRack(gtx C) D { return dims } -func (pe *UnitEditor) drawSignals(gtx C, rowTitleWidth int) { +func (pe *InstrumentEditor) drawSignals(gtx C, rowTitleWidth int) { t := TrackerFromContext(gtx) colP := pe.paramTable.ColTitleList.List.Position rowP := pe.paramTable.RowTitleList.List.Position @@ -461,7 +417,7 @@ func (pe *UnitEditor) drawSignals(gtx C, rowTitleWidth int) { } } -func (pe *UnitEditor) drawBackGround(gtx C) { +func (pe *InstrumentEditor) drawBackGround(gtx C) { t := TrackerFromContext(gtx) rowP := pe.paramTable.RowTitleList.List.Position defer op.Offset(image.Pt(0, -rowP.Offset)).Push(gtx.Ops).Pop() @@ -471,14 +427,14 @@ func (pe *UnitEditor) drawBackGround(gtx C) { } } -func (pe *UnitEditor) drawRemoteSendSignal(gtx C, wire tracker.Wire, col, row int) { +func (pe *InstrumentEditor) drawRemoteSendSignal(gtx C, wire tracker.Wire, col, row int) { sy := wire.From - row t := TrackerFromContext(gtx) defer op.Offset(image.Pt(gtx.Dp(5), (sy+1)*gtx.Dp(t.Theme.UnitEditor.Height)-gtx.Dp(16))).Push(gtx.Ops).Pop() Label(t.Theme, &t.Theme.UnitEditor.WireHint, wire.Hint).Layout(gtx) } -func (pe *UnitEditor) drawRemoteReceiveSignal(gtx C, wire tracker.Wire, col, row int, clr color.NRGBA) { +func (pe *InstrumentEditor) drawRemoteReceiveSignal(gtx C, wire tracker.Wire, col, row int, clr color.NRGBA) { ex := wire.To.X - col ey := wire.To.Y - row t := TrackerFromContext(gtx) @@ -506,7 +462,7 @@ func (pe *UnitEditor) drawRemoteReceiveSignal(gtx C, wire tracker.Wire, col, row Label(t.Theme, &t.Theme.UnitEditor.WireHint, wire.Hint).Layout(gtx) } -func (pe *UnitEditor) drawSignal(gtx C, wire tracker.Wire, col, row int, clr color.NRGBA) { +func (pe *InstrumentEditor) drawSignal(gtx C, wire tracker.Wire, col, row int, clr color.NRGBA) { sy := wire.From - row ex := wire.To.X - col ey := wire.To.Y - row @@ -551,7 +507,7 @@ func mulVec(a, b f32.Point) f32.Point { return f32.Pt(a.X*b.X, a.Y*b.Y) } -func (pe *UnitEditor) layoutFooter(gtx C) D { +func (pe *InstrumentEditor) layoutFooter(gtx C) D { t := TrackerFromContext(gtx) text := "Choose unit type" if !t.UnitSearching().Value() { @@ -577,7 +533,7 @@ func (pe *UnitEditor) layoutFooter(gtx C) D { ) } -func (pe *UnitEditor) layoutUnitTypeChooser(gtx C) D { +func (pe *InstrumentEditor) layoutUnitTypeChooser(gtx C) D { t := TrackerFromContext(gtx) var namesArray [256]string names := namesArray[:0] @@ -600,10 +556,3 @@ func (pe *UnitEditor) layoutUnitTypeChooser(gtx C) D { fdl.LayoutScrollBar(gtx) return dims } - -func (t *UnitEditor) Tags(level int, yield TagYieldFunc) bool { - if t.showingChooser() { - return yield(level, t.searchList) && yield(level+1, &t.commentEditor.widgetEditor) - } - return yield(level+1, t.paramTable.RowTitleList) && yield(level, t.paramTable) && yield(level+1, &t.commentEditor.widgetEditor) -} diff --git a/tracker/gioui/patch_panel.go b/tracker/gioui/patch_panel.go index 4eeec62..0975c77 100644 --- a/tracker/gioui/patch_panel.go +++ b/tracker/gioui/patch_panel.go @@ -62,7 +62,7 @@ type ( func NewPatchPanel(model *tracker.Model) *PatchPanel { return &PatchPanel{ - instrEditor: MakeInstrumentEditor(model), + instrEditor: *NewInstrumentEditor(model), instrList: MakeInstrList(model), tools: MakeInstrumentTools(model), instrProps: *NewInstrumentProperties(),