From 331597b9f8a7942cbcb233a328301e4d5bf94fb0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 11 Jan 2019 23:28:47 +0200 Subject: Switch to Go modules and make other changes --- vendor/maunium.net/go/tview/table.go | 1096 ---------------------------------- 1 file changed, 1096 deletions(-) delete mode 100644 vendor/maunium.net/go/tview/table.go (limited to 'vendor/maunium.net/go/tview/table.go') diff --git a/vendor/maunium.net/go/tview/table.go b/vendor/maunium.net/go/tview/table.go deleted file mode 100644 index 6c636e7..0000000 --- a/vendor/maunium.net/go/tview/table.go +++ /dev/null @@ -1,1096 +0,0 @@ -package tview - -import ( - "sort" - - "maunium.net/go/tcell" - colorful "github.com/lucasb-eyer/go-colorful" -) - -// TableCell represents one cell inside a Table. You can instantiate this type -// directly but all colors (background and text) will be set to their default -// which is black. -type TableCell struct { - // The text to be displayed in the table cell. - Text string - - // The alignment of the cell text. One of AlignLeft (default), AlignCenter, - // or AlignRight. - Align int - - // The maximum width of the cell in screen space. This is used to give a - // column a maximum width. Any cell text whose screen width exceeds this width - // is cut off. Set to 0 if there is no maximum width. - MaxWidth int - - // If the total table width is less than the available width, this value is - // used to add extra width to a column. See SetExpansion() for details. - Expansion int - - // The color of the cell text. - Color tcell.Color - - // The background color of the cell. - BackgroundColor tcell.Color - - // The style attributes of the cell. - Attributes tcell.AttrMask - - // If set to true, this cell cannot be selected. - NotSelectable bool - - // The position and width of the cell the last time table was drawn. - x, y, width int -} - -// NewTableCell returns a new table cell with sensible defaults. That is, left -// aligned text with the primary text color (see Styles) and a transparent -// background (using the background of the Table). -func NewTableCell(text string) *TableCell { - return &TableCell{ - Text: text, - Align: AlignLeft, - Color: Styles.PrimaryTextColor, - BackgroundColor: tcell.ColorDefault, - } -} - -// SetText sets the cell's text. -func (c *TableCell) SetText(text string) *TableCell { - c.Text = text - return c -} - -// SetAlign sets the cell's text alignment, one of AlignLeft, AlignCenter, or -// AlignRight. -func (c *TableCell) SetAlign(align int) *TableCell { - c.Align = align - return c -} - -// SetMaxWidth sets maximum width of the cell in screen space. This is used to -// give a column a maximum width. Any cell text whose screen width exceeds this -// width is cut off. Set to 0 if there is no maximum width. -func (c *TableCell) SetMaxWidth(maxWidth int) *TableCell { - c.MaxWidth = maxWidth - return c -} - -// SetExpansion sets the value by which the column of this cell expands if the -// available width for the table is more than the table width (prior to applying -// this expansion value). This is a proportional value. The amount of unused -// horizontal space is divided into widths to be added to each column. How much -// extra width a column receives depends on the expansion value: A value of 0 -// (the default) will not cause the column to increase in width. Other values -// are proportional, e.g. a value of 2 will cause a column to grow by twice -// the amount of a column with a value of 1. -// -// Since this value affects an entire column, the maximum over all visible cells -// in that column is used. -// -// This function panics if a negative value is provided. -func (c *TableCell) SetExpansion(expansion int) *TableCell { - if expansion < 0 { - panic("Table cell expansion values may not be negative") - } - c.Expansion = expansion - return c -} - -// SetTextColor sets the cell's text color. -func (c *TableCell) SetTextColor(color tcell.Color) *TableCell { - c.Color = color - return c -} - -// SetBackgroundColor sets the cell's background color. Set to -// tcell.ColorDefault to use the table's background color. -func (c *TableCell) SetBackgroundColor(color tcell.Color) *TableCell { - c.BackgroundColor = color - return c -} - -// SetAttributes sets the cell's text attributes. You can combine different -// attributes using bitmask operations: -// -// cell.SetAttributes(tcell.AttrUnderline | tcell.AttrBold) -func (c *TableCell) SetAttributes(attr tcell.AttrMask) *TableCell { - c.Attributes = attr - return c -} - -// SetStyle sets the cell's style (foreground color, background color, and -// attributes) all at once. -func (c *TableCell) SetStyle(style tcell.Style) *TableCell { - c.Color, c.BackgroundColor, c.Attributes = style.Decompose() - return c -} - -// SetSelectable sets whether or not this cell can be selected by the user. -func (c *TableCell) SetSelectable(selectable bool) *TableCell { - c.NotSelectable = !selectable - return c -} - -// GetLastPosition returns the position of the table cell the last time it was -// drawn on screen. If the cell is not on screen, the return values are -// undefined. -// -// Because the Table class will attempt to keep selected cells on screen, this -// function is most useful in response to a "selected" event (see -// SetSelectedFunc()) or a "selectionChanged" event (see -// SetSelectionChangedFunc()). -func (c *TableCell) GetLastPosition() (x, y, width int) { - return c.x, c.y, c.width -} - -// Table visualizes two-dimensional data consisting of rows and columns. Each -// Table cell is defined via SetCell() by the TableCell type. They can be added -// dynamically to the table and changed any time. -// -// The most compact display of a table is without borders. Each row will then -// occupy one row on screen and columns are separated by the rune defined via -// SetSeparator() (a space character by default). -// -// When borders are turned on (via SetBorders()), each table cell is surrounded -// by lines. Therefore one table row will require two rows on screen. -// -// Columns will use as much horizontal space as they need. You can constrain -// their size with the MaxWidth parameter of the TableCell type. -// -// Fixed Columns -// -// You can define fixed rows and rolumns via SetFixed(). They will always stay -// in their place, even when the table is scrolled. Fixed rows are always the -// top rows. Fixed columns are always the leftmost columns. -// -// Selections -// -// You can call SetSelectable() to set columns and/or rows to "selectable". If -// the flag is set only for columns, entire columns can be selected by the user. -// If it is set only for rows, entire rows can be selected. If both flags are -// set, individual cells can be selected. The "selected" handler set via -// SetSelectedFunc() is invoked when the user presses Enter on a selection. -// -// Navigation -// -// If the table extends beyond the available space, it can be navigated with -// key bindings similar to Vim: -// -// - h, left arrow: Move left by one column. -// - l, right arrow: Move right by one column. -// - j, down arrow: Move down by one row. -// - k, up arrow: Move up by one row. -// - g, home: Move to the top. -// - G, end: Move to the bottom. -// - Ctrl-F, page down: Move down by one page. -// - Ctrl-B, page up: Move up by one page. -// -// When there is no selection, this affects the entire table (except for fixed -// rows and columns). When there is a selection, the user moves the selection. -// The class will attempt to keep the selection from moving out of the screen. -// -// Use SetInputCapture() to override or modify keyboard input. -// -// See https://github.com/rivo/tview/wiki/Table for an example. -type Table struct { - *Box - - // Whether or not this table has borders around each cell. - borders bool - - // The color of the borders or the separator. - bordersColor tcell.Color - - // If there are no borders, the column separator. - separator rune - - // The cells of the table. Rows first, then columns. - cells [][]*TableCell - - // The rightmost column in the data set. - lastColumn int - - // The number of fixed rows / columns. - fixedRows, fixedColumns int - - // Whether or not rows or columns can be selected. If both are set to true, - // cells can be selected. - rowsSelectable, columnsSelectable bool - - // The currently selected row and column. - selectedRow, selectedColumn int - - // The number of rows/columns by which the table is scrolled down/to the - // right. - rowOffset, columnOffset int - - // If set to true, the table's last row will always be visible. - trackEnd bool - - // The number of visible rows the last time the table was drawn. - visibleRows int - - // The style of the selected rows. If this value is 0, selected rows are - // simply inverted. - selectedStyle tcell.Style - - // An optional function which gets called when the user presses Enter on a - // selected cell. If entire rows selected, the column value is undefined. - // Likewise for entire columns. - selected func(row, column int) - - // An optional function which gets called when the user changes the selection. - // If entire rows selected, the column value is undefined. - // Likewise for entire columns. - selectionChanged func(row, column int) - - // An optional function which gets called when the user presses Escape, Tab, - // or Backtab. Also when the user presses Enter if nothing is selectable. - done func(key tcell.Key) -} - -// NewTable returns a new table. -func NewTable() *Table { - return &Table{ - Box: NewBox(), - bordersColor: Styles.GraphicsColor, - separator: ' ', - lastColumn: -1, - } -} - -// Clear removes all table data. -func (t *Table) Clear() *Table { - t.cells = nil - t.lastColumn = -1 - return t -} - -// SetBorders sets whether or not each cell in the table is surrounded by a -// border. -func (t *Table) SetBorders(show bool) *Table { - t.borders = show - return t -} - -// SetBordersColor sets the color of the cell borders. -func (t *Table) SetBordersColor(color tcell.Color) *Table { - t.bordersColor = color - return t -} - -// SetSelectedStyle sets a specific style for selected cells. If no such style -// is set, per default, selected cells are inverted (i.e. their foreground and -// background colors are swapped). -// -// To reset a previous setting to its default, make the following call: -// -// table.SetSelectedStyle(tcell.ColorDefault, tcell.ColorDefault, 0) -func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, attributes tcell.AttrMask) *Table { - t.selectedStyle = tcell.StyleDefault.Foreground(foregroundColor).Background(backgroundColor) | tcell.Style(attributes) - return t -} - -// SetSeparator sets the character used to fill the space between two -// neighboring cells. This is a space character ' ' per default but you may -// want to set it to Borders.Vertical (or any other rune) if the column -// separation should be more visible. If cell borders are activated, this is -// ignored. -// -// Separators have the same color as borders. -func (t *Table) SetSeparator(separator rune) *Table { - t.separator = separator - return t -} - -// SetFixed sets the number of fixed rows and columns which are always visible -// even when the rest of the cells are scrolled out of view. Rows are always the -// top-most ones. Columns are always the left-most ones. -func (t *Table) SetFixed(rows, columns int) *Table { - t.fixedRows, t.fixedColumns = rows, columns - return t -} - -// SetSelectable sets the flags which determine what can be selected in a table. -// There are three selection modi: -// -// - rows = false, columns = false: Nothing can be selected. -// - rows = true, columns = false: Rows can be selected. -// - rows = false, columns = true: Columns can be selected. -// - rows = true, columns = true: Individual cells can be selected. -func (t *Table) SetSelectable(rows, columns bool) *Table { - t.rowsSelectable, t.columnsSelectable = rows, columns - return t -} - -// GetSelectable returns what can be selected in a table. Refer to -// SetSelectable() for details. -func (t *Table) GetSelectable() (rows, columns bool) { - return t.rowsSelectable, t.columnsSelectable -} - -// GetSelection returns the position of the current selection. -// If entire rows are selected, the column index is undefined. -// Likewise for entire columns. -func (t *Table) GetSelection() (row, column int) { - return t.selectedRow, t.selectedColumn -} - -// Select sets the selected cell. Depending on the selection settings -// specified via SetSelectable(), this may be an entire row or column, or even -// ignored completely. -func (t *Table) Select(row, column int) *Table { - t.selectedRow, t.selectedColumn = row, column - return t -} - -// SetOffset sets how many rows and columns should be skipped when drawing the -// table. This is useful for large tables that do not fit on the screen. -// Navigating a selection can change these values. -// -// Fixed rows and columns are never skipped. -func (t *Table) SetOffset(row, column int) *Table { - t.rowOffset, t.columnOffset = row, column - return t -} - -// GetOffset returns the current row and column offset. This indicates how many -// rows and columns the table is scrolled down and to the right. -func (t *Table) GetOffset() (row, column int) { - return t.rowOffset, t.columnOffset -} - -// SetSelectedFunc sets a handler which is called whenever the user presses the -// Enter key on a selected cell/row/column. The handler receives the position of -// the selection and its cell contents. If entire rows are selected, the column -// index is undefined. Likewise for entire columns. -func (t *Table) SetSelectedFunc(handler func(row, column int)) *Table { - t.selected = handler - return t -} - -// SetSelectionChangedFunc sets a handler which is called whenever the user -// navigates to a new selection. The handler receives the position of the new -// selection. If entire rows are selected, the column index is undefined. -// Likewise for entire columns. -func (t *Table) SetSelectionChangedFunc(handler func(row, column int)) *Table { - t.selectionChanged = handler - return t -} - -// SetDoneFunc sets a handler which is called whenever the user presses the -// Escape, Tab, or Backtab key. If nothing is selected, it is also called when -// user presses the Enter key (because pressing Enter on a selection triggers -// the "selected" handler set via SetSelectedFunc()). -func (t *Table) SetDoneFunc(handler func(key tcell.Key)) *Table { - t.done = handler - return t -} - -// SetCell sets the content of a cell the specified position. It is ok to -// directly instantiate a TableCell object. If the cell has content, at least -// the Text and Color fields should be set. -// -// Note that setting cells in previously unknown rows and columns will -// automatically extend the internal table representation, e.g. starting with -// a row of 100,000 will immediately create 100,000 empty rows. -// -// To avoid unnecessary garbage collection, fill columns from left to right. -func (t *Table) SetCell(row, column int, cell *TableCell) *Table { - if row >= len(t.cells) { - t.cells = append(t.cells, make([][]*TableCell, row-len(t.cells)+1)...) - } - rowLen := len(t.cells[row]) - if column >= rowLen { - t.cells[row] = append(t.cells[row], make([]*TableCell, column-rowLen+1)...) - for c := rowLen; c < column; c++ { - t.cells[row][c] = &TableCell{} - } - } - t.cells[row][column] = cell - if column > t.lastColumn { - t.lastColumn = column - } - return t -} - -// SetCellSimple calls SetCell() with the given text, left-aligned, in white. -func (t *Table) SetCellSimple(row, column int, text string) *Table { - t.SetCell(row, column, NewTableCell(text)) - return t -} - -// GetCell returns the contents of the cell at the specified position. A valid -// TableCell object is always returned but it will be uninitialized if the cell -// was not previously set. -func (t *Table) GetCell(row, column int) *TableCell { - if row >= len(t.cells) || column >= len(t.cells[row]) { - return &TableCell{} - } - return t.cells[row][column] -} - -// RemoveRow removes the row at the given position from the table. If there is -// no such row, this has no effect. -func (t *Table) RemoveRow(row int) *Table { - if row < 0 || row >= len(t.cells) { - return t - } - - t.cells = append(t.cells[:row], t.cells[row+1:]...) - - return t -} - -// RemoveColumn removes the column at the given position from the table. If -// there is no such column, this has no effect. -func (t *Table) RemoveColumn(column int) *Table { - for row := range t.cells { - if column < 0 || column >= len(t.cells[row]) { - continue - } - t.cells[row] = append(t.cells[row][:column], t.cells[row][column+1:]...) - } - - return t -} - -// GetRowCount returns the number of rows in the table. -func (t *Table) GetRowCount() int { - return len(t.cells) -} - -// GetColumnCount returns the (maximum) number of columns in the table. -func (t *Table) GetColumnCount() int { - if len(t.cells) == 0 { - return 0 - } - return t.lastColumn + 1 -} - -// ScrollToBeginning scrolls the table to the beginning to that the top left -// corner of the table is shown. Note that this position may be corrected if -// there is a selection. -func (t *Table) ScrollToBeginning() *Table { - t.trackEnd = false - t.columnOffset = 0 - t.rowOffset = 0 - return t -} - -// ScrollToEnd scrolls the table to the beginning to that the bottom left corner -// of the table is shown. Adding more rows to the table will cause it to -// automatically scroll with the new data. Note that this position may be -// corrected if there is a selection. -func (t *Table) ScrollToEnd() *Table { - t.trackEnd = true - t.columnOffset = 0 - t.rowOffset = len(t.cells) - return t -} - -// Draw draws this primitive onto the screen. -func (t *Table) Draw(screen tcell.Screen) { - t.Box.Draw(screen) - - // What's our available screen space? - x, y, width, height := t.GetInnerRect() - if t.borders { - t.visibleRows = height / 2 - } else { - t.visibleRows = height - } - - // Return the cell at the specified position (nil if it doesn't exist). - getCell := func(row, column int) *TableCell { - if row < 0 || column < 0 || row >= len(t.cells) || column >= len(t.cells[row]) { - return nil - } - return t.cells[row][column] - } - - // If this cell is not selectable, find the next one. - if t.rowsSelectable || t.columnsSelectable { - if t.selectedColumn < 0 { - t.selectedColumn = 0 - } - if t.selectedRow < 0 { - t.selectedRow = 0 - } - for t.selectedRow < len(t.cells) { - cell := getCell(t.selectedRow, t.selectedColumn) - if cell == nil || !cell.NotSelectable { - break - } - t.selectedColumn++ - if t.selectedColumn > t.lastColumn { - t.selectedColumn = 0 - t.selectedRow++ - } - } - } - - // Clamp row offsets. - if t.rowsSelectable { - if t.selectedRow >= t.fixedRows && t.selectedRow < t.fixedRows+t.rowOffset { - t.rowOffset = t.selectedRow - t.fixedRows - t.trackEnd = false - } - if t.borders { - if 2*(t.selectedRow+1-t.rowOffset) >= height { - t.rowOffset = t.selectedRow + 1 - height/2 - t.trackEnd = false - } - } else { - if t.selectedRow+1-t.rowOffset >= height { - t.rowOffset = t.selectedRow + 1 - height - t.trackEnd = false - } - } - } - if t.borders { - if 2*(len(t.cells)-t.rowOffset) < height { - t.trackEnd = true - } - } else { - if len(t.cells)-t.rowOffset < height { - t.trackEnd = true - } - } - if t.trackEnd { - if t.borders { - t.rowOffset = len(t.cells) - height/2 - } else { - t.rowOffset = len(t.cells) - height - } - } - if t.rowOffset < 0 { - t.rowOffset = 0 - } - - // Clamp column offset. (Only left side here. The right side is more - // difficult and we'll do it below.) - if t.columnsSelectable && t.selectedColumn >= t.fixedColumns && t.selectedColumn < t.fixedColumns+t.columnOffset { - t.columnOffset = t.selectedColumn - t.fixedColumns - } - if t.columnOffset < 0 { - t.columnOffset = 0 - } - if t.selectedColumn < 0 { - t.selectedColumn = 0 - } - - // Determine the indices and widths of the columns and rows which fit on the - // screen. - var ( - columns, rows, widths []int - tableHeight, tableWidth int - ) - rowStep := 1 - if t.borders { - rowStep = 2 // With borders, every table row takes two screen rows. - tableWidth = 1 // We start at the second character because of the left table border. - } - indexRow := func(row int) bool { // Determine if this row is visible, store its index. - if tableHeight >= height { - return false - } - rows = append(rows, row) - tableHeight += rowStep - return true - } - for row := 0; row < t.fixedRows && row < len(t.cells); row++ { // Do the fixed rows first. - if !indexRow(row) { - break - } - } - for row := t.fixedRows + t.rowOffset; row < len(t.cells); row++ { // Then the remaining rows. - if !indexRow(row) { - break - } - } - var ( - skipped, lastTableWidth, expansionTotal int - expansions []int - ) -ColumnLoop: - for column := 0; ; column++ { - // If we've moved beyond the right border, we stop or skip a column. - for tableWidth-1 >= width { // -1 because we include one extra column if the separator falls on the right end of the box. - // We've moved beyond the available space. - if column < t.fixedColumns { - break ColumnLoop // We're in the fixed area. We're done. - } - if !t.columnsSelectable && skipped >= t.columnOffset { - break ColumnLoop // There is no selection and we've already reached the offset. - } - if t.columnsSelectable && t.selectedColumn-skipped == t.fixedColumns { - break ColumnLoop // The selected column reached the leftmost point before disappearing. - } - if t.columnsSelectable && skipped >= t.columnOffset && - (t.selectedColumn < column && lastTableWidth < width-1 && tableWidth < width-1 || t.selectedColumn < column-1) { - break ColumnLoop // We've skipped as many as requested and the selection is visible. - } - if len(columns) <= t.fixedColumns { - break // Nothing to skip. - } - - // We need to skip a column. - skipped++ - lastTableWidth -= widths[t.fixedColumns] + 1 - tableWidth -= widths[t.fixedColumns] + 1 - columns = append(columns[:t.fixedColumns], columns[t.fixedColumns+1:]...) - widths = append(widths[:t.fixedColumns], widths[t.fixedColumns+1:]...) - expansions = append(expansions[:t.fixedColumns], expansions[t.fixedColumns+1:]...) - } - - // What's this column's width (without expansion)? - maxWidth := -1 - expansion := 0 - for _, row := range rows { - if cell := getCell(row, column); cell != nil { - _, _, _, _, cellWidth := decomposeString(cell.Text) - if cell.MaxWidth > 0 && cell.MaxWidth < cellWidth { - cellWidth = cell.MaxWidth - } - if cellWidth > maxWidth { - maxWidth = cellWidth - } - if cell.Expansion > expansion { - expansion = cell.Expansion - } - } - } - if maxWidth < 0 { - break // No more cells found in this column. - } - - // Store new column info at the end. - columns = append(columns, column) - widths = append(widths, maxWidth) - lastTableWidth = tableWidth - tableWidth += maxWidth + 1 - expansions = append(expansions, expansion) - expansionTotal += expansion - } - t.columnOffset = skipped - - // If we have space left, distribute it. - if tableWidth < width { - toDistribute := width - tableWidth - for index, expansion := range expansions { - if expansionTotal <= 0 { - break - } - expWidth := toDistribute * expansion / expansionTotal - widths[index] += expWidth - toDistribute -= expWidth - expansionTotal -= expansion - } - } - - // Helper function which draws border runes. - borderStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.bordersColor) - drawBorder := func(colX, rowY int, ch rune) { - screen.SetContent(x+colX, y+rowY, ch, nil, borderStyle) - } - - // Draw the cells (and borders). - var columnX int - if !t.borders { - columnX-- - } - for columnIndex, column := range columns { - columnWidth := widths[columnIndex] - for rowY, row := range rows { - if t.borders { - // Draw borders. - rowY *= 2 - for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ { - drawBorder(columnX+pos+1, rowY, Borders.Horizontal) - } - ch := Borders.Cross - if columnIndex == 0 { - if rowY == 0 { - ch = Borders.TopLeft - } else { - ch = Borders.LeftT - } - } else if rowY == 0 { - ch = Borders.TopT - } - drawBorder(columnX, rowY, ch) - rowY++ - if rowY >= height { - break // No space for the text anymore. - } - drawBorder(columnX, rowY, Borders.Vertical) - } else if columnIndex > 0 { - // Draw separator. - drawBorder(columnX, rowY, t.separator) - } - - // Get the cell. - cell := getCell(row, column) - if cell == nil { - continue - } - - // Draw text. - finalWidth := columnWidth - if columnX+1+columnWidth >= width { - finalWidth = width - columnX - 1 - } - cell.x, cell.y, cell.width = x+columnX+1, y+rowY, finalWidth - _, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color)|tcell.Style(cell.Attributes)) - if StringWidth(cell.Text)-printed > 0 && printed > 0 { - _, _, style, _ := screen.GetContent(x+columnX+1+finalWidth-1, y+rowY) - printWithStyle(screen, string(SemigraphicsHorizontalEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, style) - } - } - - // Draw bottom border. - if rowY := 2 * len(rows); t.borders && rowY < height { - for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ { - drawBorder(columnX+pos+1, rowY, Borders.Horizontal) - } - ch := Borders.BottomT - if columnIndex == 0 { - ch = Borders.BottomLeft - } - drawBorder(columnX, rowY, ch) - } - - columnX += columnWidth + 1 - } - - // Draw right border. - if t.borders && len(t.cells) > 0 && columnX < width { - for rowY := range rows { - rowY *= 2 - if rowY+1 < height { - drawBorder(columnX, rowY+1, Borders.Vertical) - } - ch := Borders.RightT - if rowY == 0 { - ch = Borders.TopRight - } - drawBorder(columnX, rowY, ch) - } - if rowY := 2 * len(rows); rowY < height { - drawBorder(columnX, rowY, Borders.BottomRight) - } - } - - // Helper function which colors the background of a box. - // backgroundColor == tcell.ColorDefault => Don't color the background. - // textColor == tcell.ColorDefault => Don't change the text color. - // attr == 0 => Don't change attributes. - // invert == true => Ignore attr, set text to backgroundColor or t.backgroundColor; - // set background to textColor. - colorBackground := func(fromX, fromY, w, h int, backgroundColor, textColor tcell.Color, attr tcell.AttrMask, invert bool) { - for by := 0; by < h && fromY+by < y+height; by++ { - for bx := 0; bx < w && fromX+bx < x+width; bx++ { - m, c, style, _ := screen.GetContent(fromX+bx, fromY+by) - fg, bg, a := style.Decompose() - if invert { - if fg == textColor || fg == t.bordersColor { - fg = backgroundColor - } - if fg == tcell.ColorDefault { - fg = t.backgroundColor - } - style = style.Background(textColor).Foreground(fg) - } else { - if backgroundColor != tcell.ColorDefault { - bg = backgroundColor - } - if textColor != tcell.ColorDefault { - fg = textColor - } - if attr != 0 { - a = attr - } - style = style.Background(bg).Foreground(fg) | tcell.Style(a) - } - screen.SetContent(fromX+bx, fromY+by, m, c, style) - } - } - } - - // Color the cell backgrounds. To avoid undesirable artefacts, we combine - // the drawing of a cell by background color, selected cells last. - type cellInfo struct { - x, y, w, h int - text tcell.Color - selected bool - } - cellsByBackgroundColor := make(map[tcell.Color][]*cellInfo) - var backgroundColors []tcell.Color - for rowY, row := range rows { - columnX := 0 - rowSelected := t.rowsSelectable && !t.columnsSelectable && row == t.selectedRow - for columnIndex, column := range columns { - columnWidth := widths[columnIndex] - cell := getCell(row, column) - if cell == nil { - continue - } - bx, by, bw, bh := x+columnX, y+rowY, columnWidth+1, 1 - if t.borders { - by = y + rowY*2 - bw++ - bh = 3 - } - columnSelected := t.columnsSelectable && !t.rowsSelectable && column == t.selectedColumn - cellSelected := !cell.NotSelectable && (columnSelected || rowSelected || t.rowsSelectable && t.columnsSelectable && column == t.selectedColumn && row == t.selectedRow) - entries, ok := cellsByBackgroundColor[cell.BackgroundColor] - cellsByBackgroundColor[cell.BackgroundColor] = append(entries, &cellInfo{ - x: bx, - y: by, - w: bw, - h: bh, - text: cell.Color, - selected: cellSelected, - }) - if !ok { - backgroundColors = append(backgroundColors, cell.BackgroundColor) - } - columnX += columnWidth + 1 - } - } - sort.Slice(backgroundColors, func(i int, j int) bool { - // Draw brightest colors last (i.e. on top). - r, g, b := backgroundColors[i].RGB() - c := colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255} - _, _, li := c.Hcl() - r, g, b = backgroundColors[j].RGB() - c = colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255} - _, _, lj := c.Hcl() - return li < lj - }) - selFg, selBg, selAttr := t.selectedStyle.Decompose() - for _, bgColor := range backgroundColors { - entries := cellsByBackgroundColor[bgColor] - for _, cell := range entries { - if cell.selected { - if t.selectedStyle != 0 { - defer colorBackground(cell.x, cell.y, cell.w, cell.h, selBg, selFg, selAttr, false) - } else { - defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, 0, true) - } - } else { - colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, tcell.ColorDefault, 0, false) - } - } - } -} - -// InputHandler returns the handler for this primitive. -func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { - return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { - key := event.Key() - - if (!t.rowsSelectable && !t.columnsSelectable && key == tcell.KeyEnter) || - key == tcell.KeyEscape || - key == tcell.KeyTab || - key == tcell.KeyBacktab { - if t.done != nil { - t.done(key) - } - return - } - - // Movement functions. - previouslySelectedRow, previouslySelectedColumn := t.selectedRow, t.selectedColumn - var ( - getCell = func(row, column int) *TableCell { - if row < 0 || column < 0 || row >= len(t.cells) || column >= len(t.cells[row]) { - return nil - } - return t.cells[row][column] - } - - previous = func() { - for t.selectedRow >= 0 { - cell := getCell(t.selectedRow, t.selectedColumn) - if cell == nil || !cell.NotSelectable { - return - } - t.selectedColumn-- - if t.selectedColumn < 0 { - t.selectedColumn = t.lastColumn - t.selectedRow-- - } - } - } - - next = func() { - if t.selectedColumn > t.lastColumn { - t.selectedColumn = 0 - t.selectedRow++ - if t.selectedRow >= len(t.cells) { - t.selectedRow = len(t.cells) - 1 - } - } - for t.selectedRow < len(t.cells) { - cell := getCell(t.selectedRow, t.selectedColumn) - if cell == nil || !cell.NotSelectable { - return - } - t.selectedColumn++ - if t.selectedColumn > t.lastColumn { - t.selectedColumn = 0 - t.selectedRow++ - } - } - t.selectedColumn = t.lastColumn - t.selectedRow = len(t.cells) - 1 - previous() - } - - home = func() { - if t.rowsSelectable { - t.selectedRow = 0 - t.selectedColumn = 0 - next() - } else { - t.trackEnd = false - t.rowOffset = 0 - t.columnOffset = 0 - } - } - - end = func() { - if t.rowsSelectable { - t.selectedRow = len(t.cells) - 1 - t.selectedColumn = t.lastColumn - previous() - } else { - t.trackEnd = true - t.columnOffset = 0 - } - } - - down = func() { - if t.rowsSelectable { - t.selectedRow++ - if t.selectedRow >= len(t.cells) { - t.selectedRow = len(t.cells) - 1 - } - next() - } else { - t.rowOffset++ - } - } - - up = func() { - if t.rowsSelectable { - t.selectedRow-- - if t.selectedRow < 0 { - t.selectedRow = 0 - } - previous() - } else { - t.trackEnd = false - t.rowOffset-- - } - } - - left = func() { - if t.columnsSelectable { - t.selectedColumn-- - if t.selectedColumn < 0 { - t.selectedColumn = 0 - } - previous() - } else { - t.columnOffset-- - } - } - - right = func() { - if t.columnsSelectable { - t.selectedColumn++ - if t.selectedColumn > t.lastColumn { - t.selectedColumn = t.lastColumn - } - next() - } else { - t.columnOffset++ - } - } - - pageDown = func() { - if t.rowsSelectable { - t.selectedRow += t.visibleRows - if t.selectedRow >= len(t.cells) { - t.selectedRow = len(t.cells) - 1 - } - next() - } else { - t.rowOffset += t.visibleRows - } - } - - pageUp = func() { - if t.rowsSelectable { - t.selectedRow -= t.visibleRows - if t.selectedRow < 0 { - t.selectedRow = 0 - } - previous() - } else { - t.trackEnd = false - t.rowOffset -= t.visibleRows - } - } - ) - - switch key { - case tcell.KeyRune: - switch event.Rune() { - case 'g': - home() - case 'G': - end() - case 'j': - down() - case 'k': - up() - case 'h': - left() - case 'l': - right() - } - case tcell.KeyHome: - home() - case tcell.KeyEnd: - end() - case tcell.KeyUp: - up() - case tcell.KeyDown: - down() - case tcell.KeyLeft: - left() - case tcell.KeyRight: - right() - case tcell.KeyPgDn, tcell.KeyCtrlF: - pageDown() - case tcell.KeyPgUp, tcell.KeyCtrlB: - pageUp() - case tcell.KeyEnter: - if (t.rowsSelectable || t.columnsSelectable) && t.selected != nil { - t.selected(t.selectedRow, t.selectedColumn) - } - } - - // If the selection has changed, notify the handler. - if t.selectionChanged != nil && - (t.rowsSelectable && previouslySelectedRow != t.selectedRow || - t.columnsSelectable && previouslySelectedColumn != t.selectedColumn) { - t.selectionChanged(t.selectedRow, t.selectedColumn) - } - }) -} -- cgit v1.2.3