def print_container(container, file=None):
    """
    Print any layout to the output in a non-interactive way.

    Example usage::

        from prompt_toolkit.widgets import Frame, TextArea
        print_container(
            Frame(TextArea(text='Hello world!')))
    """
    if file:
        output = create_output(stdout=file)
    else:
        output = get_default_output()

    def exit_immediately():
        # Use `call_from_executor` to exit "soon", so that we still render one
        # initial time, before exiting the application.
        get_event_loop().call_from_executor(
             lambda: app.exit())

    app = Application(
        layout=Layout(container=container),
        output=output,
        input=DummyInput())
    app.run(pre_run=exit_immediately)
예제 #2
0
파일: view.py 프로젝트: dagraham/etm-mv
def main(etmdir=""):
    global item, settings, ampm, style, etmstyle, application
    ampm = settings['ampm']
    terminal_style = settings['style']
    if terminal_style == "dark": 
        style = dark_style
        etmstyle = dark_etmstyle
    else:
        style = light_style
        etmstyle = light_etmstyle
    agenda_view()

    application = Application(
        layout=Layout(
            root_container,
            focused_element=text_area,
        ),
        key_bindings=bindings,
        enable_page_navigation_bindings=True,
        mouse_support=True,
        style=style,
        full_screen=True)

    # Tell prompt_toolkit to use asyncio.
    use_asyncio_event_loop()
    # Run application async.
    loop = get_event_loop()
    loop.call_later(0, event_handler, loop)
    loop.run_until_complete(
        application.run_async().to_asyncio_future())
예제 #3
0
def build_application(container: Container, keys: KeyBindings) -> Application:
    return Application(
        layout=Layout(container),
        key_bindings=keys,
        full_screen=True,
        style=Style([
            ("header", "bg:#005fff fg:black")
        ])
    )
예제 #4
0
파일: pager.py 프로젝트: mm4nn/pypager
    def __init__(self,
                 vi_mode=False,
                 style=None,
                 search_text=None,
                 titlebar_tokens=None):
        assert isinstance(vi_mode, bool)
        assert style is None or isinstance(style, Style)

        self.sources = []
        self.current_source = 0  # Index in `self.sources`.
        self.vi_mode = vi_mode
        self.highlight_search = True
        self.in_colon_mode = False
        self.message = None
        self.displaying_help = False
        self.search_text = search_text
        self.display_titlebar = bool(titlebar_tokens)
        self.titlebar_tokens = titlebar_tokens or []

        # When this is True, always make sure that the cursor goes to the
        # bottom of the visible content. This is similar to 'tail -f'.
        self.forward_forever = False

        # Status information for all sources. Source -> _SourceInfo.
        # (Remember this info as long as the Source object exists.)
        self.source_info = weakref.WeakKeyDictionary()

        # Create prompt_toolkit stuff.
        self.buffers = BufferMapping({})

        def open_file(cli, buff):
            # Open file.
            self.open_file(buff.text)

            # Focus main buffer again.
            self.buffers.focus(cli, self.source_info[self.source].buffer_name)
            buff.reset()

        self.buffers['EXAMINE'] = Buffer(
            # Buffer for the 'Examine:' input.
            completer=PathCompleter(expanduser=True),
            accept_action=AcceptAction(open_file))

        self.layout = Layout(self)

        registry = create_key_bindings(self)
        self.application = Application(layout=self.layout.container,
                                       buffers=self.buffers,
                                       key_bindings_registry=registry,
                                       style=style or create_style(),
                                       mouse_support=True,
                                       on_render=self._on_render,
                                       use_alternate_screen=True,
                                       on_initialize=self._on_cli_initialize)

        self.cli = None
        self.eventloop = None
예제 #5
0
파일: main.py 프로젝트: jlmitch5/druid
async def shell():
    global crow
    input_field = TextArea(height=1,
                           prompt='> ',
                           style='class:input-field',
                           multiline=False,
                           wrap_lines=False)
    captures = VSplit([capture1, capture2])
    container = HSplit([
        captures, output_field,
        Window(height=1,
               char='/',
               style='class:line',
               content=FormattedTextControl(text='druid////'),
               align=WindowAlign.RIGHT), input_field
    ])

    def cwrite(xs):
        global crow
        try:
            crow.write(xs)
        except:
            crowreconnect()

    def accept(buff):
        try:
            myprint('\n> ' + input_field.text + '\n')
            druidparser(cwrite, input_field.text)
        except ValueError as err:
            print(err)
            get_app().exit()

    input_field.accept_handler = accept

    kb = KeyBindings()

    @kb.add('c-c', eager=True)
    @kb.add('c-q', eager=True)
    def _(event):
        event.app.exit()

    style = Style([
        ('capture-field', '#747369'),
        ('output-field', '#d3d0c8'),
        ('input-field', '#f2f0ec'),
        ('line', '#747369'),
    ])

    application = Application(
        layout=Layout(container, focused_element=input_field),
        key_bindings=kb,
        style=style,
        mouse_support=True,
        full_screen=True,
    )
    result = await application.run_async()
예제 #6
0
def show_error_dialog(messages):
    texts = []
    for message in messages:
        texts.append(
            Label(message, style='class:error', dont_extend_height=True))
    dialog = Dialog(title='Some inputs are invalid',
                    body=HSplit(texts, padding=1),
                    buttons=[
                        Button(text='Ok', handler=lambda: get_app().exit()),
                    ],
                    with_background=True)

    app = Application(layout=Layout(dialog),
                      key_bindings=load_key_bindings(),
                      mouse_support=True,
                      style=for_dialog(),
                      full_screen=True)

    app.run()
예제 #7
0
def set_dummy_app():
    """
    Return a context manager that makes sure that this dummy application is
    active. This is important, because we need an `Application` with
    `is_done=False` flag, otherwise no keys will be processed.
    """
    app = Application(layout=Layout(Window()),
                      output=DummyOutput(),
                      input=create_pipe_input())
    return set_app(app)
예제 #8
0
 def run(self):
     """Start the python_prompt application with ctui's default settings"""
     Path(self._project_folder).mkdir(parents=True, exist_ok=True)
     if Path(self._project_path).exists(
     ):  # start with clean default project at each start
         Path.unlink(Path(self._project_path))
     self._init_db()
     self.layout = CtuiLayout(self)
     self.style = CtuiStyle()
     self._mode = 'term_ui'  # For future headless mode
     layout = Layout(self.layout.root_container,
                     focused_element=self.layout.input_field)
     self.app = Application(layout=layout,
                            key_bindings=get_key_bindings(self),
                            style=self.style.dark_theme,
                            enable_page_navigation_bindings=False,
                            mouse_support=True,
                            full_screen=True)
     self.app.run()
예제 #9
0
def mock_app(mocker):
    app = Application(
        input=create_pipe_input(),
        output=DummyOutput(),
    )
    mocker.patch('upsies.uis.tui.tui.TUI._make_app', Mock(return_value=app))
    mocker.patch('upsies.uis.tui.tui.TUI._jobs_container',
                 Mock(children=[]),
                 create=True)
    mocker.patch('upsies.uis.tui.tui.TUI._layout', Mock(), create=True)
예제 #10
0
    def pager(self, html, end="\n"):
        """
        Construct pager using prompt_toolkit
        """

        my_buffer = Buffer()
        my_window = Window(
            BufferControl(
                buffer=my_buffer,
                focusable=True,
                preview_search=True,
                input_processors=[FormatText()],
            ))

        my_buffer.text = html
        my_buffer.read_only = to_filter(True)

        root_container = HSplit([
            my_window,
        ])

        bindings = KeyBindings()

        @bindings.add("c-c")
        @bindings.add("q")
        def _(event):
            "Quit."
            event.app.exit()

        application = Application(
            layout=Layout(
                root_container,
                focused_element=my_window,
            ),
            key_bindings=bindings,
            enable_page_navigation_bindings=True,
            mouse_support=True,
            full_screen=True,
        )

        application.run()
        super().msg(html=html, end=end)
예제 #11
0
    def __init__(self, configuration, exchange):
        self._project_name = configuration.project.name
        self._local_dir = configuration.local_dir
        self._remote_directory = None
        self._exchange = exchange
        self._loop = get_event_loop()

        self._current_screen = None
        self.root_container = HSplit([Window()])
        self.layout = Layout(container=self.root_container)
        self._render()

        self.bindings = self._create_bindings()

        self.application = Application(layout=self.layout,
                                       key_bindings=self.bindings,
                                       full_screen=True)

        self._exchange.subscribe(Messages.REMOTE_DIRECTORY_SET,
                                 self._set_remote_dir)
