Skip to content
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

Rendering glitches on scrolling #5099

Closed
darrenburns opened this issue Oct 9, 2024 · 4 comments · Fixed by #5104
Closed

Rendering glitches on scrolling #5099

darrenburns opened this issue Oct 9, 2024 · 4 comments · Fixed by #5104
Labels
bug Something isn't working

Comments

@darrenburns
Copy link
Member

darrenburns commented Oct 9, 2024

I'm seeing quite a lot of rendering glitches when scrolling in my demo app.

It was happening on 0.79.1, so I upgraded to main but I'm getting the same issue.

I'm unsure if there are specific circumstances which are triggering this - it seems to happen pretty consistently for me.

All I'm doing is scrolling to the top of a container which containers a bunch of widgets and then quickly scrolling back down. I'd say around a third of the time I get a glitch of some sort.

They look like this:

image image image

MRE

from __future__ import annotations
from typing import Any

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Vertical, VerticalScroll
from textual.widgets import (
    DataTable,
    Footer,
    Input,
    Label,
    ListItem,
    ListView,
    OptionList,
    RadioSet,
    SelectionList,
    Switch,
    TextArea,
    Tree,
)
from textual.widgets._toggle_button import ToggleButton
from textual.widgets.option_list import Option
from textual.widgets.text_area import Selection

HEADERS = ("lane", "swimmer", "country", "time")
ROWS = [
    (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),
    (10, "Darren Burns", "Scotland", 51.84),
]

LOREM_IPSUM = """\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Sed euismod, nunc sit amet aliquam lacinia, nisl nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem. Sed euismod, nunc sit amet aliquam lacinia, nisl nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem. Sed euismod, nunc sit amet aliquam lacinia, nisl nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem.

Donec auctor, nisl eget ultricies ultricies, nunc nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem. Sed euismod, nunc sit amet aliquam lacinia, nisl nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem. Sed euismod, nunc sit amet aliquam lacinia, nisl nisl aliquam nisl, nec aliquam nisl nisl sit amet lorem.
"""

class ChangingThemeApp(App[None]):
    CSS = """
    Button {
        width: 1fr;
    }
    TextArea {
        height: 8;
    }
    DataTable {
        height: 8;
    }
    ColorSample {
        width: 1fr;
        color: $text;
        &.primary {
            background: $primary;   
        }
        &.secondary {
            background: $secondary;
        }
        &.accent {
            background: $accent;
        }
        &.warning {
            background: $warning;
        }
        &.error {
            background: $error;
        }
        &.success {
            background: $success;
        }
        &.background {
            background: $background;
        }
        &.surface {
            background: $surface;
        }
        &.panel {
            background: $panel;
        }
    }
    ListView {
        height: auto;
        & > ListItem {
            width: 1fr;
            & > Label {
                width: 1fr;
            }
        }
    }
    Tree {
        height: 5;
    }


    #palette {
        height: auto;
        margin: 1 2;
    }
    #widget-list {
        border: solid $primary;

        &:focus-within {
            border: solid $accent;
        }

        & > OptionList {
            height: 6;
        }
        & > RadioSet {
            height: 6;
        }
    }
    #widget-list > * {
        margin: 1 2;
    }
    """

    def compose(self) -> ComposeResult:
        with VerticalScroll(id="widget-list") as container:
            container.border_title = "Widget Gallery"
            container.can_focus = False
            yield Input(placeholder="Hello, world!")
            yield TextArea(LOREM_IPSUM)
            table = DataTable[Any]()
            table.add_columns(*HEADERS)
            table.add_rows(ROWS)
            yield table
            yield ListView(
                ListItem(Label("One")),
                ListItem(Label("Two")),
                ListItem(Label("Three")),
            )
            yield OptionList(
                "Aerilon",
                "Aquaria",
                "Canceron",
                "Caprica",
                "Gemenon",
                "Leonis",
                "Libran",
                "Picon",
                "Sagittaron",
                "Scorpia",
                "Tauron",
                "Virgon",
            )
            tree: Tree[str] = Tree("Dune")
            tree.root.expand()
            characters = tree.root.add("Characters", expand=True)
            characters.add_leaf("Paul")
            characters.add_leaf("Jessica")
            characters.add_leaf("Chani")
            yield tree

            yield Switch()
            yield ToggleButton(label="Toggle Button")

            yield SelectionList[int](
                ("Falken's Maze", 0, True),
                ("Black Jack", 1),
                ("Gin Rummy", 2),
                ("Hearts", 3),
                ("Bridge", 4),
                ("Checkers", 5),
                ("Chess", 6, True),
                ("Poker", 7),
                ("Fighter Combat", 8, True),
            )
            yield RadioSet(
                "Amanda",
                "Connor MacLeod",
                "Duncan MacLeod",
                "Heather MacLeod",
                "Joe Dawson",
                "Kurgan, [bold italic red]The[/]",
                "Methos",
                "Rachel Ellenstein",
                "Ramírez",
            )

        yield Footer()

    def on_mount(self) -> None:
        text_area = self.query_one(TextArea)
        text_area.selection = Selection((0, 0), (1, 10))


app = ChangingThemeApp()
if __name__ == "__main__":
    app.run()
@darrenburns darrenburns added the bug Something isn't working label Oct 9, 2024
@TomJGooding
Copy link
Contributor

I did notice some other glitches when running this MRE, although they may be completely unrelated to this issue.

Watch the content of the TextArea after simply moving the mouse:

repro-5099-text-area-glitch

@darrenburns
Copy link
Member Author

It looks like the initial wrapping in the text area is being computed and then re-computed after the cursor moves - my guess is that the initial render isn't accounting for the scrollbar (there should be a 1 cell gap at the end that in your video, before you move the cursor, appears to be missing/under the scrollbar).

@darrenburns
Copy link
Member Author

Thanks @TomJGooding! I've created a standalone issue for that in #5103.

Copy link

Don't forget to star the repository!

Follow @textualizeio for Textual updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants