1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// +build example 6// 7// This build tag means that "go install golang.org/x/exp/shiny/..." doesn't 8// install this example program. Use "go run main.go" to run it or "go install 9// -tags=example" to install it. 10 11// Basic is a basic example of a graphical application. 12package main 13 14import ( 15 "fmt" 16 "image" 17 "image/color" 18 "log" 19 "math" 20 21 "golang.org/x/exp/shiny/driver" 22 "golang.org/x/exp/shiny/imageutil" 23 "golang.org/x/exp/shiny/screen" 24 "golang.org/x/image/math/f64" 25 "golang.org/x/mobile/event/key" 26 "golang.org/x/mobile/event/lifecycle" 27 "golang.org/x/mobile/event/paint" 28 "golang.org/x/mobile/event/size" 29) 30 31var ( 32 blue0 = color.RGBA{0x00, 0x00, 0x1f, 0xff} 33 blue1 = color.RGBA{0x00, 0x00, 0x3f, 0xff} 34 darkGray = color.RGBA{0x3f, 0x3f, 0x3f, 0xff} 35 green = color.RGBA{0x00, 0x7f, 0x00, 0x7f} 36 red = color.RGBA{0x7f, 0x00, 0x00, 0x7f} 37 yellow = color.RGBA{0x3f, 0x3f, 0x00, 0x3f} 38 39 cos30 = math.Cos(math.Pi / 6) 40 sin30 = math.Sin(math.Pi / 6) 41) 42 43func main() { 44 driver.Main(func(s screen.Screen) { 45 w, err := s.NewWindow(&screen.NewWindowOptions{ 46 Title: "Basic Shiny Example", 47 }) 48 if err != nil { 49 log.Fatal(err) 50 } 51 defer w.Release() 52 53 size0 := image.Point{256, 256} 54 b, err := s.NewBuffer(size0) 55 if err != nil { 56 log.Fatal(err) 57 } 58 defer b.Release() 59 drawGradient(b.RGBA()) 60 61 t0, err := s.NewTexture(size0) 62 if err != nil { 63 log.Fatal(err) 64 } 65 defer t0.Release() 66 t0.Upload(image.Point{}, b, b.Bounds()) 67 68 size1 := image.Point{32, 20} 69 t1, err := s.NewTexture(size1) 70 if err != nil { 71 log.Fatal(err) 72 } 73 defer t1.Release() 74 t1.Fill(t1.Bounds(), green, screen.Src) 75 t1.Fill(t1.Bounds().Inset(2), red, screen.Over) 76 t1.Fill(t1.Bounds().Inset(4), red, screen.Src) 77 78 var sz size.Event 79 for { 80 e := w.NextEvent() 81 82 // This print message is to help programmers learn what events this 83 // example program generates. A real program shouldn't print such 84 // messages; they're not important to end users. 85 format := "got %#v\n" 86 if _, ok := e.(fmt.Stringer); ok { 87 format = "got %v\n" 88 } 89 fmt.Printf(format, e) 90 91 switch e := e.(type) { 92 case lifecycle.Event: 93 if e.To == lifecycle.StageDead { 94 return 95 } 96 97 case key.Event: 98 if e.Code == key.CodeEscape { 99 return 100 } 101 102 case paint.Event: 103 const inset = 10 104 for _, r := range imageutil.Border(sz.Bounds(), inset) { 105 w.Fill(r, blue0, screen.Src) 106 } 107 w.Fill(sz.Bounds().Inset(inset), blue1, screen.Src) 108 w.Upload(image.Point{20, 0}, b, b.Bounds()) 109 w.Fill(image.Rect(50, 50, 350, 120), red, screen.Over) 110 111 // By default, draw the entirety of the texture using the Over 112 // operator. Uncomment one or both of the lines below to see 113 // their different effects. 114 op := screen.Over 115 // op = screen.Src 116 t0Rect := t0.Bounds() 117 // t0Rect = image.Rect(16, 0, 240, 100) 118 119 // Draw the texture t0 twice, as a 1:1 copy and under the 120 // transform src2dst. 121 w.Copy(image.Point{150, 100}, t0, t0Rect, op, nil) 122 src2dst := f64.Aff3{ 123 +0.5 * cos30, -1.0 * sin30, 100, 124 +0.5 * sin30, +1.0 * cos30, 200, 125 } 126 w.Draw(src2dst, t0, t0Rect, op, nil) 127 w.DrawUniform(src2dst, yellow, t0Rect.Inset(30), screen.Over, nil) 128 129 // Draw crosses at the transformed corners of t0Rect. 130 for _, sx := range []int{t0Rect.Min.X, t0Rect.Max.X} { 131 for _, sy := range []int{t0Rect.Min.Y, t0Rect.Max.Y} { 132 dx := int(src2dst[0]*float64(sx) + src2dst[1]*float64(sy) + src2dst[2]) 133 dy := int(src2dst[3]*float64(sx) + src2dst[4]*float64(sy) + src2dst[5]) 134 w.Fill(image.Rect(dx-0, dy-1, dx+1, dy+2), darkGray, screen.Src) 135 w.Fill(image.Rect(dx-1, dy-0, dx+2, dy+1), darkGray, screen.Src) 136 } 137 } 138 139 // Draw t1. 140 w.Copy(image.Point{400, 50}, t1, t1.Bounds(), screen.Src, nil) 141 142 w.Publish() 143 144 case size.Event: 145 sz = e 146 147 case error: 148 log.Print(e) 149 } 150 } 151 }) 152} 153 154func drawGradient(m *image.RGBA) { 155 b := m.Bounds() 156 for y := b.Min.Y; y < b.Max.Y; y++ { 157 for x := b.Min.X; x < b.Max.X; x++ { 158 if x%64 == 0 || y%64 == 0 { 159 m.SetRGBA(x, y, color.RGBA{0xff, 0xff, 0xff, 0xff}) 160 } else if x%64 == 63 || y%64 == 63 { 161 m.SetRGBA(x, y, color.RGBA{0x00, 0x00, 0xff, 0xff}) 162 } else { 163 m.SetRGBA(x, y, color.RGBA{uint8(x), uint8(y), 0x00, 0xff}) 164 } 165 } 166 } 167 168 // Round off the corners. 169 const radius = 64 170 lox := b.Min.X + radius - 1 171 loy := b.Min.Y + radius - 1 172 hix := b.Max.X - radius 173 hiy := b.Max.Y - radius 174 for y := 0; y < radius; y++ { 175 for x := 0; x < radius; x++ { 176 if x*x+y*y <= radius*radius { 177 continue 178 } 179 m.SetRGBA(lox-x, loy-y, color.RGBA{}) 180 m.SetRGBA(hix+x, loy-y, color.RGBA{}) 181 m.SetRGBA(lox-x, hiy+y, color.RGBA{}) 182 m.SetRGBA(hix+x, hiy+y, color.RGBA{}) 183 } 184 } 185} 186