// Spike: prove that a Plan 9 GUI can be written in Go with nothing but the // standard library -- no C, no cgo, no libdraw, no window system. // // Draws a panel layout and a cursor block that tracks the mouse. // Button 3 quits; so does the deadline, so a forgotten instance on a VM // does not sit on /dev/draw forever. package main import ( "fmt" "os" "time" "9front/gui/draw" ) func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "spike: %v\n", err) os.Exit(1) } } func run() error { d, err := draw.Init("/dev") if err != nil { return err } defer d.Close() if d.Screen == nil { return fmt.Errorf("draw device gave no screen image") } scr := d.Screen r := scr.Rect() fmt.Fprintf(os.Stderr, "spike: screen %dx%d\n", r.Dx(), r.Dy()) col := map[string]uint32{} img := map[string]*draw.Image{} for name, v := range map[string]uint32{ "bg": 0x2B3A42FF, "panel": 0x3F5765FF, "accent": 0xBDD4DEFF, "hot": 0xEFA00BFF, } { col[name] = v if img[name], err = d.Color(v); err != nil { return err } } // Static layout: a header bar and three panels, laid out by arithmetic // rather than by hand-placed constants. This is the seam where a real // layout pass would go. repaint := func() { draw.Draw(scr, r, img["bg"], nil, draw.ZP) hdr := draw.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+40) draw.Draw(scr, hdr, img["accent"], nil, draw.ZP) const gap = 12 top := r.Min.Y + 40 + gap w := (r.Dx() - 4*gap) / 3 for i := int32(0); i < 3; i++ { x := r.Min.X + gap + i*(w+gap) p := draw.Rect(x, top, x+w, r.Max.Y-gap) draw.Draw(scr, p, img["panel"], nil, draw.ZP) } } repaint() d.Flush() mc, err := draw.OpenMouse("/dev") if err != nil { return err } defer mc.Close() deadline := time.After(10 * time.Minute) cursor := draw.Rect(0, 0, 28, 28) var last draw.Rectangle for { select { case m, ok := <-mc.C: if !ok { return nil } if m.Buttons&4 != 0 { return nil } // Damage repair without a full repaint: erase where the // block was, then draw it where the mouse is now. if last != (draw.Rectangle{}) { repaint() } now := cursor.Add(draw.Point{X: m.X - 14, Y: m.Y - 14}) draw.Draw(scr, now, img["hot"], nil, draw.ZP) d.Flush() last = now case <-mc.Resize: r = scr.Rect() repaint() d.Flush() case <-deadline: return nil } } }