mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-23 07:24:47 -04:00
drafting
This commit is contained in:
parent
083ccc58b5
commit
0182d004b1
@ -5,6 +5,7 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"gioui.org/text"
|
"gioui.org/text"
|
||||||
|
"gioui.org/unit"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"gioui.org/widget/material"
|
"gioui.org/widget/material"
|
||||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
@ -84,11 +85,16 @@ type Theme struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UnitEditor struct {
|
UnitEditor struct {
|
||||||
Hint LabelStyle
|
Name LabelStyle
|
||||||
Chooser LabelStyle
|
Chooser LabelStyle
|
||||||
ParameterName LabelStyle
|
Hint LabelStyle
|
||||||
InvalidParam color.NRGBA
|
InvalidParam color.NRGBA
|
||||||
SendTarget color.NRGBA
|
SendTarget color.NRGBA
|
||||||
|
Width unit.Dp
|
||||||
|
Height unit.Dp
|
||||||
|
RowTitleWidth unit.Dp
|
||||||
|
ColumnTitleHeight unit.Dp
|
||||||
|
RowTitle LabelStyle
|
||||||
}
|
}
|
||||||
Cursor CursorStyle
|
Cursor CursorStyle
|
||||||
Selection CursorStyle
|
Selection CursorStyle
|
||||||
@ -102,6 +108,7 @@ type Theme struct {
|
|||||||
}
|
}
|
||||||
Split SplitStyle
|
Split SplitStyle
|
||||||
ScrollBar ScrollBarStyle
|
ScrollBar ScrollBarStyle
|
||||||
|
Knob KnobStyle
|
||||||
|
|
||||||
// iconCache is used to cache the icons created from iconvg data
|
// iconCache is used to cache the icons created from iconvg data
|
||||||
iconCache map[*byte]*widget.Icon
|
iconCache map[*byte]*widget.Icon
|
||||||
|
@ -178,12 +178,6 @@ instrumenteditor:
|
|||||||
disabled: { textsize: 12, color: *disabled }
|
disabled: { textsize: 12, color: *disabled }
|
||||||
warning: *warningcolor
|
warning: *warningcolor
|
||||||
error: *errorcolor
|
error: *errorcolor
|
||||||
uniteditor:
|
|
||||||
hint: { textsize: 16, color: *highemphasis, shadowcolor: *black }
|
|
||||||
chooser: { textsize: 12, color: *white, shadowcolor: *black }
|
|
||||||
parametername: { textsize: 16, color: *white, shadowcolor: *black }
|
|
||||||
invalidparam: { r: 120, g: 120, b: 120, a: 190 }
|
|
||||||
sendtarget: { r: 120, g: 120, b: 210, a: 255 }
|
|
||||||
cursor:
|
cursor:
|
||||||
active: { r: 100, g: 140, b: 255, a: 48 }
|
active: { r: 100, g: 140, b: 255, a: 48 }
|
||||||
activealt: { r: 255, g: 100, b: 140, a: 48 }
|
activealt: { r: 255, g: 100, b: 140, a: 48 }
|
||||||
@ -211,3 +205,21 @@ dialog:
|
|||||||
textinset: { top: 12, bottom: 12, left: 20, right: 20 }
|
textinset: { top: 12, bottom: 12, left: 20, right: 20 }
|
||||||
buttons: *textbutton
|
buttons: *textbutton
|
||||||
split: { bar: 10, minsize1: 180, minsize2: 180 }
|
split: { bar: 10, minsize1: 180, minsize2: 180 }
|
||||||
|
uniteditor:
|
||||||
|
hint: { textsize: 16, color: *highemphasis, shadowcolor: *black }
|
||||||
|
chooser: { textsize: 12, color: *white, shadowcolor: *black }
|
||||||
|
name:
|
||||||
|
{ textsize: 12, alignment: 2, color: *highemphasis, shadowcolor: *black }
|
||||||
|
invalidparam: { r: 120, g: 120, b: 120, a: 190 }
|
||||||
|
sendtarget: { r: 120, g: 120, b: 210, a: 255 }
|
||||||
|
width: 60
|
||||||
|
height: 60
|
||||||
|
rowtitlewidth: 16
|
||||||
|
columntitleheight: 16
|
||||||
|
rowtitle: { textsize: 12, color: *white, alignment: 2 }
|
||||||
|
knob:
|
||||||
|
diameter: 36
|
||||||
|
strokewidth: 4
|
||||||
|
color: *primarycolor
|
||||||
|
trackcolor: { r: 0, g: 0, b: 0, a: 255 }
|
||||||
|
value: { textsize: 12, color: *highemphasis }
|
||||||
|
@ -4,10 +4,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
|
"gioui.org/gesture"
|
||||||
"gioui.org/io/clipboard"
|
"gioui.org/io/clipboard"
|
||||||
"gioui.org/io/event"
|
"gioui.org/io/event"
|
||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
@ -17,9 +20,9 @@ import (
|
|||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/text"
|
"gioui.org/text"
|
||||||
|
"gioui.org/unit"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"gioui.org/widget/material"
|
"gioui.org/widget/material"
|
||||||
"gioui.org/x/component"
|
|
||||||
"github.com/vsariola/sointu"
|
"github.com/vsariola/sointu"
|
||||||
"github.com/vsariola/sointu/tracker"
|
"github.com/vsariola/sointu/tracker"
|
||||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
@ -27,7 +30,8 @@ import (
|
|||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UnitEditor struct {
|
type (
|
||||||
|
UnitEditor struct {
|
||||||
paramTable *ScrollTable
|
paramTable *ScrollTable
|
||||||
searchList *DragList
|
searchList *DragList
|
||||||
Parameters [][]*ParameterWidget
|
Parameters [][]*ParameterWidget
|
||||||
@ -46,6 +50,33 @@ type UnitEditor struct {
|
|||||||
searching tracker.Bool
|
searching tracker.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KnobState struct {
|
||||||
|
click gesture.Click
|
||||||
|
drag gesture.Drag
|
||||||
|
dragStartPt f32.Point // used to calculate the drag amount
|
||||||
|
dragStartVal int
|
||||||
|
tipArea TipArea
|
||||||
|
}
|
||||||
|
|
||||||
|
KnobStyle struct {
|
||||||
|
Diameter unit.Dp
|
||||||
|
StrokeWidth unit.Dp
|
||||||
|
Color color.NRGBA
|
||||||
|
TrackColor color.NRGBA
|
||||||
|
Value LabelStyle
|
||||||
|
Title LabelStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
KnobWidget struct {
|
||||||
|
Theme *Theme
|
||||||
|
Value tracker.Parameter
|
||||||
|
State *KnobState
|
||||||
|
Style *KnobStyle
|
||||||
|
Hint string
|
||||||
|
Scroll bool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func NewUnitEditor(m *tracker.Model) *UnitEditor {
|
func NewUnitEditor(m *tracker.Model) *UnitEditor {
|
||||||
ret := &UnitEditor{
|
ret := &UnitEditor{
|
||||||
DeleteUnitBtn: new(Clickable),
|
DeleteUnitBtn: new(Clickable),
|
||||||
@ -157,25 +188,28 @@ func (pe *UnitEditor) layoutSliders(gtx C) D {
|
|||||||
for len(pe.Parameters) < pe.paramTable.Table.Height() {
|
for len(pe.Parameters) < pe.paramTable.Table.Height() {
|
||||||
pe.Parameters = append(pe.Parameters, make([]*ParameterWidget, 0))
|
pe.Parameters = append(pe.Parameters, make([]*ParameterWidget, 0))
|
||||||
}
|
}
|
||||||
|
cellWidth := gtx.Dp(t.Theme.UnitEditor.Width)
|
||||||
|
cellHeight := gtx.Dp(t.Theme.UnitEditor.Height)
|
||||||
|
rowTitleWidth := gtx.Dp(t.Theme.UnitEditor.RowTitleWidth)
|
||||||
|
columnTitleHeight := gtx.Dp(t.Theme.UnitEditor.ColumnTitleHeight)
|
||||||
for i := range pe.Parameters {
|
for i := range pe.Parameters {
|
||||||
for len(pe.Parameters[i]) < width {
|
for len(pe.Parameters[i]) < width {
|
||||||
pe.Parameters[i] = append(pe.Parameters[i], &ParameterWidget{})
|
pe.Parameters[i] = append(pe.Parameters[i], &ParameterWidget{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
coltitle := func(gtx C, x int) D {
|
coltitle := func(gtx C, x int) D {
|
||||||
return D{Size: image.Pt(gtx.Dp(100), gtx.Dp(10))}
|
return D{Size: image.Pt(cellWidth, columnTitleHeight)}
|
||||||
}
|
}
|
||||||
rowtitle := func(gtx C, y int) D {
|
rowtitle := func(gtx C, y int) D {
|
||||||
h := gtx.Dp(100)
|
|
||||||
//defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
//defer op.Offset(image.Pt(0, -2)).Push(gtx.Ops).Pop()
|
||||||
defer op.Affine(f32.Affine2D{}.Rotate(f32.Pt(0, 0), -90*math.Pi/180).Offset(f32.Point{X: 0, Y: float32(h)})).Push(gtx.Ops).Pop()
|
defer op.Affine(f32.Affine2D{}.Rotate(f32.Pt(0, 0), -90*math.Pi/180).Offset(f32.Point{X: 0, Y: float32(cellHeight)})).Push(gtx.Ops).Pop()
|
||||||
gtx.Constraints = layout.Exact(image.Pt(1e6, 1e6))
|
gtx.Constraints = layout.Exact(image.Pt(cellHeight, rowTitleWidth))
|
||||||
Label(t.Theme, &t.Theme.OrderEditor.TrackTitle, t.Units().Item(y).Type).Layout(gtx)
|
Label(t.Theme, &t.Theme.UnitEditor.RowTitle, t.Units().Item(y).Type).Layout(gtx)
|
||||||
return D{Size: image.Pt(gtx.Dp(10), h)}
|
return D{Size: image.Pt(rowTitleWidth, cellHeight)}
|
||||||
}
|
}
|
||||||
cursor := t.Model.Params().Cursor()
|
cursor := t.Model.Params().Cursor()
|
||||||
cell := func(gtx C, x, y int) D {
|
cell := func(gtx C, x, y int) D {
|
||||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(100), gtx.Dp(100)))
|
gtx.Constraints = layout.Exact(image.Pt(cellWidth, cellHeight))
|
||||||
point := tracker.Point{X: x, Y: y}
|
point := tracker.Point{X: x, Y: y}
|
||||||
if y < 0 || y >= len(pe.Parameters) || x < 0 || x >= len(pe.Parameters[y]) {
|
if y < 0 || y >= len(pe.Parameters) || x < 0 || x >= len(pe.Parameters[y]) {
|
||||||
return D{}
|
return D{}
|
||||||
@ -192,14 +226,14 @@ func (pe *UnitEditor) layoutSliders(gtx C) D {
|
|||||||
pe.Parameters[y][x].Parameter = param
|
pe.Parameters[y][x].Parameter = param
|
||||||
paramStyle := t.ParamStyle(t.Theme, pe.Parameters[y][x])
|
paramStyle := t.ParamStyle(t.Theme, pe.Parameters[y][x])
|
||||||
paramStyle.Focus = pe.paramTable.Table.Cursor() == tracker.Point{X: x, Y: y}
|
paramStyle.Focus = pe.paramTable.Table.Cursor() == tracker.Point{X: x, Y: y}
|
||||||
dims := paramStyle.Layout(gtx)
|
paramStyle.Layout(gtx)
|
||||||
return D{Size: image.Pt(gtx.Constraints.Max.X, dims.Size.Y)}
|
return D{Size: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y)}
|
||||||
}
|
}
|
||||||
table := FilledScrollTable(t.Theme, pe.paramTable)
|
table := FilledScrollTable(t.Theme, pe.paramTable)
|
||||||
table.RowTitleWidth = 10
|
table.RowTitleWidth = t.Theme.UnitEditor.RowTitleWidth
|
||||||
table.ColumnTitleHeight = 10
|
table.ColumnTitleHeight = t.Theme.UnitEditor.ColumnTitleHeight
|
||||||
table.CellWidth = 100
|
table.CellWidth = t.Theme.UnitEditor.Width
|
||||||
table.CellHeight = 100
|
table.CellHeight = t.Theme.UnitEditor.Height
|
||||||
return table.Layout(gtx, cell, coltitle, rowtitle, nil, nil)
|
return table.Layout(gtx, cell, coltitle, rowtitle, nil, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -268,7 +302,7 @@ func (t *UnitEditor) Tags(level int, yield TagYieldFunc) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ParameterWidget struct {
|
type ParameterWidget struct {
|
||||||
floatWidget widget.Float
|
knobState KnobState
|
||||||
boolWidget widget.Bool
|
boolWidget widget.Bool
|
||||||
instrBtn Clickable
|
instrBtn Clickable
|
||||||
instrMenu MenuState
|
instrMenu MenuState
|
||||||
@ -302,47 +336,13 @@ func (t *Tracker) ParamStyle(th *Theme, paramWidget *ParameterWidget) ParameterS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p ParameterStyle) Layout(gtx C) D {
|
func (p ParameterStyle) Layout(gtx C) D {
|
||||||
info, infoOk := p.w.Parameter.Info()
|
//_, _ := p.w.Parameter.Info()
|
||||||
title := Label(p.Theme, &p.Theme.UnitEditor.ParameterName, p.w.Parameter.Name())
|
title := Label(p.Theme, &p.Theme.UnitEditor.Name, p.w.Parameter.Name())
|
||||||
title.Alignment = text.Middle
|
widget := func(gtx C) D {
|
||||||
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
|
|
||||||
layout.Rigid(title.Layout),
|
|
||||||
layout.Rigid(func(gtx C) D {
|
|
||||||
gtx.Constraints.Min.X = gtx.Dp(100)
|
|
||||||
gtx.Constraints.Min.Y = gtx.Dp(50)
|
|
||||||
switch p.w.Parameter.Type() {
|
switch p.w.Parameter.Type() {
|
||||||
case tracker.IntegerParameter:
|
case tracker.IntegerParameter:
|
||||||
for p.Focus {
|
k := Knob(p.w.Parameter, p.Theme, &p.w.knobState, p.w.Parameter.Hint().Label, p.Focus)
|
||||||
e, ok := gtx.Event(pointer.Filter{
|
return k.Layout(gtx)
|
||||||
Target: &p.w.floatWidget,
|
|
||||||
Kinds: pointer.Scroll,
|
|
||||||
ScrollY: pointer.ScrollRange{Min: -1e6, Max: 1e6},
|
|
||||||
})
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if ev, ok := e.(pointer.Event); ok && ev.Kind == pointer.Scroll {
|
|
||||||
delta := math.Min(math.Max(float64(ev.Scroll.Y), -1), 1)
|
|
||||||
p.w.Parameter.SetValue(p.w.Parameter.Value() - int(delta))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ra := p.w.Parameter.Range()
|
|
||||||
if !p.w.floatWidget.Dragging() {
|
|
||||||
p.w.floatWidget.Value = (float32(p.w.Parameter.Value()) - float32(ra.Min)) / float32(ra.Max-ra.Min)
|
|
||||||
}
|
|
||||||
sliderStyle := material.Slider(&p.Theme.Material, &p.w.floatWidget)
|
|
||||||
if infoOk {
|
|
||||||
sliderStyle.Color = p.Theme.UnitEditor.SendTarget
|
|
||||||
}
|
|
||||||
r := image.Rectangle{Max: gtx.Constraints.Min}
|
|
||||||
defer clip.Rect(r).Push(gtx.Ops).Pop()
|
|
||||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
|
||||||
if p.Focus {
|
|
||||||
event.Op(gtx.Ops, &p.w.floatWidget)
|
|
||||||
}
|
|
||||||
dims := sliderStyle.Layout(gtx)
|
|
||||||
p.w.Parameter.SetValue(int(p.w.floatWidget.Value*float32(ra.Max-ra.Min) + float32(ra.Min) + 0.5))
|
|
||||||
return dims
|
|
||||||
case tracker.BoolParameter:
|
case tracker.BoolParameter:
|
||||||
ra := p.w.Parameter.Range()
|
ra := p.w.Parameter.Range()
|
||||||
p.w.boolWidget.Value = p.w.Parameter.Value() > ra.Min
|
p.w.boolWidget.Value = p.w.Parameter.Value() > ra.Min
|
||||||
@ -399,8 +399,11 @@ func (p ParameterStyle) Layout(gtx C) D {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return D{}
|
return D{}
|
||||||
}),
|
}
|
||||||
layout.Rigid(func(gtx C) D {
|
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
|
||||||
|
layout.Rigid(title.Layout),
|
||||||
|
layout.Flexed(1, func(gtx C) D { return layout.Center.Layout(gtx, widget) }),
|
||||||
|
/* layout.Rigid(func(gtx C) D {
|
||||||
if p.w.Parameter.Type() != tracker.IDParameter {
|
if p.w.Parameter.Type() != tracker.IDParameter {
|
||||||
hint := p.w.Parameter.Hint()
|
hint := p.w.Parameter.Hint()
|
||||||
label := Label(p.tracker.Theme, &p.tracker.Theme.UnitEditor.Hint, hint.Label)
|
label := Label(p.tracker.Theme, &p.tracker.Theme.UnitEditor.Hint, hint.Label)
|
||||||
@ -415,7 +418,7 @@ func (p ParameterStyle) Layout(gtx C) D {
|
|||||||
return p.w.tipArea.Layout(gtx, tooltip, label.Layout)
|
return p.w.tipArea.Layout(gtx, tooltip, label.Layout)
|
||||||
}
|
}
|
||||||
return D{}
|
return D{}
|
||||||
}),
|
}),*/
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,3 +429,113 @@ func buildUnitLabel(index int, u sointu.Unit) string {
|
|||||||
}
|
}
|
||||||
return fmt.Sprintf("%d: %s", index, text)
|
return fmt.Sprintf("%d: %s", index, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Knob(v tracker.Parameter, th *Theme, state *KnobState, hint string, scroll bool) KnobWidget {
|
||||||
|
return KnobWidget{
|
||||||
|
Theme: th,
|
||||||
|
Value: v,
|
||||||
|
State: state,
|
||||||
|
Style: &th.Knob,
|
||||||
|
Hint: hint,
|
||||||
|
Scroll: scroll,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KnobWidget) Layout(gtx C) D {
|
||||||
|
k.update(gtx)
|
||||||
|
knob := func(gtx C) D {
|
||||||
|
m := k.Value.Range()
|
||||||
|
amount := float32(k.Value.Value()-m.Min) / float32(m.Max-m.Min)
|
||||||
|
sw := gtx.Dp(k.Style.StrokeWidth)
|
||||||
|
d := gtx.Dp(k.Style.Diameter)
|
||||||
|
defer clip.Rect(image.Rectangle{Max: image.Pt(d, d)}).Push(gtx.Ops).Pop()
|
||||||
|
event.Op(gtx.Ops, k.State)
|
||||||
|
k.State.drag.Add(gtx.Ops)
|
||||||
|
k.State.click.Add(gtx.Ops)
|
||||||
|
strokeKnobArc(gtx, k.Style.TrackColor, sw, d, 1)
|
||||||
|
strokeKnobArc(gtx, k.Style.Color, sw, d, amount)
|
||||||
|
return D{Size: image.Pt(d, d)}
|
||||||
|
}
|
||||||
|
label := Label(k.Theme, &k.Style.Value, strconv.Itoa(k.Value.Value()))
|
||||||
|
w := func(gtx C) D {
|
||||||
|
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||||
|
layout.Stacked(knob),
|
||||||
|
layout.Stacked(label.Layout))
|
||||||
|
}
|
||||||
|
if k.Hint != "" {
|
||||||
|
c := gtx.Constraints
|
||||||
|
gtx.Constraints.Max = image.Pt(1e6, 1e6)
|
||||||
|
return k.State.tipArea.Layout(gtx, Tooltip(k.Theme, k.Hint), func(gtx C) D {
|
||||||
|
gtx.Constraints = c
|
||||||
|
return w(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return w(gtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KnobWidget) update(gtx C) {
|
||||||
|
for {
|
||||||
|
p, ok := k.State.drag.Update(gtx.Metric, gtx.Source, gesture.Both)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch p.Kind {
|
||||||
|
case pointer.Press:
|
||||||
|
k.State.dragStartPt = p.Position
|
||||||
|
k.State.dragStartVal = k.Value.Value()
|
||||||
|
case pointer.Drag:
|
||||||
|
// update the value based on the drag amount
|
||||||
|
m := k.Value.Range()
|
||||||
|
d := p.Position.Sub(k.State.dragStartPt)
|
||||||
|
amount := float32(d.X-d.Y) / float32(gtx.Dp(k.Style.Diameter)) / 4
|
||||||
|
newValue := int(float32(k.State.dragStartVal) + amount*float32(m.Max-m.Min))
|
||||||
|
k.Value.SetValue(newValue)
|
||||||
|
k.State.tipArea.Appear(gtx.Now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
g, ok := k.State.click.Update(gtx.Source)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if g.Kind == gesture.KindClick && g.NumClicks > 1 {
|
||||||
|
k.Value.Reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k.Scroll {
|
||||||
|
e, ok := gtx.Event(pointer.Filter{
|
||||||
|
Target: k.State,
|
||||||
|
Kinds: pointer.Scroll,
|
||||||
|
ScrollY: pointer.ScrollRange{Min: -1e6, Max: 1e6},
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ev, ok := e.(pointer.Event); ok && ev.Kind == pointer.Scroll {
|
||||||
|
delta := math.Min(math.Max(float64(ev.Scroll.Y), -1), 1)
|
||||||
|
k.Value.SetValue(k.Value.Value() - int(delta))
|
||||||
|
k.State.tipArea.Appear(gtx.Now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func strokeKnobArc(gtx C, color color.NRGBA, strokeWidth, diameter int, amount float32) {
|
||||||
|
var path clip.Path
|
||||||
|
rad := float32(diameter) / 2
|
||||||
|
amount = min(max(amount, 0), 1)
|
||||||
|
if amount <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
angle := amount * 8 * math.Pi / 5
|
||||||
|
center := f32.Point{X: rad, Y: rad}
|
||||||
|
r2 := rad - float32(strokeWidth)/2
|
||||||
|
start := f32.Point{X: rad - r2*float32(math.Sin(math.Pi/5)), Y: rad + r2*float32(math.Cos(math.Pi/5))}
|
||||||
|
path.Begin(gtx.Ops)
|
||||||
|
path.MoveTo(start)
|
||||||
|
path.ArcTo(center, center, angle)
|
||||||
|
paint.FillShape(gtx.Ops, color,
|
||||||
|
clip.Stroke{
|
||||||
|
Path: path.End(),
|
||||||
|
Width: float32(strokeWidth),
|
||||||
|
}.Op())
|
||||||
|
}
|
||||||
|
@ -143,6 +143,7 @@ func (pt *Params) Cursor2() Point { return pt.Cursor() }
|
|||||||
func (pt *Params) SetCursor(p Point) {
|
func (pt *Params) SetCursor(p Point) {
|
||||||
pt.d.ParamIndex = max(min(p.X, pt.Width()-1), 0)
|
pt.d.ParamIndex = max(min(p.X, pt.Width()-1), 0)
|
||||||
pt.d.UnitIndex = max(min(p.Y, pt.Height()-1), 0)
|
pt.d.UnitIndex = max(min(p.Y, pt.Height()-1), 0)
|
||||||
|
pt.d.UnitIndex2 = pt.d.UnitIndex
|
||||||
}
|
}
|
||||||
func (pt *Params) SetCursor2(p Point) {}
|
func (pt *Params) SetCursor2(p Point) {}
|
||||||
func (pt *Params) Width() int {
|
func (pt *Params) Width() int {
|
||||||
@ -227,7 +228,7 @@ func (n *namedParameter) Hint(p *Parameter) ParameterHint {
|
|||||||
label := strconv.Itoa(val)
|
label := strconv.Itoa(val)
|
||||||
if p.up.DisplayFunc != nil {
|
if p.up.DisplayFunc != nil {
|
||||||
valueInUnits, units := p.up.DisplayFunc(val)
|
valueInUnits, units := p.up.DisplayFunc(val)
|
||||||
label = fmt.Sprintf("%d / %s %s", val, valueInUnits, units)
|
label = fmt.Sprintf("%s %s", valueInUnits, units)
|
||||||
}
|
}
|
||||||
if p.unit.Type == "send" {
|
if p.unit.Type == "send" {
|
||||||
instrIndex, targetType, ok := p.m.UnitHintInfo(p.unit.Parameters["target"])
|
instrIndex, targetType, ok := p.m.UnitHintInfo(p.unit.Parameters["target"])
|
||||||
@ -305,9 +306,9 @@ func (g *gmDlsEntryParameter) Name(p *Parameter) string {
|
|||||||
return "sample"
|
return "sample"
|
||||||
}
|
}
|
||||||
func (g *gmDlsEntryParameter) Hint(p *Parameter) ParameterHint {
|
func (g *gmDlsEntryParameter) Hint(p *Parameter) ParameterHint {
|
||||||
label := "0 / custom"
|
label := "custom"
|
||||||
if v := g.Value(p); v > 0 {
|
if v := g.Value(p); v > 0 {
|
||||||
label = fmt.Sprintf("%v / %v", v, GmDlsEntries[v-1].Name)
|
label = GmDlsEntries[v-1].Name
|
||||||
}
|
}
|
||||||
return ParameterHint{label, true}
|
return ParameterHint{label, true}
|
||||||
}
|
}
|
||||||
@ -350,11 +351,11 @@ func (d *delayTimeParameter) Hint(p *Parameter) ParameterHint {
|
|||||||
switch p.unit.Parameters["notetracking"] {
|
switch p.unit.Parameters["notetracking"] {
|
||||||
default:
|
default:
|
||||||
case 0:
|
case 0:
|
||||||
text = fmt.Sprintf("%v / %.3f rows", val, float32(val)/float32(p.m.d.Song.SamplesPerRow()))
|
text = fmt.Sprintf("%.3f rows", float32(val)/float32(p.m.d.Song.SamplesPerRow()))
|
||||||
case 1:
|
case 1:
|
||||||
relPitch := float64(val) / 10787
|
relPitch := float64(val) / 10787
|
||||||
semitones := -math.Log2(relPitch) * 12
|
semitones := -math.Log2(relPitch) * 12
|
||||||
text = fmt.Sprintf("%v / %.3f st", val, semitones)
|
text = fmt.Sprintf("%.3f st", semitones)
|
||||||
case 2:
|
case 2:
|
||||||
k := 0
|
k := 0
|
||||||
v := val
|
v := val
|
||||||
@ -467,9 +468,9 @@ func (r *reverbParameter) Name(p *Parameter) string {
|
|||||||
}
|
}
|
||||||
func (r *reverbParameter) Hint(p *Parameter) ParameterHint {
|
func (r *reverbParameter) Hint(p *Parameter) ParameterHint {
|
||||||
i := r.Value(p)
|
i := r.Value(p)
|
||||||
label := "0 / custom"
|
label := "custom"
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
label = fmt.Sprintf("%v / %v", i, reverbs[i-1].name)
|
label = reverbs[i-1].name
|
||||||
}
|
}
|
||||||
return ParameterHint{label, true}
|
return ParameterHint{label, true}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user