예제 #12
0
def repl(parser, interpreter, style_name='default'):
    registry = load_key_bindings()

    @registry.add_binding(Keys.Escape, Keys.Enter)  # meta-enter/alt-enter
    def _(event):
        '''Evaluate the buffer
        '''
        code = buffers[DEFAULT_BUFFER].text
        try:
            ast = parser.parse(code)
        except (UnexpectedToken, UnexpectedInput) as e:
            toolbar_value = str(e)
            return

        try:
            start_eval_time = time.time()
            retval = interpreter.eval(ast)
        except Exception as e:
            toolbar_value = "Error: %s" % e.args
            return
        else:
            buffers['RESULT'].text = str(retval)
            toolbar_value = "Time: {:0.4f}, Value: {}".format(
                time.time() - start_eval_time, str(retval))

    @registry.add_binding(Keys.ControlC, eager=True)
    @registry.add_binding(Keys.ControlQ, eager=True)
    def _(event):
        '''Exit the REPL
        '''
        event.cli.set_return_value(None)

    buffers = {
        DEFAULT_BUFFER: Buffer(is_multiline=True),
        'RESULT': Buffer(is_multiline=True),
    }
    style = style_from_pygments(get_style_by_name(style_name))

    application = Application(layout=layout,
                              buffers=buffers,
                              mouse_support=True,
                              style=style,
                              use_alternate_screen=True,
                              key_bindings_registry=registry)

    eventloop = create_eventloop()

    try:
        cli = CommandLineInterface(application=application,
                                   eventloop=eventloop)
        cli.run()

    finally:
        eventloop.close()
예제 #13
0
def run():
    content = []
    for line in iter(sys.stdin.readline, ""):
        content.append([line.strip(), False])

    chk = CheckboxList(content)

    root_container = chk
    layout = Layout(root_container)
    kb = KeyBindings()

    @kb.add('q')
    def exit_(event):
        event.app.exit()

    app = Application(input=create_input(sys.stdout),
                      key_bindings=kb,
                      layout=layout,
                      full_screen=True)
    app.run()
예제 #14
0
def prompt(
    title: str, options: Sequence[Tuple[RadioListType,
                                        AnyFormattedText]]) -> RadioListType:
    control = RadioList(options_to_html(options))

    application: Application[None] = Application(
        layout=Layout(HSplit([Label(HTML(title)), control])),
        mouse_support=False,
        full_screen=False,
    )

    return cast(RadioListType, application.run())
예제 #15
0
    def __init__(self,
                 input_handler: Callable,
                 bindings: KeyBindings,
                 completer: Completer):
        use_asyncio_event_loop()
        self.input_field = create_input_field(completer=completer)
        self.output_field = create_output_field()
        self.log_field = create_log_field()
        self.layout = generate_layout(self.input_field, self.output_field, self.log_field)

        self.bindings = bindings
        self.input_handler = input_handler
        self.input_field.accept_handler = self.accept
        self.app = Application(layout=self.layout, full_screen=True, key_bindings=self.bindings, style=load_style(),
                               mouse_support=True, clipboard=PyperclipClipboard())

        # settings
        self.prompt_text = ">>> "
        self.pending_input = None
        self.input_event = None
        self.hide_input = False
예제 #16
0
def test_keybindings():
    from prompt_toolkit.application import Application
    from prompt_toolkit.layout import Layout
    from prompt_toolkit.layout.containers import FormattedTextControl, Window
    textarea = FormattedTextControl(
        text='Press "a b c" to quit.',
        show_cursor=False,
    )

    kb = KeyBindings()

    @kb.add('a', 'b', 'c')
    def _(event):
        event.app.exit()

    @kb.add('<any>')
    def _(event):
        textarea.text += "\n{}".format(event.key_sequence)

    app = Application(layout=Layout(Window(textarea)), key_bindings=kb)
    app.run()
예제 #17
0
    def __init__(self, use_theme):
        self.statusbar = Window(height=1,
                                char='/',
                                style='class:line',
                                content=FormattedTextControl(text='druid////'),
                                align=WindowAlign.RIGHT)

        self.content = HSplit([
            Window(),
            self.statusbar,
            Window(height=1),
        ])
        self.container = FloatContainer(
            content=self.content,
            floats=[
                Float(
                    xcursor=True,
                    ycursor=True,
                    content=CompletionsMenu(max_height=16, scroll_offset=1),
                ),
            ],
        )
        self.key_bindings = KeyBindings()

        @self.key_bindings.add('c-c', eager=True)
        @self.key_bindings.add('c-q', eager=True)
        def quit_druid(event):
            event.app.exit()

        if use_theme:
            self.style = Style([
                ('capture-field', '#747369'),
                ('output-field', '#d3d0c8'),
                ('input-field', '#f2f0ec'),
                ('line', '#747369'),
                ('scrollbar.background', 'bg:#000000'),
                ('scrollbar.button', 'bg:#747369'),
            ])
        else:
            self.style = Style([])

        self.layout = Layout(self.container)

        self.app = Application(
            layout=self.layout,
            key_bindings=self.key_bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
        )

        self.pages = dict()
        self.current_page = None
예제 #18
0
def _create_app(dialog: AnyContainer, style: Optional[BaseStyle]) -> Application[Any]:
    # Key bindings.
    bindings = KeyBindings()
    bindings.add("tab")(focus_next)
    bindings.add("s-tab")(focus_previous)

    return Application(
        layout=Layout(dialog),
        key_bindings=merge_key_bindings([load_key_bindings(), bindings]),
        mouse_support=True,
        style=style,
        full_screen=True,
    )
예제 #19
0
def select_prompt(message, options, mark='>'):
    control = SelectControl(options)

    def get_formatted_text():
        return control.select_option_text(mark)

    layout = Layout(
        HSplit([
            Window(
                height=Dimension.exact(1),
                content=FormattedTextControl(lambda: message + '\n',
                                             show_cursor=False),
            ),
            Window(height=Dimension.exact(len(control.options)),
                   content=FormattedTextControl(get_formatted_text)),
            ConditionalContainer(Window(control), filter=~IsDone())
        ]))

    app = Application(layout=layout,
                      key_bindings=control.key_bindings,
                      full_screen=False)
    return app.run()
예제 #20
0
def main():
    def done():
        application.exit()

    term = Terminal(
        width=D(preferred=60),
        height=D(preferred=25),
        done_callback=done)

    application = Application(
        layout=Layout(
            container=Dialog(
                title='Terminal demo',
                body=term,
                with_background=True
            ),
            focused_element=term
        ),
        full_screen=True,
        mouse_support=True,
    )
    application.run()
예제 #21
0
def print_container(container, file=None):
    """
    Print any layout to the output in a non-interactive way.

    Example usage::

        from prompt_toolkit.widgets import Frame, TextArea
        print_container(
            Frame(TextArea(text='Hello world!')))
    """
    if file:
        output = create_output(stdout=file)
    else:
        output = get_default_output()

    def exit_immediately():
        # Use `call_from_executor` to exit "soon", so that we still render one
        # initial time, before exiting the application.
        get_event_loop().call_from_executor(lambda: app.exit())

    app = Application(layout=Layout(container=container), output=output)
    app.run(pre_run=exit_immediately)
예제 #22
0
    def __init__(self, input_handler: Callable, bindings: KeyBindings,
                 completer: Completer):
        self.search_field = create_search_field()
        self.input_field = create_input_field(completer=completer)
        self.output_field = create_output_field()
        self.log_field = create_log_field(self.search_field)
        self.timer = create_timer()
        self.process_usage = create_process_monitor()
        self.trade_monitor = create_trade_monitor()
        self.layout = generate_layout(self.input_field, self.output_field,
                                      self.log_field, self.search_field,
                                      self.timer, self.process_usage,
                                      self.trade_monitor)
        # add self.to_stop_config to know if cancel is triggered
        self.to_stop_config: bool = False

        self.live_updates = False
        self.bindings = bindings
        self.input_handler = input_handler
        self.input_field.accept_handler = self.accept
        self.app = Application(layout=self.layout,
                               full_screen=True,
                               key_bindings=self.bindings,
                               style=load_style(),
                               mouse_support=True,
                               clipboard=PyperclipClipboard())

        # settings
        self.prompt_text = ">>> "
        self.pending_input = None
        self.input_event = None
        self.hide_input = False

        # start ui tasks
        loop = asyncio.get_event_loop()
        loop.create_task(start_timer(self.timer))
        loop.create_task(start_process_monitor(self.process_usage))
        loop.create_task(start_trade_monitor(self.trade_monitor))
예제 #23
0
def radiolist_dialog(title='', values=None, style=None, async_=False):
    # Add exit key binding.
    kb = KeyBindings()
    @kb.add('c-c')
    @kb.add("escape")
    def exit_(event):
        """
        Pressing Ctrl-c will exit the user interface.
        """
        event.app.exit()

    radio_list = SingleSelectList(values)
    application = Application(
        layout=Layout(HSplit([Label(title), radio_list])),
        key_bindings=kb,
        mouse_support=True,
        style=style,
        full_screen=False,
        )
    if async_:
        return application.run_async()
    else:
        return application.run()
