sointu/tracker/uniteditor.go
vsariola 4e1731f6e3 refactor(sointu): move parameter string conversion to song level
Some parameter values need the whole song or at least the unit to give accurate hint what the parameter means. For example: send needs to know the entire song to know what the target unit refers to.
2021-02-07 23:25:15 +02:00

133 lines
4.8 KiB
Go

package tracker
import (
"fmt"
"image"
"image/color"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"github.com/vsariola/sointu"
"golang.org/x/exp/shiny/materialdesign/icons"
)
func (t *Tracker) layoutUnitEditor(gtx C) D {
editorFunc := t.layoutUnitSliders
if t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Type == "" {
editorFunc = t.layoutUnitTypeChooser
}
paint.FillShape(gtx.Ops, unitSurfaceColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y)}.Op())
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Flexed(1, editorFunc),
layout.Rigid(t.layoutUnitFooter()),
)
}
func (t *Tracker) layoutUnitSliders(gtx C) D {
ut, ok := sointu.UnitTypes[t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Type]
if !ok {
return layout.Dimensions{}
}
listElements := func(gtx C, index int) D {
if ut[index].MaxValue < ut[index].MinValue {
return layout.Dimensions{}
}
for len(t.ParameterSliders) <= index {
t.ParameterSliders = append(t.ParameterSliders, new(widget.Float))
}
params := t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Parameters
for t.ParameterSliders[index].Changed() {
params[ut[index].Name] = int(t.ParameterSliders[index].Value)
// TODO: tracker should have functions to update parameters and
// to do this efficiently i.e. not compile the whole patch again
t.LoadSong(t.song)
}
t.ParameterSliders[index].Value = float32(params[ut[index].Name])
sliderStyle := material.Slider(t.Theme, t.ParameterSliders[index], float32(ut[index].MinValue), float32(ut[index].MaxValue))
sliderStyle.Color = t.Theme.Fg
var valueText string
value := params[ut[index].Name]
hint := t.song.ParamHintString(t.CurrentInstrument, t.CurrentUnit, ut[index].Name)
if hint != "" {
valueText = fmt.Sprintf("%v / %v", value, hint)
} else {
valueText = fmt.Sprintf("%v", value)
}
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
layout.Rigid(func(gtx C) D {
gtx.Constraints.Min.X = gtx.Px(unit.Dp(110))
return layout.E.Layout(gtx, Label(ut[index].Name, white))
}),
layout.Rigid(func(gtx C) D {
gtx.Constraints.Min.X = gtx.Px(unit.Dp(200))
return sliderStyle.Layout(gtx)
}),
layout.Rigid(Label(valueText, white)),
)
}
return t.ParameterList.Layout(gtx, len(ut), listElements)
}
func (t *Tracker) layoutUnitFooter() layout.Widget {
return func(gtx C) D {
for t.ClearUnitBtn.Clicked() {
t.ClearUnit()
op.InvalidateOp{}.Add(gtx.Ops)
}
for t.DeleteUnitBtn.Clicked() {
t.DeleteUnit()
op.InvalidateOp{}.Add(gtx.Ops)
}
deleteUnitBtnStyle := material.IconButton(t.Theme, t.DeleteUnitBtn, widgetForIcon(icons.ActionDelete))
deleteUnitBtnStyle.Background = transparent
deleteUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(6))
if len(t.song.Patch.Instruments[t.CurrentInstrument].Units) > 1 {
deleteUnitBtnStyle.Color = primaryColor
} else {
deleteUnitBtnStyle.Color = disabledTextColor
}
if t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Type == "" {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
layout.Rigid(deleteUnitBtnStyle.Layout))
}
clearUnitBtnStyle := material.IconButton(t.Theme, t.ClearUnitBtn, widgetForIcon(icons.ContentClear))
clearUnitBtnStyle.Color = primaryColor
clearUnitBtnStyle.Background = transparent
clearUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(6))
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
layout.Rigid(clearUnitBtnStyle.Layout),
layout.Rigid(deleteUnitBtnStyle.Layout))
}
}
func (t *Tracker) layoutUnitTypeChooser(gtx C) D {
paint.FillShape(gtx.Ops, unitSurfaceColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y)}.Op())
listElem := func(gtx C, i int) D {
for t.ChooseUnitTypeBtns[i].Clicked() {
t.SetUnit(allUnits[i])
}
labelStyle := LabelStyle{Text: allUnits[i], ShadeColor: black, Color: white, Font: labelDefaultFont, FontSize: unit.Sp(12)}
bg := func(gtx C) D {
gtx.Constraints = layout.Exact(image.Pt(120, 20))
var color color.NRGBA
if t.ChooseUnitTypeBtns[i].Hovered() {
color = unitTypeListHighlightColor
}
paint.FillShape(gtx.Ops, color, clip.Rect{Max: image.Pt(gtx.Constraints.Min.X, gtx.Constraints.Min.Y)}.Op())
return D{Size: gtx.Constraints.Min}
}
return layout.Stack{Alignment: layout.W}.Layout(gtx,
layout.Stacked(bg),
layout.Expanded(labelStyle.Layout),
layout.Expanded(t.ChooseUnitTypeBtns[i].Layout))
}
return t.ChooseUnitTypeList.Layout(gtx, len(allUnits), listElem)
}