/
ui.go
111 lines (100 loc) · 2.28 KB
/
ui.go
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
101
102
103
104
105
106
107
108
109
110
111
package client
import (
"os"
"strings"
"time"
ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
"github.com/gorilla/websocket"
)
type chatLayout struct {
// Grid
grid *ui.Grid
// Room widget storing chat members
room *widgets.List
// Chat output storing chat messages
output *widgets.List
// Message input
input *widgets.Paragraph
}
// Render UI layout
func renderLayout() (chatLayout, error) {
if err := ui.Init(); err != nil {
return chatLayout{}, err
}
termWidth, termHeight := ui.TerminalDimensions()
chatRoom := widgets.NewList()
chatOutput := widgets.NewList()
chatInput := widgets.NewParagraph()
grid := ui.NewGrid()
grid.SetRect(0, 0, termWidth, termHeight)
grid.Set(
ui.NewRow(1.0-0.2,
ui.NewCol(0.2, chatRoom),
ui.NewCol(1.0-0.2, chatOutput),
),
ui.NewRow(0.2, chatInput),
)
cl := chatLayout{
grid: grid,
room: chatRoom,
output: chatOutput,
input: chatInput,
}
ui.Render(cl.grid)
return cl, nil
}
// Handle UI keyboard events
func handleUiEvents(cl *chatLayout, c *client) error {
uiEvents := ui.PollEvents()
ticker := time.NewTicker(time.Second)
for {
select {
case e := <-uiEvents:
switch e.ID {
case "<Escape>", "<C-c>":
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
ui.Close()
os.Exit(0)
case "<Resize>":
payload := e.Payload.(ui.Resize)
width, height := payload.Width, payload.Height
cl.grid.SetRect(0, 0, width, height)
ui.Render(cl.grid)
}
switch e.Type {
case ui.KeyboardEvent:
switch e.ID {
case "<Up>":
cl.output.ScrollUp()
case "<Down>":
cl.output.ScrollDown()
case "<PageUp>":
cl.output.ScrollPageUp()
case "<PageDown>":
cl.output.ScrollPageDown()
case "<Home>":
cl.output.ScrollTop()
case "<End>":
cl.output.ScrollBottom()
case "<Backspace>":
if len(cl.input.Text) > 0 {
cl.input.Text = cl.input.Text[:len(cl.input.Text)-1]
}
case "<Enter>":
if err := c.conn.WriteMessage(websocket.TextMessage, []byte(strings.TrimSuffix(cl.input.Text, "\n"))); err != nil {
return err
}
cl.input.Text = ""
case "<Space>":
cl.input.Text += " "
default:
cl.input.Text += e.ID
}
ui.Render(cl.grid)
}
case <-ticker.C:
ui.Render(cl.grid)
}
}
}