rich/examples/fullscreen.py

187 lines
5.8 KiB
Python
Raw Normal View History

2021-02-15 12:04:26 +00:00
"""
Demonstrates a Rich "application" using the Layout and Live classes.
"""
2021-02-13 17:50:43 +00:00
from datetime import datetime
2021-02-15 12:04:26 +00:00
from rich import box
2021-02-13 17:50:43 +00:00
from rich.console import Console
from rich.layout import Layout
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn
from rich.syntax import Syntax
from rich.table import Table
2021-02-15 12:04:26 +00:00
from rich.text import Text
2021-02-13 17:50:43 +00:00
console = Console()
def make_layout() -> Layout:
2021-02-15 12:04:26 +00:00
"""Define the layout."""
2021-02-13 17:50:43 +00:00
layout = Layout(name="root")
2021-02-14 20:38:08 +00:00
layout.split(
Layout(name="header", size=3),
Layout(name="main", ratio=1),
Layout(name="footer", size=7),
)
layout["main"].split(
Layout(name="side"),
Layout(name="body", ratio=2),
direction="horizontal",
)
layout["side"].split(Layout(name="box1"), Layout(name="box2"))
2021-02-13 17:50:43 +00:00
return layout
2021-02-15 12:04:26 +00:00
def make_sponsor_message() -> Panel:
"""Some example content."""
sponsor_message = Table.grid(padding=1)
sponsor_message.add_column(style="green", justify="right")
sponsor_message.add_column(no_wrap=True)
sponsor_message.add_row(
"Sponsor me",
"[u blue link=https://github.com/sponsors/willmcgugan]https://github.com/sponsors/willmcgugan",
)
sponsor_message.add_row(
"Buy me a :coffee:",
"[u blue link=https://ko-fi.com/willmcgugan]https://ko-fi.com/willmcgugan",
)
sponsor_message.add_row(
"Twitter",
"[u blue link=https://twitter.com/willmcgugan]https://twitter.com/willmcgugan",
)
sponsor_message.add_row(
"Blog", "[u blue link=https://www.willmcgugan.com]https://www.willmcgugan.com"
)
intro_message = Text.from_markup(
"""\
It takes a lot of time to develop Rich and to provide support.
Consider supporting my work via Github Sponsors (ask your company / organization), or buy me a coffee to say thanks.
- Will McGugan"""
)
message = Table.grid(padding=2)
message.add_column()
message.add_column(no_wrap=True)
message.add_row(intro_message, sponsor_message)
message_panel = Panel.fit(
message,
box=box.ROUNDED,
padding=(1, 2),
title="[b red]Thanks for trying out Rich!",
border_style="bright_blue",
)
return message_panel
2021-02-13 17:50:43 +00:00
class Header:
2021-02-15 12:04:26 +00:00
"""Display header with clock."""
2021-02-13 17:50:43 +00:00
def __rich__(self) -> Panel:
grid = Table.grid(expand=True)
grid.add_column(justify="center", ratio=1)
grid.add_column(justify="right")
grid.add_row(
"[b]Rich[/b] Layout application",
datetime.now().ctime().replace(":", "[blink]:[/]"),
)
return Panel(grid, style="white on blue")
2021-02-15 12:04:26 +00:00
def make_syntax() -> Syntax:
code = """\
def ratio_resolve(total: int, edges: List[Edge]) -> List[int]:
sizes = [(edge.size or None) for edge in edges]
# While any edges haven't been calculated
while any(size is None for size in sizes):
# Get flexible edges and index to map these back on to sizes list
flexible_edges = [
(index, edge)
for index, (size, edge) in enumerate(zip(sizes, edges))
if size is None
]
# Remaining space in total
remaining = total - sum(size or 0 for size in sizes)
if remaining <= 0:
# No room for flexible edges
sizes[:] = [(size or 0) for size in sizes]
2021-02-13 17:50:43 +00:00
break
2021-02-15 12:04:26 +00:00
# Calculate number of characters in a ratio portion
portion = remaining / sum((edge.ratio or 1) for _, edge in flexible_edges)
2021-02-13 17:50:43 +00:00
2021-02-15 12:04:26 +00:00
# If any edges will be less than their minimum, replace size with the minimum
for index, edge in flexible_edges:
if portion * edge.ratio <= edge.minimum_size:
sizes[index] = edge.minimum_size
break
else:
# Distribute flexible space and compensate for rounding error
# Since edge sizes can only be integers we need to add the remainder
# to the following line
_modf = modf
remainder = 0.0
for index, edge in flexible_edges:
remainder, size = _modf(portion * edge.ratio + remainder)
sizes[index] = int(size)
break
# Sizes now contains integers only
return cast(List[int], sizes)
"""
syntax = Syntax(code, "python", line_numbers=True)
return syntax
2021-02-13 17:50:43 +00:00
job_progress = Progress(
"{task.description}",
SpinnerColumn(),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
)
2021-02-15 12:04:26 +00:00
job_progress.add_task("[green]Cooking")
job_progress.add_task("[magenta]Baking", total=200)
job_progress.add_task("[cyan]Mixing", total=400)
2021-02-13 17:50:43 +00:00
total = sum(task.total for task in job_progress.tasks)
overall_progress = Progress()
overall_task = overall_progress.add_task("All Jobs", total=int(total))
progress_table = Table.grid(expand=True)
progress_table.add_row(
Panel(
2021-02-15 12:04:26 +00:00
overall_progress,
title="Overall Progress",
border_style="green",
padding=(2, 2),
2021-02-13 17:50:43 +00:00
),
Panel(job_progress, title="[b]Jobs", border_style="red", padding=(1, 2)),
)
2021-02-15 12:04:26 +00:00
layout = make_layout()
layout["header"].update(Header())
layout["body"].update(make_sponsor_message())
layout["box2"].update(Panel(make_syntax(), border_style="green"))
layout["box1"].update(Panel(layout.tree, border_style="red"))
2021-02-13 17:50:43 +00:00
layout["footer"].update(progress_table)
from rich.live import Live
from time import sleep
with Live(layout, refresh_per_second=10, screen=True):
while not overall_progress.finished:
sleep(0.1)
for job in job_progress.tasks:
if not job.finished:
job_progress.advance(job.id)
completed = sum(task.completed for task in job_progress.tasks)
overall_progress.update(overall_task, completed=completed)