예제 #24
0
def _create_app(dialog, style):
    # Key bindings.
    bindings = KeyBindings()
    bindings.add('tab')(focus_next)
    bindings.add('s-tab')(focus_previous)

    return Application(layout=Layout(dialog),
                       key_bindings=merge_key_bindings([
                           load_key_bindings(),
                           bindings,
                       ]),
                       mouse_support=True,
                       style=style,
                       full_screen=True)
예제 #25
0
def radiolist_dialog(title='', values=None, style=None, async_=False):
    # Add exit key binding.
    bindings = KeyBindings()

    @bindings.add('c-d')
    def exit_(event):
        """
        Pressing Ctrl-d will exit the user interface.
        """
        event.app.exit()

    radio_list = RadioListFast(values)
    application = Application(
        layout=Layout(HSplit([Label(title), radio_list])),
        key_bindings=merge_key_bindings([load_key_bindings(), bindings]),
        mouse_support=True,
        style=style,
        full_screen=False)

    if async_:
        return application.run_async()
    else:
        return application.run()
예제 #26
0
async def start_application(tab_completer):

    ui.core.input_field.accept_handler = c.handle_input
    ui.core.input_field.completer = tab_completer

    application = Application(
        layout=Layout(ui.core.container, focused_element=ui.core.input_field),
        key_bindings=ui.core.kb,
        style=ui.core.style,
        mouse_support=True,
        full_screen=True,
    )

    await application.run_async(set_exception_handler=True)
예제 #27
0
    def get_app(self):
        bindings = KeyBindings()

        @bindings.add(Keys.ControlC)
        def _ctrl_c(event):
            get_app().exit(exception=KeyboardInterrupt)

        @bindings.add(Keys.Enter)
        def _enter(event):
            get_app().exit(result=self.get_answer())

        return Application(layout=Layout(self.get_layout()),
                           key_bindings=merge_key_bindings(
                               [load_key_bindings(), bindings]),
                           style=get_theme_manager().get_current_style())
예제 #28
0
파일: editor.py 프로젝트: singajeet/ide
 def setup_application(self):
     """docstring for setup_application"""
     self._clipboard = InMemoryClipboard()
     self._application = Application(key_bindings_registry=self._key_binding_registry,
             layout=self._layout,
             mouse_support=bool(egc.EDITOR_MOUSE_SUPPORT),
             use_alternate_screen=True,
             initial_focussed_buffer=self._editor_buffer_name,
             clipboard=self._clipboard,
             get_title=self.get_editor_title,
             editing_mode=EditingMode.VI if egc.EDITOR_EDITING_MODE == 'VI' else EditingMode.EMACS,
             on_initialize=self.editor_started_callback,
             on_render=self.editor_rendered_callback,
             on_buffer_changed=self.editor_content_changed
             )
예제 #29
0
    def __init__(self):
        self._current_channel = None

        self._message_text_area = TextArea(read_only=True, focusable=False)

        self._message_input = TextArea(height=3, multiline=False)
        self._message_input.accept_handler = self._handle_message_entered

        self._root_container = HSplit([
            Frame(Window(height=1,
                         content=FormattedTextControl(lambda: [("class:title", self.get_title())]),
                         align=WindowAlign.CENTER)),
            self._message_text_area,
            Frame(self._message_input)
        ])

        self._keybindings = KeyBindings()

        @self._keybindings.add("c-c")
        def _(event):
            event.app.exit()

        self._app = Application(layout=Layout(self._root_container), full_screen=True, key_bindings=self._keybindings)
        self._app.run()
예제 #30
0
    def __init__(self, python_input, original_document):
        """
        Create an `Application` for the history screen.
        This has to be run as a sub application of `python_input`.

        When this application runs and returns, it retuns the selected lines.
        """
        self.python_input = python_input

        history_mapping = HistoryMapping(self, python_input.history,
                                         original_document)
        self.history_mapping = history_mapping

        document = Document(history_mapping.concatenated_history)
        document = Document(
            document.text,
            cursor_position=document.cursor_position +
            document.get_start_of_line_position(),
        )

        self.history_buffer = Buffer(
            document=document,
            on_cursor_position_changed=self._history_buffer_pos_changed,
            accept_handler=(
                lambda buff: get_app().exit(result=self.default_buffer.text)),
            read_only=True,
        )

        self.default_buffer = Buffer(
            name=DEFAULT_BUFFER,
            document=history_mapping.get_new_document(),
            on_cursor_position_changed=self._default_buffer_pos_changed,
            read_only=True,
        )

        self.help_buffer = Buffer(document=Document(HELP_TEXT, 0),
                                  read_only=True)

        self.history_layout = HistoryLayout(self)

        self.app = Application(
            layout=self.history_layout.layout,
            full_screen=True,
            style=python_input._current_style,
            mouse_support=Condition(lambda: python_input.enable_mouse_support),
            key_bindings=create_key_bindings(self, python_input,
                                             history_mapping),
        )
예제 #31
0
    def _create_application(self, editing_mode, erase_when_done):

        prompt_bindings = self._create_prompt_bindings()
        search_mode_bindings = self._create_search_mode_bindings()

        application = Application(
            layout=self.layout,
            full_screen=True,
            key_bindings=merge_key_bindings([
                merge_key_bindings([search_mode_bindings, prompt_bindings]),
            ]),
            color_depth=lambda: self.color_depth,
            input=self.input,
            output=self.output)

        return application
예제 #32
0
파일: console.py 프로젝트: bopopescu/icsw
    def __init__(self, opt_ns, srv_c, inst_xml):
        manager = KeyBindingManager()  # Start with the `KeyBindingManager`.

        self.srv_text = ServiceOutput(opt_ns, srv_c, inst_xml)
        layout = HSplit(
            [
                # One window that holds the BufferControl with the default buffer on the
                # left.
                Window(
                    height=D.exact(1),
                    content=TokenListControl(
                        self.get_title_line,
                        default_char=Char(" ", token=Token.String.ICSW.Header)
                    )
                ),
                Window(
                    height=D.exact(1),
                    content=FillControl('-', token=Token.Line)
                ),
                # Display the text 'Hello world' on the right.
                Window(
                    content=TokenListControl(
                        self.get_icsw_output,
                    )
                ),
            ]
        )

        self._updating = False

        @manager.registry.add_binding(Keys.ControlC, eager=True)
        @manager.registry.add_binding("q", eager=True)
        def _handler_data(event):
            event.cli.set_return_value(0)

        our_style = style_from_dict(logging_tools.get_icsw_prompt_styles())
        application = Application(
            layout=layout,
            use_alternate_screen=True,
            style=our_style,
            on_input_timeout=self.input_timeout,
            key_bindings_registry=manager.registry,
        )
        event_loop = create_eventloop()
        self.application = application
        self.event_loop = event_loop
예제 #33
0
    def __init__(self, player):
        self.player = player
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
                ('', ' '),
                ('#cc00cc', self.playerClans, "utf-8"),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
            ]) 
        self.result = None

        self.mainRadiosRows = []
        self.listOfItems = []
        self.populateMainRadios() # declares self.mainRadios
        self.currentRadios = self.mainRadios
        self.description = self.mainRadios.description # description is whataver is in the description box on the right
        self.requestingConfirmation = False
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.handleEscape)

        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getRootContainer(),
                focused_element=self.mainRadios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )
예제 #34
0
    def __init__(self, player, nameOfShop, shopInventory, shopKeeperAsciiArt=None, customCurrency=None):
        '''shopInventory is a list of items'''
        self.player = player
        self.name = nameOfShop
        self.shopInventory = shopInventory
        self.shopKeeperAsciiArt = shopKeeperAsciiArt
        if self.shopKeeperAsciiArt == None:
            self.shopKeeperAsciiArt ='''
     _\|/^
      (_oo     what can i get for ya
       |     
      /|\\
       |
       LL
            '''
          
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
                ('', ' '),
                ('#cc00cc', self.playerClans, "utf-8"),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
            ]) 
        if customCurrency == None: self.currency = "dollars"
        else: self.currency = customCurrency
        self.result = None

        self.buySellRadiosRows = []
        self.listOfItems = []
        self.populateBuySellRadios() # declares self.buySellRadios
        self.currentRadios = self.buySellRadios
        self.rightWindowDescription = self.buySellRadios.description # description is whataver is in the description box on the right
        self.requestingConfirmation = False
        self.playerIs = "at buy/sell menu"
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.handleEscape)

        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getShopContainer(),
                focused_element=self.buySellRadios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )
