1# Copyright 2022 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Wrapper fuctions to add borders around prompt_toolkit containers.""" 15 16from typing import Callable, List, Optional, Union 17 18from prompt_toolkit.layout import ( 19 AnyContainer, 20 FormattedTextControl, 21 HSplit, 22 VSplit, 23 Window, 24) 25 26 27def create_border( 28 # pylint: disable=too-many-arguments 29 content: AnyContainer, 30 content_height: Optional[int] = None, 31 title: Union[Callable[[], str], str] = '', 32 border_style: Union[Callable[[], str], str] = '', 33 base_style: Union[Callable[[], str], str] = '', 34 top: bool = True, 35 bottom: bool = True, 36 left: bool = True, 37 right: bool = True, 38 horizontal_char: str = '━', 39 vertical_char: str = '┃', 40 top_left_char: str = '┏', 41 top_right_char: str = '┓', 42 bottom_left_char: str = '┗', 43 bottom_right_char: str = '┛', 44 left_margin_columns: int = 0, 45 right_margin_columns: int = 0, 46) -> HSplit: 47 """Wrap any prompt_toolkit container in a border.""" 48 49 top_border_items: List[AnyContainer] = [] 50 if left: 51 top_border_items.append( 52 Window(width=1, height=1, char=top_left_char, style=border_style) 53 ) 54 55 title_text = None 56 if title: 57 if isinstance(title, str): 58 title_text = FormattedTextControl( 59 [('', f'{horizontal_char}{horizontal_char} {title} ')] 60 ) 61 else: 62 title_text = FormattedTextControl(title) 63 64 top_border_items.append( 65 Window( 66 title_text, 67 char=horizontal_char, 68 # Expand width to max available space 69 dont_extend_width=False, 70 style=border_style, 71 ) 72 ) 73 if right: 74 top_border_items.append( 75 Window(width=1, height=1, char=top_right_char, style=border_style) 76 ) 77 78 content_items: List[AnyContainer] = [] 79 if left: 80 content_items.append( 81 Window( 82 width=1, 83 height=content_height, 84 char=vertical_char, 85 style=border_style, 86 ) 87 ) 88 89 if left_margin_columns > 0: 90 content_items.append( 91 Window( 92 width=left_margin_columns, 93 height=content_height, 94 char=' ', 95 style=border_style, 96 ) 97 ) 98 content_items.append(content) 99 if right_margin_columns > 0: 100 content_items.append( 101 Window( 102 width=right_margin_columns, 103 height=content_height, 104 char=' ', 105 style=border_style, 106 ) 107 ) 108 109 if right: 110 content_items.append( 111 Window(width=1, height=2, char=vertical_char, style=border_style) 112 ) 113 114 bottom_border_items: List[AnyContainer] = [] 115 if left: 116 bottom_border_items.append( 117 Window(width=1, height=1, char=bottom_left_char) 118 ) 119 bottom_border_items.append( 120 Window( 121 char=horizontal_char, 122 # Expand width to max available space 123 dont_extend_width=False, 124 ) 125 ) 126 if right: 127 bottom_border_items.append( 128 Window(width=1, height=1, char=bottom_right_char) 129 ) 130 131 rows: List[AnyContainer] = [] 132 if top: 133 rows.append(VSplit(top_border_items, height=1, padding=0)) 134 rows.append(VSplit(content_items, height=content_height)) 135 if bottom: 136 rows.append( 137 VSplit(bottom_border_items, height=1, padding=0, style=border_style) 138 ) 139 140 return HSplit(rows, style=base_style) 141