more docs

This commit is contained in:
Will McGugan
2022-08-04 15:27:41 +01:00
parent ae9862ce1f
commit fa4b971bff
13 changed files with 218 additions and 89 deletions

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"

View File

@@ -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"
```

43
docs/styles/scrollbar.md Normal file
View File

@@ -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"
```

View File

@@ -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
```

View File

@@ -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

View File

@@ -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"

View File

@@ -100,7 +100,7 @@ Tweet {
.scrollable {
overflow-x: auto;
overflow-y: scroll;
margin: 1 2;
height: 20;

View File

@@ -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,

View File

@@ -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 <name>=<edge>/<zindex>...",
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("<name> can be any string you want"),
Bullet(f"<edge> must be one of {friendly_list(VALID_EDGE)}"),
Bullet(f"<zindex> 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.

View File

@@ -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,

View File

@@ -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