예제 #35
0
    def __enter__(self):
        # 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):
            # 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(
            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,
            color_depth=self.color_depth,
            output=self.output,
            input=self.input)

        # Run application in different thread.
        def run():
            with _auto_refresh_context(self.app, .3):
                try:
                    self.app.run()
                except BaseException as e:
                    traceback.print_exc()
                    print(e)

        self._thread = threading.Thread(target=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 = self._loop.add_signal_handler(
                signal.SIGWINCH, self.app.invalidate)

        return self
예제 #36
0
def main():
    # The layout.
    search_field = SearchToolbar()  # For reverse search.

    output_field = TextArea(style='class:output-field', text=help_text)
    input_field = TextArea(
        height=1, prompt='>>> ', style='class:input-field', multiline=False,
        wrap_lines=False, search_field=search_field)

    container = HSplit([
        output_field,
        Window(height=1, char='-', style='class:line'),
        input_field,
        search_field,
    ])

    # Attach accept handler to the input field. We do this by assigning the
    # handler to the `TextArea` that we created earlier. it is also possible to
    # pass it to the constructor of `TextArea`.
    # NOTE: It's better to assign an `accept_handler`, rather then adding a
    #       custom ENTER key binding. This will automatically reset the input
    #       field and add the strings to the history.
    def accept(buff):
        # Evaluate "calculator" expression.
        try:
            output = '\n\nIn:  {}\nOut: {}'.format(
                input_field.text,
                eval(input_field.text))  # Don't do 'eval' in real code!
        except BaseException as e:
            output = '\n\n{}'.format(e)
        new_text = output_field.text + output

        # Add text to output buffer.
        output_field.buffer.document = Document(
            text=new_text, cursor_position=len(new_text))

    input_field.accept_handler = accept

    # The key bindings.
    kb = KeyBindings()

    @kb.add('c-c')
    @kb.add('c-q')
    def _(event):
        " Pressing Ctrl-Q or Ctrl-C will exit the user interface. "
        event.app.exit()

    # Style.
    style = Style([
        ('output-field', 'bg:#000044 #ffffff'),
        ('input-field', 'bg:#000000 #ffffff'),
        ('line',        '#004400'),
    ])

    # Run application.
    application = Application(
        layout=Layout(container, focused_element=input_field),
        key_bindings=kb,
        style=style,
        mouse_support=True,
        full_screen=True)

    application.run()
예제 #37
0
    def _create_app(self):
        """
        Create `Application` instance for this .
        """
        pymux = self.pymux

        def on_focus_changed():
            """ When the focus changes to a read/write buffer, make sure to go
            to insert mode. This happens when the ViState was set to NAVIGATION
            in the copy buffer. """
            vi_state = app.vi_state

            if app.current_buffer.read_only():
                vi_state.input_mode = InputMode.NAVIGATION
            else:
                vi_state.input_mode = InputMode.INSERT

        app = Application(
            output=self.output,
            input=self.input,
            color_depth=self.color_depth,

            layout=Layout(container=self.layout_manager.layout),
            key_bindings=pymux.key_bindings_manager.key_bindings,
            mouse_support=Condition(lambda: pymux.enable_mouse_support),
            full_screen=True,
            style=self.pymux.style,
            style_transformation=ConditionalStyleTransformation(
                SwapLightAndDarkStyleTransformation(),
                Condition(lambda: self.pymux.swap_dark_and_light),
            ),
            on_invalidate=(lambda _: pymux.invalidate()))

        # Synchronize the Vi state with the CLI object.
        # (This is stored in the current class, but expected to be in the
        # CommandLineInterface.)
        def sync_vi_state(_):
            VI = EditingMode.VI
            EMACS = EditingMode.EMACS

            if self.confirm_text or self.prompt_command or self.command_mode:
                app.editing_mode = VI if pymux.status_keys_vi_mode else EMACS
            else:
                app.editing_mode = VI if pymux.mode_keys_vi_mode else EMACS

        app.key_processor.before_key_press += sync_vi_state
        app.key_processor.after_key_press += sync_vi_state
        app.key_processor.after_key_press += self.sync_focus

        # Set render postpone time. (.1 instead of 0).
        # This small change ensures that if for a split second a process
        # outputs a lot of information, we don't give the highest priority to
        # rendering output. (Nobody reads that fast in real-time.)
        app.max_render_postpone_time = .1  # Second.

        # Hide message when a key has been pressed.
        def key_pressed(_):
            self.message = None
        app.key_processor.before_key_press += key_pressed

        # The following code needs to run with the application active.
        # Especially, `create_window` needs to know what the current
        # application is, in order to focus the new pane.
        with set_app(app):
            # Redraw all CLIs. (Adding a new client could mean that the others
            # change size, so everything has to be redrawn.)
            pymux.invalidate()

            pymux.startup()

        return app
예제 #38
0
    def __init__(self, player, enemy, song='worry 2.wav'):
        self.song = Sound( player,fileName = song, loop=-1)
        self.player = player
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', str(player.aspect['name'])),
                ('', ' '),
                ('#cc00cc', str(self.playerClans)),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', str(player.aspect['name'])),
            ]) 
        self.enemy = enemy

        self.playerGoesNext = True # by default, enemy always gets first strike
        self.playerJustDodged = False
        self.escapeTries = 0
        self.escapeChance = .3

        self.battleLog = '\n\n\n\n\n\n'
        self.maxHeightOfBattleLogWindow = 7
        self.totalWidth = 90
        self.actionsWidth = 30
        self.statsWidth = 20 

        self.selectedIndexText = ''
        self.result = None

        self.playerHPBar = ProgressBar()
        self.setHealthProgressBar(self.playerHPBar, self.toPercent(self.player.hp, self.player.maxhp)) 
        self.enemyHPBar = ProgressBar()
        self.setHealthProgressBar(self.enemyHPBar, 100) 

        self.radios = RadioList(
            values=[ #value, lable
                ('Attack', 'Attack'), # use eqipped weapon
                ('Dodge', 'Dodge'), # icrease miss chance for enemy
                ('Item', 'Item'),
                ('Run', 'Run') # try to escape
                # more options could be:
                # check - returns text about enemy potentially indicating weaknessess
            ],
            player = self.player,
            width = self.actionsWidth)
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.tryToEscape)
        # self.bindings.add('up')(self.setSelectedIndexTextUp)
        # TODO: make secret easter egg key bindings # self.bindings.add('a', 'a')(self.test)  
        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getRootContainer(),
                focused_element=self.radios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )
