mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
parent
12d5d392c5
commit
692615c76d
@ -33,11 +33,6 @@ func (t *Tracker) layoutInstruments(gtx C) D {
|
|||||||
pointer.InputOp{Tag: &instrumentPointerTag,
|
pointer.InputOp{Tag: &instrumentPointerTag,
|
||||||
Types: pointer.Press,
|
Types: pointer.Press,
|
||||||
}.Add(gtx.Ops)
|
}.Add(gtx.Ops)
|
||||||
if t.CurrentInstrument > 7 {
|
|
||||||
t.InstrumentDragList.List.Position.First = t.CurrentInstrument - 7
|
|
||||||
} else {
|
|
||||||
t.InstrumentDragList.List.Position.First = 0
|
|
||||||
}
|
|
||||||
for t.NewInstrumentBtn.Clicked() {
|
for t.NewInstrumentBtn.Clicked() {
|
||||||
t.AddInstrument()
|
t.AddInstrument()
|
||||||
}
|
}
|
||||||
@ -53,7 +48,14 @@ func (t *Tracker) layoutInstruments(gtx C) D {
|
|||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return layout.Flex{}.Layout(
|
return layout.Flex{}.Layout(
|
||||||
gtx,
|
gtx,
|
||||||
layout.Flexed(1, t.layoutInstrumentNames),
|
layout.Flexed(1, func(gtx C) D {
|
||||||
|
return layout.Stack{}.Layout(gtx,
|
||||||
|
layout.Stacked(t.layoutInstrumentNames),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
return t.InstrumentScrollBar.Layout(gtx, unit.Dp(6), len(t.song.Patch.Instruments), &t.InstrumentDragList.List.Position)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return layout.E.Layout(gtx, btnStyle.Layout)
|
return layout.E.Layout(gtx, btnStyle.Layout)
|
||||||
}),
|
}),
|
||||||
@ -180,7 +182,6 @@ func (t *Tracker) layoutInstrumentEditor(gtx C) D {
|
|||||||
}
|
}
|
||||||
addUnitBtnStyle := material.IconButton(t.Theme, t.AddUnitBtn, widgetForIcon(icons.ContentAdd))
|
addUnitBtnStyle := material.IconButton(t.Theme, t.AddUnitBtn, widgetForIcon(icons.ContentAdd))
|
||||||
addUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(4))
|
addUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(4))
|
||||||
margin := layout.UniformInset(unit.Dp(2))
|
|
||||||
|
|
||||||
for len(t.StackUse) < len(t.song.Patch.Instruments[t.CurrentInstrument].Units) {
|
for len(t.StackUse) < len(t.song.Patch.Instruments[t.CurrentInstrument].Units) {
|
||||||
t.StackUse = append(t.StackUse, 0)
|
t.StackUse = append(t.StackUse, 0)
|
||||||
@ -212,10 +213,12 @@ func (t *Tracker) layoutInstrumentEditor(gtx C) D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)}
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Flexed(1, unitNameLabel.Layout),
|
layout.Flexed(1, unitNameLabel.Layout),
|
||||||
layout.Rigid(stackLabel.Layout),
|
layout.Rigid(func(gtx C) D {
|
||||||
|
return rightMargin.Layout(gtx, stackLabel.Layout)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +242,11 @@ func (t *Tracker) layoutInstrumentEditor(gtx C) D {
|
|||||||
}
|
}
|
||||||
return dims
|
return dims
|
||||||
}),
|
}),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
return t.UnitScrollBar.Layout(gtx, unit.Dp(10), len(t.song.Patch.Instruments[t.CurrentInstrument].Units), &t.UnitDragList.List.Position)
|
||||||
|
}),
|
||||||
layout.Stacked(func(gtx C) D {
|
layout.Stacked(func(gtx C) D {
|
||||||
|
margin := layout.Inset{Right: unit.Dp(20), Bottom: unit.Dp(1)}
|
||||||
return margin.Layout(gtx, addUnitBtnStyle.Layout)
|
return margin.Layout(gtx, addUnitBtnStyle.Layout)
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
|
128
tracker/scrollbar.go
Normal file
128
tracker/scrollbar.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package tracker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
|
||||||
|
"gioui.org/f32"
|
||||||
|
"gioui.org/io/pointer"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/op/clip"
|
||||||
|
"gioui.org/op/paint"
|
||||||
|
"gioui.org/unit"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ScrollBar struct {
|
||||||
|
Axis layout.Axis
|
||||||
|
dragStart float32
|
||||||
|
hovering bool
|
||||||
|
dragging bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Position) D {
|
||||||
|
defer op.Save(gtx.Ops).Load()
|
||||||
|
clip.Rect{Max: gtx.Constraints.Min}.Add(gtx.Ops)
|
||||||
|
gradientSize := gtx.Px(unit.Dp(4))
|
||||||
|
var totalPixelsEstimate, scrollBarRelLength float32
|
||||||
|
switch s.Axis {
|
||||||
|
case layout.Vertical:
|
||||||
|
if pos.First > 0 || pos.Offset > 0 {
|
||||||
|
paint.LinearGradientOp{Color1: black, Color2: transparent, Stop2: f32.Pt(0, float32(gradientSize))}.Add(gtx.Ops)
|
||||||
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
if pos.BeforeEnd {
|
||||||
|
paint.LinearGradientOp{Color1: black, Color2: transparent, Stop1: f32.Pt(0, float32(gtx.Constraints.Min.Y)), Stop2: f32.Pt(0, float32(gtx.Constraints.Min.Y-gradientSize))}.Add(gtx.Ops)
|
||||||
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
totalPixelsEstimate = float32(gtx.Constraints.Min.Y+pos.Offset-pos.OffsetLast) * float32(numItems) / float32(pos.Count)
|
||||||
|
scrollBarRelLength = float32(gtx.Constraints.Min.Y) / float32(totalPixelsEstimate)
|
||||||
|
|
||||||
|
case layout.Horizontal:
|
||||||
|
if pos.First > 0 || pos.Offset > 0 {
|
||||||
|
paint.LinearGradientOp{Color1: black, Color2: transparent, Stop2: f32.Pt(float32(gradientSize), 0)}.Add(gtx.Ops)
|
||||||
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
if pos.BeforeEnd {
|
||||||
|
paint.LinearGradientOp{Color1: black, Color2: transparent, Stop1: f32.Pt(float32(gtx.Constraints.Min.X), 0), Stop2: f32.Pt(float32(gtx.Constraints.Min.X-gradientSize), 0)}.Add(gtx.Ops)
|
||||||
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
totalPixelsEstimate = float32(gtx.Constraints.Min.X+pos.Offset-pos.OffsetLast) * float32(numItems) / float32(pos.Count)
|
||||||
|
scrollBarRelLength = float32(gtx.Constraints.Min.X) / float32(totalPixelsEstimate)
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollBarRelStart := (float32(pos.First)*totalPixelsEstimate/float32(numItems) + float32(pos.Offset)) / totalPixelsEstimate
|
||||||
|
scrWidth := gtx.Px(width)
|
||||||
|
|
||||||
|
stack := op.Save(gtx.Ops)
|
||||||
|
switch s.Axis {
|
||||||
|
case layout.Vertical:
|
||||||
|
if scrollBarRelLength < 1 && (s.dragging || s.hovering) {
|
||||||
|
y1 := int(scrollBarRelStart * float32(gtx.Constraints.Min.Y))
|
||||||
|
y2 := int((scrollBarRelStart + scrollBarRelLength) * float32(gtx.Constraints.Min.Y))
|
||||||
|
paint.FillShape(gtx.Ops, scrollBarColor, clip.Rect{Min: image.Pt(gtx.Constraints.Min.X-scrWidth, y1), Max: image.Pt(gtx.Constraints.Min.X, y2)}.Op())
|
||||||
|
}
|
||||||
|
rect := image.Rect(gtx.Constraints.Min.X-scrWidth, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||||
|
pointer.Rect(rect).Add(gtx.Ops)
|
||||||
|
case layout.Horizontal:
|
||||||
|
if scrollBarRelLength < 1 && (s.dragging || s.hovering) {
|
||||||
|
x1 := int(scrollBarRelStart * float32(gtx.Constraints.Min.X))
|
||||||
|
x2 := int((scrollBarRelStart + scrollBarRelLength) * float32(gtx.Constraints.Min.X))
|
||||||
|
paint.FillShape(gtx.Ops, scrollBarColor, clip.Rect{Min: image.Pt(x1, gtx.Constraints.Min.Y-scrWidth), Max: image.Pt(x2, gtx.Constraints.Min.Y)}.Op())
|
||||||
|
}
|
||||||
|
rect := image.Rect(0, gtx.Constraints.Min.Y-scrWidth, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||||
|
pointer.Rect(rect).Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
pointer.InputOp{Tag: &s.dragStart,
|
||||||
|
Types: pointer.Drag | pointer.Press | pointer.Cancel | pointer.Release,
|
||||||
|
}.Add(gtx.Ops)
|
||||||
|
stack.Load()
|
||||||
|
|
||||||
|
for _, ev := range gtx.Events(&s.dragStart) {
|
||||||
|
e, ok := ev.(pointer.Event)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch e.Type {
|
||||||
|
case pointer.Press:
|
||||||
|
if s.Axis == layout.Horizontal {
|
||||||
|
s.dragStart = e.Position.X
|
||||||
|
s.dragging = true
|
||||||
|
} else {
|
||||||
|
s.dragStart = e.Position.Y
|
||||||
|
s.dragging = true
|
||||||
|
}
|
||||||
|
case pointer.Drag:
|
||||||
|
if s.Axis == layout.Horizontal {
|
||||||
|
pos.Offset += int(e.Position.X - s.dragStart + 0.5)
|
||||||
|
s.dragStart = e.Position.X
|
||||||
|
} else {
|
||||||
|
pos.Offset += int(e.Position.Y - s.dragStart + 0.5)
|
||||||
|
s.dragStart = e.Position.Y
|
||||||
|
}
|
||||||
|
case pointer.Release, pointer.Cancel:
|
||||||
|
s.dragging = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||||
|
rect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||||
|
pointer.Rect(rect).Add(gtx.Ops)
|
||||||
|
pointer.InputOp{Tag: s,
|
||||||
|
Types: pointer.Enter | pointer.Leave,
|
||||||
|
}.Add(gtx.Ops)
|
||||||
|
|
||||||
|
for _, ev := range gtx.Events(s) {
|
||||||
|
e, ok := ev.(pointer.Event)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch e.Type {
|
||||||
|
case pointer.Enter:
|
||||||
|
s.hovering = true
|
||||||
|
case pointer.Leave:
|
||||||
|
s.hovering = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return D{Size: gtx.Constraints.Min}
|
||||||
|
}
|
@ -69,3 +69,5 @@ var inactiveSelectionColor = color.NRGBA{R: 140, G: 140, B: 140, A: 16}
|
|||||||
var errorColor = color.NRGBA{R: 207, G: 102, B: 121, A: 255}
|
var errorColor = color.NRGBA{R: 207, G: 102, B: 121, A: 255}
|
||||||
|
|
||||||
var menuHoverColor = color.NRGBA{R: 30, G: 31, B: 38, A: 255}
|
var menuHoverColor = color.NRGBA{R: 30, G: 31, B: 38, A: 255}
|
||||||
|
|
||||||
|
var scrollBarColor = color.NRGBA{R: 255, G: 255, B: 255, A: 32}
|
||||||
|
@ -63,14 +63,18 @@ type Tracker struct {
|
|||||||
CopyInstrumentBtn *widget.Clickable
|
CopyInstrumentBtn *widget.Clickable
|
||||||
ParameterSliders []*widget.Float
|
ParameterSliders []*widget.Float
|
||||||
ParameterList *layout.List
|
ParameterList *layout.List
|
||||||
|
ParameterScrollBar *ScrollBar
|
||||||
UnitDragList *DragList
|
UnitDragList *DragList
|
||||||
|
UnitScrollBar *ScrollBar
|
||||||
DeleteUnitBtn *widget.Clickable
|
DeleteUnitBtn *widget.Clickable
|
||||||
ClearUnitBtn *widget.Clickable
|
ClearUnitBtn *widget.Clickable
|
||||||
ChooseUnitTypeList *layout.List
|
ChooseUnitTypeList *layout.List
|
||||||
|
ChooseUnitScrollBar *ScrollBar
|
||||||
ChooseUnitTypeBtns []*widget.Clickable
|
ChooseUnitTypeBtns []*widget.Clickable
|
||||||
AddUnitBtn *widget.Clickable
|
AddUnitBtn *widget.Clickable
|
||||||
ParameterLabelBtns []*widget.Clickable
|
ParameterLabelBtns []*widget.Clickable
|
||||||
InstrumentDragList *DragList
|
InstrumentDragList *DragList
|
||||||
|
InstrumentScrollBar *ScrollBar
|
||||||
TrackHexCheckBox *widget.Bool
|
TrackHexCheckBox *widget.Bool
|
||||||
TrackShowHex []bool
|
TrackShowHex []bool
|
||||||
VuMeter VuMeter
|
VuMeter VuMeter
|
||||||
@ -702,15 +706,19 @@ func New(audioContext sointu.AudioContext, synthService sointu.SynthService) *Tr
|
|||||||
Menus: make([]Menu, 2),
|
Menus: make([]Menu, 2),
|
||||||
MenuBar: make([]widget.Clickable, 2),
|
MenuBar: make([]widget.Clickable, 2),
|
||||||
UnitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}},
|
UnitDragList: &DragList{List: &layout.List{Axis: layout.Vertical}},
|
||||||
|
UnitScrollBar: &ScrollBar{Axis: layout.Vertical},
|
||||||
refresh: make(chan struct{}, 1), // use non-blocking sends; no need to queue extra ticks if one is queued already
|
refresh: make(chan struct{}, 1), // use non-blocking sends; no need to queue extra ticks if one is queued already
|
||||||
undoStack: []sointu.Song{},
|
undoStack: []sointu.Song{},
|
||||||
redoStack: []sointu.Song{},
|
redoStack: []sointu.Song{},
|
||||||
InstrumentDragList: &DragList{List: &layout.List{Axis: layout.Horizontal}},
|
InstrumentDragList: &DragList{List: &layout.List{Axis: layout.Horizontal}},
|
||||||
|
InstrumentScrollBar: &ScrollBar{Axis: layout.Horizontal},
|
||||||
ParameterList: &layout.List{Axis: layout.Vertical},
|
ParameterList: &layout.List{Axis: layout.Vertical},
|
||||||
|
ParameterScrollBar: &ScrollBar{Axis: layout.Vertical},
|
||||||
TopHorizontalSplit: new(Split),
|
TopHorizontalSplit: new(Split),
|
||||||
BottomHorizontalSplit: new(Split),
|
BottomHorizontalSplit: new(Split),
|
||||||
VerticalSplit: new(Split),
|
VerticalSplit: new(Split),
|
||||||
ChooseUnitTypeList: &layout.List{Axis: layout.Vertical},
|
ChooseUnitTypeList: &layout.List{Axis: layout.Vertical},
|
||||||
|
ChooseUnitScrollBar: &ScrollBar{Axis: layout.Vertical},
|
||||||
KeyPlaying: make(map[string]func()),
|
KeyPlaying: make(map[string]func()),
|
||||||
}
|
}
|
||||||
t.UnitDragList.HoverItem = -1
|
t.UnitDragList.HoverItem = -1
|
||||||
|
@ -150,7 +150,14 @@ func (t *Tracker) layoutUnitSliders(gtx C) D {
|
|||||||
if u.Type == "oscillator" && u.Parameters["type"] == sointu.Sample {
|
if u.Type == "oscillator" && u.Parameters["type"] == sointu.Sample {
|
||||||
l++
|
l++
|
||||||
}
|
}
|
||||||
return t.ParameterList.Layout(gtx, l, listElements)
|
return layout.Stack{}.Layout(gtx,
|
||||||
|
layout.Stacked(func(gtx C) D {
|
||||||
|
return t.ParameterList.Layout(gtx, l, listElements)
|
||||||
|
}),
|
||||||
|
layout.Stacked(func(gtx C) D {
|
||||||
|
gtx.Constraints.Min = gtx.Constraints.Max
|
||||||
|
return t.ParameterScrollBar.Layout(gtx, unit.Dp(10), l, &t.ParameterList.Position)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) layoutUnitFooter() layout.Widget {
|
func (t *Tracker) layoutUnitFooter() layout.Widget {
|
||||||
@ -173,17 +180,19 @@ func (t *Tracker) layoutUnitFooter() layout.Widget {
|
|||||||
}
|
}
|
||||||
if t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Type == "" {
|
if t.song.Patch.Instruments[t.CurrentInstrument].Units[t.CurrentUnit].Type == "" {
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
layout.Rigid(deleteUnitBtnStyle.Layout),
|
||||||
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
|
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 := material.IconButton(t.Theme, t.ClearUnitBtn, widgetForIcon(icons.ContentClear))
|
||||||
clearUnitBtnStyle.Color = primaryColor
|
clearUnitBtnStyle.Color = primaryColor
|
||||||
clearUnitBtnStyle.Background = transparent
|
clearUnitBtnStyle.Background = transparent
|
||||||
clearUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(6))
|
clearUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(6))
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
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),
|
||||||
layout.Rigid(clearUnitBtnStyle.Layout),
|
layout.Rigid(clearUnitBtnStyle.Layout),
|
||||||
layout.Rigid(deleteUnitBtnStyle.Layout))
|
layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +222,13 @@ func (t *Tracker) layoutUnitTypeChooser(gtx C) D {
|
|||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
layout.Rigid(hintText),
|
layout.Rigid(hintText),
|
||||||
layout.Flexed(1, func(gtx C) D {
|
layout.Flexed(1, func(gtx C) D {
|
||||||
return t.ChooseUnitTypeList.Layout(gtx, len(allUnits), listElem)
|
return layout.Stack{}.Layout(gtx,
|
||||||
|
layout.Stacked(func(gtx C) D {
|
||||||
|
return t.ChooseUnitTypeList.Layout(gtx, len(allUnits), listElem)
|
||||||
|
}),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
return t.ChooseUnitScrollBar.Layout(gtx, unit.Dp(10), len(allUnits), &t.ChooseUnitTypeList.Position)
|
||||||
|
}))
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user