• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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