Skip to content

Commit de9897b

Browse files
authored
Merge pull request #5278 from Textualize/demo-tweaks
Add position:absolute and game to demo
2 parents d9acae2 + 7279db8 commit de9897b

30 files changed

+1194
-36
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88

9-
## Unreleased
9+
## [0.87.0] - 2024-11-24
1010

1111
### Added
1212

1313
- Added Styles.has_any_rules https://github.com/Textualize/textual/pull/5264
14+
- Added `position` CSS rule. https://github.com/Textualize/textual/pull/5278
15+
- Added `Widget.set_scroll` https://github.com/Textualize/textual/pull/5278
16+
- Added `Select.selection` https://github.com/Textualize/textual/pull/5278
1417

1518
### Fixed
1619

@@ -2573,6 +2576,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040
25732576
- New handler system for messages that doesn't require inheritance
25742577
- Improved traceback handling
25752578

2579+
[0.87.0]: https://github.com/Textualize/textual/compare/v0.86.4...v0.87.0
25762580
[0.86.3]: https://github.com/Textualize/textual/compare/v0.86.2...v0.86.3
25772581
[0.86.2]: https://github.com/Textualize/textual/compare/v0.86.1...v0.86.2
25782582
[0.86.1]: https://github.com/Textualize/textual/compare/v0.86.0...v0.86.1

docs/css_types/position.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# <position>
2+
3+
The `<position>` CSS type defines how the the `offset` rule is applied..
4+
5+
6+
## Syntax
7+
8+
A [`<position>`](./position.md) may be any of the following values:
9+
10+
| Value | Alignment type |
11+
| ---------- | ------------------------------------------------------------ |
12+
| `relative` | Offset is applied to widgets default position. |
13+
| `absolute` | Offset is applied to the origin (top left) of its container. |
14+
15+
## Examples
16+
17+
### CSS
18+
19+
```css
20+
Label {
21+
position: absolute;
22+
offset: 10 5;
23+
}
24+
```
25+
26+
### Python
27+
28+
```py
29+
widget.styles.position = "absolute"
30+
widget.styles.offset = (10, 5)
31+
```

docs/examples/styles/position.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from textual.app import App, ComposeResult
2+
from textual.widgets import Label
3+
4+
5+
class PositionApp(App):
6+
CSS_PATH = "position.tcss"
7+
8+
def compose(self) -> ComposeResult:
9+
yield Label("Absolute", id="label1")
10+
yield Label("Relative", id="label2")
11+
12+
13+
if __name__ == "__main__":
14+
app = PositionApp()
15+
app.run()

docs/examples/styles/position.tcss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Screen {
2+
align: center middle;
3+
}
4+
5+
Label {
6+
padding: 1;
7+
background: $panel;
8+
border: thick $border;
9+
}
10+
11+
Label#label1 {
12+
position: absolute;
13+
offset: 2 1;
14+
}
15+
16+
Label#label2 {
17+
position: relative;
18+
offset: 2 1;
19+
}

docs/styles/position.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
# Position
3+
4+
The `position` style modifies what [`offset`](./offset.md) is applied to.
5+
The default for `position` is `"relative"`, which means the offset is applied to the normal position of the widget.
6+
In other words, if `offset` is (1, 1), then the widget will be moved 1 cell and 1 line down from its usual position.
7+
8+
The alternative value of `position` is `"absolute"`.
9+
With absolute positioning, the offset is relative to the origin (i.e. the top left of the container).
10+
So a widget with offset (1, 1) and absolute positioning will be 1 cell and 1 line down from the top left corner.
11+
12+
!!! note
13+
14+
Absolute positioning takes precedence over the parent's alignment rule.
15+
16+
## Syntax
17+
18+
--8<-- "docs/snippets/syntax_block_start.md"
19+
position: <a href="../../css_types/position">&lt;position&gt;</a>;
20+
--8<-- "docs/snippets/syntax_block_end.md"
21+
22+
23+
## Examples
24+
25+
26+
Two labels, the first is absolute positioned and is displayed relative to the top left of the screen.
27+
The second label is relative and is displayed offset from the center.
28+
29+
=== "Output"
30+
31+
```{.textual path="docs/examples/styles/position.py"}
32+
```
33+
34+
=== "position.py"
35+
36+
```py
37+
--8<-- "docs/examples/styles/position.py"
38+
```
39+
40+
=== "position.tcss"
41+
42+
```css
43+
--8<-- "docs/examples/styles/position.tcss"
44+
```
45+
46+
47+
48+
49+
## CSS
50+
51+
```css
52+
position: relative;
53+
position: absolute;
54+
```
55+
56+
## Python
57+
58+
```py
59+
widget.styles.position = "relative"
60+
widget.styles.position = "absolute"
61+
```

