summaryrefslogtreecommitdiffstats
path: root/src/prompt_toolkit/widgets/dialogs.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/prompt_toolkit/widgets/dialogs.py')
-rw-r--r--src/prompt_toolkit/widgets/dialogs.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/prompt_toolkit/widgets/dialogs.py b/src/prompt_toolkit/widgets/dialogs.py
new file mode 100644
index 0000000..c47c15b
--- /dev/null
+++ b/src/prompt_toolkit/widgets/dialogs.py
@@ -0,0 +1,107 @@
+"""
+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 []
+
+ # When a button is selected, handle left/right key bindings.
+ 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(
+ [
+ # Add optional padding around the body.
+ Box(
+ body=DynamicContainer(lambda: self.body),
+ padding=D(preferred=1, max=1),
+ padding_bottom=0,
+ ),
+ # The buttons.
+ Box(
+ body=VSplit(buttons, padding=1, key_bindings=buttons_kb),
+ height=D(min=1, max=3, preferred=3),
+ ),
+ ]
+ )
+ else:
+ frame_body = body
+
+ # Key bindings for whole dialog.
+ 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