1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package views
16
17 import (
18 "sync"
19
20 "github.com/gdamore/tcell/v2"
21 )
22
23
24
25 type CellModel interface {
26 GetCell(x, y int) (rune, tcell.Style, []rune, int)
27 GetBounds() (int, int)
28 SetCursor(int, int)
29 GetCursor() (int, int, bool, bool)
30 MoveCursor(offx, offy int)
31 }
32
33
34
35 type CellView struct {
36 port *ViewPort
37 view View
38 content Widget
39 contentV *ViewPort
40 style tcell.Style
41 lines []string
42 model CellModel
43 once sync.Once
44
45 WidgetWatchers
46 }
47
48
49 func (a *CellView) Draw() {
50
51 port := a.port
52 model := a.model
53 port.Fill(' ', a.style)
54
55 if a.view == nil {
56 return
57 }
58 if model == nil {
59 return
60 }
61 vw, vh := a.view.Size()
62 for y := 0; y < vh; y++ {
63 for x := 0; x < vw; x++ {
64 a.view.SetContent(x, y, ' ', nil, a.style)
65 }
66 }
67
68 ex, ey := model.GetBounds()
69 vx, vy := port.Size()
70 if ex < vx {
71 ex = vx
72 }
73 if ey < vy {
74 ey = vy
75 }
76
77 cx, cy, en, sh := a.model.GetCursor()
78 for y := 0; y < ey; y++ {
79 for x := 0; x < ex; x++ {
80 ch, style, comb, wid := model.GetCell(x, y)
81 if ch == 0 {
82 ch = ' '
83 style = a.style
84 }
85 if en && x == cx && y == cy && sh {
86 style = style.Reverse(true)
87 }
88 port.SetContent(x, y, ch, comb, style)
89 x += wid - 1
90 }
91 }
92 }
93
94 func (a *CellView) keyUp() {
95 if _, _, en, _ := a.model.GetCursor(); !en {
96 a.port.ScrollUp(1)
97 return
98 }
99 a.model.MoveCursor(0, -1)
100 a.MakeCursorVisible()
101 }
102
103 func (a *CellView) keyDown() {
104 if _, _, en, _ := a.model.GetCursor(); !en {
105 a.port.ScrollDown(1)
106 return
107 }
108 a.model.MoveCursor(0, 1)
109 a.MakeCursorVisible()
110 }
111
112 func (a *CellView) keyLeft() {
113 if _, _, en, _ := a.model.GetCursor(); !en {
114 a.port.ScrollLeft(1)
115 return
116 }
117 a.model.MoveCursor(-1, 0)
118 a.MakeCursorVisible()
119 }
120
121 func (a *CellView) keyRight() {
122 if _, _, en, _ := a.model.GetCursor(); !en {
123 a.port.ScrollRight(1)
124 return
125 }
126 a.model.MoveCursor(+1, 0)
127 a.MakeCursorVisible()
128 }
129
130 func (a *CellView) keyPgUp() {
131 _, vy := a.port.Size()
132 if _, _, en, _ := a.model.GetCursor(); !en {
133 a.port.ScrollUp(vy)
134 return
135 }
136 a.model.MoveCursor(0, -vy)
137 a.MakeCursorVisible()
138 }
139
140 func (a *CellView) keyPgDn() {
141 _, vy := a.port.Size()
142 if _, _, en, _ := a.model.GetCursor(); !en {
143 a.port.ScrollDown(vy)
144 return
145 }
146 a.model.MoveCursor(0, +vy)
147 a.MakeCursorVisible()
148 }
149
150 func (a *CellView) keyHome() {
151 vx, vy := a.model.GetBounds()
152 if _, _, en, _ := a.model.GetCursor(); !en {
153 a.port.ScrollUp(vy)
154 a.port.ScrollLeft(vx)
155 return
156 }
157 a.model.SetCursor(0, 0)
158 a.MakeCursorVisible()
159 }
160
161 func (a *CellView) keyEnd() {
162 vx, vy := a.model.GetBounds()
163 if _, _, en, _ := a.model.GetCursor(); !en {
164 a.port.ScrollDown(vy)
165 a.port.ScrollRight(vx)
166 return
167 }
168 a.model.SetCursor(vx, vy)
169 a.MakeCursorVisible()
170 }
171
172
173
174 func (a *CellView) MakeCursorVisible() {
175 if a.model == nil {
176 return
177 }
178 x, y, enabled, _ := a.model.GetCursor()
179 if enabled {
180 a.MakeVisible(x, y)
181 }
182 }
183
184
185
186 func (a *CellView) HandleEvent(e tcell.Event) bool {
187 if a.model == nil {
188 return false
189 }
190 switch e := e.(type) {
191 case *tcell.EventKey:
192 switch e.Key() {
193 case tcell.KeyUp, tcell.KeyCtrlP:
194 a.keyUp()
195 return true
196 case tcell.KeyDown, tcell.KeyCtrlN:
197 a.keyDown()
198 return true
199 case tcell.KeyRight, tcell.KeyCtrlF:
200 a.keyRight()
201 return true
202 case tcell.KeyLeft, tcell.KeyCtrlB:
203 a.keyLeft()
204 return true
205 case tcell.KeyPgDn:
206 a.keyPgDn()
207 return true
208 case tcell.KeyPgUp:
209 a.keyPgUp()
210 return true
211 case tcell.KeyEnd:
212 a.keyEnd()
213 return true
214 case tcell.KeyHome:
215 a.keyHome()
216 return true
217 }
218 }
219 return false
220 }
221
222
223 func (a *CellView) Size() (int, int) {
224
225 w, h := a.model.GetBounds()
226
227 if w < 2 {
228 w = 2
229 }
230 if h < 2 {
231 h = 2
232 }
233 return w, h
234 }
235
236
237 func (a *CellView) GetModel() CellModel {
238 return a.model
239 }
240
241
242 func (a *CellView) SetModel(model CellModel) {
243 w, h := model.GetBounds()
244 a.model = model
245 a.port.SetContentSize(w, h, true)
246 a.port.ValidateView()
247 a.PostEventWidgetContent(a)
248 }
249
250
251 func (a *CellView) SetView(view View) {
252 port := a.port
253 port.SetView(view)
254 a.view = view
255 if view == nil {
256 return
257 }
258 width, height := view.Size()
259 a.port.Resize(0, 0, width, height)
260 if a.model != nil {
261 w, h := a.model.GetBounds()
262 a.port.SetContentSize(w, h, true)
263 }
264 a.Resize()
265 }
266
267
268
269 func (a *CellView) Resize() {
270
271 width, height := a.view.Size()
272 a.port.Resize(0, 0, width, height)
273 a.port.ValidateView()
274 a.MakeCursorVisible()
275 }
276
277
278 func (a *CellView) SetCursor(x, y int) {
279 a.model.SetCursor(x, y)
280 }
281
282
283 func (a *CellView) SetCursorX(x int) {
284 _, y, _, _ := a.model.GetCursor()
285 a.SetCursor(x, y)
286 }
287
288
289 func (a *CellView) SetCursorY(y int) {
290 x, _, _, _ := a.model.GetCursor()
291 a.SetCursor(x, y)
292 }
293
294
295
296 func (a *CellView) MakeVisible(x, y int) {
297 a.port.MakeVisible(x, y)
298 }
299
300
301 func (a *CellView) SetStyle(s tcell.Style) {
302 a.style = s
303 }
304
305
306 func (a *CellView) Init() {
307 a.once.Do(func() {
308 a.port = NewViewPort(nil, 0, 0, 0, 0)
309 a.style = tcell.StyleDefault
310 })
311 }
312
313
314 func NewCellView() *CellView {
315 cv := &CellView{}
316 cv.Init()
317 return cv
318 }
319
View as plain text