diff --git a/tracker/layout.go b/tracker/layout.go index fe7cd87..c21678f 100644 --- a/tracker/layout.go +++ b/tracker/layout.go @@ -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) { - 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 { return layout.Flex{Axis: layout.Vertical}.Layout(gtx2, layout.Rigid(t.layoutControls), - layout.Rigid(t.darkLine(true)), - layout.Flexed(1, Raised(t.layoutTracker))) + layout.Flexed(1, t.layoutTracker)) }) } @@ -56,7 +61,7 @@ func (t *Tracker) layoutTracker(gtx layout.Context) layout.Dimensions { 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].Sequence), t.CursorRow, @@ -64,26 +69,35 @@ func (t *Tracker) layoutTracker(gtx layout.Context) layout.Dimensions { t.CursorColumn, t.PlayRow, playPat, - ))) + )) + leftInset := layout.Inset{Left: unit.Dp(4)} for i, trk := range t.song.Tracks { - flexTracks[i] = layout.Rigid(Lowered(t.layoutTrack( - trk.Patterns, - trk.Sequence, - t.ActiveTrack == i, - t.CursorRow, - t.DisplayPattern, - t.CursorColumn, - t.PlayRow, - playPat, - ))) + i2 := i // avoids i being updated in the closure + trk2 := trk // avoids trk being updated in the closure + flexTracks[i] = layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return leftInset.Layout(gtx, t.layoutTrack( + trk2.Patterns, + trk2.Sequence, + t.ActiveTrack == i2, + t.CursorRow, + 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 { + paint.FillShape(gtx.Ops, trackMenuSurfaceColor, clip.Rect{ + Max: gtx.Constraints.Max, + }.Op()) iconBtn := material.IconButton(t.Theme, t.NewTrackBtn, addIcon) 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() { for t.NewTrackBtn.Clicked() { @@ -113,7 +127,7 @@ func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions { if !t.Playing { playPat = -1 } - in := layout.UniformInset(unit.Dp(8)) + in := layout.UniformInset(unit.Dp(1)) go func() { 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, - layout.Rigid(Raised(t.layoutPatterns( + layout.Rigid(t.layoutPatterns( t.song.Tracks, t.ActiveTrack, t.DisplayPattern, t.CursorColumn, playPat, - ))), - layout.Rigid(t.darkLine(false)), + )), + layout.Rigid(Label(fmt.Sprintf("OCT: %v", t.CurrentOctave), white)), 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 { - 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 { - 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 { - 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 { - 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) }), ) } diff --git a/tracker/patterns.go b/tracker/patterns.go index e5a947e..ffa022b 100644 --- a/tracker/patterns.go +++ b/tracker/patterns.go @@ -22,7 +22,7 @@ func (t *Tracker) layoutPatterns(tracks []sointu.Track, activeTrack, cursorPatte gtx.Constraints.Max.X = patternCellWidth * len(tracks) defer op.Push(gtx.Ops).Pop() 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 { pop := op.Push(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{ Max: gtx.Constraints.Max, }.Op()) - } else { - paint.FillShape(gtx.Ops, inactiveTrackColor, clip.Rect{ - Max: gtx.Constraints.Max, - }.Op()) } for j, p := range track.Sequence { if j == playingPattern { diff --git a/tracker/rowmarkers.go b/tracker/rowmarkers.go index 73db753..519e6ab 100644 --- a/tracker/rowmarkers.go +++ b/tracker/rowmarkers.go @@ -19,7 +19,7 @@ func (t *Tracker) layoutRowMarkers(patternRows, sequenceLength, cursorRow, curso return func(gtx layout.Context) layout.Dimensions { gtx.Constraints.Min.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, }.Op()) 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()) } 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))) } if songRow == cursorSongRow { paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops) } 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) widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j))) diff --git a/tracker/theme.go b/tracker/theme.go index 6280df8..0437a13 100644 --- a/tracker/theme.go +++ b/tracker/theme.go @@ -11,35 +11,60 @@ import ( var fontCollection []text.FontFace = gofont.Collection() 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 dark = color.RGBA{R: 15, G: 15, B: 15, 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 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 yellow = color.RGBA{R: 255, G: 255, B: 130, 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 panelShadeColor = neutral var panelLightColor = light +var backgroundColor = color.RGBA{R: 18, G: 18, B: 18, A: 255} + var labelFont = fontCollection[6].Font var labelFontSize = unit.Px(18) -var activeTrackColor = color.RGBA{R: 45, G: 45, B: 45, A: 255} -var inactiveTrackColor = darkGray +var activeTrackColor = focusedContainerColor +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 trackerFontSize = unit.Px(16) -var trackerInactiveTextColor = color.RGBA{R: 212, G: 212, B: 212, A: 255} +var trackerInactiveTextColor = highEmphasisTextColor var trackerTextColor = white var trackerActiveTextColor = yellow 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 trackerPatMarker = blue +var trackerPatMarker = primaryColor var trackerCursorColor = color.RGBA{R: 38, G: 79, B: 120, A: 64} var patternBgColor = black diff --git a/tracker/track.go b/tracker/track.go index 74eade1..f1208e7 100644 --- a/tracker/track.go +++ b/tracker/track.go @@ -21,7 +21,7 @@ func (t *Tracker) layoutTrack(patterns [][]byte, sequence []byte, active bool, c return func(gtx layout.Context) layout.Dimensions { gtx.Constraints.Min.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, }.Op()) defer op.Push(gtx.Ops).Pop() diff --git a/tracker/tracker.go b/tracker/tracker.go index 6753f0a..83ed7f1 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -2,7 +2,6 @@ package tracker import ( "fmt" - "image/color" "sync" "gioui.org/font/gofont" @@ -243,7 +242,8 @@ func New(audioContext sointu.AudioContext) *Tracker { undoStack: []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) if err := t.LoadSong(defaultSong); err != nil { panic(fmt.Errorf("cannot load default song: %w", err))