From 05143d44a5abf59f799042919d2665f2e0bdb54a Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Wed, 10 Aug 2022 16:13:54 +0100 Subject: [PATCH 1/6] Fill the spacing between the scrollbars --- sandbox/darren/just_a_box.css | 57 ++++++----------------------------- sandbox/darren/just_a_box.py | 24 +++++++++++---- src/textual/_compositor.py | 1 + src/textual/scrollbar.py | 9 ++++++ src/textual/widget.py | 21 ++++++++++--- 5 files changed, 55 insertions(+), 57 deletions(-) diff --git a/sandbox/darren/just_a_box.css b/sandbox/darren/just_a_box.css index 062dff0ec7..8279a027ac 100644 --- a/sandbox/darren/just_a_box.css +++ b/sandbox/darren/just_a_box.css @@ -1,61 +1,24 @@ Screen { - height: 100vh; - width: 100%; - background: red; -} - -#horizontal { - width: 100%; -} - -.box { - height: 5; - width: 5; - margin: 1 10; + background: lightcoral; } #left_pane { - width: 1fr; - background: $background; + background: red; + width: 10; + height: auto; } #middle_pane { - margin-top: 4; - width: 1fr; - background: #173f5f; -} - -#middle_pane:focus { - tint: cyan 40%; -} - -#right_pane { - width: 1fr; - background: #f6d55c; -} - -.box:focus { - tint: cyan 40%; -} - -#box1 { background: green; + width: 140; } -#box2 { - offset-y: 3; - background: hotpink; -} - -#box3 { - background: red; -} - - -#box4 { +#right_pane { background: blue; + width: 10; } -#box5 { - background: darkviolet; +.box { + height: 5; + width: 15; } diff --git a/sandbox/darren/just_a_box.py b/sandbox/darren/just_a_box.py index 8e6fc3ae79..781c66f67f 100644 --- a/sandbox/darren/just_a_box.py +++ b/sandbox/darren/just_a_box.py @@ -3,6 +3,7 @@ from rich.console import RenderableType from rich.panel import Panel +from textual import events from textual.app import App, ComposeResult from textual.layout import Horizontal, Vertical from textual.widget import Widget @@ -21,26 +22,37 @@ def render(self) -> RenderableType: class JustABox(App): - dark = True - def compose(self) -> ComposeResult: yield Horizontal( Vertical( Box(id="box1", classes="box"), Box(id="box2", classes="box"), - Box(id="box3", classes="box"), + # Box(id="box3", classes="box"), + # Box(id="box4", classes="box"), + # Box(id="box5", classes="box"), + # Box(id="box6", classes="box"), + # Box(id="box7", classes="box"), + # Box(id="box8", classes="box"), + # Box(id="box9", classes="box"), + # Box(id="box10", classes="box"), id="left_pane", ), Box(id="middle_pane"), Vertical( - Box(id="box", classes="box"), - Box(id="box4", classes="box"), - Box(id="box5", classes="box"), + Box(id="boxa", classes="box"), + Box(id="boxb", classes="box"), + Box(id="boxc", classes="box"), id="right_pane", ), id="horizontal", ) + def key_p(self): + print(self.query("#horizontal").first().styles.layout) + + async def on_key(self, event: events.Key) -> None: + await self.dispatch_key(event) + if __name__ == "__main__": app = JustABox(css_path="just_a_box.css", watch_css=True) diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 72b309d89a..bbb46ec6e6 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -405,6 +405,7 @@ def add_widget( for chrome_widget, chrome_region in widget._arrange_scrollbars( container_region ): + print(chrome_widget, chrome_region) map[chrome_widget] = MapGeometry( chrome_region + layout_offset, order, diff --git a/src/textual/scrollbar.py b/src/textual/scrollbar.py index ea5d510dd4..24674735df 100644 --- a/src/textual/scrollbar.py +++ b/src/textual/scrollbar.py @@ -9,6 +9,7 @@ from rich.style import Style, StyleType from textual.reactive import Reactive +from textual.renderables.blank import Blank from . import events from ._types import MessageTarget from .geometry import Offset @@ -287,6 +288,14 @@ async def on_mouse_move(self, event: events.MouseMove) -> None: await self.emit(ScrollTo(self, x=x, y=y)) +class ScrollBarCorner(Widget): + def __init__(self, name: str | None = None): + super().__init__(name=name) + + def render(self) -> RenderableType: + return Blank("violet") + + if __name__ == "__main__": from rich.console import Console diff --git a/src/textual/widget.py b/src/textual/widget.py index 76e4dd0439..663a796655 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -17,7 +17,6 @@ from rich.align import Align from rich.console import Console, RenderableType from rich.measure import Measurement - from rich.segment import Segment from rich.style import Style from rich.styled import Styled @@ -27,8 +26,7 @@ from ._animator import BoundAnimator from ._arrange import arrange, DockArrangeResult from ._context import active_app -from ._layout import ArrangeResult, Layout -from ._segment_tools import line_crop +from ._layout import Layout from ._styles_cache import StylesCache from ._types import Lines from .box_model import BoxModel, get_box_model @@ -47,6 +45,7 @@ ScrollRight, ScrollTo, ScrollUp, + ScrollBarCorner, ) @@ -103,6 +102,7 @@ def __init__( self._vertical_scrollbar: ScrollBar | None = None self._horizontal_scrollbar: ScrollBar | None = None + self._scrollbar_corner: ScrollBarCorner | None = None self._render_cache = RenderCache(Size(0, 0), []) # Regions which need to be updated (in Widget) @@ -342,6 +342,16 @@ def max_scroll_y(self) -> int: + self.scrollbar_size_horizontal, ) + @property + def scrollbar_corner(self) -> ScrollBarCorner: + from .scrollbar import ScrollBarCorner + + if self._scrollbar_corner is not None: + return self._scrollbar_corner + self._scrollbar_corner = ScrollBarCorner() + self.app.start_widget(self, self._scrollbar_corner) + return self._scrollbar_corner + @property def vertical_scrollbar(self) -> ScrollBar: """Get a vertical scrollbar (create if necessary) @@ -907,15 +917,18 @@ def _arrange_scrollbars(self, region: Region) -> Iterable[tuple[Widget, Region]] _, vertical_scrollbar_region, horizontal_scrollbar_region, - _, + scrollbar_corner_gap, ) = region.split( -scrollbar_size_vertical, -scrollbar_size_horizontal, ) + if scrollbar_corner_gap: + yield self.scrollbar_corner, scrollbar_corner_gap if vertical_scrollbar_region: yield self.vertical_scrollbar, vertical_scrollbar_region if horizontal_scrollbar_region: yield self.horizontal_scrollbar, horizontal_scrollbar_region + elif show_vertical_scrollbar: _, scrollbar_region = region.split_vertical(-scrollbar_size_vertical) if scrollbar_region: From e0fd91f88b0106f7bbfa9075c7ffe1add9c66c7a Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Wed, 10 Aug 2022 17:09:28 +0100 Subject: [PATCH 2/6] Add "scrollbar-corner-color" CSS rule and doc --- docs/styles/scrollbar.md | 18 ++++++++++-------- sandbox/darren/just_a_box.css | 4 ++-- sandbox/darren/just_a_box.py | 2 +- src/textual/css/_styles_builder.py | 1 + src/textual/css/styles.py | 4 ++++ src/textual/scrollbar.py | 4 +++- src/textual/widget.py | 4 ++++ 7 files changed, 25 insertions(+), 12 deletions(-) diff --git a/docs/styles/scrollbar.md b/docs/styles/scrollbar.md index 9a11b1cd95..1ad254ae9c 100644 --- a/docs/styles/scrollbar.md +++ b/docs/styles/scrollbar.md @@ -2,14 +2,16 @@ There are a number of rules to set the colors used in Textual scrollbars. You won't typically need to do this, as the default themes have carefully chosen colors, but you can if you want to. -| Rule | Color | -| ----------------------------- | ------------------------------------------------------- | -| `scrollbar-color` | Scrollbar "thumb" (movable part) | -| `scrollbar-color-hover` | Scrollbar thumb when the mouse is hovering over it | -| `scrollbar-color-active` | Scrollbar thumb when it is active (being dragged) | -| `scrollbar-background` | Scrollbar background | -| `scrollbar-background-hover` | Scrollbar background when the mouse is hovering over it | -| `scrollbar-background-active` | Scrollbar background when the thumb is being dragged | +| Rule | Color | +|-------------------------------|-------------------------------------------------------------| +| `scrollbar-color` | Scrollbar "thumb" (movable part) | +| `scrollbar-color-hover` | Scrollbar thumb when the mouse is hovering over it | +| `scrollbar-color-active` | Scrollbar thumb when it is active (being dragged) | +| `scrollbar-background` | Scrollbar background | +| `scrollbar-background-hover` | Scrollbar background when the mouse is hovering over it | +| `scrollbar-background-active` | Scrollbar background when the thumb is being dragged | +| `scrollbar-corner-color` | Color of the gap between horizontal and vertical scrollbars | + ## Example diff --git a/sandbox/darren/just_a_box.css b/sandbox/darren/just_a_box.css index 8279a027ac..617fbaf598 100644 --- a/sandbox/darren/just_a_box.css +++ b/sandbox/darren/just_a_box.css @@ -4,7 +4,7 @@ Screen { #left_pane { background: red; - width: 10; + width: 30; height: auto; } @@ -15,7 +15,7 @@ Screen { #right_pane { background: blue; - width: 10; + width: 30; } .box { diff --git a/sandbox/darren/just_a_box.py b/sandbox/darren/just_a_box.py index 781c66f67f..ba264c9c01 100644 --- a/sandbox/darren/just_a_box.py +++ b/sandbox/darren/just_a_box.py @@ -24,6 +24,7 @@ def render(self) -> RenderableType: class JustABox(App): def compose(self) -> ComposeResult: yield Horizontal( + Box(id="middle_pane"), Vertical( Box(id="box1", classes="box"), Box(id="box2", classes="box"), @@ -37,7 +38,6 @@ def compose(self) -> ComposeResult: # Box(id="box10", classes="box"), id="left_pane", ), - Box(id="middle_pane"), Vertical( Box(id="boxa", classes="box"), Box(id="boxb", classes="box"), diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py index f52021c472..4b1184127b 100644 --- a/src/textual/css/_styles_builder.py +++ b/src/textual/css/_styles_builder.py @@ -600,6 +600,7 @@ def process_color(self, name: str, tokens: list[Token]) -> None: process_scrollbar_color = process_color process_scrollbar_color_hover = process_color process_scrollbar_color_active = process_color + process_scrollbar_corner_color = process_color process_scrollbar_background = process_color process_scrollbar_background_hover = process_color process_scrollbar_background_active = process_color diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index 311903a0a5..e68f0da89c 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -126,6 +126,8 @@ class RulesMap(TypedDict, total=False): scrollbar_color_hover: Color scrollbar_color_active: Color + scrollbar_corner_color: Color + scrollbar_background: Color scrollbar_background_hover: Color scrollbar_background_active: Color @@ -231,6 +233,8 @@ class StylesBase(ABC): scrollbar_color_hover = ColorProperty("ansi_yellow") scrollbar_color_active = ColorProperty("ansi_bright_yellow") + scrollbar_corner_color = ColorProperty("#666666") + scrollbar_background = ColorProperty("#555555") scrollbar_background_hover = ColorProperty("#444444") scrollbar_background_active = ColorProperty("black") diff --git a/src/textual/scrollbar.py b/src/textual/scrollbar.py index 24674735df..ff7f172d8f 100644 --- a/src/textual/scrollbar.py +++ b/src/textual/scrollbar.py @@ -293,7 +293,9 @@ def __init__(self, name: str | None = None): super().__init__(name=name) def render(self) -> RenderableType: - return Blank("violet") + styles = self.parent.styles + color = styles.scrollbar_corner_color + return Blank(color) if __name__ == "__main__": diff --git a/src/textual/widget.py b/src/textual/widget.py index 526af9dac7..7e8a4ea88c 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -73,6 +73,7 @@ class Widget(DOMNode): scrollbar-background-hover: $panel-darken-2; scrollbar-color: $primary-lighten-1; scrollbar-color-active: $warning-darken-1; + scrollbar-corner-color: $panel-darken-3; scrollbar-size-vertical: 2; scrollbar-size-horizontal: 1; } @@ -344,6 +345,9 @@ def max_scroll_y(self) -> int: @property def scrollbar_corner(self) -> ScrollBarCorner: + """Return the ScrollBarCorner - the cells that appear between the + horizontal and vertical scrollbars (only when both are visible). + """ from .scrollbar import ScrollBarCorner if self._scrollbar_corner is not None: From 51b141db0398b579431a60c2a8dfb322e692e1a8 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Wed, 10 Aug 2022 17:12:47 +0100 Subject: [PATCH 3/6] Remove unused print statement --- src/textual/_compositor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index bbb46ec6e6..72b309d89a 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -405,7 +405,6 @@ def add_widget( for chrome_widget, chrome_region in widget._arrange_scrollbars( container_region ): - print(chrome_widget, chrome_region) map[chrome_widget] = MapGeometry( chrome_region + layout_offset, order, From ccbbc9f495152602c0642c98af27fdbfd568c4e6 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 16 Aug 2022 09:58:30 +0100 Subject: [PATCH 4/6] Some sandbox changes --- sandbox/darren/just_a_box.css | 6 +++--- sandbox/darren/just_a_box.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sandbox/darren/just_a_box.css b/sandbox/darren/just_a_box.css index 617fbaf598..d1f36cf111 100644 --- a/sandbox/darren/just_a_box.css +++ b/sandbox/darren/just_a_box.css @@ -5,7 +5,7 @@ Screen { #left_pane { background: red; width: 30; - height: auto; + overflow: scroll scroll; } #middle_pane { @@ -19,6 +19,6 @@ Screen { } .box { - height: 5; - width: 15; + height: 12; + width: 30; } diff --git a/sandbox/darren/just_a_box.py b/sandbox/darren/just_a_box.py index ba264c9c01..781c66f67f 100644 --- a/sandbox/darren/just_a_box.py +++ b/sandbox/darren/just_a_box.py @@ -24,7 +24,6 @@ def render(self) -> RenderableType: class JustABox(App): def compose(self) -> ComposeResult: yield Horizontal( - Box(id="middle_pane"), Vertical( Box(id="box1", classes="box"), Box(id="box2", classes="box"), @@ -38,6 +37,7 @@ def compose(self) -> ComposeResult: # Box(id="box10", classes="box"), id="left_pane", ), + Box(id="middle_pane"), Vertical( Box(id="boxa", classes="box"), Box(id="boxb", classes="box"), From 9e15124dd43dd7a30cf0771a5727f4f722ef96f8 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 16 Aug 2022 10:15:21 +0100 Subject: [PATCH 5/6] Remove redundant words from docs --- docs/styles/scrollbar.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/styles/scrollbar.md b/docs/styles/scrollbar.md index 1ad254ae9c..514436eca7 100644 --- a/docs/styles/scrollbar.md +++ b/docs/styles/scrollbar.md @@ -2,15 +2,15 @@ There are a number of rules to set the colors used in Textual scrollbars. You won't typically need to do this, as the default themes have carefully chosen colors, but you can if you want to. -| Rule | Color | -|-------------------------------|-------------------------------------------------------------| -| `scrollbar-color` | Scrollbar "thumb" (movable part) | -| `scrollbar-color-hover` | Scrollbar thumb when the mouse is hovering over it | -| `scrollbar-color-active` | Scrollbar thumb when it is active (being dragged) | -| `scrollbar-background` | Scrollbar background | -| `scrollbar-background-hover` | Scrollbar background when the mouse is hovering over it | -| `scrollbar-background-active` | Scrollbar background when the thumb is being dragged | -| `scrollbar-corner-color` | Color of the gap between horizontal and vertical scrollbars | +| Rule | Color | +|-------------------------------|---------------------------------------------------------| +| `scrollbar-color` | Scrollbar "thumb" (movable part) | +| `scrollbar-color-hover` | Scrollbar thumb when the mouse is hovering over it | +| `scrollbar-color-active` | Scrollbar thumb when it is active (being dragged) | +| `scrollbar-background` | Scrollbar background | +| `scrollbar-background-hover` | Scrollbar background when the mouse is hovering over it | +| `scrollbar-background-active` | Scrollbar background when the thumb is being dragged | +| `scrollbar-corner-color` | The gap between the horizontal and vertical scrollbars | ## Example From dddd483af2a4c297143bb87059a9d55999d49359 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 16 Aug 2022 10:26:56 +0100 Subject: [PATCH 6/6] Add docstring to ScrollBarCorner class --- sandbox/darren/just_a_box.css | 2 +- src/textual/scrollbar.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sandbox/darren/just_a_box.css b/sandbox/darren/just_a_box.css index d1f36cf111..881e436bf5 100644 --- a/sandbox/darren/just_a_box.css +++ b/sandbox/darren/just_a_box.css @@ -4,7 +4,7 @@ Screen { #left_pane { background: red; - width: 30; + width: 20; overflow: scroll scroll; } diff --git a/src/textual/scrollbar.py b/src/textual/scrollbar.py index ff7f172d8f..7ae1dcb45b 100644 --- a/src/textual/scrollbar.py +++ b/src/textual/scrollbar.py @@ -289,6 +289,9 @@ async def on_mouse_move(self, event: events.MouseMove) -> None: class ScrollBarCorner(Widget): + """Widget which fills the gap between horizontal and vertical scrollbars, + should they both be present.""" + def __init__(self, name: str | None = None): super().__init__(name=name)