package cview

import (
	
	
	

	
	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 reference object.
	Reference interface{}

	// The text to be displayed in the table cell.
	Text []byte

	// 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

	sync.RWMutex
}

// 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 ( string) *TableCell {
	return &TableCell{
		Text:            []byte(),
		Align:           AlignLeft,
		Color:           Styles.PrimaryTextColor,
		BackgroundColor: tcell.ColorDefault,
	}
}

// SetBytes sets the cell's text.
func ( *TableCell) ( []byte) {
	.Lock()
	defer .Unlock()

	.Text = 
}

// SetText sets the cell's text.
func ( *TableCell) ( string) {
	.SetBytes([]byte())
}

// GetBytes returns the cell's text.
func ( *TableCell) () []byte {
	.RLock()
	defer .RUnlock()

	return .Text
}

// GetText returns the cell's text.
func ( *TableCell) () string {
	return string(.GetBytes())
}

// SetAlign sets the cell's text alignment, one of AlignLeft, AlignCenter, or
// AlignRight.
func ( *TableCell) ( int) {
	.Lock()
	defer .Unlock()

	.Align = 
}

// 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 ( *TableCell) ( int) {
	.Lock()
	defer .Unlock()

	.MaxWidth = 
}

// 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 ( *TableCell) ( int) {
	.Lock()
	defer .Unlock()

	if  < 0 {
		panic("Table cell expansion values may not be negative")
	}
	.Expansion = 
}

// SetTextColor sets the cell's text color.
func ( *TableCell) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.Color = 
}

// SetBackgroundColor sets the cell's background color. Set to
// tcell.ColorDefault to use the table's background color.
func ( *TableCell) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.BackgroundColor = 
}

// SetAttributes sets the cell's text attributes. You can combine different
// attributes using bitmask operations:
//
//	cell.SetAttributes(tcell.AttrUnderline | tcell.AttrBold)
func ( *TableCell) ( tcell.AttrMask) {
	.Lock()
	defer .Unlock()

	.Attributes = 
}

// SetStyle sets the cell's style (foreground color, background color, and
// attributes) all at once.
func ( *TableCell) ( tcell.Style) {
	.Lock()
	defer .Unlock()

	.Color, .BackgroundColor, .Attributes = .Decompose()
}

// SetSelectable sets whether or not this cell can be selected by the user.
func ( *TableCell) ( bool) {
	.Lock()
	defer .Unlock()

	.NotSelectable = !
}

// SetReference allows you to store a reference of any type in this cell. This
// will allow you to establish a mapping between the cell and your
// actual data.
func ( *TableCell) ( interface{}) {
	.Lock()
	defer .Unlock()

	.Reference = 
}

// GetReference returns this cell's reference object.
func ( *TableCell) () interface{} {
	.RLock()
	defer .RUnlock()

	return .Reference
}

// 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 ( *TableCell) () (, ,  int) {
	.RLock()
	defer .RUnlock()

	return .x, .y, .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.
//
// Each row of the table must have the same number of columns when it is drawn
// or navigated. This isn't strictly enforced, however you may encounter issues
// when navigating a table with rows of varied column sizes.
//
// 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.
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

	// If true, when calculating the widths of the columns, all rows are evaluated
	// instead of only the visible ones.
	evaluateAllRows bool

	// 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 sort function of the table. Defaults to a case-sensitive comparison.
	sortFunc func(column, i, j int) bool

	// Whether or not the table should be sorted when a fixed row is clicked.
	sortClicked bool

	// The last direction the table was sorted by when clicked.
	sortClickedDescending bool

	// The last column the table was sorted by when clicked.
	sortClickedColumn int

	// The number of visible rows the last time the table was drawn.
	visibleRows int

	// The indices of the visible columns as of the last time the table was drawn.
	visibleColumnIndices []int

	// The net widths of the visible columns as of the last time the table was
	// drawn.
	visibleColumnWidths []int

	// Visibility of the scroll bar.
	scrollBarVisibility ScrollBarVisibility

	// The scroll bar color.
	scrollBarColor tcell.Color

	// The style of the selected rows. If this value is StyleDefault, 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)

	sync.RWMutex
}

