mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
parent
160eb8eea9
commit
9779beee99
@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Units can have comments, to make it easier to distinguish between units of
|
||||
same type within an instrument. These comments are also shown when choosing
|
||||
the send target. ([#114][i114])
|
||||
- A toggle button for copying non-unique patterns before editing. When enabled
|
||||
and if the pattern is used in multiple places, the pattern is copied first.
|
||||
([#77][i77])
|
||||
@ -232,6 +235,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
[i77]: https://github.com/vsariola/sointu/issues/77
|
||||
[i94]: https://github.com/vsariola/sointu/issues/94
|
||||
[i112]: https://github.com/vsariola/sointu/issues/112
|
||||
[i114]: https://github.com/vsariola/sointu/issues/114
|
||||
[i116]: https://github.com/vsariola/sointu/issues/116
|
||||
[i120]: https://github.com/vsariola/sointu/issues/120
|
||||
[i121]: https://github.com/vsariola/sointu/issues/121
|
||||
|
7
patch.go
7
patch.go
@ -49,6 +49,11 @@ type (
|
||||
// Disabled is a flag that can be set to true to disable the unit.
|
||||
// Disabled units are considered to be not present in the patch.
|
||||
Disabled bool `yaml:",omitempty"`
|
||||
|
||||
// Comment is a free-form comment about the unit that can be displayed
|
||||
// instead of/besides the type of the unit in the GUI, to make it easier
|
||||
// to track what the unit is doing & to make it easier to target sends.
|
||||
Comment string `yaml:",omitempty"`
|
||||
}
|
||||
|
||||
// UnitParameter documents one parameter that an unit takes
|
||||
@ -291,7 +296,7 @@ func (u *Unit) Copy() Unit {
|
||||
}
|
||||
varArgs := make([]int, len(u.VarArgs))
|
||||
copy(varArgs, u.VarArgs)
|
||||
return Unit{Type: u.Type, Parameters: parameters, VarArgs: varArgs, ID: u.ID, Disabled: u.Disabled}
|
||||
return Unit{Type: u.Type, Parameters: parameters, VarArgs: varArgs, ID: u.ID, Disabled: u.Disabled, Comment: u.Comment}
|
||||
}
|
||||
|
||||
// StackChange returns how this unit will affect the signal stack. "pop" and
|
||||
|
@ -393,7 +393,8 @@ func (ie *InstrumentEditor) layoutUnitList(gtx C, t *Tracker) D {
|
||||
count := intMin(ie.unitDragList.TrackerList.Count(), 256)
|
||||
|
||||
element := func(gtx C, i int) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(unit.Dp(120)), gtx.Dp(unit.Dp(20))))
|
||||
gtx.Constraints.Max.Y = gtx.Dp(20)
|
||||
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
|
||||
if i < 0 || i > 255 {
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
@ -418,7 +419,7 @@ func (ie *InstrumentEditor) layoutUnitList(gtx C, t *Tracker) D {
|
||||
stackLabel := LabelStyle{Text: stackText, ShadeColor: black, Color: mediumEmphasisTextColor, Font: labelDefaultFont, FontSize: unit.Sp(12), Shaper: t.Theme.Shaper}
|
||||
rightMargin := layout.Inset{Right: unit.Dp(10)}
|
||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
layout.Rigid(func(gtx C) D {
|
||||
if i == ie.unitDragList.TrackerList.Selected() {
|
||||
editor := material.Editor(t.Theme, ie.searchEditor, "---")
|
||||
editor.Color = color
|
||||
@ -473,6 +474,11 @@ func (ie *InstrumentEditor) layoutUnitList(gtx C, t *Tracker) D {
|
||||
return unitNameLabel.Layout(gtx)
|
||||
}
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
unitNameLabel := LabelStyle{Text: u.Comment, ShadeColor: black, Color: mediumEmphasisTextColor, Font: f, FontSize: unit.Sp(12), Shaper: t.Theme.Shaper}
|
||||
inset := layout.Inset{Left: unit.Dp(5)}
|
||||
return inset.Layout(gtx, unitNameLabel.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return rightMargin.Layout(gtx, stackLabel.Layout)
|
||||
}),
|
||||
@ -517,7 +523,7 @@ func (ie *InstrumentEditor) layoutUnitList(gtx C, t *Tracker) D {
|
||||
return layout.Stack{Alignment: layout.SE}.Layout(gtx,
|
||||
layout.Expanded(func(gtx C) D {
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(unit.Dp(120)), gtx.Constraints.Max.Y))
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(140), gtx.Constraints.Max.Y))
|
||||
dims := unitList.Layout(gtx)
|
||||
unitList.LayoutScrollBar(gtx)
|
||||
return dims
|
||||
|
@ -32,7 +32,9 @@ type UnitEditor struct {
|
||||
ClearUnitBtn *ActionClickable
|
||||
DisableUnitBtn *BoolClickable
|
||||
SelectTypeBtn *widget.Clickable
|
||||
commentEditor *widget.Editor
|
||||
caser cases.Caser
|
||||
commentFilters []event.Filter
|
||||
|
||||
copyHint string
|
||||
disableUnitHint string
|
||||
@ -46,10 +48,19 @@ func NewUnitEditor(m *tracker.Model) *UnitEditor {
|
||||
DisableUnitBtn: NewBoolClickable(m.UnitDisabled().Bool()),
|
||||
CopyUnitBtn: new(TipClickable),
|
||||
SelectTypeBtn: new(widget.Clickable),
|
||||
commentEditor: &widget.Editor{SingleLine: true, Submit: true, MaxLen: 16},
|
||||
sliderList: NewDragList(m.Params().List(), layout.Vertical),
|
||||
searchList: NewDragList(m.SearchResults().List(), layout.Vertical),
|
||||
}
|
||||
ret.caser = cases.Title(language.English)
|
||||
for k, a := range keyBindingMap {
|
||||
if len(a) < 4 || a[:4] != "Note" {
|
||||
continue
|
||||
}
|
||||
ret.commentFilters = append(ret.commentFilters, key.Filter{Name: k.Name, Required: k.Modifiers, Focus: ret.commentEditor})
|
||||
}
|
||||
ret.commentFilters = append(ret.commentFilters, key.Filter{Name: key.NameSpace, Focus: ret.commentEditor})
|
||||
ret.commentFilters = append(ret.commentFilters, key.Filter{Name: key.NameEscape, Focus: ret.commentEditor})
|
||||
ret.copyHint = makeHint("Copy unit", " (%s)", "Copy")
|
||||
ret.disableUnitHint = makeHint("Disable unit", " (%s)", "UnitDisabledToggle")
|
||||
ret.enableUnitHint = makeHint("Enable unit", " (%s)", "UnitDisabledToggle")
|
||||
@ -139,6 +150,11 @@ func (pe *UnitEditor) layoutFooter(gtx C, t *Tracker) D {
|
||||
text = pe.caser.String(text)
|
||||
}
|
||||
hintText := Label(text, white, t.Theme.Shaper)
|
||||
commentStyle := material.Editor(t.Theme, pe.commentEditor, "---")
|
||||
commentStyle.Font = labelDefaultFont
|
||||
commentStyle.TextSize = labelDefaultFontSize
|
||||
commentStyle.Color = mediumEmphasisTextColor
|
||||
commentStyle.HintColor = mediumEmphasisTextColor
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(deleteUnitBtnStyle.Layout),
|
||||
layout.Rigid(copyUnitBtnStyle.Layout),
|
||||
@ -151,7 +167,39 @@ func (pe *UnitEditor) layoutFooter(gtx C, t *Tracker) D {
|
||||
}
|
||||
return D{Size: image.Pt(gtx.Dp(unit.Dp(48)), dims.Size.Y)}
|
||||
}),
|
||||
layout.Flexed(1, hintText),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints.Min.X = gtx.Dp(120)
|
||||
return hintText(gtx)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
s := t.UnitComment().String()
|
||||
if pe.commentEditor.Text() != s.Value() {
|
||||
pe.commentEditor.SetText(s.Value())
|
||||
}
|
||||
for {
|
||||
ev, ok := pe.commentEditor.Update(gtx)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
_, ok = ev.(widget.SubmitEvent)
|
||||
if ok {
|
||||
t.InstrumentEditor.Focus()
|
||||
continue
|
||||
}
|
||||
}
|
||||
for {
|
||||
event, ok := gtx.Event(pe.commentFilters...)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if e, ok := event.(key.Event); ok && e.State == key.Press && e.Name == key.NameEscape {
|
||||
t.InstrumentEditor.Focus()
|
||||
}
|
||||
}
|
||||
ret := commentStyle.Layout(gtx)
|
||||
s.Set(commentStyle.Editor.Text())
|
||||
return ret
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@ -317,11 +365,11 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
targetInstrument := p.tracker.Instrument(targetI)
|
||||
instrName = targetInstrument.Name
|
||||
units := targetInstrument.Units
|
||||
unitName = fmt.Sprintf("%v: %v", targetU, units[targetU].Type)
|
||||
unitName = fmt.Sprintf("%d: %s %s", targetU, units[targetU].Type, units[targetU].Comment)
|
||||
unitItems = make([]MenuItem, len(units))
|
||||
for j, unit := range units {
|
||||
id := unit.ID
|
||||
unitItems[j].Text = fmt.Sprintf("%v: %v", j, unit.Type)
|
||||
unitItems[j].Text = fmt.Sprintf("%d: %s %s", j, unit.Type, unit.Comment)
|
||||
unitItems[j].IconBytes = icons.NavigationChevronRight
|
||||
unitItems[j].Doer = tracker.Allow(func() {
|
||||
tracker.Int{IntData: p.w.Parameter}.Set(id)
|
||||
@ -333,7 +381,7 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
layout.Rigid(p.tracker.layoutMenu(gtx, instrName, &p.w.instrBtn, &p.w.instrMenu, unit.Dp(200),
|
||||
instrItems...,
|
||||
)),
|
||||
layout.Rigid(p.tracker.layoutMenu(gtx, unitName, &p.w.unitBtn, &p.w.unitMenu, unit.Dp(200),
|
||||
layout.Rigid(p.tracker.layoutMenu(gtx, unitName, &p.w.unitBtn, &p.w.unitMenu, unit.Dp(240),
|
||||
unitItems...,
|
||||
)),
|
||||
)
|
||||
|
@ -33,7 +33,7 @@ type (
|
||||
}
|
||||
|
||||
UnitListItem struct {
|
||||
Type string
|
||||
Type, Comment string
|
||||
Disabled bool
|
||||
StackNeed, StackBefore, StackAfter int
|
||||
}
|
||||
@ -332,6 +332,7 @@ func (v *Units) Iterate(yield UnitYieldFunc) {
|
||||
stackAfter := stackBefore + unit.StackChange()
|
||||
if !yield(UnitListItem{
|
||||
Type: unit.Type,
|
||||
Comment: unit.Comment,
|
||||
Disabled: unit.Disabled,
|
||||
StackNeed: unit.StackNeed(),
|
||||
StackBefore: stackBefore,
|
||||
|
@ -15,6 +15,7 @@ type (
|
||||
InstrumentName Model
|
||||
InstrumentComment Model
|
||||
UnitSearch Model
|
||||
UnitComment Model
|
||||
)
|
||||
|
||||
func (v String) Set(value string) {
|
||||
@ -30,6 +31,7 @@ func (m *Model) FilePath() *FilePath { return (*FilePath)(m) }
|
||||
func (m *Model) InstrumentName() *InstrumentName { return (*InstrumentName)(m) }
|
||||
func (m *Model) InstrumentComment() *InstrumentComment { return (*InstrumentComment)(m) }
|
||||
func (m *Model) UnitSearch() *UnitSearch { return (*UnitSearch)(m) }
|
||||
func (m *Model) UnitComment() *UnitComment { return (*UnitComment)(m) }
|
||||
|
||||
// FilePathString
|
||||
|
||||
@ -108,3 +110,26 @@ func (v *InstrumentComment) setValue(value string) {
|
||||
func (v *InstrumentComment) change(kind string) func() {
|
||||
return (*Model)(v).change("InstrumentComment."+kind, PatchChange, MinorChange)
|
||||
}
|
||||
|
||||
// UnitComment
|
||||
|
||||
func (v *UnitComment) String() String { return String{v} }
|
||||
func (v *UnitComment) Value() string {
|
||||
if v.d.InstrIndex < 0 || v.d.InstrIndex >= len(v.d.Song.Patch) ||
|
||||
v.d.UnitIndex < 0 || v.d.UnitIndex >= len(v.d.Song.Patch[v.d.InstrIndex].Units) {
|
||||
return ""
|
||||
}
|
||||
return v.d.Song.Patch[v.d.InstrIndex].Units[v.d.UnitIndex].Comment
|
||||
}
|
||||
|
||||
func (v *UnitComment) setValue(value string) {
|
||||
if v.d.InstrIndex < 0 || v.d.InstrIndex >= len(v.d.Song.Patch) ||
|
||||
v.d.UnitIndex < 0 || v.d.UnitIndex >= len(v.d.Song.Patch[v.d.InstrIndex].Units) {
|
||||
return
|
||||
}
|
||||
v.d.Song.Patch[v.d.InstrIndex].Units[v.d.UnitIndex].Comment = value
|
||||
}
|
||||
|
||||
func (v *UnitComment) change(kind string) func() {
|
||||
return (*Model)(v).change("UnitComment."+kind, PatchChange, MinorChange)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user