mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-19 05:24:48 -04:00
refactor(tracker/gioui): update gioui to newer version
This commit is contained in:
parent
f5980ecb79
commit
8c4f7ee61f
@ -1,10 +1,10 @@
|
||||
package gioui
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
@ -94,10 +94,10 @@ func (a *Alert) Layout(gtx C) D {
|
||||
}.Op())
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
}
|
||||
labelStyle := LabelStyle{Text: a.showMessage, Color: textColor, ShadeColor: shadeColor, Font: labelDefaultFont, Alignment: layout.Center, FontSize: unit.Dp(16)}
|
||||
labelStyle := LabelStyle{Text: a.showMessage, Color: textColor, ShadeColor: shadeColor, Font: labelDefaultFont, Alignment: layout.Center, FontSize: unit.Sp(16)}
|
||||
return alertMargin.Layout(gtx, func(gtx C) D {
|
||||
return layout.S.Layout(gtx, func(gtx C) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
gtx.Constraints.Min.X = gtx.Constraints.Max.X
|
||||
recording := op.Record(gtx.Ops)
|
||||
dims := layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
@ -107,8 +107,8 @@ func (a *Alert) Layout(gtx C) D {
|
||||
}),
|
||||
)
|
||||
macro := recording.Stop()
|
||||
totalY := dims.Size.Y + gtx.Px(alertMargin.Bottom)
|
||||
op.Offset(f32.Pt(0, float32((1-a.pos)*float64(totalY)))).Add((gtx.Ops))
|
||||
totalY := dims.Size.Y + gtx.Dp(alertMargin.Bottom)
|
||||
op.Offset(image.Point{0, int((1 - a.pos) * float64(totalY))}).Add((gtx.Ops))
|
||||
macro.Add(gtx.Ops)
|
||||
return dims
|
||||
})
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func IconButton(th *material.Theme, w *widget.Clickable, icon []byte, enabled bool) material.IconButtonStyle {
|
||||
ret := material.IconButton(th, w, widgetForIcon(icon))
|
||||
ret := material.IconButton(th, w, widgetForIcon(icon), "")
|
||||
ret.Background = transparent
|
||||
ret.Inset = layout.UniformInset(unit.Dp(6))
|
||||
if enabled {
|
||||
|
@ -46,7 +46,7 @@ func (d *DialogStyle) Layout(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(Label(d.Text, highEmphasisTextColor)),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(120))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(120))
|
||||
if d.ShowAlt {
|
||||
return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx,
|
||||
layout.Rigid(d.OkStyle.Layout),
|
||||
|
@ -59,7 +59,13 @@ func (d *DragList) Focused() bool {
|
||||
func (s *FilledDragListStyle) Layout(gtx C) D {
|
||||
swap := 0
|
||||
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
keys := key.Set("↑|↓|Ctrl-↑|Ctrl-↓")
|
||||
if s.dragList.List.Axis == layout.Horizontal {
|
||||
keys = key.Set("←|→|Ctrl-←|Ctrl-→")
|
||||
}
|
||||
key.InputOp{Tag: &s.dragList.mainTag, Keys: keys}.Add(gtx.Ops)
|
||||
|
||||
if s.dragList.List.Axis == layout.Horizontal {
|
||||
gtx.Constraints.Min.X = gtx.Constraints.Max.X
|
||||
@ -121,7 +127,7 @@ func (s *FilledDragListStyle) Layout(gtx C) D {
|
||||
}
|
||||
|
||||
inputFg := func(gtx C) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
//defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
for _, ev := range gtx.Events(&s.dragList.tags[index]) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
if !ok {
|
||||
@ -143,12 +149,13 @@ func (s *FilledDragListStyle) Layout(gtx C) D {
|
||||
}
|
||||
}
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &s.dragList.tags[index],
|
||||
Types: pointer.Press | pointer.Enter | pointer.Leave,
|
||||
}.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
if index == s.dragList.SelectedItem {
|
||||
for _, ev := range gtx.Events(s.dragList) {
|
||||
for _, ev := range gtx.Events(&s.dragList.focused) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
if !ok {
|
||||
continue
|
||||
@ -156,6 +163,7 @@ func (s *FilledDragListStyle) Layout(gtx C) D {
|
||||
switch e.Type {
|
||||
case pointer.Press:
|
||||
s.dragList.dragID = e.PointerID
|
||||
s.dragList.drag = true
|
||||
case pointer.Drag:
|
||||
if s.dragList.dragID != e.PointerID {
|
||||
break
|
||||
@ -181,22 +189,24 @@ func (s *FilledDragListStyle) Layout(gtx C) D {
|
||||
s.dragList.drag = false
|
||||
}
|
||||
}
|
||||
pointer.InputOp{Tag: s.dragList,
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &s.dragList.focused,
|
||||
Types: pointer.Drag | pointer.Press | pointer.Release,
|
||||
Grab: s.dragList.drag,
|
||||
}.Add(gtx.Ops)
|
||||
pointer.CursorNameOp{Name: pointer.CursorGrab}.Add(gtx.Ops)
|
||||
pointer.CursorGrab.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
return layout.Stack{Alignment: layout.W}.Layout(gtx,
|
||||
layout.Expanded(bg),
|
||||
layout.Expanded(inputFg),
|
||||
layout.Stacked(func(gtx C) D {
|
||||
return s.element(gtx, index)
|
||||
}),
|
||||
layout.Expanded(inputFg))
|
||||
)
|
||||
}
|
||||
key.InputOp{Tag: &s.dragList.mainTag}.Add(gtx.Ops)
|
||||
dims := s.dragList.List.Layout(gtx, s.Count, listElem)
|
||||
if !s.dragList.swapped && swap != 0 && s.dragList.SelectedItem+swap >= 0 && s.dragList.SelectedItem+swap < s.Count {
|
||||
s.swap(s.dragList.SelectedItem, s.dragList.SelectedItem+swap)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/unit"
|
||||
"gioui.org/widget"
|
||||
@ -77,7 +78,7 @@ func commonFileDialog(th *material.Theme, f *FileDialog) FileDialogStyle {
|
||||
DirEditorStyle: material.Editor(th, &f.Directory, "Directory"),
|
||||
FileNameStyle: material.Editor(th, &f.FileName, "Filename"),
|
||||
CancelStyle: LowEmphasisButton(th, &f.BtnCancel, "Cancel"),
|
||||
UseAltExtStyle: material.Switch(th, &f.UseAltExt),
|
||||
UseAltExtStyle: material.Switch(th, &f.UseAltExt, "Change extension"),
|
||||
}
|
||||
ret.UseAltExtStyle.Color.Enabled = white
|
||||
ret.UseAltExtStyle.Color.Disabled = white
|
||||
@ -174,11 +175,9 @@ func (f *FileDialogStyle) Layout(gtx C) D {
|
||||
var text string
|
||||
if index < len(subDirs) {
|
||||
icon = widgetForIcon(icons.FileFolder)
|
||||
icon.Color = primaryColor
|
||||
text = subDirs[index]
|
||||
} else {
|
||||
icon = widgetForIcon(icons.EditorInsertDriveFile)
|
||||
icon.Color = primaryColor
|
||||
text = files[index-len(subDirs)]
|
||||
}
|
||||
labelColor := highEmphasisTextColor
|
||||
@ -189,17 +188,20 @@ func (f *FileDialogStyle) Layout(gtx C) D {
|
||||
layout.Stacked(func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return icon.Layout(gtx, unit.Dp(24))
|
||||
p := gtx.Dp(unit.Dp(24))
|
||||
gtx.Constraints.Min = image.Pt(p, p)
|
||||
return icon.Layout(gtx, primaryColor)
|
||||
}),
|
||||
layout.Rigid(Label(text, labelColor)),
|
||||
)
|
||||
}),
|
||||
layout.Expanded(func(gtx C) D {
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &f.dialog.tags[index],
|
||||
Types: pointer.Press | pointer.Drag | pointer.Release,
|
||||
}.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
return D{}
|
||||
}),
|
||||
)
|
||||
@ -215,14 +217,14 @@ func (f *FileDialogStyle) Layout(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(f.FolderUpStyle.Layout),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return D{Size: image.Pt(gtx.Px(unit.Dp(6)), gtx.Px(unit.Dp(36)))}
|
||||
return D{Size: image.Pt(gtx.Dp(unit.Dp(6)), gtx.Dp(unit.Dp(36)))}
|
||||
}),
|
||||
layout.Rigid(f.DirEditorStyle.Layout))
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layout.Stack{Alignment: layout.NE}.Layout(gtx,
|
||||
layout.Stacked(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Px(unit.Dp(600)), gtx.Px(unit.Dp(400))))
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(unit.Dp(600)), gtx.Dp(unit.Dp(400))))
|
||||
if listLen > 0 {
|
||||
return f.dialog.FileList.Layout(gtx, listLen, listElement)
|
||||
} else {
|
||||
@ -235,11 +237,11 @@ func (f *FileDialogStyle) Layout(gtx C) D {
|
||||
)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(36))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(36))
|
||||
return layout.W.Layout(gtx, f.FileNameStyle.Layout)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Px(unit.Dp(600)), gtx.Px(unit.Dp(36))))
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(unit.Dp(600)), gtx.Dp(unit.Dp(36))))
|
||||
if f.ExtAlt != "" {
|
||||
mainLabelColor := disabledTextColor
|
||||
altLabelColor := disabledTextColor
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/text"
|
||||
"gioui.org/unit"
|
||||
"gioui.org/widget"
|
||||
@ -96,10 +97,11 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
||||
}
|
||||
}
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &ie.tag,
|
||||
Types: pointer.Press,
|
||||
}.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
|
||||
var icon []byte
|
||||
if t.InstrEnlarged() {
|
||||
@ -118,8 +120,8 @@ func (ie *InstrumentEditor) Layout(gtx C, t *Tracker) D {
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
t.OctaveNumberInput.Value = t.Octave()
|
||||
numStyle := NumericUpDown(t.Theme, t.OctaveNumberInput, 0, 9)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
t.SetOctave(t.OctaveNumberInput.Value)
|
||||
return dims
|
||||
@ -185,8 +187,8 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
|
||||
maxRemain := t.MaxInstrumentVoices()
|
||||
t.InstrumentVoices.Value = t.Instrument().NumVoices
|
||||
numStyle := NumericUpDown(t.Theme, t.InstrumentVoices, 0, maxRemain)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := numStyle.Layout(gtx)
|
||||
t.SetInstrumentVoices(t.InstrumentVoices.Value)
|
||||
return dims
|
||||
@ -267,8 +269,8 @@ func (ie *InstrumentEditor) layoutInstrumentHeader(gtx C, t *Tracker) D {
|
||||
|
||||
func (ie *InstrumentEditor) layoutInstrumentNames(gtx C, t *Tracker) D {
|
||||
element := func(gtx C, i int) D {
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(36))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(30))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(36))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(30))
|
||||
grabhandle := LabelStyle{Text: "", ShadeColor: black, Color: white, FontSize: unit.Sp(10), Alignment: layout.Center}
|
||||
if i == t.InstrIndex() {
|
||||
grabhandle.Text = ":::"
|
||||
@ -303,7 +305,7 @@ func (ie *InstrumentEditor) layoutInstrumentNames(gtx C, t *Tracker) D {
|
||||
editor := material.Editor(t.Theme, ie.nameEditor, "Instr")
|
||||
editor.Color = color
|
||||
editor.HintColor = instrumentNameHintColor
|
||||
editor.TextSize = unit.Dp(12)
|
||||
editor.TextSize = unit.Sp(12)
|
||||
dims := layout.Center.Layout(gtx, editor.Layout)
|
||||
t.SetInstrumentName(ie.nameEditor.Text())
|
||||
return dims
|
||||
@ -332,34 +334,27 @@ func (ie *InstrumentEditor) layoutInstrumentNames(gtx C, t *Tracker) D {
|
||||
instrumentList.HoverColor = instrumentHoverColor
|
||||
|
||||
ie.instrumentDragList.SelectedItem = t.InstrIndex()
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||
spy, spiedGtx := eventx.Enspy(gtx)
|
||||
dims := instrumentList.Layout(spiedGtx)
|
||||
for _, group := range spy.AllEvents() {
|
||||
for _, event := range group.Items {
|
||||
switch e := event.(type) {
|
||||
case key.Event:
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
continue
|
||||
}
|
||||
if !ie.nameEditor.Focused() {
|
||||
switch e.State {
|
||||
case key.Press:
|
||||
switch e.Name {
|
||||
case key.NameDownArrow:
|
||||
ie.unitDragList.Focus()
|
||||
case key.NameReturn, key.NameEnter:
|
||||
ie.nameEditor.Focus()
|
||||
}
|
||||
t.JammingPressed(e)
|
||||
case key.Release:
|
||||
t.JammingReleased(e)
|
||||
}
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
key.InputOp{Tag: ie.instrumentDragList, Keys: "↓"}.Add(gtx.Ops)
|
||||
|
||||
for _, event := range gtx.Events(ie.instrumentDragList) {
|
||||
switch e := event.(type) {
|
||||
case key.Event:
|
||||
switch e.State {
|
||||
case key.Press:
|
||||
switch e.Name {
|
||||
case key.NameDownArrow:
|
||||
ie.unitDragList.Focus()
|
||||
case key.NameReturn, key.NameEnter:
|
||||
ie.nameEditor.Focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dims := instrumentList.Layout(gtx)
|
||||
|
||||
if t.InstrIndex() != ie.instrumentDragList.SelectedItem {
|
||||
t.SetInstrIndex(ie.instrumentDragList.SelectedItem)
|
||||
op.InvalidateOp{}.Add(gtx.Ops)
|
||||
@ -371,7 +366,7 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
||||
t.AddUnit(true)
|
||||
ie.unitDragList.Focus()
|
||||
}
|
||||
addUnitBtnStyle := material.IconButton(t.Theme, ie.addUnitBtn, widgetForIcon(icons.ContentAdd))
|
||||
addUnitBtnStyle := material.IconButton(t.Theme, ie.addUnitBtn, widgetForIcon(icons.ContentAdd), "Add unit")
|
||||
addUnitBtnStyle.Color = t.Theme.ContrastFg
|
||||
addUnitBtnStyle.Background = t.Theme.Fg
|
||||
addUnitBtnStyle.Inset = layout.UniformInset(unit.Dp(4))
|
||||
@ -388,7 +383,7 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
||||
}
|
||||
|
||||
element := func(gtx C, i int) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Px(unit.Dp(120)), gtx.Px(unit.Dp(20))))
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(unit.Dp(120)), gtx.Dp(unit.Dp(20))))
|
||||
u := units[i]
|
||||
var color color.NRGBA = white
|
||||
|
||||
@ -439,21 +434,7 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
||||
editor.HintColor = instrumentNameHintColor
|
||||
editor.TextSize = unit.Sp(12)
|
||||
editor.Font = labelDefaultFont
|
||||
unitName = func(gtx C) D {
|
||||
spy, spiedGtx := eventx.Enspy(gtx)
|
||||
ret := editor.Layout(spiedGtx)
|
||||
for _, group := range spy.AllEvents() {
|
||||
for _, event := range group.Items {
|
||||
switch e := event.(type) {
|
||||
case key.Event:
|
||||
if e.Name == key.NameEscape {
|
||||
ie.unitDragList.Focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
unitName = editor.Layout
|
||||
} else {
|
||||
unitNameLabel := LabelStyle{Text: u.Type, ShadeColor: black, Color: color, Font: labelDefaultFont, FontSize: unit.Sp(12)}
|
||||
if unitNameLabel.Text == "" {
|
||||
@ -472,8 +453,7 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
||||
)
|
||||
}
|
||||
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
unitList := FilledDragList(t.Theme, ie.unitDragList, len(units), element, t.SwapUnits)
|
||||
ie.unitDragList.SelectedItem = t.UnitIndex()
|
||||
return Surface{Gray: 30, Focus: ie.wasFocused}.Layout(gtx, func(gtx C) D {
|
||||
@ -481,53 +461,44 @@ func (ie *InstrumentEditor) layoutInstrumentEditor(gtx C, t *Tracker) D {
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layout.Stack{Alignment: layout.SE}.Layout(gtx,
|
||||
layout.Expanded(func(gtx C) D {
|
||||
spy, spiedGtx := eventx.Enspy(gtx)
|
||||
dims := unitList.Layout(spiedGtx)
|
||||
prevUnitIndex := t.UnitIndex()
|
||||
if t.UnitIndex() != ie.unitDragList.SelectedItem {
|
||||
t.SetUnitIndex(ie.unitDragList.SelectedItem)
|
||||
ie.unitTypeEditor.SetText(t.Unit().Type)
|
||||
}
|
||||
if ie.unitDragList.Focused() {
|
||||
for _, group := range spy.AllEvents() {
|
||||
for _, event := range group.Items {
|
||||
switch e := event.(type) {
|
||||
case key.Event:
|
||||
switch e.State {
|
||||
case key.Press:
|
||||
switch e.Name {
|
||||
case key.NameUpArrow:
|
||||
if prevUnitIndex == 0 {
|
||||
ie.instrumentDragList.Focus()
|
||||
}
|
||||
case key.NameRightArrow:
|
||||
ie.paramEditor.Focus()
|
||||
case key.NameDeleteBackward:
|
||||
t.SetUnitType("")
|
||||
ie.unitTypeEditor.Focus()
|
||||
l := len(ie.unitTypeEditor.Text())
|
||||
ie.unitTypeEditor.SetCaret(l, l)
|
||||
case key.NameDeleteForward:
|
||||
t.DeleteUnit(true)
|
||||
case key.NameReturn:
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.AddUnit(true)
|
||||
}
|
||||
ie.unitTypeEditor.Focus()
|
||||
l := len(ie.unitTypeEditor.Text())
|
||||
ie.unitTypeEditor.SetCaret(l, l)
|
||||
}
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
continue
|
||||
}
|
||||
t.JammingPressed(e)
|
||||
case key.Release:
|
||||
t.JammingReleased(e)
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
key.InputOp{Tag: ie.unitDragList, Keys: "→|⏎|⌫|⌦|⎋|Ctrl-⏎"}.Add(gtx.Ops)
|
||||
for _, event := range gtx.Events(ie.unitDragList) {
|
||||
switch e := event.(type) {
|
||||
case key.Event:
|
||||
switch e.State {
|
||||
case key.Press:
|
||||
switch e.Name {
|
||||
case key.NameEscape:
|
||||
ie.instrumentDragList.Focus()
|
||||
case key.NameRightArrow:
|
||||
ie.paramEditor.Focus()
|
||||
case key.NameDeleteBackward:
|
||||
t.SetUnitType("")
|
||||
ie.unitTypeEditor.Focus()
|
||||
l := len(ie.unitTypeEditor.Text())
|
||||
ie.unitTypeEditor.SetCaret(l, l)
|
||||
case key.NameDeleteForward:
|
||||
t.DeleteUnit(true)
|
||||
case key.NameReturn:
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.AddUnit(true)
|
||||
ie.unitDragList.SelectedItem = t.UnitIndex()
|
||||
ie.unitTypeEditor.SetText("")
|
||||
}
|
||||
ie.unitTypeEditor.Focus()
|
||||
l := len(ie.unitTypeEditor.Text())
|
||||
ie.unitTypeEditor.SetCaret(l, l)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dims := unitList.Layout(gtx)
|
||||
if t.UnitIndex() != ie.unitDragList.SelectedItem {
|
||||
t.SetUnitIndex(ie.unitDragList.SelectedItem)
|
||||
ie.unitTypeEditor.SetText(t.Unit().Type)
|
||||
}
|
||||
return dims
|
||||
}),
|
||||
layout.Expanded(func(gtx C) D {
|
||||
|
@ -3,8 +3,9 @@ package gioui
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gioui.org/app"
|
||||
"gioui.org/io/clipboard"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/op"
|
||||
"github.com/vsariola/sointu/tracker"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@ -45,86 +46,80 @@ var noteMap = map[string]int{
|
||||
}
|
||||
|
||||
// KeyEvent handles incoming key events and returns true if repaint is needed.
|
||||
func (t *Tracker) KeyEvent(e key.Event, window *app.Window) bool {
|
||||
func (t *Tracker) KeyEvent(e key.Event, o *op.Ops) {
|
||||
if e.State == key.Press {
|
||||
if t.OpenSongDialog.Visible ||
|
||||
t.SaveSongDialog.Visible ||
|
||||
t.SaveInstrumentDialog.Visible ||
|
||||
t.OpenInstrumentDialog.Visible ||
|
||||
t.ExportWavDialog.Visible {
|
||||
return false
|
||||
return
|
||||
}
|
||||
switch e.Name {
|
||||
case "C":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
contents, err := yaml.Marshal(t.Song())
|
||||
if err == nil {
|
||||
window.WriteClipboard(string(contents))
|
||||
clipboard.WriteOp{Text: string(contents)}.Add(o)
|
||||
t.Alert.Update("Song copied to clipboard", Notify, time.Second*3)
|
||||
}
|
||||
return true
|
||||
return
|
||||
}
|
||||
case "V":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
window.ReadClipboard()
|
||||
return true
|
||||
clipboard.ReadOp{Tag: t}.Add(o)
|
||||
return
|
||||
}
|
||||
case "Z":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.Undo()
|
||||
return true
|
||||
return
|
||||
}
|
||||
case "Y":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.Redo()
|
||||
return true
|
||||
return
|
||||
}
|
||||
case "N":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.NewSong(false)
|
||||
return true
|
||||
return
|
||||
}
|
||||
case "S":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.SaveSongFile()
|
||||
return false
|
||||
return
|
||||
}
|
||||
case "O":
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
t.OpenSongFile(false)
|
||||
return true
|
||||
return
|
||||
}
|
||||
case "F1":
|
||||
t.OrderEditor.Focus()
|
||||
return true
|
||||
return
|
||||
case "F2":
|
||||
t.TrackEditor.Focus()
|
||||
return true
|
||||
return
|
||||
case "F3":
|
||||
t.InstrumentEditor.Focus()
|
||||
return true
|
||||
return
|
||||
case "F4":
|
||||
t.TrackEditor.Focus()
|
||||
return true
|
||||
return
|
||||
case "F5":
|
||||
t.SetNoteTracking(true)
|
||||
startRow := t.Cursor().SongRow
|
||||
if t.OrderEditor.Focused() {
|
||||
startRow.Row = 0
|
||||
}
|
||||
t.PlayFromPosition(startRow)
|
||||
return true
|
||||
return
|
||||
case "F6":
|
||||
t.SetNoteTracking(false)
|
||||
startRow := t.Cursor().SongRow
|
||||
if t.OrderEditor.Focused() {
|
||||
startRow.Row = 0
|
||||
}
|
||||
t.PlayFromPosition(startRow)
|
||||
return true
|
||||
return
|
||||
case "F8":
|
||||
t.SetPlaying(false)
|
||||
return true
|
||||
return
|
||||
case "Space":
|
||||
if !t.Playing() && !t.InstrEnlarged() {
|
||||
t.SetNoteTracking(!e.Modifiers.Contain(key.ModShortcut))
|
||||
@ -172,9 +167,10 @@ func (t *Tracker) KeyEvent(e key.Event, window *app.Window) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
t.JammingPressed(e)
|
||||
} else { // e.State == key.Release
|
||||
t.JammingReleased(e)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// NumberPressed handles incoming presses while in either of the hex number columns
|
||||
@ -191,7 +187,7 @@ func (t *Tracker) NumberPressed(iv byte) {
|
||||
t.SetNote(val)
|
||||
}
|
||||
|
||||
func (t *Tracker) JammingPressed(e key.Event) {
|
||||
func (t *Tracker) JammingPressed(e key.Event) byte {
|
||||
if val, ok := noteMap[e.Name]; ok {
|
||||
if _, ok := t.KeyPlaying[e.Name]; !ok {
|
||||
n := tracker.NoteAsValue(t.OctaveNumberInput.Value, val)
|
||||
@ -199,16 +195,17 @@ func (t *Tracker) JammingPressed(e key.Event) {
|
||||
noteID := tracker.NoteIDInstr(instr, n)
|
||||
t.NoteOn(noteID)
|
||||
t.KeyPlaying[e.Name] = noteID
|
||||
return n
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (t *Tracker) JammingReleased(e key.Event) {
|
||||
func (t *Tracker) JammingReleased(e key.Event) bool {
|
||||
if noteID, ok := t.KeyPlaying[e.Name]; ok {
|
||||
t.NoteOff(noteID)
|
||||
delete(t.KeyPlaying, e.Name)
|
||||
if t.TrackEditor.focused && t.Playing() && t.Note() == 1 && t.NoteTracking() {
|
||||
t.SetNote(0)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/font"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/paint"
|
||||
@ -18,20 +18,20 @@ type LabelStyle struct {
|
||||
Color color.NRGBA
|
||||
ShadeColor color.NRGBA
|
||||
Alignment layout.Direction
|
||||
Font text.Font
|
||||
FontSize unit.Value
|
||||
Font font.Font
|
||||
FontSize unit.Sp
|
||||
}
|
||||
|
||||
func (l LabelStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Stack{Alignment: l.Alignment}.Layout(gtx,
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
paint.ColorOp{Color: l.ShadeColor}.Add(gtx.Ops)
|
||||
op.Offset(f32.Pt(2, 2)).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(2, 2)).Add(gtx.Ops)
|
||||
dims := widget.Label{
|
||||
Alignment: text.Start,
|
||||
MaxLines: 1,
|
||||
}.Layout(gtx, textShaper, l.Font, l.FontSize, l.Text)
|
||||
}.Layout(gtx, textShaper, l.Font, l.FontSize, l.Text, op.CallOp{})
|
||||
return layout.Dimensions{
|
||||
Size: dims.Size.Add(image.Pt(2, 2)),
|
||||
Baseline: dims.Baseline,
|
||||
@ -42,7 +42,7 @@ func (l LabelStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
return widget.Label{
|
||||
Alignment: text.Start,
|
||||
MaxLines: 1,
|
||||
}.Layout(gtx, textShaper, l.Font, l.FontSize, l.Text)
|
||||
}.Layout(gtx, textShaper, l.Font, l.FontSize, l.Text, op.CallOp{})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ import (
|
||||
"fmt"
|
||||
"image"
|
||||
|
||||
"gioui.org/app"
|
||||
"gioui.org/io/clipboard"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
@ -12,7 +15,21 @@ import (
|
||||
type C = layout.Context
|
||||
type D = layout.Dimensions
|
||||
|
||||
func (t *Tracker) Layout(gtx layout.Context) {
|
||||
func (t *Tracker) Layout(gtx layout.Context, w *app.Window) {
|
||||
// this is the top level input handler for the whole app
|
||||
// it handles all the global key events and clipboard events
|
||||
// we need to tell gio that we handle tabs too; otherwise
|
||||
// it will steal them for focus switching
|
||||
key.InputOp{Tag: t, Keys: "Tab|Shift-Tab"}.Add(gtx.Ops)
|
||||
for _, ev := range gtx.Events(t) {
|
||||
switch e := ev.(type) {
|
||||
case key.Event:
|
||||
t.KeyEvent(e, gtx.Ops)
|
||||
case clipboard.Event:
|
||||
t.UnmarshalContent([]byte(e.Text))
|
||||
}
|
||||
}
|
||||
|
||||
paint.FillShape(gtx.Ops, backgroundColor, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
|
||||
if t.InstrEnlarged() {
|
||||
t.layoutTop(gtx)
|
||||
|
@ -28,8 +28,8 @@ type MenuStyle struct {
|
||||
IconColor color.NRGBA
|
||||
TextColor color.NRGBA
|
||||
ShortCutColor color.NRGBA
|
||||
FontSize unit.Value
|
||||
IconSize unit.Value
|
||||
FontSize unit.Sp
|
||||
IconSize unit.Dp
|
||||
HoverColor color.NRGBA
|
||||
}
|
||||
|
||||
@ -82,16 +82,15 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
|
||||
i2 := i // avoid loop variable getting updated in closure
|
||||
item2 := item
|
||||
flexChildren[i] = layout.Rigid(func(gtx C) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
var macro op.MacroOp
|
||||
if i2 == m.Menu.hover-1 && !item2.Disabled {
|
||||
macro = op.Record(gtx.Ops)
|
||||
}
|
||||
icon := widgetForIcon(item2.IconBytes)
|
||||
if !item2.Disabled {
|
||||
icon.Color = m.IconColor
|
||||
} else {
|
||||
icon.Color = mediumEmphasisTextColor
|
||||
iconColor := m.IconColor
|
||||
if item2.Disabled {
|
||||
iconColor = mediumEmphasisTextColor
|
||||
}
|
||||
iconInset := layout.Inset{Left: unit.Dp(12), Right: unit.Dp(6)}
|
||||
textLabel := LabelStyle{Text: item2.Text, FontSize: m.FontSize, Color: m.TextColor}
|
||||
@ -103,7 +102,9 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
|
||||
dims := layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return iconInset.Layout(gtx, func(gtx C) D {
|
||||
return icon.Layout(gtx, m.IconSize)
|
||||
p := gtx.Dp(unit.Dp(m.IconSize))
|
||||
gtx.Constraints.Min = image.Pt(p, p)
|
||||
return icon.Layout(gtx, iconColor)
|
||||
})
|
||||
}),
|
||||
layout.Rigid(textLabel.Layout),
|
||||
@ -121,10 +122,11 @@ func (m *MenuStyle) Layout(gtx C, items ...MenuItem) D {
|
||||
}
|
||||
if !item2.Disabled {
|
||||
rect := image.Rect(0, 0, dims.Size.X, dims.Size.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &m.Menu.tags[i2],
|
||||
Types: pointer.Press | pointer.Enter | pointer.Leave,
|
||||
}.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
}
|
||||
return dims
|
||||
})
|
||||
@ -144,7 +146,7 @@ func PopupMenu(th *material.Theme, menu *Menu) MenuStyle {
|
||||
IconColor: white,
|
||||
TextColor: white,
|
||||
ShortCutColor: mediumEmphasisTextColor,
|
||||
FontSize: unit.Dp(16),
|
||||
FontSize: unit.Sp(16),
|
||||
IconSize: unit.Dp(16),
|
||||
HoverColor: menuHoverColor,
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/font"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/widget"
|
||||
@ -34,15 +34,15 @@ type NumericUpDownStyle struct {
|
||||
Min int
|
||||
Max int
|
||||
Color color.NRGBA
|
||||
Font text.Font
|
||||
TextSize unit.Value
|
||||
Font font.Font
|
||||
TextSize unit.Sp
|
||||
BorderColor color.NRGBA
|
||||
IconColor color.NRGBA
|
||||
BackgroundColor color.NRGBA
|
||||
CornerRadius unit.Value
|
||||
Border unit.Value
|
||||
ButtonWidth unit.Value
|
||||
UnitsPerStep unit.Value
|
||||
CornerRadius unit.Dp
|
||||
Border unit.Dp
|
||||
ButtonWidth unit.Dp
|
||||
UnitsPerStep unit.Dp
|
||||
shaper text.Shaper
|
||||
}
|
||||
|
||||
@ -63,26 +63,23 @@ func NumericUpDown(th *material.Theme, number *NumberInput, min, max int) Numeri
|
||||
ButtonWidth: unit.Dp(16),
|
||||
Border: unit.Dp(1),
|
||||
UnitsPerStep: unit.Dp(8),
|
||||
TextSize: th.TextSize.Scale(14.0 / 16.0),
|
||||
shaper: th.Shaper,
|
||||
TextSize: th.TextSize * 14 / 16,
|
||||
shaper: *th.Shaper,
|
||||
}
|
||||
}
|
||||
|
||||
func (s NumericUpDownStyle) Layout(gtx C) D {
|
||||
size := gtx.Constraints.Min
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
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)
|
||||
rr := gtx.Dp(s.CornerRadius)
|
||||
border := gtx.Dp(s.Border)
|
||||
c := clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(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)
|
||||
c.Pop()
|
||||
off := op.Offset(image.Pt(border, border)).Push(gtx.Ops)
|
||||
c2 := clip.UniformRRect(image.Rectangle{Max: image.Pt(
|
||||
gtx.Constraints.Min.X-border*2,
|
||||
gtx.Constraints.Min.Y-border*2,
|
||||
)}, rr-border).Push(gtx.Ops)
|
||||
gtx.Constraints.Min.X -= int(border * 2)
|
||||
gtx.Constraints.Min.Y -= int(border * 2)
|
||||
gtx.Constraints.Max = gtx.Constraints.Min
|
||||
@ -97,12 +94,14 @@ func (s NumericUpDownStyle) Layout(gtx C) D {
|
||||
if s.NumberInput.Value > s.Max {
|
||||
s.NumberInput.Value = s.Max
|
||||
}
|
||||
off.Pop()
|
||||
c2.Pop()
|
||||
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)
|
||||
btnWidth := gtx.Dp(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())
|
||||
@ -117,8 +116,12 @@ func (s NumericUpDownStyle) button(height int, icon *widget.Icon, delta int, cli
|
||||
size = 1
|
||||
}
|
||||
if icon != nil {
|
||||
icon.Color = s.IconColor
|
||||
return icon.Layout(gtx, unit.Px(float32(size)))
|
||||
p := gtx.Dp(unit.Dp(size))
|
||||
if p < 1 {
|
||||
p = 1
|
||||
}
|
||||
gtx.Constraints = layout.Exact(image.Pt(p, p))
|
||||
return icon.Layout(gtx, s.IconColor)
|
||||
}
|
||||
return layout.Dimensions{}
|
||||
}),
|
||||
@ -137,7 +140,7 @@ func (s NumericUpDownStyle) layoutText(gtx C) D {
|
||||
}),
|
||||
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))
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, &s.shaper, s.Font, s.TextSize, fmt.Sprintf("%v", s.NumberInput.Value), op.CallOp{})
|
||||
}),
|
||||
layout.Expanded(s.layoutDrag),
|
||||
)
|
||||
@ -145,7 +148,7 @@ func (s NumericUpDownStyle) layoutText(gtx C) D {
|
||||
|
||||
func (s NumericUpDownStyle) layoutDrag(gtx layout.Context) layout.Dimensions {
|
||||
{ // handle dragging
|
||||
pxPerStep := float32(gtx.Px(s.UnitsPerStep))
|
||||
pxPerStep := float32(gtx.Dp(s.UnitsPerStep))
|
||||
for _, ev := range gtx.Events(s.NumberInput) {
|
||||
if e, ok := ev.(pointer.Event); ok {
|
||||
switch e.Type {
|
||||
@ -162,15 +165,16 @@ func (s NumericUpDownStyle) layoutDrag(gtx layout.Context) layout.Dimensions {
|
||||
}
|
||||
|
||||
// Avoid affecting the input tree with pointer events.
|
||||
stack := op.Save(gtx.Ops)
|
||||
stack := op.Offset(image.Point{}).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)
|
||||
area := clip.Rect(dragRect).Push(gtx.Ops)
|
||||
pointer.InputOp{
|
||||
Tag: s.NumberInput,
|
||||
Types: pointer.Press | pointer.Drag | pointer.Release,
|
||||
}.Add(gtx.Ops)
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
stack.Pop()
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
@ -184,11 +188,13 @@ func (s NumericUpDownStyle) layoutClick(gtx layout.Context, delta int, click *ge
|
||||
}
|
||||
}
|
||||
// Avoid affecting the input tree with pointer events.
|
||||
stack := op.Save(gtx.Ops)
|
||||
stack := op.Offset(image.Point{}).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)
|
||||
area := clip.Rect(clickRect).Push(gtx.Ops)
|
||||
click.Add(gtx.Ops)
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
stack.Pop()
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
@ -64,7 +63,7 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
key.FocusOp{Tag: &oe.tag}.Add(gtx.Ops)
|
||||
}
|
||||
case key.Event:
|
||||
if !oe.focused || e.State != key.Press {
|
||||
if e.State != key.Press {
|
||||
continue
|
||||
}
|
||||
switch e.Name {
|
||||
@ -129,6 +128,14 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
case "-":
|
||||
t.AdjustPatternNumber(-1, e.Modifiers.Contain(key.ModShortcut))
|
||||
continue
|
||||
case key.NameHome:
|
||||
cursor := t.Cursor()
|
||||
cursor.Track = 0
|
||||
t.SetCursor(cursor)
|
||||
case key.NameEnd:
|
||||
cursor := t.Cursor()
|
||||
cursor.Track = len(t.Song().Score.Tracks) - 1
|
||||
t.SetCursor(cursor)
|
||||
}
|
||||
if (e.Name != key.NameLeftArrow &&
|
||||
e.Name != key.NameRightArrow &&
|
||||
@ -156,18 +163,18 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
}
|
||||
}
|
||||
}
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
if oe.requestFocus {
|
||||
oe.requestFocus = false
|
||||
key.FocusOp{Tag: &oe.tag}.Add(gtx.Ops)
|
||||
}
|
||||
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
defer clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Push(gtx.Ops).Pop()
|
||||
pointer.InputOp{Tag: &oe.tag,
|
||||
Types: pointer.Press,
|
||||
}.Add(gtx.Ops)
|
||||
key.InputOp{Tag: &oe.tag}.Add(gtx.Ops)
|
||||
|
||||
key.InputOp{Tag: &oe.tag, Keys: "←|→|↑|↓|Shift-←|Shift-→|Shift-↑|Shift-↓|⏎|⇱|⇲|⌫|⌦|Ctrl-⌫|Ctrl-⌦|+|-|Space|0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z"}.Add(gtx.Ops)
|
||||
|
||||
patternRect := tracker.SongRect{
|
||||
Corner1: tracker.SongPoint{SongRow: tracker.SongRow{Pattern: t.Cursor().Pattern}, Track: t.Cursor().Track},
|
||||
Corner2: tracker.SongPoint{SongRow: tracker.SongRow{Pattern: t.SelectionCorner().Pattern}, Track: t.SelectionCorner().Track},
|
||||
@ -176,8 +183,7 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
// draw the single letter titles for tracks
|
||||
{
|
||||
gtx := gtx
|
||||
stack := op.Save(gtx.Ops)
|
||||
op.Offset(f32.Pt(patternRowMarkerWidth, 0)).Add(gtx.Ops)
|
||||
stack := op.Offset(image.Pt(patternRowMarkerWidth, 0)).Push(gtx.Ops)
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X-patternRowMarkerWidth, patternCellHeight))
|
||||
elem := func(gtx C, i int) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(patternCellWidth, patternCellHeight))
|
||||
@ -188,16 +194,16 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
} else {
|
||||
title = "?"
|
||||
}
|
||||
LabelStyle{Alignment: layout.N, Text: title, FontSize: unit.Dp(12), Color: mediumEmphasisTextColor}.Layout(gtx)
|
||||
LabelStyle{Alignment: layout.N, Text: title, FontSize: unit.Sp(12), Color: mediumEmphasisTextColor}.Layout(gtx)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
}
|
||||
style := FilledDragList(t.Theme, oe.titleList, len(t.Song().Score.Tracks), elem, t.SwapTracks)
|
||||
style.HoverColor = transparent
|
||||
style.SelectedColor = transparent
|
||||
style.Layout(gtx)
|
||||
stack.Load()
|
||||
stack.Pop()
|
||||
}
|
||||
op.Offset(f32.Pt(0, patternCellHeight)).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(0, patternCellHeight)).Add(gtx.Ops)
|
||||
gtx.Constraints.Max.Y -= patternCellHeight
|
||||
gtx.Constraints.Min.Y -= patternCellHeight
|
||||
element := func(gtx C, j int) D {
|
||||
@ -205,18 +211,17 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
paint.FillShape(gtx.Ops, patternPlayColor, clip.Rect{Max: image.Pt(gtx.Constraints.Max.X, patternCellHeight)}.Op())
|
||||
}
|
||||
paint.ColorOp{Color: rowMarkerPatternTextColor}.Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)))
|
||||
stack := op.Save(gtx.Ops)
|
||||
op.Offset(f32.Pt(patternRowMarkerWidth, 0)).Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)), op.CallOp{})
|
||||
stack := op.Offset(image.Pt(patternRowMarkerWidth, 0)).Push(gtx.Ops)
|
||||
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 >= 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)
|
||||
widget.Label{Alignment: text.Middle}.Layout(gtx, textShaper, trackerFont, trackerFontSize, patternIndexToString(track.Order[j]))
|
||||
op.Offset(f32.Pt(0, 2)).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(0, -2)).Add(gtx.Ops)
|
||||
widget.Label{Alignment: text.Middle}.Layout(gtx, textShaper, trackerFont, trackerFontSize, patternIndexToString(track.Order[j]), op.CallOp{})
|
||||
op.Offset(image.Pt(0, 2)).Add(gtx.Ops)
|
||||
}
|
||||
point := tracker.SongPoint{Track: i, SongRow: tracker.SongRow{Pattern: j}}
|
||||
if oe.focused || t.TrackEditor.Focused() {
|
||||
@ -231,9 +236,9 @@ func (oe *OrderEditor) doLayout(gtx C, t *Tracker) D {
|
||||
paint.FillShape(gtx.Ops, color, clip.Rect{Max: image.Pt(patternCellWidth, patternCellHeight)}.Op())
|
||||
}
|
||||
}
|
||||
op.Offset(f32.Pt(patternCellWidth, 0)).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(patternCellWidth, 0)).Add(gtx.Ops)
|
||||
}
|
||||
stack.Load()
|
||||
stack.Pop()
|
||||
return D{Size: image.Pt(gtx.Constraints.Max.X, patternCellHeight)}
|
||||
}
|
||||
|
||||
|
@ -94,12 +94,6 @@ func (pe *ParamEditor) Bind(t *Tracker) layout.Widget {
|
||||
case key.NameEscape:
|
||||
t.InstrumentEditor.unitDragList.Focus()
|
||||
}
|
||||
if e.Modifiers.Contain(key.ModShortcut) {
|
||||
continue
|
||||
}
|
||||
t.JammingPressed(e)
|
||||
case key.Release:
|
||||
t.JammingReleased(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,12 +112,13 @@ func (pe *ParamEditor) Bind(t *Tracker) layout.Widget {
|
||||
}),
|
||||
layout.Rigid(pe.layoutUnitFooter(t)))
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)
|
||||
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
pointer.InputOp{Tag: &pe.tag,
|
||||
Types: pointer.Press,
|
||||
}.Add(gtx.Ops)
|
||||
key.InputOp{Tag: &pe.tag}.Add(gtx.Ops)
|
||||
key.InputOp{Tag: &pe.tag, Keys: "←|Shift-←|→|Shift-→|↑|↓|⎋"}.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
return ret
|
||||
})
|
||||
}
|
||||
@ -138,12 +133,12 @@ func (pe *ParamEditor) layoutUnitSliders(gtx C, t *Tracker) D {
|
||||
|
||||
listItem := func(gtx C, index int) D {
|
||||
for pe.Parameters[index].Clicked() {
|
||||
if !pe.focused || t.ParamIndex() != index {
|
||||
pe.Focus()
|
||||
if t.ParamIndex() != index {
|
||||
t.SetParamIndex(index)
|
||||
} else {
|
||||
t.ResetParam()
|
||||
}
|
||||
pe.Focus()
|
||||
}
|
||||
param, err := t.Param(index)
|
||||
if err != nil {
|
||||
@ -199,7 +194,7 @@ func (pe *ParamEditor) layoutUnitFooter(t *Tracker) layout.Widget {
|
||||
clearUnitBtnStyle := IconButton(t.Theme, pe.ClearUnitBtn, icons.ContentClear, true)
|
||||
dims = clearUnitBtnStyle.Layout(gtx)
|
||||
}
|
||||
return D{Size: image.Pt(gtx.Px(unit.Dp(48)), dims.Size.Y)}
|
||||
return D{Size: image.Pt(gtx.Dp(unit.Dp(48)), dims.Size.Y)}
|
||||
}),
|
||||
layout.Flexed(1, hintText),
|
||||
)
|
||||
@ -230,9 +225,10 @@ func (pe *ParamEditor) layoutUnitTypeChooser(gtx C, t *Tracker) D {
|
||||
return layout.Stack{Alignment: layout.W}.Layout(gtx,
|
||||
layout.Stacked(bg),
|
||||
layout.Expanded(func(gtx C) D {
|
||||
return leftMargin.Layout(gtx, labelStyle.Layout)
|
||||
}),
|
||||
layout.Expanded(pe.ChooseUnitTypeBtns[i].Layout))
|
||||
return pe.ChooseUnitTypeBtns[i].Layout(gtx, func(gtx C) D {
|
||||
return leftMargin.Layout(gtx, labelStyle.Layout)
|
||||
})
|
||||
}))
|
||||
}
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Stacked(func(gtx C) D {
|
||||
|
@ -47,19 +47,16 @@ func (p *ParameterWidget) Clicked() bool {
|
||||
func (p ParameterStyle) Layout(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Stacked(func(gtx C) D {
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(110))
|
||||
return layout.E.Layout(gtx, Label(p.Parameter.Name, white))
|
||||
}),
|
||||
layout.Expanded(p.ParameterWidget.labelBtn.Layout),
|
||||
)
|
||||
return p.ParameterWidget.labelBtn.Layout(gtx, func(gtx C) D {
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(110))
|
||||
return layout.E.Layout(gtx, Label(p.Parameter.Name, white))
|
||||
})
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
switch p.Parameter.Type {
|
||||
case tracker.IntegerParameter:
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(200))
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(40))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(200))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(40))
|
||||
if p.Focus {
|
||||
paint.FillShape(gtx.Ops, cursorColor, clip.Rect{
|
||||
Max: gtx.Constraints.Min,
|
||||
@ -74,15 +71,15 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
p.Parameter.Value = int(p.ParameterWidget.floatWidget.Value + 0.5)
|
||||
return dims
|
||||
case tracker.BoolParameter:
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(60))
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(40))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(60))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(40))
|
||||
if p.Focus {
|
||||
paint.FillShape(gtx.Ops, cursorColor, clip.Rect{
|
||||
Max: gtx.Constraints.Min,
|
||||
}.Op())
|
||||
}
|
||||
p.ParameterWidget.boolWidget.Value = p.Parameter.Value > p.Parameter.Min
|
||||
boolStyle := material.Switch(p.Theme, &p.ParameterWidget.boolWidget)
|
||||
boolStyle := material.Switch(p.Theme, &p.ParameterWidget.boolWidget, "Toggle boolean parameter")
|
||||
boolStyle.Color.Disabled = p.Theme.Fg
|
||||
boolStyle.Color.Enabled = white
|
||||
dims := layout.Center.Layout(gtx, boolStyle.Layout)
|
||||
@ -93,8 +90,8 @@ func (p ParameterStyle) Layout(gtx C) D {
|
||||
}
|
||||
return dims
|
||||
case tracker.IDParameter:
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(200))
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(40))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(200))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(40))
|
||||
if p.Focus {
|
||||
paint.FillShape(gtx.Ops, cursorColor, clip.Rect{
|
||||
Max: gtx.Constraints.Min,
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
@ -17,11 +16,11 @@ type PopupStyle struct {
|
||||
Visible *bool
|
||||
SurfaceColor color.NRGBA
|
||||
ShadowColor color.NRGBA
|
||||
ShadowN unit.Value
|
||||
ShadowE unit.Value
|
||||
ShadowW unit.Value
|
||||
ShadowS unit.Value
|
||||
SE, SW, NW, NE unit.Value
|
||||
ShadowN unit.Dp
|
||||
ShadowE unit.Dp
|
||||
ShadowW unit.Dp
|
||||
ShadowS unit.Dp
|
||||
SE, SW, NW, NE unit.Dp
|
||||
}
|
||||
|
||||
func Popup(visible *bool) PopupStyle {
|
||||
@ -58,33 +57,30 @@ func (s PopupStyle) Layout(gtx C, contents layout.Widget) D {
|
||||
}
|
||||
|
||||
bg := func(gtx C) D {
|
||||
pointer.PassOp{Pass: false}.Add(gtx.Ops)
|
||||
rrect := clip.RRect{
|
||||
Rect: f32.Rectangle{Max: f32.Pt(float32(gtx.Constraints.Min.X), float32(gtx.Constraints.Min.Y))},
|
||||
SE: float32(gtx.Px(s.SE)),
|
||||
SW: float32(gtx.Px(s.SW)),
|
||||
NW: float32(gtx.Px(s.NW)),
|
||||
NE: float32(gtx.Px(s.NE)),
|
||||
Rect: image.Rectangle{Max: gtx.Constraints.Min},
|
||||
SE: gtx.Dp(s.SE),
|
||||
SW: gtx.Dp(s.SW),
|
||||
NW: gtx.Dp(s.NW),
|
||||
NE: gtx.Dp(s.NE),
|
||||
}
|
||||
rrect2 := rrect
|
||||
rrect2.Rect.Min = rrect2.Rect.Min.Sub(f32.Pt(float32(gtx.Px(s.ShadowW)), float32(gtx.Px(s.ShadowN))))
|
||||
rrect2.Rect.Max = rrect2.Rect.Max.Add(f32.Pt(float32(gtx.Px(s.ShadowE)), float32(gtx.Px(s.ShadowS))))
|
||||
rrect2.Rect.Min = rrect2.Rect.Min.Sub(image.Pt(gtx.Dp(s.ShadowW), gtx.Dp(s.ShadowN)))
|
||||
rrect2.Rect.Max = rrect2.Rect.Max.Add(image.Pt(gtx.Dp(s.ShadowE), gtx.Dp(s.ShadowS)))
|
||||
paint.FillShape(gtx.Ops, s.ShadowColor, rrect2.Op(gtx.Ops))
|
||||
paint.FillShape(gtx.Ops, s.SurfaceColor, rrect.Op(gtx.Ops))
|
||||
rect := image.Rect(int(rrect2.Rect.Min.X), int(rrect2.Rect.Min.Y), int(rrect2.Rect.Max.X), int(rrect2.Rect.Max.Y))
|
||||
state := op.Save(gtx.Ops)
|
||||
area := clip.Rect(image.Rect(-1e6, -1e6, 1e6, 1e6)).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: s.Visible,
|
||||
Types: pointer.Press,
|
||||
Grab: true,
|
||||
}.Add(gtx.Ops)
|
||||
state.Load()
|
||||
state = op.Save(gtx.Ops)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
pointer.InputOp{Tag: dummyTag,
|
||||
area.Pop()
|
||||
area = clip.Rect(rrect2.Rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &dummyTag,
|
||||
Types: pointer.Press,
|
||||
Grab: true,
|
||||
}.Add(gtx.Ops)
|
||||
state.Load()
|
||||
area.Pop()
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
}
|
||||
macro := op.Record(gtx.Ops)
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"image"
|
||||
"strings"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
@ -20,13 +19,13 @@ func (t *Tracker) layoutRowMarkers(gtx C) D {
|
||||
paint.FillShape(gtx.Ops, rowMarkerSurfaceColor, clip.Rect{
|
||||
Max: gtx.Constraints.Max,
|
||||
}.Op())
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
||||
op.Offset(f32.Pt(0, float32(gtx.Constraints.Max.Y-trackRowHeight)/2)).Add(gtx.Ops)
|
||||
//defer op.Save(gtx.Ops).Load()
|
||||
defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
|
||||
op.Offset(image.Pt(0, (gtx.Constraints.Max.Y-trackRowHeight)/2)).Add(gtx.Ops)
|
||||
cursorSongRow := t.Cursor().Pattern*t.Song().Score.RowsPerPattern + t.Cursor().Row
|
||||
playPos := t.PlayPosition()
|
||||
playSongRow := playPos.Pattern*t.Song().Score.RowsPerPattern + playPos.Row
|
||||
op.Offset(f32.Pt(0, (-1*trackRowHeight)*float32(cursorSongRow))).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(0, (-1*trackRowHeight)*(cursorSongRow))).Add(gtx.Ops)
|
||||
beatMarkerDensity := t.Song().RowsPerBeat
|
||||
for beatMarkerDensity <= 2 {
|
||||
beatMarkerDensity *= 2
|
||||
@ -44,16 +43,16 @@ func (t *Tracker) layoutRowMarkers(gtx C) D {
|
||||
}
|
||||
if j == 0 {
|
||||
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)), op.CallOp{})
|
||||
}
|
||||
if t.TrackEditor.Focused() && songRow == cursorSongRow {
|
||||
paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops)
|
||||
} else {
|
||||
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)))
|
||||
op.Offset(f32.Pt(-rowMarkerWidth/2, trackRowHeight)).Add(gtx.Ops)
|
||||
op.Offset(image.Pt(rowMarkerWidth/2, 0)).Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(fmt.Sprintf("%02x", j)), op.CallOp{})
|
||||
op.Offset(image.Pt(-rowMarkerWidth/2, trackRowHeight)).Add(gtx.Ops)
|
||||
}
|
||||
}
|
||||
return layout.Dimensions{Size: image.Pt(rowMarkerWidth, gtx.Constraints.Max.Y)}
|
||||
|
@ -20,10 +20,10 @@ type ScrollBar struct {
|
||||
tag bool
|
||||
}
|
||||
|
||||
func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Position) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
clip.Rect{Max: gtx.Constraints.Min}.Add(gtx.Ops)
|
||||
gradientSize := gtx.Px(unit.Dp(4))
|
||||
func (s *ScrollBar) Layout(gtx C, width unit.Dp, numItems int, pos *layout.Position) D {
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
||||
gradientSize := gtx.Dp(unit.Dp(4))
|
||||
var totalPixelsEstimate, scrollBarRelLength float32
|
||||
switch s.Axis {
|
||||
case layout.Vertical:
|
||||
@ -52,9 +52,10 @@ func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Po
|
||||
}
|
||||
|
||||
scrollBarRelStart := (float32(pos.First)*totalPixelsEstimate/float32(numItems) + float32(pos.Offset)) / totalPixelsEstimate
|
||||
scrWidth := gtx.Px(width)
|
||||
scrWidth := gtx.Dp(width)
|
||||
|
||||
stack := op.Save(gtx.Ops)
|
||||
stack := op.Offset(image.Point{}).Push(gtx.Ops)
|
||||
var area clip.Stack
|
||||
switch s.Axis {
|
||||
case layout.Vertical:
|
||||
if scrollBarRelLength < 1 && (s.dragging || s.hovering) {
|
||||
@ -63,7 +64,7 @@ func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Po
|
||||
paint.FillShape(gtx.Ops, scrollBarColor, clip.Rect{Min: image.Pt(gtx.Constraints.Min.X-scrWidth, y1), Max: image.Pt(gtx.Constraints.Min.X, y2)}.Op())
|
||||
}
|
||||
rect := image.Rect(gtx.Constraints.Min.X-scrWidth, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area = clip.Rect(rect).Push(gtx.Ops)
|
||||
case layout.Horizontal:
|
||||
if scrollBarRelLength < 1 && (s.dragging || s.hovering) {
|
||||
x1 := int(scrollBarRelStart * float32(gtx.Constraints.Min.X))
|
||||
@ -71,12 +72,14 @@ func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Po
|
||||
paint.FillShape(gtx.Ops, scrollBarColor, clip.Rect{Min: image.Pt(x1, gtx.Constraints.Min.Y-scrWidth), Max: image.Pt(x2, gtx.Constraints.Min.Y)}.Op())
|
||||
}
|
||||
rect := image.Rect(0, gtx.Constraints.Min.Y-scrWidth, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area = clip.Rect(rect).Push(gtx.Ops)
|
||||
}
|
||||
pointer.InputOp{Tag: &s.dragStart,
|
||||
Types: pointer.Drag | pointer.Press | pointer.Cancel | pointer.Release,
|
||||
Grab: s.dragging,
|
||||
}.Add(gtx.Ops)
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
stack.Pop()
|
||||
|
||||
for _, ev := range gtx.Events(&s.dragStart) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
@ -105,12 +108,13 @@ func (s *ScrollBar) Layout(gtx C, width unit.Value, numItems int, pos *layout.Po
|
||||
}
|
||||
}
|
||||
|
||||
pointer.PassOp{Pass: true}.Add(gtx.Ops)
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area2 := clip.Rect(rect).Push(gtx.Ops)
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
pointer.InputOp{Tag: &s.tag,
|
||||
Types: pointer.Enter | pointer.Leave,
|
||||
}.Add(gtx.Ops)
|
||||
area2.Pop()
|
||||
|
||||
for _, ev := range gtx.Events(&s.tag) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/clipboard"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
@ -41,29 +40,29 @@ func (t *Tracker) layoutSongPanel(gtx C) D {
|
||||
)
|
||||
}
|
||||
|
||||
func (t *Tracker) layoutMenu(title string, clickable *widget.Clickable, menu *Menu, width unit.Value, items ...MenuItem) layout.Widget {
|
||||
func (t *Tracker) layoutMenu(title string, clickable *widget.Clickable, menu *Menu, width unit.Dp, items ...MenuItem) layout.Widget {
|
||||
for clickable.Clicked() {
|
||||
menu.Visible = true
|
||||
}
|
||||
m := PopupMenu(t.Theme, menu)
|
||||
return func(gtx C) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
titleBtn := material.Button(t.Theme, clickable, title)
|
||||
titleBtn.Color = white
|
||||
titleBtn.Background = transparent
|
||||
titleBtn.CornerRadius = unit.Dp(0)
|
||||
dims := titleBtn.Layout(gtx)
|
||||
op.Offset(f32.Pt(0, float32(dims.Size.Y))).Add(gtx.Ops)
|
||||
gtx.Constraints.Max.X = gtx.Px(width)
|
||||
gtx.Constraints.Max.Y = gtx.Px(unit.Dp(1000))
|
||||
op.Offset(image.Pt(0, dims.Size.Y)).Add(gtx.Ops)
|
||||
gtx.Constraints.Max.X = gtx.Dp(width)
|
||||
gtx.Constraints.Max.Y = gtx.Dp(unit.Dp(1000))
|
||||
m.Layout(gtx, items...)
|
||||
return dims
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracker) layoutMenuBar(gtx C) D {
|
||||
gtx.Constraints.Max.Y = gtx.Px(unit.Dp(36))
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(36))
|
||||
gtx.Constraints.Max.Y = gtx.Dp(unit.Dp(36))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(36))
|
||||
|
||||
for clickedItem, hasClicked := t.Menus[0].Clicked(); hasClicked; {
|
||||
switch clickedItem {
|
||||
@ -95,7 +94,7 @@ func (t *Tracker) layoutMenuBar(gtx C) D {
|
||||
t.Alert.Update("Song copied to clipboard", Notify, time.Second*3)
|
||||
}
|
||||
case 3:
|
||||
clipboard.ReadOp{Tag: &t.Menus[1]}.Add(gtx.Ops)
|
||||
clipboard.ReadOp{Tag: t}.Add(gtx.Ops)
|
||||
case 4:
|
||||
t.RemoveUnusedData()
|
||||
}
|
||||
@ -150,8 +149,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
t.SongLength.Value = t.Song().Score.Length
|
||||
numStyle := NumericUpDown(t.Theme, t.SongLength, 1, math.MaxInt32)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
t.SetSongLength(t.SongLength.Value)
|
||||
return dims
|
||||
@ -164,8 +163,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
t.BPM.Value = t.Song().BPM
|
||||
numStyle := NumericUpDown(t.Theme, t.BPM, 1, 999)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
t.SetBPM(t.BPM.Value)
|
||||
return dims
|
||||
@ -178,8 +177,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
t.RowsPerPattern.Value = t.Song().Score.RowsPerPattern
|
||||
numStyle := NumericUpDown(t.Theme, t.RowsPerPattern, 1, 255)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
t.SetRowsPerPattern(t.RowsPerPattern.Value)
|
||||
return dims
|
||||
@ -192,8 +191,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
t.RowsPerBeat.Value = t.Song().RowsPerBeat
|
||||
numStyle := NumericUpDown(t.Theme, t.RowsPerBeat, 1, 32)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
t.SetRowsPerBeat(t.RowsPerBeat.Value)
|
||||
return dims
|
||||
@ -206,8 +205,8 @@ func (t *Tracker) layoutSongOptions(gtx C) D {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
numStyle := NumericUpDown(t.Theme, t.Step, 0, 8)
|
||||
numStyle.UnitsPerStep = unit.Dp(20)
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
dims := in.Layout(gtx, numStyle.Layout)
|
||||
return dims
|
||||
}),
|
||||
|
@ -3,10 +3,10 @@ package gioui
|
||||
import (
|
||||
"image"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/unit"
|
||||
)
|
||||
|
||||
@ -15,7 +15,7 @@ type Split struct {
|
||||
// 0 is center, -1 completely to the left, 1 completely to the right.
|
||||
Ratio float32
|
||||
// Bar is the width for resizing the layout
|
||||
Bar unit.Value
|
||||
Bar unit.Dp
|
||||
// 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
|
||||
@ -28,9 +28,9 @@ type Split struct {
|
||||
var defaultBarWidth = unit.Dp(10)
|
||||
|
||||
func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.Dimensions {
|
||||
bar := gtx.Px(s.Bar)
|
||||
bar := gtx.Dp(s.Bar)
|
||||
if bar <= 1 {
|
||||
bar = gtx.Px(defaultBarWidth)
|
||||
bar = gtx.Dp(defaultBarWidth)
|
||||
}
|
||||
|
||||
var coord int
|
||||
@ -48,7 +48,6 @@ func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.D
|
||||
|
||||
{ // handle input
|
||||
// Avoid affecting the input tree with pointer events.
|
||||
stack := op.Save(gtx.Ops)
|
||||
|
||||
for _, ev := range gtx.Events(s) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
@ -123,43 +122,43 @@ func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.D
|
||||
} else {
|
||||
barRect = image.Rect(0, firstSize, gtx.Constraints.Max.X, secondOffset)
|
||||
}
|
||||
pointer.Rect(barRect).Add(gtx.Ops)
|
||||
area := clip.Rect(barRect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: s,
|
||||
Types: pointer.Press | pointer.Drag | pointer.Release,
|
||||
Grab: s.drag,
|
||||
}.Add(gtx.Ops)
|
||||
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
}
|
||||
|
||||
{
|
||||
gtx := gtx
|
||||
stack := op.Save(gtx.Ops)
|
||||
|
||||
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))
|
||||
}
|
||||
area := clip.Rect(image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)).Push(gtx.Ops)
|
||||
first(gtx)
|
||||
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
}
|
||||
|
||||
{
|
||||
gtx := gtx
|
||||
stack := op.Save(gtx.Ops)
|
||||
|
||||
var transform op.TransformStack
|
||||
if s.Axis == layout.Horizontal {
|
||||
op.Offset(f32.Pt(float32(secondOffset), 0)).Add(gtx.Ops)
|
||||
transform = op.Offset(image.Pt(secondOffset, 0)).Push(gtx.Ops)
|
||||
gtx.Constraints = layout.Exact(image.Pt(secondSize, gtx.Constraints.Max.Y))
|
||||
} else {
|
||||
op.Offset(f32.Pt(0, float32(secondOffset))).Add(gtx.Ops)
|
||||
transform = op.Offset(image.Pt(0, secondOffset)).Push(gtx.Ops)
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Constraints.Max.X, secondSize))
|
||||
}
|
||||
|
||||
area := clip.Rect(image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)).Push(gtx.Ops)
|
||||
second(gtx)
|
||||
|
||||
stack.Load()
|
||||
area.Pop()
|
||||
transform.Pop()
|
||||
}
|
||||
|
||||
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
var fontCollection []text.FontFace = gofont.Collection()
|
||||
var textShaper = text.NewCache(fontCollection)
|
||||
var textShaper = text.NewShaper(fontCollection)
|
||||
|
||||
var white = color.NRGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
var black = color.NRGBA{R: 0, G: 0, B: 0, A: 255}
|
||||
@ -34,7 +34,7 @@ var rowMarkerPatternTextColor = secondaryColor
|
||||
var rowMarkerRowTextColor = mediumEmphasisTextColor
|
||||
|
||||
var trackerFont = fontCollection[6].Font
|
||||
var trackerFontSize = unit.Px(16)
|
||||
var trackerFontSize = unit.Sp(16)
|
||||
var trackerInactiveTextColor = highEmphasisTextColor
|
||||
var trackerActiveTextColor = color.NRGBA{R: 255, G: 255, B: 130, A: 255}
|
||||
var trackerPlayColor = color.NRGBA{R: 55, G: 55, B: 61, A: 255}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
@ -58,17 +57,23 @@ func (te *TrackEditor) Focus() {
|
||||
}
|
||||
|
||||
func (te *TrackEditor) Focused() bool {
|
||||
return te.focused
|
||||
return te.focused || te.ChildFocused()
|
||||
}
|
||||
|
||||
func (te *TrackEditor) ChildFocused() bool {
|
||||
return te.AddOctaveBtn.Focused() || te.AddSemitoneBtn.Focused() || te.DeleteTrackBtn.Focused() || te.NewTrackBtn.Focused() || te.NoteOffBtn.Focused() || te.SubtractOctaveBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused() || te.SubtractSemitoneBtn.Focused()
|
||||
}
|
||||
|
||||
var trackerEditorKeys key.Set = "+|-|←|→|↑|↓|Ctrl-←|Ctrl-→|Ctrl-↑|Ctrl-↓|Shift-←|Shift-→|Shift-↑|Shift-↓|⏎|⇱|⇲|⌫|⌦|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|,|."
|
||||
|
||||
func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions {
|
||||
for _, e := range gtx.Events(&te.tag) {
|
||||
for _, e := range gtx.Events(te) {
|
||||
switch e := e.(type) {
|
||||
case key.FocusEvent:
|
||||
te.focused = e.Focus
|
||||
case pointer.Event:
|
||||
if e.Type == pointer.Press {
|
||||
key.FocusOp{Tag: &te.tag}.Add(gtx.Ops)
|
||||
key.FocusOp{Tag: te}.Add(gtx.Ops)
|
||||
}
|
||||
case key.Event:
|
||||
switch e.State {
|
||||
@ -170,17 +175,18 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
|
||||
t.SetCursor(t.Cursor().AddRows(t.Step.Value))
|
||||
t.SetSelectionCorner(t.Cursor())
|
||||
}
|
||||
|
||||
t.JammingPressed(e)
|
||||
case key.Release:
|
||||
t.JammingReleased(e)
|
||||
if noteID, ok := t.KeyPlaying[e.Name]; ok {
|
||||
t.NoteOff(noteID)
|
||||
delete(t.KeyPlaying, e.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if te.requestFocus {
|
||||
if te.requestFocus || te.ChildFocused() {
|
||||
te.requestFocus = false
|
||||
key.FocusOp{Tag: &te.tag}.Add(gtx.Ops)
|
||||
key.FocusOp{Tag: te}.Add(gtx.Ops)
|
||||
}
|
||||
|
||||
rowMarkers := layout.Rigid(t.layoutRowMarkers)
|
||||
@ -235,14 +241,14 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
|
||||
in := layout.UniformInset(unit.Dp(1))
|
||||
voiceUpDown := func(gtx C) D {
|
||||
numStyle := NumericUpDown(t.Theme, te.TrackVoices, 1, t.MaxTrackVoices())
|
||||
gtx.Constraints.Min.Y = gtx.Px(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Px(unit.Dp(70))
|
||||
gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
|
||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(70))
|
||||
return in.Layout(gtx, numStyle.Layout)
|
||||
}
|
||||
t.TrackHexCheckBox.Value = t.Song().Score.Tracks[t.Cursor().Track].Effect
|
||||
hexCheckBoxStyle := material.CheckBox(t.Theme, t.TrackHexCheckBox, "Hex")
|
||||
dims := layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D { return layout.Dimensions{Size: image.Pt(gtx.Px(unit.Dp(12)), 0)} }),
|
||||
layout.Rigid(func(gtx C) D { return layout.Dimensions{Size: image.Pt(gtx.Dp(unit.Dp(12)), 0)} }),
|
||||
layout.Rigid(addSemitoneBtnStyle.Layout),
|
||||
layout.Rigid(subtractSemitoneBtnStyle.Layout),
|
||||
layout.Rigid(addOctaveBtnStyle.Layout),
|
||||
@ -260,16 +266,16 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
|
||||
}
|
||||
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
pointer.InputOp{Tag: &te.tag,
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: te,
|
||||
Types: pointer.Press,
|
||||
}.Add(gtx.Ops)
|
||||
key.InputOp{Tag: &te.tag}.Add(gtx.Ops)
|
||||
key.InputOp{Tag: te, Keys: trackerEditorKeys}.Add(gtx.Ops)
|
||||
|
||||
return Surface{Gray: 24, Focus: te.focused}.Layout(gtx, func(gtx C) D {
|
||||
dims := Surface{Gray: 24, Focus: te.Focused()}.Layout(gtx, func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
return Surface{Gray: 37, Focus: te.focused, FitSize: true}.Layout(gtx, menu)
|
||||
return Surface{Gray: 37, Focus: te.Focused(), FitSize: true}.Layout(gtx, menu)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||
@ -280,11 +286,14 @@ func (te *TrackEditor) Layout(gtx layout.Context, t *Tracker) layout.Dimensions
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
area.Pop()
|
||||
return dims
|
||||
}
|
||||
|
||||
func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
clip.Rect{Max: gtx.Constraints.Max}.Add(gtx.Ops)
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
|
||||
cursorSongRow := t.Cursor().Pattern*t.Song().Score.RowsPerPattern + t.Cursor().Row
|
||||
for _, ev := range gtx.Events(&te.trackJumpPointerTag) {
|
||||
e, ok := ev.(pointer.Event)
|
||||
@ -302,11 +311,12 @@ func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
}
|
||||
}
|
||||
rect := image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)
|
||||
pointer.Rect(rect).Add(gtx.Ops)
|
||||
area := clip.Rect(rect).Push(gtx.Ops)
|
||||
pointer.InputOp{Tag: &te.trackJumpPointerTag,
|
||||
Types: pointer.Press,
|
||||
}.Add(gtx.Ops)
|
||||
stack := op.Save(gtx.Ops)
|
||||
area.Pop()
|
||||
stack := op.Offset(image.Point{}).Push(gtx.Ops)
|
||||
curVoice := 0
|
||||
for _, trk := range t.Song().Score.Tracks {
|
||||
gtx := gtx
|
||||
@ -341,14 +351,14 @@ func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
}
|
||||
}
|
||||
gtx.Constraints.Max.X = trackColWidth
|
||||
LabelStyle{Alignment: layout.N, Text: instrName, FontSize: unit.Dp(12), Color: mediumEmphasisTextColor}.Layout(gtx)
|
||||
op.Offset(f32.Pt(trackColWidth, 0)).Add(gtx.Ops)
|
||||
LabelStyle{Alignment: layout.N, Text: instrName, FontSize: unit.Sp(12), Color: mediumEmphasisTextColor}.Layout(gtx)
|
||||
op.Offset(image.Point{trackColWidth, 0}).Add(gtx.Ops)
|
||||
curVoice += trk.NumVoices
|
||||
}
|
||||
stack.Load()
|
||||
op.Offset(f32.Pt(0, float32(gtx.Constraints.Max.Y-trackRowHeight)/2)).Add(gtx.Ops)
|
||||
op.Offset(f32.Pt(0, (-1*trackRowHeight)*float32(cursorSongRow))).Add(gtx.Ops)
|
||||
if te.focused || t.OrderEditor.Focused() {
|
||||
stack.Pop()
|
||||
op.Offset(image.Point{0, (gtx.Constraints.Max.Y - trackRowHeight) / 2}).Add(gtx.Ops)
|
||||
op.Offset(image.Point{0, int((-1 * trackRowHeight) * (cursorSongRow))}).Add(gtx.Ops)
|
||||
if te.Focused() || t.OrderEditor.Focused() {
|
||||
x1, y1 := t.Cursor().Track, t.Cursor().Pattern
|
||||
x2, y2 := t.SelectionCorner().Track, t.SelectionCorner().Pattern
|
||||
if x1 > x2 {
|
||||
@ -365,7 +375,7 @@ func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
y2 *= trackRowHeight * t.Song().Score.RowsPerPattern
|
||||
paint.FillShape(gtx.Ops, inactiveSelectionColor, clip.Rect{Min: image.Pt(x1, y1), Max: image.Pt(x2, y2)}.Op())
|
||||
}
|
||||
if te.focused {
|
||||
if te.Focused() {
|
||||
x1, y1 := t.Cursor().Track, t.Cursor().Pattern*t.Song().Score.RowsPerPattern+t.Cursor().Row
|
||||
x2, y2 := t.SelectionCorner().Track, t.SelectionCorner().Pattern*t.Song().Score.RowsPerPattern+t.SelectionCorner().Row
|
||||
if x1 > x2 {
|
||||
@ -401,27 +411,27 @@ func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
if l := t.Song().Score.LengthInRows(); lastRow >= l {
|
||||
lastRow = l - 1
|
||||
}
|
||||
op.Offset(f32.Pt(0, float32(trackRowHeight*firstRow))).Add(gtx.Ops)
|
||||
op.Offset(image.Point{0, trackRowHeight * firstRow}).Add(gtx.Ops)
|
||||
for trkIndex, trk := range t.Song().Score.Tracks {
|
||||
stack := op.Save(gtx.Ops)
|
||||
stack := op.Offset(image.Point{}).Push(gtx.Ops)
|
||||
for row := firstRow; row <= lastRow; row++ {
|
||||
pat := row / t.Song().Score.RowsPerPattern
|
||||
patRow := row % t.Song().Score.RowsPerPattern
|
||||
s := trk.Order.Get(pat)
|
||||
if s < 0 {
|
||||
op.Offset(f32.Pt(0, trackRowHeight)).Add(gtx.Ops)
|
||||
op.Offset(image.Point{0, trackRowHeight}).Add(gtx.Ops)
|
||||
continue
|
||||
}
|
||||
if s >= 0 && patRow == 0 {
|
||||
paint.ColorOp{Color: trackerPatMarker}.Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, patternIndexToString(s))
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, patternIndexToString(s), op.CallOp{})
|
||||
}
|
||||
if s >= 0 && patRow == 1 && t.IsPatternUnique(trkIndex, s) {
|
||||
paint.ColorOp{Color: mediumEmphasisTextColor}.Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, "*")
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, "*", op.CallOp{})
|
||||
}
|
||||
op.Offset(f32.Pt(patmarkWidth, 0)).Add(gtx.Ops)
|
||||
if te.focused && t.Cursor().Row == patRow && t.Cursor().Pattern == pat {
|
||||
op.Offset(image.Point{patmarkWidth, 0}).Add(gtx.Ops)
|
||||
if te.Focused() && t.Cursor().Row == patRow && t.Cursor().Pattern == pat {
|
||||
paint.ColorOp{Color: trackerActiveTextColor}.Add(gtx.Ops)
|
||||
} else {
|
||||
paint.ColorOp{Color: trackerInactiveTextColor}.Add(gtx.Ops)
|
||||
@ -440,14 +450,14 @@ func (te *TrackEditor) layoutTracks(gtx C, t *Tracker) D {
|
||||
default:
|
||||
text = fmt.Sprintf("%02x", c)
|
||||
}
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(text))
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, strings.ToUpper(text), op.CallOp{})
|
||||
} else {
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, tracker.NoteStr(c))
|
||||
widget.Label{}.Layout(gtx, textShaper, trackerFont, trackerFontSize, tracker.NoteStr(c), op.CallOp{})
|
||||
}
|
||||
op.Offset(f32.Pt(-patmarkWidth, trackRowHeight)).Add(gtx.Ops)
|
||||
op.Offset(image.Point{-patmarkWidth, trackRowHeight}).Add(gtx.Ops)
|
||||
}
|
||||
stack.Load()
|
||||
op.Offset(f32.Pt(trackColWidth, 0)).Add(gtx.Ops)
|
||||
stack.Pop()
|
||||
op.Offset(image.Point{trackColWidth, 0}).Add(gtx.Ops)
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ import (
|
||||
|
||||
"gioui.org/app"
|
||||
"gioui.org/font/gofont"
|
||||
"gioui.org/io/clipboard"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/io/system"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
@ -192,18 +190,9 @@ mainloop:
|
||||
app.Title("Sointu Tracker"),
|
||||
)
|
||||
}
|
||||
case key.Event:
|
||||
if t.KeyEvent(e, w) {
|
||||
w.Invalidate()
|
||||
}
|
||||
case clipboard.Event:
|
||||
err := t.UnmarshalContent([]byte(e.Text))
|
||||
if err == nil {
|
||||
w.Invalidate()
|
||||
}
|
||||
case system.FrameEvent:
|
||||
gtx := layout.NewContext(&ops, e)
|
||||
t.Layout(gtx)
|
||||
t.Layout(gtx, w)
|
||||
e.Frame(gtx.Ops)
|
||||
}
|
||||
}
|
||||
@ -211,5 +200,5 @@ mainloop:
|
||||
break mainloop
|
||||
}
|
||||
}
|
||||
w.Close()
|
||||
w.Perform(system.ActionClose)
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package gioui
|
||||
import (
|
||||
"image"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
@ -17,9 +16,9 @@ type VuMeter struct {
|
||||
}
|
||||
|
||||
func (v VuMeter) Layout(gtx C) D {
|
||||
defer op.Save(gtx.Ops).Load()
|
||||
gtx.Constraints.Max.Y = gtx.Px(unit.Dp(12))
|
||||
height := gtx.Px(unit.Dp(6))
|
||||
defer op.Offset(image.Point{}).Push(gtx.Ops).Pop()
|
||||
gtx.Constraints.Max.Y = gtx.Dp(unit.Dp(12))
|
||||
height := gtx.Dp(unit.Dp(6))
|
||||
for j := 0; j < 2; j++ {
|
||||
value := float32(v.Volume.Average[j]) + v.Range
|
||||
if value > 0 {
|
||||
@ -41,7 +40,7 @@ func (v VuMeter) Layout(gtx C) D {
|
||||
}
|
||||
paint.FillShape(gtx.Ops, color, clip.Rect(image.Rect(x-1, 0, x, height)).Op())
|
||||
}
|
||||
op.Offset(f32.Pt(0, float32(height))).Add(gtx.Ops)
|
||||
op.Offset(image.Point{0, height}).Add(gtx.Ops)
|
||||
}
|
||||
return D{Size: gtx.Constraints.Max}
|
||||
}
|
||||
|
Reference in New Issue
Block a user