diff --git a/tracker/gioui/keyevent.go b/tracker/gioui/keyevent.go index 5b59237..420ab00 100644 --- a/tracker/gioui/keyevent.go +++ b/tracker/gioui/keyevent.go @@ -241,6 +241,7 @@ func (t *Tracker) KeyEvent(w *app.Window, e key.Event) bool { if !e.Modifiers.Contain(key.ModShift) { t.SetSelectionCorner(t.Cursor()) } + scrollToView(t.PatternOrderList, t.Cursor().Pattern, t.Song().Score.Length) return true case key.NameDownArrow: cursor := t.Cursor() @@ -272,6 +273,7 @@ func (t *Tracker) KeyEvent(w *app.Window, e key.Event) bool { if !e.Modifiers.Contain(key.ModShift) { t.SetSelectionCorner(t.Cursor()) } + scrollToView(t.PatternOrderList, t.Cursor().Pattern, t.Song().Score.Length) return true case key.NameLeftArrow: cursor := t.Cursor() diff --git a/tracker/gioui/patterns.go b/tracker/gioui/patterns.go index cd72d3e..fc7f93c 100644 --- a/tracker/gioui/patterns.go +++ b/tracker/gioui/patterns.go @@ -69,7 +69,7 @@ func (t *Tracker) layoutPatterns(gtx C) D { op.Offset(f32.Pt(0, patternCellHeight)).Add(gtx.Ops) gtx.Constraints.Max.Y -= patternCellHeight gtx.Constraints.Min.Y -= patternCellHeight - for j := 0; j < t.Song().Score.Length; j++ { + element := func(gtx C, j int) D { if playPos, ok := t.player.Position(); ok && j == playPos.Pattern { paint.FillShape(gtx.Ops, patternPlayColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, patternCellHeight)}.Op()) } @@ -80,7 +80,7 @@ func (t *Tracker) layoutPatterns(gtx C) D { for i, track := range t.Song().Score.Tracks { paint.FillShape(gtx.Ops, patternCellColor, clip.Rect{Min: image.Pt(1, 1), Max: image.Pt(patternCellWidth-1, patternCellHeight-1)}.Op()) paint.ColorOp{Color: patternTextColor}.Add(gtx.Ops) - if j < len(track.Order) && track.Order[j] >= 0 { + if j >= 0 && j < len(track.Order) && track.Order[j] >= 0 { gtx := gtx gtx.Constraints.Max.X = patternCellWidth op.Offset(f32.Pt(0, -2)).Add(gtx.Ops) @@ -103,9 +103,16 @@ func (t *Tracker) layoutPatterns(gtx C) D { op.Offset(f32.Pt(patternCellWidth, 0)).Add(gtx.Ops) } stack.Load() - op.Offset(f32.Pt(0, patternCellHeight)).Add(gtx.Ops) + return D{Size: image.Pt(gtx.Constraints.Max.X, patternCellHeight)} } - return layout.Dimensions{Size: gtx.Constraints.Max} + return layout.Stack{Alignment: layout.NE}.Layout(gtx, + layout.Expanded(func(gtx C) D { + return t.PatternOrderList.Layout(gtx, t.Song().Score.Length, element) + }), + layout.Expanded(func(gtx C) D { + return t.PatternOrderScrollBar.Layout(gtx, unit.Dp(10), t.Song().Score.Length, &t.PatternOrderList.Position) + }), + ) } func patternIndexToString(index int) string { diff --git a/tracker/gioui/scrollbar.go b/tracker/gioui/scrollbar.go index 5819df7..1e35be2 100644 --- a/tracker/gioui/scrollbar.go +++ b/tracker/gioui/scrollbar.go @@ -126,3 +126,28 @@ func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Po return D{Size: gtx.Constraints.Min} } + +func scrollToView(l *layout.List, index int, length int) { + pmin := index + 2 - l.Position.Count + pmax := index - 1 + if pmin < 0 { + pmin = 0 + } + if pmax < 0 { + pmax = 0 + } + m := length - 1 + if pmin > m { + pmin = m + } + if pmax > m { + pmax = m + } + if l.Position.First > pmax { + l.Position.First = pmax + l.Position.Offset = 0 + } + if l.Position.First < pmin { + l.Position.First = pmin + } +} diff --git a/tracker/gioui/tracker.go b/tracker/gioui/tracker.go index 2195065..0daf9ae 100644 --- a/tracker/gioui/tracker.go +++ b/tracker/gioui/tracker.go @@ -59,6 +59,8 @@ type Tracker struct { StackUse []int KeyPlaying map[string]uint32 Alert Alert + PatternOrderList *layout.List + PatternOrderScrollBar *ScrollBar lastVolume tracker.Volume volumeChan chan tracker.Volume @@ -146,6 +148,8 @@ func New(audioContext sointu.AudioContext, synthService sointu.SynthService, syn KeyPlaying: make(map[string]uint32), volumeChan: make(chan tracker.Volume, 1), playerCloser: make(chan struct{}), + PatternOrderList: &layout.List{Axis: layout.Vertical}, + PatternOrderScrollBar: &ScrollBar{Axis: layout.Vertical}, } t.Model = tracker.NewModel() vuBufferObserver := make(chan []float32)