~eliasnaur/gio-example

ref: ci gio-example/multiwindow/log.go -rw-r--r-- 1.9 KiB
bb9a341eElias Naur opengl: don't switch rendering threads 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// SPDX-License-Identifier: Unlicense OR MIT

package main

import (
	"fmt"

	"gioui.org/io/system"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/widget"
	"gioui.org/widget/material"
)

// Log shows a list of strings.
type Log struct {
	addLine chan string
	lines   []string

	close widget.Clickable
	list  widget.List
}

// NewLog crates a new log view.
func NewLog() *Log {
	return &Log{
		addLine: make(chan string, 100),
		list:    widget.List{List: layout.List{Axis: layout.Vertical}},
	}
}

// Printf adds a new line to the log.
func (log *Log) Printf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)

	// ensure that this logging does not block.
	select {
	case log.addLine <- s:
	default:
	}
}

// Run handles window loop for the log.
func (log *Log) Run(w *Window) error {
	var ops op.Ops

	applicationClose := w.App.Context.Done()
	for {
		select {
		case <-applicationClose:
			return nil
		// listen to new lines from Printf and add them to our lines.
		case line := <-log.addLine:
			log.lines = append(log.lines, line)
			w.Invalidate()
		case e := <-w.Events():
			switch e := e.(type) {
			case system.DestroyEvent:
				return e.Err
			case system.FrameEvent:
				gtx := layout.NewContext(&ops, e)
				log.Layout(w, w.App.Theme, gtx)
				e.Frame(gtx.Ops)
			}
		}
	}
}

// Layout displays the log with a close button.
func (log *Log) Layout(w *Window, th *material.Theme, gtx layout.Context) {
	// This is here to demonstrate programmatic closing of a window,
	// however it's probably better to use OS close button instead.
	for log.close.Clicked() {
		w.Window.Close()
	}

	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(material.Button(th, &log.close, "Close").Layout),
		layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
			return material.List(th, &log.list).Layout(gtx, len(log.lines), func(gtx layout.Context, i int) layout.Dimensions {
				return material.Body1(th, log.lines[i]).Layout(gtx)
			})
		}),
	)

}