Beispiel #1
0
    def __init__(self) -> None:
        self._percentage = 60

        self.label = Label('60%')
        self.container = FloatContainer(
            content=Window(height=1),
            floats=[
                # We first draw the label, then the actual progress bar.  Right
                # now, this is the only way to have the colors of the progress
                # bar appear on top of the label. The problem is that our label
                # can't be part of any `Window` below.
                Float(content=self.label, top=0, bottom=0),
                Float(left=0,
                      top=0,
                      right=0,
                      bottom=0,
                      content=VSplit([
                          Window(
                              style='class:progress-bar.used',
                              width=lambda: D(weight=int(self._percentage))),
                          Window(style='class:progress-bar',
                                 width=lambda: D(weight=int(100 - self.
                                                            _percentage))),
                      ])),
            ])
Beispiel #2
0
    def __init__(self, title='', label_text='', completer=None):
        self.future = Future()

        def accept_text(buf):
            get_app().layout.focus(ok_button)
            buf.complete_state = None
            return True

        def accept():
            self.future.set_result(self.text_area.text)

        def cancel():
            self.future.set_result(None)

        self.text_area = TextArea(completer=completer,
                                  multiline=False,
                                  width=D(preferred=40),
                                  accept_handler=accept_text)

        ok_button = Button(text='OK', handler=accept)
        cancel_button = Button(text='Cancel', handler=cancel)

        self.dialog = Dialog(title=title,
                             body=HSplit(
                                 [Label(text=label_text), self.text_area]),
                             buttons=[ok_button, cancel_button],
                             width=D(preferred=80),
                             modal=True)
Beispiel #3
0
    def get_width(self, progress_bar: 'ProgressBar') -> AnyDimension:
        if self.width:
            return self.width

        all_labels = [self._add_suffix(c.label) for c in progress_bar.counters]
        if all_labels:
            max_widths = max(fragment_list_width(l) for l in all_labels)
            return D(preferred=max_widths, max=max_widths)
        else:
            return D()
