codekingpro/portable-devtools
114k
1from __future__ import annotations2 3import enum4import typing5 6from urwid.canvas import CompositeCanvas, SolidCanvas7 8from .constants import BOX_SYMBOLS, SHADE_SYMBOLS, Sizing9from .widget import Widget10 11 12class DividerSymbols(str, enum.Enum):13 """Common symbols for divider widgets."""14 15 # Lines16 LIGHT_HL = BOX_SYMBOLS.LIGHT.HORIZONTAL17 LIGHT_4_DASHES = BOX_SYMBOLS.LIGHT.HORIZONTAL_4_DASHES18 LIGHT_3_DASHES = BOX_SYMBOLS.LIGHT.HORIZONTAL_3_DASHES19 LIGHT_2_DASHES = BOX_SYMBOLS.LIGHT.HORIZONTAL_2_DASHES20 HEAVY_HL = BOX_SYMBOLS.HEAVY.HORIZONTAL21 HEAVY_4_DASHES = BOX_SYMBOLS.HEAVY.HORIZONTAL_4_DASHES22 HEAVY_3_DASHES = BOX_SYMBOLS.HEAVY.HORIZONTAL_3_DASHES23 HEAVY_2_DASHES = BOX_SYMBOLS.HEAVY.HORIZONTAL_2_DASHES24 DOUBLE_HL = BOX_SYMBOLS.DOUBLE.HORIZONTAL25 26 # Full block27 FULL_BLOCK = SHADE_SYMBOLS.FULL_BLOCK28 DARK_SHADE = SHADE_SYMBOLS.DARK_SHADE29 MEDIUM_SHADE = SHADE_SYMBOLS.MEDIUM_SHADE30 LITE_SHADE = SHADE_SYMBOLS.LITE_SHADE31 32 33class Divider(Widget):34 """35 Horizontal divider widget36 """37 38 Symbols = DividerSymbols39 40 _sizing = frozenset([Sizing.FLOW])41 42 ignore_focus = True43 44 def __init__(45 self,46 div_char: str | bytes = " ",47 top: int = 0,48 bottom: int = 0,49 ) -> None:50 """51 :param div_char: character to repeat across line52 :type div_char: bytes or unicode53 54 :param top: number of blank lines above55 :type top: int56 57 :param bottom: number of blank lines below58 :type bottom: int59 60 >>> Divider()61 <Divider flow widget>62 >>> Divider("-")63 <Divider flow widget '-'>64 >>> Divider("x", 1, 2)65 <Divider flow widget 'x' bottom=2 top=1>66 """67 super().__init__()68 self.div_char = div_char69 self.top = top70 self.bottom = bottom71 72 def _repr_words(self) -> list[str]:73 return super()._repr_words() + [repr(self.div_char)] * (self.div_char != " ")74 75 def _repr_attrs(self) -> dict[str, typing.Any]:76 attrs = dict(super()._repr_attrs())77 if self.top:78 attrs["top"] = self.top79 if self.bottom:80 attrs["bottom"] = self.bottom81 return attrs82 83 def rows(self, size: tuple[int], focus: bool = False) -> int:84 """85 Return the number of lines that will be rendered.86 87 >>> Divider().rows((10,))88 189 >>> Divider("x", 1, 2).rows((10,))90 491 """92 (_maxcol,) = size93 return self.top + 1 + self.bottom94 95 def render(96 self,97 size: tuple[int], # type: ignore[override]98 focus: bool = False,99 ) -> CompositeCanvas:100 """101 Render the divider as a canvas and return it.102 103 >>> Divider().render((10,)).text # ... = b in Python 3104 [...' ']105 >>> Divider("-", top=1).render((10,)).text106 [...' ', ...'----------']107 >>> Divider("x", bottom=2).render((5,)).text108 [...'xxxxx', ...' ', ...' ']109 """110 (maxcol,) = size111 canv = CompositeCanvas(SolidCanvas(self.div_char, maxcol, 1))112 if self.top or self.bottom:113 canv.pad_trim_top_bottom(self.top, self.bottom)114 return canv115 