0
# Layout and UI Components
1
2
Comprehensive layout system with containers, windows, controls, and widgets for building complex terminal interfaces. The layout system uses a hierarchical approach with containers that organize child components and controls that render actual content.
3
4
## Capabilities
5
6
### Layout Core
7
8
The Layout class serves as the root container for all UI components and manages focus and rendering.
9
10
```python { .api }
11
class Layout:
12
def __init__(self, container, focused_element=None):
13
"""
14
Create a layout with a root container.
15
16
Parameters:
17
- container: Root Container instance
18
- focused_element: Initial focused UI element
19
"""
20
21
def focus(self, focusable):
22
"""
23
Set focus to a specific UI element.
24
25
Parameters:
26
- focusable: UI element to focus
27
"""
28
29
def focus_next(self):
30
"""Move focus to next focusable element."""
31
32
def focus_previous(self):
33
"""Move focus to previous focusable element."""
34
35
def walk(container, skip_hidden=False):
36
"""
37
Walk through all UI elements in layout tree.
38
39
Parameters:
40
- container: Container to walk through
41
- skip_hidden: bool, whether to skip hidden elements
42
43
Yields:
44
UI elements in the container tree
45
"""
46
47
class InvalidLayoutError(Exception):
48
"""Exception raised for invalid layout configurations."""
49
```
50
51
### Dimensions
52
53
System for specifying layout dimensions with support for fixed, percentage, and weighted sizing.
54
55
```python { .api }
56
class Dimension:
57
def __init__(self, min=None, max=None, weight=None, preferred=None):
58
"""
59
Specify layout dimension constraints.
60
61
Parameters:
62
- min: int, minimum size
63
- max: int, maximum size
64
- weight: int, relative weight for distribution
65
- preferred: int, preferred size
66
"""
67
68
def D(min=None, max=None, weight=None, preferred=None):
69
"""
70
Shortcut function to create Dimension.
71
72
Parameters:
73
- min: int, minimum size
74
- max: int, maximum size
75
- weight: int, relative weight
76
- preferred: int, preferred size
77
78
Returns:
79
Dimension instance
80
"""
81
82
def sum_layout_dimensions(dimensions):
83
"""
84
Sum multiple dimensions.
85
86
Parameters:
87
- dimensions: List of Dimension instances
88
89
Returns:
90
Combined Dimension
91
"""
92
93
def max_layout_dimensions(dimensions):
94
"""
95
Get maximum of multiple dimensions.
96
97
Parameters:
98
- dimensions: List of Dimension instances
99
100
Returns:
101
Maximum Dimension
102
"""
103
104
def to_dimension(value):
105
"""
106
Convert value to Dimension.
107
108
Parameters:
109
- value: int, Dimension, or None
110
111
Returns:
112
Dimension instance
113
"""
114
115
def is_dimension(obj):
116
"""
117
Check if object is a Dimension.
118
119
Parameters:
120
- obj: Object to check
121
122
Returns:
123
bool: True if object is Dimension
124
"""
125
126
# Type alias for dimension values
127
AnyDimension = Union[None, int, Dimension]
128
```
129
130
### Container Classes
131
132
Container classes organize child UI elements with different layout strategies.
133
134
```python { .api }
135
class Container:
136
"""Abstract base class for all containers."""
137
138
def __init__(self):
139
"""Create base container."""
140
141
class HSplit(Container):
142
def __init__(
143
self,
144
children,
145
window_too_small=None,
146
align=HorizontalAlign.JUSTIFY,
147
padding=0,
148
padding_char=None,
149
padding_style="",
150
width=None,
151
height=None,
152
z_index=None,
153
modal=False,
154
key_bindings=None,
155
style=""
156
):
157
"""
158
Horizontal split container that stacks children vertically.
159
160
Parameters:
161
- children: List of child containers/windows
162
- window_too_small: Container to show when space is insufficient
163
- align: HorizontalAlign, horizontal alignment of children
164
- padding: int, padding around container
165
- padding_char: str, character for padding
166
- padding_style: str, style for padding
167
- width: AnyDimension, container width
168
- height: AnyDimension, container height
169
- z_index: int, z-order for overlapping
170
- modal: bool, whether container is modal
171
- key_bindings: KeyBindings for container
172
- style: str, CSS-like style
173
"""
174
175
class VSplit(Container):
176
def __init__(
177
self,
178
children,
179
window_too_small=None,
180
align=VerticalAlign.JUSTIFY,
181
padding=0,
182
padding_char=None,
183
padding_style="",
184
width=None,
185
height=None,
186
z_index=None,
187
modal=False,
188
key_bindings=None,
189
style=""
190
):
191
"""
192
Vertical split container that arranges children horizontally.
193
194
Parameters:
195
- children: List of child containers/windows
196
- window_too_small: Container to show when space is insufficient
197
- align: VerticalAlign, vertical alignment of children
198
- padding: int, padding around container
199
- padding_char: str, character for padding
200
- padding_style: str, style for padding
201
- width: AnyDimension, container width
202
- height: AnyDimension, container height
203
- z_index: int, z-order for overlapping
204
- modal: bool, whether container is modal
205
- key_bindings: KeyBindings for container
206
- style: str, CSS-like style
207
"""
208
209
class FloatContainer(Container):
210
def __init__(
211
self,
212
content,
213
floats=None,
214
modal=False,
215
key_bindings=None,
216
style=""
217
):
218
"""
219
Container with floating overlay elements.
220
221
Parameters:
222
- content: Background container content
223
- floats: List of Float instances for overlays
224
- modal: bool, whether container is modal
225
- key_bindings: KeyBindings for container
226
- style: str, CSS-like style
227
"""
228
229
class Float:
230
def __init__(
231
self,
232
content=None,
233
top=None,
234
right=None,
235
bottom=None,
236
left=None,
237
width=None,
238
height=None,
239
xcursor=False,
240
ycursor=False,
241
transparent=False,
242
allow_cover_cursor=False
243
):
244
"""
245
Floating element specification.
246
247
Parameters:
248
- content: Container content for float
249
- top: int, distance from top edge
250
- right: int, distance from right edge
251
- bottom: int, distance from bottom edge
252
- left: int, distance from left edge
253
- width: AnyDimension, float width
254
- height: AnyDimension, float height
255
- xcursor: bool, position relative to cursor X
256
- ycursor: bool, position relative to cursor Y
257
- transparent: bool, whether background is transparent
258
- allow_cover_cursor: bool, allow covering cursor
259
"""
260
261
class Window(Container):
262
def __init__(
263
self,
264
content=None,
265
width=None,
266
height=None,
267
z_index=None,
268
dont_extend_width=False,
269
dont_extend_height=False,
270
ignore_content_width=False,
271
ignore_content_height=False,
272
left_margins=None,
273
right_margins=None,
274
scroll_offsets=None,
275
allow_scroll_beyond_bottom=False,
276
wrap_lines=False,
277
get_vertical_scroll=None,
278
get_horizontal_scroll=None,
279
always_hide_cursor=False,
280
cursorline=False,
281
cursorcolumn=False,
282
colorcolumns=None,
283
align=WindowAlign.LEFT,
284
style="",
285
char=None
286
):
287
"""
288
Window container for displaying UI controls.
289
290
Parameters:
291
- content: UIControl instance to display
292
- width: AnyDimension, window width
293
- height: AnyDimension, window height
294
- z_index: int, z-order for overlapping
295
- dont_extend_width: bool, don't extend to fill width
296
- dont_extend_height: bool, don't extend to fill height
297
- ignore_content_width: bool, ignore content width
298
- ignore_content_height: bool, ignore content height
299
- left_margins: List of Margin instances for left side
300
- right_margins: List of Margin instances for right side
301
- scroll_offsets: ScrollOffsets for scrolling behavior
302
- allow_scroll_beyond_bottom: bool, allow scrolling past end
303
- wrap_lines: bool, wrap long lines
304
- get_vertical_scroll: Function returning vertical scroll position
305
- get_horizontal_scroll: Function returning horizontal scroll position
306
- always_hide_cursor: bool, never show cursor
307
- cursorline: bool, highlight cursor line
308
- cursorcolumn: bool, highlight cursor column
309
- colorcolumns: List of ColorColumn instances
310
- align: WindowAlign, content alignment
311
- style: str, CSS-like style
312
- char: str, background character
313
"""
314
315
class WindowRenderInfo:
316
"""Information about rendered window."""
317
def __init__(self):
318
"""Create window render info."""
319
320
class ConditionalContainer(Container):
321
def __init__(self, container, filter):
322
"""
323
Container shown based on condition.
324
325
Parameters:
326
- container: Container to wrap
327
- filter: Filter determining visibility
328
"""
329
330
class DynamicContainer(Container):
331
def __init__(self, get_container):
332
"""
333
Container with dynamic content.
334
335
Parameters:
336
- get_container: Function returning container
337
"""
338
339
class ScrollablePane(Container):
340
def __init__(
341
self,
342
content,
343
scroll_offsets=None,
344
keep_cursor_visible=True,
345
keep_focused_window_visible=True,
346
max_available_height=None,
347
width=None,
348
height=None,
349
show_scrollbar=True,
350
display_arrows=True,
351
up_arrow_symbol="^",
352
down_arrow_symbol="v"
353
):
354
"""
355
Scrollable container for content larger than display area.
356
357
Parameters:
358
- content: Container content to make scrollable
359
- scroll_offsets: ScrollOffsets configuration
360
- keep_cursor_visible: bool, ensure cursor stays visible
361
- keep_focused_window_visible: bool, keep focused window visible
362
- max_available_height: int, maximum height available
363
- width: AnyDimension, pane width
364
- height: AnyDimension, pane height
365
- show_scrollbar: bool, display scrollbar
366
- display_arrows: bool, show scroll arrows
367
- up_arrow_symbol: str, up arrow character
368
- down_arrow_symbol: str, down arrow character
369
"""
370
371
class ColorColumn:
372
def __init__(self, position, style="class:color-column"):
373
"""
374
Color column background marker.
375
376
Parameters:
377
- position: int, column position
378
- style: str, CSS-like style for column
379
"""
380
381
def to_container(container):
382
"""
383
Convert value to Container.
384
385
Parameters:
386
- container: Container, Window, or UIControl
387
388
Returns:
389
Container instance
390
"""
391
392
def to_window(container):
393
"""
394
Convert value to Window.
395
396
Parameters:
397
- container: Container, Window, or UIControl
398
399
Returns:
400
Window instance
401
"""
402
403
def is_container(obj):
404
"""
405
Check if object is a Container.
406
407
Parameters:
408
- obj: Object to check
409
410
Returns:
411
bool: True if object is Container
412
"""
413
414
# Type alias for container values
415
AnyContainer = Union[Container, UIControl]
416
```
417
418
### Alignment Enums
419
420
Enumeration classes for specifying alignment options.
421
422
```python { .api }
423
class HorizontalAlign(Enum):
424
"""Horizontal alignment options."""
425
LEFT = "left"
426
CENTER = "center"
427
RIGHT = "right"
428
JUSTIFY = "justify"
429
430
class VerticalAlign(Enum):
431
"""Vertical alignment options."""
432
TOP = "top"
433
CENTER = "center"
434
BOTTOM = "bottom"
435
JUSTIFY = "justify"
436
437
class WindowAlign(Enum):
438
"""Window content alignment options."""
439
LEFT = "left"
440
RIGHT = "right"
441
CENTER = "center"
442
```
443
444
### UI Controls
445
446
Controls are the components that actually render content within windows.
447
448
```python { .api }
449
class UIControl:
450
"""Abstract base class for UI controls."""
451
452
def create_content(self, width, height):
453
"""
454
Create content for rendering.
455
456
Parameters:
457
- width: int, available width
458
- height: int, available height
459
460
Returns:
461
UIContent instance
462
"""
463
464
class UIContent:
465
def __init__(
466
self,
467
get_line=None,
468
line_count=0,
469
cursor_position=None,
470
menu_position=None,
471
show_cursor=True
472
):
473
"""
474
UI content data for rendering.
475
476
Parameters:
477
- get_line: Function to get line content by index
478
- line_count: int, total number of lines
479
- cursor_position: Point, cursor position
480
- menu_position: Point, menu position
481
- show_cursor: bool, whether to show cursor
482
"""
483
484
class FormattedTextControl(UIControl):
485
def __init__(
486
self,
487
text="",
488
style="",
489
focusable=False,
490
key_bindings=None,
491
show_cursor=True
492
):
493
"""
494
Control for displaying formatted text.
495
496
Parameters:
497
- text: AnyFormattedText, text content to display
498
- style: str, CSS-like style
499
- focusable: bool, whether control can receive focus
500
- key_bindings: KeyBindings for control
501
- show_cursor: bool, whether to show cursor
502
"""
503
504
class BufferControl(UIControl):
505
def __init__(
506
self,
507
buffer=None,
508
lexer=None,
509
input_processors=None,
510
include_default_input_processors=True,
511
search_buffer_control=None,
512
menu_position=None,
513
focusable=True,
514
focus_on_click=False,
515
key_bindings=None,
516
get_cursor_position=None
517
):
518
"""
519
Control for displaying and editing buffer content.
520
521
Parameters:
522
- buffer: Buffer instance to display/edit
523
- lexer: Lexer for syntax highlighting
524
- input_processors: List of InputProcessor instances
525
- include_default_input_processors: bool, include default processors
526
- search_buffer_control: SearchBufferControl for search highlighting
527
- menu_position: Function returning menu position
528
- focusable: bool, whether control can receive focus
529
- focus_on_click: bool, focus on mouse click
530
- key_bindings: KeyBindings for control
531
- get_cursor_position: Function returning cursor position
532
"""
533
534
class SearchBufferControl(BufferControl):
535
def __init__(
536
self,
537
buffer=None,
538
input_processors=None,
539
lexer=None,
540
ignore_case=False
541
):
542
"""
543
Control for search buffer with highlighting.
544
545
Parameters:
546
- buffer: Buffer instance for search text
547
- input_processors: List of InputProcessor instances
548
- lexer: Lexer for syntax highlighting
549
- ignore_case: bool, case-insensitive search
550
"""
551
552
class DummyControl(UIControl):
553
def __init__(self):
554
"""Dummy control for testing and placeholders."""
555
```
556
557
### Scroll Configuration
558
559
Classes for configuring scrolling behavior.
560
561
```python { .api }
562
class ScrollOffsets:
563
def __init__(self, top=0, bottom=0, left=0, right=0):
564
"""
565
Scroll offset configuration.
566
567
Parameters:
568
- top: int, lines to keep visible above cursor
569
- bottom: int, lines to keep visible below cursor
570
- left: int, columns to keep visible left of cursor
571
- right: int, columns to keep visible right of cursor
572
"""
573
```
574
575
## Usage Examples
576
577
### Basic Layout Structure
578
579
```python
580
from prompt_toolkit.application import Application
581
from prompt_toolkit.layout import Layout
582
from prompt_toolkit.layout.containers import HSplit, VSplit, Window
583
from prompt_toolkit.layout.controls import FormattedTextControl
584
from prompt_toolkit.key_binding import KeyBindings
585
586
# Create layout with horizontal and vertical splits
587
layout = Layout(
588
HSplit([
589
# Header
590
Window(
591
FormattedTextControl('Header Area'),
592
height=1,
593
style='class:header'
594
),
595
# Main content area with sidebar
596
VSplit([
597
# Sidebar
598
Window(
599
FormattedTextControl('Sidebar'),
600
width=20,
601
style='class:sidebar'
602
),
603
# Main content
604
Window(FormattedTextControl('Main Content Area')),
605
]),
606
# Footer
607
Window(
608
FormattedTextControl('Footer Area'),
609
height=1,
610
style='class:footer'
611
)
612
])
613
)
614
615
# Key bindings
616
bindings = KeyBindings()
617
618
@bindings.add('c-c')
619
def exit_app(event):
620
event.app.exit()
621
622
# Create and run application
623
app = Application(
624
layout=layout,
625
key_bindings=bindings,
626
full_screen=True
627
)
628
629
app.run()
630
```
631
632
### Dynamic Layout with Conditions
633
634
```python
635
from prompt_toolkit.layout.containers import ConditionalContainer, HSplit, Window
636
from prompt_toolkit.layout.controls import FormattedTextControl
637
from prompt_toolkit.filters import Condition
638
639
# Create condition for showing/hiding sidebar
640
show_sidebar = Condition(lambda: True) # Can be dynamic
641
642
layout = Layout(
643
HSplit([
644
VSplit([
645
# Conditional sidebar
646
ConditionalContainer(
647
Window(
648
FormattedTextControl('Sidebar Content'),
649
width=20
650
),
651
filter=show_sidebar
652
),
653
# Main content
654
Window(FormattedTextControl('Main Content'))
655
])
656
])
657
)
658
```
659
660
### Floating Elements
661
662
```python
663
from prompt_toolkit.layout.containers import FloatContainer, Float, HSplit, Window
664
from prompt_toolkit.layout.controls import FormattedTextControl
665
666
# Create layout with floating dialog
667
layout = Layout(
668
FloatContainer(
669
# Background content
670
HSplit([
671
Window(FormattedTextControl('Background Content')),
672
]),
673
# Floating elements
674
floats=[
675
Float(
676
Window(
677
FormattedTextControl('Floating Dialog'),
678
width=40,
679
height=10
680
),
681
left=10,
682
top=5
683
)
684
]
685
)
686
)
687
```
688
689
### Scrollable Content
690
691
```python
692
from prompt_toolkit.layout.containers import ScrollablePane, HSplit, Window
693
from prompt_toolkit.layout.controls import FormattedTextControl
694
695
# Create large content that needs scrolling
696
large_content = '\n'.join([f'Line {i}' for i in range(100)])
697
698
layout = Layout(
699
ScrollablePane(
700
HSplit([
701
Window(FormattedTextControl(large_content))
702
]),
703
show_scrollbar=True
704
)
705
)
706
```
707
708
### Buffer Control with Editing
709
710
```python
711
from prompt_toolkit.buffer import Buffer
712
from prompt_toolkit.layout import Layout
713
from prompt_toolkit.layout.containers import HSplit, Window
714
from prompt_toolkit.layout.controls import BufferControl
715
from prompt_toolkit.lexers import PygmentsLexer
716
from pygments.lexers import PythonLexer
717
718
# Create buffer with Python content
719
buffer = Buffer(
720
document=Document('def hello():\n print("Hello, World!")'),
721
multiline=True
722
)
723
724
# Create buffer control with syntax highlighting
725
buffer_control = BufferControl(
726
buffer=buffer,
727
lexer=PygmentsLexer(PythonLexer)
728
)
729
730
layout = Layout(
731
HSplit([
732
Window(buffer_control),
733
Window(
734
FormattedTextControl('Press Ctrl-C to exit'),
735
height=1
736
)
737
])
738
)
739
```
740
741
### Margins and Decorations
742
743
```python
744
from prompt_toolkit.layout.margins import NumberedMargin, ScrollbarMargin
745
from prompt_toolkit.layout.containers import HSplit, Window
746
from prompt_toolkit.layout.controls import BufferControl
747
from prompt_toolkit.buffer import Buffer
748
749
# Create buffer
750
buffer = Buffer(multiline=True)
751
752
# Window with line numbers and scrollbar
753
layout = Layout(
754
HSplit([
755
Window(
756
BufferControl(buffer),
757
left_margins=[NumberedMargin()],
758
right_margins=[ScrollbarMargin()],
759
wrap_lines=True
760
)
761
])
762
)
763
```