-
Notifications
You must be signed in to change notification settings - Fork 814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A Widget with {margin: 1} style in a ScrollableContainer causes infinite resizes and scrollbars flicker #4141
Comments
By the way, this problem happened since Textual 0.48.0. Versions below it are OK. |
I found the scrollbars flicker even if you remove the margin - unfortunately this might be a bug introduced with #4037? |
The underlying error actually seems to go way back. Take this app: from textual.app import App, ComposeResult
from textual.widget import Widget
class A(App[None]):
CSS = """
Screen {
overflow: auto auto;
}
#one {
height: 1;
}
#two {
height: 100%;
}
"""
def compose(self) -> ComposeResult:
yield Widget(id="one")
yield Widget(id="two")
if __name__ == "__main__":
A().run() At v0.19.0 this app doesn't generate this flickering error but it does at v0.19.1. |
The source of the issue was commit 4f7b2d0. Reverting that back now reveals two failed tests:
It looks like the reason those two tests fail is that some unnecessary scrollbar gutters stick around on app startup. |
Ok, I've banged my head against the wall for a while and now I understand what the source of the issue is / what needs to be done. Consider the app below and suppose the terminal size is 80 x 24. from textual.app import App, ComposeResult
from textual.widget import Widget
class A(App[None]):
CSS = """
Screen {
overflow: auto auto;
}
#one {
height: 1;
}
#two {
height: 100%;
}
"""
def compose(self) -> ComposeResult:
yield Widget(id="one")
yield Widget(id="two")
if __name__ == "__main__":
A().run() When the two widgets are mounted the screen is reflowed and we eventually end up at Lines 1463 to 1464 in c7370f3
A bit further down, we have a second check to see if we need a horizontal scrollbar. Lines 1467 to 1470 in c7370f3
However, this isn't needed because the children of this container have relative sizes and as soon as the vertical scrollbar gets added, they will be resized to take up less horizontal space. However, this isn't all. Again, when we get to |
Given the above, it looks like the fix is to go through the children of the widget that is having its scrollbars refreshed and checking if any of them is:
A rough implementation of this (that probably doesn't handle edge cases) would be to replace Lines 1467 to 1470 in c7370f3
with something like if overflow_x == "auto" and show_vertical and not show_horizontal:
show_horizontal = any(
child.size.width == width
and child.styles.width
and (child.styles.width.is_cells or child.styles.width.is_auto)
for child in self.children
) Running the tests shows a single failing test that has to do with if overflow_x == "auto" and show_vertical and not show_horizontal:
if self.children:
show_horizontal = any(
child.size.width == width
and child.styles.width
and (child.styles.width.is_cells or child.styles.width.is_auto)
for child in self.children
)
else:
show_horizontal = self.virtual_size.width > (
width - styles.scrollbar_size_vertical
) However this feels like patching the symptom instead of fixing the underlying issue. |
Don't forget to star the repository! Follow @textualizeio for Textual updates. |
When presenting a ScrollableContainer with a Widget that has styles above in it, there will have a infinite resizes.
Example:
Screen Record:
'textual diagnose' result:
Textual Diagnostics
Versions
Python
Operating System
Terminal
Rich Console options
The text was updated successfully, but these errors were encountered: