Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
panel.py
Go to the documentation of this file.
1from typing import TYPE_CHECKING, Optional
2
3from .align import AlignMethod
4from .box import ROUNDED, Box
5from .cells import cell_len
6from .jupyter import JupyterMixin
7from .measure import Measurement, measure_renderables
8from .padding import Padding, PaddingDimensions
9from .segment import Segment
10from .style import Style, StyleType
11from .text import Text, TextType
12
13if TYPE_CHECKING:
14 from .console import Console, ConsoleOptions, RenderableType, RenderResult
15
16
18 """A console renderable that draws a border around its contents.
19
20 Example:
21 >>> console.print(Panel("Hello, World!"))
22
23 Args:
24 renderable (RenderableType): A console renderable object.
25 box (Box, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`.
26 Defaults to box.ROUNDED.
27 safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.
28 expand (bool, optional): If True the panel will stretch to fill the console
29 width, otherwise it will be sized to fit the contents. Defaults to True.
30 style (str, optional): The style of the panel (border and contents). Defaults to "none".
31 border_style (str, optional): The style of the border. Defaults to "none".
32 width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.
33 height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect.
34 padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0.
35 highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False.
36 """
37
39 self,
40 renderable: "RenderableType",
41 box: Box = ROUNDED,
42 *,
43 title: Optional[TextType] = None,
44 title_align: AlignMethod = "center",
45 subtitle: Optional[TextType] = None,
46 subtitle_align: AlignMethod = "center",
47 safe_box: Optional[bool] = None,
48 expand: bool = True,
49 style: StyleType = "none",
50 border_style: StyleType = "none",
51 width: Optional[int] = None,
52 height: Optional[int] = None,
53 padding: PaddingDimensions = (0, 1),
54 highlight: bool = False,
55 ) -> None:
56 self.renderable = renderable
57 self.box = box
58 self.title = title
59 self.title_align: AlignMethod = title_align
60 self.subtitle = subtitle
61 self.subtitle_align = subtitle_align
62 self.safe_box = safe_box
63 self.expand = expand
64 self.style = style
65 self.border_style = border_style
66 self.width = width
67 self.height = height
68 self.padding = padding
69 self.highlight = highlight
70
71 @classmethod
72 def fit(
73 cls,
74 renderable: "RenderableType",
75 box: Box = ROUNDED,
76 *,
77 title: Optional[TextType] = None,
78 title_align: AlignMethod = "center",
79 subtitle: Optional[TextType] = None,
80 subtitle_align: AlignMethod = "center",
81 safe_box: Optional[bool] = None,
82 style: StyleType = "none",
83 border_style: StyleType = "none",
84 width: Optional[int] = None,
85 padding: PaddingDimensions = (0, 1),
86 ) -> "Panel":
87 """An alternative constructor that sets expand=False."""
88 return cls(
89 renderable,
90 box,
91 title=title,
92 title_align=title_align,
93 subtitle=subtitle,
94 subtitle_align=subtitle_align,
95 safe_box=safe_box,
96 style=style,
97 border_style=border_style,
98 width=width,
99 padding=padding,
100 expand=False,
101 )
102
103 @property
104 def _title(self) -> Optional[Text]:
105 if self.title:
106 title_text = (
108 if isinstance(self.title, str)
109 else self.title.copy()
110 )
111 title_text.end = ""
113 title_text.no_wrap = True
116 return title_text
117 return None
118
119 @property
120 def _subtitle(self) -> Optional[Text]:
121 if self.subtitle:
122 subtitle_text = (
124 if isinstance(self.subtitle, str)
125 else self.subtitle.copy()
126 )
132 return subtitle_text
133 return None
134
136 self, console: "Console", options: "ConsoleOptions"
137 ) -> "RenderResult":
138 _padding = Padding.unpack(self.padding)
139 renderable = (
140 Padding(self.renderable, _padding) if any(_padding) else self.renderable
141 )
142 style = console.get_style(self.style)
143 border_style = style + console.get_style(self.border_style)
144 width = (
146 if self.width is None
147 else min(options.max_width, self.width)
148 )
149
150 safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box
151 box = self.box.substitute(options, safe=safe_box)
152
153 def align_text(
154 text: Text, width: int, align: str, character: str, style: Style
155 ) -> Text:
156 """Gets new aligned text.
157
158 Args:
159 text (Text): Title or subtitle text.
160 width (int): Desired width.
161 align (str): Alignment.
162 character (str): Character for alignment.
163 style (Style): Border style
164
165 Returns:
166 Text: New text instance
167 """
168 text = text.copy()
169 text.truncate(width)
170 excess_space = width - cell_len(text.plain)
171 if excess_space:
172 if align == "left":
173 return Text.assemble(
174 text,
175 (character * excess_space, style),
176 no_wrap=True,
177 end="",
178 )
179 elif align == "center":
180 left = excess_space // 2
181 return Text.assemble(
182 (character * left, style),
183 text,
184 (character * (excess_space - left), style),
185 no_wrap=True,
186 end="",
187 )
188 else:
189 return Text.assemble(
190 (character * excess_space, style),
191 text,
192 no_wrap=True,
193 end="",
194 )
195 return text
196
197 title_text = self._title
198 if title_text is not None:
199 title_text.stylize_before(border_style)
200
201 child_width = (
202 width - 2
203 if self.expand
204 else console.measure(
205 renderable, options=options.update_width(width - 2)
206 ).maximum
207 )
208 child_height = self.height or options.height or None
209 if child_height:
210 child_height -= 2
211 if title_text is not None:
212 child_width = min(
213 options.max_width - 2, max(child_width, title_text.cell_len + 2)
214 )
215
216 width = child_width + 2
217 child_options = options.update(
218 width=child_width, height=child_height, highlight=self.highlight
219 )
220 lines = console.render_lines(renderable, child_options, style=style)
221
222 line_start = Segment(box.mid_left, border_style)
223 line_end = Segment(f"{box.mid_right}", border_style)
224 new_line = Segment.line()
225 if title_text is None or width <= 4:
226 yield Segment(box.get_top([width - 2]), border_style)
227 else:
228 title_text = align_text(
229 title_text,
230 width - 4,
232 box.top,
233 border_style,
234 )
235 yield Segment(box.top_left + box.top, border_style)
236 yield from console.render(title_text, child_options.update_width(width - 4))
237 yield Segment(box.top + box.top_right, border_style)
238
239 yield new_line
240 for line in lines:
241 yield line_start
242 yield from line
243 yield line_end
244 yield new_line
245
246 subtitle_text = self._subtitle
247 if subtitle_text is not None:
248 subtitle_text.stylize_before(border_style)
249
250 if subtitle_text is None or width <= 4:
251 yield Segment(box.get_bottom([width - 2]), border_style)
252 else:
253 subtitle_text = align_text(
254 subtitle_text,
255 width - 4,
256 self.subtitle_align,
258 border_style,
259 )
260 yield Segment(box.bottom_left + box.bottom, border_style)
261 yield from console.render(
262 subtitle_text, child_options.update_width(width - 4)
263 )
264 yield Segment(box.bottom + box.bottom_right, border_style)
265
266 yield new_line
267
269 self, console: "Console", options: "ConsoleOptions"
270 ) -> "Measurement":
271 _title = self._title
272 _, right, _, left = Padding.unpack(self.padding)
273 padding = left + right
274 renderables = [self.renderable, _title] if _title else [self.renderable]
275
276 if self.width is None:
277 width = (
278 measure_renderables(
279 console,
281 renderables,
282 ).maximum
283 + padding
284 + 2
285 )
286 else:
287 width = self.width
288 return Measurement(width, width)
289
290
291if __name__ == "__main__": # pragma: no cover
292 from .console import Console
293
295
296 from .box import DOUBLE, ROUNDED
297 from .padding import Padding
298
299 p = Panel(
300 "Hello, World!",
301 title="rich.Panel",
302 style="white on blue",
303 box=DOUBLE,
304 padding=1,
305 )
306
307 c.print()
308 c.print(p)
Optional[Text] _subtitle(self)
Definition panel.py:120
"Measurement" __rich_measure__(self, "Console" console, "ConsoleOptions" options)
Definition panel.py:270
Optional[Text] _title(self)
Definition panel.py:104
"RenderResult" __rich_console__(self, "Console" console, "ConsoleOptions" options)
Definition panel.py:137
"Panel" fit(cls, "RenderableType" renderable, Box box=ROUNDED, *Optional[TextType] title=None, AlignMethod title_align="center", Optional[TextType] subtitle=None, AlignMethod subtitle_align="center", Optional[bool] safe_box=None, StyleType style="none", StyleType border_style="none", Optional[int] width=None, PaddingDimensions padding=(0, 1))
Definition panel.py:86
None __init__(self, "RenderableType" renderable, Box box=ROUNDED, *Optional[TextType] title=None, AlignMethod title_align="center", Optional[TextType] subtitle=None, AlignMethod subtitle_align="center", Optional[bool] safe_box=None, bool expand=True, StyleType style="none", StyleType border_style="none", Optional[int] width=None, Optional[int] height=None, PaddingDimensions padding=(0, 1), bool highlight=False)
Definition panel.py:55
for i