From 8c4f7ee61f53252ee9f5449f6affa0232bb3ab23 Mon Sep 17 00:00:00 2001 From: "5684185+vsariola@users.noreply.github.com" <5684185+vsariola@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:56:09 +0300 Subject: [PATCH] refactor(tracker/gioui): update gioui to newer version --- go.mod | 20 ++-- go.sum | 73 +++++++++++--- tracker/gioui/alert.go | 10 +- tracker/gioui/buttons.go | 2 +- tracker/gioui/dialog.go | 2 +- tracker/gioui/draglist.go | 26 +++-- tracker/gioui/filedialog.go | 20 ++-- tracker/gioui/instrumenteditor.go | 157 ++++++++++++------------------ tracker/gioui/keyevent.go | 61 ++++++------ tracker/gioui/label.go | 14 +-- tracker/gioui/layout.go | 19 +++- tracker/gioui/menu.go | 22 +++-- tracker/gioui/numericupdown.go | 70 +++++++------ tracker/gioui/ordereditor.go | 45 +++++---- tracker/gioui/parameditor.go | 26 +++-- tracker/gioui/parameter.go | 25 +++-- tracker/gioui/popup.go | 38 ++++---- tracker/gioui/rowmarkers.go | 17 ++-- tracker/gioui/scrollbar.go | 26 ++--- tracker/gioui/songpanel.go | 37 ++++--- tracker/gioui/split.go | 31 +++--- tracker/gioui/theme.go | 4 +- tracker/gioui/trackeditor.go | 90 +++++++++-------- tracker/gioui/tracker.go | 15 +-- tracker/gioui/vumeter.go | 9 +- 25 files changed, 457 insertions(+), 402 deletions(-) diff --git a/go.mod b/go.mod index 074afc1..6dc4d6a 100644 --- a/go.mod +++ b/go.mod @@ -3,30 +3,36 @@ module github.com/vsariola/sointu go 1.17 require ( - gioui.org v0.0.0-20210410094005-495c69018772 - gioui.org/x v0.0.0-20210419013052-6db76265c4e1 + gioui.org v0.1.0 + gioui.org/x v0.1.0 github.com/Masterminds/sprig v2.22.0+incompatible github.com/hajimehoshi/oto v0.6.6 - golang.org/x/exp v0.0.0-20201229011636-eab1b5eb1a03 + golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 pipelined.dev/audio/vst2 v0.10.1-0.20230513073541-08ee2a4520cb ) require ( + gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect + gioui.org/shader v1.0.6 // indirect + git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 // indirect github.com/Masterminds/goutils v1.1.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect + github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433 // indirect + github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/google/uuid v1.1.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/stretchr/testify v1.6.1 // indirect - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect - golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 // indirect + golang.org/x/image v0.7.0 // indirect golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect - golang.org/x/sys v0.0.0-20210304124612-50617c2ba197 // indirect - golang.org/x/text v0.3.4 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect pipelined.dev/pipe v0.11.0 // indirect pipelined.dev/signal v0.10.0 // indirect ) diff --git a/go.sum b/go.sum index 9447d71..07360a7 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,21 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY= +eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA= gioui.org v0.0.0-20210402191542-ce7f0da06ee3/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -gioui.org v0.0.0-20210410094005-495c69018772 h1:QpGMsubuP4JVlZj5VvvFfRikbLDN0QJj71oX9ABeaqM= -gioui.org v0.0.0-20210410094005-495c69018772/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +gioui.org v0.1.0 h1:fEDY5A4+epOdzjCBYSUC4BzvjWqsjfqf5D6mskbthOs= +gioui.org v0.1.0/go.mod h1:a3hz8FyrPMkt899D9YrxMGtyRzpPrJpz1Lzbssn81vI= +gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= +gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc= +gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= +gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y= +gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= gioui.org/x v0.0.0-20210419013052-6db76265c4e1 h1:NfHFIxNzNY/s7ePtrf9nCKr9f3gYiVS40rAIdbj5Q1k= gioui.org/x v0.0.0-20210419013052-6db76265c4e1/go.mod h1:qsAS5EBzGhn3sJ98FJdA+ae+E5/DgmxjySERjjR1Zvg= +gioui.org/x v0.1.0 h1:CvphvaQSroRaNEZ+JbXBkV3J3klA76U3JpieyEwHFX4= +gioui.org/x v0.1.0/go.mod h1:5qZxjtK/TVznMlcEOyn8OheiCZlArxF3IKnLqSehKXQ= +git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI= +git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -16,6 +27,13 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433 h1:Pdyvqsfi1QYgFfZa4R8otBOtgO+CGyBDMEG8cM3jwvE= +github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433/go.mod h1:KmrpWuSMFcO2yjmyhGpnBGQHSKAoEgMTSSzvLDzCuEA= +github.com/go-text/typesetting-utils v0.0.0-20230412163830-89e4bcfa3ecc h1:9Kf84pnrmmjdRzZIkomfjowmGUhHs20jkrWYw/I6CYc= +github.com/go-text/typesetting-utils v0.0.0-20230412163830-89e4bcfa3ecc/go.mod h1:RaqFwjcYyM5BjbYGwON0H5K0UqwO3sJlo9ukKha80ZE= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hajimehoshi/oto v0.6.6 h1:HYSZ8cYZqOL4iHugvbcfhNN2smiSOsBMaoSBi4nnWcw= @@ -24,6 +42,7 @@ github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jezek/xgb v1.0.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= @@ -33,20 +52,29 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20201229011636-eab1b5eb1a03 h1:XlAInxBYX5nBofPaY51uv/x9xmRgZGr/lDOsePd2AcE= golang.org/x/exp v0.0.0-20201229011636-eab1b5eb1a03/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= +golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg= +golang.org/x/exp v0.0.0-20221012211006-4de253d81b95/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 h1:ryT6Nf0R83ZgD8WnFFdfI8wCeyqgdXWN4+CkFVNPAT0= +golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A= +golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= +golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -56,26 +84,53 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197 h1:7+SpRyhoo46QjKkYInQXpcfxx3TYFEYkn131lwGE9/0= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= @@ -85,10 +140,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -pipelined.dev/audio/vst2 v0.10.0 h1:exmszZmQ2KZeqfXnxqrQ2UsLexaz9B5WZHE2Kbbd/mg= -pipelined.dev/audio/vst2 v0.10.0/go.mod h1:wETLxsbBPftj6t4iVBCXvH/Xgd27ZgIC4hNnHDYNuz8= -pipelined.dev/audio/vst2 v0.10.1-0.20230501210043-10b5e35ddc62 h1:cDF8OupcD4iSldxY1j5kbMsXtBzrQ9ODJM7tnCzyul8= -pipelined.dev/audio/vst2 v0.10.1-0.20230501210043-10b5e35ddc62/go.mod h1:wETLxsbBPftj6t4iVBCXvH/Xgd27ZgIC4hNnHDYNuz8= pipelined.dev/audio/vst2 v0.10.1-0.20230513073541-08ee2a4520cb h1:KupwowSEQavEdUQfZc3TKGzls96Dax1eva/0sBfdqHQ= pipelined.dev/audio/vst2 v0.10.1-0.20230513073541-08ee2a4520cb/go.mod h1:wETLxsbBPftj6t4iVBCXvH/Xgd27ZgIC4hNnHDYNuz8= pipelined.dev/pipe v0.10.0/go.mod h1:aIt+NPlW0QLYByqYniG77lTxSvl7OtCNLws/m+Xz5ww= diff --git a/tracker/gioui/alert.go b/tracker/gioui/alert.go index 66d63d9..2e8a468 100644 --- a/tracker/gioui/alert.go +++ b/tracker/gioui/alert.go @@ -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 }) diff --git a/tracker/gioui/buttons.go b/tracker/gioui/buttons.go index 0fe4e18..7468e77 100644 --- a/tracker/gioui/buttons.go +++ b/tracker/gioui/buttons.go @@ -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 { diff --git a/tracker/gioui/dialog.go b/tracker/gioui/dialog.go index 8c406be..fecc2df 100644 --- a/tracker/gioui/dialog.go +++ b/tracker/gioui/dialog.go @@ -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), diff --git a/tracker/gioui/draglist.go b/tracker/gioui/draglist.go index 558c977..7557b89 100644 --- a/tracker/gioui/draglist.go +++ b/tracker/gioui/draglist.go @@ -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) diff --git a/tracker/gioui/filedialog.go b/tracker/gioui/filedialog.go index 85ec40c..25dbb45 100644 --- a/tracker/gioui/filedialog.go +++ b/tracker/gioui/filedialog.go @@ -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 diff --git a/tracker/gioui/instrumenteditor.go b/tracker/gioui/instrumenteditor.go index 5828968..6211911 100644 --- a/tracker/gioui/instrumenteditor.go +++ b/tracker/gioui/instrumenteditor.go @@ -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 { diff --git a/tracker/gioui/keyevent.go b/tracker/gioui/keyevent.go index 6526938..d0a8bc8 100644 --- a/tracker/gioui/keyevent.go +++ b/tracker/gioui/keyevent.go @@ -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 } diff --git a/tracker/gioui/label.go b/tracker/gioui/label.go index 1aae016..d4b365d 100644 --- a/tracker/gioui/label.go +++ b/tracker/gioui/label.go @@ -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{}) }), ) } diff --git a/tracker/gioui/layout.go b/tracker/gioui/layout.go index de32015..b299eea 100644 --- a/tracker/gioui/layout.go +++ b/tracker/gioui/layout.go @@ -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) diff --git a/tracker/gioui/menu.go b/tracker/gioui/menu.go index a498a7b..00bd6e1 100644 --- a/tracker/gioui/menu.go +++ b/tracker/gioui/menu.go @@ -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, } diff --git a/tracker/gioui/numericupdown.go b/tracker/gioui/numericupdown.go index 7917e51..8c85d4d 100644 --- a/tracker/gioui/numericupdown.go +++ b/tracker/gioui/numericupdown.go @@ -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} } diff --git a/tracker/gioui/ordereditor.go b/tracker/gioui/ordereditor.go index cac8062..609ed5a 100644 --- a/tracker/gioui/ordereditor.go +++ b/tracker/gioui/ordereditor.go @@ -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)} } diff --git a/tracker/gioui/parameditor.go b/tracker/gioui/parameditor.go index 60d3512..7b799d6 100644 --- a/tracker/gioui/parameditor.go +++ b/tracker/gioui/parameditor.go @@ -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 { diff --git a/tracker/gioui/parameter.go b/tracker/gioui/parameter.go index 3b7e173..7cf8ec5 100644 --- a/tracker/gioui/parameter.go +++ b/tracker/gioui/parameter.go @@ -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, diff --git a/tracker/gioui/popup.go b/tracker/gioui/popup.go index 011e7f2..e831219 100644 --- a/tracker/gioui/popup.go +++ b/tracker/gioui/popup.go @@ -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) diff --git a/tracker/gioui/rowmarkers.go b/tracker/gioui/rowmarkers.go index 765fc8e..4e0dca0 100644 --- a/tracker/gioui/rowmarkers.go +++ b/tracker/gioui/rowmarkers.go @@ -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)} diff --git a/tracker/gioui/scrollbar.go b/tracker/gioui/scrollbar.go index 60e14e9..c359a8e 100644 --- a/tracker/gioui/scrollbar.go +++ b/tracker/gioui/scrollbar.go @@ -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) diff --git a/tracker/gioui/songpanel.go b/tracker/gioui/songpanel.go index ca69b0c..f021c44 100644 --- a/tracker/gioui/songpanel.go +++ b/tracker/gioui/songpanel.go @@ -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 }), diff --git a/tracker/gioui/split.go b/tracker/gioui/split.go index d7a526f..490eaea 100644 --- a/tracker/gioui/split.go +++ b/tracker/gioui/split.go @@ -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} diff --git a/tracker/gioui/theme.go b/tracker/gioui/theme.go index af91abf..a3a44dc 100644 --- a/tracker/gioui/theme.go +++ b/tracker/gioui/theme.go @@ -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} diff --git a/tracker/gioui/trackeditor.go b/tracker/gioui/trackeditor.go index fb692e3..7bf27a1 100644 --- a/tracker/gioui/trackeditor.go +++ b/tracker/gioui/trackeditor.go @@ -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} } diff --git a/tracker/gioui/tracker.go b/tracker/gioui/tracker.go index 8453da0..f3929ea 100644 --- a/tracker/gioui/tracker.go +++ b/tracker/gioui/tracker.go @@ -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) } diff --git a/tracker/gioui/vumeter.go b/tracker/gioui/vumeter.go index 714db4d..a1a1b4f 100644 --- a/tracker/gioui/vumeter.go +++ b/tracker/gioui/vumeter.go @@ -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} }