// NewTable returns a new table.
func () *Table {
	return &Table{
		Box:                 NewBox(),
		scrollBarVisibility: ScrollBarAuto,
		scrollBarColor:      Styles.ScrollBarColor,
		bordersColor:        Styles.GraphicsColor,
		separator:           ' ',
		sortClicked:         true,
		lastColumn:          -1,
	}
}

// Clear removes all table data.
func ( *Table) () {
	.Lock()
	defer .Unlock()

	.cells = nil
	.lastColumn = -1
}

// SetBorders sets whether or not each cell in the table is surrounded by a
// border.
func ( *Table) ( bool) {
	.Lock()
	defer .Unlock()

	.borders = 
}

// SetBordersColor sets the color of the cell borders.
func ( *Table) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.bordersColor = 
}

// SetScrollBarVisibility specifies the display of the scroll bar.
func ( *Table) ( ScrollBarVisibility) {
	.Lock()
	defer .Unlock()

	.scrollBarVisibility = 
}

// SetScrollBarColor sets the color of the scroll bar.
func ( *Table) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.scrollBarColor = 
}

// 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 ( *Table) (,  tcell.Color,  tcell.AttrMask) {
	.Lock()
	defer .Unlock()

	.selectedStyle = SetAttributes(tcell.StyleDefault.Foreground().Background(), )
}

// 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 ( *Table) ( rune) {
	.Lock()
	defer .Unlock()

	.separator = 
}

// 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 ( *Table) (,  int) {
	.Lock()
	defer .Unlock()

	.fixedRows, .fixedColumns = , 
}

// 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 ( *Table) (,  bool) {
	.Lock()
	defer .Unlock()

	.rowsSelectable, .columnsSelectable = , 
}

// GetSelectable returns what can be selected in a table. Refer to
// SetSelectable() for details.
func ( *Table) () (,  bool) {
	.RLock()
	defer .RUnlock()

	return .rowsSelectable, .columnsSelectable
}

// GetSelection returns the position of the current selection.
// If entire rows are selected, the column index is undefined.
// Likewise for entire columns.
func ( *Table) () (,  int) {
	.RLock()
	defer .RUnlock()

	return .selectedRow, .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. The "selection changed" event is fired if such a callback
// is available (even if the selection ends up being the same as before and even
// if cells are not selectable).
func ( *Table) (,  int) {
	.Lock()
	defer .Unlock()

	.selectedRow, .selectedColumn = , 
	if .selectionChanged != nil {
		.Unlock()
		.selectionChanged(, )
		.Lock()
	}
}

// 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 ( *Table) (,  int) {
	.Lock()
	defer .Unlock()

	.rowOffset, .columnOffset = , 
	.trackEnd = false
}

// 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 ( *Table) () (,  int) {
	.RLock()
	defer .RUnlock()

	return .rowOffset, .columnOffset
}

// SetEvaluateAllRows sets a flag which determines the rows to be evaluated when
// calculating the widths of the table's columns. When false, only visible rows
// are evaluated. When true, all rows in the table are evaluated.
//
// Set this flag to true to avoid shifting column widths when the table is
// scrolled. (May be slower for large tables.)
func ( *Table) ( bool) {
	.Lock()
	defer .Unlock()

	.evaluateAllRows = 
}

// 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 ( *Table) ( func(,  int)) {
	.Lock()
	defer .Unlock()

	.selected = 
}

// SetSelectionChangedFunc sets a handler which is called whenever the current
// selection changes. The handler receives the position of the new selection.
// If entire rows are selected, the column index is undefined. Likewise for
// entire columns.
func ( *Table) ( func(,  int)) {
	.Lock()
	defer .Unlock()

	.selectionChanged = 
}

