mirror of https://github.com/Textualize/rich.git
Use fractions for ratio
This commit is contained in:
parent
ff53e78053
commit
b7779eb772
|
@ -1,4 +1,5 @@
|
|||
from math import ceil, modf
|
||||
from fractions import Fraction
|
||||
from math import ceil, floor, modf
|
||||
from typing import cast, List, Optional, Sequence
|
||||
from typing_extensions import Protocol
|
||||
|
||||
|
@ -30,6 +31,8 @@ def ratio_resolve(total: int, edges: Sequence[Edge]) -> List[int]:
|
|||
# Size of edge or None for yet to be determined
|
||||
sizes = [(edge.size or None) for edge in edges]
|
||||
|
||||
_Fraction = Fraction
|
||||
|
||||
# While any edges haven't been calculated
|
||||
while None in sizes:
|
||||
# Get flexible edges and index to map these back on to sizes list
|
||||
|
@ -47,7 +50,9 @@ def ratio_resolve(total: int, edges: Sequence[Edge]) -> List[int]:
|
|||
for size, edge in zip(sizes, edges)
|
||||
]
|
||||
# Calculate number of characters in a ratio portion
|
||||
portion = remaining / sum((edge.ratio or 1) for _, edge in flexible_edges)
|
||||
portion = _Fraction(
|
||||
remaining, sum((edge.ratio or 1) for _, edge in flexible_edges)
|
||||
)
|
||||
|
||||
# If any edges will be less than their minimum, replace size with the minimum
|
||||
for index, edge in flexible_edges:
|
||||
|
@ -59,11 +64,11 @@ def ratio_resolve(total: int, edges: Sequence[Edge]) -> List[int]:
|
|||
# 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
|
||||
_divmod = divmod
|
||||
remainder = _Fraction(0)
|
||||
for index, edge in flexible_edges:
|
||||
remainder, size = _modf(portion * edge.ratio + remainder)
|
||||
sizes[index] = int(size)
|
||||
size, remainder = _divmod(portion * edge.ratio + remainder, 1)
|
||||
sizes[index] = size
|
||||
break
|
||||
# Sizes now contains integers only
|
||||
return cast(List[int], sizes)
|
||||
|
@ -135,3 +140,17 @@ def ratio_distribute(
|
|||
total_ratio -= ratio
|
||||
total_remaining -= distributed
|
||||
return distributed_total
|
||||
|
||||
|
||||
if __name__ == "__main__": # type: ignore
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class E:
|
||||
|
||||
size: Optional[int] = None
|
||||
ratio: int = 1
|
||||
minimum_size: int = 1
|
||||
|
||||
resolved = ratio_resolve(110, [E(None, 1, 1), E(None, 1, 1), E(None, 1, 1)])
|
||||
print(sum(resolved))
|
||||
|
|
|
@ -185,7 +185,6 @@ class Layout:
|
|||
def unsplit(self) -> None:
|
||||
"""Reset splits to initial state."""
|
||||
del self._children[:]
|
||||
self.direction = None
|
||||
|
||||
def update(self, renderable: RenderableType) -> None:
|
||||
"""Update renderable.
|
||||
|
@ -294,7 +293,7 @@ if __name__ == "__main__": # type: ignore
|
|||
Layout(name="s1"), Layout(name="s2"), Layout(), direction="horizontal"
|
||||
)
|
||||
|
||||
layout["s2"].split(Layout(name="top"), Layout(), Layout())
|
||||
# layout["s2"].split(Layout(name="top"), Layout(), Layout())
|
||||
|
||||
layout["side"].split(Layout(), Layout())
|
||||
|
||||
|
|
Loading…
Reference in New Issue