Beispiel #4
0
    def __init__(self,
                 body: AnyContainer,
                 title: AnyFormattedText = '',
                 buttons: Optional[Sequence[Button]] = 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: Union[Box, Shadow]
        if with_background:
            self.container = Box(body=frame, style='class:dialog', width=width)
        else:
            self.container = frame
Beispiel #5
0
 def get_width() -> AnyDimension:
     if width is None:
         text_fragments = to_formatted_text(self.text)
         text = fragment_list_to_text(text_fragments)
         if text:
             longest_line = max(
                 get_cwidth(line) for line in text.splitlines())
         else:
             return D(preferred=0)
         return D(preferred=longest_line)
     else:
         return width
def progress_dialog(title: AnyFormattedText = '',
                    text: AnyFormattedText = '',
                    run_callback: Callable[
                        [Callable[[int], None], Callable[[str], None]],
                        None] = (lambda *a: None),
                    style: Optional[BaseStyle] = None) -> Application[None]:
    """
    :param run_callback: A function that receives as input a `set_percentage`
        function and it does the work.
    """
    loop = get_event_loop()
    progressbar = ProgressBar()
    text_area = TextArea(
        focusable=False,

        # Prefer this text area as big as possible, to avoid having a window
        # that keeps resizing when we add text to it.
        height=D(preferred=10**10))

    dialog = Dialog(body=HSplit([
        Box(Label(text=text)),
        Box(text_area, padding=D.exact(1)),
        progressbar,
    ]),
                    title=title,
                    with_background=True)
    app = _create_app(dialog, style)

    def set_percentage(value: int) -> None:
        progressbar.percentage = int(value)
        app.invalidate()

    def log_text(text: str) -> None:
        loop.call_soon_threadsafe(text_area.buffer.insert_text, text)
        app.invalidate()

    # Run the callback in the executor. When done, set a return value for the
    # UI, so that it quits.
    def start() -> None:
        try:
            run_callback(set_percentage, log_text)
        finally:
            app.exit()

    def pre_run() -> None:
        run_in_executor_with_context(start)

    app.pre_run_callables.append(pre_run)

    return app
Beispiel #7
0
    def __init__(self, title, text):
        self.future = Future()

        def set_done():
            self.future.set_result(None)

        ok_button = Button(text='OK', handler=(lambda: set_done()))

        self.dialog = Dialog(title=title,
                             body=HSplit([
                                 Label(text=text),
                             ]),
                             buttons=[ok_button],
                             width=D(preferred=80),
                             modal=True)
Beispiel #8
0
    def __init__(self,
                 body: AnyContainer,
                 padding: AnyDimension = None,
                 padding_left: AnyDimension = None,
                 padding_right: AnyDimension = None,
                 padding_top: AnyDimension = None,
                 padding_bottom: AnyDimension = None,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 style: str = '',
                 char: Union[None, str, Callable[[], str]] = None,
                 modal: bool = False,
                 key_bindings: Optional[KeyBindings] = None) -> None:

        if padding is None:
            padding = D(preferred=0)

        def get(value: AnyDimension) -> D:
            if value is None:
                value = padding
            return to_dimension(value)

        self.padding_left = get(padding_left)
        self.padding_right = get(padding_right)
        self.padding_top = get(padding_top)
        self.padding_bottom = get(padding_bottom)
        self.body = body

        self.container = HSplit([
            Window(height=self.padding_top, char=char),
            VSplit([
                Window(width=self.padding_left, char=char),
                body,
                Window(width=self.padding_right, char=char),
            ]),
            Window(height=self.padding_bottom, char=char),
        ],
                                width=width,
                                height=height,
                                style=style,
                                modal=modal,
                                key_bindings=None)
def input_dialog(title: AnyFormattedText = '',
                 text: AnyFormattedText = '',
                 ok_text: str = 'OK',
                 cancel_text: str = 'Cancel',
                 completer: Optional[Completer] = None,
                 password: FilterOrBool = False,
                 style: Optional[BaseStyle] = None) -> Application[str]:
    """
    Display a text input box.
    Return the given text, or None when cancelled.
    """
    def accept(buf: Buffer) -> bool:
        get_app().layout.focus(ok_button)
        return True  # Keep text.

    def ok_handler() -> None:
        get_app().exit(result=textfield.text)

    ok_button = Button(text=ok_text, handler=ok_handler)
    cancel_button = Button(text=cancel_text, handler=_return_none)

    textfield = TextArea(multiline=False,
                         password=password,
                         completer=completer,
                         accept_handler=accept)

    dialog = Dialog(title=title,
                    body=HSplit([
                        Label(text=text, dont_extend_height=True),
                        textfield,
                    ],
                                padding=D(preferred=1, max=1)),
                    buttons=[ok_button, cancel_button],
                    with_background=True)

    return _create_app(dialog, style)
Beispiel #10
0
 def get_width(self, progress_bar: 'ProgressBar') -> AnyDimension:
     return D()
Beispiel #11
0
 def get_width(self, progress_bar: 'ProgressBar') -> AnyDimension:
     all_lengths = [len('{0:>3}'.format(c.total or '?')) for c in progress_bar.counters]
     all_lengths.append(1)
     return D.exact(max(all_lengths) * 2 + 1)
Beispiel #12
0
    def __enter__(self) -> 'ProgressBar':
        # Create UI Application.
        title_toolbar = ConditionalContainer(
            Window(FormattedTextControl(lambda: self.title), height=1, style='class:progressbar,title'),
            filter=Condition(lambda: self.title is not None))

        bottom_toolbar = ConditionalContainer(
            Window(FormattedTextControl(lambda: self.bottom_toolbar,
                                        style='class:bottom-toolbar.text'),
                   style='class:bottom-toolbar',
                   height=1),
            filter=~is_done & renderer_height_is_known &
                Condition(lambda: self.bottom_toolbar is not None))

        def width_for_formatter(formatter: Formatter) -> AnyDimension:
            # Needs to be passed as callable (partial) to the 'width'
            # parameter, because we want to call it on every resize.
            return formatter.get_width(progress_bar=self)

        progress_controls = [
            Window(
                content=_ProgressControl(self, f),
                width=functools.partial(width_for_formatter, f))
            for f in self.formatters
        ]

        self.app: Application[None] = Application(
            min_redraw_interval=.05,
            layout=Layout(HSplit([
                title_toolbar,
                VSplit(progress_controls,
                       height=lambda: D(
                           preferred=len(self.counters),
                           max=len(self.counters))),
                Window(),
                bottom_toolbar,
            ])),
            style=self.style,
            key_bindings=self.key_bindings,
            refresh_interval=.3,
            color_depth=self.color_depth,
            output=self.output,
            input=self.input)

        # Run application in different thread.
        def run() -> None:
            set_event_loop(self._app_loop)
            try:
                self.app.run()
            except BaseException as e:
                traceback.print_exc()
                print(e)

        ctx: contextvars.Context = contextvars.copy_context()

        self._thread = threading.Thread(target=ctx.run, args=(run, ))
        self._thread.start()

        # Attach WINCH signal handler in main thread.
        # (Interrupt that we receive during resize events.)
        self._has_sigwinch = hasattr(signal, 'SIGWINCH') and in_main_thread()
        if self._has_sigwinch:
            self._previous_winch_handler = signal.getsignal(signal.SIGWINCH)
            self._loop.add_signal_handler(signal.SIGWINCH, self.invalidate)

        return self
])

animal_completer = WordCompleter([
    'alligator', 'ant', 'ape', 'bat', 'bear', 'beaver', 'bee', 'bison',
    'butterfly', 'cat', 'chicken', 'crocodile', 'dinosaur', 'dog', 'dolphin',
    'dove', 'duck', 'eagle', 'elephant', 'fish', 'goat', 'gorilla', 'kangaroo',
    'leopard', 'lion', 'mouse', 'rabbit', 'rat', 'snake', 'spider', 'turkey',
    'turtle', ], ignore_case=True)

root_container = HSplit([
    VSplit([
        Frame(body=Label(text='Left frame\ncontent')),
        Dialog(title='The custom window',
               body=Label('hello\ntest')),
        textfield,
    ], height=D()),
    VSplit([
        Frame(body=ProgressBar(),
              title='Progress bar'),
        Frame(title='Checkbox list',
              body=HSplit([
                  checkbox1,
                  checkbox2,
              ])),
        Frame(title='Radio list', body=radios),
    ], padding=1),
    Box(
        body=VSplit([
            yes_button,
            no_button,
        ], align='CENTER', padding=3),