// 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 ( *Table) ( func( tcell.Key)) {
	.Lock()
	defer .Unlock()

	.done = 
}

// 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 ( *Table) (,  int,  *TableCell) {
	.Lock()
	defer .Unlock()

	if  >= len(.cells) {
		.cells = append(.cells, make([][]*TableCell, -len(.cells)+1)...)
	}
	 := len(.cells[])
	if  >=  {
		.cells[] = append(.cells[], make([]*TableCell, -+1)...)
		for  := ;  < ; ++ {
			.cells[][] = &TableCell{}
		}
	}
	.cells[][] = 
	if  > .lastColumn {
		.lastColumn = 
	}
}

// SetCellSimple calls SetCell() with the given text, left-aligned, in white.
func ( *Table) (,  int,  string) {
	.SetCell(, , NewTableCell())
}

// 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. Such an uninitialized object will not automatically
// be inserted. Therefore, repeated calls to this function may return different
// pointers for uninitialized cells.
func ( *Table) (,  int) *TableCell {
	.RLock()
	defer .RUnlock()

	if  >= len(.cells) ||  >= len(.cells[]) {
		return &TableCell{}
	}
	return .cells[][]
}

// RemoveRow removes the row at the given position from the table. If there is
// no such row, this has no effect.
func ( *Table) ( int) {
	.Lock()
	defer .Unlock()

	if  < 0 ||  >= len(.cells) {
		return
	}

	.cells = append(.cells[:], .cells[+1:]...)
}

// RemoveColumn removes the column at the given position from the table. If
// there is no such column, this has no effect.
func ( *Table) ( int) {
	.Lock()
	defer .Unlock()

	for  := range .cells {
		if  < 0 ||  >= len(.cells[]) {
			continue
		}
		.cells[] = append(.cells[][:], .cells[][+1:]...)
	}
}

// InsertRow inserts a row before the row with the given index. Cells on the
// given row and below will be shifted to the bottom by one row. If "row" is
// equal or larger than the current number of rows, this function has no effect.
func ( *Table) ( int) {
	.Lock()
	defer .Unlock()

	if  >= len(.cells) {
		return
	}
	.cells = append(.cells, nil)       // Extend by one.
	copy(.cells[+1:], .cells[:]) // Shift down.
	.cells[] = nil                   // New row is uninitialized.
}

// InsertColumn inserts a column before the column with the given index. Cells
// in the given column and to its right will be shifted to the right by one
// column. Rows that have fewer initialized cells than "column" will remain
// unchanged.
func ( *Table) ( int) {
	.Lock()
	defer .Unlock()

	for  := range .cells {
		if  >= len(.cells[]) {
			continue
		}
		.cells[] = append(.cells[], nil)             // Extend by one.
		copy(.cells[][+1:], .cells[][:]) // Shift to the right.
		.cells[][] = &TableCell{}                  // New element is an uninitialized table cell.
	}
}

// GetRowCount returns the number of rows in the table.
func ( *Table) () int {
	.RLock()
	defer .RUnlock()

	return len(.cells)
}

// GetColumnCount returns the (maximum) number of columns in the table.
func ( *Table) () int {
	.RLock()
	defer .RUnlock()

	if len(.cells) == 0 {
		return 0
	}
	return .lastColumn + 1
}

// cellAt returns the row and column located at the given screen coordinates.
// Each returned value may be negative if there is no row and/or cell. This
// function will also process coordinates outside the table's inner rectangle so
// callers will need to check for bounds themselves.
func ( *Table) (,  int) (,  int) {
	, , ,  := .GetInnerRect()

	// Determine row as seen on screen.
	if .borders {
		 = ( -  - 1) / 2
	} else {
		 =  - 
	}

	// Respect fixed rows and row offset.
	if  >= 0 {
		if  >= .fixedRows {
			 += .rowOffset
		}
		if  >= len(.cells) {
			 = -1
		}
	}

	// Search for the clicked column.
	 = -1
	if  >=  {
		 := 
		if .borders {
			++
		}
		for ,  := range .visibleColumnWidths {
			 +=  + 1
			if  <  {
				 = .visibleColumnIndices[]
				break
			}
		}
	}

	return
}

