// Display a window of the sheet using termbox. // // The top-left changes based on where in the sheet the selected cell is moved by movement commands. func (s *Sheet) display() { if s.loading { return } defer termbox.Flush() displayWidth, displayHeight := termbox.Size() selectedRow, selectedCol := s.SelectedCell.RowCol() // Column Headers rowStr := fmt.Sprintf("%3d", s.startRow+displayHeight) x := 0 for x <= len(rowStr) { termbox.SetCell(x, DISPLAY_SHEET_START_ROW, ' ', termbox.ColorWhite, termbox.ColorWhite) x++ } startDispColumn := x displayColumns := 0 columnAddr := NewAddress(0, s.startCol) for column := s.startCol; x+s.getColumnWidth(columnAddr.ColumnHeader()) < displayWidth; column++ { columnAddr = NewAddress(0, column) display.DisplayValue(columnAddr.ColumnHeader(), DISPLAY_SHEET_START_ROW, x, x+s.getColumnWidth(columnAddr.ColumnHeader()), align.AlignCenter, selectedCol != column) x += s.getColumnWidth(columnAddr.ColumnHeader()) displayColumns = column - s.startCol + 1 } displayRows := 0 y := DISPLAY_SHEET_START_ROW + 1 for row := s.startRow; y < displayHeight; y++ { rowStr := fmt.Sprintf("%3d", row) display.DisplayValue(rowStr, y, 0, len(rowStr)-1, align.AlignRight, selectedRow != row) displayRows = row - s.startRow + 1 row++ } termCol := startDispColumn for column := 0; column < displayColumns; column++ { valCol := column + s.startCol for row := 0; row < displayRows; row++ { valRow := row + s.startRow address := NewAddress(valRow, valCol) if cell, err := s.GetCell(address); err == nil { cell.display(s, address, row+DISPLAY_SHEET_START_ROW+1, termCol, termCol+s.getColumnWidth(address.ColumnHeader()), s.SelectedCell == address) } else { display.DisplayValue("", row+DISPLAY_SHEET_START_ROW+1, termCol, termCol+s.getColumnWidth(address.ColumnHeader()), align.AlignLeft, false) } } columnAddr := NewAddress(0, valCol) termCol += s.getColumnWidth(columnAddr.ColumnHeader()) } s.displayRows, s.displayCols = displayRows, displayColumns }
// Displays cell value using termbox. func (c *Cell) display(s *Sheet, address Address, row, colStart, colEnd int, selected bool) { dispVal := c.value if !c.stringType { dispVal = c.getDisplayValue(s, address) } display.DisplayValue(dispVal, row, colStart, colEnd, c.alignment, selected) }
// Processes all the key strokes from termbox. // // Also refreshes the two top rows the the display. The status bar and the command row. func processTermboxEvents(s *sheet.Sheet) { prompt := "" stringEntry := false smode := NORMAL_MODE valBuffer := bytes.Buffer{} insAlign := align.AlignRight // Display go func() { for _ = range time.Tick(200 * time.Millisecond) { switch smode { case FORMAT_MODE: display.DisplayValue(fmt.Sprintf("Current format is %s", s.DisplayFormat(s.SelectedCell)), 1, 0, 80, align.AlignLeft, false) fallthrough case NORMAL_MODE: selSel, _ := s.GetCell(s.SelectedCell) display.DisplayValue(fmt.Sprintf("%s (%s) [%s]", s.SelectedCell, s.DisplayFormat(s.SelectedCell), selSel.StatusBarVal()), 0, 0, 80, align.AlignLeft, false) case INSERT_MODE: display.DisplayValue(fmt.Sprintf("i> %s %s = %s", prompt, s.SelectedCell, valBuffer.String()), 0, 0, 80, align.AlignLeft, false) case EXIT_MODE: display.DisplayValue(fmt.Sprintf("File \"%s\" is modified, save before exiting?", s.Filename), 0, 0, 80, align.AlignLeft, false) case YANK_MODE: display.DisplayValue("Yank row/column: r: row c: column", 0, 0, 80, align.AlignLeft, false) case PUT_MODE: display.DisplayValue("Put row/column: r: row c: column", 0, 0, 80, align.AlignLeft, false) } termbox.Flush() } }() // Events for ev := termbox.PollEvent(); ev.Type != termbox.EventError; ev = termbox.PollEvent() { switch ev.Type { case termbox.EventKey: switch smode { case NORMAL_MODE: switch ev.Key { case termbox.KeyArrowUp: s.MoveUp() case termbox.KeyArrowDown: s.MoveDown() case termbox.KeyArrowLeft: s.MoveLeft() case termbox.KeyArrowRight: s.MoveRight() case 0: switch ev.Ch { case 'q': smode = EXIT_MODE case '=', 'i': smode = INSERT_MODE prompt = "let" insAlign = align.AlignRight case '<': prompt = "leftstring" smode = INSERT_MODE insAlign = align.AlignLeft stringEntry = true case '>': prompt = "rightstring" smode = INSERT_MODE insAlign = align.AlignRight stringEntry = true case '\\': prompt = "label" smode = INSERT_MODE insAlign = align.AlignCenter stringEntry = true case 'h': s.MoveLeft() case 'j': s.MoveDown() case 'k': s.MoveUp() case 'l': s.MoveRight() case 'x': s.ClearCell(s.SelectedCell) case 'y': smode = YANK_MODE case 'p': smode = PUT_MODE case 'f': smode = FORMAT_MODE } } case INSERT_MODE: if ev.Key == termbox.KeyEnter { s.SetCell(s.SelectedCell, sheet.NewCell(valBuffer.String(), insAlign, stringEntry)) valBuffer.Reset() smode = NORMAL_MODE stringEntry = false } else if ev.Key == termbox.KeyEsc { valBuffer.Reset() smode = NORMAL_MODE stringEntry = false } else if ev.Key == termbox.KeyBackspace { s := valBuffer.String() valBuffer = bytes.Buffer{} if len(s) > 0 { s = s[0 : len(s)-1] } valBuffer.WriteString(s) } else { valBuffer.WriteRune(ev.Ch) } case EXIT_MODE: if ev.Key == 0 && ev.Ch == 'y' { s.Save() } termbox.Close() return case YANK_MODE: if ev.Key == 0 && ev.Ch == 'r' { s.YankRow() } else if ev.Key == 0 && ev.Ch == 'c' { s.YankColumn() } smode = NORMAL_MODE case PUT_MODE: if ev.Key == 0 && ev.Ch == 'r' { s.PutRow() } else if ev.Key == 0 && ev.Ch == 'c' { s.PutColumn() } smode = NORMAL_MODE case FORMAT_MODE: switch ev.Key { case termbox.KeyEsc, termbox.KeyEnter: smode = NORMAL_MODE case termbox.KeyArrowLeft: s.DecreaseColumnWidth(s.SelectedCell.ColumnHeader()) case termbox.KeyArrowRight: s.IncreaseColumnWidth(s.SelectedCell.ColumnHeader()) case termbox.KeyArrowDown: s.DecreaseColumnPrecision(s.SelectedCell.ColumnHeader()) case termbox.KeyArrowUp: s.IncreaseColumnPrecision(s.SelectedCell.ColumnHeader()) case 0: switch ev.Ch { case 'q': smode = NORMAL_MODE case '<', 'h': s.DecreaseColumnWidth(s.SelectedCell.ColumnHeader()) case '>', 'l': s.IncreaseColumnWidth(s.SelectedCell.ColumnHeader()) case '-', 'j': s.DecreaseColumnPrecision(s.SelectedCell.ColumnHeader()) case '+', 'k': s.IncreaseColumnPrecision(s.SelectedCell.ColumnHeader()) } } // Once switched out of format mode, clear the format prompt line. if smode == NORMAL_MODE { display.DisplayValue("", 1, 0, 80, align.AlignLeft, false) } } } } }