dimensions

This commit is contained in:
Will McGugan
2022-09-14 13:19:45 +01:00
parent 8020101c73
commit e85f9dc045
5 changed files with 119 additions and 19 deletions

View File

@@ -3,8 +3,8 @@
#dialog { #dialog {
margin: 4 8; margin: 4 8;
background: $primary; background: $primary;
color: $text-primary; color: $text;
border: tall $text-primary; border: tall $background;
padding: 1 2; padding: 1 2;
} }

View File

@@ -5,12 +5,14 @@ from textual.widgets import Static
class ColorApp(App): class ColorApp(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
self.widgets = [Static(f"Textual {n+1}") for n in range(10)] self.widgets = [Static("") for n in range(10)]
yield from self.widgets yield from self.widgets
def on_mount(self) -> None: def on_mount(self) -> None:
for index, widget in enumerate(self.widgets, 1): for index, widget in enumerate(self.widgets, 1):
widget.styles.background = Color(191, 78, 96, index * 0.1) alpha = index * 0.1
widget.update(f"alpha={alpha:.1f}")
widget.styles.background = Color(191, 78, 96, a=alpha)
app = ColorApp() app = ColorApp()

View File

@@ -0,0 +1,27 @@
from textual.app import App, ComposeResult
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 DimensionsApp(App):
def compose(self) -> ComposeResult:
self.widget = Static(TEXT)
yield self.widget
def on_mount(self) -> None:
self.widget.styles.background = "purple"
self.widget.styles.width = 30
self.widget.styles.height = 10
app = DimensionsApp()
if __name__ == "__main__":
app.run()

View File

@@ -0,0 +1,27 @@
from textual.app import App, ComposeResult
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 DimensionsApp(App):
def compose(self) -> ComposeResult:
self.widget = Static(TEXT)
yield self.widget
def on_mount(self) -> None:
self.widget.styles.background = "purple"
self.widget.styles.width = 30
self.widget.styles.height = "auto"
app = DimensionsApp()
if __name__ == "__main__":
app.run()

View File

@@ -5,14 +5,12 @@ In this chapter will explore how you can apply styles to your application to cre
## Styles object ## Styles object
Every Textual widget class provides a `styles` object which contains a number of attributes. These attributes tell Textual how the widget should be displayed, and how it should be positioned on the screen relative to other widgets. Every Textual widget class provides a `styles` object which contains a number of attributes. These attributes tell Textual how the widget should be displayed, and how it should be positioned on the screen relative to other widgets. You can set any of these styles in your code and Textual will update the screen accordingly.
!!! note !!! note
These docs use the term *screen* to describe the contents of the terminal, which will typically be a window on your desktop. These docs use the term *screen* to describe the contents of the terminal, which will typically be a window on your desktop.
If you write to any styles attribute the screen will update accordingly.
Let's look at a simple example which sets the styles on `screen` (a special widget that represents the screen). Let's look at a simple example which sets the styles on `screen` (a special widget that represents the screen).
```python title="screen.py" hl_lines="6-7" ```python title="screen.py" hl_lines="6-7"
@@ -28,11 +26,11 @@ The second line sets [border](../styles/border.md) to a tuple of `("heavy", "whi
## Styling widgets ## Styling widgets
The screen is a special-case for a widget, in that it always matches the dimensions of your terminal window. Widgets provide more flexibility for styling. Setting styles on screen is useful, but to create most user interfaces we will also need to apply styles to other widgets.
The following example adds a static widget which we will apply some styles to: The following example adds a static widget which we will apply some styles to:
```python title="widget.py" hl_lines="11-12" ```python title="widget.py" hl_lines="7 11-12"
--8<-- "docs/examples/guide/styles/widget.py" --8<-- "docs/examples/guide/styles/widget.py"
``` ```
@@ -43,9 +41,9 @@ The compose method stores a reference to the widget before yielding it. In our m
Widgets will occupy the full width of the screen and as many lines as required to fit in the vertical direction, which is why we see a wide box on the top of the screen. Widgets will occupy the full width of the screen and as many lines as required to fit in the vertical direction, which is why we see a wide box on the top of the screen.
Note how the combined height of the widget is three rows (lines) in the terminal. This is because a border adds two rows (and two column). If you were to remove the line that sets the border style, the widget would occupy only a single row. Note how the combined height of the widget is three rows (lines) in the terminal. This is because a border adds two rows (and two columns). If you were to remove the line that sets the border style, the widget would occupy only a single row.
Widgets will also wrap text by default. If you were to replace `"Textual"` with a long paragraph of text, it will wrap lines and the widget will extend downwards. Widgets will also wrap text by default. If you were to replace `"Textual"` with a long paragraph of text, the widget will expand downwards to fit.
## Colors ## Colors
@@ -63,7 +61,7 @@ In addition to color names, you can also use any of the following ways of expres
- RGB hex colors starts with a `#` followed by three pairs of one or two hex digits; one for the red, green, and blue color components. For example, `#f00` is an intense red color, and `#9932CC` is *dark orchid*. - RGB hex colors starts with a `#` followed by three pairs of one or two hex digits; one for the red, green, and blue color components. For example, `#f00` is an intense red color, and `#9932CC` is *dark orchid*.
- RGB decimal color start with `rgb` followed by a tuple of three numbers in the range 0 to 255. For example `rgb(255,0,0)` is intense red, and `rgb(153,50,204)` is *dark orchid*. - RGB decimal color start with `rgb` followed by a tuple of three numbers in the range 0 to 255. For example `rgb(255,0,0)` is intense red, and `rgb(153,50,204)` is *dark orchid*.
- HSL colors start with `hsl` followed by a tuple of three colors in the range 0 to 255, representing the Hue Saturation and Lightness. For example `hsl(0,100%,50%)` is intense red and `hsl(280,60%,49%)` is *dark orchid* - HSL colors start with `hsl` followed by a angle between 0 adn 360 and two percentage values, representing Hue, Saturation and Lightness. For example `hsl(0,100%,50%)` is intense red and `hsl(280,60%,49%)` is *dark orchid*
The background and color styles will also accept a [color][textual.color.Color] object which is convenient if you want to create colors dynamically. The background and color styles will also accept a [color][textual.color.Color] object which is convenient if you want to create colors dynamically.
@@ -79,21 +77,21 @@ Here is the output:
```{.textual path="docs/examples/guide/styles/colors01.py"} ```{.textual path="docs/examples/guide/styles/colors01.py"}
``` ```
### Alpha component ### Alpha
Textual (and computers in general) represents color as a tuple of three values for the red, green, and blue components which when combined create all of the 16.7 million colors a typical computer screen can display. Textual (and computers in general) represents color internally as a tuple of three values for the red, green, and blue components, which when combined create all of the 16.7 million colors a typical computer screen can display.
Textual support a common fourth value called *alpha* can be thought of as how transparent a color is. If you set this value on a background color then Textual will blend the background color with the background underneath it. If you set alpha on the text, then it will blend the text with its background. Textual support a common fourth value called *alpha* which is how transparent a color is. If you set this value on a background color Textual will blend the background color with the background underneath it. If you set alpha on the text, then it will blend the text with its background.
There are a few ways you can set alpha on a color in Textual. There are a few ways you can set alpha on a color in Textual.
- You can set the alpha value of a color by adding a fourth pair (or digit) to a hex color. The extra digits set an opacity of 0 for completely transparent to 255 (completely opaque). Any values between 0 and 255 will be translucent. For example `"#9932CC7f"` is a dark orchid which is roughly 50% translucent. - You can set the alpha value of a color by adding a fourth pair (or digit) to a hex color. The extra digits set an opacity of 0 for completely transparent to 255 (completely opaque). Any values between 0 and 255 will be translucent. For example `"#9932CC7f"` is a dark orchid which is roughly 50% translucent.
- You can set alpha with the `rgba` format, which is identical to `rgb` with the additional of a fourth value that should be between 0 and 1, where 0 is invisible and 1 is opaque. - You can set alpha with the `rgba` format, which is identical to `rgb` with the additional of a fourth value that should be between 0 and 1, where 0 is invisible and 1 is opaque. For example `"rgba(192,78,96,0.5)"`.
- You can add a fourth value to a [Color][textual.color.Color] object. For example `Color(192, 78, 96, 0.5)` creates a translucent dark orchid. - You can add the `a` parameter on a [Color][textual.color.Color] object. For example `Color(192, 78, 96, a=0.5)` creates a translucent dark orchid.
The following examples shows what happens when you set alpha on background colors: The following examples shows what happens when you set alpha on background colors:
```python title="colors01.py" hl_lines="12-13" ```python title="colors01.py" hl_lines="12-15"
--8<-- "docs/examples/guide/styles/colors02.py" --8<-- "docs/examples/guide/styles/colors02.py"
``` ```
@@ -102,14 +100,60 @@ We set the `background` style to a color with an alpha that ranges from 0.1 to 1
```{.textual path="docs/examples/guide/styles/colors02.py"} ```{.textual path="docs/examples/guide/styles/colors02.py"}
``` ```
## Box Model ## Dimensions
Widgets occupy a rectangular region of the screen, which may be as small as a single character or as large as the screen. Potentially *larger* if scrolling is enabled.
### Box Model
The size of a widget on screen is the total of a number of settings.
- [width](../styles/width.md) and [height](../styles/width.md) define the size of the content area which contains text or other content set in your code.
- [padding](../styles/padding.md) adds optional space around the content area.
- [border](../styles/border.md) draws an optional rectangular border around the padding and the content area.
Additionally, the [margin](../styles/margin.md) style adds space around a widgets border, which isn't technically part of the widget, but provide visual separation between widgets.
Together these styles compose the widget's *box model*. The following diagram shows how these settings are combined:
<div class="excalidraw"> <div class="excalidraw">
--8<-- "docs/images/styles/box.excalidraw.svg" --8<-- "docs/images/styles/box.excalidraw.svg"
</div> </div>
### Width and height
Setting the width restricts the number of columns used by a widget, and setting the height restricts the number of rows. Let's look at an example which sets both dimensions.
```python title="dimensions01.py" hl_lines="21-22"
--8<-- "docs/examples/guide/styles/dimensions01.py"
```
This code produces the following result.
```{.textual path="docs/examples/guide/styles/dimensions01.py"}
```
Note how the text wraps in the widget, and is cropped because it doesn't fit in the space provided.
#### Auto
In practice, we generally want the size of a widget to adapt to it's content. We can use a special value to achieve this. If you set width or height to "auto", then that dimension will grow to fit the content.
Let's set the height to auto and see what happens.
```python title="dimensions02.py" hl_lines="22"
--8<-- "docs/examples/guide/styles/dimensions02.py"
```
If you run this you will see the following:
```{.textual path="docs/examples/guide/styles/dimensions02.py"}
```
The height has grown to accommodate the full text.
#### Units
TODO: Styles docs TODO: Styles docs