// 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 ( *Table) () {
	.Lock()
	defer .Unlock()

	.trackEnd = false
	.columnOffset = 0
	.rowOffset = 0
}

// 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 ( *Table) () {
	.Lock()
	defer .Unlock()

	.trackEnd = true
	.columnOffset = 0
	.rowOffset = len(.cells)
}

// SetSortClicked sets a flag which determines whether the table is sorted when
// a fixed row is clicked. This flag is enabled by default.
func ( *Table) ( bool) {
	.Lock()
	defer .Unlock()

	.sortClicked = 
}

// SetSortFunc sets the sorting function used for the table. When unset, a
// case-sensitive string comparison is used.
func ( *Table) ( func(, ,  int) bool) {
	.Lock()
	defer .Unlock()

	.sortFunc = 
}

// Sort sorts the table by the column at the given index. You may set a custom
// sorting function with SetSortFunc.
func ( *Table) ( int,  bool) {
	.Lock()
	defer .Unlock()

	if len(.cells) == 0 ||  < 0 ||  >= len(.cells[0]) {
		return
	}

	if .sortFunc == nil {
		.sortFunc = func(, ,  int) bool {
			return bytes.Compare(.cells[][].Text, .cells[][].Text) == -1
		}
	}

	sort.SliceStable(.cells, func(,  int) bool {
		if  < .fixedRows {
			return  < 
		} else if  < .fixedRows {
			return  > 
		}

		if ! {
			return .sortFunc(, , )
		}
		return .sortFunc(, , )
	})
}