예제 #39
0
class CombatUI():

    def __init__(self, player, enemy, song='worry 2.wav'):
        self.song = Sound( player,fileName = song, loop=-1)
        self.player = player
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', str(player.aspect['name'])),
                ('', ' '),
                ('#cc00cc', str(self.playerClans)),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', str(player.aspect['name'])),
            ]) 
        self.enemy = enemy

        self.playerGoesNext = True # by default, enemy always gets first strike
        self.playerJustDodged = False
        self.escapeTries = 0
        self.escapeChance = .3

        self.battleLog = '\n\n\n\n\n\n'
        self.maxHeightOfBattleLogWindow = 7
        self.totalWidth = 90
        self.actionsWidth = 30
        self.statsWidth = 20 

        self.selectedIndexText = ''
        self.result = None

        self.playerHPBar = ProgressBar()
        self.setHealthProgressBar(self.playerHPBar, self.toPercent(self.player.hp, self.player.maxhp)) 
        self.enemyHPBar = ProgressBar()
        self.setHealthProgressBar(self.enemyHPBar, 100) 

        self.radios = RadioList(
            values=[ #value, lable
                ('Attack', 'Attack'), # use eqipped weapon
                ('Dodge', 'Dodge'), # icrease miss chance for enemy
                ('Item', 'Item'),
                ('Run', 'Run') # try to escape
                # more options could be:
                # check - returns text about enemy potentially indicating weaknessess
            ],
            player = self.player,
            width = self.actionsWidth)
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.tryToEscape)
        # self.bindings.add('up')(self.setSelectedIndexTextUp)
        # TODO: make secret easter egg key bindings # self.bindings.add('a', 'a')(self.test)  
        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getRootContainer(),
                focused_element=self.radios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )

    

    # call this function to change the value a progress bar (prog) to a percent
    def setHealthProgressBar(self,progbar, percent):
        if percent < 0: # should never happen but for safety
            percent = 0
        progbar.container = FloatContainer(
            content=Window(height=1),
            floats=[
                Float(left=0, top=0, right=0, bottom=0, content=VSplit([
                    Window(style='bg:#00cc00', # health, green
                            width=lambda: D(weight=int(percent))),
                    Window(style='bg:#ff0000', # damage, red
                            width=lambda: D(weight=int(100 - percent))),
                ])),
            ])

    def toPercent(self, value, max):
        return int(100*(float(value)/float(max)))

    def handleEnter(self, event):
        if not self.playerGoesNext: # check if it's actually your turn
            return
        self.playerGoesNext = False

        choice = self.radios.values[self.radios._selected_index][0] 
        s = ''
        if choice == "Attack":
            self.attackEnemy()
            return # return early so attackEnemy can go to enemy turn so damaging consunmables work
        elif choice == "Dodge": # dodging increases chance for enemy to miss by 30% SCALING
            s += "You tried to dodge... "
            self.playerJustDodged = True 
        elif choice == "Item": # doesnt take your turn
            self.playerGoesNext = True
            self.done(result='inventory')
            return
        elif choice == "Run":
            s += self.tryToEscape()
        else:
            s += "How did you do that!?"
        
        self.enemyTurn(s)

    def attackEnemy(self, alwaysHit=True, consumableDamage=None, consumableName=None ):
        s = ''
        if not consumableDamage == None: # if has consumable damage
            damage = consumableDamage # better also have a name
            s += "You threw the " + str(consumableName) + "... "
        else:
            s +=  "You tried to attack... "
            damage = self.player.getTotalAttackPower()
        s += " and did " 
        s += str(damage)
        s += " damage!" # TODO color
        self.enemy.hp = self.enemy.hp - int(damage)
        if self.enemy.hp < 0:
            self.enemy.hp = 0
        self.setHealthProgressBar(self.enemyHPBar, self.toPercent(self.enemy.hp, self.enemy.maxhp))
        self.enemyTurn(s)
    
    def tryToEscape(self, event=None):
        s = ''
        s += "You tried to run..." 
        randomChance = random.uniform(0,1) - (self.escapeTries-1) *.1 # each try makes it 10 percent easier to escape after first try
        if self.escapeChance > randomChance and self.escapeTries>0: #has to have already tried to escape once
            s += " and escaped the combat!" # TODO advanced combat: isnt ever visible
            self.done("escaped")
        else:
            s += " but failed to escape!"
        self.escapeTries += 1
        return s

    def enemyTurn(self, textOfPlayerTurn=False):
        if self.enemy.hp == 0: # check if he dead
            self.done("win")
            return
        # for now, always try to attack TODO advanced combat
        self.playerGoesNext = True
        s=''
        s += self.enemy.name + " tried to " 
        attack = self.enemy.getRandomAttack() 
        if attack[-1] == "*": # if attack finishes the sentence
            s += attack[:-1] # remove *
        else :
            s += str(attack)
            s += " you... "
            
        # calculate hit chance and handle
        dodgeModifier = 0 # TODO advanced combat dodge modifier
        if self.playerJustDodged == True:
            dodgeModifier = 30
            self.playerJustDodged = False
        if self.enemy.missChancePercent + dodgeModifier > random.randint(0,100):
            # missed
            if not attack[-1] == "*": s += " but missed!"
            else: s += " But missed!"
        else:
            # hit
            damage = self.enemy.attack
            if not attack[-1] == "*": s += " and dealt " + str(damage) + " damage!"
            else: 
                s += " It dealt " + str(damage) + " damage!"
            self.player.hp = self.player.hp - damage # lose health
            #t1 = threading.Thread(target=self.rollNumbers(self.player.hp, self.player.hp - damage), args=())
            #t1.start()
            # self.rollNumbers(self.player.hp, self.player.hp - damage)

            if self.player.hp < 0:
                self.player.hp = 0
            self.setHealthProgressBar(self.playerHPBar, self.toPercent(self.player.hp, self.player.maxhp))
            if self.player.hp == 0: #dead
                # TODO make death less awkwawrd
                self.done("lose")
                return
        if textOfPlayerTurn: 
            self.battleLog = textOfPlayerTurn + '\n\n' + s 
        else:
            self.battleLog = s 
        self.refresh()

    def rollNumbers(self, start, end, speed=1.5):
        r = start-end # range
        maxSpeed = .01
        if r < 0: r *= -1
        startTime = .5
        for t in range(r):
            startTime /= speed
        time = startTime
        for c in range(r+1):
            s = int(start - c )
            self.player.hp = s
            self.refresh()
            if time < maxSpeed:
                wait(maxSpeed)
            else:
                wait(time)
            time *= speed 

    def refresh(self):
        self.fillBattleLogWithNewlines()
        self.application.layout=Layout(
            self.getRootContainer(),
            focused_element=self.radios)

    def fillBattleLogWithNewlines(self):
        self.battleLog = wrap(self.battleLog, limit=self.totalWidth-self.actionsWidth-self.statsWidth)
        slicedBattleLog = self.battleLog.split('\n') # list of rows of the battlelog
        while True:
            if len(slicedBattleLog) < self.maxHeightOfBattleLogWindow: 
                slicedBattleLog.append('\n') 
            else:
                break
        self.battleLog = '\n'.join(slicedBattleLog)

    # def suspense(self): # doesnt work because ui updates on run method, not during other methods
    #     for i in range(3):
    #         wait(.5)
    #         self.battleLog += '.'
    #         self.refresh()

    def makeFormattedText(self, text, color='#ffffff'):
        return FormattedText([
            (color, str(text)) 
        ])

    # returns new root container (updates text and stuff)
    def getRootContainer(self):
        height = self.maxHeightOfBattleLogWindow
        enemyName = self.makeFormattedText(self.enemy.name) 
        battleLogTitle = FormattedText([
            ('#ffffff', "Battle Log") 
        ])
        actionsTitle = FormattedText([
            ('#ffffff', "Actions") 
        ])
        statsTitle = FormattedText([
            ('#ffffff', "Stats") 
        ])
        root_container = HSplit([
            VSplit([
                Dialog( # actions
                    title=actionsTitle,
                    body=HSplit([
                        self.radios,
                    ], height= height),
                    width=self.actionsWidth
                ), # battlelog 
                Dialog(
                    title = battleLogTitle,
                    body=Label(self.battleLog),
                    width=self.totalWidth-self.actionsWidth - self.statsWidth
                ),
                Dialog( # stats
                    title = statsTitle,
                    body=Label(getStats(self.player)),
                    width=self.statsWidth ,
                ),
            ], padding=0, width = self.actionsWidth, height=height+2 ),
            # health bars #
            VSplit([ 
                Frame(
                    body=self.playerHPBar,
                    title=self.playerName,
                    width=int(self.totalWidth/2)
                ),
                Frame(
                    body=self.enemyHPBar,
                    title=enemyName,
                    width=int(self.totalWidth/2)
                ), 
            ], padding=0, width = self.totalWidth)
        ])
        return root_container

    def run(self):
        self.application.run()

    def done(self, result='?'):
        self.result = result
        if self.result != 'inventory':
            self.song.stopSound()
        get_app().exit(result=self.result)
