feat(tracker): add adjustable vertical split between top and bottom

This commit is contained in:
vsariola 2021-01-15 12:42:06 +02:00
parent c90f8efbdc
commit f665a529e5
3 changed files with 121 additions and 88 deletions

View File

@ -77,11 +77,9 @@ func trackButton(t *material.Theme, w *widget.Clickable, text string, enabled bo
func (t *Tracker) Layout(gtx layout.Context) {
paint.FillShape(gtx.Ops, backgroundColor, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx2 layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx2,
layout.Rigid(t.layoutControls),
layout.Flexed(1, t.layoutTracksAndPatterns))
})
t.VerticalSplit.Layout(gtx,
t.layoutControls,
t.layoutTracksAndPatterns)
t.updateInstrumentScroll()
}
@ -90,7 +88,7 @@ func (t *Tracker) layoutTracksAndPatterns(gtx layout.Context) layout.Dimensions
if !t.Playing {
playPat = -1
}
return t.BottomSplit.Layout(gtx,
return t.BottomHorizontalSplit.Layout(gtx,
t.layoutPatterns(
t.song.Tracks,
t.ActiveTrack,
@ -208,9 +206,6 @@ func (t *Tracker) layoutTracks(gtx layout.Context) layout.Dimensions {
}
func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.Y = 250
gtx.Constraints.Max.Y = 250
go func() {
for t.BPMUpBtn.Clicked() {
t.ChangeBPM(1)
@ -231,7 +226,7 @@ func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
t.DecreaseSongLength()
}
return t.TopSplit.Layout(gtx,
return t.TopHorizontalSplit.Layout(gtx,
t.layoutSongPanel,
t.layoutInstruments(),
)

View File

@ -16,25 +16,35 @@ type Split struct {
Ratio float32
// Bar is the width for resizing the layout
Bar unit.Value
// Axis is the split direction: layout.Horizontal splits the view in left
// and right, layout.Vertical splits the view in top and bottom
Axis layout.Axis
drag bool
dragID pointer.ID
dragX float32
drag bool
dragID pointer.ID
dragCoord float32
}
var defaultBarWidth = unit.Dp(10)
func (s *Split) Layout(gtx layout.Context, left, right layout.Widget) layout.Dimensions {
func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.Dimensions {
bar := gtx.Px(s.Bar)
if bar <= 1 {
bar = gtx.Px(defaultBarWidth)
}
proportion := (s.Ratio + 1) / 2
leftsize := int(proportion*float32(gtx.Constraints.Max.X) - float32(bar))
var coord int
if s.Axis == layout.Horizontal {
coord = gtx.Constraints.Max.X
} else {
coord = gtx.Constraints.Max.Y
}
rightoffset := leftsize + bar
rightsize := gtx.Constraints.Max.X - rightoffset
proportion := (s.Ratio + 1) / 2
firstSize := int(proportion*float32(coord) - float32(bar))
secondOffset := firstSize + bar
secondSize := coord - secondOffset
{ // handle input
// Avoid affecting the input tree with pointer events.
@ -53,17 +63,28 @@ func (s *Split) Layout(gtx layout.Context, left, right layout.Widget) layout.Dim
}
s.dragID = e.PointerID
s.dragX = e.Position.X
if s.Axis == layout.Horizontal {
s.dragCoord = e.Position.X
} else {
s.dragCoord = e.Position.Y
}
case pointer.Drag:
if s.dragID != e.PointerID {
break
}
deltaX := e.Position.X - s.dragX
s.dragX = e.Position.X
var deltaCoord, deltaRatio float32
if s.Axis == layout.Horizontal {
deltaCoord = e.Position.X - s.dragCoord
s.dragCoord = e.Position.X
deltaRatio = deltaCoord * 2 / float32(gtx.Constraints.Max.X)
} else {
deltaCoord = e.Position.Y - s.dragCoord
s.dragCoord = e.Position.Y
deltaRatio = deltaCoord * 2 / float32(gtx.Constraints.Max.Y)
}
deltaRatio := deltaX * 2 / float32(gtx.Constraints.Max.X)
s.Ratio += deltaRatio
case pointer.Release:
@ -74,7 +95,12 @@ func (s *Split) Layout(gtx layout.Context, left, right layout.Widget) layout.Dim
}
// register for input
barRect := image.Rect(leftsize, 0, rightoffset, gtx.Constraints.Max.X)
var barRect image.Rectangle
if s.Axis == layout.Horizontal {
barRect = image.Rect(firstSize, 0, secondOffset, gtx.Constraints.Max.X)
} else {
barRect = image.Rect(0, firstSize, gtx.Constraints.Max.Y, secondOffset)
}
pointer.Rect(barRect).Add(gtx.Ops)
pointer.InputOp{Tag: s,
Types: pointer.Press | pointer.Drag | pointer.Release,
@ -85,22 +111,31 @@ func (s *Split) Layout(gtx layout.Context, left, right layout.Widget) layout.Dim
}
{
gtx := gtx
stack := op.Push(gtx.Ops)
gtx := gtx
gtx.Constraints = layout.Exact(image.Pt(leftsize, gtx.Constraints.Max.Y))
left(gtx)
if s.Axis == layout.Horizontal {
gtx.Constraints = layout.Exact(image.Pt(firstSize, gtx.Constraints.Max.Y))
} else {
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X, firstSize))
}
first(gtx)
stack.Pop()
}
{
stack := op.Push(gtx.Ops)
op.Offset(f32.Pt(float32(rightoffset), 0)).Add(gtx.Ops)
gtx := gtx
gtx.Constraints = layout.Exact(image.Pt(rightsize, gtx.Constraints.Max.Y))
right(gtx)
stack := op.Push(gtx.Ops)
if s.Axis == layout.Horizontal {
op.Offset(f32.Pt(float32(secondOffset), 0)).Add(gtx.Ops)
gtx.Constraints = layout.Exact(image.Pt(secondSize, gtx.Constraints.Max.Y))
} else {
op.Offset(f32.Pt(0, float32(secondOffset))).Add(gtx.Ops)
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X, secondSize))
}
second(gtx)
stack.Pop()
}

View File

@ -18,37 +18,38 @@ type Tracker struct {
song sointu.Song
Playing bool
// protects PlayPattern and PlayRow
playRowPatMutex sync.RWMutex // protects song and playing
PlayPattern int
PlayRow int
CursorRow int
CursorColumn int
DisplayPattern int
ActiveTrack int
CurrentInstrument int
CurrentUnit int
CurrentOctave byte
NoteTracking bool
Theme *material.Theme
OctaveUpBtn *widget.Clickable
OctaveDownBtn *widget.Clickable
BPMUpBtn *widget.Clickable
BPMDownBtn *widget.Clickable
NewTrackBtn *widget.Clickable
NewInstrumentBtn *widget.Clickable
LoadSongFileBtn *widget.Clickable
NewSongFileBtn *widget.Clickable
SongLengthUpBtn *widget.Clickable
SongLengthDownBtn *widget.Clickable
SaveSongFileBtn *widget.Clickable
ParameterSliders []*widget.Float
UnitBtns []*widget.Clickable
InstrumentBtns []*widget.Clickable
InstrumentList *layout.List
TrackHexCheckBoxes []*widget.Bool
TrackShowHex []bool
TopSplit *Split
BottomSplit *Split
playRowPatMutex sync.RWMutex // protects song and playing
PlayPattern int
PlayRow int
CursorRow int
CursorColumn int
DisplayPattern int
ActiveTrack int
CurrentInstrument int
CurrentUnit int
CurrentOctave byte
NoteTracking bool
Theme *material.Theme
OctaveUpBtn *widget.Clickable
OctaveDownBtn *widget.Clickable
BPMUpBtn *widget.Clickable
BPMDownBtn *widget.Clickable
NewTrackBtn *widget.Clickable
NewInstrumentBtn *widget.Clickable
LoadSongFileBtn *widget.Clickable
NewSongFileBtn *widget.Clickable
SongLengthUpBtn *widget.Clickable
SongLengthDownBtn *widget.Clickable
SaveSongFileBtn *widget.Clickable
ParameterSliders []*widget.Float
UnitBtns []*widget.Clickable
InstrumentBtns []*widget.Clickable
InstrumentList *layout.List
TrackHexCheckBoxes []*widget.Bool
TrackShowHex []bool
TopHorizontalSplit *Split
BottomHorizontalSplit *Split
VerticalSplit *Split
sequencer *Sequencer
ticked chan struct{}
@ -279,33 +280,35 @@ func (t *Tracker) DecreaseSongLength() {
func New(audioContext sointu.AudioContext) *Tracker {
t := &Tracker{
Theme: material.NewTheme(gofont.Collection()),
QuitButton: new(widget.Clickable),
CurrentOctave: 4,
audioContext: audioContext,
OctaveUpBtn: new(widget.Clickable),
OctaveDownBtn: new(widget.Clickable),
BPMUpBtn: new(widget.Clickable),
BPMDownBtn: new(widget.Clickable),
NewTrackBtn: new(widget.Clickable),
NewInstrumentBtn: new(widget.Clickable),
NewSongFileBtn: new(widget.Clickable),
LoadSongFileBtn: new(widget.Clickable),
SaveSongFileBtn: new(widget.Clickable),
SongLengthUpBtn: new(widget.Clickable),
SongLengthDownBtn: new(widget.Clickable),
setPlaying: make(chan bool),
rowJump: make(chan int),
patternJump: make(chan int),
ticked: make(chan struct{}),
closer: make(chan struct{}),
undoStack: []sointu.Song{},
redoStack: []sointu.Song{},
InstrumentList: &layout.List{Axis: layout.Horizontal},
TopSplit: new(Split),
BottomSplit: new(Split),
Theme: material.NewTheme(gofont.Collection()),
QuitButton: new(widget.Clickable),
CurrentOctave: 4,
audioContext: audioContext,
OctaveUpBtn: new(widget.Clickable),
OctaveDownBtn: new(widget.Clickable),
BPMUpBtn: new(widget.Clickable),
BPMDownBtn: new(widget.Clickable),
NewTrackBtn: new(widget.Clickable),
NewInstrumentBtn: new(widget.Clickable),
NewSongFileBtn: new(widget.Clickable),
LoadSongFileBtn: new(widget.Clickable),
SaveSongFileBtn: new(widget.Clickable),
SongLengthUpBtn: new(widget.Clickable),
SongLengthDownBtn: new(widget.Clickable),
setPlaying: make(chan bool),
rowJump: make(chan int),
patternJump: make(chan int),
ticked: make(chan struct{}),
closer: make(chan struct{}),
undoStack: []sointu.Song{},
redoStack: []sointu.Song{},
InstrumentList: &layout.List{Axis: layout.Horizontal},
TopHorizontalSplit: new(Split),
BottomHorizontalSplit: new(Split),
VerticalSplit: new(Split),
}
t.BottomSplit.Ratio = -.5
t.VerticalSplit.Axis = layout.Vertical
t.BottomHorizontalSplit.Ratio = -.5
t.Theme.Color.Primary = primaryColor
t.Theme.Color.InvText = black
go t.sequencerLoop(t.closer)