// Draw draws this primitive onto the screen.
func ( *Table) ( tcell.Screen) {
	if !.GetVisible() {
		return
	}

	.Box.Draw()

	.Lock()
	defer .Unlock()

	// What's our available screen space?
	, , ,  := .GetInnerRect()
	if .borders {
		.visibleRows =  / 2
	} else {
		.visibleRows = 
	}

	 := .scrollBarVisibility == ScrollBarAlways || (.scrollBarVisibility == ScrollBarAuto && len(.cells) > .visibleRows-.fixedRows)
	if  {
		-- // Subtract space for scroll bar.
	}

	// TODO horizontal scrollbar

	// Return the cell at the specified position (nil if it doesn't exist).
	 := func(,  int) *TableCell {
		if  < 0 ||  < 0 ||  >= len(.cells) ||  >= len(.cells[]) {
			return nil
		}
		return .cells[][]
	}

	// If this cell is not selectable, find the next one.
	if .rowsSelectable || .columnsSelectable {
		if .selectedColumn < 0 {
			.selectedColumn = 0
		}
		if .selectedRow < 0 {
			.selectedRow = 0
		}
		for .selectedRow < len(.cells) {
			 := (.selectedRow, .selectedColumn)
			if  == nil {
				break
			}
			.RLock()
			if !.NotSelectable {
				.RUnlock()
				break
			}
			.RUnlock()
			.selectedColumn++
			if .selectedColumn > .lastColumn {
				.selectedColumn = 0
				.selectedRow++
			}
		}
	}

	// Clamp row offsets.
	if .rowsSelectable {
		if .selectedRow >= .fixedRows && .selectedRow < .fixedRows+.rowOffset {
			.rowOffset = .selectedRow - .fixedRows
			.trackEnd = false
		}
		if .borders {
			if 2*(.selectedRow+1-.rowOffset) >=  {
				.rowOffset = .selectedRow + 1 - /2
				.trackEnd = false
			}
		} else {
			if .selectedRow+1-.rowOffset >=  {
				.rowOffset = .selectedRow + 1 - 
				.trackEnd = false
			}
		}
	}
	if .borders {
		if 2*(len(.cells)-.rowOffset) <  {
			.trackEnd = true
		}
	} else {
		if len(.cells)-.rowOffset <  {
			.trackEnd = true
		}
	}
	if .trackEnd {
		if .borders {
			.rowOffset = len(.cells) - /2
		} else {
			.rowOffset = len(.cells) - 
		}
	}
	if .rowOffset < 0 {
		.rowOffset = 0
	}

	// Clamp column offset. (Only left side here. The right side is more
	// difficult and we'll do it below.)
	if .columnsSelectable && .selectedColumn >= .fixedColumns && .selectedColumn < .fixedColumns+.columnOffset {
		.columnOffset = .selectedColumn - .fixedColumns
	}
	if .columnOffset < 0 {
		.columnOffset = 0
	}
	if .selectedColumn < 0 {
		.selectedColumn = 0
	}

	// Determine the indices and widths of the columns and rows which fit on the
	// screen.
	var (
		, , ,  []int
		,         int
	)
	 := 1
	if .borders {
		 = 2    // With borders, every table row takes two screen rows.
		 = 1 // We start at the second character because of the left table border.
	}
	if .evaluateAllRows {
		 = make([]int, len(.cells))
		for  := range .cells {
			[] = 
		}
	}
	 := func( int) bool { // Determine if this row is visible, store its index.
		if  >=  {
			return false
		}
		 = append(, )
		 += 
		return true
	}
	for  := 0;  < .fixedRows &&  < len(.cells); ++ { // Do the fixed rows first.
		if !() {
			break
		}
	}
	for  := .fixedRows + .rowOffset;  < len(.cells); ++ { // Then the remaining rows.
		if !() {
			break
		}
	}
	var (
		, ,  int
		                              []int
	)
:
	for  := 0; ; ++ {
		// If we've moved beyond the right border, we stop or skip a column.
		for -1 >=  { // -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  < .fixedColumns {
				break  // We're in the fixed area. We're done.
			}
			if !.columnsSelectable &&  >= .columnOffset {
				break  // There is no selection and we've already reached the offset.
			}
			if .columnsSelectable && .selectedColumn- == .fixedColumns {
				break  // The selected column reached the leftmost point before disappearing.
			}
			if .columnsSelectable &&  >= .columnOffset &&
				(.selectedColumn <  &&  < -1 &&  < -1 || .selectedColumn < -1) {
				break  // We've skipped as many as requested and the selection is visible.
			}
			if len() <= .fixedColumns {
				break // Nothing to skip.
			}

			// We need to skip a column.
			++
			 -= [.fixedColumns] + 1
			 -= [.fixedColumns] + 1
			 = append([:.fixedColumns], [.fixedColumns+1:]...)
			 = append([:.fixedColumns], [.fixedColumns+1:]...)
			 = append([:.fixedColumns], [.fixedColumns+1:]...)
		}

		// What's this column's width (without expansion)?
		 := -1
		 := 0
		 := 
		if .evaluateAllRows {
			 = 
		}
		for ,  := range  {
			if  := (, );  != nil {
				.RLock()

				, , , , , ,  := decomposeText(.Text, true, false)
				if .MaxWidth > 0 && .MaxWidth <  {
					 = .MaxWidth
				}
				if  >  {
					 = 
				}
				if .Expansion >  {
					 = .Expansion
				}
				.RUnlock()
			}
		}
		if  < 0 {
			break // No more cells found in this column.
		}

		// Store new column info at the end.
		 = append(, )
		 = append(, )
		 = 
		 +=  + 1
		 = append(, )
		 += 
	}
	.columnOffset = 

	// If we have space left, distribute it.
	if  <  {
		 :=  - 
		for ,  := range  {
			if  <= 0 {
				break
			}
			 :=  *  / 
			[] += 
			 -= 
			 -= 
		}
		 =  - 
	}

	// Helper function which draws border runes.
	 := tcell.StyleDefault.Background(.backgroundColor).Foreground(.bordersColor)
	 := func(,  int,  rune) {
		.SetContent(+, +, , nil, )
	}

	// Draw the cells (and borders).
	var  int
	if !.borders {
		--
	}
	for ,  := range  {
		 := []
		for ,  := range  {
			if .borders {
				// Draw borders.
				 *= 2
				for  := 0;  <  && +1+ < ; ++ {
					(++1, , Borders.Horizontal)
				}
				 := Borders.Cross
				if  == 0 {
					if  == 0 {
						 = Borders.TopLeft
					} else {
						 = Borders.LeftT
					}
				} else if  == 0 {
					 = Borders.TopT
				}
				(, , )
				++
				if  >=  {
					break // No space for the text anymore.
				}
				(, , Borders.Vertical)
			} else if  > 0 {
				// Draw separator.
				(, , .separator)
			}

			// Get the cell.
			 := (, )
			if  == nil {
				continue
			}
			.Lock()

			// Draw text.
			 := 
			if +1+ >=  {
				 =  -  - 1
			}
			.x, .y, .width = ++1, +, 
			,  := PrintStyle(, .Text, ++1, +, , .Align, SetAttributes(tcell.StyleDefault.Foreground(.Color), .Attributes))
			if TaggedTextWidth(.Text)- > 0 &&  > 0 {
				, , ,  := .GetContent(++, +)
				PrintStyle(, []byte(string(SemigraphicsHorizontalEllipsis)), ++, +, 1, AlignLeft, )
			}
			.Unlock()
		}

		// Draw bottom border.
		if  := 2 * len(); .borders &&  <  {
			for  := 0;  <  && +1+ < ; ++ {
				(++1, , Borders.Horizontal)
			}
			 := Borders.BottomT
			if  == 0 {
				 = Borders.BottomLeft
			}
			(, , )
		}

		 +=  + 1
	}

	// Draw right border.
	if .borders && len(.cells) > 0 &&  <  {
		for  := range  {
			 *= 2
			if +1 <  {
				(, +1, Borders.Vertical)
			}
			 := Borders.RightT
			if  == 0 {
				 = Borders.TopRight
			}
			(, , )
		}
		if  := 2 * len();  <  {
			(, , Borders.BottomRight)
		}
	}

	if  {
		// Calculate scroll bar position and dimensions.
		 := len(.cells)

		 :=  - .fixedRows
		 := .visibleRows - .fixedRows

		 :=  + 
		 :=  + .fixedRows
		if  > + {
			 =  + 
		}

		 := 1
		if .borders {
			 = 2

			 *= 2
			 = ( * 2) - 1

			 += .fixedRows + 1
		}

		// Draw scroll bar.
		 := int(float64() * (float64(.rowOffset) / float64(((-.fixedRows)-.visibleRows)+)))
		for  := 0;  < ; ++ {
			RenderScrollBar(, .scrollBarVisibility, , +, , , , , .hasFocus, .scrollBarColor)
		}
	}

	// TODO Draw horizontal scroll bar

	// 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.
	 := func(, , ,  int, ,  tcell.Color,  tcell.AttrMask,  bool) {
		for  := 0;  <  && + < +; ++ {
			for  := 0;  <  && + < +; ++ {
				, , ,  := .GetContent(+, +)
				, ,  := .Decompose()
				if  {
					if  ==  ||  == .bordersColor {
						 = 
					}
					if  == tcell.ColorDefault {
						 = .backgroundColor
					}
					 = .Background().Foreground()
				} else {
					if  != tcell.ColorDefault {
						 = 
					}
					if  != tcell.ColorDefault {
						 = 
					}
					if  != 0 {
						 = 
					}
					 = SetAttributes(.Background().Foreground(), )
				}
				.SetContent(+, +, , , )
			}
		}
	}

	// Color the cell backgrounds. To avoid undesirable artefacts, we combine
	// the drawing of a cell by background color, selected cells last.
	type  struct {
		, , ,  int
		      tcell.Color
		   bool
	}
	 := make(map[tcell.Color][]*)
	var  []tcell.Color
	for ,  := range  {
		 := 0
		 := .rowsSelectable && !.columnsSelectable &&  == .selectedRow
		for ,  := range  {
			 := []
			 := (, )
			if  == nil {
				continue
			}
			, , ,  := +, +, +1, 1
			if .borders {
				 =  + *2
				++
				 = 3
			}
			 := .columnsSelectable && !.rowsSelectable &&  == .selectedColumn
			 := !.NotSelectable && ( ||  || .rowsSelectable && .columnsSelectable &&  == .selectedColumn &&  == .selectedRow)
			,  := [.BackgroundColor]
			[.BackgroundColor] = append(, &{
				:        ,
				:        ,
				:        ,
				:        ,
				:    .Color,
				: ,
			})
			if ! {
				 = append(, .BackgroundColor)
			}
			 +=  + 1
		}
	}
	sort.Slice(, func( int,  int) bool {
		// Draw brightest colors last (i.e. on top).
		, ,  := [].RGB()
		 := colorful.Color{R: float64() / 255, G: float64() / 255, B: float64() / 255}
		, ,  := .Hcl()
		, ,  = [].RGB()
		 = colorful.Color{R: float64() / 255, G: float64() / 255, B: float64() / 255}
		, ,  := .Hcl()
		return  < 
	})
	, ,  := .selectedStyle.Decompose()
	for ,  := range  {
		 := []
		for ,  := range  {
			if . && .hasFocus {
				if .selectedStyle != tcell.StyleDefault {
					defer (., ., ., ., , , , false)
				} else {
					defer (., ., ., ., , ., 0, true)
				}
			} else {
				(., ., ., ., , tcell.ColorDefault, 0, false)
			}
		}
	}

	// Remember column infos.
	.visibleColumnIndices, .visibleColumnWidths = , 
}

