ginger/gim/main.go
2017-11-02 16:45:10 -06:00

281 lines
4.6 KiB
Go

package main
import (
"fmt"
"math/rand"
"os"
"os/signal"
"strings"
"time"
"github.com/buger/goterm"
)
const (
// Reset all custom styles
ansiReset = "\033[0m"
// Reset to default color
ansiResetColor = "\033[32m"
// Return curor to start of line and clean it
ansiResetLine = "\r\033[K"
)
// List of possible colors
const (
black = iota
red
green
yellow
blue
magenta
cyan
white
)
func getFgColor(code int) string {
return fmt.Sprintf("\033[3%dm", code)
}
func getBgColor(code int) string {
return fmt.Sprintf("\033[4%dm", code)
}
func fgColor(str string, color int) string {
return fmt.Sprintf("%s%s%s", getFgColor(color), str, ansiReset)
}
func bgColor(str string, color int) string {
return fmt.Sprintf("%s%s%s", getBgColor(color), str, ansiReset)
}
type xy [2]int
func (p xy) x() int {
return p[0]
}
func (p xy) y() int {
return p[1]
}
func (p xy) add(p2 xy) xy {
p[0] += p2[0]
p[1] += p2[1]
return p
}
////////////////////////////////////////////////////////////////////////////////
type terminal struct {
cursorPos xy
}
func (t *terminal) moveAbs(to xy) {
t.cursorPos = to
goterm.MoveCursor(to.x()+1, to.y()+1)
}
func (t *terminal) size() xy {
return xy{goterm.Width(), goterm.Height()}
}
////////////////////////////////////////////////////////////////////////////////
const (
boxBorderHoriz = iota
boxBorderVert
boxBorderTL
boxBorderTR
boxBorderBL
boxBorderBR
)
var boxDefault = []string{
"─",
"│",
"┌",
"┐",
"└",
"┘",
}
type box struct {
pos xy
size xy // if unset, auto-determined
body string
transparent bool
}
func (b box) lines() []string {
lines := strings.Split(b.body, "\n")
// if the last line is empty don't include it, it means there was a trailing
// newline (or the whole string is empty)
if lines[len(lines)-1] == "" {
lines = lines[:len(lines)-1]
}
return lines
}
func (b box) getSize() xy {
if b.size != (xy{}) {
return b.size
}
var size xy
for _, line := range b.lines() {
size[1]++
if l := len(line); l > size[0] {
size[0] = l
}
}
return size
}
func (b box) draw(term *terminal) {
chars := boxDefault
pos := b.pos
size := b.getSize()
w, h := size.x(), size.y()
// draw top line
term.moveAbs(pos)
goterm.Print(chars[boxBorderTL])
for i := 0; i < w; i++ {
goterm.Print(chars[boxBorderHoriz])
}
goterm.Print(chars[boxBorderTR])
drawLine := func(line string) {
pos[1]++
term.moveAbs(pos)
goterm.Print(chars[boxBorderVert])
if len(line) > w {
line = line[:w]
}
goterm.Print(line)
if b.transparent {
term.moveAbs(pos.add(xy{w + 1, 0}))
} else {
goterm.Print(strings.Repeat(" ", w-len(line)))
}
goterm.Print(chars[boxBorderVert])
}
// truncate lines if necessary
lines := b.lines()
if len(lines) > h {
lines = lines[:h]
}
// draw body
for _, line := range lines {
drawLine(line)
}
// draw empty lines
for i := 0; i < h-len(lines); i++ {
drawLine("")
}
// draw bottom line
pos[1]++
term.moveAbs(pos)
goterm.Print(chars[boxBorderBL])
for i := 0; i < w; i++ {
goterm.Print(chars[boxBorderHoriz])
}
goterm.Print(chars[boxBorderBR])
}
////////////////////////////////////////////////////////////////////////////////
const (
framerate = 30
frameperiod = time.Second / time.Duration(framerate)
)
func debugf(str string, args ...interface{}) {
fmt.Fprintf(os.Stderr, str, args...)
}
func main() {
rand.Seed(time.Now().UnixNano())
{ // exit signal handling, cause ctrl-c doesn't work with goterm otherwise
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
goterm.Clear()
goterm.Flush()
os.Stdout.Sync()
os.Exit(0)
}()
}
term := new(terminal)
type movingBox struct {
box
xRight bool
yDown bool
}
randBox := func() movingBox {
tsize := term.size()
return movingBox{
box: box{
pos: xy{rand.Intn(tsize[0]), rand.Intn(tsize[1])},
},
xRight: rand.Intn(1) == 0,
yDown: rand.Intn(1) == 0,
}
}
boxes := []movingBox{
randBox(),
randBox(),
randBox(),
randBox(),
randBox(),
}
for range time.Tick(frameperiod) {
goterm.Clear()
termSize := term.size()
now := time.Now()
for i := range boxes {
b := &boxes[i]
b.body = fmt.Sprintf("%d\n%s", now.Unix(), now.String())
size := b.getSize()
if b.pos[0] <= 0 {
b.xRight = true
} else if b.pos[0]+size[0]+2 > termSize[0] {
b.xRight = false
}
if b.pos[1] <= 0 {
b.yDown = true
} else if b.pos[1]+size[1]+2 > termSize[1] {
b.yDown = false
}
if b.xRight {
b.pos[0] += 3
} else {
b.pos[0] -= 3
}
if b.yDown {
b.pos[1]++
} else {
b.pos[1]--
}
b.draw(term)
}
goterm.Flush()
}
}