From 9737782ecc3865edcaf6a8d5248bc82a5bc831ea Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 6 Sep 2026 10:17:26 +0200 Subject: [PATCH] gallery: a native-controls page mirroring the wasm demo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wasm gallery shows the toolkit's drawn widgets; this adds its native mirror — one toolkit.NativeControl descriptor per NativeKind (all nineteen: button, label, entry, secure, checkbox, radio, switch, slider, pop-up, progress, spinner, stepper, search, editable combo, segmented, multi-line text view, link, date, colour), hosted by go-widgets/window's cocoa/win32/gtk back-end as real OS controls over the framebuffer, pure Go CGO=0. native.go builds the descriptor grid (tag-less, 100%-tested); native_main.go opens the window behind the 'gallerynative' build tag so the wasm build and the coverage-gated tests never pull in the windowing stack. Proven on Linux GTK4 under Xvfb — every control renders as its GTK widget. Adds go-widgets/window; CI gains a native build smoke. --- .github/workflows/ci.yml | 5 +++ README.md | 19 +++++++++ go.mod | 13 +++++- go.sum | 48 +++++++++++----------- native.go | 86 ++++++++++++++++++++++++++++++++++++++++ native_main.go | 34 ++++++++++++++++ native_test.go | 56 ++++++++++++++++++++++++++ 7 files changed, 235 insertions(+), 26 deletions(-) create mode 100644 native.go create mode 100644 native_main.go create mode 100644 native_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8de5ab..be206cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,3 +50,8 @@ jobs: GOOS: js GOARCH: wasm run: go build -o /tmp/gallery.wasm . + + - name: Native gallery build smoke (all NativeKinds over go-widgets/window) + env: + CGO_ENABLED: "0" + run: go build -tags gallerynative -o /tmp/gallery-native . diff --git a/README.md b/README.md index 1092161..e52ab1f 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,25 @@ SharedArrayBuffer, no COOP/COEP, no server-side dep. That makes it easy to iframe from any static host (`python3 -m http.server`, GitHub Pages, S3, ...). +## Native controls gallery + +The wasm page above shows the toolkit's **drawn** widgets. Its native +mirror shows the same widget set as the **platform's own controls** — +one `toolkit.NativeControl` descriptor per `NativeKind`, hosted by +`go-widgets/window`'s cocoa / win32 / gtk back-end (real +`NSButton`/`GtkEntry`/… over the framebuffer), pure Go, `CGO_ENABLED=0`. + +```text +go build -tags gallerynative -o gallery-native . +./gallery-native # macOS / Windows +GO_WIDGETS_GTK=1 ./gallery-native # Linux (GTK4-hosted back-end) +``` + +`native.go` builds the descriptor grid (tag-less, 100%-tested); +`native_main.go` (behind the `gallerynative` tag, so the wasm build and +the coverage-gated tests never pull in the windowing stack) opens the +window and runs it. + ## Layout `scene.go` composes widgets from the toolkit onto a **960-wide** diff --git a/go.mod b/go.mod index 47a78b6..fd94cfb 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,9 @@ require ( github.com/go-widgets/isoicons v0.1.0 github.com/go-widgets/mvvm v0.9.0 github.com/go-widgets/painter v0.12.0 - github.com/go-widgets/toolkit v0.301.0 + github.com/go-widgets/toolkit v0.306.0 github.com/go-widgets/webcanvas v0.1.0 + github.com/go-widgets/window v0.70.0 ) require ( @@ -17,14 +18,22 @@ require ( github.com/ajroetker/go-jpeg2000 v0.0.2 // indirect github.com/andybalholm/brotli v1.2.3 // indirect github.com/coder/websocket v1.8.15 // indirect - github.com/go-crdt/collab v0.37.0 // indirect + github.com/ebitengine/purego v0.11.0 // indirect + github.com/go-crdt/collab v0.40.0 // indirect + github.com/go-freedesktop/x11 v0.2.0 // indirect + github.com/go-gtk/gtk4 v0.5.0 // indirect github.com/go-icons/iconoir v0.2.0 // indirect github.com/go-images/images v0.0.0-20260831115433-23d959d868e3 // indirect + github.com/go-macos/appkit v0.5.0 // indirect + github.com/go-macos/objc v0.9.1 // indirect + github.com/go-mswin/win32 v0.4.0 // indirect github.com/go-opentype/fonts v0.9.0 // indirect github.com/go-opentype/opentype v0.12.0 // indirect github.com/go-opentype/shape v0.5.0 // indirect github.com/go-richdoc/richdoc v0.3.0 // indirect github.com/go-typeset/bidi v0.3.0 // indirect + github.com/go-widgets/android v0.13.1 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/sergeymakinen/go-bmp v1.0.0 // indirect github.com/sergeymakinen/go-ico v1.0.0 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect diff --git a/go.sum b/go.sum index e167a7b..683fd6d 100644 --- a/go.sum +++ b/go.sum @@ -8,60 +8,60 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coder/websocket v1.8.15 h1:6B2JPeOGlpff2Uz6vOEH1Vzpi0iUz20A+lPVhPHtNUA= github.com/coder/websocket v1.8.15/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/go-crdt/collab v0.36.1 h1:2NTn1iKFoUHnNSeD2hAyy+8bCnpeUI57W7yQ1CY5bko= -github.com/go-crdt/collab v0.36.1/go.mod h1:CNtopa+kzRg3jfb2bES9+rEIavVrb52IbDcfVV05+6E= -github.com/go-crdt/collab v0.37.0 h1:tLtDqao5GODY2pxE/wcEA8U9I/rPdN4LvjEPeE4/QwA= -github.com/go-crdt/collab v0.37.0/go.mod h1:kxTeZDZ6p8wC9gEkf2iWgFg2870lYliHJyCC6vDlsAs= -github.com/go-crdt/crdt v0.37.0 h1:offp5UlAqIt2lQwvWamguRBWp6yZs4uUhVISfqw2+l0= -github.com/go-crdt/crdt v0.37.0/go.mod h1:vbfvns9B9FUaMi2sPKzMYttKmbxfgO7EK3Yu82SrlYw= -github.com/go-crdt/crdt v0.39.0 h1:DJimBDQqmdqKVCAiU4k1aCWPgXeZ+id/FbO09DklTBw= -github.com/go-crdt/crdt v0.39.0/go.mod h1:vbfvns9B9FUaMi2sPKzMYttKmbxfgO7EK3Yu82SrlYw= +github.com/ebitengine/purego v0.11.0 h1:jhp/D+Nyv7UUW8HAcmcjt2N2rYrYi9m3SL21k0Ua/NI= +github.com/ebitengine/purego v0.11.0/go.mod h1:DCHPP08djqhNSoTfImcnHYQRZmd0qhakvrozqaEYhGQ= +github.com/go-crdt/collab v0.40.0 h1:/LfqtwoiQKBHOZMoF9NfQj19GQRkXFzfn3XTDry4o5I= +github.com/go-crdt/collab v0.40.0/go.mod h1:524ptwB8GQti5cZwMsaNaG2nQv+4XykUnE35Z6lN4f0= github.com/go-crdt/crdt v0.42.0 h1:L2+yvKjs3RgagncbU6JAkBnRz6wVylNynkzntL5pKpQ= github.com/go-crdt/crdt v0.42.0/go.mod h1:vbfvns9B9FUaMi2sPKzMYttKmbxfgO7EK3Yu82SrlYw= +github.com/go-freedesktop/x11 v0.2.0 h1:qHvov5jn7GG4QxeealqRJVj72/MjR5qi2IXqyD7N02A= +github.com/go-freedesktop/x11 v0.2.0/go.mod h1:a+Fma9oOlsagw0CJKe+VHYxIl5/PzPSmlCVaYCtUSYA= github.com/go-gfx/gfx v0.19.0 h1:nA2Eg8Aq2kytR5Hrm/eQ6618w4vT0+Ao8BMZiuYh84c= github.com/go-gfx/gfx v0.19.0/go.mod h1:VAK6hgCgkhT3j3ek2K7G8zDfkCPD3RCF45UbcRlCV8Q= +github.com/go-gtk/gtk4 v0.5.0 h1:97/WDULZ3cVIYldSIPT9FV7GBkEf4cOMunF7nsIODNk= +github.com/go-gtk/gtk4 v0.5.0/go.mod h1:jjaA29sFQTpy2D3N+FrnxMFZq07mG48ahgQoEEECpPA= github.com/go-icons/iconoir v0.2.0 h1:I5AnDEIPgYfawTmwzemDRJjlYCUbFHuS8GJXrjADhXc= github.com/go-icons/iconoir v0.2.0/go.mod h1:Td/M2vy4xdVv4aOudAskV0nXR9Wv0MlhWvyRIzPBz5U= -github.com/go-images/images v0.0.0-20260815210351-4a50ef5ab734 h1:nU+MGeyJzidGvCtx+HLZgHKG9GpUUomkQvB5nXLRWoc= -github.com/go-images/images v0.0.0-20260815210351-4a50ef5ab734/go.mod h1:ObuOBKDEidGX0LqLKY/5nqj7JVN/hsCzHMAJd0TNc0k= -github.com/go-images/images v0.0.0-20260830151046-7e8189dc2288 h1:+ljs5FdeIrwsVzMdH43o72xjzBIc8ZJ/gnW6KK0tRrw= -github.com/go-images/images v0.0.0-20260830151046-7e8189dc2288/go.mod h1:Rz3bjq22JH21J8ipYRVLsJCB7QAEDjfHnxR7JCOmc54= github.com/go-images/images v0.0.0-20260831115433-23d959d868e3 h1:SinmtXWpA4a30ZQ5A9QI9YrsYvytmLGeTRVbXqqEezw= github.com/go-images/images v0.0.0-20260831115433-23d959d868e3/go.mod h1:Epqq+oFyfwKIS4zmrr12eZVtCuwXhoxV6E+OBEnNsFs= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-opentype/fonts v0.6.0 h1:pUKITjwC/gZg+XNCqP5eGLi8RHu2RAIcDrr6yp1VKMU= -github.com/go-opentype/fonts v0.6.0/go.mod h1:C6yQL2apHItfEZ5hztpsHF0S5mlX/hklLlq/Z5fRG/g= +github.com/go-macos/appkit v0.5.0 h1:4LeIstgHaKcoTk4Eb0qFoHmUVa7arW1NNZAO8VLJtfQ= +github.com/go-macos/appkit v0.5.0/go.mod h1:KQ+vIsZ2hBFniqFJ5Q4uQ4ylQX+MXPvJcMOzvBpJRdE= +github.com/go-macos/objc v0.9.1 h1:GGBoj8aMijBCYNPjGAYS4neeA3lWa8/JEIF1K5GswDo= +github.com/go-macos/objc v0.9.1/go.mod h1:00GJyieLzPcb65rPLVWNPPUCVm79nmmiEXUDsslRpOs= +github.com/go-macos/virtualdisplay v0.3.0 h1:OWo8bGaXWEGutoGHO/RV9qO5Lzfe1hFx2aXNocZ4bHI= +github.com/go-macos/virtualdisplay v0.3.0/go.mod h1:68/38e3PlQ3cwK7du2wflPaNan+DQqKz7Hhi89uo6gg= +github.com/go-mswin/win32 v0.4.0 h1:0JAvm3XNMxOyfYX1anbtAqxNvxvUA0DZ1SyAUinhMa0= +github.com/go-mswin/win32 v0.4.0/go.mod h1:ypmW4zosl3mXhy0O39EDbHk+AUjgaXGyFgY5UpX3AxI= github.com/go-opentype/fonts v0.9.0 h1:slB6OB3riLyUPrOxqXe0s6/AzdenF1TDvCN8N87hhQk= github.com/go-opentype/fonts v0.9.0/go.mod h1:C6yQL2apHItfEZ5hztpsHF0S5mlX/hklLlq/Z5fRG/g= -github.com/go-opentype/opentype v0.5.0 h1:++VoqgbXgYACyTTNzUAivoxW9M3m2gxWMAn6bIY7DXg= -github.com/go-opentype/opentype v0.5.0/go.mod h1:AOixevJf7XQaH7+WG+OMIOZEbYPXfMqklVk26Y6YTUU= github.com/go-opentype/opentype v0.12.0 h1:wBlcDi+3ZaNZXEt5z+Ixr11/cYYwi5W+jX6yTl/qr1I= github.com/go-opentype/opentype v0.12.0/go.mod h1:AOixevJf7XQaH7+WG+OMIOZEbYPXfMqklVk26Y6YTUU= github.com/go-opentype/shape v0.5.0 h1:jHNaOMHNBdDj5EixOevlrrsi92svMxvVMKN7GYaPfxo= github.com/go-opentype/shape v0.5.0/go.mod h1:3ImRYNIj6zpwWQ/DV3BWhgMFfmzDITH6XpZw2auQHTo= -github.com/go-richdoc/richdoc v0.2.0 h1:z9cLox9MoInZL6fIlweMzgDT/VqgnB2ZucSIEaRFglY= -github.com/go-richdoc/richdoc v0.2.0/go.mod h1:aCX8ulqg5CoKqSWgWeEWul1Oj0d2VxQeaQNI0+jsm7c= github.com/go-richdoc/richdoc v0.3.0 h1:BPUHZ0NUrmDVffs2jJcj6ur8mqlccZpZVpCOsuQT9gQ= github.com/go-richdoc/richdoc v0.3.0/go.mod h1:aCX8ulqg5CoKqSWgWeEWul1Oj0d2VxQeaQNI0+jsm7c= github.com/go-typeset/bidi v0.3.0 h1:4fjGjejvjE2LzLNzY4si8PkVO321NcsKIiANhWT3jF4= github.com/go-typeset/bidi v0.3.0/go.mod h1:ct3cmYT8Qt1FGJQ+2QaakrUxqaP4ZysgdQQg2ym5+Xo= +github.com/go-widgets/android v0.13.1 h1:lo51C5xjTEceNxK2eUDOlpWIFi+LKS5XpKMNjnJns+U= +github.com/go-widgets/android v0.13.1/go.mod h1:MsEBpJyEUhmq4yKPXIMMf+BX21NWAPQW9lfU0deDR+g= github.com/go-widgets/isoicons v0.1.0 h1:j4rwOVN9VIGqoT7w8O06x3TmqZNDGIqsk9IDIxmaCVg= github.com/go-widgets/isoicons v0.1.0/go.mod h1:hq3O6KyyNI8y7aPoMdCRuWoj7t8LINuMvgSr1EPsaWE= github.com/go-widgets/mvvm v0.9.0 h1:NwW/hAAsJUGlxmNt0ErQ7fUrud3w5Ys1RWm7hVugdJs= github.com/go-widgets/mvvm v0.9.0/go.mod h1:1cUYVpDei59Ka7W3pMD1FWksBmBXfPnbPWHzBAJ/ebA= github.com/go-widgets/painter v0.12.0 h1:gMqTVbIbGSKmaE28NKsbbKdNIk2drupNMNuLjFP6T6I= github.com/go-widgets/painter v0.12.0/go.mod h1:IPRLqdUJuJX8sfuHeYLZCzjoLvA0ApbOlyIAVmguJDQ= -github.com/go-widgets/toolkit v0.298.0 h1:Gx6F6PdqWnG9suXGEPm5I3LhlFwli+2yeeiG/y1jGkA= -github.com/go-widgets/toolkit v0.298.0/go.mod h1:oQuOK+iE7Dc1xG1EXsBeO5Kjdf+091uIZSVu3AVLXwc= -github.com/go-widgets/toolkit v0.300.0 h1:vyQ6oN/XsfUPo/WYzrjD5AIFPEj1X1OVaJd7yihmxJk= -github.com/go-widgets/toolkit v0.300.0/go.mod h1:5G/reoXwETtl6LJGB56471Sqv6keCIYVkhx/bvFPB+g= -github.com/go-widgets/toolkit v0.301.0 h1:ymKltlmsMiMIHDObIiljo2umNF+ArbTmLD/Dg/9AYNw= -github.com/go-widgets/toolkit v0.301.0/go.mod h1:NMj7CghnZKC+L9BRaAcKjykewTChSFuuTuVH+2wDjV4= +github.com/go-widgets/toolkit v0.306.0 h1:QKNFcxLK2ZwI+TxMCXZwwRBWqtNrc+tnI0fktXuuQLw= +github.com/go-widgets/toolkit v0.306.0/go.mod h1:tpn/Pcd+kra6UnIe8LPwaZWYQaCvvatYXrbuMJyoBfc= github.com/go-widgets/webcanvas v0.1.0 h1:fSGllghHlFZSC7CBb1oetj/PKR/S3ds/piDrpr0Kmg0= github.com/go-widgets/webcanvas v0.1.0/go.mod h1:UAoPu9dO6ZzcFFwQbVeW4Jm4X67XFKVJab9A6qWwsMM= +github.com/go-widgets/window v0.70.0 h1:ix9TAmEmCt+PvsYscrZiQm20l2KcT65QnQZ/U3Yav/4= +github.com/go-widgets/window v0.70.0/go.mod h1:DGE3u3flDSWvDZiZhwqLz3IEV9kKq0Tjj8cdFD9CrQo= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= diff --git a/native.go b/native.go new file mode 100644 index 0000000..716f42f --- /dev/null +++ b/native.go @@ -0,0 +1,86 @@ +// Copyright (c) 2026 the go-widgets/gallery authors. All rights reserved. +// Use of this source code is governed by a BSD-3-Clause license that can be +// found in the LICENSE file at the root of this repository. + +// This file (tag-less, so it is compiled and 100%-tested natively) builds the +// NATIVE-controls page of the gallery: one descriptor per platform control the +// go-widgets native-control seam offers. A native host (go-widgets/window's +// cocoa / win32 / gtk back-end — see native_main.go) turns each into a REAL OS +// widget over the framebuffer, so the gallery shows the same widget set the wasm +// demo draws, but as the platform's own controls. The wasm page stays the drawn +// toolkit; this page is its native mirror. +package main + +import "github.com/go-widgets/toolkit" + +// nativeW, nativeH are the native gallery's logical window size. +const nativeW, nativeH = 780, 680 + +// galleryControl describes one showcased control by value; nativeControls turns +// it into a positioned descriptor. Data, not closures, so every field is covered +// by one pass. +type galleryControl struct { + name string + kind toolkit.NativeKind + text string + on bool + num float64 + min float64 + max float64 + items []string +} + +// galleryControls is the showcased set: every NativeKind, in reading order. +var galleryControls = []galleryControl{ + {name: "Button", kind: toolkit.NativeButton, text: "Click me"}, + {name: "Label", kind: toolkit.NativeLabel, text: "A static label"}, + {name: "Entry", kind: toolkit.NativeEntry, text: "editable"}, + {name: "SecureEntry", kind: toolkit.NativeSecureEntry, text: "secret"}, + {name: "Checkbox", kind: toolkit.NativeCheckbox, text: "on", on: true}, + {name: "Radio", kind: toolkit.NativeRadio, text: "choice", on: true}, + {name: "Switch", kind: toolkit.NativeSwitch, on: true}, + {name: "Slider", kind: toolkit.NativeSlider, min: 0, max: 100, num: 50}, + {name: "PopUp", kind: toolkit.NativePopUp, items: []string{"One", "Two", "Three"}, text: "Two"}, + {name: "Progress", kind: toolkit.NativeProgress, min: 0, max: 100, num: 65}, + {name: "Spinner", kind: toolkit.NativeSpinner, on: true}, + {name: "Stepper", kind: toolkit.NativeStepper, min: 0, max: 10, num: 4}, + {name: "Search", kind: toolkit.NativeSearch, text: "search…"}, + {name: "Combo", kind: toolkit.NativeCombo, items: []string{"Alpha", "Beta"}, text: "Alpha"}, + {name: "Segmented", kind: toolkit.NativeSegmented, items: []string{"Day", "Week", "Month"}, text: "Week"}, + {name: "TextView", kind: toolkit.NativeTextView, text: "multi-line\ntext area"}, + {name: "Link", kind: toolkit.NativeLink, text: "a hyperlink"}, + {name: "Date", kind: toolkit.NativeDate, text: "2026-09-01"}, + {name: "Color", kind: toolkit.NativeColor, text: "#3366cc"}, +} + +// nativeControls lays the showcased controls out in two columns, each row a +// caption label beside its control, and returns the flat descriptor list a +// [toolkit.Surface] publishes through its Controls field. +func nativeControls() []toolkit.NativeControl { + const colW, rowH, labelW, ctlW, ctlH, perCol = 380, 62, 110, 210, 30, 10 + out := make([]toolkit.NativeControl, 0, len(galleryControls)*2) + for i, s := range galleryControls { + x := 20 + (i/perCol)*colW + y := 20 + (i%perCol)*rowH + out = append(out, toolkit.NativeControl{ + Kind: toolkit.NativeLabel, Key: "cap:" + s.name, Visible: true, + Text: s.name + ":", Rect: toolkit.Rect{X: x, Y: y + 4, W: labelW, H: ctlH}, + }) + out = append(out, toolkit.NativeControl{ + Kind: s.kind, Key: "ctl:" + s.name, Visible: true, + Text: s.text, On: s.on, Number: s.num, Min: s.min, Max: s.max, Items: s.items, + Rect: toolkit.Rect{X: x + labelW, Y: y, W: ctlW, H: ctlH}, + }) + } + return out +} + +// nativeBackground is the gallery's flat ground, an opaque light RGBA buffer the +// native controls sit over. +func nativeBackground(w, h int) []byte { + buf := make([]byte, w*h*4) + for i := 0; i < len(buf); i += 4 { + buf[i], buf[i+1], buf[i+2], buf[i+3] = 0xf3, 0xf3, 0xf5, 0xff + } + return buf +} diff --git a/native_main.go b/native_main.go new file mode 100644 index 0000000..12636a1 --- /dev/null +++ b/native_main.go @@ -0,0 +1,34 @@ +// Copyright (c) 2026 the go-widgets/gallery authors. All rights reserved. +// Use of this source code is governed by a BSD-3-Clause license that can be +// found in the LICENSE file at the root of this repository. + +//go:build gallerynative + +// Command gallery, built with -tags gallerynative, is the NATIVE-controls +// gallery: a go-widgets/window whose Surface publishes one descriptor per +// NativeKind, so the platform back-end (cocoa / win32 / gtk) shows every control +// as a real OS widget. It is the native mirror of the default wasm demo, kept +// behind a build tag so the wasm build and the coverage-gated native tests never +// pull in the windowing stack. On Linux, run with GO_WIDGETS_GTK=1 for the +// GTK4-hosted back-end. +// +// Build: go build -tags gallerynative -o gallery-native . +package main + +import ( + "github.com/go-widgets/toolkit" + "github.com/go-widgets/window" +) + +func main() { + buf := nativeBackground(nativeW, nativeH) + surf := toolkit.NewSurface(func() ([]byte, int, int) { return buf, nativeW, nativeH }) + surf.Controls = nativeControls + w, err := window.Open(window.Config{Title: "Native Widget Gallery", Width: nativeW, Height: nativeH}) + if err != nil { + panic(err) + } + if err := w.Run(surf); err != nil { + panic(err) + } +} diff --git a/native_test.go b/native_test.go new file mode 100644 index 0000000..746fd69 --- /dev/null +++ b/native_test.go @@ -0,0 +1,56 @@ +// Copyright (c) 2026 the go-widgets/gallery authors. All rights reserved. +// Use of this source code is governed by a BSD-3-Clause license that can be +// found in the LICENSE file at the root of this repository. + +package main + +import ( + "testing" + + "github.com/go-widgets/toolkit" +) + +// TestNativeControls checks the native gallery publishes a caption + a control +// for every showcased kind, positioned and carrying its value. +func TestNativeControls(t *testing.T) { + got := nativeControls() + if want := len(galleryControls) * 2; len(got) != want { + t.Fatalf("descriptor count = %d, want %d (a label + a control each)", len(got), want) + } + byKey := map[string]toolkit.NativeControl{} + for _, c := range got { + byKey[c.Key] = c + if !c.Visible || c.Rect == (toolkit.Rect{}) { + t.Errorf("%s: not visible or unpositioned (%+v)", c.Key, c.Rect) + } + } + // Every kind is present as a control, its caption as a label. + for _, s := range galleryControls { + ctl, ok := byKey["ctl:"+s.name] + if !ok || ctl.Kind != s.kind { + t.Errorf("control %q missing or wrong kind (%v, want %v)", s.name, ctl.Kind, s.kind) + } + cap, ok := byKey["cap:"+s.name] + if !ok || cap.Kind != toolkit.NativeLabel { + t.Errorf("caption for %q missing or not a label", s.name) + } + } + // Spot-check a value carried through. + if byKey["ctl:Slider"].Number != 50 { + t.Errorf("slider Number = %v, want 50", byKey["ctl:Slider"].Number) + } + if byKey["ctl:PopUp"].Text != "Two" { + t.Errorf("pop-up Text = %q, want Two", byKey["ctl:PopUp"].Text) + } +} + +// TestNativeBackground checks the ground buffer is the right size and opaque. +func TestNativeBackground(t *testing.T) { + buf := nativeBackground(4, 3) + if len(buf) != 4*3*4 { + t.Fatalf("background len = %d, want %d", len(buf), 4*3*4) + } + if buf[3] != 0xff { + t.Errorf("background not opaque: alpha = %d", buf[3]) + } +}