// InputHandler returns the handler for this primitive.
func ( *Table) () func( *tcell.EventKey,  func( Primitive)) {
	return .WrapInputHandler(func( *tcell.EventKey,  func( Primitive)) {
		.Lock()
		defer .Unlock()

		 := .Key()

		if (!.rowsSelectable && !.columnsSelectable &&  == tcell.KeyEnter) ||
			 == tcell.KeyEscape ||
			 == tcell.KeyTab ||
			 == tcell.KeyBacktab {
			if .done != nil {
				.Unlock()
				.done()
				.Lock()
			}
			return
		}

		// Movement functions.
		,  := .selectedRow, .selectedColumn
		var (
			 = func(,  int) bool {
				if  < .fixedRows ||  >= len(.cells) ||  < .fixedColumns ||  > .lastColumn {
					return false
				}
				 := .cells[][]
				return  == nil || !.NotSelectable
			}

			 = func() {
				if .rowsSelectable {
					.selectedRow = 0
					.selectedColumn = 0
				} else {
					.trackEnd = false
					.rowOffset = 0
					.columnOffset = 0
				}
			}

			 = func() {
				if .rowsSelectable {
					.selectedRow = len(.cells) - 1
					.selectedColumn = .lastColumn
				} else {
					.trackEnd = true
					.columnOffset = 0
				}
			}

			 = func() {
				if .rowsSelectable {
					if (.selectedRow+1, .selectedColumn) {
						.selectedRow++
					}
				} else {
					.rowOffset++
				}
			}

			 = func() {
				if .rowsSelectable {
					if (.selectedRow-1, .selectedColumn) {
						.selectedRow--
					}
				} else {
					.trackEnd = false
					.rowOffset--
				}
			}

			 = func() {
				if .columnsSelectable {
					for  := .selectedColumn - 1;  >= 0; -- {
						if (.selectedRow, ) {
							.selectedColumn = 
							break
						}
					}
				} else {
					.columnOffset--
				}
			}

			 = func() {
				if .columnsSelectable {
					for  := .selectedColumn + 1;  <= .lastColumn; ++ {
						if (.selectedRow, ) {
							.selectedColumn = 
							break
						}
					}
				} else {
					.columnOffset++
				}
			}

			 = func() {
				 := .visibleRows - .fixedRows
				if  < 0 {
					 = 0
				}

				if .rowsSelectable {
					.selectedRow += 
					if .selectedRow >= len(.cells) {
						.selectedRow = len(.cells) - 1
					}
				} else {
					.rowOffset += 
				}
			}

			 = func() {
				 := .visibleRows - .fixedRows
				if  < 0 {
					 = 0
				}

				if .rowsSelectable {
					.selectedRow -= 
					if .selectedRow < 0 {
						.selectedRow = 0
					}
				} else {
					.trackEnd = false
					.rowOffset -= 
				}
			}
		)

		if HitShortcut(, Keys.MoveFirst, Keys.MoveFirst2) {
			()
		} else if HitShortcut(, Keys.MoveLast, Keys.MoveLast2) {
			()
		} else if HitShortcut(, Keys.MoveUp, Keys.MoveUp2) {
			()
		} else if HitShortcut(, Keys.MoveDown, Keys.MoveDown2) {
			()
		} else if HitShortcut(, Keys.MoveLeft, Keys.MoveLeft2) {
			()
		} else if HitShortcut(, Keys.MoveRight, Keys.MoveRight2) {
			()
		} else if HitShortcut(, Keys.MovePreviousPage) {
			()
		} else if HitShortcut(, Keys.MoveNextPage) {
			()
		} else if HitShortcut(, Keys.Select, Keys.Select2) {
			if (.rowsSelectable || .columnsSelectable) && .selected != nil {
				.Unlock()
				.selected(.selectedRow, .selectedColumn)
				.Lock()
			}
		}

		// If the selection has changed, notify the handler.
		if .selectionChanged != nil && ((.rowsSelectable &&  != .selectedRow) || (.columnsSelectable &&  != .selectedColumn)) {
			.Unlock()
			.selectionChanged(.selectedRow, .selectedColumn)
			.Lock()
		}
	})
}

