mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
feat(tracker, gioui): make a Editor for inputting the unit type manually
The keyboard shortcuts were too wonky, so removed them altogether. Had to remove also unit wrapping from model (now it just clamps the parameter to the current units) as it did not play nice with the new editor. Closes #70.
This commit is contained in:
parent
ede70380f2
commit
7885c306ee
@ -19,6 +19,7 @@ import (
|
|||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"gioui.org/widget/material"
|
"gioui.org/widget/material"
|
||||||
"gioui.org/x/eventx"
|
"gioui.org/x/eventx"
|
||||||
|
"github.com/vsariola/sointu/tracker"
|
||||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@ -33,6 +34,7 @@ type InstrumentEditor struct {
|
|||||||
commentExpandBtn *widget.Clickable
|
commentExpandBtn *widget.Clickable
|
||||||
commentEditor *widget.Editor
|
commentEditor *widget.Editor
|
||||||
nameEditor *widget.Editor
|
nameEditor *widget.Editor
|
||||||
|
unitTypeEditor *widget.Editor
|
||||||
instrumentDragList *DragList
|
instrumentDragList *DragList
|
||||||
instrumentScrollBar *ScrollBar
|
instrumentScrollBar *ScrollBar
|
||||||
unitDragList *DragList
|
unitDragList *DragList
|
||||||
@ -56,6 +58,7 @@ func NewInstrumentEditor() *InstrumentEditor {
|
|||||||
commentExpandBtn: new(widget.Clickable),
|
commentExpandBtn: new(widget.Clickable),
|
||||||
commentEditor: new(widget.Editor),
|
commentEditor: new(widget.Editor),
|
||||||
nameEditor: &widget.Editor{SingleLine: true, Submit: true, Alignment: text.Middle},
|
nameEditor: &widget.Editor{SingleLine: true, Submit: true, Alignment: text.Middle},
|
||||||
|
unitTypeEditor: &widget.Editor{SingleLine: true, Submit: true, Alignment: text.Start},
|
||||||
instrumentDragList: &DragList{List: &layout.List{Axis: layout.Horizontal}, HoverItem: -1},
|
instrumentDragList: &DragList{List: &layout.List{Axis: layout.Horizontal}, HoverItem: -1},
|
||||||
instrumentScrollBar: &ScrollBar{Axis: layout.Horizontal},
|
instrumentScrollBar: &ScrollBar{Axis: layout.Horizontal},
|
||||||
unitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}, HoverItem: -1},
|
unitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}, HoverItem: -1},
|
||||||
@ -78,7 +81,7 @@ func (ie *InstrumentEditor) Focused() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ie *InstrumentEditor) ChildFocused() bool {
|
func (ie *InstrumentEditor) ChildFocused() bool {
|
||||||
return ie.paramEditor.Focused() || ie.instrumentDragList.Focused() || ie.commentEditor.Focused() || ie.nameEditor.Focused()
|
return ie.paramEditor.Focused() || ie.instrumentDragList.Focused() || ie.commentEditor.Focused() || ie.nameEditor.Focused() || ie.unitTypeEditor.Focused()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
||||||
@ -349,11 +352,8 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
|||||||
element := func(gtx C, i int) D {
|
element := func(gtx C, i int) D {
|
||||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Px(unit.Dp(120)), gtx.Px(unit.Dp(20))))
|
gtx.Constraints = layout.Exact(image.Pt(gtx.Px(unit.Dp(120)), gtx.Px(unit.Dp(20))))
|
||||||
u := units[i]
|
u := units[i]
|
||||||
unitNameLabel := LabelStyle{Text: u.Type, ShadeColor: black, Color: white, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
var color color.NRGBA = white
|
||||||
if unitNameLabel.Text == "" {
|
|
||||||
unitNameLabel.Text = "---"
|
|
||||||
unitNameLabel.Alignment = layout.Center
|
|
||||||
}
|
|
||||||
var stackText string
|
var stackText string
|
||||||
if i < len(ie.stackUse) {
|
if i < len(ie.stackUse) {
|
||||||
stackText = strconv.FormatInt(int64(ie.stackUse[i]), 10)
|
stackText = strconv.FormatInt(int64(ie.stackUse[i]), 10)
|
||||||
@ -362,27 +362,80 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
|||||||
prevStackUse = ie.stackUse[i-1]
|
prevStackUse = ie.stackUse[i-1]
|
||||||
}
|
}
|
||||||
if stackNeed := u.StackNeed(); stackNeed > prevStackUse {
|
if stackNeed := u.StackNeed(); stackNeed > prevStackUse {
|
||||||
unitNameLabel.Color = errorColor
|
color = errorColor
|
||||||
typeString := u.Type
|
typeString := u.Type
|
||||||
if u.Parameters["stereo"] == 1 {
|
if u.Parameters["stereo"] == 1 {
|
||||||
typeString += " (stereo)"
|
typeString += " (stereo)"
|
||||||
}
|
}
|
||||||
t.Alert.Update(fmt.Sprintf("%v needs at least %v input signals, got %v", typeString, stackNeed, prevStackUse), Error, 0)
|
t.Alert.Update(fmt.Sprintf("%v needs at least %v input signals, got %v", typeString, stackNeed, prevStackUse), Error, 0)
|
||||||
} else if i == len(units)-1 && ie.stackUse[i] != 0 {
|
} else if i == len(units)-1 && ie.stackUse[i] != 0 {
|
||||||
unitNameLabel.Color = warningColor
|
color = warningColor
|
||||||
t.Alert.Update(fmt.Sprintf("Instrument leaves %v signal(s) on the stack", ie.stackUse[i]), Warning, 0)
|
t.Alert.Update(fmt.Sprintf("Instrument leaves %v signal(s) on the stack", ie.stackUse[i]), Warning, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var unitName layout.Widget
|
||||||
|
if i == t.UnitIndex() {
|
||||||
|
for _, ev := range ie.unitTypeEditor.Events() {
|
||||||
|
_, ok := ev.(widget.SubmitEvent)
|
||||||
|
if ok {
|
||||||
|
ie.unitDragList.Focus()
|
||||||
|
if text := ie.unitTypeEditor.Text(); text != "" {
|
||||||
|
for _, n := range tracker.UnitTypeNames {
|
||||||
|
if strings.HasPrefix(n, ie.unitTypeEditor.Text()) {
|
||||||
|
t.SetUnitType(n)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.SetUnitType("")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ie.unitTypeEditor.Focused() && !ie.paramEditor.Focused() && ie.unitTypeEditor.Text() != t.Unit().Type {
|
||||||
|
ie.unitTypeEditor.SetText(t.Unit().Type)
|
||||||
|
}
|
||||||
|
editor := material.Editor(t.Theme, ie.unitTypeEditor, "---")
|
||||||
|
editor.Color = color
|
||||||
|
editor.HintColor = instrumentNameHintColor
|
||||||
|
editor.TextSize = unit.Sp(12)
|
||||||
|
editor.Font = labelDefaultFont
|
||||||
|
unitName = func(gtx C) D {
|
||||||
|
spy, spiedGtx := eventx.Enspy(gtx)
|
||||||
|
ret := editor.Layout(spiedGtx)
|
||||||
|
for _, group := range spy.AllEvents() {
|
||||||
|
for _, event := range group.Items {
|
||||||
|
switch e := event.(type) {
|
||||||
|
case key.Event:
|
||||||
|
if e.Name == key.NameEscape {
|
||||||
|
ie.unitDragList.Focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unitNameLabel := LabelStyle{Text: u.Type, ShadeColor: black, Color: color, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
||||||
|
if unitNameLabel.Text == "" {
|
||||||
|
unitNameLabel.Text = "---"
|
||||||
|
}
|
||||||
|
unitName = unitNameLabel.Layout
|
||||||
|
}
|
||||||
|
|
||||||
stackLabel := LabelStyle{Text: stackText, ShadeColor: black, Color: mediumEmphasisTextColor, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
stackLabel := LabelStyle{Text: stackText, ShadeColor: black, Color: mediumEmphasisTextColor, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
||||||
rightMargin := layout.Inset{Right: unit.Dp(10)}
|
rightMargin := layout.Inset{Right: unit.Dp(10)}
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Flexed(1, unitNameLabel.Layout),
|
layout.Flexed(1, unitName),
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return rightMargin.Layout(gtx, stackLabel.Layout)
|
return rightMargin.Layout(gtx, stackLabel.Layout)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer op.Save(gtx.Ops).Load()
|
||||||
|
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||||
unitList := FilledDragList(t.Theme, ie.unitDragList, len(units), element, t.SwapUnits)
|
unitList := FilledDragList(t.Theme, ie.unitDragList, len(units), element, t.SwapUnits)
|
||||||
ie.unitDragList.SelectedItem = t.UnitIndex()
|
ie.unitDragList.SelectedItem = t.UnitIndex()
|
||||||
return Surface{Gray: 30, Focus: ie.wasFocused}.Layout(gtx, func(gtx C) D {
|
return Surface{Gray: 30, Focus: ie.wasFocused}.Layout(gtx, func(gtx C) D {
|
||||||
@ -395,41 +448,44 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
|||||||
prevUnitIndex := t.UnitIndex()
|
prevUnitIndex := t.UnitIndex()
|
||||||
if t.UnitIndex() != ie.unitDragList.SelectedItem {
|
if t.UnitIndex() != ie.unitDragList.SelectedItem {
|
||||||
t.SetUnitIndex(ie.unitDragList.SelectedItem)
|
t.SetUnitIndex(ie.unitDragList.SelectedItem)
|
||||||
|
ie.unitTypeEditor.SetText(t.Unit().Type)
|
||||||
}
|
}
|
||||||
for _, group := range spy.AllEvents() {
|
if ie.unitDragList.Focused() {
|
||||||
for _, event := range group.Items {
|
for _, group := range spy.AllEvents() {
|
||||||
switch e := event.(type) {
|
for _, event := range group.Items {
|
||||||
case key.Event:
|
switch e := event.(type) {
|
||||||
switch e.State {
|
case key.Event:
|
||||||
case key.Press:
|
switch e.State {
|
||||||
switch e.Name {
|
case key.Press:
|
||||||
case key.NameUpArrow:
|
switch e.Name {
|
||||||
if prevUnitIndex == 0 {
|
case key.NameUpArrow:
|
||||||
ie.instrumentDragList.Focus()
|
if prevUnitIndex == 0 {
|
||||||
|
ie.instrumentDragList.Focus()
|
||||||
|
}
|
||||||
|
case key.NameRightArrow:
|
||||||
|
ie.paramEditor.Focus()
|
||||||
|
case key.NameDeleteBackward:
|
||||||
|
t.SetUnitType("")
|
||||||
|
ie.unitTypeEditor.Focus()
|
||||||
|
l := len(ie.unitTypeEditor.Text())
|
||||||
|
ie.unitTypeEditor.SetCaret(l, l)
|
||||||
|
case key.NameDeleteForward:
|
||||||
|
t.DeleteUnit(true)
|
||||||
|
case key.NameReturn:
|
||||||
|
if e.Modifiers.Contain(key.ModShortcut) {
|
||||||
|
t.AddUnit(true)
|
||||||
|
}
|
||||||
|
ie.unitTypeEditor.Focus()
|
||||||
|
l := len(ie.unitTypeEditor.Text())
|
||||||
|
ie.unitTypeEditor.SetCaret(l, l)
|
||||||
}
|
}
|
||||||
case key.NameRightArrow:
|
|
||||||
ie.paramEditor.Focus()
|
|
||||||
case key.NameDeleteForward, key.NameDeleteBackward:
|
|
||||||
t.DeleteUnit(e.Name == key.NameDeleteForward)
|
|
||||||
case key.NameReturn:
|
|
||||||
t.AddUnit(!e.Modifiers.Contain(key.ModShortcut))
|
|
||||||
}
|
|
||||||
name := e.Name
|
|
||||||
if !e.Modifiers.Contain(key.ModShift) {
|
|
||||||
name = strings.ToLower(name)
|
|
||||||
}
|
|
||||||
if val, ok := unitKeyMap[name]; ok {
|
|
||||||
if e.Modifiers.Contain(key.ModShortcut) {
|
if e.Modifiers.Contain(key.ModShortcut) {
|
||||||
t.SetUnitType(val)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
t.JammingPressed(e)
|
||||||
|
case key.Release:
|
||||||
|
t.JammingReleased(e)
|
||||||
}
|
}
|
||||||
if e.Modifiers.Contain(key.ModShortcut) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.JammingPressed(e)
|
|
||||||
case key.Release:
|
|
||||||
t.JammingReleased(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,38 +43,6 @@ var noteMap = map[string]int{
|
|||||||
"P": 16,
|
"P": 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
var unitKeyMap = map[string]string{
|
|
||||||
"e": "envelope",
|
|
||||||
"o": "oscillator",
|
|
||||||
"m": "mulp",
|
|
||||||
"M": "mul",
|
|
||||||
"a": "addp",
|
|
||||||
"A": "add",
|
|
||||||
"p": "pan",
|
|
||||||
"S": "push",
|
|
||||||
"P": "pop",
|
|
||||||
"O": "out",
|
|
||||||
"l": "loadnote",
|
|
||||||
"L": "loadval",
|
|
||||||
"h": "xch",
|
|
||||||
"d": "delay",
|
|
||||||
"D": "distort",
|
|
||||||
"H": "hold",
|
|
||||||
"b": "crush",
|
|
||||||
"g": "gain",
|
|
||||||
"i": "invgain",
|
|
||||||
"f": "filter",
|
|
||||||
"I": "clip",
|
|
||||||
"E": "speed",
|
|
||||||
"r": "compressor",
|
|
||||||
"u": "outaux",
|
|
||||||
"U": "aux",
|
|
||||||
"s": "send",
|
|
||||||
"n": "noise",
|
|
||||||
"N": "in",
|
|
||||||
"R": "receive",
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyEvent handles incoming key events and returns true if repaint is needed.
|
// KeyEvent handles incoming key events and returns true if repaint is needed.
|
||||||
func (t *Tracker) KeyEvent(e key.Event) bool {
|
func (t *Tracker) KeyEvent(e key.Event) bool {
|
||||||
if e.State == key.Press {
|
if e.State == key.Press {
|
||||||
|
@ -108,7 +108,7 @@ func (pe *ParamEditor) Bind(t *Tracker) layout.Widget {
|
|||||||
key.FocusOp{Tag: &pe.tag}.Add(gtx.Ops)
|
key.FocusOp{Tag: &pe.tag}.Add(gtx.Ops)
|
||||||
}
|
}
|
||||||
editorFunc := pe.layoutUnitSliders
|
editorFunc := pe.layoutUnitSliders
|
||||||
if t.Unit().Type == "" {
|
if y := t.Unit().Type; y == "" || y != t.InstrumentEditor.unitTypeEditor.Text() {
|
||||||
editorFunc = pe.layoutUnitTypeChooser
|
editorFunc = pe.layoutUnitTypeChooser
|
||||||
}
|
}
|
||||||
return Surface{Gray: 24, Focus: t.InstrumentEditor.wasFocused}.Layout(gtx, func(gtx C) D {
|
return Surface{Gray: 24, Focus: t.InstrumentEditor.wasFocused}.Layout(gtx, func(gtx C) D {
|
||||||
@ -210,8 +210,13 @@ func (pe *ParamEditor) layoutUnitTypeChooser(gtx C, t *Tracker) D {
|
|||||||
listElem := func(gtx C, i int) D {
|
listElem := func(gtx C, i int) D {
|
||||||
for pe.ChooseUnitTypeBtns[i].Clicked() {
|
for pe.ChooseUnitTypeBtns[i].Clicked() {
|
||||||
t.SetUnitType(tracker.UnitTypeNames[i])
|
t.SetUnitType(tracker.UnitTypeNames[i])
|
||||||
|
t.InstrumentEditor.unitTypeEditor.SetText(tracker.UnitTypeNames[i])
|
||||||
}
|
}
|
||||||
labelStyle := LabelStyle{Text: tracker.UnitTypeNames[i], ShadeColor: black, Color: white, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
text := tracker.UnitTypeNames[i]
|
||||||
|
if t.InstrumentEditor.unitTypeEditor.Focused() && !strings.HasPrefix(text, t.InstrumentEditor.unitTypeEditor.Text()) {
|
||||||
|
return D{}
|
||||||
|
}
|
||||||
|
labelStyle := LabelStyle{Text: text, ShadeColor: black, Color: white, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
||||||
bg := func(gtx C) D {
|
bg := func(gtx C) D {
|
||||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X, 20))
|
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X, 20))
|
||||||
var color color.NRGBA
|
var color color.NRGBA
|
||||||
|
@ -794,22 +794,7 @@ func (m *Model) clampPositions() {
|
|||||||
}
|
}
|
||||||
m.instrIndex = clamp(m.instrIndex, 0, len(m.song.Patch)-1)
|
m.instrIndex = clamp(m.instrIndex, 0, len(m.song.Patch)-1)
|
||||||
m.unitIndex = clamp(m.unitIndex, 0, len(m.Instrument().Units)-1)
|
m.unitIndex = clamp(m.unitIndex, 0, len(m.Instrument().Units)-1)
|
||||||
for m.paramIndex < 0 {
|
m.paramIndex = clamp(m.paramIndex, 0, m.NumParams()-1)
|
||||||
if m.unitIndex == 0 {
|
|
||||||
m.paramIndex = 0
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.unitIndex--
|
|
||||||
m.paramIndex += m.NumParams()
|
|
||||||
}
|
|
||||||
for n := m.NumParams(); m.paramIndex >= n; n = m.NumParams() {
|
|
||||||
if m.unitIndex == len(m.Instrument().Units)-1 {
|
|
||||||
m.paramIndex = n - 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.paramIndex -= n
|
|
||||||
m.unitIndex++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) NumParams() int {
|
func (m *Model) NumParams() int {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user