mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
feat(tracker): add adjustable vertical split between top and bottom
This commit is contained in:
parent
c90f8efbdc
commit
f665a529e5
@ -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(),
|
||||
)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user