12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- from typing import Optional, Union
- from .color import Color
- from .console import Console, ConsoleOptions, RenderResult
- from .jupyter import JupyterMixin
- from .measure import Measurement
- from .segment import Segment
- from .style import Style
- # There are left-aligned characters for 1/8 to 7/8, but
- # the right-aligned characters exist only for 1/8 and 4/8.
- BEGIN_BLOCK_ELEMENTS = ["█", "█", "█", "▐", "▐", "▐", "▕", "▕"]
- END_BLOCK_ELEMENTS = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"]
- FULL_BLOCK = "█"
- class Bar(JupyterMixin):
- """Renders a solid block bar.
- Args:
- size (float): Value for the end of the bar.
- begin (float): Begin point (between 0 and size, inclusive).
- end (float): End point (between 0 and size, inclusive).
- width (int, optional): Width of the bar, or ``None`` for maximum width. Defaults to None.
- color (Union[Color, str], optional): Color of the bar. Defaults to "default".
- bgcolor (Union[Color, str], optional): Color of bar background. Defaults to "default".
- """
- def __init__(
- self,
- size: float,
- begin: float,
- end: float,
- *,
- width: Optional[int] = None,
- color: Union[Color, str] = "default",
- bgcolor: Union[Color, str] = "default",
- ):
- self.size = size
- self.begin = max(begin, 0)
- self.end = min(end, size)
- self.width = width
- self.style = Style(color=color, bgcolor=bgcolor)
- def __repr__(self) -> str:
- return f"Bar({self.size}, {self.begin}, {self.end})"
- def __rich_console__(
- self, console: Console, options: ConsoleOptions
- ) -> RenderResult:
- width = min(
- self.width if self.width is not None else options.max_width,
- options.max_width,
- )
- if self.begin >= self.end:
- yield Segment(" " * width, self.style)
- yield Segment.line()
- return
- prefix_complete_eights = int(width * 8 * self.begin / self.size)
- prefix_bar_count = prefix_complete_eights // 8
- prefix_eights_count = prefix_complete_eights % 8
- body_complete_eights = int(width * 8 * self.end / self.size)
- body_bar_count = body_complete_eights // 8
- body_eights_count = body_complete_eights % 8
- # When start and end fall into the same cell, we ideally should render
- # a symbol that's "center-aligned", but there is no good symbol in Unicode.
- # In this case, we fall back to right-aligned block symbol for simplicity.
- prefix = " " * prefix_bar_count
- if prefix_eights_count:
- prefix += BEGIN_BLOCK_ELEMENTS[prefix_eights_count]
- body = FULL_BLOCK * body_bar_count
- if body_eights_count:
- body += END_BLOCK_ELEMENTS[body_eights_count]
- suffix = " " * (width - len(body))
- yield Segment(prefix + body[len(prefix) :] + suffix, self.style)
- yield Segment.line()
- def __rich_measure__(
- self, console: Console, options: ConsoleOptions
- ) -> Measurement:
- return (
- Measurement(self.width, self.width)
- if self.width is not None
- else Measurement(4, options.max_width)
- )
|