mirror of
https://github.com/vsariola/sointu.git
synced 2026-02-16 05:03:18 -05:00
169 lines
7.6 KiB
Go
169 lines
7.6 KiB
Go
package gioui
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
|
|
"gioui.org/layout"
|
|
"gioui.org/op/clip"
|
|
"gioui.org/op/paint"
|
|
"gioui.org/text"
|
|
"gioui.org/unit"
|
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
|
)
|
|
|
|
type (
|
|
InstrumentProperties struct {
|
|
nameEditor *Editor
|
|
commentEditor *Editor
|
|
list *layout.List
|
|
soloBtn *Clickable
|
|
muteBtn *Clickable
|
|
threadBtns [4]*Clickable
|
|
soloHint string
|
|
unsoloHint string
|
|
muteHint string
|
|
unmuteHint string
|
|
voices *NumericUpDownState
|
|
splitInstrumentBtn *Clickable
|
|
splitInstrumentHint string
|
|
|
|
ignoreNoteOff *Clickable
|
|
velocity *Clickable
|
|
change *Clickable
|
|
noteStart *NumericUpDownState
|
|
noteEnd *NumericUpDownState
|
|
transpose *NumericUpDownState
|
|
midiChannel *NumericUpDownState
|
|
}
|
|
)
|
|
|
|
func NewInstrumentProperties() *InstrumentProperties {
|
|
ret := &InstrumentProperties{
|
|
list: &layout.List{Axis: layout.Vertical},
|
|
nameEditor: NewEditor(true, true, text.Start),
|
|
commentEditor: NewEditor(false, false, text.Start),
|
|
soloBtn: new(Clickable),
|
|
muteBtn: new(Clickable),
|
|
voices: NewNumericUpDownState(),
|
|
splitInstrumentBtn: new(Clickable),
|
|
threadBtns: [4]*Clickable{new(Clickable), new(Clickable), new(Clickable), new(Clickable)},
|
|
ignoreNoteOff: new(Clickable),
|
|
velocity: new(Clickable),
|
|
change: new(Clickable),
|
|
noteStart: NewNumericUpDownState(),
|
|
noteEnd: NewNumericUpDownState(),
|
|
transpose: NewNumericUpDownState(),
|
|
midiChannel: NewNumericUpDownState(),
|
|
}
|
|
ret.soloHint = makeHint("Solo", " (%s)", "SoloToggle")
|
|
ret.unsoloHint = makeHint("Unsolo", " (%s)", "SoloToggle")
|
|
ret.muteHint = makeHint("Mute", " (%s)", "MuteToggle")
|
|
ret.unmuteHint = makeHint("Unmute", " (%s)", "MuteToggle")
|
|
ret.splitInstrumentHint = makeHint("Split instrument", " (%s)", "SplitInstrument")
|
|
return ret
|
|
}
|
|
|
|
func (ip *InstrumentProperties) Tags(level int, yield TagYieldFunc) bool {
|
|
return yield(level, &ip.commentEditor.widgetEditor)
|
|
}
|
|
|
|
// layout
|
|
func (ip *InstrumentProperties) layout(gtx C) D {
|
|
// get tracker from values
|
|
tr := TrackerFromContext(gtx)
|
|
voiceLine := func(gtx C) D {
|
|
splitInstrumentBtn := ActionIconBtn(tr.Instrument().Split(), tr.Theme, ip.splitInstrumentBtn, icons.CommunicationCallSplit, ip.splitInstrumentHint)
|
|
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
|
layout.Rigid(func(gtx C) D {
|
|
instrumentVoices := NumUpDown(tr.Model.Instrument().Voices(), tr.Theme, ip.voices, "Number of voices for this instrument")
|
|
return instrumentVoices.Layout(gtx)
|
|
}),
|
|
layout.Rigid(splitInstrumentBtn.Layout),
|
|
)
|
|
}
|
|
|
|
thread1btn := ToggleIconBtn(tr.Instrument().Thread1(), tr.Theme, ip.threadBtns[0], icons.ImageCropSquare, icons.ImageFilter1, "Do not render instrument on thread 1", "Render instrument on thread 1")
|
|
thread2btn := ToggleIconBtn(tr.Instrument().Thread2(), tr.Theme, ip.threadBtns[1], icons.ImageCropSquare, icons.ImageFilter2, "Do not render instrument on thread 2", "Render instrument on thread 2")
|
|
thread3btn := ToggleIconBtn(tr.Instrument().Thread3(), tr.Theme, ip.threadBtns[2], icons.ImageCropSquare, icons.ImageFilter3, "Do not render instrument on thread 3", "Render instrument on thread 3")
|
|
thread4btn := ToggleIconBtn(tr.Instrument().Thread4(), tr.Theme, ip.threadBtns[3], icons.ImageCropSquare, icons.ImageFilter4, "Do not render instrument on thread 4", "Render instrument on thread 4")
|
|
|
|
threadbtnline := func(gtx C) D {
|
|
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
|
layout.Rigid(thread1btn.Layout),
|
|
layout.Rigid(thread2btn.Layout),
|
|
layout.Rigid(thread3btn.Layout),
|
|
layout.Rigid(thread4btn.Layout),
|
|
)
|
|
}
|
|
gtx.Constraints.Max.X = min(gtx.Dp(300), gtx.Constraints.Max.X)
|
|
gtx.Constraints.Min.X = min(gtx.Constraints.Max.X, gtx.Constraints.Min.X)
|
|
return ip.list.Layout(gtx, 18, func(gtx C, index int) D {
|
|
switch index {
|
|
case 0:
|
|
return layoutInstrumentPropertyLine(gtx, "Name", func(gtx C) D {
|
|
return ip.nameEditor.Layout(gtx, tr.Instrument().Name(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Instr")
|
|
})
|
|
case 2:
|
|
return layoutInstrumentPropertyLine(gtx, "Voices", voiceLine)
|
|
case 4:
|
|
muteBtn := ToggleIconBtn(tr.Instrument().Mute(), tr.Theme, ip.muteBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.muteHint, ip.unmuteHint)
|
|
return layoutInstrumentPropertyLine(gtx, "Mute", muteBtn.Layout)
|
|
case 5:
|
|
soloBtn := ToggleIconBtn(tr.Instrument().Solo(), tr.Theme, ip.soloBtn, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, ip.soloHint, ip.unsoloHint)
|
|
return layoutInstrumentPropertyLine(gtx, "Solo", soloBtn.Layout)
|
|
case 7:
|
|
return layoutInstrumentPropertyLine(gtx, "Thread", threadbtnline)
|
|
case 9:
|
|
l := Label(tr.Theme, &tr.Theme.InstrumentEditor.Properties.Label, "MIDI")
|
|
l.Alignment = text.Middle
|
|
return l.Layout(gtx)
|
|
case 10:
|
|
channelLine := NumUpDown(tr.MIDI().Channel(), tr.Theme, ip.midiChannel, "0 = automatic")
|
|
return layoutInstrumentPropertyLine(gtx, "Channel", channelLine.Layout)
|
|
case 11:
|
|
start := NumUpDown(tr.MIDI().NoteStart(), tr.Theme, ip.noteStart, "Lowest note triggering\nthis instrument")
|
|
end := NumUpDown(tr.MIDI().NoteEnd(), tr.Theme, ip.noteEnd, "Highest note triggering\nthis instrument")
|
|
noteRangeLine := func(gtx C) D {
|
|
return layout.Flex{}.Layout(gtx,
|
|
layout.Rigid(start.Layout),
|
|
layout.Rigid(layout.Spacer{Width: 6}.Layout),
|
|
layout.Rigid(end.Layout),
|
|
)
|
|
}
|
|
return layoutInstrumentPropertyLine(gtx, "Note range", noteRangeLine)
|
|
case 12:
|
|
transpose := NumUpDown(tr.MIDI().Transpose(), tr.Theme, ip.transpose, "Transpose of the MIDI values")
|
|
return layoutInstrumentPropertyLine(gtx, "Transpose", transpose.Layout)
|
|
case 13:
|
|
velocityBtn := ToggleIconBtn(tr.MIDI().Velocity(), tr.Theme, ip.velocity, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, "Instrument triggered by\nMIDI note", "Instrument triggered by\nMIDI velocity")
|
|
return layoutInstrumentPropertyLine(gtx, "Velocity", velocityBtn.Layout)
|
|
case 14:
|
|
retriggerBtn := ToggleIconBtn(tr.MIDI().Change(), tr.Theme, ip.change, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, "Every note/velocity retriggers", "Retrigger only when\nnote/velocity changes")
|
|
return layoutInstrumentPropertyLine(gtx, "No retrigger", retriggerBtn.Layout)
|
|
case 15:
|
|
noteOff := ToggleIconBtn(tr.MIDI().IgnoreNoteOff(), tr.Theme, ip.ignoreNoteOff, icons.ToggleCheckBoxOutlineBlank, icons.ToggleCheckBox, "Notes released", "Notes never released")
|
|
return layoutInstrumentPropertyLine(gtx, "Ignore note off", noteOff.Layout)
|
|
case 17:
|
|
return layout.UniformInset(unit.Dp(6)).Layout(gtx, func(gtx C) D {
|
|
return ip.commentEditor.Layout(gtx, tr.Instrument().Comment(), tr.Theme, &tr.Theme.InstrumentEditor.InstrumentComment, "Comment")
|
|
})
|
|
default: // odd valued list items are dividers
|
|
px := max(gtx.Dp(unit.Dp(1)), 1)
|
|
paint.FillShape(gtx.Ops, color.NRGBA{255, 255, 255, 3}, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, px)).Op())
|
|
return D{Size: image.Pt(gtx.Constraints.Max.X, px)}
|
|
}
|
|
})
|
|
}
|
|
|
|
func layoutInstrumentPropertyLine(gtx C, text string, content layout.Widget) D {
|
|
tr := TrackerFromContext(gtx)
|
|
label := Label(tr.Theme, &tr.Theme.InstrumentEditor.Properties.Label, text)
|
|
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
|
layout.Rigid(layout.Spacer{Width: 6, Height: 36}.Layout),
|
|
layout.Rigid(label.Layout),
|
|
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
|
|
layout.Rigid(content),
|
|
)
|
|
}
|