Filling the gap between horizontal and vertical scrollbars (#664)

* Fill the spacing between the scrollbars

* Add "scrollbar-corner-color" CSS rule and doc

* Remove unused print statement

* Some sandbox changes

* Remove redundant words from docs

* Add docstring to ScrollBarCorner class
This commit is contained in:
darrenburns
2022-08-16 10:55:34 +01:00
committed by GitHub
parent 5ae00815e6
commit e94ea25faf
7 changed files with 70 additions and 56 deletions

View File

@@ -3,13 +3,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` | The gap between the horizontal and vertical scrollbars |
## Example

View File

@@ -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: 20;
overflow: scroll scroll;
}
#middle_pane {
margin-top: 4;
width: 1fr;
background: #173f5f;
}
#middle_pane:focus {
tint: cyan 40%;
background: green;
width: 140;
}
#right_pane {
width: 1fr;
background: #f6d55c;
}
.box:focus {
tint: cyan 40%;
}
#box1 {
background: green;
}
#box2 {
offset-y: 3;
background: hotpink;
}
#box3 {
background: red;
}
#box4 {
background: blue;
width: 30;
}
#box5 {
background: darkviolet;
.box {
height: 12;
width: 30;
}

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
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 @@ class Box(Widget, can_focus=True):
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)

View File

@@ -600,6 +600,7 @@ class StylesBuilder:
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

View File

@@ -125,6 +125,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
@@ -228,6 +230,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")

View File

@@ -9,6 +9,7 @@ from rich.segment import Segment, Segments
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,19 @@ class ScrollBar(Widget):
await self.emit(ScrollTo(self, x=x, y=y))
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)
def render(self) -> RenderableType:
styles = self.parent.styles
color = styles.scrollbar_corner_color
return Blank(color)
if __name__ == "__main__":
from rich.console import Console

View File

@@ -17,7 +17,6 @@ import rich.repr
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
@@ -46,6 +45,7 @@ if TYPE_CHECKING:
ScrollRight,
ScrollTo,
ScrollUp,
ScrollBarCorner,
)
@@ -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;
}
@@ -102,6 +103,7 @@ class Widget(DOMNode):
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)
@@ -353,6 +355,19 @@ class Widget(DOMNode):
+ self.scrollbar_size_horizontal,
)
@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:
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)
@@ -918,15 +933,18 @@ class Widget(DOMNode):
_,
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: