From fa4b971bffb9f488d155981794b7f0bf3b657c72 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 4 Aug 2022 15:27:41 +0100 Subject: [PATCH] more docs --- docs/examples/styles/scrollbar_size.py | 38 ++++++++++++++ docs/examples/styles/scrollbars.py | 49 ++++++++++++++++++ docs/styles/height.md | 4 +- docs/styles/overflow.md | 4 +- docs/styles/scrollbar.md | 43 ++++++++++++++++ docs/styles/scrollbar_size.md | 37 ++++++++++++++ docs/styles/width.md | 2 +- mkdocs.yml | 2 + sandbox/will/basic.css | 2 +- sandbox/will/basic.py | 71 ++++++++++++++++---------- src/textual/css/_help_text.py | 46 ----------------- src/textual/css/_styles_builder.py | 1 - tests/css/test_help_text.py | 8 --- 13 files changed, 218 insertions(+), 89 deletions(-) create mode 100644 docs/examples/styles/scrollbar_size.py create mode 100644 docs/examples/styles/scrollbars.py create mode 100644 docs/styles/scrollbar.md create mode 100644 docs/styles/scrollbar_size.md diff --git a/docs/examples/styles/scrollbar_size.py b/docs/examples/styles/scrollbar_size.py new file mode 100644 index 000000000..2caaafed6 --- /dev/null +++ b/docs/examples/styles/scrollbar_size.py @@ -0,0 +1,38 @@ +from textual.app import App +from textual import layout +from textual.widgets import Static + +TEXT = """I must not fear. +Fear is the mind-killer. +Fear is the little-death that brings total obliteration. +I will face my fear. +I will permit it to pass over me and through me. +And when it has gone past, I will turn the inner eye to see its path. +Where the fear has gone there will be nothing. Only I will remain. +""" + + +class ScrollbarApp(App): + CSS = """ + Screen { + background: white; + color: blue 80%; + layout: horizontal; + } + + Static { + padding: 1 2; + width: 200; + } + + .panel { + scrollbar-size: 10 4; + padding: 1 2; + } + """ + + def compose(self): + yield layout.Vertical(Static(TEXT * 5), classes="panel") + + +app = ScrollbarApp() diff --git a/docs/examples/styles/scrollbars.py b/docs/examples/styles/scrollbars.py new file mode 100644 index 000000000..0a024e5e8 --- /dev/null +++ b/docs/examples/styles/scrollbars.py @@ -0,0 +1,49 @@ +from textual.app import App +from textual import layout +from textual.widgets import Static + +TEXT = """I must not fear. +Fear is the mind-killer. +Fear is the little-death that brings total obliteration. +I will face my fear. +I will permit it to pass over me and through me. +And when it has gone past, I will turn the inner eye to see its path. +Where the fear has gone there will be nothing. Only I will remain. +""" + + +class ScrollbarApp(App): + CSS = """ + + Screen { + background: #212121; + color: white 80%; + layout: horizontal; + } + + Static { + padding: 1 2; + } + + .panel1 { + width: 1fr; + scrollbar-color: green; + scrollbar-background: #bbb; + padding: 1 2; + } + + .panel2 { + width: 1fr; + scrollbar-color: yellow; + scrollbar-background: purple; + padding: 1 2; + } + + """ + + def compose(self): + yield layout.Vertical(Static(TEXT * 5), classes="panel1") + yield layout.Vertical(Static(TEXT * 5), classes="panel2") + + +app = ScrollbarApp() diff --git a/docs/styles/height.md b/docs/styles/height.md index b7c6b664d..b7ba4a0db 100644 --- a/docs/styles/height.md +++ b/docs/styles/height.md @@ -1,10 +1,10 @@ # Height -The `height` style sets a widget's height. By default, it sets the height of the content area, but if `box-sizing` is set to `border-box` it sets the height of the border area. +The `height` rule sets a widget's height. By default, it sets the height of the content area, but if `box-sizing` is set to `border-box` it sets the height of the border area. ## Example -=== "width.py" +=== "height.py" ```python --8<-- "docs/examples/styles/height.py" diff --git a/docs/styles/overflow.md b/docs/styles/overflow.md index 752ac2f64..8429403a4 100644 --- a/docs/styles/overflow.md +++ b/docs/styles/overflow.md @@ -42,9 +42,9 @@ overflow-x: scroll; ```python # Hide the vertical scrollbar -self.styles.overflow_y = "hidden" +widget.styles.overflow_y = "hidden" # Always show the horizontal scrollbar -self.styles.overflow_x = "scroll" +widget.styles.overflow_x = "scroll" ``` diff --git a/docs/styles/scrollbar.md b/docs/styles/scrollbar.md new file mode 100644 index 000000000..7a8a3912b --- /dev/null +++ b/docs/styles/scrollbar.md @@ -0,0 +1,43 @@ +# Scrollbar colors + +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-color-active` | Scrollbar background when the thumb is being dragged | + +## Example + +In this example we have two panels, with different scrollbar colors set for each. + +=== "scrollbars.py" + + ```python + --8<-- "docs/examples/styles/scrollbars.py" + ``` + +=== "Output" + + ```{.textual path="docs/examples/styles/scrollbars.py"} + ``` + +## CSS + +```sass +/* Set widget scrollbar color to yellow */ +Widget { + scrollbar-color: yellow; +} +``` + +## Python + +```python +# Set the scrollbar color to yellow +widget.styles.scrollbar_color = "yellow" +``` diff --git a/docs/styles/scrollbar_size.md b/docs/styles/scrollbar_size.md new file mode 100644 index 000000000..f6653c254 --- /dev/null +++ b/docs/styles/scrollbar_size.md @@ -0,0 +1,37 @@ +# Scrollbar-size + +The `scrollbar-size` rule changes the size of the scrollbars. It takes 2 integers for horizontal and vertical scrollbar size respectively. + +The scrollbar dimensions may also be set individually with `scrollbar-size-horizontal` and `scrollbar-size-vertical`. + +## Example + +In this example we modify the size of the widgets scrollbar to be _much_ larger than usual. + +=== "scrollbar_size.py" + + ```python + --8<-- "docs/examples/styles/scrollbar_size.py" + ``` + +=== "Output" + + ```{.textual path="docs/examples/styles/scrollbar_size.py"} + ``` + +## CSS + +```sass +/* Set horizontal scrollbar to 10, and vertical scrollbar to 4 */ +Widget { + scrollbar-size: 10 4; +} +``` + +## Python + +```python +# Set horizontal scrollbar to 10, and vertical scrollbar to 4 +widget.styles.horizontal_scrollbar = 10 +widget.styles.vertical_scrollbar = 10 +``` diff --git a/docs/styles/width.md b/docs/styles/width.md index 933f9257d..666552002 100644 --- a/docs/styles/width.md +++ b/docs/styles/width.md @@ -1,6 +1,6 @@ # Width -The `width` style sets a widget's width. By default, it sets the width of the content area, but if `box-sizing` is set to `border-box` it sets the width of the border area. +The `width` rule sets a widget's width. By default, it sets the width of the content area, but if `box-sizing` is set to `border-box` it sets the width of the border area. ## Example diff --git a/mkdocs.yml b/mkdocs.yml index 9e1a76e21..d35b2d676 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,6 +26,8 @@ nav: - "styles/outline.md" - "styles/overflow.md" - "styles/padding.md" + - "styles/scrollbar.md" + - "styles/scrollbar_size.md" - "styles/text_style.md" - "styles/tint.md" - "styles/visibility.md" diff --git a/sandbox/will/basic.css b/sandbox/will/basic.css index 3c9043b6b..fef9e4248 100644 --- a/sandbox/will/basic.css +++ b/sandbox/will/basic.css @@ -100,7 +100,7 @@ Tweet { .scrollable { - + overflow-x: auto; overflow-y: scroll; margin: 1 2; height: 20; diff --git a/sandbox/will/basic.py b/sandbox/will/basic.py index dee825f0e..bda44f314 100644 --- a/sandbox/will/basic.py +++ b/sandbox/will/basic.py @@ -9,39 +9,51 @@ from textual.widget import Widget from textual.widgets import Static, DataTable CODE = ''' -class Offset(NamedTuple): - """A point defined by x and y coordinates.""" +from __future__ import annotations - x: int = 0 - y: int = 0 +from typing import Iterable, TypeVar - @property - def is_origin(self) -> bool: - """Check if the point is at the origin (0, 0)""" - return self == (0, 0) +T = TypeVar("T") - def __bool__(self) -> bool: - return self != (0, 0) - def __add__(self, other: object) -> Offset: - if isinstance(other, tuple): - _x, _y = self - x, y = other - return Offset(_x + x, _y + y) - return NotImplemented +def loop_first(values: Iterable[T]) -> Iterable[tuple[bool, T]]: + """Iterate and generate a tuple with a flag for first value.""" + iter_values = iter(values) + try: + value = next(iter_values) + except StopIteration: + return + yield True, value + for value in iter_values: + yield False, value - def __sub__(self, other: object) -> Offset: - if isinstance(other, tuple): - _x, _y = self - x, y = other - return Offset(_x - x, _y - y) - return NotImplemented - def __mul__(self, other: object) -> Offset: - if isinstance(other, (float, int)): - x, y = self - return Offset(int(x * other), int(y * other)) - return NotImplemented +def loop_last(values: Iterable[T]) -> Iterable[tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value + + +def loop_first_last(values: Iterable[T]) -> Iterable[tuple[bool, bool, T]]: + """Iterate and generate a tuple with a flag for first and last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + first = True + for value in iter_values: + yield first, False, previous_value + first = False + previous_value = value + yield first, True, previous_value ''' @@ -111,7 +123,10 @@ class BasicApp(App, css_path="basic.css"): yield from ( Tweet(TweetBody()), Widget( - Static(Syntax(CODE, "python"), classes="code"), + Static( + Syntax(CODE, "python", line_numbers=True, indent_guides=True), + classes="code", + ), classes="scrollable", ), table, diff --git a/src/textual/css/_help_text.py b/src/textual/css/_help_text.py index 220add7dc..d24835e93 100644 --- a/src/textual/css/_help_text.py +++ b/src/textual/css/_help_text.py @@ -443,52 +443,6 @@ def layout_property_help_text(property_name: str, context: StylingContext) -> He ) -def docks_property_help_text(property_name: str, context: StylingContext) -> HelpText: - """Help text to show when the user supplies an invalid value for docks. - - Args: - property_name (str): The name of the property - context (StylingContext | None): The context the property is being used in. - - Returns: - HelpText: Renderable for displaying the help text for this property - """ - property_name = _contextualize_property_name(property_name, context) - return HelpText( - summary=f"Invalid value for [i]{property_name}[/] property", - bullets=[ - *ContextSpecificBullets( - inline=[ - Bullet( - f"The [i]{property_name}[/] property expects an iterable of DockGroups", - examples=[ - Example( - f"widget.styles.{property_name} = [DockGroup(...), DockGroup(...)]" - ) - ], - ), - ], - css=[ - Bullet( - f"The [i]{property_name}[/] property expects a value of the form =/...", - examples=[ - Example( - f"{property_name}: lhs=left/2; [dim]# dock named [u]lhs[/], on [u]left[/] edge, with z-index [u]2[/]" - ), - Example( - f"{property_name}: top=top/3 rhs=right/2; [dim]# declaring multiple docks" - ), - ], - ), - Bullet(" can be any string you want"), - Bullet(f" must be one of {friendly_list(VALID_EDGE)}"), - Bullet(f" must be an integer"), - ], - ).get_by_context(context) - ], - ) - - def dock_property_help_text(property_name: str, context: StylingContext) -> HelpText: """Help text to show when the user supplies an invalid value for dock. diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py index 8eee77d6a..f52021c47 100644 --- a/src/textual/css/_styles_builder.py +++ b/src/textual/css/_styles_builder.py @@ -15,7 +15,6 @@ from ._help_text import ( string_enum_help_text, border_property_help_text, layout_property_help_text, - docks_property_help_text, dock_property_help_text, fractional_property_help_text, align_help_text, diff --git a/tests/css/test_help_text.py b/tests/css/test_help_text.py index 1114961d8..928ca2d62 100644 --- a/tests/css/test_help_text.py +++ b/tests/css/test_help_text.py @@ -9,8 +9,6 @@ from textual.css._help_text import ( color_property_help_text, border_property_help_text, layout_property_help_text, - docks_property_help_text, - dock_property_help_text, fractional_property_help_text, offset_property_help_text, align_help_text, @@ -92,12 +90,6 @@ def test_layout_property_help_text(styling_context): assert "layout" in rendered -def test_docks_property_help_text(styling_context): - rendered = render(docks_property_help_text("docks", styling_context)) - assert "Invalid value for" in rendered - assert "docks" in rendered - - def test_fractional_property_help_text(styling_context): rendered = render(fractional_property_help_text("opacity", styling_context)) assert "Invalid value for" in rendered