From f665a529e5e1720b2d9a037e877690d4f05cdfc6 Mon Sep 17 00:00:00 2001 From: vsariola <5684185+vsariola@users.noreply.github.com> Date: Fri, 15 Jan 2021 12:42:06 +0200 Subject: [PATCH] feat(tracker): add adjustable vertical split between top and bottom --- tracker/layout.go | 15 ++---- tracker/split.go | 77 +++++++++++++++++++++-------- tracker/tracker.go | 117 +++++++++++++++++++++++---------------------- 3 files changed, 121 insertions(+), 88 deletions(-) diff --git a/tracker/layout.go b/tracker/layout.go index 6cca282..9ec419f 100644 --- a/tracker/layout.go +++ b/tracker/layout.go @@ -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(), ) diff --git a/tracker/split.go b/tracker/split.go index ad314f7..1df7e7a 100644 --- a/tracker/split.go +++ b/tracker/split.go @@ -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() } diff --git a/tracker/tracker.go b/tracker/tracker.go index b095db2..f2241db 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -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)