From 79d4cc321256d43fb9c57880b4cf8233ff536ab2 Mon Sep 17 00:00:00 2001 From: Oliver <480930+rivo@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:14:10 +0200 Subject: [PATCH] Added individual styling for selected table cells. Resolves #934 --- application.go | 2 +- box.go | 8 ++--- table.go | 98 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/application.go b/application.go index 7c3bdfe..e5d9784 100644 --- a/application.go +++ b/application.go @@ -679,7 +679,7 @@ func (a *Application) draw() *Application { } // Resize if requested. - if fullscreen && root != nil { + if fullscreen { // root is not nil here. width, height := screen.Size() root.SetRect(0, 0, width, height) } diff --git a/box.go b/box.go index 1b6ed5d..23fd416 100644 --- a/box.go +++ b/box.go @@ -437,8 +437,8 @@ func (b *Box) DrawForSubclass(screen tcell.Screen, p Primitive) { } // SetFocusFunc sets a callback function which is invoked when this primitive -// receives focus. Container primitives such as Flex or Grid may not be notified -// if one of their descendents receive focus directly. +// receives focus. Container primitives such as [Flex] or [Grid] may not be +// notified if one of their descendents receive focus directly. // // Set to nil to remove the callback function. func (b *Box) SetFocusFunc(callback func()) *Box { @@ -447,8 +447,8 @@ func (b *Box) SetFocusFunc(callback func()) *Box { } // SetBlurFunc sets a callback function which is invoked when this primitive -// loses focus. This does not apply to container primitives such as Flex or -// Grid. +// loses focus. This does not apply to container primitives such as [Flex] or +// [Grid]. // // Set to nil to remove the callback function. func (b *Box) SetBlurFunc(callback func()) *Box { diff --git a/table.go b/table.go index 66b1bc8..92b94cc 100644 --- a/table.go +++ b/table.go @@ -30,19 +30,32 @@ type TableCell struct { // used to add extra width to a column. See SetExpansion() for details. Expansion int - // The color of the cell text. + // The color of the cell text. You should not use this anymore, it is only + // here for backwards compatibility. Use the Style field instead. Color tcell.Color - // The background color of the cell. + // The background color of the cell. You should not use this anymore, it is + // only here for backwards compatibility. Use the Style field instead. BackgroundColor tcell.Color + // The style attributes of the cell. You should not use this anymore, it is + // only here for backwards compatibility. Use the Style field instead. + Attributes tcell.AttrMask + + // The style of the cell. If this is uninitialized (tcell.StyleDefault), the + // Color and BackgroundColor fields are used instead. + Style tcell.Style + + // The style of the cell when it is selected. If this is uninitialized + // (tcell.StyleDefault), the table's selected style is used instead. If that + // is uninitialized as well, the cell's background and text color are + // swapped. + SelectedStyle tcell.Style + // If set to true, the BackgroundColor is not used and the cell will have // the background color of the table. Transparent bool - // The style attributes of the cell. - Attributes tcell.AttrMask - // If set to true, this cell cannot be selected. NotSelectable bool @@ -60,11 +73,10 @@ type TableCell struct { // background (using the background of the Table). func NewTableCell(text string) *TableCell { return &TableCell{ - Text: text, - Align: AlignLeft, - Color: Styles.PrimaryTextColor, - BackgroundColor: Styles.PrimitiveBackgroundColor, - Transparent: true, + Text: text, + Align: AlignLeft, + Style: tcell.StyleDefault.Foreground(Styles.PrimaryTextColor).Background(Styles.PrimitiveBackgroundColor), + Transparent: true, } } @@ -112,14 +124,22 @@ func (c *TableCell) SetExpansion(expansion int) *TableCell { // SetTextColor sets the cell's text color. func (c *TableCell) SetTextColor(color tcell.Color) *TableCell { - c.Color = color + if c.Style == tcell.StyleDefault { + c.Color = color + } else { + c.Style = c.Style.Foreground(color) + } return c } // SetBackgroundColor sets the cell's background color. This will also cause the // cell's Transparent flag to be set to "false". func (c *TableCell) SetBackgroundColor(color tcell.Color) *TableCell { - c.BackgroundColor = color + if c.Style == tcell.StyleDefault { + c.BackgroundColor = color + } else { + c.Style = c.Style.Background(color) + } c.Transparent = false return c } @@ -137,14 +157,27 @@ func (c *TableCell) SetTransparency(transparent bool) *TableCell { // // cell.SetAttributes(tcell.AttrUnderline | tcell.AttrBold) func (c *TableCell) SetAttributes(attr tcell.AttrMask) *TableCell { - c.Attributes = attr + if c.Style == tcell.StyleDefault { + c.Attributes = attr + } else { + c.Style = c.Style.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() + c.Style = style + return c +} + +// SetSelectedStyle sets the cell's style when it is selected. If this is +// uninitialized (tcell.StyleDefault), the table's selected style is used +// instead. If that is uninitialized as well, the cell's background and text +// color are swapped. +func (c *TableCell) SetSelectedStyle(style tcell.Style) *TableCell { + c.SelectedStyle = style return c } @@ -549,12 +582,12 @@ func (t *Table) SetBordersColor(color tcell.Color) *Table { } // 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). +// is set, the cell's background and text color are swapped. If a cell defines +// its own selected style, that will be used instead. // // To reset a previous setting to its default, make the following call: // -// table.SetSelectedStyle(tcell.Style{}) +// table.SetSelectedStyle(tcell.StyleDefault) func (t *Table) SetSelectedStyle(style tcell.Style) *Table { t.selectedStyle = style return t @@ -1157,7 +1190,11 @@ func (t *Table) Draw(screen tcell.Screen) { finalWidth = width - columnX } cell.x, cell.y, cell.width = x+columnX, y+rowY, finalWidth - start, end, _ := printWithStyle(screen, cell.Text, x+columnX, y+rowY, 0, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color).Attributes(cell.Attributes), true) + style := cell.Style + if style == tcell.StyleDefault { + style = tcell.StyleDefault.Background(cell.BackgroundColor).Foreground(cell.Color).Attributes(cell.Attributes) + } + start, end, _ := printWithStyle(screen, cell.Text, x+columnX, y+rowY, 0, finalWidth, cell.Align, style, true) printed := end - start if TaggedStringWidth(cell.Text)-printed > 0 && printed > 0 { _, _, style, _ := screen.GetContent(x+columnX+finalWidth-1, y+rowY) @@ -1272,8 +1309,12 @@ func (t *Table) Draw(screen tcell.Screen) { } 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{ + backgroundColor := cell.BackgroundColor + if cell.Style != tcell.StyleDefault { + _, backgroundColor, _ = cell.Style.Decompose() + } + entries, ok := cellsByBackgroundColor[backgroundColor] + cellsByBackgroundColor[backgroundColor] = append(entries, &cellInfo{ x: bx, y: by, w: bw, @@ -1282,7 +1323,7 @@ func (t *Table) Draw(screen tcell.Screen) { selected: cellSelected, }) if !ok { - backgroundColors = append(backgroundColors, cell.BackgroundColor) + backgroundColors = append(backgroundColors, backgroundColor) } columnX += columnWidth + 1 } @@ -1297,18 +1338,25 @@ func (t *Table) Draw(screen tcell.Screen) { _, _, lj := c.Hcl() return li < lj }) - selFg, selBg, selAttr := t.selectedStyle.Decompose() for _, bgColor := range backgroundColors { entries := cellsByBackgroundColor[bgColor] for _, info := range entries { + textColor := info.cell.Color + if info.cell.Style != tcell.StyleDefault { + textColor, _, _ = info.cell.Style.Decompose() + } if info.selected { - if t.selectedStyle != (tcell.Style{}) { + if info.cell.SelectedStyle != tcell.StyleDefault { + selFg, selBg, selAttr := info.cell.SelectedStyle.Decompose() + defer colorBackground(info.x, info.y, info.w, info.h, selBg, selFg, false, false, selAttr, false) + } else if t.selectedStyle != tcell.StyleDefault { + selFg, selBg, selAttr := t.selectedStyle.Decompose() defer colorBackground(info.x, info.y, info.w, info.h, selBg, selFg, false, false, selAttr, false) } else { - defer colorBackground(info.x, info.y, info.w, info.h, bgColor, info.cell.Color, false, false, 0, true) + defer colorBackground(info.x, info.y, info.w, info.h, bgColor, textColor, false, false, 0, true) } } else { - colorBackground(info.x, info.y, info.w, info.h, bgColor, info.cell.Color, info.cell.Transparent, true, 0, false) + colorBackground(info.x, info.y, info.w, info.h, bgColor, textColor, info.cell.Transparent, true, 0, false) } } }