-
Notifications
You must be signed in to change notification settings - Fork 826
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a Progress Bar widget. (#2333)
* First prototype of PB. * Repurpose UnderlineBar. * Factor out 'Bar' widget. * Revert "Factor out 'Bar' widget." This reverts commit 0bb4871. * Add Bar widget. * Cap progress at 100%. * Add skeleton for the ETA label. [skip ci] * Add ETA display. * Improve docstrings. * Directly compute percentage. * Watch percentage changes directly. [skip ci] * Documentation. * Make reactive percentage private. Instead, we create a public read-only percentage property. * Update griffe to fix documentation issue. Related issues: #1572, mkdocstrings/griffe#128. Related PRs: mkdocstrings/griffe#135. * Add example and docs. * Address review feedback. [skip ci] * More documentation. * Add tests. * Changelog. * More tests. * Fix/fake tests. * Final tweaks.
- Loading branch information
1 parent
ee0d407
commit 4148b1d
Showing
20 changed files
with
2,242 additions
and
262 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Container { | ||
overflow: hidden hidden; | ||
height: auto; | ||
} | ||
|
||
Center { | ||
margin-top: 1; | ||
margin-bottom: 1; | ||
layout: horizontal; | ||
} | ||
|
||
ProgressBar { | ||
padding-left: 3; | ||
} | ||
|
||
Input { | ||
width: 16; | ||
} | ||
|
||
VerticalScroll { | ||
height: auto; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from textual.app import App, ComposeResult | ||
from textual.containers import Center, VerticalScroll | ||
from textual.widgets import Button, Header, Input, Label, ProgressBar | ||
|
||
|
||
class FundingProgressApp(App[None]): | ||
CSS_PATH = "progress_bar.css" | ||
|
||
TITLE = "Funding tracking" | ||
|
||
def compose(self) -> ComposeResult: | ||
yield Header() | ||
with Center(): | ||
yield Label("Funding: ") | ||
yield ProgressBar(total=100, show_eta=False) # (1)! | ||
with Center(): | ||
yield Input(placeholder="$$$") | ||
yield Button("Donate") | ||
|
||
yield VerticalScroll(id="history") | ||
|
||
def on_button_pressed(self) -> None: | ||
self.add_donation() | ||
|
||
def on_input_submitted(self) -> None: | ||
self.add_donation() | ||
|
||
def add_donation(self) -> None: | ||
text_value = self.query_one(Input).value | ||
try: | ||
value = int(text_value) | ||
except ValueError: | ||
return | ||
self.query_one(ProgressBar).advance(value) | ||
self.query_one(VerticalScroll).mount(Label(f"Donation for ${value} received!")) | ||
self.query_one(Input).value = "" | ||
|
||
|
||
if __name__ == "__main__": | ||
FundingProgressApp().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from textual.app import App, ComposeResult | ||
from textual.containers import Center, Middle | ||
from textual.timer import Timer | ||
from textual.widgets import Footer, ProgressBar | ||
|
||
|
||
class IndeterminateProgressBar(App[None]): | ||
BINDINGS = [("s", "start", "Start")] | ||
|
||
progress_timer: Timer | ||
"""Timer to simulate progress happening.""" | ||
|
||
def compose(self) -> ComposeResult: | ||
with Center(): | ||
with Middle(): | ||
yield ProgressBar() | ||
yield Footer() | ||
|
||
def on_mount(self) -> None: | ||
"""Set up a timer to simulate progess happening.""" | ||
self.progress_timer = self.set_interval(1 / 10, self.make_progress, pause=True) | ||
|
||
def make_progress(self) -> None: | ||
"""Called automatically to advance the progress bar.""" | ||
self.query_one(ProgressBar).advance(1) | ||
|
||
def action_start(self) -> None: | ||
"""Start the progress tracking.""" | ||
self.query_one(ProgressBar).update(total=100) | ||
self.progress_timer.resume() | ||
|
||
|
||
if __name__ == "__main__": | ||
IndeterminateProgressBar().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from textual.app import App, ComposeResult | ||
from textual.containers import Center, Middle | ||
from textual.timer import Timer | ||
from textual.widgets import Footer, ProgressBar | ||
|
||
|
||
class IndeterminateProgressBar(App[None]): | ||
BINDINGS = [("s", "start", "Start")] | ||
|
||
progress_timer: Timer | ||
"""Timer to simulate progress happening.""" | ||
|
||
def compose(self) -> ComposeResult: | ||
with Center(): | ||
with Middle(): | ||
yield ProgressBar() | ||
yield Footer() | ||
|
||
def on_mount(self) -> None: | ||
"""Set up a timer to simulate progess happening.""" | ||
self.progress_timer = self.set_interval(1 / 10, self.make_progress, pause=True) | ||
|
||
def make_progress(self) -> None: | ||
"""Called automatically to advance the progress bar.""" | ||
self.query_one(ProgressBar).advance(1) | ||
|
||
def action_start(self) -> None: | ||
"""Start the progress tracking.""" | ||
self.query_one(ProgressBar).update(total=100) | ||
self.progress_timer.resume() | ||
|
||
def key_f(self) -> None: | ||
# Freeze time for the indeterminate progress bar. | ||
self.query_one(ProgressBar).query_one("#bar")._get_elapsed_time = lambda: 5 | ||
|
||
def key_t(self) -> None: | ||
# Freeze time to show always the same ETA. | ||
self.query_one(ProgressBar).query_one("#eta")._get_elapsed_time = lambda: 3.9 | ||
self.query_one(ProgressBar).update(total=100, progress=39) | ||
|
||
def key_u(self) -> None: | ||
self.query_one(ProgressBar).update(total=100, progress=100) | ||
|
||
|
||
if __name__ == "__main__": | ||
IndeterminateProgressBar().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Bar > .bar--indeterminate { | ||
color: $primary; | ||
background: $secondary; | ||
} | ||
|
||
Bar > .bar--bar { | ||
color: $primary; | ||
background: $primary 30%; | ||
} | ||
|
||
Bar > .bar--complete { | ||
color: $error; | ||
} | ||
|
||
PercentageStatus { | ||
text-style: reverse; | ||
color: $secondary; | ||
} | ||
|
||
ETAStatus { | ||
text-style: underline; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from textual.app import App, ComposeResult | ||
from textual.containers import Center, Middle | ||
from textual.timer import Timer | ||
from textual.widgets import Footer, ProgressBar | ||
|
||
|
||
class StyledProgressBar(App[None]): | ||
BINDINGS = [("s", "start", "Start")] | ||
CSS_PATH = "progress_bar_styled.css" | ||
|
||
progress_timer: Timer | ||
"""Timer to simulate progress happening.""" | ||
|
||
def compose(self) -> ComposeResult: | ||
with Center(): | ||
with Middle(): | ||
yield ProgressBar() | ||
yield Footer() | ||
|
||
def on_mount(self) -> None: | ||
"""Set up a timer to simulate progess happening.""" | ||
self.progress_timer = self.set_interval(1 / 10, self.make_progress, pause=True) | ||
|
||
def make_progress(self) -> None: | ||
"""Called automatically to advance the progress bar.""" | ||
self.query_one(ProgressBar).advance(1) | ||
|
||
def action_start(self) -> None: | ||
"""Start the progress tracking.""" | ||
self.query_one(ProgressBar).update(total=100) | ||
self.progress_timer.resume() | ||
|
||
|
||
if __name__ == "__main__": | ||
StyledProgressBar().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from textual.app import App, ComposeResult | ||
from textual.containers import Center, Middle | ||
from textual.timer import Timer | ||
from textual.widgets import Footer, ProgressBar | ||
|
||
|
||
class StyledProgressBar(App[None]): | ||
BINDINGS = [("s", "start", "Start")] | ||
CSS_PATH = "progress_bar_styled.css" | ||
|
||
progress_timer: Timer | ||
"""Timer to simulate progress happening.""" | ||
|
||
def compose(self) -> ComposeResult: | ||
with Center(): | ||
with Middle(): | ||
yield ProgressBar() | ||
yield Footer() | ||
|
||
def on_mount(self) -> None: | ||
"""Set up a timer to simulate progess happening.""" | ||
self.progress_timer = self.set_interval(1 / 10, self.make_progress, pause=True) | ||
|
||
def make_progress(self) -> None: | ||
"""Called automatically to advance the progress bar.""" | ||
self.query_one(ProgressBar).advance(1) | ||
|
||
def action_start(self) -> None: | ||
"""Start the progress tracking.""" | ||
self.query_one(ProgressBar).update(total=100) | ||
self.progress_timer.resume() | ||
|
||
def key_f(self) -> None: | ||
# Freeze time for the indeterminate progress bar. | ||
self.query_one(ProgressBar).query_one("#bar")._get_elapsed_time = lambda: 5 | ||
|
||
def key_t(self) -> None: | ||
# Freeze time to show always the same ETA. | ||
self.query_one(ProgressBar).query_one("#eta")._get_elapsed_time = lambda: 3.9 | ||
self.query_one(ProgressBar).update(total=100, progress=39) | ||
|
||
def key_u(self) -> None: | ||
self.query_one(ProgressBar).update(total=100, progress=100) | ||
|
||
|
||
if __name__ == "__main__": | ||
StyledProgressBar().run() |
Oops, something went wrong.