| """ |
| Collection of reusable components for building full screen applications. |
| """ |
| from __future__ import annotations |
|
|
| from typing import Sequence |
|
|
| from prompt_toolkit.filters import has_completions, has_focus |
| from prompt_toolkit.formatted_text import AnyFormattedText |
| from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous |
| from prompt_toolkit.key_binding.key_bindings import KeyBindings |
| from prompt_toolkit.layout.containers import ( |
| AnyContainer, |
| DynamicContainer, |
| HSplit, |
| VSplit, |
| ) |
| from prompt_toolkit.layout.dimension import AnyDimension |
| from prompt_toolkit.layout.dimension import Dimension as D |
|
|
| from .base import Box, Button, Frame, Shadow |
|
|
| __all__ = [ |
| "Dialog", |
| ] |
|
|
|
|
| class Dialog: |
| """ |
| Simple dialog window. This is the base for input dialogs, message dialogs |
| and confirmation dialogs. |
| |
| Changing the title and body of the dialog is possible at runtime by |
| assigning to the `body` and `title` attributes of this class. |
| |
| :param body: Child container object. |
| :param title: Text to be displayed in the heading of the dialog. |
| :param buttons: A list of `Button` widgets, displayed at the bottom. |
| """ |
|
|
| def __init__( |
| self, |
| body: AnyContainer, |
| title: AnyFormattedText = "", |
| buttons: Sequence[Button] | None = None, |
| modal: bool = True, |
| width: AnyDimension = None, |
| with_background: bool = False, |
| ) -> None: |
| self.body = body |
| self.title = title |
|
|
| buttons = buttons or [] |
|
|
| |
| buttons_kb = KeyBindings() |
| if len(buttons) > 1: |
| first_selected = has_focus(buttons[0]) |
| last_selected = has_focus(buttons[-1]) |
|
|
| buttons_kb.add("left", filter=~first_selected)(focus_previous) |
| buttons_kb.add("right", filter=~last_selected)(focus_next) |
|
|
| frame_body: AnyContainer |
| if buttons: |
| frame_body = HSplit( |
| [ |
| |
| Box( |
| body=DynamicContainer(lambda: self.body), |
| padding=D(preferred=1, max=1), |
| padding_bottom=0, |
| ), |
| |
| Box( |
| body=VSplit(buttons, padding=1, key_bindings=buttons_kb), |
| height=D(min=1, max=3, preferred=3), |
| ), |
| ] |
| ) |
| else: |
| frame_body = body |
|
|
| |
| kb = KeyBindings() |
| kb.add("tab", filter=~has_completions)(focus_next) |
| kb.add("s-tab", filter=~has_completions)(focus_previous) |
|
|
| frame = Shadow( |
| body=Frame( |
| title=lambda: self.title, |
| body=frame_body, |
| style="class:dialog.body", |
| width=(None if with_background is None else width), |
| key_bindings=kb, |
| modal=modal, |
| ) |
| ) |
|
|
| self.container: Box | Shadow |
| if with_background: |
| self.container = Box(body=frame, style="class:dialog", width=width) |
| else: |
| self.container = frame |
|
|
| def __pt_container__(self) -> AnyContainer: |
| return self.container |
|
|