tally/sheet.go

222 lines
4.6 KiB
Go

package main
import (
"fmt"
"strings"
)
type sheet struct {
name string
selection point
cells [][]cell
cols int
rows int
zoom int
rowOff int
colOff int
yankBuff cell
yankPoint point
}
func (s sheet) Draw(termCols, termRows int) {
var selected bool
rowDigits := DigitCount(len(s.cells))
width := (termCols - rowDigits) / s.zoom
if width * s.zoom + rowDigits + 1 > termCols {
width -= 1
}
// Print column header
fmt.Printf("%s ", strings.Repeat(" ", rowDigits))
for i := s.colOff+1; i <= s.colOff + s.zoom; i++ {
if i > s.cols {
break
}
pre := "\033[7m"
if i == s.selection.col {
pre = ""
}
fmt.Printf("%s%-*c\033[0m", pre, width, i+64)
}
fmt.Print("\n")
// Print Rows
for row, r := range s.cells[s.rowOff:] {
if row >= termRows-5 {
break
}
mod := "\033[7m"
if row + s.rowOff == s.selection.row-1 {
mod = ""
}
fmt.Printf("%s%-*d \033[0m", mod, rowDigits, row+1+s.rowOff)
// Print Cells
for col, cell := range r[s.colOff:] {
if col >= s.zoom {
break
}
selected = false
if s.selection.row-1 == row + s.rowOff && s.selection.col-1 == col + s.colOff {
selected = true
}
fmt.Printf(cell.String(width, selected))
}
fmt.Print("\n\033[2K")
}
}
func (s sheet) CurrentValue(raw bool) string {
if raw {
return s.cells[s.selection.row-1][s.selection.col-1].rawVal
}
return s.cells[s.selection.row-1][s.selection.col-1].mask
}
func (s *sheet) Recalculate() {
for row, _ := range s.cells {
for col, _ := range s.cells[row] {
// TODO do this concurrently
s.cells[row][col].Calculate()
}
}
}
func (s *sheet) AddRows(count int) {
for ;count > 0; count-- {
s.cells = append(s.cells, make([]cell, s.cols))
s.rows++
}
}
func (s *sheet) AddCols(count int) {
for ;count > 0; count-- {
for i, _ := range s.cells {
s.cells[i] = append(s.cells[i], cell{})
}
s.cols++
}
}
func (s *sheet) Yank() {
c := s.cells[s.selection.row-1][s.selection.col-1]
s.yankBuff = cell{}
s.yankBuff.kind = c.kind
s.yankBuff.rawVal = c.rawVal
s.yankBuff.num = c.num
s.yankBuff.mask = c.mask
s.yankBuff.expr = append(s.yankBuff.expr, c.expr...)
s.yankBuff.mods = append(s.yankBuff.mods, c.mods...)
s.yankPoint = point{row: s.selection.row-1, col: s.selection.col-1}
}
func (s *sheet) Paste() {
c := cell{}
c.kind = s.yankBuff.kind
c.rawVal = s.yankBuff.rawVal
c.num = s.yankBuff.num
c.mask = s.yankBuff.mask
c.expr = append(c.expr, s.yankBuff.expr...)
c.mods = append(c.mods, s.yankBuff.mods...)
s.cells[s.selection.row-1][s.selection.col-1] = c
}
func (s *sheet) PasteRelative() {
c := cell{}
c.kind = s.yankBuff.kind
c.rawVal = s.yankBuff.rawVal
c.num = s.yankBuff.num
c.mask = s.yankBuff.mask
c.expr = append(c.expr, s.yankBuff.expr...)
c.mods = append(c.mods, s.yankBuff.mods...)
if c.kind == Expr {
for i, v := range c.expr {
if IsAddr(v) {
refPoint := Addr2Point(v)
diff := point{row: s.yankPoint.row-s.selection.row+1, col: s.yankPoint.col-s.selection.col+1}
diffApply := point{row: refPoint.row-diff.row, col: refPoint.col-diff.col}
p2a := Point2Addr(diffApply)
c.expr[i] = p2a
}
}
c.rawVal = strings.Join(c.expr, " ")
}
s.cells[s.selection.row-1][s.selection.col-1] = c
}
func (s *sheet) moveSelection(dir rune, termRows int) {
switch dir {
case Left:
if s.selection.col > 1 {
s.selection.col--
}
if s.selection.col <= s.colOff {
s.colOff--
}
case Right:
s.selection.col++
if s.selection.col > s.cols && s.selection.col < 27 {
s.AddCols(1)
}
if s.selection.col > s.colOff + s.zoom && s.cols > s.zoom {
s.colOff++
}
if s.selection.col > 26 {
s.selection.col = 26
}
case Up:
if s.selection.row > 1 {
s.selection.row--
}
if s.selection.row <= s.rowOff {
s.rowOff--
}
case Down:
s.selection.row++
if s.selection.row > s.rows {
s.AddRows(1)
}
if s.selection.row > s.rowOff + termRows - 5 && s.rows > termRows - 5 {
s.rowOff++
}
case RowStart:
s.selection.col = 1
s.colOff = 0
case ToTop:
s.selection.row = 1
s.rowOff = 0
case RowEnd:
s.selection.col = s.cols
s.colOff = s.cols - s.zoom
if s.colOff < 0 {
s.colOff = 0
}
case ToBottom:
s.selection.row = s.rows
s.rowOff = s.rows - termRows + 5
if s.rowOff < 0 {
s.rowOff = 0
}
}
}
func (s *sheet) ZoomIn() {
if s.zoom == 1 {
return
}
s.zoom-- // Zooming in reduces number of cols viewed
}
func (s *sheet) ZoomOut() {
s.zoom++ // Zooming out increases number of cols viewed
}
func makeSheet(name string) sheet {
if name == "" {
name = "Sheet1"
}
row := make([][]cell,1, 26)
row[0] = make([]cell, 1, 26)
return sheet{name, point{1,1}, row, 1, 1, 6, 0, 0, cell{}, point{}}
}