Replies: 6 comments 4 replies
-
I thought this might be achievable with a grid layout, but unfortunately it seems The docs suggest this accepts a scalar, so might need updating? https://textual.textualize.io/styles/grid/grid_gutter/ from textual.app import App, ComposeResult
from textual.widgets import Static
class EvenSpacingApp(App):
CSS = """
Screen {
layout: grid;
grid-size: 3;
grid-columns: auto;
grid-gutter: 1fr;
background: lightgreen;
}
Static {
background: darkmagenta;
}
"""
def compose(self) -> ComposeResult:
yield Static("Text")
yield Static("Slightly longer text")
yield Static("Some more text")
if __name__ == "__main__":
app = EvenSpacingApp()
app.run() |
Beta Was this translation helpful? Give feedback.
-
Thank you, but I can't get this to run.
I've tried with textual 0.36.0 and `pip install --upgrade --force git+https://github.com/textualize/textual/`.
It always expects an integer:
```
╭─ Error at [...]/demo_suggested.py:EvenSpacingApp:6:22 ────────────────────────────────────────────────────────────────╮
│ 4 │ │ grid-size: 3; │
│ 5 │ │ grid-columns: auto; │
│ ❱ 6 │ │ grid-gutter: 1fr; │
│ 7 │ │ background: lightgreen; │
│ 8 │ } │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Invalid value for grid-gutter
└── An integer value is expected here
e.g. grid-gutter: 2;
CSS parsing failed: 1 error found in stylesheet
╭─ Error at [...]/demo_suggested.py:EvenSpacingApp:6:22 ────────────────────────────────────────────────────────────────╮
│ 4 │ │ grid-size: 3; │
│ 5 │ │ grid-columns: auto; │
│ ❱ 6 │ │ grid-gutter: 1fr; │
│ 7 │ │ background: lightgreen; │
│ 8 │ } │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Invalid value for grid-gutter
└── An integer value is expected here
e.g. grid-gutter: 2;
CSS parsing failed: 1 error found in stylesheet
NOTE: 2 errors shown above.
```
|
Beta Was this translation helpful? Give feedback.
-
It really depends on how you want things to behave when you resize things. If your code gives you the behaviour you want, then there is nothing much wrong with it. But your center text is not quite centered relative to the screen. It's only centered in the space between the left and right text. I would create three columns, and use from textual.app import App, ComposeResult
from textual.widgets import Label
from textual.containers import Horizontal
class TestApp(App):
CSS = """
Horizontal {
height: auto;
}
Horizontal Label {
width: 1fr;
}
#middle {
content-align-horizontal: center;
}
#right {
content-align-horizontal: right;
}
"""
def compose(self) -> ComposeResult:
with Horizontal():
yield Label("[on red]Text", id="left")
yield Label("[on green]Slightly longer text", id="middle")
yield Label("[on blue]Some more text", id="right")
if __name__ == "__main__":
TestApp().run() BTW No need to spend hours on things like this. Join the Discord and ask. We are here to help. @TomJGooding I think you are correct about the docs erroneously saying gutter can be a scalar. It does only accept an integer. |
Beta Was this translation helpful? Give feedback.
-
@TomJGooding Ah, yes, sorry. Should've read more carefully. @willmcgugan I actually don't want anything centered, I want the widgets evenly spaced out. As I said, the number of widgets is not fixed. There might be 2 or 5 or 6 widgets in that line and I want to add and remove them while the app is running. So that makes your solution a bit awkward. I'm very new to textual, so I might be wrong, but I think my I could put more work into this and make a PR if there's interest. |
Beta Was this translation helpful? Give feedback.
-
Would "visibility: hidden" be preferable to filling with an arbitrary character, using space as the default?
|
Beta Was this translation helpful? Give feedback.
-
I tried, but it's not good enough for a PR. It seems to mostly work, but I don't really understand why. This is what I came up with. Maybe someone finds it useful. class EvenlySpaced(textual.widget.Widget):
class _Spacer(textual.widget.Widget):
def __init__(self, character=' '):
super().__init__()
self.character = character
def render(self):
return '\n'.join(
(
self.character * self.content_size.width
for _ in range(self.content_size.height)
)
)
class _HorizontalSpacer(_Spacer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.styles.width = '1fr'
self.styles.background = 'crimson'
class _VerticalSpacer(_Spacer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.styles.height = '1fr'
self.styles.background = 'indianred'
def __init__(self, *children, layout, **kwargs):
def generate_children():
# Tell children to not expand if they have no width/height set.
if layout == 'horizontal':
for child in children:
if child.styles.width is None:
child.styles.width = 'auto'
else:
for child in children:
if child.styles.height is None:
child.styles.height = 'auto'
# Insert one spacer between two adjacent children.
def intersperse_spacers(children):
for child in children[:-1]:
yield child
if layout == 'horizontal':
yield self._HorizontalSpacer()
else:
yield self._VerticalSpacer()
yield children[-1]
return intersperse_spacers(children)
super().__init__(*generate_children(), **kwargs)
self.styles.layout = layout
self.styles.height = 'auto'
self.styles.width = '1fr' And this is how you use it: EvenlySpaced(
Static('foo'),
Static('bar'),
Static('baz'),
layout='horizontal',
) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I made a custom widget that fills space between widgets.
My use case is: I have a varying number of widgets with varying width aligned horizontally, and I want them to be spaced out evenly.
After searching and fiddling for hours, I came up with a
Spacer
widget. Is there a better way to achieve this?Beta Was this translation helpful? Give feedback.
All reactions