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

List view #1143

Merged
merged 44 commits into from
Dec 9, 2022
Merged

List view #1143

merged 44 commits into from
Dec 9, 2022

Conversation

darrenburns
Copy link
Member

@darrenburns darrenburns commented Nov 9, 2022

image

@willmcgugan willmcgugan marked this pull request as draft November 9, 2022 14:45
@@ -259,7 +259,7 @@ def screen(self) -> "Screen":
from .screen import Screen

node = self
while node and not isinstance(node, Screen):
while node is not None and not isinstance(node, Screen):
Copy link
Member Author

@darrenburns darrenburns Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the line that ultimately resulted in those weird NoScreen errors. Because ListView has a __len__, the condition was evaluating as False and terminating the search for the Screen.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Good catch!

class ListView(Vertical, can_focus=True, can_focus_children=False):
DEFAULT_CSS = """
ListView {
scrollbar-size-vertical: 1;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective, but I prefer width 1 scrollbars for scrollbars that aren't Screen-level.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was more of an issue with the click target being too small. Suspect for that reason, we should keep it at 2 , even if the aesthetics suffer for it.

@darrenburns darrenburns marked this pull request as ready for review November 21, 2022 15:58
@darrenburns darrenburns marked this pull request as draft November 21, 2022 15:59
@darrenburns darrenburns marked this pull request as ready for review November 22, 2022 10:36
Copy link
Collaborator

@willmcgugan willmcgugan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Some requests to consider.

We're kind of finding our feet here. As we build these widgets, I think we will formulate some best practices / standards.

ListItem > Widget :hover {
background: $boost;
}
ListView ListItem.--highlight {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a > here? For the (hopefully rare) scenario of nested ListViews

class ListView(Vertical, can_focus=True, can_focus_children=False):
DEFAULT_CSS = """
ListView {
scrollbar-size-vertical: 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was more of an issue with the click target being too small. Suspect for that reason, we should keep it at 2 , even if the aesthetics suffer for it.

src/textual/widgets/_list_view.py Outdated Show resolved Hide resolved

@property
def highlighted_child(self) -> ListItem | None:
"""Get the currently highlighted ListItem
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're going to adopt property style docstrings in this format:

"""ListItem | None: description"""

self._scroll_highlighted_region()
self.emit_no_wait(self.Highlighted(self, new_child))

async def append(self, item: ListItem) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this non-async?

Use emit_no_wait and return the awaitable from the mount method.

Hopefully that won't break anything.

Ditto for clear

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically yes, but I think this will cause a lot confusion/subtle bugs. It needs to be async because we need to await the call to remove inside it. Otherwise we'll send a ChildrenUpdated with undefined children (could contain children before or after update, who knows).

If I receive a ChildrenUpdated message, I won't know inside my on_children_updated handler if the children have actually been updated yet or not, and I'll have no easy way of awaiting it (I won't have access to the AwaitRemove in there). It would mean we can't actually trust that message any more since the state of the children is undefined. Doing anything to my ListView on receipt of this message would be dangerous.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a children update message? Generally it is the parent that is doing the updating, so it will know there has been an updated.

Do you have a use-case in mind?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed it, don't think it's necessary.

It was to give the ancestors a single hook (the children update handler) that they could use when the children changed. e.g. a single place they can update a label to reflect the number of items in the list rather.

self.index = self.children.index(event.sender)
self.emit_no_wait(self.Selected(self, event.sender))

def key_up(self, event: events.Key) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these used at all? We want to use bindings wherever possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is where the handling is actually done. The bindings for up/down are dummies just to populate the footer. As far as I know when you use bindings you have no way to stop the event and so it was doing Textuals default scrolling behaviour when you pressed up and down.

I've hit a similar issue several times now - maybe I'm just missing something though. In my case I actually very rarely want the scrolling to occur when up/down is pressed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think that is because the Widget class was using key events. I changed that in the tree pr to use bindings. You might find it will work with bindings now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works with bindings now, thanks.

docs/widgets/list_item.md Outdated Show resolved Hide resolved
docs/widgets/list_view.md Show resolved Hide resolved
docs/widgets/list_view.md Outdated Show resolved Hide resolved
tests/snapshot_tests/test_snapshots.py Show resolved Hide resolved
src/textual/widgets/_list_view.py Show resolved Hide resolved
src/textual/widgets/_list_view.py Show resolved Hide resolved
src/textual/widgets/_list_view.py Show resolved Hide resolved
darrenburns and others added 6 commits November 30, 2022 11:37
Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
@willmcgugan willmcgugan merged commit 54a2e3e into main Dec 9, 2022
@willmcgugan willmcgugan deleted the list-view branch December 9, 2022 10:28
davep added a commit to davep/textual that referenced this pull request Jan 24, 2023
As pointed out in Textualize#1649, a `ChildrenUpdated` message is documented but it
doesn't exist in the code. It looks like it got added during development,
then removed after it was realised it wasn't needed, but presumably it got
left in the docs:

  Textualize#1143 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants