|
|
@ -10,16 +10,19 @@ import ( |
|
|
|
`time` |
|
|
|
`time` |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// Screen ...
|
|
|
|
// Screen is thin wrapper aroung Termbox library to provide basic display
|
|
|
|
|
|
|
|
// capabilities as requied by Mop.
|
|
|
|
type Screen struct { |
|
|
|
type Screen struct { |
|
|
|
width int |
|
|
|
width int // Current number of columns.
|
|
|
|
height int |
|
|
|
height int // Current number of rows.
|
|
|
|
cleared bool |
|
|
|
cleared bool // True after the screens gets cleared.
|
|
|
|
layout *Layout |
|
|
|
layout *Layout // Pointer to layout (gets created by screen).
|
|
|
|
markup *Markup |
|
|
|
markup *Markup // Pointer to markup processor (gets created by screen).
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Initialize ...
|
|
|
|
// Initialize loads the Termbox, allocates and initializes layout and markup,
|
|
|
|
|
|
|
|
// and calculates current screen dimensions. Once initialized the screen is
|
|
|
|
|
|
|
|
// ready for display.
|
|
|
|
func (screen *Screen) Initialize() *Screen { |
|
|
|
func (screen *Screen) Initialize() *Screen { |
|
|
|
if err := termbox.Init(); err != nil { |
|
|
|
if err := termbox.Init(); err != nil { |
|
|
|
panic(err) |
|
|
|
panic(err) |
|
|
@ -30,14 +33,15 @@ func (screen *Screen) Initialize() *Screen { |
|
|
|
return screen.Resize() |
|
|
|
return screen.Resize() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Close ...
|
|
|
|
// Close gets called upon program termination to close the Termbox.
|
|
|
|
func (screen *Screen) Close() *Screen { |
|
|
|
func (screen *Screen) Close() *Screen { |
|
|
|
termbox.Close() |
|
|
|
termbox.Close() |
|
|
|
|
|
|
|
|
|
|
|
return screen |
|
|
|
return screen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Resize ...
|
|
|
|
// 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 { |
|
|
|
func (screen *Screen) Resize() *Screen { |
|
|
|
screen.width, screen.height = termbox.Size() |
|
|
|
screen.width, screen.height = termbox.Size() |
|
|
|
screen.cleared = false |
|
|
|
screen.cleared = false |
|
|
@ -45,7 +49,7 @@ func (screen *Screen) Resize() *Screen { |
|
|
|
return screen |
|
|
|
return screen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Clear ...
|
|
|
|
// Clear makes the entire screen blank using default background color.
|
|
|
|
func (screen *Screen) Clear() *Screen { |
|
|
|
func (screen *Screen) Clear() *Screen { |
|
|
|
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) |
|
|
|
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) |
|
|
|
screen.cleared = true |
|
|
|
screen.cleared = true |
|
|
@ -53,16 +57,19 @@ func (screen *Screen) Clear() *Screen { |
|
|
|
return screen |
|
|
|
return screen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ClearLine ...
|
|
|
|
// ClearLine erases the contents of the line starting from (x,y) coordinate
|
|
|
|
func (screen *Screen) ClearLine(x int, y int) { |
|
|
|
// till the end of the line.
|
|
|
|
|
|
|
|
func (screen *Screen) ClearLine(x int, y int) *Screen { |
|
|
|
for i := x; i < screen.width; i++ { |
|
|
|
for i := x; i < screen.width; i++ { |
|
|
|
termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault) |
|
|
|
termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
termbox.Flush() |
|
|
|
termbox.Flush() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return screen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Draw ...
|
|
|
|
// Draw accepts variable number of arguments and knows how to display the
|
|
|
|
|
|
|
|
// market data, stock quotes, current time, and an arbitrary string.
|
|
|
|
func (screen *Screen) Draw(objects ...interface{}) *Screen { |
|
|
|
func (screen *Screen) Draw(objects ...interface{}) *Screen { |
|
|
|
for _, ptr := range objects { |
|
|
|
for _, ptr := range objects { |
|
|
|
switch ptr.(type) { |
|
|
|
switch ptr.(type) { |
|
|
@ -83,27 +90,33 @@ func (screen *Screen) Draw(objects ...interface{}) *Screen { |
|
|
|
return screen |
|
|
|
return screen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// DrawLine ...
|
|
|
|
// 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) { |
|
|
|
func (screen *Screen) DrawLine(x int, y int, str string) { |
|
|
|
start, column := 0, 0 |
|
|
|
start, column := 0, 0 |
|
|
|
|
|
|
|
|
|
|
|
for _, token := range screen.markup.Tokenize(str) { |
|
|
|
for _, token := range screen.markup.Tokenize(str) { |
|
|
|
if !screen.markup.IsTag(token) { |
|
|
|
// First check if it's a tag. Tags are eaten up and not displayed.
|
|
|
|
for i, char := range token { |
|
|
|
if screen.markup.IsTag(token) { |
|
|
|
if !screen.markup.RightAligned { |
|
|
|
continue |
|
|
|
start = x + column |
|
|
|
} |
|
|
|
column++ |
|
|
|
|
|
|
|
} else { |
|
|
|
// Here comes the actual text: display it one character at a time.
|
|
|
|
start = screen.width - len(token) + i |
|
|
|
for i, char := range token { |
|
|
|
} |
|
|
|
if !screen.markup.RightAligned { |
|
|
|
termbox.SetCell(start, y, char, screen.markup.Foreground, screen.markup.Background) |
|
|
|
start = x + column |
|
|
|
|
|
|
|
column++ |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
start = screen.width - len(token) + i |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
termbox.SetCell(start, y, char, screen.markup.Foreground, screen.markup.Background) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
termbox.Flush() |
|
|
|
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) { |
|
|
|
func (screen *Screen) draw(str string) { |
|
|
|
if !screen.cleared { |
|
|
|
if !screen.cleared { |
|
|
|
screen.Clear() |
|
|
|
screen.Clear() |
|
|
|