mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
feat(tracker): implement a numeric up down widget and use that for the numbers
This commit is contained in:
parent
f665a529e5
commit
80d87dea8c
@ -69,9 +69,9 @@ func (t *Tracker) KeyEvent(e key.Event) bool {
|
|||||||
return true
|
return true
|
||||||
case `\`:
|
case `\`:
|
||||||
if e.Modifiers.Contain(key.ModShift) {
|
if e.Modifiers.Contain(key.ModShift) {
|
||||||
return t.ChangeBPM(1)
|
return t.ChangeOctave(1)
|
||||||
}
|
}
|
||||||
return t.ChangeBPM(-1)
|
return t.ChangeOctave(-1)
|
||||||
case key.NameUpArrow:
|
case key.NameUpArrow:
|
||||||
delta := -1
|
delta := -1
|
||||||
if e.Modifiers.Contain(key.ModCtrl) {
|
if e.Modifiers.Contain(key.ModCtrl) {
|
||||||
@ -161,7 +161,7 @@ func (t *Tracker) getCurrent() byte {
|
|||||||
|
|
||||||
// NotePressed handles incoming key presses while in the note column
|
// NotePressed handles incoming key presses while in the note column
|
||||||
func (t *Tracker) NotePressed(val int) {
|
func (t *Tracker) NotePressed(val int) {
|
||||||
t.SetCurrentNote(getNoteValue(int(t.CurrentOctave), val))
|
t.SetCurrentNote(getNoteValue(int(t.Octave.Value), val))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumberPressed handles incoming presses while in either of the hex number columns
|
// NumberPressed handles incoming presses while in either of the hex number columns
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package tracker
|
package tracker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
@ -156,12 +155,6 @@ func (t *Tracker) layoutTracks(gtx layout.Context) layout.Dimensions {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
in2 := layout.UniformInset(unit.Dp(8))
|
in2 := layout.UniformInset(unit.Dp(8))
|
||||||
for t.OctaveUpBtn.Clicked() {
|
|
||||||
t.ChangeOctave(1)
|
|
||||||
}
|
|
||||||
for t.OctaveDownBtn.Clicked() {
|
|
||||||
t.ChangeOctave(-1)
|
|
||||||
}
|
|
||||||
menu := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
menu := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
newTrack := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
newTrack := layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
paint.FillShape(gtx.Ops, trackMenuSurfaceColor, clip.Rect{
|
paint.FillShape(gtx.Ops, trackMenuSurfaceColor, clip.Rect{
|
||||||
@ -175,11 +168,10 @@ func (t *Tracker) layoutTracks(gtx layout.Context) layout.Dimensions {
|
|||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(
|
return layout.Flex{Axis: layout.Horizontal}.Layout(
|
||||||
gtx,
|
gtx,
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.OctaveUpBtn, upIcon)), t.CurrentOctave < 9).Layout)
|
numStyle := NumericUpDown(t.Theme, t.Octave, 0, 9)
|
||||||
}),
|
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||||
layout.Rigid(Label(fmt.Sprintf("%v", t.CurrentOctave), white)),
|
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
return in.Layout(gtx, numStyle.Layout)
|
||||||
return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.OctaveDownBtn, downIcon)), t.CurrentOctave > 0).Layout)
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -207,25 +199,17 @@ func (t *Tracker) layoutTracks(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
|
func (t *Tracker) layoutControls(gtx layout.Context) layout.Dimensions {
|
||||||
go func() {
|
go func() {
|
||||||
for t.BPMUpBtn.Clicked() {
|
/*for t.BPMUpBtn.Clicked() {
|
||||||
t.ChangeBPM(1)
|
t.ChangeBPM(1)
|
||||||
}
|
}
|
||||||
for t.BPMDownBtn.Clicked() {
|
for t.BPMDownBtn.Clicked() {
|
||||||
t.ChangeBPM(-1)
|
t.ChangeBPM(-1)
|
||||||
}
|
}*/
|
||||||
for t.NewInstrumentBtn.Clicked() {
|
for t.NewInstrumentBtn.Clicked() {
|
||||||
t.AddInstrument()
|
t.AddInstrument()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for t.SongLengthUpBtn.Clicked() {
|
|
||||||
t.IncreaseSongLength()
|
|
||||||
}
|
|
||||||
|
|
||||||
for t.SongLengthDownBtn.Clicked() {
|
|
||||||
t.DecreaseSongLength()
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.TopHorizontalSplit.Layout(gtx,
|
return t.TopHorizontalSplit.Layout(gtx,
|
||||||
t.layoutSongPanel,
|
t.layoutSongPanel,
|
||||||
t.layoutInstruments(),
|
t.layoutInstruments(),
|
||||||
|
224
tracker/numericupdown.go
Normal file
224
tracker/numericupdown.go
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
package tracker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||||
|
|
||||||
|
"gioui.org/f32"
|
||||||
|
"gioui.org/op/clip"
|
||||||
|
"gioui.org/op/paint"
|
||||||
|
"gioui.org/widget"
|
||||||
|
|
||||||
|
"gioui.org/gesture"
|
||||||
|
"gioui.org/io/pointer"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/text"
|
||||||
|
"gioui.org/unit"
|
||||||
|
"gioui.org/widget/material"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultNumericLeftIcon *widget.Icon
|
||||||
|
var defaultNumericRightIcon *widget.Icon
|
||||||
|
var defaultNumericUpIcon *widget.Icon
|
||||||
|
var defaultNumericDownIcon *widget.Icon
|
||||||
|
|
||||||
|
type NumberInput struct {
|
||||||
|
Value int
|
||||||
|
drag gesture.Drag
|
||||||
|
dragStartValue int
|
||||||
|
dragStartXY float32
|
||||||
|
clickDecrease gesture.Click
|
||||||
|
clickIncrease gesture.Click
|
||||||
|
}
|
||||||
|
|
||||||
|
type NumericUpDownStyle struct {
|
||||||
|
NumberInput *NumberInput
|
||||||
|
Min int
|
||||||
|
Max int
|
||||||
|
Axis layout.Axis
|
||||||
|
Color color.RGBA
|
||||||
|
Font text.Font
|
||||||
|
TextSize unit.Value
|
||||||
|
BorderColor color.RGBA
|
||||||
|
IconColor color.RGBA
|
||||||
|
BackgroundColor color.RGBA
|
||||||
|
CornerRadius unit.Value
|
||||||
|
Border unit.Value
|
||||||
|
ButtonWidth unit.Value
|
||||||
|
UnitsPerStep unit.Value
|
||||||
|
shaper text.Shaper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NumericUpDown(th *material.Theme, number *NumberInput, min, max int) NumericUpDownStyle {
|
||||||
|
bgColor := th.Color.Primary
|
||||||
|
bgColor.R /= 4
|
||||||
|
bgColor.G /= 4
|
||||||
|
bgColor.B /= 4
|
||||||
|
return NumericUpDownStyle{
|
||||||
|
NumberInput: number,
|
||||||
|
Min: min,
|
||||||
|
Max: max,
|
||||||
|
Axis: layout.Horizontal,
|
||||||
|
Color: white,
|
||||||
|
BorderColor: th.Color.Primary,
|
||||||
|
IconColor: th.Color.InvText,
|
||||||
|
BackgroundColor: bgColor,
|
||||||
|
CornerRadius: unit.Dp(4),
|
||||||
|
ButtonWidth: unit.Dp(16),
|
||||||
|
Border: unit.Dp(1),
|
||||||
|
UnitsPerStep: unit.Dp(8),
|
||||||
|
TextSize: th.TextSize.Scale(14.0 / 16.0),
|
||||||
|
shaper: th.Shaper,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s NumericUpDownStyle) Layout(gtx C) D {
|
||||||
|
size := gtx.Constraints.Min
|
||||||
|
defer op.Push(gtx.Ops).Pop()
|
||||||
|
rr := float32(gtx.Px(s.CornerRadius))
|
||||||
|
border := float32(gtx.Px(s.Border))
|
||||||
|
clip.UniformRRect(f32.Rectangle{Max: f32.Point{
|
||||||
|
X: float32(gtx.Constraints.Min.X),
|
||||||
|
Y: float32(gtx.Constraints.Min.Y),
|
||||||
|
}}, rr).Add(gtx.Ops)
|
||||||
|
paint.Fill(gtx.Ops, s.BorderColor)
|
||||||
|
op.Offset(f32.Pt(border, border)).Add(gtx.Ops)
|
||||||
|
clip.UniformRRect(f32.Rectangle{Max: f32.Point{
|
||||||
|
X: float32(gtx.Constraints.Min.X) - border*2,
|
||||||
|
Y: float32(gtx.Constraints.Min.Y) - border*2,
|
||||||
|
}}, rr-border).Add(gtx.Ops)
|
||||||
|
gtx.Constraints.Min.X -= int(border * 2)
|
||||||
|
gtx.Constraints.Min.Y -= int(border * 2)
|
||||||
|
gtx.Constraints.Max = gtx.Constraints.Min
|
||||||
|
layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||||
|
layout.Rigid(s.button(gtx.Constraints.Max.Y, defaultNumericLeftIcon, -1, &s.NumberInput.clickDecrease)),
|
||||||
|
layout.Flexed(1, s.layoutText),
|
||||||
|
layout.Rigid(s.button(gtx.Constraints.Max.Y, defaultNumericRightIcon, 1, &s.NumberInput.clickIncrease)),
|
||||||
|
)
|
||||||
|
if s.NumberInput.Value < s.Min {
|
||||||
|
s.NumberInput.Value = s.Min
|
||||||
|
}
|
||||||
|
if s.NumberInput.Value > s.Max {
|
||||||
|
s.NumberInput.Value = s.Max
|
||||||
|
}
|
||||||
|
return layout.Dimensions{Size: size}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s NumericUpDownStyle) button(height int, icon *widget.Icon, delta int, click *gesture.Click) layout.Widget {
|
||||||
|
return func(gtx C) D {
|
||||||
|
btnWidth := gtx.Px(s.ButtonWidth)
|
||||||
|
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||||
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
//paint.FillShape(gtx.Ops, black, clip.Rect(image.Rect(0, 0, btnWidth, height)).Op())
|
||||||
|
return layout.Dimensions{Size: image.Point{X: btnWidth, Y: height}}
|
||||||
|
}),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
size := btnWidth
|
||||||
|
if height < size {
|
||||||
|
size = height
|
||||||
|
}
|
||||||
|
if icon != nil {
|
||||||
|
icon.Color = s.IconColor
|
||||||
|
return icon.Layout(gtx, unit.Px(float32(size)))
|
||||||
|
}
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}),
|
||||||
|
layout.Expanded(func(gtx C) D {
|
||||||
|
return s.layoutClick(gtx, delta, click)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s NumericUpDownStyle) layoutText(gtx C) D {
|
||||||
|
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||||
|
layout.Stacked(func(gtx C) D {
|
||||||
|
paint.FillShape(gtx.Ops, s.BackgroundColor, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
|
||||||
|
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||||
|
}),
|
||||||
|
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
paint.ColorOp{Color: s.Color}.Add(gtx.Ops)
|
||||||
|
return widget.Label{Alignment: text.Middle}.Layout(gtx, s.shaper, s.Font, s.TextSize, fmt.Sprintf("%v", s.NumberInput.Value))
|
||||||
|
}),
|
||||||
|
layout.Expanded(s.layoutDrag),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s NumericUpDownStyle) layoutDrag(gtx layout.Context) layout.Dimensions {
|
||||||
|
{ // handle dragging
|
||||||
|
pxPerStep := float32(gtx.Px(s.UnitsPerStep))
|
||||||
|
for _, e := range s.NumberInput.drag.Events(gtx.Metric, gtx, gesture.Axis(s.Axis)) {
|
||||||
|
switch e.Type {
|
||||||
|
case pointer.Press:
|
||||||
|
s.NumberInput.dragStartValue = s.NumberInput.Value
|
||||||
|
if s.Axis == layout.Horizontal {
|
||||||
|
s.NumberInput.dragStartXY = e.Position.X
|
||||||
|
} else {
|
||||||
|
s.NumberInput.dragStartXY = e.Position.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
case pointer.Drag:
|
||||||
|
var deltaCoord float32
|
||||||
|
if s.Axis == layout.Horizontal {
|
||||||
|
deltaCoord = e.Position.X - s.NumberInput.dragStartXY
|
||||||
|
} else {
|
||||||
|
deltaCoord = e.Position.Y - s.NumberInput.dragStartXY
|
||||||
|
}
|
||||||
|
|
||||||
|
s.NumberInput.Value = s.NumberInput.dragStartValue + int(deltaCoord/pxPerStep+0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid affecting the input tree with pointer events.
|
||||||
|
stack := op.Push(gtx.Ops)
|
||||||
|
// register for input
|
||||||
|
dragRect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||||
|
pointer.Rect(dragRect).Add(gtx.Ops)
|
||||||
|
s.NumberInput.drag.Add(gtx.Ops)
|
||||||
|
stack.Pop()
|
||||||
|
}
|
||||||
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s NumericUpDownStyle) layoutClick(gtx layout.Context, delta int, click *gesture.Click) layout.Dimensions {
|
||||||
|
// handle clicking
|
||||||
|
for _, e := range click.Events(gtx) {
|
||||||
|
switch e.Type {
|
||||||
|
case gesture.TypeClick:
|
||||||
|
s.NumberInput.Value += delta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Avoid affecting the input tree with pointer events.
|
||||||
|
stack := op.Push(gtx.Ops)
|
||||||
|
// register for input
|
||||||
|
clickRect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||||
|
pointer.Rect(clickRect).Add(gtx.Ops)
|
||||||
|
click.Add(gtx.Ops)
|
||||||
|
stack.Pop()
|
||||||
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
defaultNumericLeftIcon, err = widget.NewIcon(icons.NavigationArrowBack)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defaultNumericRightIcon, err = widget.NewIcon(icons.NavigationArrowForward)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defaultNumericUpIcon, err = widget.NewIcon(icons.NavigationArrowDropUp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defaultNumericDownIcon, err = widget.NewIcon(icons.NavigationArrowDropDown)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package tracker
|
package tracker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"image"
|
"image"
|
||||||
|
"math"
|
||||||
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
@ -68,23 +68,30 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
|||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Rigid(Label(fmt.Sprintf("LEN: %3v", t.song.SequenceLength()), white)),
|
layout.Rigid(Label("LEN:", white)),
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, smallButton(material.IconButton(t.Theme, t.SongLengthUpBtn, upIcon)).Layout)
|
t.SongLength.Value = t.song.SequenceLength()
|
||||||
}),
|
numStyle := NumericUpDown(t.Theme, t.SongLength, 1, math.MaxInt32)
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||||
return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.SongLengthDownBtn, downIcon)), t.song.SequenceLength() > 1).Layout)
|
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||||
|
dims := in.Layout(gtx, numStyle.Layout)
|
||||||
|
t.SetSongLength(t.SongLength.Value)
|
||||||
|
return dims
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Rigid(Label(fmt.Sprintf("BPM: %3v", t.song.BPM), white)),
|
layout.Rigid(Label("BPM:", white)),
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.BPMUpBtn, upIcon)), t.song.BPM < 999).Layout)
|
t.BPM.Value = t.song.BPM
|
||||||
}),
|
numStyle := NumericUpDown(t.Theme, t.BPM, 1, 999)
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||||
return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.BPMDownBtn, downIcon)), t.song.BPM > 1).Layout)
|
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||||
|
dims := in.Layout(gtx, numStyle.Layout)
|
||||||
|
t.SetBPM(t.BPM.Value)
|
||||||
|
return dims
|
||||||
|
//return in.Layout(gtx, enableButton(smallButton(material.IconButton(t.Theme, t.BPMUpBtn, upIcon)), t.song.BPM < 999).Layout)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
@ -27,19 +27,15 @@ type Tracker struct {
|
|||||||
ActiveTrack int
|
ActiveTrack int
|
||||||
CurrentInstrument int
|
CurrentInstrument int
|
||||||
CurrentUnit int
|
CurrentUnit int
|
||||||
CurrentOctave byte
|
|
||||||
NoteTracking bool
|
NoteTracking bool
|
||||||
Theme *material.Theme
|
Theme *material.Theme
|
||||||
OctaveUpBtn *widget.Clickable
|
Octave *NumberInput
|
||||||
OctaveDownBtn *widget.Clickable
|
BPM *NumberInput
|
||||||
BPMUpBtn *widget.Clickable
|
|
||||||
BPMDownBtn *widget.Clickable
|
|
||||||
NewTrackBtn *widget.Clickable
|
NewTrackBtn *widget.Clickable
|
||||||
NewInstrumentBtn *widget.Clickable
|
NewInstrumentBtn *widget.Clickable
|
||||||
LoadSongFileBtn *widget.Clickable
|
LoadSongFileBtn *widget.Clickable
|
||||||
NewSongFileBtn *widget.Clickable
|
NewSongFileBtn *widget.Clickable
|
||||||
SongLengthUpBtn *widget.Clickable
|
SongLength *NumberInput
|
||||||
SongLengthDownBtn *widget.Clickable
|
|
||||||
SaveSongFileBtn *widget.Clickable
|
SaveSongFileBtn *widget.Clickable
|
||||||
ParameterSliders []*widget.Float
|
ParameterSliders []*widget.Float
|
||||||
UnitBtns []*widget.Clickable
|
UnitBtns []*widget.Clickable
|
||||||
@ -174,31 +170,30 @@ func (t *Tracker) sequencerLoop(closer <-chan struct{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) ChangeOctave(delta int) bool {
|
func (t *Tracker) ChangeOctave(delta int) bool {
|
||||||
newOctave := int(t.CurrentOctave) + delta
|
newOctave := t.Octave.Value + delta
|
||||||
if newOctave < 0 {
|
if newOctave < 0 {
|
||||||
newOctave = 0
|
newOctave = 0
|
||||||
}
|
}
|
||||||
if newOctave > 9 {
|
if newOctave > 9 {
|
||||||
newOctave = 9
|
newOctave = 9
|
||||||
}
|
}
|
||||||
if newOctave != int(t.CurrentOctave) {
|
if newOctave != t.Octave.Value {
|
||||||
t.CurrentOctave = byte(newOctave)
|
t.Octave.Value = newOctave
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) ChangeBPM(delta int) bool {
|
func (t *Tracker) SetBPM(value int) bool {
|
||||||
|
if value < 1 {
|
||||||
|
value = 1
|
||||||
|
}
|
||||||
|
if value > 999 {
|
||||||
|
value = 999
|
||||||
|
}
|
||||||
|
if value != int(t.song.BPM) {
|
||||||
t.SaveUndo()
|
t.SaveUndo()
|
||||||
newBPM := t.song.BPM + delta
|
t.song.BPM = value
|
||||||
if newBPM < 1 {
|
|
||||||
newBPM = 1
|
|
||||||
}
|
|
||||||
if newBPM > 999 {
|
|
||||||
newBPM = 999
|
|
||||||
}
|
|
||||||
if newBPM != int(t.song.BPM) {
|
|
||||||
t.song.BPM = newBPM
|
|
||||||
t.sequencer.SetRowLength(44100 * 60 / (4 * t.song.BPM))
|
t.sequencer.SetRowLength(44100 * 60 / (4 * t.song.BPM))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -261,19 +256,22 @@ func (t *Tracker) SetCurrentPattern(pat byte) {
|
|||||||
t.song.Tracks[t.ActiveTrack].Sequence[t.DisplayPattern] = pat
|
t.song.Tracks[t.ActiveTrack].Sequence[t.DisplayPattern] = pat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) IncreaseSongLength() {
|
func (t *Tracker) SetSongLength(value int) {
|
||||||
|
if value < 1 {
|
||||||
|
value = 1
|
||||||
|
}
|
||||||
|
if value != t.song.SequenceLength() {
|
||||||
t.SaveUndo()
|
t.SaveUndo()
|
||||||
for i := range t.song.Tracks {
|
for i := range t.song.Tracks {
|
||||||
seq := t.song.Tracks[i].Sequence
|
seq := t.song.Tracks[i].Sequence
|
||||||
|
if len(t.song.Tracks[i].Sequence) > value {
|
||||||
|
t.song.Tracks[i].Sequence = t.song.Tracks[i].Sequence[:value]
|
||||||
|
} else if len(t.song.Tracks[i].Sequence) < value {
|
||||||
|
for k := len(t.song.Tracks[i].Sequence); k < value; k++ {
|
||||||
t.song.Tracks[i].Sequence = append(seq, seq[len(seq)-1])
|
t.song.Tracks[i].Sequence = append(seq, seq[len(seq)-1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) DecreaseSongLength() {
|
|
||||||
t.SaveUndo()
|
|
||||||
for i := range t.song.Tracks {
|
|
||||||
if len(t.song.Tracks[i].Sequence) > 0 {
|
|
||||||
t.song.Tracks[i].Sequence = t.song.Tracks[i].Sequence[0 : len(t.song.Tracks[i].Sequence)-1]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,19 +280,15 @@ func New(audioContext sointu.AudioContext) *Tracker {
|
|||||||
t := &Tracker{
|
t := &Tracker{
|
||||||
Theme: material.NewTheme(gofont.Collection()),
|
Theme: material.NewTheme(gofont.Collection()),
|
||||||
QuitButton: new(widget.Clickable),
|
QuitButton: new(widget.Clickable),
|
||||||
CurrentOctave: 4,
|
|
||||||
audioContext: audioContext,
|
audioContext: audioContext,
|
||||||
OctaveUpBtn: new(widget.Clickable),
|
BPM: new(NumberInput),
|
||||||
OctaveDownBtn: new(widget.Clickable),
|
Octave: new(NumberInput),
|
||||||
BPMUpBtn: new(widget.Clickable),
|
SongLength: new(NumberInput),
|
||||||
BPMDownBtn: new(widget.Clickable),
|
|
||||||
NewTrackBtn: new(widget.Clickable),
|
NewTrackBtn: new(widget.Clickable),
|
||||||
NewInstrumentBtn: new(widget.Clickable),
|
NewInstrumentBtn: new(widget.Clickable),
|
||||||
NewSongFileBtn: new(widget.Clickable),
|
NewSongFileBtn: new(widget.Clickable),
|
||||||
LoadSongFileBtn: new(widget.Clickable),
|
LoadSongFileBtn: new(widget.Clickable),
|
||||||
SaveSongFileBtn: new(widget.Clickable),
|
SaveSongFileBtn: new(widget.Clickable),
|
||||||
SongLengthUpBtn: new(widget.Clickable),
|
|
||||||
SongLengthDownBtn: new(widget.Clickable),
|
|
||||||
setPlaying: make(chan bool),
|
setPlaying: make(chan bool),
|
||||||
rowJump: make(chan int),
|
rowJump: make(chan int),
|
||||||
patternJump: make(chan int),
|
patternJump: make(chan int),
|
||||||
@ -307,6 +301,7 @@ func New(audioContext sointu.AudioContext) *Tracker {
|
|||||||
BottomHorizontalSplit: new(Split),
|
BottomHorizontalSplit: new(Split),
|
||||||
VerticalSplit: new(Split),
|
VerticalSplit: new(Split),
|
||||||
}
|
}
|
||||||
|
t.Octave.Value = 4
|
||||||
t.VerticalSplit.Axis = layout.Vertical
|
t.VerticalSplit.Axis = layout.Vertical
|
||||||
t.BottomHorizontalSplit.Ratio = -.5
|
t.BottomHorizontalSplit.Ratio = -.5
|
||||||
t.Theme.Color.Primary = primaryColor
|
t.Theme.Color.Primary = primaryColor
|
||||||
|
Loading…
x
Reference in New Issue
Block a user