~adnano/astronaut

ref: 5b2ba7d7bffd153f57a7eac22f172a5d4d56c6a9 astronaut/ui/ui.go -rw-r--r-- 1.6 KiB
5b2ba7d7Adnan Maolood ui/view: Remove focus variable 8 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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package ui

import (
	"os"
	"sync/atomic"

	"github.com/gdamore/tcell/v2"
)

var debug = os.Getenv("DEBUG") == "1"

// UI represents the user interface.
type UI struct {
	screen  tcell.Screen
	invalid int32
	exit    int32
}

// New returns a new UI that runs the provided application.
func New() (*UI, error) {
	var screen tcell.Screen
	if debug {
		screen = tcell.NewSimulationScreen("utf-8")
	} else {
		var err error
		screen, err = tcell.NewScreen()
		if err != nil {
			return nil, err
		}
	}

	if err := screen.Init(); err != nil {
		return nil, err
	}
	screen.Clear()
	screen.HideCursor()
	screen.EnableMouse()

	return &UI{
		screen:  screen,
		invalid: 1,
	}, nil
}

// Application represents an application.
type Application interface {
	Draw()
	Event(tcell.Event)
	Layout(x, y, w, h int)
}

// Init initializes the application.
func (u *UI) Init(app Application) {
	w, h := u.screen.Size()
	app.Layout(0, 0, w, h)
}

// Tick advances the UI by one tick.
func (u *UI) Tick(app Application) bool {
	var more bool

	if u.screen.HasPendingEvent() {
		event := u.screen.PollEvent()

		if event, ok := event.(*tcell.EventResize); ok {
			w, h := event.Size()
			app.Layout(0, 0, w, h)
		}

		app.Event(event)
		more = true
	}

	if atomic.SwapInt32(&u.invalid, 0) != 0 {
		u.screen.Clear()
		app.Draw()
		u.screen.Show()
		more = true
	}
	return more
}

// Close closes the UI.
func (u *UI) Close() {
	u.screen.Fini()
}

// Exiting reports whether the UI is exiting.
func (u *UI) Exiting() bool {
	return atomic.LoadInt32(&u.exit) == 1
}

// View returns a new view.
func (u *UI) View() *View {
	return &View{
		v:       u.screen,
		invalid: &u.invalid,
		exit:    &u.exit,
	}
}