forked from mop-tracker/mop
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathscreen.go
113 lines (93 loc) · 3.31 KB
/
screen.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
112
113
// Copyright (c) 2013-2021 by Michael Dvorkin, Brandon Lee Camilleri and contributors. All Rights Reserved. Use of this source code is governed by a MIT-style license that can be found in README.md.
package TerminalStocks
import (
"strings"
"github.com/nsf/termbox-go"
)
// Screen is thin wrapper aroung Termbox library to provide basic display capabilities as requied by TerminalStocks.
type Screen struct {
width int // Current number of columns.
height int // Current number of rows.
cleared bool // True after the screens gets cleared.
layout *Layout // Pointer to layout (gets created by screen).
markup *Markup // Pointer to markup processor (gets created by screen).
}
// Initializes Termbox, creates screen along with layout and markup, and calculates current screen dimensions. Once initialized the screen is ready for display.
func NewScreen() *Screen {
if err := termbox.Init(); err != nil {
panic(err)
}
screen := &Screen{}
screen.layout = NewLayout()
screen.markup = NewMarkup()
return screen.Resize()
}
// Close gets called upon program termination to close the Termbox.
func (screen *Screen) Close() *Screen {
termbox.Close()
return screen
}
// Resize gets called when the screen is being resized.
// It recalculates screen dimensions and requests to clear the screen on next update.
func (screen *Screen) Resize() *Screen {
screen.width, screen.height = termbox.Size()
screen.cleared = false
return screen
}
// Clear makes the entire screen blank using default background color.
func (screen *Screen) Clear() *Screen {
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
screen.cleared = true
return screen
}
// ClearLine erases the contents of the line starting from (x,y) coordinate till the end of the line.
func (screen *Screen) ClearLine(x int, y int) *Screen {
for i := x; i < screen.width; i++ {
termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
}
termbox.Flush()
return screen
}
// Draw accepts variable number of arguments and knows how to display the stock quotes, and an arbitrary string.
func (screen *Screen) Draw(objects ...interface{}) *Screen {
for _, ptr := range objects {
switch ptr.(type) {
case *Quotes:
object := ptr.(*Quotes)
screen.draw(screen.layout.Quotes(object.Fetch()))
default:
screen.draw(ptr.(string))
}
}
return screen
}
// DrawLine takes the incoming string, tokenizes it to extract markup elements, and displays it all starting at (x,y) location.
func (screen *Screen) DrawLine(x int, y int, str string) {
start, column := 0, 0
for _, token := range screen.markup.Tokenize(str) {
// First check if it's a tag. Tags are eaten up and not displayed.
if screen.markup.IsTag(token) {
continue
}
// Here comes the actual text: display it one character at a time.
for i, char := range token {
if !screen.markup.RightAligned {
start = x + column
column++
} else {
start = screen.width - len(token) + i
}
termbox.SetCell(start, y, char, screen.markup.Foreground, screen.markup.Background)
}
}
termbox.Flush()
}
// Underlying workhorse function that takes multiline string, splits it into lines, and displays them row by row.
func (screen *Screen) draw(str string) {
if !screen.cleared {
screen.Clear()
}
for row, line := range strings.Split(str, "\n") {
screen.DrawLine(0, row, line)
}
}