Files
silver_pose/v2/cmd/gio-spike/main.go
T
ilaandClaude Opus 4.8 43ec154075 feat(v2): Gio UI spike, cross-compiles CGo-free for Windows
Adds cmd/gio-spike: a minimal Gio window (dual tabs, an *image.RGBA video
area, start/stop) that avoids the Walk TTM_ADDTOOL/comctl manifest problem
entirely. Verified via GOOS=windows CGO_ENABLED=0 go build (11MB single
exe). Windows visual smoke pending. Existing Walk ui-spike left untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 08:45:21 +08:00

160 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Command gio-spike validates a Gio window for the V2 UI, bypassing the Walk
// TTM_ADDTOOL startup failure (Gio uses no Win32 common controls, so the
// manifest/comctl issue cannot occur). It shows a synthetic RGBA frame — the
// same *image.RGBA type internal/render produces — a top dual-tab bar and a
// start/stop button, then closes cleanly.
//
// Run on Windows: go run ./cmd/gio-spike
package main
import (
"image"
"image/color"
"log"
"os"
"gioui.org/app"
"gioui.org/font/gofont"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
)
func main() {
go func() {
w := new(app.Window)
w.Option(
app.Title("Silver Pose V2 · Gio Spike"),
app.Size(unit.Dp(960), unit.Dp(600)),
)
if err := loop(w); err != nil {
log.Fatal(err)
}
os.Exit(0)
}()
app.Main()
}
type spikeUI struct {
theme *material.Theme
frame paint.ImageOp
tabs []string
tabButton []widget.Clickable
active int
startStop widget.Clickable
running bool
}
func newSpikeUI() *spikeUI {
theme := material.NewTheme()
theme.Shaper = text.NewShaper(text.WithCollection(gofont.Collection()))
ui := &spikeUI{
theme: theme,
frame: paint.NewImageOp(syntheticFrame(640, 360)),
tabs: []string{"实时监控", "设置"},
}
ui.tabButton = make([]widget.Clickable, len(ui.tabs))
return ui
}
func loop(w *app.Window) error {
ui := newSpikeUI()
var ops op.Ops
for {
switch e := w.Event().(type) {
case app.DestroyEvent:
return e.Err
case app.FrameEvent:
gtx := app.NewContext(&ops, e)
ui.layout(gtx)
e.Frame(gtx.Ops)
}
}
}
func (ui *spikeUI) layout(gtx layout.Context) layout.Dimensions {
paint.Fill(gtx.Ops, color.NRGBA{R: 0xEA, G: 0xF1, B: 0xF8, A: 0xFF})
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(ui.layoutTabs),
layout.Flexed(1, ui.layoutBody),
layout.Rigid(ui.layoutControls),
)
}
func (ui *spikeUI) layoutTabs(gtx layout.Context) layout.Dimensions {
for i := range ui.tabButton {
if ui.tabButton[i].Clicked(gtx) {
ui.active = i
}
}
children := make([]layout.FlexChild, 0, len(ui.tabs))
for i := range ui.tabs {
i := i
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
button := material.Button(ui.theme, &ui.tabButton[i], ui.tabs[i])
if i != ui.active {
button.Background = color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}
button.Color = color.NRGBA{R: 0x52, G: 0x65, B: 0x7C, A: 0xFF}
}
return layout.UniformInset(unit.Dp(6)).Layout(gtx, button.Layout)
}))
}
return layout.Flex{}.Layout(gtx, children...)
}
func (ui *spikeUI) layoutBody(gtx layout.Context) layout.Dimensions {
if ui.active == 0 {
return layout.UniformInset(unit.Dp(8)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return widget.Image{
Src: ui.frame,
Fit: widget.Contain,
Position: layout.Center,
}.Layout(gtx)
})
}
return layout.Center.Layout(gtx, material.Body1(ui.theme, "设置页占位(spike)").Layout)
}
func (ui *spikeUI) layoutControls(gtx layout.Context) layout.Dimensions {
if ui.startStop.Clicked(gtx) {
ui.running = !ui.running
}
label := "开始监控"
if ui.running {
label = "停止监控"
}
return layout.UniformInset(unit.Dp(8)).Layout(gtx, material.Button(ui.theme, &ui.startStop, label).Layout)
}
// syntheticFrame stands in for internal/render's *image.RGBA output: a gradient
// with a 6px red border, mimicking a CONFIRMED overlay, to prove image display.
func syntheticFrame(width, height int) *image.RGBA {
img := image.NewRGBA(image.Rect(0, 0, width, height))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
img.SetRGBA(x, y, color.RGBA{
R: uint8(x * 255 / width),
G: uint8(y * 255 / height),
B: 90,
A: 255,
})
}
}
red := color.RGBA{R: 198, G: 40, B: 40, A: 255}
for t := 0; t < 6; t++ {
for x := 0; x < width; x++ {
img.SetRGBA(x, t, red)
img.SetRGBA(x, height-1-t, red)
}
for y := 0; y < height; y++ {
img.SetRGBA(t, y, red)
img.SetRGBA(width-1-t, y, red)
}
}
return img
}