예제 #40
0
class Pager(object):
    """
    The Pager main application.

    Usage::
        p = Pager()
        p.add_source(...)
        p.run()

    :param source: :class:`.Source` instance.
    :param lexer: Prompt_toolkit `lexer` instance.
    :param vi_mode: Enable Vi key bindings.
    :param style: Prompt_toolkit `Style` instance.
    :param search_text: `None` or the search string that is highlighted.
    """
    def __init__(self, vi_mode=False, style=None, search_text=None,
                 titlebar_tokens=None):
        assert isinstance(vi_mode, bool)
        assert style is None or isinstance(style, Style)

        self.sources = []
        self.current_source_index = 0  # Index in `self.sources`.
        self.highlight_search = True
        self.in_colon_mode = False
        self.message = None
        self.displaying_help = False
        self.search_text = search_text
        self.display_titlebar = bool(titlebar_tokens)
        self.titlebar_tokens = titlebar_tokens or []

        self._dummy_source = DummySource()

        # When this is True, always make sure that the cursor goes to the
        # bottom of the visible content. This is similar to 'tail -f'.
        self.forward_forever = False

        # Status information for all sources. Source -> _SourceInfo.
        # (Remember this info as long as the Source object exists.)
        self.source_info = weakref.WeakKeyDictionary()

        # Create prompt_toolkit stuff.

        def open_file(buff):
            # Open file.
            self.open_file(buff.text)

            # Focus main buffer again.
            buff.reset()

        # Buffer for the 'Examine:' input.
        self.examine_buffer = Buffer(
            name='EXAMINE',
            completer=PathCompleter(expanduser=True),
            accept_handler=open_file,
            multiline=False)

        # Search buffer.
        self.search_buffer = Buffer(multiline=False)

        self.layout = PagerLayout(self)

        bindings = create_key_bindings(self)
        self.application = Application(
            input=create_input(sys.stdout),
            layout=Layout(container=self.layout.container),
            enable_page_navigation_bindings=True,
            key_bindings=bindings,
            style=style or Style.from_dict(ui_style),
            mouse_support=True,
            after_render=self._after_render,
            full_screen=True)

        # Hide message when a key is pressed.
        def key_pressed(_):
            self.message = None
        self.application.key_processor.before_key_press += key_pressed

        if vi_mode:
            self.application.editing_mode = EditingMode.VI

    @classmethod
    def from_pipe(cls, lexer=None):
        """
        Create a pager from another process that pipes in our stdin.
        """
        assert not sys.stdin.isatty()
        self = cls()
        self.add_source(PipeSource(fileno=sys.stdin.fileno(), lexer=lexer))
        return self

    @property
    def current_source(self):
        " The current `Source`. "
        try:
            return self.sources[self.current_source_index]
        except IndexError:
            return self._dummy_source

    @property
    def current_source_info(self):
        try:
            return self.source_info[self.current_source]
        except KeyError:
            return _SourceInfo(self, self.current_source)

    def open_file(self, filename):
        """
        Open this file.
        """
        lexer = PygmentsLexer.from_filename(filename, sync_from_start=False)

        try:
            source = FileSource(filename, lexer=lexer)
        except IOError as e:
            self.message = '{}'.format(e)
        else:
            self.add_source(source)

    def add_source(self, source):
        """
        Add a new :class:`.Source` instance.
        """
        assert isinstance(source, Source)

        source_info = _SourceInfo(self, source)
        self.source_info[source] = source_info

        self.sources.append(source)

        # Focus
        self.current_source_index = len(self.sources) - 1
        self.application.layout.focus(source_info.window)

    def remove_current_source(self):
        """
        Remove the current source from the pager.
        (If >1 source is left.)
        """
        if len(self.sources) > 1:
            current_source_index = self.current_source

            # Focus the previous source.
            self.focus_previous_source()

            # Remove the last source.
            self.sources.remove(current_source_index)
        else:
            self.message = "Can't remove the last buffer."

    def focus_previous_source(self):
        self.current_source_index = (self.current_source_index - 1) % len(self.sources)
        self.application.layout.focus(self.current_source_info.window)
        self.in_colon_mode = False

    def focus_next_source(self):
        self.current_source_index = (self.current_source_index + 1) % len(self.sources)
        self.application.layout.focus(self.current_source_info.window)
        self.in_colon_mode = False

    def display_help(self):
        """
        Display help text.
        """
        if not self.displaying_help:
            source = FormattedTextSource(HELP, name='<help>')
            self.add_source(source)
            self.displaying_help = True

    def quit_help(self):
        """
        Hide the help text.
        """
        if self.displaying_help:
            self.remove_current_source()
            self.displaying_help = False

    def _after_render(self, app):
        """
        Each time when the rendering is done, we should see whether we need to
        read more data from the input pipe.
        """
        # When the bottom is visible, read more input.
        # Try at least `info.window_height`, if this amount of data is
        # available.
        info = self.layout.dynamic_body.get_render_info()
        source = self.current_source
        source_info = self.source_info[source]
        b = source_info.buffer
        line_tokens = source_info.line_tokens

        if not source_info.waiting_for_input_stream and not source.eof() and info:
            lines_below_bottom = info.ui_content.line_count - info.last_visible_line()

            # Make sure to preload at least 2x the amount of lines on a page.
            if lines_below_bottom < info.window_height * 2 or self.forward_forever:
                # Lines to be loaded.
                lines = [info.window_height * 2 - lines_below_bottom]  # nonlocal

                fd = source.get_fd()

                def handle_content(tokens):
                    """ Handle tokens, update `line_tokens`, decrease
                    line count and return list of characters. """
                    data = []
                    for token_char in tokens:
                        char = token_char[1]
                        if char == '\n':
                            line_tokens.append([])

                            # Decrease line count.
                            lines[0] -= 1
                        else:
                            line_tokens[-1].append(token_char)
                        data.append(char)
                    return data

                def insert_text(list_of_fragments):
                    document = Document(b.text + ''.join(list_of_fragments), b.cursor_position)
                    b.set_document(document, bypass_readonly=True)

                    if self.forward_forever:
                        b.cursor_position = len(b.text)

                def receive_content_from_fd():
                    # Read data from the source.
                    tokens = source.read_chunk()
                    data = handle_content(tokens)

                    # Set document.
                    insert_text(data)

                    # Remove the reader when we received another whole page.
                    # or when there is nothing more to read.
                    if lines[0] <= 0 or source.eof():
                        if fd is not None:
                            get_event_loop().remove_reader(fd)
                        source_info.waiting_for_input_stream = False

                    # Redraw.
                    self.application.invalidate()

                def receive_content_from_generator():
                    " (in executor) Read data from generator. "
                    # Call `read_chunk` as long as we need more lines.
                    while lines[0] > 0 and not source.eof():
                        tokens = source.read_chunk()
                        data = handle_content(tokens)
                        insert_text(data)

                        # Schedule redraw.
                        self.application.invalidate()

                    source_info.waiting_for_input_stream = False

                # Set 'waiting_for_input_stream' and render.
                source_info.waiting_for_input_stream = True
                self.application.invalidate()

                # Add reader for stdin.
                if fd is not None:
                    get_event_loop().add_reader(fd, receive_content_from_fd)
                else:
                    # Execute receive_content_from_generator in thread.
                    # (Don't use 'run_in_executor', because we need a daemon.
                    t = threading.Thread(target=receive_content_from_generator)
                    t.daemon = True
                    t.start()

    def run(self):
        """
        Create an event loop for the application and run it.
        """
        try:
            # Set search highlighting.
            if self.search_text:
                self.application.search_state.text = self.search_text

            return self.application.run()
        finally:
            # XXX: Close all sources which are opened by the pager itself.
            pass
