1""" 
    2Collection of reusable components for building full screen applications. 
    3""" 
    4 
    5from __future__ import annotations 
    6 
    7from typing import Sequence 
    8 
    9from prompt_toolkit.filters import has_completions, has_focus 
    10from prompt_toolkit.formatted_text import AnyFormattedText 
    11from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous 
    12from prompt_toolkit.key_binding.key_bindings import KeyBindings 
    13from prompt_toolkit.layout.containers import ( 
    14    AnyContainer, 
    15    DynamicContainer, 
    16    HSplit, 
    17    VSplit, 
    18) 
    19from prompt_toolkit.layout.dimension import AnyDimension 
    20from prompt_toolkit.layout.dimension import Dimension as D 
    21 
    22from .base import Box, Button, Frame, Shadow 
    23 
    24__all__ = [ 
    25    "Dialog", 
    26] 
    27 
    28 
    29class Dialog: 
    30    """ 
    31    Simple dialog window. This is the base for input dialogs, message dialogs 
    32    and confirmation dialogs. 
    33 
    34    Changing the title and body of the dialog is possible at runtime by 
    35    assigning to the `body` and `title` attributes of this class. 
    36 
    37    :param body: Child container object. 
    38    :param title: Text to be displayed in the heading of the dialog. 
    39    :param buttons: A list of `Button` widgets, displayed at the bottom. 
    40    """ 
    41 
    42    def __init__( 
    43        self, 
    44        body: AnyContainer, 
    45        title: AnyFormattedText = "", 
    46        buttons: Sequence[Button] | None = None, 
    47        modal: bool = True, 
    48        width: AnyDimension = None, 
    49        with_background: bool = False, 
    50    ) -> None: 
    51        self.body = body 
    52        self.title = title 
    53 
    54        buttons = buttons or [] 
    55 
    56        # When a button is selected, handle left/right key bindings. 
    57        buttons_kb = KeyBindings() 
    58        if len(buttons) > 1: 
    59            first_selected = has_focus(buttons[0]) 
    60            last_selected = has_focus(buttons[-1]) 
    61 
    62            buttons_kb.add("left", filter=~first_selected)(focus_previous) 
    63            buttons_kb.add("right", filter=~last_selected)(focus_next) 
    64 
    65        frame_body: AnyContainer 
    66        if buttons: 
    67            frame_body = HSplit( 
    68                [ 
    69                    # Add optional padding around the body. 
    70                    Box( 
    71                        body=DynamicContainer(lambda: self.body), 
    72                        padding=D(preferred=1, max=1), 
    73                        padding_bottom=0, 
    74                    ), 
    75                    # The buttons. 
    76                    Box( 
    77                        body=VSplit(buttons, padding=1, key_bindings=buttons_kb), 
    78                        height=D(min=1, max=3, preferred=3), 
    79                    ), 
    80                ] 
    81            ) 
    82        else: 
    83            frame_body = body 
    84 
    85        # Key bindings for whole dialog. 
    86        kb = KeyBindings() 
    87        kb.add("tab", filter=~has_completions)(focus_next) 
    88        kb.add("s-tab", filter=~has_completions)(focus_previous) 
    89 
    90        frame = Shadow( 
    91            body=Frame( 
    92                title=lambda: self.title, 
    93                body=frame_body, 
    94                style="class:dialog.body", 
    95                width=(None if with_background is None else width), 
    96                key_bindings=kb, 
    97                modal=modal, 
    98            ) 
    99        ) 
    100 
    101        self.container: Box | Shadow 
    102        if with_background: 
    103            self.container = Box(body=frame, style="class:dialog", width=width) 
    104        else: 
    105            self.container = frame 
    106 
    107    def __pt_container__(self) -> AnyContainer: 
    108        return self.container