Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 .
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down
13 changes: 11 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,32 @@ 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 (
github.com/ajroetker/go-highway v0.0.4 // indirect
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
Expand Down
48 changes: 24 additions & 24 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
86 changes: 86 additions & 0 deletions native.go
Original file line number Diff line number Diff line change
@@ -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
}
34 changes: 34 additions & 0 deletions native_main.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
56 changes: 56 additions & 0 deletions native_test.go
Original file line number Diff line number Diff line change
@@ -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])
}
}