예제 #41
0
class ShopUI():

    def __init__(self, player, nameOfShop, shopInventory, shopKeeperAsciiArt=None, customCurrency=None):
        '''shopInventory is a list of items'''
        self.player = player
        self.name = nameOfShop
        self.shopInventory = shopInventory
        self.shopKeeperAsciiArt = shopKeeperAsciiArt
        if self.shopKeeperAsciiArt == None:
            self.shopKeeperAsciiArt ='''
     _\|/^
      (_oo     what can i get for ya
       |     
      /|\\
       |
       LL
            '''
          
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
                ('', ' '),
                ('#cc00cc', self.playerClans, "utf-8"),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
            ]) 
        if customCurrency == None: self.currency = "dollars"
        else: self.currency = customCurrency
        self.result = None

        self.buySellRadiosRows = []
        self.listOfItems = []
        self.populateBuySellRadios() # declares self.buySellRadios
        self.currentRadios = self.buySellRadios
        self.rightWindowDescription = self.buySellRadios.description # description is whataver is in the description box on the right
        self.requestingConfirmation = False
        self.playerIs = "at buy/sell menu"
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.handleEscape)

        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getShopContainer(),
                focused_element=self.buySellRadios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )

    def handleEscape(self, event):
        self.requestingConfirmation = False
        if self.currentRadios == self.buySellRadios:
            self.done()
        else: # return to main page
            self.playerIs = "at buy/sell menu"
            self.populateBuySellRadios()
            self.currentRadios = self.buySellRadios
            # self.description = self.buySellRadios.description
            self.refresh()

    def handleEnter(self, event):
        if self.requestingConfirmation:
            self.requestingConfirmation = False
            if self.playerIs == "buying":
                self.buy()
                self.listOfItems = self.shopInventory
            elif self.playerIs == "selling":
                self.sell()
                self.listOfItems = self.player.getAllInventoryItemsAsObjectList()
            if self.handleEmptiness(self.listOfItems): return
            self.makeListCurrentRadios(self.listOfItems) 
            # TODO sound music, sound effect of eating a consumable
            return

        elif self.currentRadios == self.buySellRadios: # if on main page
            if self.currentRadios._selected_index == 0: # BUY, show shops inventory
                self.playerIs = "buying"
                self.listOfItems = self.shopInventory
            elif self.currentRadios._selected_index == 1: # SELL, show player inventory
                self.playerIs = "selling"
                self.listOfItems = self.player.getAllInventoryItemsAsObjectList()
            else:log("what the f**k")
            if self.handleEmptiness(self.listOfItems): return
            self.makeListCurrentRadios(self.listOfItems) 
        elif self.currentRadios == self.selectedRadios: # if not on main page
            self.requestingConfirmation = True
            price = self.getCurrentlySelectedItem().sellValue
            if price == 1 and self.currency.endswith('s'): currency = 'dollar'
            else: currency = self.currency
            nameOfItem = self.getCurrentlySelectedItem().name
            if self.playerIs == "buying":
                self.refresh(setDescription="Purchase " + str(nameOfItem) +" for " + str(price) + " " + currency + "?")
            elif self.playerIs == "selling":
                self.refresh(setDescription="Sell " + str(nameOfItem) +" for " + str(price) + " " + currency + "?")

    def buy(self):
        item = self.getCurrentlySelectedItem()
        if item.sellValue > self.player.money:
            self.refresh(setDescription="You can't afford that.")
        else:
            self.player.money = self.player.money - item.sellValue # subtract funds
            self.player.money = round(self.player.money, 2) # round to cents
            item.sellValue = item.sellValue /2 # half the worth of the item after buying
            self.shopInventory.remove(item)
            self.player.addToInventory(item, printAboutIt=False)

    def sell(self):
        item = self.getCurrentlySelectedItem()
        if item.equipped == True: self.player.unequip(item=item)
        self.player.inventory.remove(item) # remove item from player inventory
        self.player.money = self.player.money + item.sellValue # get paid
        self.player.money = round(self.player.money, 2) # round just in case
        self.shopInventory.append(item) # give item to shop owner

    def getCurrentlySelectedItem(self):
        return self.listOfItems[self.currentRadios._selected_index]

    def handleEmptiness(self, lis):
        if len(self.listOfItems) == 0:
            self.currentRadios = self.buySellRadios
            if self.playerIs == "buying":
                self.playerIs = "at buy/sell menu"
                self.refresh(setDescription="Sold out!")
            elif self.playerIs == "selling":
                self.playerIs = "at buy/sell menu"
                self.refresh(setDescription="You've got nothing left!")
            return True

    def makeListCurrentRadios(self, lisp, selectedIndex=0):
        lisp = self.refreshItemDescriptions(lisp)
        self.listOfItemsTupled = self.tuplify(lisp)
        self.selectedRadios = RadioList2(
            values=self.listOfItemsTupled,
            app = self)    
        self.selectedRadios._selected_index = selectedIndex
        self.currentRadios = self.selectedRadios 
        # self.description = self.currentRadios.values[selectedIndex]
        self.refresh()

    def refreshItemDescriptions(self, lis):
        for i in lis:
            i.description = i.buildItemDescriptionString()
        return lis

    def tuplify(self, listt):
        if len(listt) == 0:
            return [] # should never see this
        newlist=[]
        for i in range(len(listt)):
            l = []
            l.append(self.unicodify(listt[i].description))
            l.append(self.unicodify(colorItem(listt[i], useGetName=True))) # colors
            newlist.append( tuple(l) )
        return newlist

    
        
    

    def refresh(self, setDescription=False):
        index = self.currentRadios._selected_index
        if setDescription:
            self.rightWindowDescription = setDescription
        else:
            self.rightWindowDescription = self.currentRadios.values[index][0]
        
        self.application.layout=Layout(
            self.getShopContainer(),
            focused_element=self.currentRadios)
            
        
    def populateBuySellRadios(self):
        self.buySellRadiosRows = []
        self.populateBuySellRadiosHelper('Buy')
        self.populateBuySellRadiosHelper('Sell')
        self.buySellRadios = RadioList2(
            values=self.buySellRadiosRows,
            app = self)

    def populateBuySellRadiosHelper(self, category):
        desc = self.shopKeeperAsciiArt
        tup = []
        tup.append(desc)
        tup.append(category.capitalize())
        self.buySellRadiosRows.append( tuple(tup) )

    def unicodify(self, text):
        if isinstance(text, str):
            return str(text)
        else:
            return text

    def getShopContainer(self):
        width = 40
        smallerWidth = 30
        statsWidth = 20
        height = 10
        if self.playerIs == "at buy/sell menu":
            leftWindowTitle = ""
            descriptionArea =makeFormattedText(self.name)
            desc = self.rightWindowDescription
        elif self.playerIs == "buying":
            leftWindowTitle = makeFormattedText(self.name)
            descriptionArea = colorItem(self.getCurrentlySelectedItem())
            desc = wrap(self.rightWindowDescription, width-2)
        elif self.playerIs == "selling":
            leftWindowTitle = makeFormattedText(self.player.aspect["name"])
            descriptionArea = colorItem(self.getCurrentlySelectedItem())
            desc = wrap(self.rightWindowDescription, width-2)
        root_container = VSplit([
            HSplit([
                Dialog(
                    title=leftWindowTitle,
                    body=HSplit([
                        self.currentRadios,
                    ], )
                ),
            ], padding=0, width = smallerWidth, ),
            HSplit([
                Dialog(
                    title = descriptionArea,
                    body=Label(desc),
                ),
            ], padding=0, width = width,),
            HSplit([
                Dialog(
                    title =  makeFormattedText("Stats"),
                    body=Label(getStats(self.player)),
                ),
            ], padding=0, width = statsWidth, height= height,),
        ])
        return root_container 

    def run(self):
        self.application.run()

    def done(self):
        self.result = "hit escape"
        get_app().exit(result="hit escape")
 
# TODO:
# colors
예제 #42
0
class InventoryUI():

    def __init__(self, player):
        self.player = player
        self.playerClans = ' '.join(self.player.clantags)
        if len(self.player.clantags) > 0 : 
            self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
                ('', ' '),
                ('#cc00cc', self.playerClans, "utf-8"),
            ]) 
        else: 
            self.playerClans =  self.playerName = FormattedText([
                ('#ffffff', player.aspect['name']),
            ]) 
        self.result = None

        self.mainRadiosRows = []
        self.listOfItems = []
        self.populateMainRadios() # declares self.mainRadios
        self.currentRadios = self.mainRadios
        self.description = self.mainRadios.description # description is whataver is in the description box on the right
        self.requestingConfirmation = False
        
        self.bindings = KeyBindings()
        self.bindings.add('right' )(focus_next)
        self.bindings.add('tab' )(focus_next)
        self.bindings.add('s-tab')(focus_previous)
        self.bindings.add('left')(focus_previous)
        self.bindings.add('c-m')(self.handleEnter)
        self.bindings.add('escape')(self.handleEscape)

        self.style = Style.from_dict({
            'dialog.body':        'bg:#000000 #ffcccc', #background color, text color
        })

        self.application = Application(
            layout=Layout(
                self.getRootContainer(),
                focused_element=self.mainRadios,
            ),
            key_bindings=self.bindings,
            style=self.style,
            mouse_support=True,
            full_screen=True,
            )

    def handleEscape(self, event):
        self.requestingConfirmation = False
        if self.currentRadios == self.mainRadios:
            self.done()
        else: # return to main page
            self.populateMainRadios()
            self.currentRadios = self.mainRadios
            # self.description = self.mainRadios.description
            self.refresh()

    def handleEnter(self, event):
        if self.requestingConfirmation:
            self.requestingConfirmation = False
            result = self.player.activateItem(self.getCurrentlySelectedItem())
            if not isinstance(result, str): # if result isnt a string
                self.done(result)# this should be different
            self.updateListOfItems()
            self.makeListCurrentRadios(self.listOfItems) 
            self.refresh(setDescription=result)
            # TODO sound music, sound effect of eating a consumable
            return

        if self.currentRadios == self.mainRadios: # if on main page
            self.updateListOfItems()
            self.makeListCurrentRadios(self.listOfItems) 
        elif self.currentRadios == self.selectedRadios: # if not on main page
            currentItem = self.listOfItems[self.currentRadios._selected_index]
            if currentItem.type == "consumable":
                if currentItem.consumable.consumableType == 'xp':
                    description = 'Eat it?'
                elif currentItem.consumable.consumableType == 'damage':
                    description = 'Throw it?'
                elif currentItem.consumable.consumableType == 'heal':
                    description = 'Eat it?'
                else:
                    description = 'Crash the game?' # shouldnt ever see
                self.requestingConfirmation = True
                self.refresh(setDescription=description)
                return
            self.player.activateItem(self.listOfItems[self.currentRadios._selected_index]) # can delete items
            self.makeListCurrentRadios(self.listOfItems,self.selectedRadios._selected_index) 

    def updateListOfItems(self):
        category = self.mainRadios.values[self.mainRadios._selected_index][1]
        if category == 'Weapons':
            self.listOfItems = self.player.getAllInventoryItemsAsObjectList(_type='weapon')
        elif category == 'Armour':
            self.listOfItems = self.player.getAllInventoryItemsAsObjectList(_type='armour')
        elif category == 'Consumable':
            self.listOfItems = self.player.getAllInventoryItemsAsObjectList(_type='consumable')
        elif category == 'Quest':
            self.listOfItems = self.player.getAllInventoryItemsAsObjectList(_type='quest')
        elif category == 'Misc':
            self.listOfItems = self.player.getAllInventoryItemsAsObjectList(_type='misc')
        if len(self.listOfItems) == 0:
            self.populateMainRadios()
            self.currentRadios = self.mainRadios
            self.refresh()

    def makeListCurrentRadios(self, lisp, selectedIndex=0):
        if len(lisp) == 0:
            self.populateMainRadios()
            self.currentRadios = self.mainRadios
        else: 
            lisp = self.refreshItemDescriptions(lisp)
            self.listOfItemsTupled = self.tuplify(lisp)
            self.selectedRadios = RadioList2(
                values=self.listOfItemsTupled,
                app = self)    
            self.selectedRadios._selected_index = selectedIndex
            self.currentRadios = self.selectedRadios 
            # self.description = self.currentRadios.values[selectedIndex]
        self.refresh()

    def refreshItemDescriptions(self, lis):
        for i in lis:
            i.description = i.buildItemDescriptionString()
        return lis

    def tuplify(self, listt):
        if len(listt) == 0:
            return [] # should never see this
        newlist=[]
        for i in listt:
            l = []
            l.append(self.unicodify(i.description))
            l.append(self.unicodify(colorItem(i, useGetName=True))) # colors
            newlist.append( tuple(l) )
        return newlist

    def refresh(self, setDescription=False):
        index = self.currentRadios._selected_index
        if setDescription:
            self.description = setDescription
        else:
            self.description = self.currentRadios.values[index][0]
        
        self.application.layout=Layout(
            self.getRootContainer(),
            focused_element=self.currentRadios)
            
        
    def populateMainRadios(self):
        self.mainRadiosRows = []
        self.populateMainRadiosHelper('weapon')
        self.populateMainRadiosHelper('armour')
        self.populateMainRadiosHelper('consumable')
        self.populateMainRadiosHelper('quest')
        self.populateMainRadiosHelper('misc')
        self.mainRadios = RadioList2(
            values=self.mainRadiosRows,
            app = self)

    def populateMainRadiosHelper(self, category):
        s = self.unicodify(self.player.getAllInventoryItemsAsString(_type=category, showEquipped=True))
        if not s == '': 
            tup = []
            tup.append(s)
            if category == 'weapon': tup.append('Weapons')
            else: tup.append(category.capitalize())
            self.mainRadiosRows.append( tuple(tup) )

    def unicodify(self, text):
        if isinstance(text, str):
            return str(text)
        else:
            return text

    def getCurrentlySelectedItem(self):
        return self.listOfItems[self.currentRadios._selected_index]

    # returns new root container (updates text and stuff)
    def getRootContainer(self):
        statsWidth = 20
        largerWidth = 40
        smallerWidth = 30
        if self.currentRadios != self.mainRadios: descriptionTitle = colorItem(self.getCurrentlySelectedItem())
        else: descriptionTitle = FormattedText([('#ffffff', "Description")])
        actionsTitle = FormattedText([('#ffffff', "Inventory")])
        stats = FormattedText([('#ffffff', "Stats")])
        desc = wrap(self.description, largerWidth-2)
        root_container = VSplit([
            HSplit([
                Dialog(
                    title=actionsTitle,
                    body=HSplit([
                        self.currentRadios,
                    ], )
                ),
            ], padding=0, width = smallerWidth, ),
            HSplit([
                Dialog(
                    title = descriptionTitle,
                    body=Label(desc),
                ),
            ], padding=0, width = largerWidth, ),
            HSplit([
                Dialog(
                    title = stats,
                    body=Label(getStats(self.player)),
                    
                ),
            ], padding=0, width=statsWidth ),
        ])
        return root_container 

    def run(self):
        self.application.run()

    def done(self, result="hit escape"):
        self.result = result
        get_app().exit(result=self.result)
 