// MouseHandler returns the mouse handler for this primitive.
func ( *Table) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		,  := .Position()
		if !.InRect(, ) {
			return false, nil
		}

		switch  {
		case MouseLeftClick:
			, , ,  := .GetInnerRect()
			 := 1
			 := 
			if .borders {
				 = 2
				 =  + 1
			}

			if .sortClicked && .fixedRows > 0 && ( >=  &&  < +(.fixedRows*)) {
				,  := .cellAt(, )
				if .sortClickedColumn !=  {
					.sortClickedColumn = 
					.sortClickedDescending = false
				} else {
					.sortClickedDescending = !.sortClickedDescending
				}
				.Sort(, .sortClickedDescending)

				if .columnsSelectable {
					.selectedColumn = 
				}
			} else if .rowsSelectable || .columnsSelectable {
				.Select(.cellAt(, ))
				// mouse always selects
				if .selected != nil {
					.selected(.selectedRow, .selectedColumn)
				}
			}

			 = true
			()
		case MouseScrollUp:
			.trackEnd = false
			.rowOffset--
			 = true
		case MouseScrollDown:
			.rowOffset++
			 = true

		// TODO test horizontal scrolling
		case MouseScrollLeft:
			.columnOffset--
			 = true
		case MouseScrollRight:
			.columnOffset++
			 = true
		}

		return
	})
}