mkdocs-nav.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ nav:
3737
- "css_types/name.md"
3838
- "css_types/number.md"
3939
- "css_types/overflow.md"
40+
- "css_types/position.md"
4041
- "css_types/percentage.md"
4142
- "css_types/scalar.md"
4243
- "css_types/text_align.md"
@@ -122,6 +123,7 @@ nav:
122123
- "styles/outline.md"
123124
- "styles/overflow.md"
124125
- "styles/padding.md"
126+
- "styles/position.md"
125127
- Scrollbar colors:
126128
- "styles/scrollbar_colors/index.md"
127129
- "styles/scrollbar_colors/scrollbar_background.md"

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "textual"
3-
version = "0.86.3"
3+
version = "0.87.0"
44
homepage = "https://github.com/Textualize/textual"
55
repository = "https://github.com/Textualize/textual"
66
documentation = "https://textual.textualize.io/"
@@ -22,6 +22,7 @@ classifiers = [
2222
"Programming Language :: Python :: 3.10",
2323
"Programming Language :: Python :: 3.11",
2424
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
2526
"Typing :: Typed",
2627
]
2728
include = [

src/textual/_arrange.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ def arrange(
109109
layout_placements, placement_offset
110110
)
111111

112+
WidgetPlacement.apply_absolute(layout_placements)
113+
112114
placements.extend(layout_placements)
113115

114116
return DockArrangeResult(placements, set(display_widgets), scroll_spacing)
@@ -186,6 +188,7 @@ def _arrange_dock_widgets(
186188
dock_widget,
187189
top_z,
188190
True,
191+
False,
189192
)
190193
)
191194

@@ -238,7 +241,7 @@ def _arrange_split_widgets(
238241

239242
append_placement(
240243
_WidgetPlacement(
241-
split_region, null_offset, null_spacing, split_widget, 1, True
244+
split_region, null_offset, null_spacing, split_widget, 1, True, False
242245
)
243246
)
244247

src/textual/_compositor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ def add_widget(
649649
z,
650650
fixed,
651651
overlay,
652+
absolute,
652653
) in reversed(placements):
653654
layer_index = get_layer_index(sub_widget.layer, 0)
654655
# Combine regions with children to calculate the "virtual size"

src/textual/css/_help_text.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
VALID_BORDER,
1515
VALID_KEYLINE,
1616
VALID_LAYOUT,
17+
VALID_POSITION,
1718
VALID_STYLE_FLAGS,
1819
VALID_TEXT_ALIGN,
1920
)
@@ -770,6 +771,23 @@ def offset_single_axis_help_text(property_name: str) -> HelpText:
770771
)
771772

772773

774+
def position_help_text(property_name: str) -> HelpText:
775+
"""Help text to show when the user supplies the wrong value for position.
776+
777+
Args:
778+
property_name: The name of the property.
779+
780+
Returns:
781+
Renderable for displaying the help text for this property.
782+
"""
783+
return HelpText(
784+
summary=f"Invalid value for [i]{property_name}[/]",
785+
bullets=[
786+
Bullet(f"Valid values are {friendly_list(VALID_POSITION)}"),
787+
],
788+
)
789+
790+
773791
def style_flags_property_help_text(
774792
property_name: str, value: str, context: StylingContext
775793
) -> HelpText:

0 commit comments

Comments
 (0)