refactor(tracker/gioui): update gioui to newer version

This commit is contained in:
5684185+vsariola@users.noreply.github.com
2023-07-07 17:56:09 +03:00
parent f5980ecb79
commit 8c4f7ee61f
25 changed files with 457 additions and 402 deletions

View File

@ -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
})

View File

@ -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 {

View File

@ -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),

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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{})
}),
)
}

View File

@ -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)

View File

@ -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,
}

View File

@ -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}
}

View File

@ -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)}
}

View File

@ -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 {

View File

@ -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,

View File

@ -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)

View File

@ -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)}

View File

@ -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)

View File

@ -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
}),

View File

@ -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}

View File

@ -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}

View File

@ -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}
}

View File

@ -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)
}

View File

@ -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}
}