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

Mouse hover highlighting of a ListItem in a ListView works in unexpected ways #3030

Open
davep opened this issue Jul 30, 2023 · 10 comments
Open
Labels
bug Something isn't working Task

Comments

@davep
Copy link
Contributor

davep commented Jul 30, 2023

Given this code:

from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.widgets import ListView, ListItem, Label

class ListViewHoverIssueApp(App[None]):

    def compose(self) -> ComposeResult:
        yield ListView(
            *[ListItem(Horizontal(Label(f"Item {n}"))) for n in range(100)]
        )

if __name__ == "__main__":
    ListViewHoverIssueApp().run()

note that the :hover highlight only appears when the mouse is hovered over the "empty" part of the item in the list, not when over the text. The reason would seem to be:

    ListItem > Widget :hover {
        background: $boost;
    }

in the code for ListItem; which means that the background boost only happens when (in the case of the example code above) the mouse is over the Horizontal, but not when it's over the Label.

@davep davep added bug Something isn't working Task labels Jul 30, 2023
@davidfokkema
Copy link

The 'inverse' seems to happen when a ListItem contains just a Label. Then only the Label is highlighted and not the empty part. The issue seems to be the same.

@davep
Copy link
Contributor Author

davep commented Jul 30, 2023

Aye, for the same reason above. I just did it the above way as it's easier to see.

@davidfokkema
Copy link

Aye, for the same reason above. I just did it the above way as it's easier to see.

I got that, 😉. Sorry for not making that clear. I like your code BTW, very concise.

@TomJGooding
Copy link
Contributor

TomJGooding commented Aug 1, 2023

I didn't even realise there was a hover highlight in ListView as the effect was so subtle!

I'm wondering if the styling should be closer to the OptionList?

from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.widgets import Label, ListItem, ListView, OptionList
from textual.widgets.option_list import Option


class ExampleApp(App):
    def compose(self) -> ComposeResult:
        with Horizontal():
            yield ListView(
                ListItem(Label("One")),
                ListItem(Label("Two")),
                ListItem(Label("Three")),
            )
            yield OptionList(
                Option("One"),
                Option("Two"),
                Option("Three"),
            )


if __name__ == "__main__":
    app = ExampleApp()
    app.run()

@davidfokkema
Copy link

I didn't even realise there was a hover highlight in ListView as the effect was so subtle!

I'm wondering if the styling should be closer to the OptionList?

So... is an OptionList just a fancy ListView? Do we even need a ListView?

@TomJGooding
Copy link
Contributor

A ListView can contain other Textual widgets, whereas an OptionList is limited to Rich renderables.

For example a ListView could contain an OptionList item - so yes actually in hindsight it doesn't make sense to compare the styling!

@davep
Copy link
Contributor Author

davep commented Aug 1, 2023

Also, further to what Tom says, each item in a ListView is going to be at least two widgets (the ListItem and at least one thing within it), which means two message queues and all that per item. ListView is great for very rich (not Rich, just rich) items but not many of them.

OptionList, on the other hand, is just a single widget no matter how many items are within it. If you've got many 100s, even 1,000s, of items to show, OptionList is a better choice.

@davep
Copy link
Contributor Author

davep commented Aug 1, 2023

I'm wondering if the styling should be closer to the OptionList?

We still have #1780 kicking about which, in part, has been diluted by some of the recent style revamping @willmcgugan did, but there's still a wee bit more work to day (in part the idea of adding some more $builtin-things to say "this is a focused cursor", "this is a non-focused cursor", etc...).

Edit to add: #1704

@davidfokkema
Copy link

So, an OptionList is basically a poor-man's ListView? And very useful at that because it is much faster? Because the OptionList reference documentation really shows of the ability to render Rich elements and the ListView docs are more basic, I thought it was the other way round. Thanks both for the clarification!

@davep
Copy link
Contributor Author

davep commented Aug 2, 2023

So, an OptionList is basically a poor-man's ListView?

I wouldn't personally characterise it like that as I think it misses the fact that they're very distinct classes of widget that serve very different purposes. I think it makes more sense to view ListView as a Vertical with pre-canned "let's navigate the widgets within and be told when things are selected" machinery. OptionList is a whole other thing with a different purpose, which can also serve as the bedrock for all sorts of other uses (see SelectionList, and also OptionList is designed to serve as the basis for classic bouncebar menus, etc).

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

No branches or pull requests

3 participants