mirror of
https://github.com/rivo/tview.git
synced 2025-04-28 13:48:53 +08:00
Fixed table background colors. More sophisticated but more aesthetically pleasing. Fixes #20
This commit is contained in:
parent
f3686bfe15
commit
ef6026df3d
171
table.go
171
table.go
@ -1,7 +1,10 @@
|
|||||||
package tview
|
package tview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
|
colorful "github.com/lucasb-eyer/go-colorful"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TableCell represents one cell inside a Table. You can instantiate this type
|
// TableCell represents one cell inside a Table. You can instantiate this type
|
||||||
@ -574,13 +577,8 @@ ColumnLoop:
|
|||||||
|
|
||||||
// Helper function which draws border runes.
|
// Helper function which draws border runes.
|
||||||
borderStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.bordersColor)
|
borderStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.bordersColor)
|
||||||
selectedBorderStyle := tcell.StyleDefault.Background(t.bordersColor).Foreground(t.backgroundColor)
|
drawBorder := func(colX, rowY int, ch rune) {
|
||||||
drawBorder := func(colX, rowY int, ch rune, selected bool) {
|
screen.SetContent(x+colX, y+rowY, ch, nil, borderStyle)
|
||||||
style := borderStyle
|
|
||||||
if selected {
|
|
||||||
style = selectedBorderStyle
|
|
||||||
}
|
|
||||||
screen.SetContent(x+colX, y+rowY, ch, nil, style)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the cells (and borders).
|
// Draw the cells (and borders).
|
||||||
@ -590,17 +588,12 @@ ColumnLoop:
|
|||||||
}
|
}
|
||||||
for columnIndex, column := range columns {
|
for columnIndex, column := range columns {
|
||||||
columnWidth := widths[columnIndex]
|
columnWidth := widths[columnIndex]
|
||||||
columnSelected := t.columnsSelectable && !t.rowsSelectable && column == t.selectedColumn
|
|
||||||
for rowY, row := range rows {
|
for rowY, row := range rows {
|
||||||
// Is this row/cell selected?
|
|
||||||
rowSelected := t.rowsSelectable && !t.columnsSelectable && row == t.selectedRow
|
|
||||||
cellSelected := columnSelected || rowSelected || t.rowsSelectable && t.columnsSelectable && column == t.selectedColumn && row == t.selectedRow
|
|
||||||
|
|
||||||
if t.borders {
|
if t.borders {
|
||||||
// Draw borders.
|
// Draw borders.
|
||||||
rowY *= 2
|
rowY *= 2
|
||||||
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
|
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
|
||||||
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar, columnSelected)
|
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar)
|
||||||
}
|
}
|
||||||
ch := GraphicsCross
|
ch := GraphicsCross
|
||||||
if columnIndex == 0 {
|
if columnIndex == 0 {
|
||||||
@ -612,15 +605,15 @@ ColumnLoop:
|
|||||||
} else if rowY == 0 {
|
} else if rowY == 0 {
|
||||||
ch = GraphicsTopT
|
ch = GraphicsTopT
|
||||||
}
|
}
|
||||||
drawBorder(columnX, rowY, ch, false)
|
drawBorder(columnX, rowY, ch)
|
||||||
rowY++
|
rowY++
|
||||||
if rowY >= height {
|
if rowY >= height {
|
||||||
break // No space for the text anymore.
|
break // No space for the text anymore.
|
||||||
}
|
}
|
||||||
drawBorder(columnX, rowY, GraphicsVertBar, rowSelected)
|
drawBorder(columnX, rowY, GraphicsVertBar)
|
||||||
} else if columnIndex > 0 {
|
} else if columnIndex > 0 {
|
||||||
// Draw separator.
|
// Draw separator.
|
||||||
drawBorder(columnX, rowY, t.separator, rowSelected)
|
drawBorder(columnX, rowY, t.separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the cell.
|
// Get the cell.
|
||||||
@ -641,61 +634,18 @@ ColumnLoop:
|
|||||||
fg, _, _ := style.Decompose()
|
fg, _, _ := style.Decompose()
|
||||||
Print(screen, string(GraphicsEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, fg)
|
Print(screen, string(GraphicsEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, fg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw cell background.
|
|
||||||
if cellSelected && !cell.NotSelectable || cell.BackgroundColor != tcell.ColorDefault {
|
|
||||||
for pos := 0; pos < finalWidth; pos++ {
|
|
||||||
m, c, style, _ := screen.GetContent(x+columnX+1+pos, y+rowY)
|
|
||||||
if cellSelected && !cell.NotSelectable {
|
|
||||||
// Create style for a selected cell.
|
|
||||||
fg, _, _ := style.Decompose()
|
|
||||||
if fg == cell.Color {
|
|
||||||
fg = cell.BackgroundColor
|
|
||||||
if fg == tcell.ColorDefault {
|
|
||||||
fg = t.backgroundColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
style = style.Background(cell.Color).Foreground(fg)
|
|
||||||
} else {
|
|
||||||
// Create style for a cell with a colored background.
|
|
||||||
style = style.Background(cell.BackgroundColor)
|
|
||||||
}
|
|
||||||
screen.SetContent(x+columnX+1+pos, y+rowY, m, c, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We may want continuous background colors in rows so change
|
|
||||||
// border/separator background colors, too.
|
|
||||||
cellBackground := cell.BackgroundColor
|
|
||||||
if cellSelected && !cell.NotSelectable {
|
|
||||||
cellBackground = cell.Color
|
|
||||||
}
|
|
||||||
if cellBackground != tcell.ColorDefault && column > 0 {
|
|
||||||
leftCell := getCell(row, column-1)
|
|
||||||
if leftCell != nil {
|
|
||||||
if cell.BackgroundColor == leftCell.BackgroundColor {
|
|
||||||
_, _, style, _ := screen.GetContent(x+columnX+1, y+rowY)
|
|
||||||
m, c, _, _ := screen.GetContent(x+columnX, y+rowY)
|
|
||||||
_, bgColor, _ := style.Decompose()
|
|
||||||
if t.columnsSelectable && column == t.selectedColumn {
|
|
||||||
bgColor = cell.BackgroundColor
|
|
||||||
}
|
|
||||||
screen.SetContent(x+columnX, y+rowY, m, c, style.Background(bgColor).Foreground(t.bordersColor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bottom border.
|
// Draw bottom border.
|
||||||
if rowY := 2 * len(rows); t.borders && rowY < height {
|
if rowY := 2 * len(rows); t.borders && rowY < height {
|
||||||
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
|
for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
|
||||||
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar, columnSelected)
|
drawBorder(columnX+pos+1, rowY, GraphicsHoriBar)
|
||||||
}
|
}
|
||||||
ch := GraphicsBottomT
|
ch := GraphicsBottomT
|
||||||
if columnIndex == 0 {
|
if columnIndex == 0 {
|
||||||
ch = GraphicsBottomLeftCorner
|
ch = GraphicsBottomLeftCorner
|
||||||
}
|
}
|
||||||
drawBorder(columnX, rowY, ch, false)
|
drawBorder(columnX, rowY, ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
columnX += columnWidth + 1
|
columnX += columnWidth + 1
|
||||||
@ -703,20 +653,109 @@ ColumnLoop:
|
|||||||
|
|
||||||
// Draw right border.
|
// Draw right border.
|
||||||
if t.borders && len(t.cells) > 0 && columnX < width {
|
if t.borders && len(t.cells) > 0 && columnX < width {
|
||||||
for rowY, row := range rows {
|
for rowY := range rows {
|
||||||
rowSelected := t.rowsSelectable && !t.columnsSelectable && row == t.selectedRow
|
|
||||||
rowY *= 2
|
rowY *= 2
|
||||||
if rowY+1 < height {
|
if rowY+1 < height {
|
||||||
drawBorder(columnX, rowY+1, GraphicsVertBar, rowSelected)
|
drawBorder(columnX, rowY+1, GraphicsVertBar)
|
||||||
}
|
}
|
||||||
ch := GraphicsRightT
|
ch := GraphicsRightT
|
||||||
if rowY == 0 {
|
if rowY == 0 {
|
||||||
ch = GraphicsTopRightCorner
|
ch = GraphicsTopRightCorner
|
||||||
}
|
}
|
||||||
drawBorder(columnX, rowY, ch, false)
|
drawBorder(columnX, rowY, ch)
|
||||||
}
|
}
|
||||||
if rowY := 2 * len(rows); rowY < height {
|
if rowY := 2 * len(rows); rowY < height {
|
||||||
drawBorder(columnX, rowY, GraphicsBottomRightCorner, false)
|
drawBorder(columnX, rowY, GraphicsBottomRightCorner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function which colors the background of a box.
|
||||||
|
colorBackground := func(fromX, fromY, w, h int, backgroundColor, textColor tcell.Color, selected 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)
|
||||||
|
if selected {
|
||||||
|
fg, _, _ := style.Decompose()
|
||||||
|
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 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
style = style.Background(backgroundColor)
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
cellsByBackgroundColor := make(map[tcell.Color][]*struct {
|
||||||
|
x, y, w, h int
|
||||||
|
text tcell.Color
|
||||||
|
selected bool
|
||||||
|
})
|
||||||
|
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, &struct {
|
||||||
|
x, y, w, h int
|
||||||
|
text tcell.Color
|
||||||
|
selected bool
|
||||||
|
}{
|
||||||
|
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
|
||||||
|
})
|
||||||
|
for _, bgColor := range backgroundColors {
|
||||||
|
entries := cellsByBackgroundColor[bgColor]
|
||||||
|
for _, cell := range entries {
|
||||||
|
if cell.selected {
|
||||||
|
defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, true)
|
||||||
|
} else {
|
||||||
|
colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user