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) { 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()) 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 { t.VerticalSplit.Layout(gtx,
return layout.Flex{Axis: layout.Vertical}.Layout(gtx2, t.layoutControls,
layout.Rigid(t.layoutControls), t.layoutTracksAndPatterns)
layout.Flexed(1, t.layoutTracksAndPatterns))
})
t.updateInstrumentScroll() t.updateInstrumentScroll()
} }
@ -90,7 +88,7 @@ func (t *Tracker) layoutTracksAndPatterns(gtx layout.Context) layout.Dimensions
if !t.Playing { if !t.Playing {
playPat = -1 playPat = -1
} }
return t.BottomSplit.Layout(gtx, return t.BottomHorizontalSplit.Layout(gtx,
t.layoutPatterns( t.layoutPatterns(
t.song.Tracks, t.song.Tracks,
t.ActiveTrack, t.ActiveTrack,
@ -208,9 +206,6 @@ func (t *Tracker) layoutTracks(gtx layout.Context) layout.Dimensions {
} }
func (t *Tracker) layoutControls(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() { go func() {
for t.BPMUpBtn.Clicked() { for t.BPMUpBtn.Clicked() {
t.ChangeBPM(1) t.ChangeBPM(1)
@ -231,7 +226,7 @@ func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
t.DecreaseSongLength() t.DecreaseSongLength()
} }
return t.TopSplit.Layout(gtx, return t.TopHorizontalSplit.Layout(gtx,
t.layoutSongPanel, t.layoutSongPanel,
t.layoutInstruments(), t.layoutInstruments(),
) )

View File

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

View File

@ -47,8 +47,9 @@ type Tracker struct {
InstrumentList *layout.List InstrumentList *layout.List
TrackHexCheckBoxes []*widget.Bool TrackHexCheckBoxes []*widget.Bool
TrackShowHex []bool TrackShowHex []bool
TopSplit *Split TopHorizontalSplit *Split
BottomSplit *Split BottomHorizontalSplit *Split
VerticalSplit *Split
sequencer *Sequencer sequencer *Sequencer
ticked chan struct{} ticked chan struct{}
@ -302,10 +303,12 @@ func New(audioContext sointu.AudioContext) *Tracker {
undoStack: []sointu.Song{}, undoStack: []sointu.Song{},
redoStack: []sointu.Song{}, redoStack: []sointu.Song{},
InstrumentList: &layout.List{Axis: layout.Horizontal}, InstrumentList: &layout.List{Axis: layout.Horizontal},
TopSplit: new(Split), TopHorizontalSplit: new(Split),
BottomSplit: 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.Primary = primaryColor
t.Theme.Color.InvText = black t.Theme.Color.InvText = black
go t.sequencerLoop(t.closer) go t.sequencerLoop(t.closer)