You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
spiel/spiel/widgets/minislides.py

71 lines
2.5 KiB
Python

from __future__ import annotations
from itertools import islice
from math import ceil
from rich.console import RenderableType
from rich.layout import Layout
from rich.panel import Panel
from rich.style import Style
from rich.text import Text
from spiel.triggers import Triggers
from spiel.utils import clamp
from spiel.widgets.widget import SpielWidget
class MiniSlides(SpielWidget):
def render(self) -> RenderableType:
grid_width = self.app.deck_grid_width
row_of_current_slide = self.app.current_slide_idx // grid_width
num_rows = ceil(len(self.app.deck) / grid_width)
start_row = clamp(
value=row_of_current_slide - (grid_width // 2),
lower=0,
upper=max(num_rows - grid_width, 0),
)
start_slide_idx = grid_width * start_row
slides = islice(enumerate(self.app.deck.slides), start_slide_idx, None)
rows = [Layout(name=str(r)) for r in range(grid_width)]
cols = [[Layout(name=f"{r}-{c}") for c in range(grid_width)] for r, _ in enumerate(rows)]
root = Layout()
root.split_column(*rows)
for row, layouts in zip(rows, cols):
row.split_row(*layouts)
for layout in layouts:
slide_idx, slide = next(slides, (None, None))
if slide_idx is None or slide is None:
layout.update("")
else:
is_active_slide = slide_idx == self.app.current_slide_idx
try:
content = slide.render(triggers=Triggers.new())
border_style = Style(
color="bright_cyan" if is_active_slide else None,
dim=not is_active_slide,
)
except Exception as e:
content = Text(
f"Failed to render slide {slide_idx + 1} due to:\n{e}",
style=Style(color="red"),
)
border_style = Style(
color="red1",
dim=not is_active_slide,
)
layout.update(
Panel(
content,
title=" | ".join((str(slide_idx + 1), slide.title)),
border_style=border_style,
)
)
return root