"""Line-API scroll view for the continuous reader — renders only the rows actually visible on screen (via Widget.render_line), reading from the flat Strip list diora_tui.layout.build_layout() precomputed once. This is what keeps very large books responsive: nothing here scales with book size at paint time, only with viewport height. """ from __future__ import annotations from textual.geometry import Size from textual.scroll_view import ScrollView from textual.strip import Strip from .layout import BookLayout class ContinuousBookView(ScrollView): # We always wrap text to fit exactly, so a horizontal scrollbar should # never be needed — and "scroll" (not "auto") for the vertical one keeps # its gutter reserved from the very first (still-empty) layout pass, so # the width we wrap text at later never has to guess whether a scrollbar # will appear and steal columns out from under already-wrapped lines. DEFAULT_CSS = """ ContinuousBookView { overflow-x: hidden; overflow-y: scroll; } """ def __init__(self, book_layout: BookLayout) -> None: super().__init__() self.book_layout = book_layout self.virtual_size = Size(book_layout.width, book_layout.total_rows) def render_line(self, y: int) -> Strip: _scroll_x, scroll_y = self.scroll_offset row = scroll_y + y strips = self.book_layout.row_strips width = self.scrollable_content_region.width if row < 0 or row >= len(strips): return Strip.blank(width, self.rich_style) return strips[row].crop_extend(0, width, self.rich_style)