diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea6ad8631b..322a868b2b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- The devtools console now confirms when CSS files have been successfully loaded after a previous error https://github.com/Textualize/textual/pull/2716
+- Added `cursor_foreground_priority` and `cursor_background_priority` to `DataTable` https://github.com/Textualize/textual/pull/2736
### Fixed
diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py
index 0f40552be0..840cb78928 100644
--- a/src/textual/widgets/_data_table.py
+++ b/src/textual/widgets/_data_table.py
@@ -579,6 +579,8 @@ def __init__(
zebra_stripes: bool = False,
header_height: int = 1,
show_cursor: bool = True,
+ cursor_foreground_priority: Literal["renderable", "css"] = "css",
+ cursor_background_priority: Literal["renderable", "css"] = "renderable",
name: str | None = None,
id: str | None = None,
classes: str | None = None,
@@ -660,6 +662,12 @@ def __init__(
"""Apply zebra effect on row backgrounds (light, dark, light, dark, ...)."""
self.show_cursor = show_cursor
"""Show/hide both the keyboard and hover cursor."""
+ self.cursor_foreground_priority = cursor_foreground_priority
+ """Should we prioritize the cursor component class CSS foreground or the renderable foreground
+ in the event where a cell contains a renderable with a foreground color."""
+ self.cursor_background_priority = cursor_background_priority
+ """Should we prioritize the cursor component class CSS background or the renderable background
+ in the event where a cell contains a renderable with a background color."""
@property
def hover_row(self) -> int:
@@ -1651,38 +1659,42 @@ def _render_cell(
else:
cell = row_cells[column_index]
- get_component = self.get_component_styles
+ get_component = self.get_component_rich_style
show_cursor = self.show_cursor
-
component_style = Style()
if hover and show_cursor and self._show_hover_cursor:
- component_style += get_component("datatable--hover").rich_style
+ component_style += get_component("datatable--hover")
if is_header_cell or is_row_label_cell:
# Apply subtle variation in style for the header/label (blue background by
# default) rows and columns affected by the cursor, to ensure we can
# still differentiate between the labels and the data.
- component_style += get_component(
- "datatable--header-hover"
- ).rich_style
+ component_style += get_component("datatable--header-hover")
if cursor and show_cursor:
- cursor_style = get_component("datatable--cursor").rich_style
+ cursor_style = get_component("datatable--cursor")
component_style += cursor_style
if is_header_cell or is_row_label_cell:
- component_style += get_component(
- "datatable--header-cursor"
- ).rich_style
+ component_style += get_component("datatable--header-cursor")
elif is_fixed_style_cell:
- component_style += get_component(
- "datatable--fixed-cursor"
- ).rich_style
+ component_style += get_component("datatable--fixed-cursor")
+
+ post_foreground = (
+ Style.from_color(color=component_style.color)
+ if self.cursor_foreground_priority == "css"
+ else Style.null()
+ )
+ post_background = (
+ Style.from_color(bgcolor=component_style.bgcolor)
+ if self.cursor_background_priority == "css"
+ else Style.null()
+ )
lines = self.app.console.render_lines(
Styled(
Padding(cell, (0, 1)),
- pre_style=base_style,
- post_style=component_style,
+ pre_style=base_style + component_style,
+ post_style=post_foreground + post_background,
),
self.app.console.options.update_dimensions(width, height),
)
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
index 7252c099af..4f50440653 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
@@ -13568,136 +13568,137 @@
font-weight: 700;
}
- .terminal-490238722-matrix {
+ .terminal-1146140386-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-490238722-title {
+ .terminal-1146140386-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-490238722-r1 { fill: #dde6ed;font-weight: bold }
- .terminal-490238722-r2 { fill: #dde6ed }
- .terminal-490238722-r3 { fill: #c5c8c6 }
- .terminal-490238722-r4 { fill: #0a180e;font-weight: bold;font-style: italic; }
- .terminal-490238722-r5 { fill: #e1e2e3 }
- .terminal-490238722-r6 { fill: #e1e1e1 }
- .terminal-490238722-r7 { fill: #cc555a }
+ .terminal-1146140386-r1 { fill: #e1e1e1 }
+ .terminal-1146140386-r2 { fill: #c5c8c6 }
+ .terminal-1146140386-r3 { fill: #dde6ed;font-weight: bold }
+ .terminal-1146140386-r4 { fill: #dde6ed }
+ .terminal-1146140386-r5 { fill: #fea62b;font-weight: bold;font-style: italic; }
+ .terminal-1146140386-r6 { fill: #e1e2e3 }
+ .terminal-1146140386-r7 { fill: #cc555a }
+ .terminal-1146140386-r8 { fill: #cc555a;font-weight: bold;font-style: italic; }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- DataTableCursorStyles
+ DataTableCursorStyles
-
-
-
- Movies
- Severance
- Foundation
- Dark
- The Boys
- The Last of Us
- Lost in Space
- Altered Carbon
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Foreground is 'css', background is 'css':
+ Movies
+ Severance
+ Foundation
+ Dark
+
+ Foreground is 'css', background is 'renderable':
+ Movies
+ Severance
+ Foundation
+ Dark
+
+ Foreground is 'renderable', background is 'renderable':
+ Movies
+ Severance
+ Foundation
+ Dark
+
+ Foreground is 'renderable', background is 'css':
+ Movies
+ Severance
+ Foundation
+ Dark
diff --git a/tests/snapshot_tests/snapshot_apps/data_table_style_order.py b/tests/snapshot_tests/snapshot_apps/data_table_style_order.py
index 06f9bf2ebc..40844053da 100644
--- a/tests/snapshot_tests/snapshot_apps/data_table_style_order.py
+++ b/tests/snapshot_tests/snapshot_apps/data_table_style_order.py
@@ -1,17 +1,26 @@
+from typing_extensions import Literal
+
from textual.app import App, ComposeResult
-from textual.widgets import DataTable
+from textual.widgets import DataTable, Label
data = [
"Severance",
"Foundation",
"Dark",
- "The Boys",
- "The Last of Us",
- "Lost in Space",
- "Altered Carbon",
]
+def make_datatable(foreground_priority: Literal["css", "renderable"],
+ background_priority: Literal["css", "renderable"]) -> DataTable:
+ table = DataTable(cursor_foreground_priority=foreground_priority,
+ cursor_background_priority=background_priority)
+ table.zebra_stripes = True
+ table.add_column("Movies")
+ for row in data:
+ table.add_row(f"[red on blue]{row}")
+ return table
+
+
class DataTableCursorStyles(App):
"""Regression test snapshot app which ensures that styles
are layered on top of each other correctly in the DataTable.
@@ -20,18 +29,28 @@ class DataTableCursorStyles(App):
on top."""
CSS = """
+ DataTable {margin-bottom: 1;}
DataTable > .datatable--cursor {
- color: $text;
+ color: $secondary;
background: $success;
text-style: bold italic;
}
"""
def compose(self) -> ComposeResult:
- table = DataTable()
- table.zebra_stripes = True
- table.add_column("Movies")
- for row in data:
- table.add_row(f"[red]{row}")
- table.focus()
- yield table
+ priorities: list[tuple[Literal["css", "renderable"], Literal["css", "renderable"]]] = [
+ ("css", "css"),
+ ("css", "renderable"),
+ ("renderable", "renderable"),
+ ("renderable", "css"),
+ ]
+ for foreground, background in priorities:
+ yield Label(f"Foreground is {foreground!r}, background is {background!r}:")
+ table = make_datatable(foreground, background)
+ yield table
+
+
+app = DataTableCursorStyles()
+
+if __name__ == '__main__':
+ app.run()