mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'css' of github.com:Textualize/textual into docs-animator
This commit is contained in:
@@ -8,7 +8,7 @@ The `Click` event is sent to a widget when the user clicks a mouse button.
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| ---------- | ---- | ----------------------------------------- |
|
||||
|------------|------|-------------------------------------------|
|
||||
| `x` | int | Mouse x coordinate, relative to Widget |
|
||||
| `y` | int | Mouse y coordinate, relative to Widget |
|
||||
| `delta_x` | int | Change in x since last mouse event |
|
||||
|
||||
@@ -8,7 +8,7 @@ The `MouseMove` event is sent to a widget when the mouse pointer is moved over a
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| ---------- | ---- | ----------------------------------------- |
|
||||
|------------|------|-------------------------------------------|
|
||||
| `x` | int | Mouse x coordinate, relative to Widget |
|
||||
| `y` | int | Mouse y coordinate, relative to Widget |
|
||||
| `delta_x` | int | Change in x since last mouse event |
|
||||
|
||||
@@ -8,7 +8,7 @@ The `MouseRelease` event is sent to a widget when it is no longer receiving mous
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| ---------------- | ------ | --------------------------------------------- |
|
||||
|------------------|--------|-----------------------------------------------|
|
||||
| `mouse_position` | Offset | Mouse coordinates when the mouse was released |
|
||||
|
||||
## Code
|
||||
|
||||
@@ -8,7 +8,7 @@ The `MouseScrollDown` event is sent to a widget when the scroll wheel (or trackp
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| --------- | ---- | -------------------------------------- |
|
||||
|-----------|------|----------------------------------------|
|
||||
| `x` | int | Mouse x coordinate, relative to Widget |
|
||||
| `y` | int | Mouse y coordinate, relative to Widget |
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ The `MouseScrollUp` event is sent to a widget when the scroll wheel (or trackpad
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| --------- | ---- | -------------------------------------- |
|
||||
|-----------|------|----------------------------------------|
|
||||
| `x` | int | Mouse x coordinate, relative to Widget |
|
||||
| `y` | int | Mouse y coordinate, relative to Widget |
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ The `MouseUp` event is sent to a widget when the user releases a mouse button.
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| ---------- | ---- | ----------------------------------------- |
|
||||
|------------|------|-------------------------------------------|
|
||||
| `x` | int | Mouse x coordinate, relative to Widget |
|
||||
| `y` | int | Mouse y coordinate, relative to Widget |
|
||||
| `delta_x` | int | Change in x since last mouse event |
|
||||
|
||||
@@ -8,7 +8,7 @@ The `Paste` event is sent to a widget when the user pastes text.
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| --------- | ---- | ------------------------ |
|
||||
|-----------|------|--------------------------|
|
||||
| `text` | str | The text that was pasted |
|
||||
|
||||
## Code
|
||||
|
||||
@@ -8,7 +8,7 @@ The `Resize` event is sent to a widget when its size changes and when it is firs
|
||||
## Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| ---------------- | ---- | ------------------------------------------------ |
|
||||
|------------------|------|--------------------------------------------------|
|
||||
| `size` | Size | The new size of the Widget |
|
||||
| `virtual_size` | Size | The virtual size (scrollable area) of the Widget |
|
||||
| `container_size` | Size | The size of the container (parent widget) |
|
||||
|
||||
16
docs/examples/guide/screens/modal01.css
Normal file
16
docs/examples/guide/screens/modal01.css
Normal file
@@ -0,0 +1,16 @@
|
||||
#dialog {
|
||||
grid-size: 2;
|
||||
grid-gutter: 1 2;
|
||||
margin: 1 2;
|
||||
}
|
||||
|
||||
#question {
|
||||
column-span: 2;
|
||||
content-align: center bottom;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 100%;
|
||||
}
|
||||
37
docs/examples/guide/screens/modal01.py
Normal file
37
docs/examples/guide/screens/modal01.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import Grid
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Static, Header, Footer, Button
|
||||
|
||||
|
||||
class QuitScreen(Screen):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Grid(
|
||||
Static("Are you sure you want to quit?", id="question"),
|
||||
Button("Quit", variant="error", id="quit"),
|
||||
Button("Cancel", variant="primary", id="cancel"),
|
||||
id="dialog",
|
||||
)
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
if event.button.id == "quit":
|
||||
self.app.exit()
|
||||
else:
|
||||
self.app.pop_screen()
|
||||
|
||||
|
||||
class ModalApp(App):
|
||||
CSS_PATH = "modal01.css"
|
||||
BINDINGS = [("q", "request_quit", "Quit")]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
yield Footer()
|
||||
|
||||
def action_request_quit(self) -> None:
|
||||
self.push_screen(QuitScreen())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = ModalApp()
|
||||
app.run()
|
||||
18
docs/examples/guide/screens/screen01.css
Normal file
18
docs/examples/guide/screens/screen01.css
Normal file
@@ -0,0 +1,18 @@
|
||||
BSOD {
|
||||
align: center middle;
|
||||
background: blue;
|
||||
color: white;
|
||||
}
|
||||
|
||||
BSOD>Static {
|
||||
width: 70;
|
||||
}
|
||||
|
||||
#title {
|
||||
content-align-horizontal: center;
|
||||
text-style: reverse;
|
||||
}
|
||||
|
||||
#any-key {
|
||||
content-align-horizontal: center;
|
||||
}
|
||||
34
docs/examples/guide/screens/screen01.py
Normal file
34
docs/examples/guide/screens/screen01.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from textual.app import App, Screen, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
ERROR_TEXT = """
|
||||
An error has occurred. To continue:
|
||||
|
||||
Press Enter to return to Windows, or
|
||||
|
||||
Press CTRL+ALT+DEL to restart your computer. If you do this,
|
||||
you will lose any unsaved information in all open applications.
|
||||
|
||||
Error: 0E : 016F : BFF9B3D4
|
||||
"""
|
||||
|
||||
|
||||
class BSOD(Screen):
|
||||
BINDINGS = [("escape", "app.pop_screen", "Pop screen")]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static(" Windows ", id="title")
|
||||
yield Static(ERROR_TEXT)
|
||||
yield Static("Press any key to continue [blink]_[/]", id="any-key")
|
||||
|
||||
|
||||
class BSODApp(App):
|
||||
CSS_PATH = "screen01.css"
|
||||
SCREENS = {"bsod": BSOD()}
|
||||
BINDINGS = [("b", "push_screen('bsod')", "BSOD")]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = BSODApp()
|
||||
app.run()
|
||||
18
docs/examples/guide/screens/screen02.css
Normal file
18
docs/examples/guide/screens/screen02.css
Normal file
@@ -0,0 +1,18 @@
|
||||
BSOD {
|
||||
align: center middle;
|
||||
background: blue;
|
||||
color: white;
|
||||
}
|
||||
|
||||
BSOD>Static {
|
||||
width: 70;
|
||||
}
|
||||
|
||||
#title {
|
||||
content-align-horizontal: center;
|
||||
text-style: reverse;
|
||||
}
|
||||
|
||||
#any-key {
|
||||
content-align-horizontal: center;
|
||||
}
|
||||
36
docs/examples/guide/screens/screen02.py
Normal file
36
docs/examples/guide/screens/screen02.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from textual.app import App, Screen, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
ERROR_TEXT = """
|
||||
An error has occurred. To continue:
|
||||
|
||||
Press Enter to return to Windows, or
|
||||
|
||||
Press CTRL+ALT+DEL to restart your computer. If you do this,
|
||||
you will lose any unsaved information in all open applications.
|
||||
|
||||
Error: 0E : 016F : BFF9B3D4
|
||||
"""
|
||||
|
||||
|
||||
class BSOD(Screen):
|
||||
BINDINGS = [("escape", "app.pop_screen", "Pop screen")]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static(" Windows ", id="title")
|
||||
yield Static(ERROR_TEXT)
|
||||
yield Static("Press any key to continue [blink]_[/]", id="any-key")
|
||||
|
||||
|
||||
class BSODApp(App):
|
||||
CSS_PATH = "screen02.css"
|
||||
BINDINGS = [("b", "push_screen('bsod')", "BSOD")]
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.install_screen(BSOD(), name="bsod")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = BSODApp()
|
||||
app.run()
|
||||
15
docs/examples/widgets/footer.py
Normal file
15
docs/examples/widgets/footer.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.widgets import Footer
|
||||
|
||||
|
||||
class FooterApp(App):
|
||||
BINDINGS = [Binding(key="q", action="quit", description="Quit the app")]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Footer()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = FooterApp()
|
||||
app.run()
|
||||
12
docs/examples/widgets/header.py
Normal file
12
docs/examples/widgets/header.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Header
|
||||
|
||||
|
||||
class HeaderApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = HeaderApp()
|
||||
app.run()
|
||||
13
docs/examples/widgets/input.py
Normal file
13
docs/examples/widgets/input.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Input
|
||||
|
||||
|
||||
class InputApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Input(placeholder="First Name")
|
||||
yield Input(placeholder="Last Name")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = InputApp()
|
||||
app.run()
|
||||
12
docs/examples/widgets/static.py
Normal file
12
docs/examples/widgets/static.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class StaticApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static("Hello, world!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = StaticApp()
|
||||
app.run()
|
||||
29
docs/examples/widgets/table.py
Normal file
29
docs/examples/widgets/table.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import csv
|
||||
import io
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import DataTable
|
||||
|
||||
CSV = """lane,swimmer,country,time
|
||||
4,Joseph Schooling,Singapore,50.39
|
||||
2,Michael Phelps,United States,51.14
|
||||
5,Chad le Clos,South Africa,51.14
|
||||
6,László Cseh,Hungary,51.14
|
||||
3,Li Zhuhao,China,51.26
|
||||
8,Mehdy Metella,France,51.58
|
||||
7,Tom Shields,United States,51.73
|
||||
1,Aleksandr Sadovnikov,Russia,51.84"""
|
||||
|
||||
|
||||
class TableApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield DataTable()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
table = self.query_one(DataTable)
|
||||
rows = csv.reader(io.StringIO(CSV))
|
||||
table.add_columns(*next(rows))
|
||||
table.add_rows(rows)
|
||||
|
||||
|
||||
app = TableApp()
|
||||
@@ -24,19 +24,23 @@ You can install Textual via PyPI.
|
||||
|
||||
If you plan on developing Textual apps, then you should install `textual[dev]`. The `[dev]` part installs a few extra dependencies for development.
|
||||
|
||||
```bash
|
||||
pip install "textual[dev]"
|
||||
```
|
||||
pip install "textual[dev]==0.2.0b5"
|
||||
```
|
||||
|
||||
If you only plan on _running_ Textual apps, then you can drop the `[dev]` part:
|
||||
|
||||
```bash
|
||||
pip install textual
|
||||
```
|
||||
pip install textual==0.2.0b5
|
||||
```
|
||||
|
||||
!!! important
|
||||
|
||||
There may be a more recent beta version since the time of writing. Check the [release history](https://pypi.org/project/textual/#history) for a more recent version.
|
||||
|
||||
## Textual CLI
|
||||
|
||||
If you installed the dev dependencies you have have access to the `textual` CLI command. There are a number of sub-commands which will aid you in building Textual apps.
|
||||
If you installed the dev dependencies you have access to the `textual` CLI command. There are a number of sub-commands which will aid you in building Textual apps.
|
||||
|
||||
```bash
|
||||
textual --help
|
||||
|
||||
@@ -131,10 +131,26 @@ Textual supports the following builtin actions which are defined on the app.
|
||||
options:
|
||||
show_root_heading: false
|
||||
|
||||
### Push screen
|
||||
|
||||
::: textual.app.App.action_push_screen
|
||||
|
||||
|
||||
### Pop screen
|
||||
|
||||
::: textual.app.App.action_pop_screen
|
||||
|
||||
|
||||
### Screenshot
|
||||
|
||||
::: textual.app.App.action_screenshot
|
||||
|
||||
|
||||
### Switch screen
|
||||
|
||||
::: textual.app.App.action_switch_screen
|
||||
|
||||
|
||||
### Toggle_dark
|
||||
|
||||
::: textual.app.App.action_toggle_dark
|
||||
|
||||
@@ -1,12 +1,151 @@
|
||||
# Screens
|
||||
|
||||
TODO: Screens docs
|
||||
This chapter covers Textual's screen API. We will discuss how to create screens and switch between them.
|
||||
|
||||
- Explanation of screens
|
||||
- Screens API
|
||||
- Install screen
|
||||
- Uninstall screen
|
||||
- Push screen
|
||||
- Pop screen
|
||||
- Switch Screen
|
||||
- Screens example
|
||||
## What is a screen?
|
||||
|
||||
Screens are containers for widgets that occupy the dimensions of your terminal. There can be many screens in a given app, but only one screen is visible at a time.
|
||||
|
||||
Textual requires that there be at least one screen object and will create one implicitly in the App class. If you don't change the screen, any widgets you [mount][textual.widget.Widget.mount] or [compose][textual.widget.Widget.compose] will be added to this default screen.
|
||||
|
||||
!!! tip
|
||||
|
||||
Try printing `widget.parent` to see what object your widget is connected to.
|
||||
|
||||
<div class="excalidraw">
|
||||
--8<-- "docs/images/dom1.excalidraw.svg"
|
||||
</div>
|
||||
|
||||
## Creating a screen
|
||||
|
||||
You can create a screen by extending the [Screen][textual.screen.Screen] class which you can import from `textual.screen`. The screen may be styled in the same way as other widgets, with the exception that you can't modify the screen's dimensions (as these will always be the size of your terminal).
|
||||
|
||||
Let's look at a simple example of writing a screen class to simulate Window's [blue screen of death](https://en.wikipedia.org/wiki/Blue_screen_of_death).
|
||||
|
||||
=== "screen01.py"
|
||||
|
||||
```python title="screen01.py" hl_lines="17-23 28"
|
||||
--8<-- "docs/examples/guide/screens/screen01.py"
|
||||
```
|
||||
|
||||
=== "screen01.css"
|
||||
|
||||
```sass title="screen01.css"
|
||||
--8<-- "docs/examples/guide/screens/screen01.css"
|
||||
```
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/guide/screens/screen01.py" press="b,_"}
|
||||
```
|
||||
|
||||
If you run this you will see an empty screen. Hit the ++b++ screen to show a blue screen of death. Hit ++escape++ to return to the default screen.
|
||||
|
||||
The `BSOD` class above defines a screen with a key binding and compose method. These should be familiar as they work in the same way as apps.
|
||||
|
||||
The app class has a new `SCREENS` class variable. Textual uses this class variable to associated a name with screen object (the name is used to reference screens in the screen API). Also in the app is a key binding associated with the action `"push_screen('bsod')"`. The screen class has a similar action `"pop_screen"` bound to the ++escape++ key. We will cover these actions below.
|
||||
|
||||
## Named screens
|
||||
|
||||
You can associate a screen with a name by defining a `SCREENS` class variable in your app, which should be dict that maps names on to Screen objects. The name of the screen may be used interchangeably with screen objects in much of the screen API.
|
||||
|
||||
You can also _install_ new named screens dynamically with the [install_screen][textual.app.App.install_screen] method. The following example installs the `BSOD` screen in a mount handler rather than from the `SCREENS` variable.
|
||||
|
||||
=== "screen02.py"
|
||||
|
||||
```python title="screen02.py" hl_lines="30-31"
|
||||
--8<-- "docs/examples/guide/screens/screen02.py"
|
||||
```
|
||||
|
||||
=== "screen02.css"
|
||||
|
||||
```sass title="screen02.css"
|
||||
--8<-- "docs/examples/guide/screens/screen02.css"
|
||||
```
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/guide/screens/screen02.py" press="b,_"}
|
||||
```
|
||||
|
||||
Although both do the same thing, we recommend the `SCREENS` for screens that exist for the lifetime of your app.
|
||||
|
||||
### Uninstalling screens
|
||||
|
||||
Screens defined in `SCREENS` or added with [install_screen][textual.app.App.install_screen] are _installed_ screens. Textual will keep these screens in memory for the lifetime of your app.
|
||||
|
||||
If you have installed a screen, but you later want it to be removed and cleaned up, you can call [uninstall_screen][textual.app.App.uninstall_screen].
|
||||
|
||||
## Screen stack
|
||||
|
||||
Textual keeps track of a _stack_ of screens. You can think of the screen stack as a stack of paper, where only the very top sheet is visible. If you remove the top sheet the paper underneath becomes visible. Screens work in a similar way.
|
||||
|
||||
The active screen (top of the stack) will render the screen and receive input events. The following API methods on the App class can manipulate this stack, and let you decide which screen the user can interact with.
|
||||
|
||||
### Push screen
|
||||
|
||||
The [push_screen][textual.app.App.push_screen] method puts a screen on top of the stack and makes that screen active. You can call this method with the name of an installed screen, or a screen object.
|
||||
|
||||
<div class="excalidraw">
|
||||
--8<-- "docs/images/screens/push_screen.excalidraw.svg"
|
||||
</div>
|
||||
|
||||
#### Action
|
||||
|
||||
You can also push screens with the `"app.push_screen"` action, which requires the name of an installed screen.
|
||||
|
||||
### Pop screen
|
||||
|
||||
The [pop_screen][textual.app.App.pop_screen] method removes the top-most screen from the stack, and makes the new top screen active.
|
||||
|
||||
!!! note
|
||||
|
||||
The screen stack must always have at least one screen. If you attempt to remove the last screen, Textual will raise a [ScreenStackError][textual.app.ScreenStackError] exception.
|
||||
|
||||
<div class="excalidraw">
|
||||
--8<-- "docs/images/screens/pop_screen.excalidraw.svg"
|
||||
</div>
|
||||
|
||||
|
||||
When you pop a screen it will be removed and deleted unless it has been installed or there is another copy of the screen on the stack.
|
||||
|
||||
#### Action
|
||||
|
||||
You can also pop screens with the `"app.pop_screen"` action.
|
||||
|
||||
### Switch screen
|
||||
|
||||
The [switch_screen][textual.app.App.switch_screen] method replaces the top of the stack with a new screen.
|
||||
|
||||
<div class="excalidraw">
|
||||
--8<-- "docs/images/screens/switch_screen.excalidraw.svg"
|
||||
</div>
|
||||
|
||||
Like [pop_screen](#pop-screen), if the screen being replaced is not installed it will be removed and deleted.
|
||||
|
||||
#### Action
|
||||
|
||||
You can also switch screens with the `"app.switch_screen"` action which accepts the name of the screen to switch to.
|
||||
|
||||
## Modal screens
|
||||
|
||||
Screens can be used to implement modal dialogs. The following example pushes a screen when you hit the ++q++ key to ask you if you really want to quit.
|
||||
|
||||
=== "modal01.py"
|
||||
|
||||
```python title="modal01.py" hl_lines="18 20 32"
|
||||
--8<-- "docs/examples/guide/screens/modal01.py"
|
||||
```
|
||||
|
||||
=== "modal01.css"
|
||||
|
||||
```sass title="modal01.css"
|
||||
--8<-- "docs/examples/guide/screens/modal01.css"
|
||||
```
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/guide/screens/modal01.py" press="q,_"}
|
||||
```
|
||||
|
||||
Note the `request_quit` action in the app which pushes a new instance of `QuitScreen`. This makes the quit screen active. if you click cancel, the quit screen calls `pop_screen` to return the default screen. This also removes and deletes the `QuitScreen` object.
|
||||
|
||||
16
docs/images/screens/pop_screen.excalidraw.svg
Normal file
16
docs/images/screens/pop_screen.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
16
docs/images/screens/push_screen.excalidraw.svg
Normal file
16
docs/images/screens/push_screen.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 21 KiB |
16
docs/images/screens/switch_screen.excalidraw.svg
Normal file
16
docs/images/screens/switch_screen.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 19 KiB |
@@ -1 +1 @@
|
||||
::: textual.app.App
|
||||
::: textual.app
|
||||
|
||||
1
docs/reference/data_table.md
Normal file
1
docs/reference/data_table.md
Normal file
@@ -0,0 +1 @@
|
||||
::: textual.widgets.DataTable
|
||||
1
docs/reference/footer.md
Normal file
1
docs/reference/footer.md
Normal file
@@ -0,0 +1 @@
|
||||
::: textual.widgets.Footer
|
||||
1
docs/reference/header.md
Normal file
1
docs/reference/header.md
Normal file
@@ -0,0 +1 @@
|
||||
::: textual.widgets.Header
|
||||
1
docs/reference/input.md
Normal file
1
docs/reference/input.md
Normal file
@@ -0,0 +1 @@
|
||||
::: textual.widgets.Input
|
||||
@@ -35,13 +35,13 @@ If you want to try the finished Stopwatch app and follow along with the code, fi
|
||||
=== "HTTPS"
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Textualize/textual.git
|
||||
git clone -b css https://github.com/Textualize/textual.git
|
||||
```
|
||||
|
||||
=== "SSH"
|
||||
|
||||
```bash
|
||||
git clone git@github.com:Textualize/textual.git
|
||||
git clone -b css git@github.com:Textualize/textual.git
|
||||
```
|
||||
|
||||
=== "GitHub CLI"
|
||||
@@ -50,6 +50,7 @@ If you want to try the finished Stopwatch app and follow along with the code, fi
|
||||
gh repo clone Textualize/textual
|
||||
```
|
||||
|
||||
|
||||
With the repository cloned, navigate to `docs/examples/tutorial` and run `stopwatch.py`.
|
||||
|
||||
```bash
|
||||
@@ -152,7 +153,7 @@ Textual has a builtin `Button` widget which takes care of the first three compon
|
||||
|
||||
Let's add those to the app. Just a skeleton for now, we will add the rest of the features as we go.
|
||||
|
||||
```python title="stopwatch02.py" hl_lines="3 6-7 10-18 30"
|
||||
```python title="stopwatch02.py" hl_lines="2-3 6-7 10-18 30"
|
||||
--8<-- "docs/examples/tutorial/stopwatch02.py"
|
||||
```
|
||||
|
||||
@@ -160,7 +161,7 @@ We've imported two new widgets in this code: `Button`, which creates a clickable
|
||||
|
||||
We've defined an empty `TimeDisplay` widget by extending `Static`. We will flesh this out later.
|
||||
|
||||
The Stopwatch widget also class extends `Static`. This class has a `compose()` method which yields child widgets, consisting of three `Button` objects and a single `TimeDisplay`. These widgets will form the stopwatch in our sketch.
|
||||
The Stopwatch widget class also extends `Static`. This class has a `compose()` method which yields child widgets, consisting of three `Button` objects and a single `TimeDisplay` object. These widgets will form the stopwatch in our sketch.
|
||||
|
||||
#### The buttons
|
||||
|
||||
@@ -377,7 +378,7 @@ We've seen how we can update widgets with a timer, but we still need to wire up
|
||||
We need to be able to start, stop, and reset each stopwatch independently. We can do this by adding a few more methods to the `TimeDisplay` class.
|
||||
|
||||
|
||||
```python title="stopwatch06.py" hl_lines="14 30-44 50-61"
|
||||
```python title="stopwatch06.py" hl_lines="14 18 30-44 50-61"
|
||||
--8<-- "docs/examples/tutorial/stopwatch06.py"
|
||||
```
|
||||
|
||||
@@ -431,6 +432,7 @@ Let's use these methods to implement adding and removing stopwatches to our app.
|
||||
|
||||
Here's a summary of the changes:
|
||||
|
||||
- The Container object in StopWatchApp grew a "timers" ID.
|
||||
- Added `action_add_stopwatch` to add a new stopwatch.
|
||||
- Added `action_remove_stopwatch` to remove a stopwatch.
|
||||
- Added keybindings for the actions.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Button
|
||||
|
||||
## Description
|
||||
|
||||
A simple button widget which can be pressed using a mouse click or by pressing ++return++
|
||||
when it has focus.
|
||||
@@ -33,16 +32,16 @@ Clicking any of the non-disabled buttons in the example app below will result in
|
||||
## Reactive Attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|------------|--------|-------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ---------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `label` | `str` | `""` | The text that appears inside the button. |
|
||||
| `variant` | `str` | `"default"` | Semantic styling variant. One of `default`, `primary`, `success`, `warning`, `error`. |
|
||||
| `disabled` | `bool` | `False` | Whether the button is disabled or not. Disabled buttons cannot be focused or clicked, and are styled in a way that suggests this. |
|
||||
|
||||
## Events
|
||||
## Messages
|
||||
|
||||
### Pressed
|
||||
|
||||
The `Button.Pressed` event is sent when the button is pressed.
|
||||
The `Button.Pressed` message is sent when the button is pressed.
|
||||
|
||||
- [x] Bubbles
|
||||
|
||||
|
||||
@@ -1 +1,38 @@
|
||||
# DataTable
|
||||
|
||||
A data table widget.
|
||||
|
||||
- [x] Focusable
|
||||
- [ ] Container
|
||||
|
||||
## Example
|
||||
|
||||
The example below populates a table with CSV data.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/table.py"}
|
||||
```
|
||||
|
||||
=== "table.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/table.py"
|
||||
```
|
||||
|
||||
|
||||
## Reactive Attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --------------- | ------ | ------- | ---------------------------------- |
|
||||
| `show_header` | `bool` | `True` | Show the table header |
|
||||
| `fixed_rows` | `int` | `0` | Number of fixed rows |
|
||||
| `fixed_columns` | `int` | `0` | Number of fixed columns |
|
||||
| `zebra_stripes` | `bool` | `False` | Display alternating colors on rows |
|
||||
| `header_height` | `int` | `1` | Height of header row |
|
||||
| `show_cursor` | `bool` | `True` | Show a cell cursor |
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
* [Table][textual.widgets.DataTable] code reference
|
||||
|
||||
@@ -1 +1,42 @@
|
||||
# Footer
|
||||
|
||||
A simple footer widget which is docked to the bottom of its parent container. Displays
|
||||
available keybindings for the currently focused widget.
|
||||
|
||||
- [ ] Focusable
|
||||
- [ ] Container
|
||||
|
||||
## Example
|
||||
|
||||
The example below shows an app with a single keybinding that contains only a `Footer`
|
||||
widget. Notice how the `Footer` automatically displays the keybind.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/footer.py"}
|
||||
```
|
||||
|
||||
=== "footer.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/footer.py"
|
||||
```
|
||||
|
||||
## Reactive Attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --------------- | ----- | ------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `highlight_key` | `str` | `None` | Stores the currently highlighted key. This is typically the key the cursor is hovered over in the footer. |
|
||||
|
||||
## Messages
|
||||
|
||||
This widget sends no messages.
|
||||
|
||||
## Additional Notes
|
||||
|
||||
* You can prevent keybindings from appearing in the footer by setting the `show` argument of the `Binding` to `False`.
|
||||
* You can customize the text that appears for the key itself in the footer using the `key_display` argument of `Binding`.
|
||||
|
||||
## See Also
|
||||
|
||||
* [Footer](../reference/footer.md) code reference
|
||||
|
||||
@@ -1 +1,35 @@
|
||||
# Header
|
||||
|
||||
A simple header widget which docks itself to the top of the parent container.
|
||||
|
||||
- [ ] Focusable
|
||||
- [ ] Container
|
||||
|
||||
## Example
|
||||
|
||||
The example below shows an app with a `Header`.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/header.py"}
|
||||
```
|
||||
|
||||
=== "header.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/header.py"
|
||||
```
|
||||
|
||||
## Reactive Attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `tall` | `bool` | `True` | Whether the `Header` widget is displayed as tall or not. The tall variant is 3 cells tall by default. The non-tall variant is a single cell tall. This can be toggled by clicking on the header. |
|
||||
|
||||
## Messages
|
||||
|
||||
This widget sends no messages.
|
||||
|
||||
## See Also
|
||||
|
||||
* [Header](../reference/header.md) code reference
|
||||
|
||||
@@ -1 +1,67 @@
|
||||
# Input
|
||||
|
||||
A single-line text input widget.
|
||||
|
||||
- [x] Focusable
|
||||
- [ ] Container
|
||||
|
||||
## Example
|
||||
|
||||
The example below shows how you might create a simple form using two `Input` widgets.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/input.py" press="tab,D,a,r,r,e,n"}
|
||||
```
|
||||
|
||||
=== "input.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/input.py"
|
||||
```
|
||||
|
||||
## Reactive Attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ----------------- | ------ | ------- | --------------------------------------------------------------- |
|
||||
| `cursor_blink` | `bool` | `True` | True if cursor blinking is enabled. |
|
||||
| `value` | `str` | `""` | The value currently in the text input. |
|
||||
| `cursor_position` | `int` | `0` | The index of the cursor in the value string. |
|
||||
| `placeholder` | `str` | `str` | The dimmed placeholder text to display when the input is empty. |
|
||||
| `password` | `bool` | `False` | True if the input should be masked. |
|
||||
|
||||
## Messages
|
||||
|
||||
### Changed
|
||||
|
||||
The `Input.Changed` message is sent when the value in the text input changes.
|
||||
|
||||
- [x] Bubbles
|
||||
|
||||
#### Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| --------- | ----- | -------------------------------- |
|
||||
| `value` | `str` | The new value in the text input. |
|
||||
|
||||
|
||||
### Submitted
|
||||
|
||||
The `Input.Submitted` message is sent when you press ++enter++ with the text field submitted.
|
||||
|
||||
- [x] Bubbles
|
||||
|
||||
#### Attributes
|
||||
|
||||
| attribute | type | purpose |
|
||||
| --------- | ----- | -------------------------------- |
|
||||
| `value` | `str` | The new value in the text input. |
|
||||
|
||||
|
||||
## Additional Notes
|
||||
|
||||
* The spacing around the text content is due to border. To remove it, set `border: none;` in your CSS.
|
||||
|
||||
## See Also
|
||||
|
||||
* [Input](../reference/input.md) code reference
|
||||
|
||||
@@ -1 +1,34 @@
|
||||
# Static
|
||||
|
||||
A widget which displays static content.
|
||||
Can be used for simple text labels, but can also contain more complex Rich renderables.
|
||||
|
||||
- [ ] Focusable
|
||||
- [x] Container
|
||||
|
||||
## Example
|
||||
|
||||
The example below shows how you can use a `Static` widget as a simple text label.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/widgets/static.py"}
|
||||
```
|
||||
|
||||
=== "static.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/widgets/static.py"
|
||||
```
|
||||
|
||||
## Reactive Attributes
|
||||
|
||||
This widget has no reactive attributes.
|
||||
|
||||
## Messages
|
||||
|
||||
This widget sends no messages.
|
||||
|
||||
## See Also
|
||||
|
||||
* [Static](../reference/static.md) code reference
|
||||
|
||||
Reference in New Issue
Block a user