diff --git a/example/glfw/main.go b/example/glfw/main.go deleted file mode 100644 index a45eef77..00000000 --- a/example/glfw/main.go +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -// GLFW doesn't build on OpenBSD and FreeBSD. -// +build !openbsd,!freebsd,!windows,!android,!ios,!js - -// The glfw example demonstrates integration of Gio into a foreign -// windowing and rendering library, in this case GLFW -// (https://www.glfw.org). -// -// See the go-glfw package for installation of the native -// dependencies: -// -// https://github.com/go-gl/glfw -package main - -import ( - "image" - "log" - "math" - "runtime" - "time" - - "gioui.org/f32" - "gioui.org/font/gofont" - "gioui.org/gpu" - giogl "gioui.org/gpu/gl" - "gioui.org/io/pointer" - "gioui.org/io/router" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/unit" - "gioui.org/widget" - "gioui.org/widget/material" - "github.com/go-gl/gl/v3.3-core/gl" - "github.com/go-gl/glfw/v3.3/glfw" -) - -type glfwConfig struct { - Scale float32 -} - -type goglFunctions struct { -} - -func main() { - // Required by the OpenGL threading model. - runtime.LockOSThread() - - err := glfw.Init() - if err != nil { - log.Fatal(err) - } - defer glfw.Terminate() - // Gio assumes a sRGB backbuffer. - glfw.WindowHint(glfw.SRGBCapable, glfw.True) - - window, err := glfw.CreateWindow(800, 600, "Gio + GLFW", nil, nil) - if err != nil { - log.Fatal(err) - } - - window.MakeContextCurrent() - - if err := gl.Init(); err != nil { - log.Fatal(err) - } - // Enable sRGB. - gl.Enable(gl.FRAMEBUFFER_SRGB) - - var queue router.Router - var ops op.Ops - th := material.NewTheme(gofont.Collection()) - backend, err := giogl.NewBackend(nil) - if err != nil { - log.Fatal(err) - } - gpu, err := gpu.New(backend) - if err != nil { - log.Fatal(err) - } - - registerCallbacks(window, &queue) - for !window.ShouldClose() { - glfw.PollEvents() - scale := float32(1.0) - if monitor := window.GetMonitor(); monitor != nil { - scalex, _ := window.GetMonitor().GetContentScale() - scale = scalex - } - width, height := window.GetSize() - sz := image.Point{X: width, Y: height} - ops.Reset() - gtx := layout.Context{ - Ops: &ops, - Now: time.Now(), - Queue: &queue, - Metric: unit.Metric{ - PxPerDp: scale, - PxPerSp: scale, - }, - Constraints: layout.Exact(sz), - } - draw(gtx, th) - gpu.Collect(sz, gtx.Ops) - gpu.BeginFrame() - queue.Frame(gtx.Ops) - gpu.EndFrame() - window.SwapBuffers() - } -} - -var button widget.Clickable - -func draw(gtx layout.Context, th *material.Theme) layout.Dimensions { - return layout.Center.Layout(gtx, - material.Button(th, &button, "Button").Layout, - ) -} - -func registerCallbacks(window *glfw.Window, q *router.Router) { - var btns pointer.Buttons - beginning := time.Now() - var lastPos f32.Point - window.SetCursorPosCallback(func(w *glfw.Window, xpos float64, ypos float64) { - lastPos = f32.Point{X: float32(xpos), Y: float32(ypos)} - q.Add(pointer.Event{ - Type: pointer.Move, - Position: lastPos, - Source: pointer.Mouse, - Time: time.Since(beginning), - Buttons: btns, - }) - }) - window.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) { - var btn pointer.Buttons - switch button { - case glfw.MouseButton1: - btn = pointer.ButtonLeft - case glfw.MouseButton2: - btn = pointer.ButtonRight - case glfw.MouseButton3: - btn = pointer.ButtonMiddle - } - var typ pointer.Type - switch action { - case glfw.Release: - typ = pointer.Release - btns &^= btn - case glfw.Press: - typ = pointer.Press - btns |= btn - } - q.Add(pointer.Event{ - Type: typ, - Source: pointer.Mouse, - Time: time.Since(beginning), - Position: lastPos, - Buttons: btns, - }) - }) -} - -func (s *glfwConfig) Px(v unit.Value) int { - scale := s.Scale - if v.U == unit.UnitPx { - scale = 1 - } - return int(math.Round(float64(scale * v.V))) -} diff --git a/example/go.mod b/example/go.mod deleted file mode 100644 index b5037f1d..00000000 --- a/example/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module gioui.org/example - -go 1.13 - -require ( - gioui.org v0.0.0-20201206220230-a87a520ae825 - github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 - github.com/google/go-github/v24 v24.0.1 - golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 - golang.org/x/image v0.0.0-20200618115811-c13761719519 - golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 -) diff --git a/example/go.sum b/example/go.sum deleted file mode 100644 index f786eb54..00000000 --- a/example/go.sum +++ /dev/null @@ -1,56 +0,0 @@ -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20201206220230-a87a520ae825 h1:8eQeFlQ0IL5sOX74YcwEBk3OtGNTRCqIU3Rz0z0U6vE= -gioui.org v0.0.0-20201206220230-a87a520ae825/go.mod h1:Y+uS7hHMvku1Q+ooaoq6fYD5B2LGoT8JtFgvmYmRzTw= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4= -github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 h1:n9HxLrNxWWtEb1cA950nuEEj3QnKbtsCJ6KjcgisNUs= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/example/gophers/main.go b/example/gophers/main.go deleted file mode 100644 index 8cd3c9f0..00000000 --- a/example/gophers/main.go +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -// A Gio program that displays Go contributors from GitHub. See https://gioui.org for more information. - -import ( - "context" - "flag" - "fmt" - "image" - "log" - "net/http" - "os" - - "golang.org/x/oauth2" - - "gioui.org/app" - "gioui.org/gesture" - "gioui.org/io/key" - "gioui.org/io/system" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/unit" - - "github.com/google/go-github/v24/github" - - _ "image/jpeg" - _ "image/png" - - _ "net/http/pprof" -) - -type App struct { - w *app.Window - - ui *UI - - updateUsers chan []*user - commitsResult chan []*github.Commit - ctx context.Context - ctxCancel context.CancelFunc -} - -var ( - prof = flag.Bool("profile", false, "serve profiling data at http://localhost:6060") - stats = flag.Bool("stats", false, "show rendering statistics") - token = flag.String("token", "", "Github authentication token") -) - -func main() { - flag.Parse() - initProfiling() - if *token == "" { - fmt.Println("The quota for anonymous GitHub API access is very low. Specify a token with -token to avoid quota errors.") - fmt.Println("See https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line.") - } - go func() { - w := app.NewWindow( - app.Size(unit.Dp(400), unit.Dp(800)), - app.Title("Gophers"), - ) - if err := newApp(w).run(); err != nil { - log.Fatal(err) - } - os.Exit(0) - }() - app.Main() -} - -func initProfiling() { - if !*prof { - return - } - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() -} - -func (a *App) run() error { - a.ui.profiling = *stats - var ops op.Ops - for { - select { - case users := <-a.updateUsers: - a.ui.users = users - a.ui.userClicks = make([]gesture.Click, len(users)) - a.w.Invalidate() - case commits := <-a.commitsResult: - a.ui.selectedUser.commits = commits - a.w.Invalidate() - case e := <-a.w.Events(): - switch e := e.(type) { - case key.Event: - switch e.Name { - case key.NameEscape: - os.Exit(0) - case "P": - if e.Modifiers.Contain(key.ModShortcut) { - a.ui.profiling = !a.ui.profiling - a.w.Invalidate() - } - } - case system.DestroyEvent: - return e.Err - case system.StageEvent: - if e.Stage >= system.StageRunning { - if a.ctxCancel == nil { - a.ctx, a.ctxCancel = context.WithCancel(context.Background()) - } - if a.ui.users == nil { - go a.fetchContributors() - } - } else { - if a.ctxCancel != nil { - a.ctxCancel() - a.ctxCancel = nil - } - } - case *system.CommandEvent: - switch e.Type { - case system.CommandBack: - if a.ui.selectedUser != nil { - a.ui.selectedUser = nil - e.Cancel = true - a.w.Invalidate() - } - } - case system.FrameEvent: - gtx := layout.NewContext(&ops, e) - a.ui.Layout(gtx) - e.Frame(gtx.Ops) - } - } - } -} - -func newApp(w *app.Window) *App { - a := &App{ - w: w, - updateUsers: make(chan []*user), - commitsResult: make(chan []*github.Commit, 1), - } - fetch := func(u string) { - a.fetchCommits(a.ctx, u) - } - a.ui = newUI(fetch) - return a -} - -func githubClient(ctx context.Context) *github.Client { - var tc *http.Client - if *token != "" { - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: *token}, - ) - tc = oauth2.NewClient(ctx, ts) - } - return github.NewClient(tc) -} - -func (a *App) fetchContributors() { - client := githubClient(a.ctx) - cons, _, err := client.Repositories.ListContributors(a.ctx, "golang", "go", nil) - if err != nil { - fmt.Fprintf(os.Stderr, "github: failed to fetch contributors: %v\n", err) - return - } - var users []*user - userErrs := make(chan error, len(cons)) - avatarErrs := make(chan error, len(cons)) - for _, con := range cons { - con := con - avatar := con.GetAvatarURL() - if avatar == "" { - continue - } - u := &user{ - login: con.GetLogin(), - } - users = append(users, u) - go func() { - guser, _, err := client.Users.Get(a.ctx, u.login) - if err != nil { - avatarErrs <- err - return - } - u.name = guser.GetName() - u.company = guser.GetCompany() - avatarErrs <- nil - }() - go func() { - a, err := fetchImage(avatar) - if a != nil { - u.avatar = a - } - userErrs <- err - }() - } - for i := 0; i < len(cons); i++ { - if err := <-userErrs; err != nil { - fmt.Fprintf(os.Stderr, "github: failed to fetch user: %v\n", err) - } - if err := <-avatarErrs; err != nil { - fmt.Fprintf(os.Stderr, "github: failed to fetch avatar: %v\n", err) - } - } - // Drop users with no avatar or name. - for i := len(users) - 1; i >= 0; i-- { - if u := users[i]; u.name == "" || u.avatar.Bounds().Size() == (image.Point{}) { - users = append(users[:i], users[i+1:]...) - } - } - a.updateUsers <- users -} - -func fetchImage(url string) (image.Image, error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("fetchImage: http.Get(%q): %v", url, err) - } - defer resp.Body.Close() - img, _, err := image.Decode(resp.Body) - if err != nil { - return nil, fmt.Errorf("fetchImage: image decode failed: %v", err) - } - return img, nil -} - -func (a *App) fetchCommits(ctx context.Context, user string) { - go func() { - gh := githubClient(ctx) - repoCommits, _, err := gh.Repositories.ListCommits(ctx, "golang", "go", &github.CommitsListOptions{ - Author: user, - }) - if err != nil { - log.Printf("failed to fetch commits: %v", err) - return - } - var commits []*github.Commit - for _, commit := range repoCommits { - if c := commit.GetCommit(); c != nil { - commits = append(commits, c) - } - } - a.commitsResult <- commits - }() -} diff --git a/example/gophers/main_test.go b/example/gophers/main_test.go deleted file mode 100644 index bc147f75..00000000 --- a/example/gophers/main_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -import ( - "image" - "testing" - - "gioui.org/layout" - "gioui.org/op" -) - -func BenchmarkUI(b *testing.B) { - fetch := func(_ string) {} - u := newUI(fetch) - var ops op.Ops - for i := 0; i < b.N; i++ { - gtx := layout.Context{ - Ops: &ops, - Constraints: layout.Exact(image.Pt(800, 600)), - } - u.Layout(gtx) - } -} diff --git a/example/gophers/ui.go b/example/gophers/ui.go deleted file mode 100644 index b3009125..00000000 --- a/example/gophers/ui.go +++ /dev/null @@ -1,424 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -// A Gio program that displays Go contributors from GitHub. See https://gioui.org for more information. - -import ( - "fmt" - "image" - "image/color" - "log" - "runtime" - - "gioui.org/f32" - "gioui.org/font/gofont" - "gioui.org/gesture" - "gioui.org/io/key" - "gioui.org/io/pointer" - "gioui.org/io/profile" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/op/clip" - "gioui.org/op/paint" - "gioui.org/text" - "gioui.org/unit" - "gioui.org/widget" - "gioui.org/widget/material" - - "github.com/google/go-github/v24/github" - - "golang.org/x/exp/shiny/materialdesign/icons" - - "golang.org/x/image/draw" -) - -type UI struct { - fab *widget.Clickable - fabIcon *widget.Icon - usersList *layout.List - users []*user - userClicks []gesture.Click - selectedUser *userPage - edit, edit2 *widget.Editor - fetchCommits func(u string) - - // Profiling. - profiling bool - profile profile.Event - lastMallocs uint64 -} - -type userPage struct { - user *user - commitsList *layout.List - commits []*github.Commit -} - -type user struct { - name string - login string - company string - avatar image.Image - avatarOp paint.ImageOp -} - -var theme *material.Theme - -type ( - C = layout.Context - D = layout.Dimensions -) - -func init() { - theme = material.NewTheme(gofont.Collection()) - theme.Palette.Fg = rgb(0x333333) -} - -func newUI(fetchCommits func(string)) *UI { - u := &UI{ - fetchCommits: fetchCommits, - } - u.usersList = &layout.List{ - Axis: layout.Vertical, - } - u.fab = new(widget.Clickable) - u.edit2 = &widget.Editor{ - //Alignment: text.End, - SingleLine: true, - } - var err error - u.fabIcon, err = widget.NewIcon(icons.ContentSend) - if err != nil { - log.Fatal(err) - } - u.edit2.SetText("Single line editor. Edit me!") - u.edit = &widget.Editor{ - //Alignment: text.End, - //SingleLine: true, - } - u.edit.SetText(longTextSample) - return u -} - -func rgb(c uint32) color.NRGBA { - return argb((0xff << 24) | c) -} - -func argb(c uint32) color.NRGBA { - return color.NRGBA{A: uint8(c >> 24), R: uint8(c >> 16), G: uint8(c >> 8), B: uint8(c)} -} - -func (u *UI) layoutTimings(gtx layout.Context) { - if !u.profiling { - return - } - for _, e := range gtx.Events(u) { - if e, ok := e.(profile.Event); ok { - u.profile = e - } - } - profile.Op{Tag: u}.Add(gtx.Ops) - var mstats runtime.MemStats - runtime.ReadMemStats(&mstats) - mallocs := mstats.Mallocs - u.lastMallocs - u.lastMallocs = mstats.Mallocs - layout.NE.Layout(gtx, func(gtx C) D { - return layout.Inset{Top: unit.Dp(16)}.Layout(gtx, func(gtx C) D { - txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings) - lbl := material.Caption(theme, txt) - lbl.Font.Variant = "Mono" - return lbl.Layout(gtx) - }) - }) -} - -func (u *UI) Layout(gtx layout.Context) { - for i := range u.userClicks { - click := &u.userClicks[i] - for _, e := range click.Events(gtx) { - if e.Type == gesture.TypeClick { - u.selectedUser = u.newUserPage(u.users[i]) - } - } - } - if u.selectedUser == nil { - u.layoutUsers(gtx) - } else { - u.selectedUser.Layout(gtx) - } - u.layoutTimings(gtx) -} - -func (u *UI) newUserPage(user *user) *userPage { - up := &userPage{ - user: user, - commitsList: &layout.List{Axis: layout.Vertical}, - } - u.fetchCommits(user.login) - return up -} - -func (up *userPage) Layout(gtx layout.Context) { - l := up.commitsList - if l.Dragging() { - key.SoftKeyboardOp{Show: false}.Add(gtx.Ops) - } - l.Layout(gtx, len(up.commits), func(gtx C, i int) D { - return up.commit(gtx, i) - }) -} - -func (up *userPage) commit(gtx layout.Context, index int) layout.Dimensions { - u := up.user - msg := up.commits[index].GetMessage() - label := material.Caption(theme, msg) - in := layout.Inset{Top: unit.Dp(16), Right: unit.Dp(8), Left: unit.Dp(8)} - return in.Layout(gtx, func(gtx C) D { - return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, - layout.Rigid(func(gtx C) D { - sz := gtx.Px(unit.Dp(48)) - cc := clipCircle{} - return cc.Layout(gtx, func(gtx C) D { - gtx.Constraints = layout.Exact(gtx.Constraints.Constrain(image.Point{X: sz, Y: sz})) - return u.layoutAvatar(gtx) - }) - }), - layout.Flexed(1, func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - return layout.Inset{Left: unit.Dp(8)}.Layout(gtx, label.Layout) - }), - ) - }) -} - -func (u *UI) layoutUsers(gtx layout.Context) { - layout.Stack{Alignment: layout.SE}.Layout(gtx, - layout.Expanded(func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - return layout.UniformInset(unit.Dp(16)).Layout(gtx, func(gtx C) D { - sz := gtx.Px(unit.Dp(200)) - cs := gtx.Constraints - gtx.Constraints = layout.Exact(cs.Constrain(image.Point{X: sz, Y: sz})) - return material.Editor(theme, u.edit, "Hint").Layout(gtx) - }) - }), - layout.Rigid(func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - in := layout.Inset{Bottom: unit.Dp(16), Left: unit.Dp(16), Right: unit.Dp(16)} - return in.Layout(gtx, func(gtx C) D { - e := material.Editor(theme, u.edit2, "Hint") - e.TextSize = unit.Sp(14) - e.Font.Style = text.Italic - return e.Layout(gtx) - }) - }), - layout.Rigid(func(gtx C) D { - return layout.Stack{}.Layout(gtx, - layout.Expanded(func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - return fill{rgb(0xf2f2f2)}.Layout(gtx) - }), - layout.Stacked(func(gtx C) D { - in := layout.Inset{Top: unit.Dp(16), Right: unit.Dp(8), Bottom: unit.Dp(8), Left: unit.Dp(8)} - return in.Layout(gtx, func(gtx C) D { - lbl := material.Caption(theme, "GOPHERS") - lbl.Color = rgb(0x888888) - return lbl.Layout(gtx) - }) - }), - ) - }), - layout.Flexed(1, func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - return u.layoutContributors(gtx) - }), - ) - }), - layout.Stacked(func(gtx C) D { - in := layout.UniformInset(unit.Dp(16)) - return in.Layout(gtx, func(gtx C) D { - for u.fab.Clicked() { - } - return material.IconButton(theme, u.fab, u.fabIcon).Layout(gtx) - }) - }), - ) -} - -func (u *UI) layoutContributors(gtx layout.Context) layout.Dimensions { - l := u.usersList - if l.Dragging() { - key.SoftKeyboardOp{Show: false}.Add(gtx.Ops) - } - return l.Layout(gtx, len(u.users), func(gtx C, i int) D { - return u.user(gtx, i) - }) -} - -func (u *UI) user(gtx layout.Context, index int) layout.Dimensions { - user := u.users[index] - in := layout.UniformInset(unit.Dp(8)) - dims := in.Layout(gtx, func(gtx C) D { - return centerRowOpts().Layout(gtx, - layout.Rigid(func(gtx C) D { - in := layout.Inset{Right: unit.Dp(8)} - cc := clipCircle{} - return in.Layout(gtx, func(gtx C) D { - return cc.Layout(gtx, func(gtx C) D { - dim := gtx.Px(unit.Dp(48)) - sz := image.Point{X: dim, Y: dim} - gtx.Constraints = layout.Exact(gtx.Constraints.Constrain(sz)) - return user.layoutAvatar(gtx) - }) - }) - }), - layout.Rigid(func(gtx C) D { - return column().Layout(gtx, - layout.Rigid(func(gtx C) D { - return baseline().Layout(gtx, - layout.Rigid(material.Body1(theme, user.name).Layout), - layout.Flexed(1, func(gtx C) D { - gtx.Constraints.Min.X = gtx.Constraints.Max.X - return layout.E.Layout(gtx, func(gtx C) D { - return layout.Inset{Left: unit.Dp(2)}.Layout(gtx, - material.Caption(theme, "3 hours ago").Layout) - }) - }), - ) - }), - layout.Rigid(func(gtx C) D { - in := layout.Inset{Top: unit.Dp(4)} - return in.Layout(gtx, func(gtx C) D { - lbl := material.Caption(theme, user.company) - lbl.Color = rgb(0xbbbbbb) - return lbl.Layout(gtx) - }) - }), - ) - }), - ) - }) - pointer.Rect(image.Rectangle{Max: dims.Size}).Add(gtx.Ops) - click := &u.userClicks[index] - click.Add(gtx.Ops) - return dims -} - -func (u *user) layoutAvatar(gtx layout.Context) layout.Dimensions { - sz := gtx.Constraints.Min.X - if u.avatarOp.Size().X != sz { - img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: sz}}) - draw.ApproxBiLinear.Scale(img, img.Bounds(), u.avatar, u.avatar.Bounds(), draw.Src, nil) - u.avatarOp = paint.NewImageOp(img) - } - img := widget.Image{Src: u.avatarOp} - img.Scale = float32(sz) / float32(gtx.Px(unit.Dp(float32(sz)))) - return img.Layout(gtx) -} - -type fill struct { - col color.NRGBA -} - -func (f fill) Layout(gtx layout.Context) layout.Dimensions { - cs := gtx.Constraints - d := cs.Min - dr := image.Rectangle{ - Max: image.Point{X: d.X, Y: d.Y}, - } - paint.FillShape(gtx.Ops, f.col, clip.Rect(dr).Op()) - return layout.Dimensions{Size: d} -} - -func column() layout.Flex { - return layout.Flex{Axis: layout.Vertical} -} - -func centerRowOpts() layout.Flex { - return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle} -} - -func baseline() layout.Flex { - return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Baseline} -} - -type clipCircle struct { -} - -func (c *clipCircle) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions { - m := op.Record(gtx.Ops) - dims := w(gtx) - call := m.Stop() - max := dims.Size.X - if dy := dims.Size.Y; dy > max { - max = dy - } - szf := float32(max) - rr := szf * .5 - defer op.Push(gtx.Ops).Pop() - clip.RRect{ - Rect: f32.Rectangle{Max: f32.Point{X: szf, Y: szf}}, - NE: rr, NW: rr, SE: rr, SW: rr, - }.Add(gtx.Ops) - call.Add(gtx.Ops) - return dims -} - -const longTextSample = `1. I learned from my grandfather, Verus, to use good manners, and to -put restraint on anger. 2. In the famous memory of my father I had a -pattern of modesty and manliness. 3. Of my mother I learned to be -pious and generous; to keep myself not only from evil deeds, but even -from evil thoughts; and to live with a simplicity which is far from -customary among the rich. 4. I owe it to my great-grandfather that I -did not attend public lectures and discussions, but had good and able -teachers at home; and I owe him also the knowledge that for things of -this nature a man should count no expense too great. - -5. My tutor taught me not to favour either green or blue at the -chariot races, nor, in the contests of gladiators, to be a supporter -either of light or heavy armed. He taught me also to endure labour; -not to need many things; to serve myself without troubling others; not -to intermeddle in the affairs of others, and not easily to listen to -slanders against them. - -6. Of Diognetus I had the lesson not to busy myself about vain things; -not to credit the great professions of such as pretend to work -wonders, or of sorcerers about their charms, and their expelling of -Demons and the like; not to keep quails (for fighting or divination), -nor to run after such things; to suffer freedom of speech in others, -and to apply myself heartily to philosophy. Him also I must thank for -my hearing first Bacchius, then Tandasis and Marcianus; that I wrote -dialogues in my youth, and took a liking to the philosopher's pallet -and skins, and to the other things which, by the Grecian discipline, -belong to that profession. - -7. To Rusticus I owe my first apprehensions that my nature needed -reform and cure; and that I did not fall into the ambition of the -common Sophists, either by composing speculative writings or by -declaiming harangues of exhortation in public; further, that I never -strove to be admired by ostentation of great patience in an ascetic -life, or by display of activity and application; that I gave over the -study of rhetoric, poetry, and the graces of language; and that I did -not pace my house in my senatorial robes, or practise any similar -affectation. I observed also the simplicity of style in his letters, -particularly in that which he wrote to my mother from Sinuessa. I -learned from him to be easily appeased, and to be readily reconciled -with those who had displeased me or given cause of offence, so soon as -they inclined to make their peace; to read with care; not to rest -satisfied with a slight and superficial knowledge; nor quickly to -assent to great talkers. I have him to thank that I met with the -discourses of Epictetus, which he furnished me from his own library. - -8. From Apollonius I learned true liberty, and tenacity of purpose; to -regard nothing else, even in the smallest degree, but reason always; -and always to remain unaltered in the agonies of pain, in the losses -of children, or in long diseases. He afforded me a living example of -how the same man can, upon occasion, be most yielding and most -inflexible. He was patient in exposition; and, as might well be seen, -esteemed his fine skill and ability in teaching others the principles -of philosophy as the least of his endowments. It was from him that I -learned how to receive from friends what are thought favours without -seeming humbled by the giver or insensible to the gift.` diff --git a/example/hello/hello.go b/example/hello/hello.go deleted file mode 100644 index 7a328e76..00000000 --- a/example/hello/hello.go +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -// A simple Gio program. See https://gioui.org for more information. - -import ( - "image/color" - "log" - "os" - - "gioui.org/app" - "gioui.org/io/system" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/text" - "gioui.org/widget/material" - - "gioui.org/font/gofont" -) - -func main() { - go func() { - w := app.NewWindow() - if err := loop(w); err != nil { - log.Fatal(err) - } - os.Exit(0) - }() - app.Main() -} - -func loop(w *app.Window) error { - th := material.NewTheme(gofont.Collection()) - var ops op.Ops - for { - e := <-w.Events() - switch e := e.(type) { - case system.DestroyEvent: - return e.Err - case system.FrameEvent: - gtx := layout.NewContext(&ops, e) - l := material.H1(th, "Hello, Gio") - maroon := color.NRGBA{R: 127, G: 0, B: 0, A: 255} - l.Color = maroon - l.Alignment = text.Middle - l.Layout(gtx) - e.Frame(gtx.Ops) - } - } -} diff --git a/example/kitchen/kitchen.go b/example/kitchen/kitchen.go deleted file mode 100644 index f9e42b97..00000000 --- a/example/kitchen/kitchen.go +++ /dev/null @@ -1,431 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -// A Gio program that demonstrates Gio widgets. See https://gioui.org for more information. - -import ( - "bytes" - "flag" - "fmt" - "image" - "image/color" - "image/png" - "io/ioutil" - "log" - "math" - "os" - "time" - - "gioui.org/app" - "gioui.org/app/headless" - "gioui.org/f32" - "gioui.org/font/gofont" - "gioui.org/io/router" - "gioui.org/io/system" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/op/clip" - "gioui.org/op/paint" - "gioui.org/text" - "gioui.org/unit" - "gioui.org/widget" - "gioui.org/widget/material" - - "golang.org/x/exp/shiny/materialdesign/icons" -) - -var screenshot = flag.String("screenshot", "", "save a screenshot to a file and exit") -var disable = flag.Bool("disable", false, "disable all widgets") - -type iconAndTextButton struct { - theme *material.Theme - button *widget.Clickable - icon *widget.Icon - word string -} - -func main() { - flag.Parse() - editor.SetText(longText) - ic, err := widget.NewIcon(icons.ContentAdd) - if err != nil { - log.Fatal(err) - } - icon = ic - progressIncrementer = make(chan int) - if *screenshot != "" { - if err := saveScreenshot(*screenshot); err != nil { - fmt.Fprintf(os.Stderr, "failed to save screenshot: %v\n", err) - os.Exit(1) - } - os.Exit(0) - } - - go func() { - for { - time.Sleep(time.Second) - progressIncrementer <- 10 - } - }() - - go func() { - w := app.NewWindow(app.Size(unit.Dp(800), unit.Dp(700))) - if err := loop(w); err != nil { - log.Fatal(err) - } - os.Exit(0) - }() - app.Main() -} - -func saveScreenshot(f string) error { - const scale = 1.5 - sz := image.Point{X: 800 * scale, Y: 600 * scale} - w, err := headless.NewWindow(sz.X, sz.Y) - if err != nil { - return err - } - gtx := layout.Context{ - Ops: new(op.Ops), - Metric: unit.Metric{ - PxPerDp: scale, - PxPerSp: scale, - }, - Constraints: layout.Exact(sz), - Queue: new(router.Router), - } - th := material.NewTheme(gofont.Collection()) - kitchen(gtx, th) - w.Frame(gtx.Ops) - img, err := w.Screenshot() - if err != nil { - return err - } - var buf bytes.Buffer - if err := png.Encode(&buf, img); err != nil { - return err - } - return ioutil.WriteFile(f, buf.Bytes(), 0666) -} - -func loop(w *app.Window) error { - th := material.NewTheme(gofont.Collection()) - - var ops op.Ops - for { - select { - case e := <-w.Events(): - switch e := e.(type) { - case system.DestroyEvent: - return e.Err - case system.FrameEvent: - gtx := layout.NewContext(&ops, e) - if *disable { - gtx = gtx.Disabled() - } - if checkbox.Changed() { - if checkbox.Value { - transformTime = e.Now - } else { - transformTime = time.Time{} - } - } - - transformedKitchen(gtx, th) - e.Frame(gtx.Ops) - } - case p := <-progressIncrementer: - progress += p - if progress > 100 { - progress = 0 - } - w.Invalidate() - } - } -} - -func transformedKitchen(gtx layout.Context, th *material.Theme) layout.Dimensions { - if !transformTime.IsZero() { - dt := float32(gtx.Now.Sub(transformTime).Seconds()) - angle := dt * .1 - op.InvalidateOp{}.Add(gtx.Ops) - defer op.Push(gtx.Ops).Pop() - tr := f32.Affine2D{} - tr = tr.Rotate(f32.Pt(300, 20), -angle) - scale := 1.0 - dt*.5 - if scale < 0.5 { - scale = 0.5 - } - tr = tr.Scale(f32.Pt(300, 20), f32.Pt(scale, scale)) - offset := dt * 50 - if offset > 200 { - offset = 200 - } - tr = tr.Offset(f32.Pt(0, offset)) - op.Affine(tr).Add(gtx.Ops) - } - - return kitchen(gtx, th) -} - -var ( - editor = new(widget.Editor) - lineEditor = &widget.Editor{ - SingleLine: true, - Submit: true, - } - button = new(widget.Clickable) - greenButton = new(widget.Clickable) - iconTextButton = new(widget.Clickable) - iconButton = new(widget.Clickable) - flatBtn = new(widget.Clickable) - disableBtn = new(widget.Clickable) - radioButtonsGroup = new(widget.Enum) - list = &layout.List{ - Axis: layout.Vertical, - } - progress = 0 - progressIncrementer chan int - green = true - topLabel = "Hello, Gio" - icon *widget.Icon - checkbox = new(widget.Bool) - swtch = new(widget.Bool) - transformTime time.Time - float = new(widget.Float) -) - -type ( - D = layout.Dimensions - C = layout.Context -) - -func (b iconAndTextButton) Layout(gtx layout.Context) layout.Dimensions { - return material.ButtonLayout(b.theme, b.button).Layout(gtx, func(gtx C) D { - return layout.UniformInset(unit.Dp(12)).Layout(gtx, func(gtx C) D { - iconAndLabel := layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle} - textIconSpacer := unit.Dp(5) - - layIcon := layout.Rigid(func(gtx C) D { - return layout.Inset{Right: textIconSpacer}.Layout(gtx, func(gtx C) D { - var d D - if icon != nil { - size := gtx.Px(unit.Dp(56)) - 2*gtx.Px(unit.Dp(16)) - b.icon.Layout(gtx, unit.Px(float32(size))) - d = layout.Dimensions{ - Size: image.Point{X: size, Y: size}, - } - } - return d - }) - }) - - layLabel := layout.Rigid(func(gtx C) D { - return layout.Inset{Left: textIconSpacer}.Layout(gtx, func(gtx C) D { - l := material.Body1(b.theme, b.word) - l.Color = b.theme.Palette.ContrastFg - return l.Layout(gtx) - }) - }) - - return iconAndLabel.Layout(gtx, layIcon, layLabel) - }) - }) -} - -func kitchen(gtx layout.Context, th *material.Theme) layout.Dimensions { - for _, e := range lineEditor.Events() { - if e, ok := e.(widget.SubmitEvent); ok { - topLabel = e.Text - lineEditor.SetText("") - } - } - widgets := []layout.Widget{ - material.H3(th, topLabel).Layout, - func(gtx C) D { - gtx.Constraints.Max.Y = gtx.Px(unit.Dp(200)) - return material.Editor(th, editor, "Hint").Layout(gtx) - }, - func(gtx C) D { - e := material.Editor(th, lineEditor, "Hint") - e.Font.Style = text.Italic - border := widget.Border{Color: color.NRGBA{A: 0xff}, CornerRadius: unit.Dp(8), Width: unit.Px(2)} - return border.Layout(gtx, func(gtx C) D { - return layout.UniformInset(unit.Dp(8)).Layout(gtx, e.Layout) - }) - }, - func(gtx C) D { - gtx.Constraints.Min.Y = gtx.Px(unit.Dp(50)) - gtx.Constraints.Max.Y = gtx.Constraints.Min.Y - - dr := image.Rectangle{Max: gtx.Constraints.Min} - defer op.Push(gtx.Ops).Pop() - paint.LinearGradientOp{ - Stop1: layout.FPt(dr.Min), - Stop2: layout.FPt(dr.Max), - Color1: color.NRGBA{R: 0x10, G: 0xff, B: 0x10, A: 0xFF}, - Color2: color.NRGBA{R: 0x10, G: 0x10, B: 0xff, A: 0xFF}, - }.Add(gtx.Ops) - clip.Rect(dr).Add(gtx.Ops) - paint.PaintOp{}.Add(gtx.Ops) - return layout.Dimensions{ - Size: gtx.Constraints.Max, - } - }, - func(gtx C) D { - in := layout.UniformInset(unit.Dp(8)) - return layout.Flex{Alignment: layout.Middle}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return in.Layout(gtx, material.IconButton(th, iconButton, icon).Layout) - }), - layout.Rigid(func(gtx C) D { - return in.Layout(gtx, iconAndTextButton{theme: th, icon: icon, word: "Icon", button: iconTextButton}.Layout) - }), - layout.Rigid(func(gtx C) D { - return in.Layout(gtx, func(gtx C) D { - for button.Clicked() { - green = !green - } - return material.Button(th, button, "Click me!").Layout(gtx) - }) - }), - layout.Rigid(func(gtx C) D { - return in.Layout(gtx, func(gtx C) D { - l := "Green" - if !green { - l = "Blue" - } - btn := material.Button(th, greenButton, l) - if green { - btn.Background = color.NRGBA{A: 0xff, R: 0x9e, G: 0x9d, B: 0x24} - } - return btn.Layout(gtx) - }) - }), - layout.Rigid(func(gtx C) D { - return in.Layout(gtx, func(gtx C) D { - return material.Clickable(gtx, flatBtn, func(gtx C) D { - return layout.UniformInset(unit.Dp(12)).Layout(gtx, func(gtx C) D { - flatBtnText := material.Body1(th, "Flat") - if gtx.Queue == nil { - flatBtnText.Color.A = 150 - } - return layout.Center.Layout(gtx, flatBtnText.Layout) - }) - }) - }) - }), - ) - }, - material.ProgressBar(th, progress).Layout, - func(gtx C) D { - return layout.Flex{Alignment: layout.Middle}.Layout(gtx, - layout.Rigid( - material.CheckBox(th, checkbox, "Transform").Layout, - ), - layout.Rigid(func(gtx C) D { - return layout.Inset{Left: unit.Dp(16)}.Layout(gtx, - material.Switch(th, swtch).Layout, - ) - }), - layout.Rigid(func(gtx C) D { - return layout.Inset{Left: unit.Dp(16)}.Layout(gtx, func(gtx C) D { - text := "enabled" - if !swtch.Value { - text = "disabled" - gtx = gtx.Disabled() - } - btn := material.Button(th, disableBtn, text) - return btn.Layout(gtx) - }) - }), - layout.Rigid(func(gtx C) D { - return layout.Inset{Left: unit.Dp(16)}.Layout(gtx, func(gtx C) D { - if !swtch.Value { - return D{} - } - return material.Loader(th).Layout(gtx) - }) - }), - ) - }, - func(gtx C) D { - return layout.Flex{}.Layout(gtx, - layout.Rigid(material.RadioButton(th, radioButtonsGroup, "r1", "RadioButton1").Layout), - layout.Rigid(material.RadioButton(th, radioButtonsGroup, "r2", "RadioButton2").Layout), - layout.Rigid(material.RadioButton(th, radioButtonsGroup, "r3", "RadioButton3").Layout), - ) - }, - func(gtx C) D { - return layout.Flex{Alignment: layout.Middle}.Layout(gtx, - layout.Flexed(1, material.Slider(th, float, 0, 2*math.Pi).Layout), - layout.Rigid(func(gtx C) D { - return layout.UniformInset(unit.Dp(8)).Layout(gtx, - material.Body1(th, fmt.Sprintf("%.2f", float.Value)).Layout, - ) - }), - ) - }, - } - - return list.Layout(gtx, len(widgets), func(gtx C, i int) D { - return layout.UniformInset(unit.Dp(16)).Layout(gtx, widgets[i]) - }) -} - -const longText = `1. I learned from my grandfather, Verus, to use good manners, and to -put restraint on anger. 2. In the famous memory of my father I had a -pattern of modesty and manliness. 3. Of my mother I learned to be -pious and generous; to keep myself not only from evil deeds, but even -from evil thoughts; and to live with a simplicity which is far from -customary among the rich. 4. I owe it to my great-grandfather that I -did not attend public lectures and discussions, but had good and able -teachers at home; and I owe him also the knowledge that for things of -this nature a man should count no expense too great. - -5. My tutor taught me not to favour either green or blue at the -chariot races, nor, in the contests of gladiators, to be a supporter -either of light or heavy armed. He taught me also to endure labour; -not to need many things; to serve myself without troubling others; not -to intermeddle in the affairs of others, and not easily to listen to -slanders against them. - -6. Of Diognetus I had the lesson not to busy myself about vain things; -not to credit the great professions of such as pretend to work -wonders, or of sorcerers about their charms, and their expelling of -Demons and the like; not to keep quails (for fighting or divination), -nor to run after such things; to suffer freedom of speech in others, -and to apply myself heartily to philosophy. Him also I must thank for -my hearing first Bacchius, then Tandasis and Marcianus; that I wrote -dialogues in my youth, and took a liking to the philosopher's pallet -and skins, and to the other things which, by the Grecian discipline, -belong to that profession. - -7. To Rusticus I owe my first apprehensions that my nature needed -reform and cure; and that I did not fall into the ambition of the -common Sophists, either by composing speculative writings or by -declaiming harangues of exhortation in public; further, that I never -strove to be admired by ostentation of great patience in an ascetic -life, or by display of activity and application; that I gave over the -study of rhetoric, poetry, and the graces of language; and that I did -not pace my house in my senatorial robes, or practise any similar -affectation. I observed also the simplicity of style in his letters, -particularly in that which he wrote to my mother from Sinuessa. I -learned from him to be easily appeased, and to be readily reconciled -with those who had displeased me or given cause of offence, so soon as -they inclined to make their peace; to read with care; not to rest -satisfied with a slight and superficial knowledge; nor quickly to -assent to great talkers. I have him to thank that I met with the -discourses of Epictetus, which he furnished me from his own library. - -8. From Apollonius I learned true liberty, and tenacity of purpose; to -regard nothing else, even in the smallest degree, but reason always; -and always to remain unaltered in the agonies of pain, in the losses -of children, or in long diseases. He afforded me a living example of -how the same man can, upon occasion, be most yielding and most -inflexible. He was patient in exposition; and, as might well be seen, -esteemed his fine skill and ability in teaching others the principles -of philosophy as the least of his endowments. It was from him that I -learned how to receive from friends what are thought favours without -seeming humbled by the giver or insensible to the gift.` diff --git a/example/kitchen/main_test.go b/example/kitchen/main_test.go deleted file mode 100644 index c3c16e5b..00000000 --- a/example/kitchen/main_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -import ( - "image" - "testing" - "time" - - "gioui.org/app/headless" - "gioui.org/f32" - "gioui.org/font/gofont" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/widget/material" -) - -func BenchmarkUI(b *testing.B) { benchmarkUI(b, transformation{}) } -func BenchmarkUI_Offset(b *testing.B) { benchmarkUI(b, transformation{offset: true}) } -func BenchmarkUI_Scale(b *testing.B) { benchmarkUI(b, transformation{scale: true}) } -func BenchmarkUI_Rotate(b *testing.B) { benchmarkUI(b, transformation{rotate: true}) } -func BenchmarkUI_All(b *testing.B) { - benchmarkUI(b, transformation{offset: true, rotate: true, scale: true}) -} - -func benchmarkUI(b *testing.B, transform transformation) { - th := material.NewTheme(gofont.Collection()) - - w, err := headless.NewWindow(800, 600) - if err != nil { - b.Fatal(err) - } - defer w.Release() - - var layoutTime time.Duration - var frameTime time.Duration - - b.ResetTimer() - var ops op.Ops - for i := 0; i < b.N; i++ { - ops.Reset() - gtx := layout.Context{ - Ops: &ops, - Constraints: layout.Exact(image.Pt(800, 600)), - } - addTransform(i, transform, gtx.Ops) - layoutTime += measure(func() { kitchen(gtx, th) }) - frameTime += measure(func() { w.Frame(&ops) }) - } - b.StopTimer() - - b.ReportMetric(float64(layoutTime.Nanoseconds())/float64(b.N), "ns/layout") - b.ReportMetric(float64(frameTime.Nanoseconds())/float64(b.N), "ns/frame") -} - -type transformation struct { - offset bool - rotate bool - scale bool -} - -func addTransform(i int, transform transformation, ops *op.Ops) { - if !(transform.offset || transform.rotate || transform.scale) { - return - } - dt := float32(i) - tr := f32.Affine2D{} - if transform.rotate { - angle := dt * .1 - tr = tr.Rotate(f32.Pt(300, 20), -angle) - } - if transform.scale { - scale := 1.0 - dt*.5 - if scale < 0.5 { - scale = 0.5 - } - tr = tr.Scale(f32.Pt(300, 20), f32.Pt(scale, scale)) - } - if transform.offset { - offset := dt * 50 - if offset > 200 { - offset = 200 - } - tr = tr.Offset(f32.Pt(0, offset)) - } - op.Affine(tr).Add(ops) -} - -func measure(fn func()) time.Duration { - start := time.Now() - fn() - return time.Since(start) -} diff --git a/example/tabs/slider.go b/example/tabs/slider.go deleted file mode 100644 index af89f6f5..00000000 --- a/example/tabs/slider.go +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -import ( - "time" - - "gioui.org/f32" - "gioui.org/layout" - "gioui.org/op" -) - -const defaultDuration = 300 * time.Millisecond - -// Slider implements sliding between old/new widget values. -type Slider struct { - Duration time.Duration - - push int - - next *op.Ops - - nextCall op.CallOp - lastCall op.CallOp - - t0 time.Time - offset float32 -} - -// PushLeft pushes the existing widget to the left. -func (s *Slider) PushLeft() { s.push = 1 } - -// PushRight pushes the existing widget to the right. -func (s *Slider) PushRight() { s.push = -1 } - -// Layout lays out widget that can be pushed. -func (s *Slider) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions { - if s.push != 0 { - s.next = nil - s.lastCall = s.nextCall - s.offset = float32(s.push) - s.t0 = gtx.Now - s.push = 0 - } - - var delta time.Duration - if !s.t0.IsZero() { - now := gtx.Now - delta = now.Sub(s.t0) - s.t0 = now - } - - if s.offset != 0 { - duration := s.Duration - if duration == 0 { - duration = defaultDuration - } - movement := float32(delta.Seconds()) / float32(duration.Seconds()) - if s.offset < 0 { - s.offset += movement - if s.offset >= 0 { - s.offset = 0 - } - } else { - s.offset -= movement - if s.offset <= 0 { - s.offset = 0 - } - } - - op.InvalidateOp{}.Add(gtx.Ops) - } - - var dims layout.Dimensions - { - if s.next == nil { - s.next = new(op.Ops) - } - gtx := gtx - gtx.Ops = s.next - gtx.Ops.Reset() - m := op.Record(gtx.Ops) - dims = w(gtx) - s.nextCall = m.Stop() - } - - if s.offset == 0 { - s.nextCall.Add(gtx.Ops) - return dims - } - - defer op.Push(gtx.Ops).Pop() - - offset := smooth(s.offset) - - if s.offset > 0 { - op.Offset(f32.Point{ - X: float32(dims.Size.X) * (offset - 1), - }).Add(gtx.Ops) - s.lastCall.Add(gtx.Ops) - - op.Offset(f32.Point{ - X: float32(dims.Size.X), - }).Add(gtx.Ops) - s.nextCall.Add(gtx.Ops) - } else { - op.Offset(f32.Point{ - X: float32(dims.Size.X) * (offset + 1), - }).Add(gtx.Ops) - s.lastCall.Add(gtx.Ops) - - op.Offset(f32.Point{ - X: float32(-dims.Size.X), - }).Add(gtx.Ops) - s.nextCall.Add(gtx.Ops) - } - return dims -} - -// smooth handles -1 to 1 with ease-in-out cubic easing func. -func smooth(t float32) float32 { - if t < 0 { - return -easeInOutCubic(-t) - } - return easeInOutCubic(t) -} - -// easeInOutCubic maps a linear value to a ease-in-out-cubic easing function. -func easeInOutCubic(t float32) float32 { - if t < 0.5 { - return 4 * t * t * t - } - return (t-1)*(2*t-2)*(2*t-2) + 1 -} diff --git a/example/tabs/tabs.go b/example/tabs/tabs.go deleted file mode 100644 index 48398ab3..00000000 --- a/example/tabs/tabs.go +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -import ( - "fmt" - "image" - "image/color" - "log" - "math" - "os" - - "gioui.org/app" - "gioui.org/f32" - "gioui.org/io/system" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/op/clip" - "gioui.org/op/paint" - "gioui.org/unit" - "gioui.org/widget" - "gioui.org/widget/material" - - "gioui.org/font/gofont" -) - -func main() { - go func() { - defer os.Exit(0) - w := app.NewWindow() - if err := loop(w); err != nil { - log.Fatal(err) - } - }() - app.Main() -} - -func loop(w *app.Window) error { - th := material.NewTheme(gofont.Collection()) - var ops op.Ops - for { - e := <-w.Events() - switch e := e.(type) { - case system.DestroyEvent: - return e.Err - case system.FrameEvent: - gtx := layout.NewContext(&ops, e) - drawTabs(gtx, th) - e.Frame(gtx.Ops) - } - } -} - -var tabs Tabs -var slider Slider - -type Tabs struct { - list layout.List - tabs []Tab - selected int -} - -type Tab struct { - btn widget.Clickable - Title string -} - -func init() { - for i := 1; i <= 100; i++ { - tabs.tabs = append(tabs.tabs, - Tab{Title: fmt.Sprintf("Tab %d", i)}, - ) - } -} - -type ( - C = layout.Context - D = layout.Dimensions -) - -func drawTabs(gtx layout.Context, th *material.Theme) layout.Dimensions { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return tabs.list.Layout(gtx, len(tabs.tabs), func(gtx C, tabIdx int) D { - t := &tabs.tabs[tabIdx] - if t.btn.Clicked() { - if tabs.selected < tabIdx { - slider.PushLeft() - } else if tabs.selected > tabIdx { - slider.PushRight() - } - tabs.selected = tabIdx - } - var tabWidth int - return layout.Stack{Alignment: layout.S}.Layout(gtx, - layout.Stacked(func(gtx C) D { - dims := material.Clickable(gtx, &t.btn, func(gtx C) D { - return layout.UniformInset(unit.Sp(12)).Layout(gtx, - material.H6(th, t.Title).Layout, - ) - }) - tabWidth = dims.Size.X - return dims - }), - layout.Stacked(func(gtx C) D { - if tabs.selected != tabIdx { - return layout.Dimensions{} - } - tabHeight := gtx.Px(unit.Dp(4)) - tabRect := image.Rect(0, 0, tabWidth, tabHeight) - paint.FillShape(gtx.Ops, th.Palette.ContrastBg, clip.Rect(tabRect).Op()) - return layout.Dimensions{ - Size: image.Point{X: tabWidth, Y: tabHeight}, - } - }), - ) - }) - }), - layout.Flexed(1, func(gtx C) D { - return slider.Layout(gtx, func(gtx C) D { - fill(gtx, dynamicColor(tabs.selected), dynamicColor(tabs.selected+1)) - return layout.Center.Layout(gtx, - material.H1(th, fmt.Sprintf("Tab content #%d", tabs.selected+1)).Layout, - ) - }) - }), - ) -} - -func fill(gtx layout.Context, col1, col2 color.NRGBA) { - dr := image.Rectangle{Max: gtx.Constraints.Min} - paint.FillShape(gtx.Ops, - color.NRGBA{R: 0, G: 0, B: 0, A: 0xFF}, - clip.Rect(dr).Op(), - ) - - col2.R = byte(float32(col2.R)) - col2.G = byte(float32(col2.G)) - col2.B = byte(float32(col2.B)) - paint.LinearGradientOp{ - Stop1: f32.Pt(float32(dr.Min.X), 0), - Stop2: f32.Pt(float32(dr.Max.X), 0), - Color1: col1, - Color2: col2, - }.Add(gtx.Ops) - defer op.Push(gtx.Ops).Pop() - clip.Rect(dr).Add(gtx.Ops) - paint.PaintOp{}.Add(gtx.Ops) -} - -func dynamicColor(i int) color.NRGBA { - sn, cs := math.Sincos(float64(i) * math.Phi) - return color.NRGBA{ - R: 0xA0 + byte(0x30*sn), - G: 0xA0 + byte(0x30*cs), - B: 0xD0, - A: 0xFF, - } -} diff --git a/example/windows/windows.go b/example/windows/windows.go deleted file mode 100644 index 116441f2..00000000 --- a/example/windows/windows.go +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package main - -// Multiple windows in Gio. - -import ( - "log" - "os" - "sync/atomic" - - "gioui.org/app" - "gioui.org/io/event" - "gioui.org/io/system" - "gioui.org/layout" - "gioui.org/op" - "gioui.org/unit" - "gioui.org/widget" - "gioui.org/widget/material" - - "gioui.org/font/gofont" -) - -type window struct { - *app.Window - - more widget.Clickable - close widget.Clickable -} - -func main() { - newWindow() - app.Main() -} - -var windowCount int32 - -func newWindow() { - atomic.AddInt32(&windowCount, +1) - go func() { - w := new(window) - w.Window = app.NewWindow() - if err := w.loop(w.Events()); err != nil { - log.Fatal(err) - } - if c := atomic.AddInt32(&windowCount, -1); c == 0 { - os.Exit(0) - } - }() -} - -func (w *window) loop(events <-chan event.Event) error { - th := material.NewTheme(gofont.Collection()) - var ops op.Ops - for { - e := <-events - switch e := e.(type) { - case system.DestroyEvent: - return e.Err - case system.FrameEvent: - for w.more.Clicked() { - newWindow() - } - for w.close.Clicked() { - w.Close() - } - gtx := layout.NewContext(&ops, e) - - layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { - return layout.Flex{ - Alignment: layout.Middle, - }.Layout(gtx, - RigidInset(material.Button(th, &w.more, "More!").Layout), - RigidInset(material.Button(th, &w.close, "Close").Layout), - ) - }) - e.Frame(gtx.Ops) - } - } -} - -func RigidInset(w layout.Widget) layout.FlexChild { - return layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.UniformInset(unit.Sp(5)).Layout(gtx, w) - }) -}