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

Add style variations to the progress bar widget #3143

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

petertalaber
Copy link

Fixes #2920.

  • Docstrings on all new or modified functions / classes
  • Updated documentation
  • Updated CHANGELOG.md (where appropriate)

@willmcgugan
Copy link
Collaborator

Hi @petertalaber Any chance of some screenshots of the variants?

@petertalaber
Copy link
Author

Sure! It would look like these:

Rainbow:
10%
50%
90%
Rainbow color ranges can be modified via component classes attribute: bar--bar.color and bar--bar.complete.

Thickness:
thin
normal
thick

@petertalaber
Copy link
Author

Adding @rodrigogiraoserrao

@rodrigogiraoserrao
Copy link
Contributor

Just to be clear, does the rainbow variant change colours as the progress increases, or are the colours changing regardless of the progress advancing?

@petertalaber
Copy link
Author

petertalaber commented Aug 23, 2023

It will change colors as the progress increases. In the example above it will start from blue via cyan, green, orange up to red according to the color circle in counterclockwise direction. The starting and ending color can be configured and this range is divided proportional to the percentage to show the proper color.

color circle

Copy link
Contributor

@rodrigogiraoserrao rodrigogiraoserrao left a comment

Choose a reason for hiding this comment

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

Thanks for your work!

I've left some questions and remarks, mostly about style – so that this code fits with the rest of the code base.

Feel free to ping me or re-request a review when you are done going through my comments.

src/textual/color.py Outdated Show resolved Hide resolved
docs/widgets/progress_bar.md Outdated Show resolved Hide resolved
docs/widgets/progress_bar.md Show resolved Hide resolved
docs/widgets/progress_bar.md Outdated Show resolved Hide resolved
docs/widgets/progress_bar.md Show resolved Hide resolved
)
return colorscheme

def validate_thickness(self, thickness: int) -> int:
Copy link
Contributor

Choose a reason for hiding this comment

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

When you create the literal type for valid thicknesses and the set of valid options, they can be used here.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

When I said "it can be used here", I also meant in the typing sense; something like

Suggested change
def validate_thickness(self, thickness: int) -> int:
def validate_thickness(self, thickness: int) -> BarThickness:

src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
Comment on lines 407 to 413
self._colorscheme = colorscheme
self._thickness = thickness
Copy link
Contributor

Choose a reason for hiding this comment

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

Docstrings, please.

Also, how do you feel of making these attributes reactives?

Copy link
Author

Choose a reason for hiding this comment

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

Isn't it enough for those to be reactive only in Bar class and be normal variables in ProgressBar?

Copy link
Contributor

Choose a reason for hiding this comment

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

If they're normal variables in the progress bar, then if someone does something like progress_bar.thickness = 2, that won't updated automatically the thickness of the progress bar because Textual has no way of knowing that it should also update the thickness of the bar renderable.

Copy link
Contributor

@rodrigogiraoserrao rodrigogiraoserrao left a comment

Choose a reason for hiding this comment

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

Great work on implementing the changes, thanks.

I have a couple of follow-up questions.

src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
)
return colorscheme

def validate_thickness(self, thickness: int) -> int:
Copy link
Contributor

Choose a reason for hiding this comment

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

When I said "it can be used here", I also meant in the typing sense; something like

Suggested change
def validate_thickness(self, thickness: int) -> int:
def validate_thickness(self, thickness: int) -> BarThickness:

src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
src/textual/widgets/_progress_bar.py Outdated Show resolved Hide resolved
@@ -59,9 +79,15 @@ class Bar(Widget, can_focus=False):
"""The percentage of progress that has been completed."""
_start_time: float | None
"""The time when the widget started tracking progress."""
color_scheme = reactive(_DEFAULT_BAR_COLOR_SCHEME)
"""The color scheme of the widget."""
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"""The color scheme of the widget."""
"""The color scheme of the rule."""

Copy link
Contributor

Choose a reason for hiding this comment

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

I hope you don't mind me sticking my nose in, but shouldn't this be "bar" rather than "rule"?

Copy link
Author

Choose a reason for hiding this comment

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

Bar is OK.

color_scheme = reactive(_DEFAULT_BAR_COLOR_SCHEME)
"""The color scheme of the widget."""
thickness = reactive(_DEFAULT_BAR_THICKNESS)
"""The thickness of the widget."""
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"""The thickness of the widget."""
"""The thickness of the rule."""

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

Ok.

Comment on lines +104 to +113
if color_scheme is None:
color_scheme = _DEFAULT_BAR_COLOR_SCHEME
Copy link
Contributor

