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 )
)