mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
render lines and scrollbars
This commit is contained in:
@@ -28,9 +28,11 @@ App > Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataTable {
|
DataTable {
|
||||||
border: solid red;
|
/*border:heavy red;*/
|
||||||
|
/* tint: 10% green; */
|
||||||
margin: 1 1;
|
/* opacity: 50%; */
|
||||||
|
padding: 1;
|
||||||
|
margin: 1 2;
|
||||||
height: 12;
|
height: 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ Tweet {
|
|||||||
|
|
||||||
|
|
||||||
.scrollable {
|
.scrollable {
|
||||||
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
margin: 1 2;
|
margin: 1 2;
|
||||||
height: 20;
|
height: 20;
|
||||||
@@ -113,8 +115,7 @@ Tweet {
|
|||||||
layout: vertical;
|
layout: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.code {
|
.code {
|
||||||
|
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -386,33 +386,23 @@ class Compositor:
|
|||||||
|
|
||||||
# Add any scrollbars
|
# Add any scrollbars
|
||||||
for chrome_widget, chrome_region in widget._arrange_scrollbars(
|
for chrome_widget, chrome_region in widget._arrange_scrollbars(
|
||||||
container_size
|
container_region
|
||||||
):
|
):
|
||||||
map[chrome_widget] = MapGeometry(
|
map[chrome_widget] = MapGeometry(
|
||||||
chrome_region + container_region.offset + layout_offset,
|
chrome_region + layout_offset,
|
||||||
order,
|
order,
|
||||||
clip,
|
clip,
|
||||||
container_size,
|
container_size,
|
||||||
container_size,
|
container_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
if widget.is_container:
|
map[widget] = MapGeometry(
|
||||||
# Add the container widget, which will render a background
|
region + layout_offset,
|
||||||
map[widget] = MapGeometry(
|
order,
|
||||||
region + layout_offset,
|
clip,
|
||||||
order,
|
total_region.size,
|
||||||
clip,
|
container_size,
|
||||||
total_region.size,
|
)
|
||||||
container_size,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
map[widget] = MapGeometry(
|
|
||||||
child_region + layout_offset,
|
|
||||||
order,
|
|
||||||
clip,
|
|
||||||
child_region.size,
|
|
||||||
container_size,
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Add the widget to the map
|
# Add the widget to the map
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from ._border import get_box, render_row
|
|||||||
from ._segment_tools import line_crop, line_pad, line_trim
|
from ._segment_tools import line_crop, line_pad, line_trim
|
||||||
from ._types import Lines
|
from ._types import Lines
|
||||||
from .color import Color
|
from .color import Color
|
||||||
from .geometry import Region, Size
|
from .geometry import Spacing, Region, Size
|
||||||
from .renderables.opacity import Opacity
|
from .renderables.opacity import Opacity
|
||||||
from .renderables.tint import Tint
|
from .renderables.tint import Tint
|
||||||
|
|
||||||
@@ -62,9 +62,18 @@ class StylesCache:
|
|||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
def is_dirty(self, y: int) -> bool:
|
def is_dirty(self, y: int) -> bool:
|
||||||
|
"""Check if a given line is dirty (needs to be rendered again).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y (int): Y coordinate of line.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if line requires a render, False if can be cached.
|
||||||
|
"""
|
||||||
return y in self._dirty_lines
|
return y in self._dirty_lines
|
||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
|
"""Clear the styles cache (will cause the content to re-render)."""
|
||||||
self._cache.clear()
|
self._cache.clear()
|
||||||
self._dirty_lines.clear()
|
self._dirty_lines.clear()
|
||||||
|
|
||||||
@@ -79,12 +88,15 @@ class StylesCache:
|
|||||||
Lines: Rendered lines.
|
Lines: Rendered lines.
|
||||||
"""
|
"""
|
||||||
(base_background, base_color), (background, color) = widget.colors
|
(base_background, base_color), (background, color) = widget.colors
|
||||||
|
padding = widget.styles.padding + widget.scrollbar_gutter
|
||||||
lines = self.render(
|
lines = self.render(
|
||||||
widget.styles,
|
widget.styles,
|
||||||
widget.region.size,
|
widget.region.size,
|
||||||
base_background,
|
base_background,
|
||||||
background,
|
background,
|
||||||
widget.render_line,
|
widget.render_line,
|
||||||
|
content_size=widget.content_region.size,
|
||||||
|
padding=padding,
|
||||||
crop=crop,
|
crop=crop,
|
||||||
)
|
)
|
||||||
return lines
|
return lines
|
||||||
@@ -95,35 +107,33 @@ class StylesCache:
|
|||||||
size: Size,
|
size: Size,
|
||||||
base_background: Color,
|
base_background: Color,
|
||||||
background: Color,
|
background: Color,
|
||||||
render_line: RenderLineCallback,
|
render_content_line: RenderLineCallback,
|
||||||
|
content_size: Size | None = None,
|
||||||
|
padding: Spacing | None = None,
|
||||||
crop: Region | None = None,
|
crop: Region | None = None,
|
||||||
) -> Lines:
|
) -> Lines:
|
||||||
"""Render a given region.
|
"""Render a widget content plus CSS styles.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
region (Region): A region in the screen to render.
|
styles (StylesBase): CSS Styles object.
|
||||||
|
size (Size): Size of widget.
|
||||||
|
base_background (Color): Background color beneath widget.
|
||||||
|
background (Color): Background color of widget.
|
||||||
|
render_content_line (RenderLineCallback): Callback to render content line.
|
||||||
|
content_size (Size | None, optional): Size of content or None to assume full size. Defaults to None.
|
||||||
|
padding (Spacing | None, optional): Override padding from Styles, or None to use styles.padding. Defaults to None.
|
||||||
|
crop (Region | None, optional): Region to crop to. Defaults to None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Lines: List of Segments, one per line.
|
Lines: Rendered lines.
|
||||||
"""
|
"""
|
||||||
return self._render(
|
if content_size is None:
|
||||||
size,
|
content_size = size
|
||||||
size.region if crop is None else crop,
|
if padding is None:
|
||||||
styles,
|
padding = styles.padding
|
||||||
base_background,
|
if crop is None:
|
||||||
background,
|
crop = size.region
|
||||||
render_line,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _render(
|
|
||||||
self,
|
|
||||||
size: Size,
|
|
||||||
crop: Region,
|
|
||||||
styles: StylesBase,
|
|
||||||
base_background: Color,
|
|
||||||
background: Color,
|
|
||||||
render_content_line: RenderLineCallback,
|
|
||||||
) -> Lines:
|
|
||||||
width, height = size
|
width, height = size
|
||||||
if width != self._width:
|
if width != self._width:
|
||||||
self.clear()
|
self.clear()
|
||||||
@@ -137,7 +147,14 @@ class StylesCache:
|
|||||||
for y in crop.line_range:
|
for y in crop.line_range:
|
||||||
if is_dirty(y) or y not in self._cache:
|
if is_dirty(y) or y not in self._cache:
|
||||||
line = render_line(
|
line = render_line(
|
||||||
styles, y, size, base_background, background, render_content_line
|
styles,
|
||||||
|
y,
|
||||||
|
size,
|
||||||
|
content_size,
|
||||||
|
padding,
|
||||||
|
base_background,
|
||||||
|
background,
|
||||||
|
render_content_line,
|
||||||
)
|
)
|
||||||
line = list(simplify(line))
|
line = list(simplify(line))
|
||||||
self._cache[y] = line
|
self._cache[y] = line
|
||||||
@@ -158,27 +175,34 @@ class StylesCache:
|
|||||||
styles: StylesBase,
|
styles: StylesBase,
|
||||||
y: int,
|
y: int,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
content_size: Size,
|
||||||
|
padding: Spacing,
|
||||||
base_background: Color,
|
base_background: Color,
|
||||||
background: Color,
|
background: Color,
|
||||||
render_content_line: RenderLineCallback,
|
render_content_line: RenderLineCallback,
|
||||||
) -> list[Segment]:
|
) -> list[Segment]:
|
||||||
"""Render a styled lines.
|
"""Render a styled line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
styles (RenderStyles): Styles object.
|
styles (StylesBase): Styles object.
|
||||||
y (int): The y coordinate of the line (relative to top of widget)
|
y (int): The y coordinate of the line (relative to widget screen offset).
|
||||||
size (Size): Size of the widget.
|
size (Size): Size of the widget.
|
||||||
base_background (Color): The background color beneath this widget.
|
content_size (Size): Size of the content area.
|
||||||
background (Color): Background color of the widget.
|
padding (Spacing): Padding.
|
||||||
|
base_background (Color): Background color of widget beneath this line.
|
||||||
|
background (Color): Background color of widget.
|
||||||
|
render_content_line (RenderLineCallback): Callback to render a line of content.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[Segment]: A line as a list of segments.
|
list[Segment]: _description_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
gutter = styles.gutter
|
gutter = styles.gutter
|
||||||
width, height = size
|
width, height = size
|
||||||
|
content_width, content_height = content_size
|
||||||
|
|
||||||
|
pad_top, pad_right, pad_bottom, pad_left = padding
|
||||||
|
|
||||||
pad_top, pad_right, pad_bottom, pad_left = styles.padding
|
|
||||||
(
|
(
|
||||||
(border_top, border_top_color),
|
(border_top, border_top_color),
|
||||||
(border_right, border_right_color),
|
(border_right, border_right_color),
|
||||||
@@ -252,7 +276,11 @@ class StylesCache:
|
|||||||
line = [Segment(" " * width, background_style)]
|
line = [Segment(" " * width, background_style)]
|
||||||
else:
|
else:
|
||||||
# Content with border and padding (C)
|
# Content with border and padding (C)
|
||||||
line = render_content_line(y - gutter.top)
|
content_y = y - gutter.top
|
||||||
|
if content_y < content_height:
|
||||||
|
line = render_content_line(y - gutter.top)
|
||||||
|
else:
|
||||||
|
line = [Segment(" " * content_width, inner)]
|
||||||
if inner:
|
if inner:
|
||||||
line = Segment.apply_style(line, inner)
|
line = Segment.apply_style(line, inner)
|
||||||
line = line_pad(line, pad_left, pad_right, inner)
|
line = line_pad(line, pad_left, pad_right, inner)
|
||||||
|
|||||||
@@ -459,6 +459,11 @@ class Region(NamedTuple):
|
|||||||
height + expand_height * 2,
|
height + expand_height * 2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def enlarge(self, size: tuple[int, int]) -> Region:
|
||||||
|
add_width, add_height = size
|
||||||
|
x, y, width, height = self
|
||||||
|
return Region(x, y, width + add_width, height + add_height)
|
||||||
|
|
||||||
@lru_cache(maxsize=1024)
|
@lru_cache(maxsize=1024)
|
||||||
def overlaps(self, other: Region) -> bool:
|
def overlaps(self, other: Region) -> bool:
|
||||||
"""Check if another region overlaps this region.
|
"""Check if another region overlaps this region.
|
||||||
|
|||||||
@@ -405,11 +405,6 @@ class Widget(DOMNode):
|
|||||||
enabled = self.show_vertical_scrollbar, self.show_horizontal_scrollbar
|
enabled = self.show_vertical_scrollbar, self.show_horizontal_scrollbar
|
||||||
return enabled
|
return enabled
|
||||||
|
|
||||||
@property
|
|
||||||
def scrollbar_dimensions(self) -> tuple[int, int]:
|
|
||||||
"""Get the size of any scrollbars on the widget"""
|
|
||||||
return (self.scrollbar_size_horizontal, self.scrollbar_size_vertical)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scrollbar_size_vertical(self) -> int:
|
def scrollbar_size_vertical(self) -> int:
|
||||||
"""Get the width used by the *vertical* scrollbar."""
|
"""Get the width used by the *vertical* scrollbar."""
|
||||||
@@ -426,6 +421,108 @@ class Widget(DOMNode):
|
|||||||
else 0
|
else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scrollbar_gutter(self) -> Spacing:
|
||||||
|
gutter = Spacing(
|
||||||
|
0, self.scrollbar_size_vertical, self.scrollbar_size_horizontal, 0
|
||||||
|
)
|
||||||
|
return gutter
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gutter(self) -> Spacing:
|
||||||
|
"""Spacing for padding / border / scrollbars."""
|
||||||
|
return self.styles.gutter + self.scrollbar_gutter
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content_size(self) -> Size:
|
||||||
|
return self.content_region.size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self) -> Size:
|
||||||
|
return self._size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def container_size(self) -> Size:
|
||||||
|
return self._container_size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content_region(self) -> Region:
|
||||||
|
"""Gets an absolute region containing the content (minus padding and border)."""
|
||||||
|
content_region = self.region.shrink(self.gutter)
|
||||||
|
return content_region
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content_offset(self) -> Offset:
|
||||||
|
"""An offset from the Widget origin where the content begins."""
|
||||||
|
x, y = self.gutter.top_left
|
||||||
|
return Offset(x, y)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def region(self) -> Region:
|
||||||
|
"""The region occupied by this widget, relative to the Screen."""
|
||||||
|
try:
|
||||||
|
return self.screen.find_widget(self).region
|
||||||
|
except errors.NoWidget:
|
||||||
|
return Region()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_region(self) -> Region:
|
||||||
|
"""The region within the scrollable area that is currently visible.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Region: New region.
|
||||||
|
"""
|
||||||
|
window_region = self.region.at_offset(self.scroll_offset)
|
||||||
|
return window_region
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scroll_offset(self) -> Offset:
|
||||||
|
return Offset(int(self.scroll_x), int(self.scroll_y))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_transparent(self) -> bool:
|
||||||
|
"""Check if the background styles is not set.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if there is background color, otherwise ``False``.
|
||||||
|
"""
|
||||||
|
return self.is_scrollable and self.styles.background.is_transparent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def console(self) -> Console:
|
||||||
|
"""Get the current console."""
|
||||||
|
return active_app.get().console
|
||||||
|
|
||||||
|
@property
|
||||||
|
def animate(self) -> BoundAnimator:
|
||||||
|
if self._animate is None:
|
||||||
|
self._animate = self.app.animator.bind(self)
|
||||||
|
assert self._animate is not None
|
||||||
|
return self._animate
|
||||||
|
|
||||||
|
@property
|
||||||
|
def layout(self) -> Layout:
|
||||||
|
"""Get the layout object if set in styles, or a default layout."""
|
||||||
|
return self.styles.layout or self._default_layout
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_container(self) -> bool:
|
||||||
|
"""Check if this widget is a container (contains other widgets).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if this widget is a container.
|
||||||
|
"""
|
||||||
|
return self.styles.layout is not None or bool(self.children)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_scrollable(self) -> bool:
|
||||||
|
"""Check if this Widget may be scrolled.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if this widget may be scrolled.
|
||||||
|
"""
|
||||||
|
return self.is_container
|
||||||
|
|
||||||
def _set_dirty(self, *regions: Region) -> None:
|
def _set_dirty(self, *regions: Region) -> None:
|
||||||
"""Set the Widget as 'dirty' (requiring re-paint).
|
"""Set the Widget as 'dirty' (requiring re-paint).
|
||||||
|
|
||||||
@@ -731,17 +828,17 @@ class Widget(DOMNode):
|
|||||||
region, _ = region.split_horizontal(-scrollbar_size_horizontal)
|
region, _ = region.split_horizontal(-scrollbar_size_horizontal)
|
||||||
return region
|
return region
|
||||||
|
|
||||||
def _arrange_scrollbars(self, size: Size) -> Iterable[tuple[Widget, Region]]:
|
def _arrange_scrollbars(self, region: Region) -> Iterable[tuple[Widget, Region]]:
|
||||||
"""Arrange the 'chrome' widgets (typically scrollbars) for a layout element.
|
"""Arrange the 'chrome' widgets (typically scrollbars) for a layout element.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
size (Size): Size of the containing region.
|
region (Region): The containing region.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Iterable[tuple[Widget, Region]]: Tuples of scrollbar Widget and region.
|
Iterable[tuple[Widget, Region]]: Tuples of scrollbar Widget and region.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
region = size.region
|
|
||||||
show_vertical_scrollbar, show_horizontal_scrollbar = self.scrollbars_enabled
|
show_vertical_scrollbar, show_horizontal_scrollbar = self.scrollbars_enabled
|
||||||
|
|
||||||
scrollbar_size_horizontal = self.scrollbar_size_horizontal
|
scrollbar_size_horizontal = self.scrollbar_size_horizontal
|
||||||
@@ -845,95 +942,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
return renderable
|
return renderable
|
||||||
|
|
||||||
@property
|
|
||||||
def content_size(self) -> Size:
|
|
||||||
return self.content_region.size
|
|
||||||
|
|
||||||
@property
|
|
||||||
def size(self) -> Size:
|
|
||||||
return self._size
|
|
||||||
|
|
||||||
@property
|
|
||||||
def container_size(self) -> Size:
|
|
||||||
return self._container_size
|
|
||||||
|
|
||||||
@property
|
|
||||||
def content_region(self) -> Region:
|
|
||||||
"""Gets an absolute region containing the content (minus padding and border)."""
|
|
||||||
return self.region.shrink(self.styles.gutter)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def content_offset(self) -> Offset:
|
|
||||||
"""An offset from the Widget origin where the content begins."""
|
|
||||||
x, y = self.styles.gutter.top_left
|
|
||||||
return Offset(x, y)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def region(self) -> Region:
|
|
||||||
"""The region occupied by this widget, relative to the Screen."""
|
|
||||||
try:
|
|
||||||
return self.screen.find_widget(self).region
|
|
||||||
except errors.NoWidget:
|
|
||||||
return Region()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def window_region(self) -> Region:
|
|
||||||
"""The region within the scrollable area that is currently visible.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Region: New region.
|
|
||||||
"""
|
|
||||||
window_region = self.region.at_offset(self.scroll_offset)
|
|
||||||
return window_region
|
|
||||||
|
|
||||||
@property
|
|
||||||
def scroll_offset(self) -> Offset:
|
|
||||||
return Offset(int(self.scroll_x), int(self.scroll_y))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_transparent(self) -> bool:
|
|
||||||
"""Check if the background styles is not set.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: ``True`` if there is background color, otherwise ``False``.
|
|
||||||
"""
|
|
||||||
return self.is_scrollable and self.styles.background.is_transparent
|
|
||||||
|
|
||||||
@property
|
|
||||||
def console(self) -> Console:
|
|
||||||
"""Get the current console."""
|
|
||||||
return active_app.get().console
|
|
||||||
|
|
||||||
@property
|
|
||||||
def animate(self) -> BoundAnimator:
|
|
||||||
if self._animate is None:
|
|
||||||
self._animate = self.app.animator.bind(self)
|
|
||||||
assert self._animate is not None
|
|
||||||
return self._animate
|
|
||||||
|
|
||||||
@property
|
|
||||||
def layout(self) -> Layout:
|
|
||||||
"""Get the layout object if set in styles, or a default layout."""
|
|
||||||
return self.styles.layout or self._default_layout
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_container(self) -> bool:
|
|
||||||
"""Check if this widget is a container (contains other widgets).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if this widget is a container.
|
|
||||||
"""
|
|
||||||
return self.styles.layout is not None or bool(self.children)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_scrollable(self) -> bool:
|
|
||||||
"""Check if this Widget may be scrolled.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if this widget may be scrolled.
|
|
||||||
"""
|
|
||||||
return self.is_container
|
|
||||||
|
|
||||||
def watch_mouse_over(self, value: bool) -> None:
|
def watch_mouse_over(self, value: bool) -> None:
|
||||||
"""Update from CSS if mouse over state changes."""
|
"""Update from CSS if mouse over state changes."""
|
||||||
self.app.update_styles()
|
self.app.update_styles()
|
||||||
|
|||||||
@@ -518,38 +518,6 @@ class DataTable(ScrollView, Generic[CellType]):
|
|||||||
lines = self._styles_cache.render_widget(self, crop)
|
lines = self._styles_cache.render_widget(self, crop)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
# def render_lines(self, crop: Region) -> Lines:
|
|
||||||
# """Render lines within a given region.
|
|
||||||
|
|
||||||
# Args:
|
|
||||||
# crop (Region): Region to crop to.
|
|
||||||
|
|
||||||
# Returns:
|
|
||||||
# Lines: A list of segments for every line within crop region.
|
|
||||||
# """
|
|
||||||
# scroll_y = self.scroll_offset.y
|
|
||||||
# x1, y1, x2, y2 = crop.translate(self.scroll_offset).corners
|
|
||||||
|
|
||||||
# base_style = self.rich_style
|
|
||||||
|
|
||||||
# fixed_top_row_count = sum(
|
|
||||||
# self.get_row_height(row_index) for row_index in range(self.fixed_rows)
|
|
||||||
# )
|
|
||||||
# if self.show_header:
|
|
||||||
# fixed_top_row_count += self.get_row_height(-1)
|
|
||||||
|
|
||||||
# render_line = self._render_line
|
|
||||||
# fixed_lines = [
|
|
||||||
# render_line(y, x1, x2, base_style) for y in range(0, fixed_top_row_count)
|
|
||||||
# ]
|
|
||||||
# lines = [render_line(y, x1, x2, base_style) for y in range(y1, y2)]
|
|
||||||
|
|
||||||
# for line_index, y in enumerate(range(y1, y2)):
|
|
||||||
# if y - scroll_y < fixed_top_row_count:
|
|
||||||
# lines[line_index] = fixed_lines[line_index]
|
|
||||||
|
|
||||||
# return lines
|
|
||||||
|
|
||||||
def on_mouse_move(self, event: events.MouseMove):
|
def on_mouse_move(self, event: events.MouseMove):
|
||||||
meta = event.style.meta
|
meta = event.style.meta
|
||||||
if meta:
|
if meta:
|
||||||
@@ -573,7 +541,6 @@ class DataTable(ScrollView, Generic[CellType]):
|
|||||||
|
|
||||||
def _scroll_cursor_in_to_view(self, animate: bool = False) -> None:
|
def _scroll_cursor_in_to_view(self, animate: bool = False) -> None:
|
||||||
region = self._get_cell_region(self.cursor_row, self.cursor_column)
|
region = self._get_cell_region(self.cursor_row, self.cursor_column)
|
||||||
region.translate(self.content_offset)
|
|
||||||
spacing = self._get_cell_border()
|
spacing = self._get_cell_border()
|
||||||
self.scroll_to_region(region, animate=animate, spacing=spacing)
|
self.scroll_to_region(region, animate=animate, spacing=spacing)
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ def test_no_styles():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
expected = [
|
expected = [
|
||||||
[Segment("foo", styles.rich_style)],
|
[Segment("foo", styles.rich_style)],
|
||||||
@@ -61,6 +62,7 @@ def test_border():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
|
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
@@ -91,6 +93,7 @@ def test_padding():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
|
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
@@ -122,6 +125,7 @@ def test_padding_border():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
|
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
@@ -154,6 +158,7 @@ def test_outline():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
|
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
@@ -181,6 +186,7 @@ def test_crop():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
content.__getitem__,
|
content.__getitem__,
|
||||||
|
content_size=Size(3, 3),
|
||||||
crop=Region(2, 2, 3, 3),
|
crop=Region(2, 2, 3, 3),
|
||||||
)
|
)
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
@@ -239,6 +245,7 @@ def test_dirty_cache():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
get_content_line,
|
get_content_line,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
assert rendered_lines == []
|
assert rendered_lines == []
|
||||||
del rendered_lines[:]
|
del rendered_lines[:]
|
||||||
@@ -254,6 +261,7 @@ def test_dirty_cache():
|
|||||||
Color.parse("blue"),
|
Color.parse("blue"),
|
||||||
Color.parse("green"),
|
Color.parse("green"),
|
||||||
get_content_line,
|
get_content_line,
|
||||||
|
content_size=Size(3, 3),
|
||||||
)
|
)
|
||||||
assert rendered_lines == [0, 1]
|
assert rendered_lines == [0, 1]
|
||||||
text_content = _extract_content(lines)
|
text_content = _extract_content(lines)
|
||||||
|
|||||||
Reference in New Issue
Block a user