mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-17 20:44:29 -04:00
feat(tracker): change tracker to more material.io style
This commit is contained in:
@ -36,13 +36,18 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func smallButton(icStyle material.IconButtonStyle) material.IconButtonStyle {
|
||||||
|
icStyle.Size = unit.Dp(14)
|
||||||
|
icStyle.Inset = layout.UniformInset(unit.Dp(1))
|
||||||
|
return icStyle
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tracker) Layout(gtx layout.Context) {
|
func (t *Tracker) Layout(gtx layout.Context) {
|
||||||
paint.FillShape(gtx.Ops, black, 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 {
|
layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx2 layout.Context) layout.Dimensions {
|
||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx2,
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx2,
|
||||||
layout.Rigid(t.layoutControls),
|
layout.Rigid(t.layoutControls),
|
||||||
layout.Rigid(t.darkLine(true)),
|
layout.Flexed(1, t.layoutTracker))
|
||||||
layout.Flexed(1, Raised(t.layoutTracker)))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +61,7 @@ func (t *Tracker) layoutTracker(gtx layout.Context) layout.Dimensions {
|
|||||||
playPat = -1
|
playPat = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
rowMarkers := layout.Rigid(Lowered(t.layoutRowMarkers(
|
rowMarkers := layout.Rigid(t.layoutRowMarkers(
|
||||||
len(t.song.Tracks[0].Patterns[0]),
|
len(t.song.Tracks[0].Patterns[0]),
|
||||||
len(t.song.Tracks[0].Sequence),
|
len(t.song.Tracks[0].Sequence),
|
||||||
t.CursorRow,
|
t.CursorRow,
|
||||||
@ -64,26 +69,35 @@ func (t *Tracker) layoutTracker(gtx layout.Context) layout.Dimensions {
|
|||||||
t.CursorColumn,
|
t.CursorColumn,
|
||||||
t.PlayRow,
|
t.PlayRow,
|
||||||
playPat,
|
playPat,
|
||||||
)))
|
))
|
||||||
|
leftInset := layout.Inset{Left: unit.Dp(4)}
|
||||||
for i, trk := range t.song.Tracks {
|
for i, trk := range t.song.Tracks {
|
||||||
flexTracks[i] = layout.Rigid(Lowered(t.layoutTrack(
|
i2 := i // avoids i being updated in the closure
|
||||||
trk.Patterns,
|
trk2 := trk // avoids trk being updated in the closure
|
||||||
trk.Sequence,
|
flexTracks[i] = layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
t.ActiveTrack == i,
|
return leftInset.Layout(gtx, t.layoutTrack(
|
||||||
t.CursorRow,
|
trk2.Patterns,
|
||||||
t.DisplayPattern,
|
trk2.Sequence,
|
||||||
t.CursorColumn,
|
t.ActiveTrack == i2,
|
||||||
t.PlayRow,
|
t.CursorRow,
|
||||||
playPat,
|
t.DisplayPattern,
|
||||||
)))
|
t.CursorColumn,
|
||||||
|
t.PlayRow,
|
||||||
|
playPat,
|
||||||
|
))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
in := layout.UniformInset(unit.Dp(8))
|
in2 := layout.UniformInset(unit.Dp(8))
|
||||||
buttons := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
buttons := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
paint.FillShape(gtx.Ops, trackMenuSurfaceColor, clip.Rect{
|
||||||
|
Max: gtx.Constraints.Max,
|
||||||
|
}.Op())
|
||||||
iconBtn := material.IconButton(t.Theme, t.NewTrackBtn, addIcon)
|
iconBtn := material.IconButton(t.Theme, t.NewTrackBtn, addIcon)
|
||||||
if t.song.TotalTrackVoices() >= t.song.Patch.TotalVoices() {
|
if t.song.TotalTrackVoices() >= t.song.Patch.TotalVoices() {
|
||||||
iconBtn.Color = inactiveBtnColor
|
iconBtn.Background = disabledContainerColor
|
||||||
|
iconBtn.Color = disabledTextColor
|
||||||
}
|
}
|
||||||
return in.Layout(gtx, iconBtn.Layout)
|
return in2.Layout(gtx, iconBtn.Layout)
|
||||||
})
|
})
|
||||||
go func() {
|
go func() {
|
||||||
for t.NewTrackBtn.Clicked() {
|
for t.NewTrackBtn.Clicked() {
|
||||||
@ -113,7 +127,7 @@ func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
|
|||||||
if !t.Playing {
|
if !t.Playing {
|
||||||
playPat = -1
|
playPat = -1
|
||||||
}
|
}
|
||||||
in := layout.UniformInset(unit.Dp(8))
|
in := layout.UniformInset(unit.Dp(1))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for t.OctaveUpBtn.Clicked() {
|
for t.OctaveUpBtn.Clicked() {
|
||||||
@ -134,36 +148,34 @@ func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Rigid(Raised(t.layoutPatterns(
|
layout.Rigid(t.layoutPatterns(
|
||||||
t.song.Tracks,
|
t.song.Tracks,
|
||||||
t.ActiveTrack,
|
t.ActiveTrack,
|
||||||
t.DisplayPattern,
|
t.DisplayPattern,
|
||||||
t.CursorColumn,
|
t.CursorColumn,
|
||||||
playPat,
|
playPat,
|
||||||
))),
|
)),
|
||||||
layout.Rigid(t.darkLine(false)),
|
layout.Rigid(Label(fmt.Sprintf("OCT: %v", t.CurrentOctave), white)),
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, material.IconButton(t.Theme, t.OctaveUpBtn, upIcon).Layout)
|
return in.Layout(gtx, smallButton(material.IconButton(t.Theme, t.OctaveUpBtn, upIcon)).Layout)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(t.darkLine(false)),
|
|
||||||
layout.Rigid(Raised(Label(fmt.Sprintf("OCT: %v", t.CurrentOctave), white))),
|
|
||||||
layout.Rigid(t.darkLine(false)),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, material.IconButton(t.Theme, t.OctaveDownBtn, downIcon).Layout)
|
return in.Layout(gtx, smallButton(material.IconButton(t.Theme, t.OctaveDownBtn, downIcon)).Layout)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(t.darkLine(false)),
|
layout.Rigid(Label(fmt.Sprintf("BPM: %3v", t.song.BPM), white)),
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, material.IconButton(t.Theme, t.BPMUpBtn, upIcon).Layout)
|
return in.Layout(gtx, smallButton(material.IconButton(t.Theme, t.BPMUpBtn, upIcon)).Layout)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(t.darkLine(false)),
|
|
||||||
layout.Rigid(Raised(Label(fmt.Sprintf("BPM: %3v", t.song.BPM), white))),
|
|
||||||
layout.Rigid(t.darkLine(false)),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, material.IconButton(t.Theme, t.BPMDownBtn, downIcon).Layout)
|
return in.Layout(gtx, smallButton(material.IconButton(t.Theme, t.BPMDownBtn, downIcon)).Layout)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(t.darkLine(false)),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, material.IconButton(t.Theme, t.NewInstrumentBtn, addIcon).Layout)
|
iconBtn := material.IconButton(t.Theme, t.NewInstrumentBtn, addIcon)
|
||||||
|
if t.song.Patch.TotalVoices() >= 32 {
|
||||||
|
iconBtn.Background = disabledContainerColor
|
||||||
|
iconBtn.Color = disabledTextColor
|
||||||
|
}
|
||||||
|
return in.Layout(gtx, iconBtn.Layout)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func (t *Tracker) layoutPatterns(tracks []sointu.Track, activeTrack, cursorPatte
|
|||||||
gtx.Constraints.Max.X = patternCellWidth * len(tracks)
|
gtx.Constraints.Max.X = patternCellWidth * len(tracks)
|
||||||
defer op.Push(gtx.Ops).Pop()
|
defer op.Push(gtx.Ops).Pop()
|
||||||
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
||||||
paint.FillShape(gtx.Ops, panelColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, trackRowHeight)}.Op())
|
paint.FillShape(gtx.Ops, patternSurfaceColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, trackRowHeight)}.Op())
|
||||||
for i, track := range tracks {
|
for i, track := range tracks {
|
||||||
pop := op.Push(gtx.Ops)
|
pop := op.Push(gtx.Ops)
|
||||||
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
||||||
@ -30,10 +30,6 @@ func (t *Tracker) layoutPatterns(tracks []sointu.Track, activeTrack, cursorPatte
|
|||||||
paint.FillShape(gtx.Ops, activeTrackColor, clip.Rect{
|
paint.FillShape(gtx.Ops, activeTrackColor, clip.Rect{
|
||||||
Max: gtx.Constraints.Max,
|
Max: gtx.Constraints.Max,
|
||||||
}.Op())
|
}.Op())
|
||||||
} else {
|
|
||||||
paint.FillShape(gtx.Ops, inactiveTrackColor, clip.Rect{
|
|
||||||
Max: gtx.Constraints.Max,
|
|
||||||
}.Op())
|
|
||||||
}
|
}
|
||||||
for j, p := range track.Sequence {
|
for j, p := range track.Sequence {
|
||||||
if j == playingPattern {
|
if j == playingPattern {
|
||||||
|
@ -19,7 +19,7 @@ func (t *Tracker) layoutRowMarkers(patternRows, sequenceLength, cursorRow, curso
|
|||||||
return func(gtx layout.Context) layout.Dimensions {
|
return func(gtx layout.Context) layout.Dimensions {
|
||||||
gtx.Constraints.Min.X = rowMarkerWidth
|
gtx.Constraints.Min.X = rowMarkerWidth
|
||||||
gtx.Constraints.Max.X = rowMarkerWidth
|
gtx.Constraints.Max.X = rowMarkerWidth
|
||||||
paint.FillShape(gtx.Ops, inactiveTrackColor, clip.Rect{
|
paint.FillShape(gtx.Ops, rowMarkerSurfaceColor, clip.Rect{
|
||||||
Max: gtx.Constraints.Max,
|
Max: gtx.Constraints.Max,
|
||||||
}.Op())
|
}.Op())
|
||||||
defer op.Push(gtx.Ops).Pop()
|
defer op.Push(gtx.Ops).Pop()
|
||||||
@ -35,13 +35,13 @@ func (t *Tracker) layoutRowMarkers(patternRows, sequenceLength, cursorRow, curso
|
|||||||
paint.FillShape(gtx.Ops, trackerPlayColor, clip.Rect{Max: image.Pt(trackWidth, trackRowHeight)}.Op())
|
paint.FillShape(gtx.Ops, trackerPlayColor, clip.Rect{Max: image.Pt(trackWidth, trackRowHeight)}.Op())
|
||||||
}
|
}
|
||||||
if j == 0 {
|
if j == 0 {
|
||||||
paint.ColorOp{Color: trackerPatMarker}.Add(gtx.Ops)
|
paint.ColorOp{Color: rowMarkerPatternTextColor}.Add(gtx.Ops)
|
||||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", i)))
|
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", i)))
|
||||||
}
|
}
|
||||||
if songRow == cursorSongRow {
|
if songRow == cursorSongRow {
|
||||||
paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops)
|
paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops)
|
||||||
} else {
|
} else {
|
||||||
paint.ColorOp{Color: trackerPatternRowTextColor}.Add(gtx.Ops)
|
paint.ColorOp{Color: rowMarkerRowTextColor}.Add(gtx.Ops)
|
||||||
}
|
}
|
||||||
op.Offset(f32.Pt(rowMarkerWidth/2, 0)).Add(gtx.Ops)
|
op.Offset(f32.Pt(rowMarkerWidth/2, 0)).Add(gtx.Ops)
|
||||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)))
|
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)))
|
||||||
|
@ -11,35 +11,60 @@ import (
|
|||||||
var fontCollection []text.FontFace = gofont.Collection()
|
var fontCollection []text.FontFace = gofont.Collection()
|
||||||
var textShaper = text.NewCache(fontCollection)
|
var textShaper = text.NewCache(fontCollection)
|
||||||
|
|
||||||
var neutral = color.RGBA{R: 38, G: 38, B: 38, A: 255}
|
var neutral = color.RGBA{R: 18, G: 18, B: 18, A: 255}
|
||||||
var light = color.RGBA{R: 128, G: 128, B: 128, A: 255}
|
var light = color.RGBA{R: 128, G: 128, B: 128, A: 255}
|
||||||
var dark = color.RGBA{R: 15, G: 15, B: 15, A: 255}
|
var dark = color.RGBA{R: 15, G: 15, B: 15, A: 255}
|
||||||
var white = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
var white = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||||
var blue = color.RGBA{R: 127, G: 127, B: 255, A: 255}
|
var blue = color.RGBA{R: 127, G: 127, B: 255, A: 255}
|
||||||
var gray = color.RGBA{R: 133, G: 133, B: 133, A: 255}
|
var gray = color.RGBA{R: 133, G: 133, B: 133, A: 255}
|
||||||
var darkGray = color.RGBA{R: 30, G: 30, B: 30, A: 255}
|
var darkGray = color.RGBA{R: 18, G: 18, B: 18, A: 255}
|
||||||
var black = color.RGBA{R: 0, G: 0, B: 0, A: 255}
|
var black = color.RGBA{R: 0, G: 0, B: 0, A: 255}
|
||||||
var yellow = color.RGBA{R: 255, G: 255, B: 130, A: 255}
|
var yellow = color.RGBA{R: 255, G: 255, B: 130, A: 255}
|
||||||
var red = color.RGBA{R: 255, G: 0, B: 0, A: 255}
|
var red = color.RGBA{R: 255, G: 0, B: 0, A: 255}
|
||||||
|
|
||||||
|
var primaryColorLight = color.RGBA{R: 243, G: 229, B: 245, A: 255}
|
||||||
|
var primaryColor = color.RGBA{R: 206, G: 147, B: 216, A: 255}
|
||||||
|
var primaryColorDark = color.RGBA{R: 123, G: 31, B: 162, A: 255}
|
||||||
|
|
||||||
|
var secondaryColorLight = color.RGBA{R: 224, G: 247, B: 250, A: 255}
|
||||||
|
var secondaryColor = color.RGBA{R: 128, G: 222, B: 234, A: 255}
|
||||||
|
var secondaryColorDark = color.RGBA{R: 0, G: 151, B: 167, A: 255}
|
||||||
|
|
||||||
|
var disabledContainerColor = color.RGBA{R: 31, G: 31, B: 31, A: 31}
|
||||||
|
var focusedContainerColor = color.RGBA{R: 31, G: 31, B: 31, A: 31}
|
||||||
|
|
||||||
|
var highEmphasisTextColor = color.RGBA{R: 222, G: 222, B: 222, A: 222}
|
||||||
|
var mediumEmphasisTextColor = color.RGBA{R: 153, G: 153, B: 153, A: 153}
|
||||||
|
var disabledTextColor = color.RGBA{R: 97, G: 97, B: 97, A: 97}
|
||||||
|
|
||||||
var panelColor = neutral
|
var panelColor = neutral
|
||||||
var panelShadeColor = neutral
|
var panelShadeColor = neutral
|
||||||
var panelLightColor = light
|
var panelLightColor = light
|
||||||
|
|
||||||
|
var backgroundColor = color.RGBA{R: 18, G: 18, B: 18, A: 255}
|
||||||
|
|
||||||
var labelFont = fontCollection[6].Font
|
var labelFont = fontCollection[6].Font
|
||||||
var labelFontSize = unit.Px(18)
|
var labelFontSize = unit.Px(18)
|
||||||
|
|
||||||
var activeTrackColor = color.RGBA{R: 45, G: 45, B: 45, A: 255}
|
var activeTrackColor = focusedContainerColor
|
||||||
var inactiveTrackColor = darkGray
|
var trackSurfaceColor = color.RGBA{R: 18, G: 18, B: 18, A: 18}
|
||||||
|
|
||||||
|
var patternSurfaceColor = color.RGBA{R: 31, G: 31, B: 31, A: 31}
|
||||||
|
|
||||||
|
var rowMarkerSurfaceColor = color.RGBA{R: 31, G: 31, B: 31, A: 31}
|
||||||
|
var rowMarkerPatternTextColor = secondaryColor
|
||||||
|
var rowMarkerRowTextColor = mediumEmphasisTextColor
|
||||||
|
|
||||||
|
var trackMenuSurfaceColor = color.RGBA{R: 31, G: 31, B: 31, A: 31}
|
||||||
|
|
||||||
var trackerFont = fontCollection[6].Font
|
var trackerFont = fontCollection[6].Font
|
||||||
var trackerFontSize = unit.Px(16)
|
var trackerFontSize = unit.Px(16)
|
||||||
var trackerInactiveTextColor = color.RGBA{R: 212, G: 212, B: 212, A: 255}
|
var trackerInactiveTextColor = highEmphasisTextColor
|
||||||
var trackerTextColor = white
|
var trackerTextColor = white
|
||||||
var trackerActiveTextColor = yellow
|
var trackerActiveTextColor = yellow
|
||||||
var trackerPatternRowTextColor = color.RGBA{R: 198, G: 198, B: 198, A: 255}
|
var trackerPatternRowTextColor = color.RGBA{R: 198, G: 198, B: 198, A: 255}
|
||||||
var trackerPlayColor = color.RGBA{R: 55, G: 55, B: 61, A: 255}
|
var trackerPlayColor = color.RGBA{R: 55, G: 55, B: 61, A: 255}
|
||||||
var trackerPatMarker = blue
|
var trackerPatMarker = primaryColor
|
||||||
var trackerCursorColor = color.RGBA{R: 38, G: 79, B: 120, A: 64}
|
var trackerCursorColor = color.RGBA{R: 38, G: 79, B: 120, A: 64}
|
||||||
|
|
||||||
var patternBgColor = black
|
var patternBgColor = black
|
||||||
|
@ -21,7 +21,7 @@ func (t *Tracker) layoutTrack(patterns [][]byte, sequence []byte, active bool, c
|
|||||||
return func(gtx layout.Context) layout.Dimensions {
|
return func(gtx layout.Context) layout.Dimensions {
|
||||||
gtx.Constraints.Min.X = trackWidth
|
gtx.Constraints.Min.X = trackWidth
|
||||||
gtx.Constraints.Max.X = trackWidth
|
gtx.Constraints.Max.X = trackWidth
|
||||||
paint.FillShape(gtx.Ops, inactiveTrackColor, clip.Rect{
|
paint.FillShape(gtx.Ops, trackSurfaceColor, clip.Rect{
|
||||||
Max: gtx.Constraints.Max,
|
Max: gtx.Constraints.Max,
|
||||||
}.Op())
|
}.Op())
|
||||||
defer op.Push(gtx.Ops).Pop()
|
defer op.Push(gtx.Ops).Pop()
|
||||||
|
@ -2,7 +2,6 @@ package tracker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gioui.org/font/gofont"
|
"gioui.org/font/gofont"
|
||||||
@ -243,7 +242,8 @@ func New(audioContext sointu.AudioContext) *Tracker {
|
|||||||
undoStack: []sointu.Song{},
|
undoStack: []sointu.Song{},
|
||||||
redoStack: []sointu.Song{},
|
redoStack: []sointu.Song{},
|
||||||
}
|
}
|
||||||
t.Theme.Color.Primary = color.RGBA{R: 64, G: 64, B: 64, A: 255}
|
t.Theme.Color.Primary = primaryColor
|
||||||
|
t.Theme.Color.InvText = black
|
||||||
go t.sequencerLoop(t.closer)
|
go t.sequencerLoop(t.closer)
|
||||||
if err := t.LoadSong(defaultSong); err != nil {
|
if err := t.LoadSong(defaultSong); err != nil {
|
||||||
panic(fmt.Errorf("cannot load default song: %w", err))
|
panic(fmt.Errorf("cannot load default song: %w", err))
|
||||||
|
Reference in New Issue
Block a user