| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package widget |
| |
| import ( |
| "image" |
| |
| "golang.org/x/exp/shiny/screen" |
| "golang.org/x/exp/shiny/unit" |
| "golang.org/x/mobile/event/lifecycle" |
| "golang.org/x/mobile/event/paint" |
| "golang.org/x/mobile/event/size" |
| ) |
| |
| // TODO: how does RunWindow's caller inject or process events (whether general |
| // like lifecycle events or app-specific)? How does it stop the event loop when |
| // the app's work is done? |
| |
| // TODO: how do widgets signal that they need repaint or relayout? |
| |
| // TODO: propagate keyboard / mouse / touch events. |
| |
| // RunWindow creates a new window for s, with the given widget tree, and runs |
| // its event loop. |
| func RunWindow(s screen.Screen, root *Node) error { |
| var ( |
| buf screen.Buffer |
| t Theme |
| ) |
| defer func() { |
| if buf != nil { |
| buf.Release() |
| } |
| }() |
| |
| w, err := s.NewWindow(nil) |
| if err != nil { |
| return err |
| } |
| defer w.Release() |
| for { |
| switch e := w.NextEvent().(type) { |
| case lifecycle.Event: |
| if e.To == lifecycle.StageDead { |
| return nil |
| } |
| |
| case paint.Event: |
| if buf != nil { |
| w.Upload(image.Point{}, buf, buf.Bounds()) |
| } |
| w.Publish() |
| |
| case size.Event: |
| if buf != nil { |
| buf.Release() |
| } |
| var err error |
| buf, err = s.NewBuffer(e.Size()) |
| if err != nil { |
| return err |
| } |
| t.DPI = float64(e.PixelsPerPt) * unit.PointsPerInch |
| root.Measure(&t) |
| root.Rect = e.Bounds() |
| root.Layout(&t) |
| root.Paint(&t, buf.RGBA(), image.Point{}) |
| |
| case error: |
| return e |
| } |
| } |
| } |