[GH-ISSUE #20] Feature request - add "BackgroundColor" field to TableCell struct #15

Closed
opened 2026-03-04 01:01:07 +03:00 by kerem · 8 comments
Owner

Originally created by @andrewuhl on GitHub (Jan 13, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/20

It would be very nice to be able to set background colors for individual table cells.

When those (individually colored) cells are selected as part of a highlighted row or column, the current behavior of inverting text and background colors should remain as default behavior. More advanced future behavior might allow for setting all of the following:

  • cell text color
  • cell background color
  • cell selected text color
  • cell selected background color
Originally created by @andrewuhl on GitHub (Jan 13, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/20 It would be very nice to be able to set background colors for individual table cells. When those (individually colored) cells are selected as part of a highlighted row or column, the current behavior of inverting text and background colors should remain as default behavior. More advanced future behavior might allow for setting all of the following: - cell text color - cell background color - cell selected text color - cell selected background color
kerem closed this issue 2026-03-04 01:01:08 +03:00
Author
Owner

@rivo commented on GitHub (Jan 13, 2018):

Can you provide an example where this could be useful? I'm trying to strike a balance between keeping the package simple and covering common use cases. It would be good to understand where this is needed.

<!-- gh-comment-id:357429117 --> @rivo commented on GitHub (Jan 13, 2018): Can you provide an example where this could be useful? I'm trying to strike a balance between keeping the package simple and covering common use cases. It would be good to understand where this is needed.
Author
Owner

@andrewuhl commented on GitHub (Jan 13, 2018):

In general, having control over cell background coloring allows for better visual contrast.

Most common use cases that would be immediately useful for me include:

  • Column and row headers
  • Alternating row colors
  • Allows some rows to serve as headers for groups of data (see image below)
  • Conditional formatting based on cell value

Controlling text color alone doesn't quite provide the visual contrast needed.

image

Having different text and background colors based on selection state is a nice-to-have but not really that important. But controlling cell background color would be wonderful.

This is a terrific package, btw. Thanks for all the great work!

<!-- gh-comment-id:357443218 --> @andrewuhl commented on GitHub (Jan 13, 2018): In general, having control over cell background coloring allows for better visual contrast. Most common use cases that would be immediately useful for me include: * Column and row headers * Alternating row colors * Allows some rows to serve as headers for groups of data (see image below) * Conditional formatting based on cell value Controlling text color alone doesn't quite provide the visual contrast needed. ![image](https://user-images.githubusercontent.com/15974852/34907341-1317c3a8-f84b-11e7-9847-fcf5666f0345.png) Having different text and background colors based on selection state is a nice-to-have but not really that important. But controlling cell background color would be wonderful. This is a terrific package, btw. Thanks for all the great work!
Author
Owner

@rivo commented on GitHub (Jan 14, 2018):

So I added this. Thank you for your explanation. It will require some people to use the NewTableCell() constructor or explicitly define a background color now because tcell.Color defaults to black (see #1 for where this would cause issues).

Also, it's quite difficult to make this work with borders. You examples don't have character-wide/high borders but in a terminal, it looks odd when a cell has a background color but the cell borders don't. I implemented a simple solution for now. Might improve this later on.

<!-- gh-comment-id:357515636 --> @rivo commented on GitHub (Jan 14, 2018): So I added this. Thank you for your explanation. It will require some people to use the `NewTableCell()` constructor or explicitly define a background color now because `tcell.Color` defaults to black (see #1 for where this would cause issues). Also, it's quite difficult to make this work with borders. You examples don't have character-wide/high borders but in a terminal, it looks odd when a cell has a background color but the cell borders don't. I implemented a simple solution for now. Might improve this later on.
Author
Owner

@andrewuhl commented on GitHub (Jan 16, 2018):

From what I have seen, something like the following should correct at least some of the border issues that come about when using cell background color (not clear what other issues it may cause):

//if cell.BackgroundColor != tcell.ColorDefault && column > 0 {
if (t.rowsSelectable || cell.BackgroundColor != tcell.ColorDefault) && column > 0 {
	leftCell := getCell(row, column-1)
	if leftCell != nil {
		//if cell.BackgroundColor == leftCell.BackgroundColor {
		ch, _, style, _ := screen.GetContent(x+columnX, y+rowY)
		screen.SetContent(x+columnX, y+rowY, ch, nil, style.Background(bgColor))
		//}
	}
}
<!-- gh-comment-id:357850491 --> @andrewuhl commented on GitHub (Jan 16, 2018): From what I have seen, something like the following should correct at least some of the border issues that come about when using cell background color (not clear what other issues it may cause): ```go //if cell.BackgroundColor != tcell.ColorDefault && column > 0 { if (t.rowsSelectable || cell.BackgroundColor != tcell.ColorDefault) && column > 0 { leftCell := getCell(row, column-1) if leftCell != nil { //if cell.BackgroundColor == leftCell.BackgroundColor { ch, _, style, _ := screen.GetContent(x+columnX, y+rowY) screen.SetContent(x+columnX, y+rowY, ch, nil, style.Background(bgColor)) //} } } ```
Author
Owner

@rivo commented on GitHub (Jan 17, 2018):

I think this causes more problems than before. It includes the left cell border in situations where it shouldn't, in my opinion.

I did make a change for column-only selections, though. Those still looked odd but should be ok now.

If you encounter any situations where it doesn't seem to look correct, you could include a screenshot here or the code which uses the Table class.

<!-- gh-comment-id:358234510 --> @rivo commented on GitHub (Jan 17, 2018): I think this causes more problems than before. It includes the left cell border in situations where it shouldn't, in my opinion. I did make a change for column-only selections, though. Those still looked odd but should be ok now. If you encounter any situations where it doesn't seem to look correct, you could include a screenshot here or the code which uses the `Table` class.
Author
Owner

@andrewuhl commented on GitHub (Jan 18, 2018):

Here is a table example using the most recent master (as of 2018/1/17).

table_gaps

Here is a table example using the above code change to table.go as of two days ago (despite other problems it causes as you identified):

table_nogaps

The above image illustrates what I believe to be desirable behavior with respect to background colors and cell borders (aka "separator" or "gap").

I used the following code to produce both images (again, the first using my small change to table.go in the previous comment, and the second using today's most recent master):

// Demo code for the Table primitive.
package main

import (
	"fmt"
	"math/rand"

	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
)

func main() {
	app := tview.NewApplication()
	table := tview.NewTable()
	table.SetBorder(false)
	cols, rows := 5, 20

	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			color := tcell.ColorWhite
			bgcolor := tcell.ColorDefault
			value := (rand.Float64() - 0.25) * 100
			text := fmt.Sprintf("%.2f%%", value)
			align := tview.AlignRight
			if r == 0 {
				bgcolor = tcell.ColorGreen
				text = fmt.Sprintf("Column %d", c+1)
				align = tview.AlignCenter
			}
			if c == 0 {
				bgcolor = tcell.ColorGreen
				if r == 0 {
					text = ""
				} else {
					text = fmt.Sprintf(" Row %d ", r)
				}
				align = tview.AlignLeft
			}
			if r > 0 && c > 0 && value < 0 {
				bgcolor = tcell.ColorDarkMagenta
			}
			table.SetCell(r, c, &tview.TableCell{
				Text:            text,
				Color:           color,
				BackgroundColor: bgcolor,
				Align:           align,
				NotSelectable:   r == 0 || c == 0,
			})
			table.SetBackgroundColor(tcell.ColorBlack)
		}
	}
	table.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) {
		if key == tcell.KeyEscape {
			table.SetSelectable(false, false)
		} else if key == tcell.KeyEnter {
			table.SetSelectable(true, false)
		} else if key == tcell.KeyBackspace {
			table.SetSelectable(false, true)
		}
	}).SetSelectedFunc(func(row int, column int) {
		table.SetSelectable(false, false)
	})
	if err := app.SetRoot(table, true).SetFocus(table).Run(); err != nil {
		panic(err)
	}
}

It seems that the default separator rune (space character) makes the logic substantially more challenging when using background colors. If this is true, would it be possible to optionally not have any cell separator, thereby (hopefully) eliminating the problems with adjacent cell background coloring?

<!-- gh-comment-id:358510365 --> @andrewuhl commented on GitHub (Jan 18, 2018): Here is a table example using the most recent master (as of 2018/1/17). ![table_gaps](https://user-images.githubusercontent.com/15974852/35076240-6008bf28-fbc5-11e7-85f3-73e681578d8d.png) Here is a table example using the above code change to table.go as of two days ago (despite other problems it causes as you identified): ![table_nogaps](https://user-images.githubusercontent.com/15974852/35076276-948e77a6-fbc5-11e7-9b85-c2214cc09048.png) The above image illustrates what I believe to be desirable behavior with respect to background colors and cell borders (aka "separator" or "gap"). I used the following code to produce both images (again, the first using my small change to table.go in the previous comment, and the second using today's most recent master): ```go // Demo code for the Table primitive. package main import ( "fmt" "math/rand" "github.com/gdamore/tcell" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() table := tview.NewTable() table.SetBorder(false) cols, rows := 5, 20 for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { color := tcell.ColorWhite bgcolor := tcell.ColorDefault value := (rand.Float64() - 0.25) * 100 text := fmt.Sprintf("%.2f%%", value) align := tview.AlignRight if r == 0 { bgcolor = tcell.ColorGreen text = fmt.Sprintf("Column %d", c+1) align = tview.AlignCenter } if c == 0 { bgcolor = tcell.ColorGreen if r == 0 { text = "" } else { text = fmt.Sprintf(" Row %d ", r) } align = tview.AlignLeft } if r > 0 && c > 0 && value < 0 { bgcolor = tcell.ColorDarkMagenta } table.SetCell(r, c, &tview.TableCell{ Text: text, Color: color, BackgroundColor: bgcolor, Align: align, NotSelectable: r == 0 || c == 0, }) table.SetBackgroundColor(tcell.ColorBlack) } } table.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { if key == tcell.KeyEscape { table.SetSelectable(false, false) } else if key == tcell.KeyEnter { table.SetSelectable(true, false) } else if key == tcell.KeyBackspace { table.SetSelectable(false, true) } }).SetSelectedFunc(func(row int, column int) { table.SetSelectable(false, false) }) if err := app.SetRoot(table, true).SetFocus(table).Run(); err != nil { panic(err) } } ``` It seems that the default separator rune (space character) makes the logic substantially more challenging when using background colors. If this is true, would it be possible to optionally not have any cell separator, thereby (hopefully) eliminating the problems with adjacent cell background coloring?
Author
Owner

@rivo commented on GitHub (Jan 19, 2018):

It probably wouldn't be very hard to make it work if there was no space at all between columns. I don't see this as an option, though. It would lead to odd side effects when two neighbouring strings are joined. (And it adds even more complexity to the code.)

Just a slight modification to your code (calling SetBorders(true)) illustrates how the situation is much more complex than what can be seen in your screenshots:

image

You can see that the current code joins neighbouring cells' background if they are the same. (Not so with joining horizontal lines.) Here we also have a green cell ("Row 1") and a magenta cell ("-18.44%"), divided by a vertical line. Does the vertical line's background need to be colored? And if so, should it be green or magenta?

Your first example definitely shows an undesired effect so I'm reopening this issue now.

But the solution will require some more thought. I don't see a quick fix here like you suggested.

<!-- gh-comment-id:359072418 --> @rivo commented on GitHub (Jan 19, 2018): It probably wouldn't be very hard to make it work if there was no space at all between columns. I don't see this as an option, though. It would lead to odd side effects when two neighbouring strings are joined. (And it adds even more complexity to the code.) Just a slight modification to your code (calling `SetBorders(true)`) illustrates how the situation is much more complex than what can be seen in your screenshots: ![image](https://user-images.githubusercontent.com/480930/35168629-ebce9a56-fd59-11e7-9198-4cc000250552.png) You can see that the current code joins neighbouring cells' background if they are the same. (Not so with joining horizontal lines.) Here we also have a green cell ("Row 1") and a magenta cell ("-18.44%"), divided by a vertical line. Does the vertical line's background need to be colored? And if so, should it be green or magenta? Your first example definitely shows an undesired effect so I'm reopening this issue now. But the solution will require some more thought. I don't see a quick fix here like you suggested.
Author
Owner

@rivo commented on GitHub (Jan 20, 2018):

I rewrote the whole background color logic. The new solution should make your examples look like one would expect.

When a table has borders around each cell, it's more difficult because neighbouring cells share the same border so I have to make a tradeoff. But I think the way it is now is the best I can think of.

<!-- gh-comment-id:359205988 --> @rivo commented on GitHub (Jan 20, 2018): I rewrote the whole background color logic. The new solution should make your examples look like one would expect. When a table has borders around each cell, it's more difficult because neighbouring cells share the same border so I have to make a tradeoff. But I think the way it is now is the best I can think of.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#15
No description provided.