Choose a reason for hiding this comment

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

So, the idea is that setting to None falls back to the default value? (And same thing for the thickness?)
If so, I think you should mention that in the docstrings for the reactives.

Copy link
Author

Choose a reason for hiding this comment

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

Yes. It is easier to use I guess if we don't have to deal with default constants around the code. If not set Bar will turn None into the default value.

@rodrigogiraoserrao
Copy link
Contributor

I'll see if I can get someone else from the team to review this.
We're pretty tight on time with major work on Textual on the web, the TextArea widget, and the command palette, though, so I hope you understand that this may take a bit of time.

@petertalaber
Copy link
Author

Sure. That Textual on the web seems cool. Don't bother with this. You will check this patch when you have time again.

orosam and others added 2 commits October 9, 2023 20:22
- Rainbow scheme will update bar color based on percentage
starting from .bar--bar.color up to .bar--complete.color in
counterclockwise direction.

- Bar thickness can have 3 styles: thin, normal or thick.
@davep
Copy link
Collaborator

davep commented Nov 1, 2023

I'm giving this an initial review, and I'm a wee bit confused by the files being used for the docs, especially when it comes to the stylesheets. There seems to be some tcss files that contain things that aren't illustrated in the example screenshot/code, and there also seems to be at least one instance of a stylesheet missing:

Screenshot 2023-11-01 at 11 38 04

There's no screenshot in this, just code, and no stylesheet.

Would it be possible to get a once over of the state of the files in the documentation, and perhaps be sure that each of the files just contain what's necessary to show off what's being illustrated.

As an aside, there looks to be a couple of files named with a trailing underscore; is there a reason for that?

def key_9(self) -> None:
self._action_common_keypress(90)

def _action_common_keypress(self, progress: int) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's a bit of a nit-pick, but given that this is intended for the docs, I think I'd be tempted to write this as slightly more idiomatic Textual code, using BINDINGS and calling on the action.

def key_2(self) -> None:
self._action_common_keypress(2)

def _action_common_keypress(self, thickness: int) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

As mentioned in another file: I think I'd be tempted to do this with BINDINGS and the action, it feels like it would be more "normal" for Textual code.

docs/widgets/progress_bar.md Show resolved Hide resolved
docs/widgets/progress_bar.md Show resolved Hide resolved
docs/widgets/progress_bar.md Show resolved Hide resolved
docs/widgets/progress_bar.md Show resolved Hide resolved
## Styling the Progress Bar

The progress bar is composed of three sub-widgets that can be styled independently:

| Widget name | ID | Description |
| ------------------ | ------------- | ---------------------------------------------------------------- |
| `Bar` | `#bar` | The bar that visually represents the progress made. |
| `Bar` | `#bar` | Bar that visually represents the progress made. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was there a specific reason for changing this? I feel it reads better before the change.

@@ -125,9 +188,9 @@ The progress bar is composed of three sub-widgets that can be styled independent

| Name | Type | Default | Description |
| ------------ | ------- | ------- | ------------------------------------------------------------------------------------------------------- |
| `percentage` | `float | None` | The read-only percentage of progress that has been made. This is `None` if the `total` hasn't been set. |
| `percentage` | `float` | `None` | The read-only percentage of progress that has been made. This is `None` if the `total` hasn't been set. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

The type looks to be wrong here, if percentage can be None then the type should be float | None.

| `progress` | `float` | `0` | The number of steps of progress already made. |
| `total` | `float | None` | The total number of steps that we are keeping track of. |
| `total` | `float` | `None` | The total number of steps that we are keeping track of. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

The type looks wrong here, of total can be None then the type should be float | None.


Args:
destination: Another color.
factor: A blend factor, -1 -> 1.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit-pick: I'd spell out that it's "between -1 and 1", and perhaps make clear if it's exclusive or inclusive.

@rodrigogiraoserrao
Copy link
Contributor

@davep the trailing underscores are there on purpose:
to make sure the docs screenshots of the progress bar are consistent, we need to “freeze” the progress bar.
So, a file progress_bar_example.py contains the code for a progress bar app with some styling, and that's the code that is shown to the user in the docs, but then we screenshot progress_bar_example_.py, which is the same code, plus a tiny cheat to make sure that the progress bar is frozen always in the same location.

Does this make sense?

Do you have a better idea of how this can be accomplished?

@davep
Copy link
Collaborator

davep commented Nov 1, 2023

Does this make sense?

Ahh hah! Okay, that makes more sense.

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.

Add style variations to the progress bar widget
6 participants