# TODO:
# colors
예제 #43
0
    def __init__(self, vi_mode=False, style=None, search_text=None,
                 titlebar_tokens=None):
        assert isinstance(vi_mode, bool)
        assert style is None or isinstance(style, Style)

        self.sources = []
        self.current_source_index = 0  # Index in `self.sources`.
        self.highlight_search = True
        self.in_colon_mode = False
        self.message = None
        self.displaying_help = False
        self.search_text = search_text
        self.display_titlebar = bool(titlebar_tokens)
        self.titlebar_tokens = titlebar_tokens or []

        self._dummy_source = DummySource()

        # When this is True, always make sure that the cursor goes to the
        # bottom of the visible content. This is similar to 'tail -f'.
        self.forward_forever = False

        # Status information for all sources. Source -> _SourceInfo.
        # (Remember this info as long as the Source object exists.)
        self.source_info = weakref.WeakKeyDictionary()

        # Create prompt_toolkit stuff.

        def open_file(buff):
            # Open file.
            self.open_file(buff.text)

            # Focus main buffer again.
            buff.reset()

        # Buffer for the 'Examine:' input.
        self.examine_buffer = Buffer(
            name='EXAMINE',
            completer=PathCompleter(expanduser=True),
            accept_handler=open_file,
            multiline=False)

        # Search buffer.
        self.search_buffer = Buffer(multiline=False)

        self.layout = PagerLayout(self)

        bindings = create_key_bindings(self)
        self.application = Application(
            input=create_input(sys.stdout),
            layout=Layout(container=self.layout.container),
            enable_page_navigation_bindings=True,
            key_bindings=bindings,
            style=style or Style.from_dict(ui_style),
            mouse_support=True,
            after_render=self._after_render,
            full_screen=True)

        # Hide message when a key is pressed.
        def key_pressed(_):
            self.message = None
        self.application.key_processor.before_key_press += key_pressed

        if vi_mode:
            self.application.editing_mode = EditingMode.VI
예제 #44
0
class ProgressBar(object):
    """
    Progress bar context manager.

    Usage ::

        with ProgressBar(...) as pb:
            for item in pb(data):
                ...

    :param title: Text to be displayed above the progress bars. This can be a
        callable or formatted text as well.
    :param formatters: List of :class:`.Formatter` instances.
    :param bottom_toolbar: Text to be displayed in the bottom toolbar. This
        can be a callable or formatted text.
    :param style: :class:`prompt_toolkit.styles.BaseStyle` instance.
    :param key_bindings: :class:`.KeyBindings` instance.
    :param file: The file object used for rendering, by default `sys.stderr` is used.

    :param color_depth: `prompt_toolkit` `ColorDepth` instance.
    :param output: :class:`~prompt_toolkit.output.Output` instance.
    :param input: :class:`~prompt_toolkit.input.Input` instance.
    """
    def __init__(self, title=None, formatters=None, bottom_toolbar=None,
                 style=None, key_bindings=None, file=None, color_depth=None,
                 output=None, input=None):
        assert formatters is None or (
            isinstance(formatters, list) and all(isinstance(fo, Formatter) for fo in formatters))
        assert style is None or isinstance(style, BaseStyle)
        assert key_bindings is None or isinstance(key_bindings, KeyBindings)

        self.title = title
        self.formatters = formatters or create_default_formatters()
        self.bottom_toolbar = bottom_toolbar
        self.counters = []
        self.style = style
        self.key_bindings = key_bindings

        # Note that we use __stderr__ as default error output, because that
        # works best with `patch_stdout`.
        self.color_depth = color_depth
        self.output = output or create_output(stdout=file or sys.__stderr__)
        self.input = input or get_default_input()

        self._thread = None

        self._loop = get_event_loop()
        self._previous_winch_handler = None
        self._has_sigwinch = False

    def __enter__(self):
        # 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):
            # 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(
            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,
            color_depth=self.color_depth,
            output=self.output,
            input=self.input)

        # Run application in different thread.
        def run():
            with _auto_refresh_context(self.app, .3):
                try:
                    self.app.run()
                except BaseException as e:
                    traceback.print_exc()
                    print(e)

        self._thread = threading.Thread(target=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 = self._loop.add_signal_handler(
                signal.SIGWINCH, self.app.invalidate)

        return self

    def __exit__(self, *a):
        # Quit UI application.
        if self.app.is_running:
            self.app.exit()

        # Remove WINCH handler.
        if self._has_sigwinch:
            self._loop.add_signal_handler(signal.SIGWINCH, self._previous_winch_handler)

        self._thread.join()

    def __call__(self, data=None, label='', remove_when_done=False, total=None):
        """
        Start a new counter.

        :param label: Title text or description for this progress. (This can be
            formatted text as well).
        :param remove_when_done: When `True`, hide this progress bar.
        :param total: Specify the maximum value if it can't be calculated by
            calling ``len``.
        """
        assert is_formatted_text(label)
        assert isinstance(remove_when_done, bool)

        counter = ProgressBarCounter(
            self, data, label=label, remove_when_done=remove_when_done, total=total)
        self.counters.append(counter)
        return counter

    def invalidate(self):
        self.app.invalidate()