From 8264e8f6cddd9ec966668101fab49ec49b1aa31c Mon Sep 17 00:00:00 2001 From: Samy A Date: Sat, 27 May 2023 10:21:07 +0100 Subject: [PATCH 1/3] Rewrite of CompletionEntry simplified code support variable height items first item automatically selected items are selected on hover and remplaced on Tap or Enter Added completion_demo to cmd Changed fyne version to latest (2.3.4) in go.mod --- cmd/completion_demo/main.go | 51 ++++++ go.mod | 6 +- go.sum | 60 ++++--- widget/completionentry.go | 288 +++++++++++++++++++-------------- widget/completionentry_test.go | 35 ++-- 5 files changed, 279 insertions(+), 161 deletions(-) create mode 100644 cmd/completion_demo/main.go diff --git a/cmd/completion_demo/main.go b/cmd/completion_demo/main.go new file mode 100644 index 00000000..2885111b --- /dev/null +++ b/cmd/completion_demo/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "encoding/json" + "net/http" + + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + xwidget "fyne.io/x/fyne/widget" +) + +func main() { + a := app.New() + w := a.NewWindow("Completion Entry Demo") + + entry := xwidget.NewCompletionEntry([]string{}) + entry.OnChanged = func(s string) { + // completion start for text length >= 3 + if len(s) < 3 { + entry.HideCompletion() + return + } + + // Make a search on wikipedia + resp, err := http.Get( + "https://en.wikipedia.org/w/api.php?action=opensearch&search=" + entry.Text, + ) + if err != nil { + entry.HideCompletion() + return + } + + // Get the list of possible completion + var results [][]string + json.NewDecoder(resp.Body).Decode(&results) + + // no results + if len(results) == 0 { + entry.HideCompletion() + return + } + + // then show them + entry.SetOptions(results[1]) + entry.ShowCompletion() + } + + w.SetContent(container.NewBorder(entry, nil, nil, nil, widget.NewLabel("Enter 3 chars to start search..."))) + w.ShowAndRun() +} diff --git a/go.mod b/go.mod index e8834a43..4170607f 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module fyne.io/x/fyne go 1.14 require ( - fyne.io/fyne/v2 v2.2.4 + fyne.io/fyne/v2 v2.3.4 github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84 github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/gorilla/websocket v1.4.2 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/stretchr/testify v1.7.2 + github.com/stretchr/testify v1.8.0 github.com/wagslane/go-password-validator v0.3.0 - golang.org/x/image v0.0.0-20220601225756-64ec528b34cd + golang.org/x/image v0.3.0 ) diff --git a/go.sum b/go.sum index fa9ab427..a6007ab5 100644 --- a/go.sum +++ b/go.sum @@ -37,10 +37,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -fyne.io/fyne/v2 v2.2.4 h1:izyiDUjJYAB7B/MST7M9GDs+mQ0CwDgRZTiVJZQoEe4= -fyne.io/fyne/v2 v2.2.4/go.mod h1:MBoGuHzLLSXdQOWFAwWhIhYTEMp33zqtGCReSWhaQTA= -fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 h1:V2IC9t0Zj9Ur6qDbfhUuzVmIvXKFyxZXRJyigUvovs4= -fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= +fyne.io/fyne/v2 v2.3.4 h1:CL8LBUoct2K3EF7Q7NdcDrDMcb3OrNJTghLYTFF400Q= +fyne.io/fyne/v2 v2.3.4/go.mod h1:X2+NrR+62mvAiAt2fwKT7035zQsE77KVV1NlvWo4vW8= +fyne.io/systray v1.10.1-0.20230403195833-7dc3c09283d6 h1:lHt8dm97Uy9ggtnt9N6XOlsp76wXmRAh3SjReWm1e2Q= +fyne.io/systray v1.10.1-0.20230403195833-7dc3c09283d6/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84 h1:L2C3QKBQwuHuiKwaBj8HDs2r0bAUGqtBYe3ymG0S6Z4= github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84/go.mod h1:oTJGG91FhtsxvUFVwHSvr6zuaTcAuroj/ToxfT7Ox8U= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -78,8 +78,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= -github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= +github.com/fredbi/uri v0.1.0 h1:8XBBD74STBLcWJ5smjEkKCZivSxSKMhFB0FbQUKeNyM= +github.com/fredbi/uri v0.1.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -96,15 +96,20 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec h1:3FLiRYO6PlQFDpUU7OEFlWgjGD1jnBIVSJ5SYRWk+9c= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-text/typesetting v0.0.0-20230405155246-bf9c697c6e16 h1:DvHeDNqK8cxdZ7C6y88pt3uE7euZH7/LluzyfnUfH/Q= +github.com/go-text/typesetting v0.0.0-20230405155246-bf9c697c6e16/go.mod h1:zvWM81wAVW6QfVDI6yxfbCuoLnobSYTuMsrXU/u11y8= +github.com/go-text/typesetting-utils v0.0.0-20230326210548-458646692de6 h1:zAAA1U4ykFwqPbcj6YDxvq3F2g0wc/ngPfLJjkR/8zs= +github.com/go-text/typesetting-utils v0.0.0-20230326210548-458646692de6/go.mod h1:RaqFwjcYyM5BjbYGwON0H5K0UqwO3sJlo9ukKha80ZE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= -github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= +github.com/goki/freetype v0.0.0-20220119013949-7a161fd3728c h1:JGCm/+tJ9gC6THUxooTldS+CUDsba0qvkvU3DHklqW8= +github.com/goki/freetype v0.0.0-20220119013949-7a161fd3728c/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -267,11 +272,12 @@ github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t6 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM= -github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= -github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= -github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= +github.com/srwiley/oksvg v0.0.0-20220731023508-a61f04f16b76 h1:Ga2uagHhDeGysCixLAzH0mS2TU+CrbQavmsHUNkEEVA= +github.com/srwiley/oksvg v0.0.0-20220731023508-a61f04f16b76/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= +github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780 h1:oDMiXaTMyBEuZMU53atpxqYsSB3U1CHkeAu2zr6wTeY= +github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -279,8 +285,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= @@ -292,8 +298,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -315,6 +322,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -328,8 +336,9 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 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-20220601225756-64ec528b34cd h1:9NbNcTg//wfC5JskFW4Z3sqwVnjmJKHxLAol1bW2qgw= -golang.org/x/image v0.0.0-20220601225756-64ec528b34cd/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg= +golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -355,6 +364,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -392,8 +402,10 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -417,6 +429,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -464,9 +477,12 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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 h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -475,8 +491,9 @@ 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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -533,6 +550,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/widget/completionentry.go b/widget/completionentry.go index 15c9a3f4..559d323a 100644 --- a/widget/completionentry.go +++ b/widget/completionentry.go @@ -2,6 +2,7 @@ package widget import ( "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -9,14 +10,18 @@ import ( // CompletionEntry is an Entry with options displayed in a PopUpMenu. type CompletionEntry struct { widget.Entry - popupMenu *widget.PopUp - navigableList *navigableList - Options []string - pause bool - itemHeight float32 + + Options []string + OnCompleted func(string) string // Called when you select an item from the list ; return different string to override the completion + SubmitOnCompleted bool // True will call Entry.OnSubmited when you select a completion item CustomCreate func() fyne.CanvasObject CustomUpdate func(id widget.ListItemID, object fyne.CanvasObject) + + popup *widget.PopUp + list *completionEntryList + selected widget.ListItemID + pause bool } // NewCompletionEntry creates a new CompletionEntry which creates a popup menu that responds to keystrokes to navigate through the items without losing the editing ability of the text input. @@ -28,8 +33,9 @@ func NewCompletionEntry(options []string) *CompletionEntry { // HideCompletion hides the completion menu. func (c *CompletionEntry) HideCompletion() { - if c.popupMenu != nil { - c.popupMenu.Hide() + if c.popup != nil { + c.list.UnselectAll() + c.popup.Hide() } } @@ -38,17 +44,17 @@ func (c *CompletionEntry) HideCompletion() { // Implements: fyne.Widget func (c *CompletionEntry) Move(pos fyne.Position) { c.Entry.Move(pos) - if c.popupMenu != nil { - c.popupMenu.Resize(c.maxSize()) - c.popupMenu.Move(c.popUpPos()) + if c.popup != nil && c.popup.Visible() { + c.popup.Move(c.popUpPos()) + c.popup.Resize(c.maxSize()) } } // Refresh the list to update the options to display. func (c *CompletionEntry) Refresh() { c.Entry.Refresh() - if c.navigableList != nil { - c.navigableList.SetOptions(c.Options) + if c.list != nil && c.list.Visible() { + c.list.Refresh() } } @@ -63,168 +69,202 @@ func (c *CompletionEntry) ShowCompletion() { if c.pause { return } - if len(c.Options) == 0 { + if len(c.Options) <= 0 { c.HideCompletion() return } - if c.navigableList == nil { - c.navigableList = newNavigableList(c.Options, &c.Entry, c.setTextFromMenu, c.HideCompletion, - c.CustomCreate, c.CustomUpdate) - } else { - c.navigableList.UnselectAll() - c.navigableList.selected = -1 + cnv := fyne.CurrentApp().Driver().CanvasForObject(c) + if cnv == nil { + return // canvas acquisiton failed (widget not showed yet?) } - holder := fyne.CurrentApp().Driver().CanvasForObject(c) - if c.popupMenu == nil { - c.popupMenu = widget.NewPopUp(c.navigableList, holder) + if c.list == nil { + c.list = newCompletionEntryList(c) } - c.popupMenu.Resize(c.maxSize()) - c.popupMenu.ShowAtPosition(c.popUpPos()) - holder.Focus(c.navigableList) + if c.popup == nil { + c.popup = widget.NewPopUp(c.list, cnv) + } + + c.popup.ShowAtPosition(c.popUpPos()) + c.popup.Resize(c.maxSize()) + + c.list.Select(0) + cnv.Focus(c.list) } // calculate the max size to make the popup to cover everything below the entry func (c *CompletionEntry) maxSize() fyne.Size { cnv := fyne.CurrentApp().Driver().CanvasForObject(c) - if c.itemHeight == 0 { - // set item height to cache - c.itemHeight = c.navigableList.CreateItem().MinSize().Height + // return empty size if cannot get canvas (widget not showed yet?) + if cnv == nil { + return fyne.Size{} + } + + pos := fyne.CurrentApp().Driver().AbsolutePositionForObject(c) + + // define size boundaries + minWidth := c.Size().Width + maxWidth := cnv.Size().Width - pos.X - theme.Padding() + maxHeight := cnv.Size().Height - pos.Y - c.MinSize().Height - 2*theme.Padding() + + // iterating items until the end or we rech maxHeight + var width, height float32 + for i := 0; i < len(c.Options); i++ { + item := c.list.CreateItem() + c.list.UpdateItem(i, item) + sz := item.MinSize() + if sz.Width > width { + width = sz.Width + } + height += sz.Height + theme.Padding() + if height > maxHeight { + height = maxHeight + break + } } + height += theme.Padding() // popup padding - listheight := float32(len(c.Options))*(c.itemHeight+2*theme.Padding()+theme.SeparatorThicknessSize()) + 2*theme.Padding() - canvasSize := cnv.Size() - entrySize := c.Size() - if canvasSize.Height > listheight { - return fyne.NewSize(entrySize.Width, listheight) + width += 2 * theme.Padding() // let some padding on the trailing end of the longest item + if width < minWidth { + width = minWidth + } + if width > maxWidth { + width = maxWidth } - return fyne.NewSize( - entrySize.Width, - canvasSize.Height-c.Position().Y-entrySize.Height-theme.InputBorderSize()-theme.Padding()) + return fyne.NewSize(width, height) } // calculate where the popup should appear func (c *CompletionEntry) popUpPos() fyne.Position { - entryPos := fyne.CurrentApp().Driver().AbsolutePositionForObject(c) - return entryPos.Add(fyne.NewPos(0, c.Size().Height)) + pos := fyne.CurrentApp().Driver().AbsolutePositionForObject(c) + return pos.Add(fyne.NewPos(0, c.Size().Height+theme.Padding())) } // Prevent the menu to open when the user validate value from the menu. func (c *CompletionEntry) setTextFromMenu(s string) { + c.popup.Hide() c.pause = true - c.Entry.SetText(s) + if c.OnCompleted != nil { + s = c.OnCompleted(s) + } + c.Entry.Text = s c.Entry.CursorColumn = len([]rune(s)) c.Entry.Refresh() c.pause = false - c.popupMenu.Hide() + if c.SubmitOnCompleted && c.OnSubmitted != nil { + c.OnSubmitted(c.Entry.Text) + } } -type navigableList struct { +type completionEntryList struct { widget.List - entry *widget.Entry - selected int - setTextFromMenu func(string) - hide func() - navigating bool - items []string - - customCreate func() fyne.CanvasObject - customUpdate func(id widget.ListItemID, object fyne.CanvasObject) -} - -func newNavigableList(items []string, entry *widget.Entry, setTextFromMenu func(string), hide func(), - create func() fyne.CanvasObject, update func(id widget.ListItemID, object fyne.CanvasObject)) *navigableList { - n := &navigableList{ - entry: entry, - selected: -1, - setTextFromMenu: setTextFromMenu, - hide: hide, - items: items, - customCreate: create, - customUpdate: update, - } - - n.List = widget.List{ - Length: func() int { - return len(n.items) - }, - CreateItem: func() fyne.CanvasObject { - if fn := n.customCreate; fn != nil { - return fn() - } - return widget.NewLabel("") - }, - UpdateItem: func(i widget.ListItemID, o fyne.CanvasObject) { - if fn := n.customUpdate; fn != nil { - fn(i, o) - return - } - o.(*widget.Label).SetText(n.items[i]) - }, - OnSelected: func(id widget.ListItemID) { - if !n.navigating && id > -1 { - setTextFromMenu(n.items[id]) - } - n.navigating = false - }, - } - n.ExtendBaseWidget(n) - return n + + // just hold a reference to the "parent" CompletionEntry that already holds all what the list needs to operate + parent *CompletionEntry } -// Implements: fyne.Focusable -func (n *navigableList) FocusGained() { +func newCompletionEntryList(parent *CompletionEntry) *completionEntryList { + list := &completionEntryList{parent: parent} + list.ExtendBaseWidget(list) + + list.List.Length = func() int { return len(parent.Options) } + list.List.CreateItem = func() fyne.CanvasObject { + var item *completionEntryListItem + if parent.CustomCreate != nil { + item = newCompletionEntryListItem(parent, parent.CustomCreate()) + } else { + item = newCompletionEntryListItem(parent, widget.NewLabel("")) + } + return item + } + list.List.UpdateItem = func(id widget.ListItemID, co fyne.CanvasObject) { + if parent.CustomUpdate != nil { + parent.CustomUpdate(id, co.(*completionEntryListItem).co) + } else { + co.(*completionEntryListItem).co.(*widget.Label).Text = parent.Options[id] + } + co.(*completionEntryListItem).id = id + list.SetItemHeight(id, co.MinSize().Height) + co.Refresh() + } + list.List.OnSelected = func(id widget.ListItemID) { + parent.selected = id + } + list.List.OnUnselected = func(_ widget.ListItemID) { + parent.selected = -1 + } + return list } // Implements: fyne.Focusable -func (n *navigableList) FocusLost() { -} +func (list *completionEntryList) FocusGained() {} -func (n *navigableList) SetOptions(items []string) { - n.Unselect(n.selected) - n.items = items - n.Refresh() - n.selected = -1 -} +// Implements: fyne.Focusable +func (list *completionEntryList) FocusLost() {} -func (n *navigableList) TypedKey(event *fyne.KeyEvent) { - switch event.Name { +// Implements: fyne.Focusable +func (list *completionEntryList) TypedKey(ke *fyne.KeyEvent) { + switch ke.Name { case fyne.KeyDown: - if n.selected < len(n.items)-1 { - n.selected++ + if list.parent.selected < len(list.parent.Options)-1 { + list.parent.list.Select(list.parent.selected + 1) } else { - n.selected = 0 + list.parent.list.Select(0) } - n.navigating = true - n.Select(n.selected) - case fyne.KeyUp: - if n.selected > 0 { - n.selected-- + if list.parent.selected > 0 { + list.parent.list.Select(list.parent.selected - 1) } else { - n.selected = len(n.items) - 1 + list.parent.list.Select(len(list.parent.Options) - 1) } - n.navigating = true - n.Select(n.selected) case fyne.KeyReturn, fyne.KeyEnter: - if n.selected == -1 { // so the user want to submit the entry - n.hide() - n.entry.TypedKey(event) + if list.parent.selected >= 0 { + list.parent.setTextFromMenu(list.parent.Options[list.parent.selected]) } else { - n.navigating = false - n.OnSelected(n.selected) + list.parent.HideCompletion() + list.parent.Entry.TypedKey(ke) } - case fyne.KeyEscape: - n.hide() + case fyne.KeyTab, fyne.KeyEscape: + list.parent.HideCompletion() default: - n.entry.TypedKey(event) - + list.parent.TypedKey(ke) } } -func (n *navigableList) TypedRune(r rune) { - n.entry.TypedRune(r) +// Implements: fyne.Focusable +func (list *completionEntryList) TypedRune(r rune) { + list.parent.TypedRune(r) +} + +// Implements: fyne.Shortcutable +func (list *completionEntryList) TypedShortcut(s fyne.Shortcut) { + list.parent.TypedShortcut(s) +} + +type completionEntryListItem struct { + widget.BaseWidget + parent *CompletionEntry + id widget.ListItemID // each list item knows where it belongs in parent's data slice + co fyne.CanvasObject +} + +func newCompletionEntryListItem(parent *CompletionEntry, co fyne.CanvasObject) *completionEntryListItem { + item := &completionEntryListItem{parent: parent, id: -1, co: co} + item.ExtendBaseWidget(item) + return item } + +func (item *completionEntryListItem) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(item.co) +} + +func (item *completionEntryListItem) Tapped(_ *fyne.PointEvent) { + item.parent.setTextFromMenu(item.parent.Options[item.id]) +} + +func (item *completionEntryListItem) MouseIn(_ *desktop.MouseEvent) { item.parent.list.Select(item.id) } +func (item *completionEntryListItem) MouseMoved(_ *desktop.MouseEvent) {} +func (item *completionEntryListItem) MouseOut() {} diff --git a/widget/completionentry_test.go b/widget/completionentry_test.go index 587232d0..7df3256b 100644 --- a/widget/completionentry_test.go +++ b/widget/completionentry_test.go @@ -40,17 +40,19 @@ func TestCompletionEntry_Custom(t *testing.T) { } entry.CustomUpdate = func(id widget.ListItemID, o fyne.CanvasObject) { o.(*widget.Check).Text = entryData[id] - o.Refresh() + // o.Refresh() // no need to refresh, completionEntryListItem is refreshed after CustomUpdate } win := test.NewWindow(entry) win.Resize(fyne.NewSize(500, 300)) defer win.Close() entry.SetText("init") - scroll := test.WidgetRenderer(entry.navigableList).Objects()[0].(fyne.Widget) + scroll := test.WidgetRenderer(entry.list).Objects()[0].(fyne.Widget) list := test.WidgetRenderer(scroll).Objects()[0].(*fyne.Container).Objects[1].(fyne.Widget) item1 := test.WidgetRenderer(list).Objects()[1] - assert.Equal(t, "bar", item1.(*widget.Check).Text) // ensure the item is a Check not Label + + // custom items are "budled" in completionEntryListItem + assert.Equal(t, "bar", item1.(*completionEntryListItem).co.(*widget.Check).Text) // ensure the item is a Check not Label } // Show the completion menu @@ -61,7 +63,7 @@ func TestCompletionEntry_ShowMenu(t *testing.T) { defer win.Close() entry.SetText("init") - assert.True(t, entry.popupMenu.Visible()) + assert.True(t, entry.popup.Visible()) } // Navigate in menu and select an entry. @@ -75,12 +77,13 @@ func TestCompletionEntry_Navigate(t *testing.T) { // navigate to "bar" and press enter, the entry should contain // "bar" in value - win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyDown}) + // Note: only one keypress because first item is already selected + // on list show win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyDown}) win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyReturn}) assert.Equal(t, "bar", entry.Text) - assert.False(t, entry.popupMenu.Visible()) + assert.False(t, entry.popup.Visible()) } // Ensure the cursor is set to the end of entry after completion. @@ -118,7 +121,7 @@ func TestCompletionEntry_Escape(t *testing.T) { win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyDown}) win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyEscape}) - assert.False(t, entry.popupMenu.Visible()) + assert.False(t, entry.popup.Visible()) } // Hide the menu on rune pressed. @@ -141,7 +144,7 @@ func TestCompletionEntry_Rune(t *testing.T) { win.Canvas().Focused().TypedRune('z') assert.Equal(t, "foobarxyz", entry.Text) - assert.True(t, entry.popupMenu.Visible()) + assert.True(t, entry.popup.Visible()) } // Hide the menu on rune pressed. @@ -159,11 +162,11 @@ func TestCompletionEntry_Rotation(t *testing.T) { win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyDown}) } - assert.Equal(t, 0, entry.navigableList.selected) + assert.Equal(t, 0, entry.selected) // Do the same in reverse order, here, onlh one time to go on the last item win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyUp}) - assert.Equal(t, len(entry.Options)-1, entry.navigableList.selected) + assert.Equal(t, len(entry.Options)-1, entry.selected) } // Test if completion is hidden when there is no options. @@ -179,7 +182,7 @@ func TestCompletionEntry_WithEmptyOptions(t *testing.T) { } entry.SetText("foo") - assert.Nil(t, entry.popupMenu) // popupMenu should not being created + assert.Nil(t, entry.popup) // popup should not being created } // Test sumbission with opened completion. @@ -193,12 +196,18 @@ func TestCompletionEntry_OnSubmit(t *testing.T) { entry.OnSubmitted = func(s string) { submitted = true entry.HideCompletion() - assert.True(t, entry.popupMenu.Hidden) + assert.True(t, entry.popup.Hidden) } entry.OnChanged = func(s string) { entry.ShowCompletion() } + entry.SetText("foo") + win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyReturn}) + assert.False(t, submitted) + + entry.SubmitOnCompleted = true + entry.SetText("foo") win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyReturn}) assert.True(t, submitted) @@ -225,7 +234,7 @@ func TestCompletionEntry_DoubleSubmissionIssue(t *testing.T) { assert.False(t, submitted) win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyReturn}) // OnSubmitted should NOT be called assert.False(t, submitted) - assert.False(t, entry.popupMenu.Visible()) + assert.False(t, entry.popup.Visible()) win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyReturn}) // OnSubmitted should be called assert.True(t, submitted) } From 2fa106ede6c17c00a1137f3c0daf6b5f25de7a6e Mon Sep 17 00:00:00 2001 From: Samy A Date: Sat, 27 May 2023 11:37:35 +0100 Subject: [PATCH 2/3] go.mod path --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4170607f..4cfd7a26 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module fyne.io/x/fyne +module github.com/matwachich/fyne-x go 1.14 From a31aaacfe09117617bf7bb9bee017d334b6163f2 Mon Sep 17 00:00:00 2001 From: Samy A Date: Wed, 14 Jun 2023 11:34:08 +0100 Subject: [PATCH 3/3] Rotation test pass Removed desktop-only features (select on hover) --- go.mod | 4 ++-- go.sum | 8 ++++---- widget/completionentry.go | 6 +----- widget/completionentry_test.go | 7 ++++--- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 4cfd7a26..d9d0984e 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ -module github.com/matwachich/fyne-x +module fyne.io/x/fyne go 1.14 require ( - fyne.io/fyne/v2 v2.3.4 + fyne.io/fyne/v2 v2.3.5 github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84 github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index a6007ab5..ae05fb41 100644 --- a/go.sum +++ b/go.sum @@ -37,10 +37,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -fyne.io/fyne/v2 v2.3.4 h1:CL8LBUoct2K3EF7Q7NdcDrDMcb3OrNJTghLYTFF400Q= -fyne.io/fyne/v2 v2.3.4/go.mod h1:X2+NrR+62mvAiAt2fwKT7035zQsE77KVV1NlvWo4vW8= -fyne.io/systray v1.10.1-0.20230403195833-7dc3c09283d6 h1:lHt8dm97Uy9ggtnt9N6XOlsp76wXmRAh3SjReWm1e2Q= -fyne.io/systray v1.10.1-0.20230403195833-7dc3c09283d6/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= +fyne.io/fyne/v2 v2.3.5 h1:Q8WOtsms+esLrBKJGdj6P+klu+UXzRq63uPxFSQm4nc= +fyne.io/fyne/v2 v2.3.5/go.mod h1:fbrL+kwOQ6sdVhnURktTHIRIEXwysQSLeejyFyABmNI= +fyne.io/systray v1.10.1-0.20230602210930-b6a2d6ca2a7b h1:MP1cUnIdF1cxrMhK9iw9H0JP3zopyD1zi84BqU6WTsE= +fyne.io/systray v1.10.1-0.20230602210930-b6a2d6ca2a7b/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84 h1:L2C3QKBQwuHuiKwaBj8HDs2r0bAUGqtBYe3ymG0S6Z4= github.com/Andrew-M-C/go.jsonvalue v1.1.2-0.20211223013816-e873b56b4a84/go.mod h1:oTJGG91FhtsxvUFVwHSvr6zuaTcAuroj/ToxfT7Ox8U= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/widget/completionentry.go b/widget/completionentry.go index 559d323a..942175ad 100644 --- a/widget/completionentry.go +++ b/widget/completionentry.go @@ -2,7 +2,6 @@ package widget import ( "fyne.io/fyne/v2" - "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -262,9 +261,6 @@ func (item *completionEntryListItem) CreateRenderer() fyne.WidgetRenderer { } func (item *completionEntryListItem) Tapped(_ *fyne.PointEvent) { + item.parent.list.Select(item.id) item.parent.setTextFromMenu(item.parent.Options[item.id]) } - -func (item *completionEntryListItem) MouseIn(_ *desktop.MouseEvent) { item.parent.list.Select(item.id) } -func (item *completionEntryListItem) MouseMoved(_ *desktop.MouseEvent) {} -func (item *completionEntryListItem) MouseOut() {} diff --git a/widget/completionentry_test.go b/widget/completionentry_test.go index 7df3256b..f142e270 100644 --- a/widget/completionentry_test.go +++ b/widget/completionentry_test.go @@ -157,14 +157,15 @@ func TestCompletionEntry_Rotation(t *testing.T) { entry.SetText("foobar") entry.CursorColumn = 6 // place the cursor after the text - // loop one time (nb items + 1) to go back to the first element - for i := 0; i <= len(entry.Options); i++ { + // loop one time (nb items) to go back to the first elements + // (don't forget that first item is selected on list display) + for i := 0; i < len(entry.Options); i++ { win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyDown}) } assert.Equal(t, 0, entry.selected) - // Do the same in reverse order, here, onlh one time to go on the last item + // Do the same in reverse order, here, only one time to go on the last item win.Canvas().Focused().TypedKey(&fyne.KeyEvent{Name: fyne.KeyUp}) assert.Equal(t, len(entry.Options)-1, entry.selected) }