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)
def main():
    # Create a big layout of many text areas, then wrap them in a `ScrollablePane`.
    root_container = Frame(
        ScrollablePane(
            HSplit([
                Frame(TextArea(text=f"label-{i}"), width=Dimension())
                for i in range(20)
            ]))
        # ScrollablePane(HSplit([TextArea(text=f"label-{i}") for i in range(20)]))
    )

    layout = Layout(container=root_container)

    # Key bindings.
    kb = KeyBindings()

    @kb.add("c-c")
    def exit(event) -> None:
        get_app().exit()

    kb.add("tab")(focus_next)
    kb.add("s-tab")(focus_previous)

    # Create and run application.
    application = Application(layout=layout, key_bindings=kb, full_screen=True)
    application.run()
Exemple #3
0
def main():
    style = Style([
        ('terminal not-focused', '#888888'),
        ('title', 'bg:#000044 #ffffff underline'),
    ])

    done_count = [0]  # nonlocal.

    def done():
        done_count[0] += 1
        if done_count[0] == 2:
            application.exit()
        else:
            switch_focus()

    term1 = Terminal(width=D(preferred=80),
                     height=D(preferred=40),
                     style='class:terminal',
                     done_callback=done)

    term2 = Terminal(width=D(preferred=80),
                     height=D(preferred=40),
                     style='class:terminal',
                     done_callback=done)

    kb = KeyBindings()

    @kb.add('c-w')
    def _(event):
        switch_focus()

    def switch_focus():
        " Change focus when Control-W is pressed."
        if application.layout.has_focus(term1):
            application.layout.focus(term2)
        else:
            application.layout.focus(term1)

    application = Application(
        layout=Layout(container=HSplit([
            Window(
                height=1,
                style='class:title',
                content=FormattedTextControl(
                    HTML(
                        ' Press <u fg="#ff8888"><b>Control-W</b></u> to <b>switch focus</b>.'
                    ))),
            VSplit([
                term1,
                Window(style='bg:#aaaaff', width=1),
                term2,
            ]),
        ]),
                      focused_element=term1),
        style=style,
        key_bindings=kb,
        full_screen=True,
        mouse_support=True,
    )
    application.run()
Exemple #4
0
class TUI:
    def __init__(self, *args, **kwargs):
        self.app = Application(
            layout=layout,
            key_bindings=kbindings(),
            full_screen=True,
            mouse_support=True,
            enable_page_navigation_bindings=True,
        )

    def initialize(self, *args, **kwargs):

        query = kwargs.get("query")
        search_term = kwargs.get("search_term")

        list_buffer = self.app.layout.get_buffer_by_name(LISTVIEW_BUFFER)
        stations.new(*query(search_term))
        list_buffer.update(str(stations))
        display_buffer = self.app.layout.get_buffer_by_name(DISPLAY_BUFFER)

        from asyncio import get_event_loop

        loop = get_event_loop()
        loop.create_task(display_buffer.run())

    def run(self):
        self.app.run()
Exemple #5
0
def cli():
    watcher = YarnWatcher()

    application = Application(layout=create_layout(watcher),
                              key_bindings=kb,
                              full_screen=True,
                              style=style)
    application.run()
Exemple #6
0
def main():
    def done():
        application.exit()

    application = Application(
        layout=Layout(container=Terminal(done_callback=done)),
        full_screen=True,
    )
    application.run()
Exemple #7
0
class TerminalUI:
    def __init__(self, path):
        self.theme = "default"
        sections_list = []
        for section in ["text", "prompt"]:
            sections_list.append(sections[section])

        book = Book(root=path)
        book.parse()
        chapters = book.chapters[1]
        chapters.parse()

        contents = chapters.contents[0]
        render = self.get_label(contents)
        label = Label(merge_formatted_text(render))

        self.container = HSplit(
            [
                VSplit(
                    [
                        sections["menu"],
                        sections["vseparator"],
                        HSplit([label, sections["prompt"]]),
                    ]
                ),
                sections["hseparator"],
                sections["status"],
            ]
        )

    def get_label(self, contents):
        render = []
        for node in contents.children:
            if node.is_terminal:
                text = node.text()
                style = node.tagname
                render.append(to_formatted_text(text, styles[style]))
            else:
                render.extend(self.get_label(node))
        render.append(to_formatted_text("\n", ""))

        return render

    def run(self):
        self.app = Application(
            layout=Layout(self.container),
            key_bindings=get_key_bindings(),
            mouse_support=True,
            full_screen=True,
        )

        self.app.run()
Exemple #8
0
def main():
    style = Style([
        ('terminal focused', 'bg:#aaaaaa'),
        ('title', 'bg:#000044 #ffffff underline'),
    ])

    term1 = Terminal()

    text_area = TextArea(text='Press Control-W to switch focus.\n'
                         'Then you can edit this text area.\n'
                         'Press Control-X to exit')

    kb = KeyBindings()

    @kb.add('c-w')
    def _(event):
        switch_focus()

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

    def switch_focus():
        " Change focus when Control-W is pressed."
        if application.layout.has_focus(term1):
            application.layout.focus(text_area)
        else:
            application.layout.focus(term1)

    application = Application(
        layout=Layout(container=HSplit([
            Window(height=1,
                   style='class:title',
                   content=FormattedTextControl(
                       ' Press Control-W to switch focus.')),
            VSplit([
                term1,
                Window(style='bg:#aaaaff', width=1),
                text_area,
            ]),
        ]),
                      focused_element=term1),
        style=style,
        key_bindings=merge_key_bindings([
            load_key_bindings(),
            kb,
        ]),
        full_screen=True,
        mouse_support=True,
    )
    application.run()
Exemple #9
0
def main():
    # The layout.
    output_field = TextArea(style='class:output-field', text=help_text)
    input_field = TextArea(height=1, prompt='>>> ', style='class:input-field')

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

    # 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()

    @kb.add('enter', filter=has_focus(input_field))
    def _(event):
        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

        output_field.buffer.document = Document(text=new_text,
                                                cursor_position=len(new_text))
        input_field.text = ''

    # 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()
Exemple #10
0
def show_dialog(
    questions,
    title,
    intro=None,
    summary=False,
    next_text='Next',
    previous_text='Previous',
    cancel_text='Cancel',
    finish_text='Finish',
):
    handlers = [get_instance(q) for q in questions]
    app = Application(
        layout=Layout(
            WizardDialog(
                title,
                handlers,
                intro=intro,
                summary=summary,
                next_text=next_text,
                previous_text=previous_text,
                cancel_text=cancel_text,
                finish_text=finish_text,
            ), ),
        mouse_support=True,
        style=for_dialog(),
        full_screen=True,
    )

    if not app.run():
        return
    answers = {}
    for handler in handlers:
        answers.update(handler.get_answer())
    return answers
Exemple #11
0
class Client(object):
    _app: Application
    _keybindings: KeyBindings

    _root_container: HSplit
    _message_text_area: TextArea
    _message_input: TextArea

    _current_channel: disco.types.Channel

    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()

    def _handle_message_entered(self, buffer: Buffer):
        self.send_message(buffer.text)
        buffer.text = ""

    def send_message(self, text):
        self._message_text_area.text += f"{text}\n"

    def get_title(self):
        if not self._current_channel:
            return "No channel selected"
        else:
            return f"{self._current_channel.guild.name} > {self._current_channel.name}"
Exemple #12
0
def main():
    # Create a big layout of many text areas, then wrap them in a `ScrollablePane`.
    root_container = VSplit([
        Label("<left column>"),
        HSplit([
            Label("ScrollContainer Demo"),
            Frame(
                ScrollablePane(
                    HSplit([
                        Frame(
                            TextArea(
                                text=f"label-{i}",
                                completer=animal_completer,
                            )) for i in range(20)
                    ])), ),
        ]),
    ])

    root_container = FloatContainer(
        root_container,
        floats=[
            Float(
                xcursor=True,
                ycursor=True,
                content=CompletionsMenu(max_height=16, scroll_offset=1),
            ),
        ],
    )

    layout = Layout(container=root_container)

    # Key bindings.
    kb = KeyBindings()

    @kb.add("c-c")
    def exit(event) -> None:
        get_app().exit()

    kb.add("tab")(focus_next)
    kb.add("s-tab")(focus_previous)

    # Create and run application.
    application = Application(layout=layout,
                              key_bindings=kb,
                              full_screen=True,
                              mouse_support=True)
    application.run()
Exemple #13
0
def print_container(container):
    """
    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!')))
    """
    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))
    app.run(pre_run=exit_immediately)
Exemple #14
0
 def run(self):
     app = Application(
         layout=Layout(self.container,
                       focused_element=self.container.input_area),
         key_bindings=self.key_bindings,
         style=self.styles,
         mouse_support=False,
         full_screen=True,
     )
     return app.run()
Exemple #15
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()
Exemple #16
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)
Exemple #17
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()
Exemple #18
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()
Exemple #19
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()
Exemple #20
0
def conf_dialog(**kwargs):
    def row(label, default):
        buffer=Buffer()
        buffer.text = default
        return VSplit([
            Label(HTML(f'{label}'), width=10),
            Window(width=2, char=": "),
            Window(content=BufferControl(buffer=buffer)),
        ])
    
    help = Label(HTML(f'(Press {ansired("Tab][Down][Up")} to move cursor. {ansired("Ctrl+C][Esc")} to quit)'))
    rows = [row(k, v) for k, v in kwargs.items()]
    
    root_container = HSplit([
        help,
        Window(height=1, char="-", width=10), 
        *rows
    ])
    kb = KeyBindings()
    
    
    @kb.add("c-c")
    @kb.add("escape")
    def _(event):
        event.app.exit()
    
    @kb.add('tab')
    @kb.add('down')
    def _(event):
        event.app.layout.focus_next()
    
    @kb.add("up")
    def _(event):
        event.app.layout.focus_previous()
    
    @kb.add("enter")
    def _(event):
        data = []
        for child in root_container.children[2:]:
            value = child.children[-1].content.buffer.text
            data.append(value)
        return event.app.exit(data)
    
    
    layout = Layout(root_container)
    
    application = Application(layout=layout, full_screen=False, key_bindings=kb)
    return application.run()  
    
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()
Exemple #22
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()
Exemple #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()
Exemple #24
0
def ui_columns(table_name, all_table_details):
    # Header
    print(column_header.format(header=f"COLUMN DETAILS FOR {table_name}"))

    # Bindings
    bindings = get_key_bindings()

    def add_tables():
        get_app().exit(result="add_tables")

    def end_tables():
        get_app().exit(result="end_tables")

    # column details
    column_names, column_details = get_column_details(table_name, all_table_details)
    # column details container
    (
        column_name_labels,
        column_details_labels,
        column_details_container,
    ) = get_column_details_container(column_names, column_details)

    column_details, column_menu_container_body, column_menu_container = get_column_menu_container(
        table_name,
        all_table_details,
        column_details,
        column_details_labels,
        column_details_container,
        bindings,
    )

    root_container = VSplit(
        width=80,
        children=[
            HSplit(
                padding=1,
                children=[
                    column_details_container,
                    VSplit(height=10, children=[column_menu_container,]),
                    VSplit(
                        children=[
                            Button("Add More Tables", handler=add_tables, width=40),
                            Button("Done", handler=end_tables, width=40),
                        ],
                    ),
                ],
            ),
        ],
    )

    layout = Layout(root_container)

    app = Application(layout=layout, key_bindings=bindings, full_screen=False)

    app.layout.focus(column_menu_container_body)

    table_status = app.run()

    if not table_status:
        abort()

    return table_status, column_details
Exemple #25
0
class Ctui(object):
    """
    Class with commands that users may use at the application prompt.

    Each function representing a command must:
        - start with a do_
        - accept self, input_text, output_text, and event as params
        - return a string to print, None, or False
    Returning a False does nothing, forcing users to correct mistakes
    """

    # User setable variables
    name = 'ctui'
    version = ''  # must be string
    description = 'Curses-like, pure python, cross-platform, as easy as Cmd or click'
    prompt = '> '
    wrap_lines = False  # Wrap lines in main output window or not

    # Settable but defaults are probably sufficient
    welcome = ''  # defaults to 'Welcome to app.name app.version'
    help_message = ''  # defaults to welcome message
    project_folder = ''  # defaults to ~/.app.name on all platforms

    output_text = ''  # used to track current output_text

    # sets various defaults if not overriden with subclass
    def __init__(self, layout=None):
        self.status_dict = {}
        self.commands = Commands()
        register_default_commands(ctui=self)
        self.project_name = 'default'

    @property
    def _welcome(self):
        if self.welcome == '':
            return f'Welcome to {self.name} {self.version}\n{self.description}\n'
        else:
            return self.welcome

    @property
    def _help_message(self):
        if self.help_message == '':
            return f'{self._welcome}\nAvailable commands are:\n\n'
        else:
            return self.help_message

    @property
    def _project_folder(self):
        if self.project_folder == '':
            return f'{Path.home()}/.{self.name}/projects/'
        else:
            return self.project_folder

    @property
    def _project_path(self):
        return f'{self._project_folder}{self.project_name}.{self.name}'

    @property
    def _statusbar(self):
        self.status_dict['Project'] = self.project_name
        return '  '.join([f'{k}: {v}' for k, v in self.status_dict.items()])

    def _init_db(self):
        """setup database storage"""
        self.db = TinyDB(self._project_path)
        self.settings = self.db.table('settings')
        self.storage = self.db.table('storage')
        self.history = self.db.table('history')

    def command(self, func):
        return self.commands.register(func)

    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()

    def _log_and_exit(self):
        date, time = str(datetime.today()).split()
        self.history.insert({
            'Date': date,
            'Time': time.split('.')[0],
            'Command': 'exit'
        })
        self.db.close()
        get_app().exit()

    def exit(self):
        """Graceful shutdown of the prompt_toolkit application"""
        if self._mode == 'term_ui' and self.project_name == 'default':
            yes_no_dialog(title='Warning',
                          text='Exit without saving project?',
                          yes_func=self._log_and_exit)
        else:
            self._log_and_exit()
Exemple #26
0
def run():
    line_cursor_pos = 0
    current_line = 0
    cursor_lock = Lock()
    during_accept = False

    # The layout.
    output_field = TextArea(style="class:output-field")
    input_field = TextArea(
        height=1,
        prompt=" # ",
        style="class:input-field",
        multiline=False,
        wrap_lines=False,
    )

    roll = ['\\', '-', '/', '|']
    current_roll = -1

    def get_statusbar_text():
        nonlocal during_accept, current_roll
        if during_accept:
            if current_roll == 3:
                current_roll = -1
            current_roll = current_roll + 1
            return ' {} Searching...'.format(roll[current_roll])
        else:
            return ' = Nice Translator'

    def get_statusbar_class():
        nonlocal during_accept
        if during_accept:
            return "class:searching-status"
        else:
            return "class:status"

    container = HSplit([
        input_field,
        Window(height=1, char="-", style="class:line"),
        output_field,
        Window(FormattedTextControl(get_statusbar_text),
               height=1,
               style=get_statusbar_class),
    ])

    def addline(old, newline):
        return old + '   {}\n'.format(newline)

    def accept(buff):
        with cursor_lock:
            nonlocal during_accept
            during_accept = True
            nonlocal line_cursor_pos
            nonlocal current_line
            line_cursor_pos = 0
            current_line = 0

            new_text = ''
            if input_field.text.strip() != '':
                try:
                    translate_result = translate.translate(input_field.text)
                    output = ''
                    for rs in translate_result:
                        output = addline(output, rs)
                    text = output
                    text_lines = text.splitlines(keepends=True)
                    for i, l in enumerate(text_lines):
                        if (l.startswith(' > ')):
                            text_lines[i] = '   ' + text_lines[i][3:]
                            break
                    text = ''.join(text_lines)
                    new_text = ' > ' + text[3:]
                except Exception as e:
                    new_text = 'Some error occured.\n{}'.format(e)

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

    def threading_accept(buff):
        l = [buff]
        t = Thread(target=accept, args=l)
        t.start()

    input_field.accept_handler = threading_accept

    # The key bindings.
    kb = KeyBindings()

    # show where the cursor is
    # @kb.add("tab")
    # def _(event):
    #     event.app.layout.focus_next()

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

    # cursor move next line
    @kb.add('escape', 'n')
    def _(event):
        with cursor_lock:
            nonlocal line_cursor_pos
            nonlocal current_line
            new_text = ''
            lines = output_field.text.splitlines(keepends=True)
            if len(lines) == 0 or current_line is len(lines) - 1:
                return
            for i, l in enumerate(lines):
                if i == current_line:
                    lines[i] = '   ' + lines[i][3:]
                    lines[i + 1] = ' > ' + lines[i + 1][3:]
                new_text = new_text + lines[i]
            line_cursor_pos = line_cursor_pos + len(lines[current_line])
            current_line = current_line + 1
            output_field.buffer.document = Document(
                text=new_text, cursor_position=line_cursor_pos)

    # cursor move previous line
    @kb.add('escape', 'm')
    def _(event):
        with cursor_lock:
            nonlocal line_cursor_pos
            nonlocal current_line
            new_text = ''
            lines = output_field.text.splitlines(keepends=True)
            if current_line is 0:
                return
            for i, l in enumerate(lines):
                if i == current_line:
                    lines[i] = '   ' + lines[i][3:]
                    lines[i - 1] = ' > ' + lines[i - 1][3:]
                    break
            for l in lines:
                new_text = new_text + l
            line_cursor_pos = line_cursor_pos - len(lines[current_line - 1])
            current_line = current_line - 1
            output_field.buffer.document = Document(
                text=new_text, cursor_position=line_cursor_pos)

    # Style.
    style = Style([("output-field", ""), ("input-field", ""),
                   ("line", "#ffffff"), ("status", "bg:grey #fff"),
                   ("searching-status", "bg:purple #fff")])

    # Run application.
    application = Application(layout=Layout(container),
                              key_bindings=kb,
                              style=style,
                              full_screen=True,
                              refresh_interval=0.3)

    application.run()
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
Exemple #28
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()
def edit_multiline(default_text=""):
    kb = KeyBindings()

    @kb.add('c-q')
    @kb.add('escape', 'enter')
    def exit_(event):
        """
        Pressing Ctrl-Q, Alt+Enter or Esc + Enter will exit the editor.
        """
        event.app.exit(textf.text)

    @kb.add('c-c')
    def do_copy(event):
        data = textf.buffer.copy_selection()
        get_app().clipboard.set_data(data)

    @kb.add('c-x', eager=True)
    def do_cut(event):
        data = textf.buffer.cut_selection()
        get_app().clipboard.set_data(data)

    @kb.add('c-z')
    def do_undo(event):
        textf.buffer.undo()

    @kb.add('c-y')
    def do_redo(event):
        textf.buffer.redo()

    @kb.add('c-a')
    def do_select_all(event):
        textf.buffer.cursor_position = 0
        textf.buffer.start_selection()
        textf.buffer.cursor_position = len(textf.buffer.text)
        update_stored_pos(None)

    @kb.add('c-v')
    def do_paste(event):
        textf.buffer.paste_clipboard_data(get_app().clipboard.get_data())

    @kb.add('left')
    def kb_left(event):
        textf.buffer.selection_state = None
        if textf.buffer.cursor_position != 0 and textf.text[
                textf.buffer.cursor_position - 1] == '\n':
            textf.buffer.cursor_up()
            textf.buffer.cursor_right(len(textf.text))
        else:
            textf.buffer.cursor_left()
        update_stored_pos(None)

    @kb.add('right')
    def kb_right(event):
        textf.buffer.selection_state = None
        if textf.buffer.cursor_position < len(textf.text) and textf.text[
                textf.buffer.cursor_position] == '\n':
            textf.buffer.cursor_down()
            textf.buffer.cursor_left(len(textf.text))

        else:
            textf.buffer.cursor_right()
        update_stored_pos(None)

    @kb.add('home')
    def kb_home(event):
        textf.buffer.selection_state = None
        width = getTermWidth()
        doc = textf.document
        if textf.buffer.cursor_position == doc._line_start_indexes[
                cursor_row()] + int(cursor_col() / width) * width:
            textf.buffer.cursor_position = doc._line_start_indexes[
                cursor_row()]
        else:
            textf.buffer.cursor_position = doc._line_start_indexes[
                cursor_row()] + int(cursor_col() / width) * width
        update_stored_pos(None)

    @kb.add('end')
    def kb_end(event):
        textf.buffer.selection_state = None
        width = getTermWidth()
        doc = textf.document
        row = cursor_row()
        if textf.buffer.cursor_position == doc._line_start_indexes[row] + (
                int(cursor_col() / width) + 1) * width - 1:
            textf.buffer.cursor_position = doc._line_start_indexes[row] + len(
                doc.current_line)
        else:
            textf.buffer.cursor_position = min(
                doc._line_start_indexes[row] +
                (int(cursor_col() / width) + 1) * width - 1,
                doc._line_start_indexes[row] + len(doc.current_line))
        update_stored_pos(None)

    @kb.add('up')
    def kb_up(event):
        textf.freezestore = True
        width = getTermWidth()
        doc = textf.document
        textf.buffer.selection_state = None
        col = cursor_col()
        row = cursor_row()
        if width > 9000:  # A failsafe in case the terminal size is incorrectly detected
            textf.buffer.cursor_up()
            return

        if col >= width:  # Move one row up staying on the same line
            textf.buffer.cursor_position = doc._line_start_indexes[row] + int(
                col / width - 1) * width + textf.stored_cursor_pos
        elif row >= 1:  # Moving up to a different line
            prevlinelen = len(doc.lines[row - 1])

            textf.buffer.cursor_position = min(
                doc._line_start_indexes[row] - 1,
                doc._line_start_indexes[row - 1] +
                int(prevlinelen / width) * width + textf.stored_cursor_pos)
        else:  # Cursor is on the first row of first line
            textf.buffer.cursor_position = 0
            textf.freezestore = False
            update_stored_pos(None)

    @kb.add('down')
    def kb_down(event):
        textf.freezestore = True
        width = getTermWidth()
        doc = textf.document
        textf.buffer.selection_state = None
        col = cursor_col()
        row = cursor_row()
        nextlinelen = len(doc.lines[row +
                                    1]) if row < len(doc.lines) - 1 else -1
        if width > 9000:  # A failsafe in case the terminal size is incorrectly detected
            textf.buffer.cursor_down()
            return

        if col <= len(doc.current_line
                      ) - width:  # Move one row down staying on the same line
            textf.buffer.cursor_position = doc._line_start_indexes[row] + int(
                col / width + 1) * width + textf.stored_cursor_pos
        elif nextlinelen < 0:  # Move to the very end
            textf.buffer.cursor_position = len(textf.text)
            textf.freezestore = False
            update_stored_pos(None)
        # Move to the end of the same line the cursor is on
        elif col != len(doc.lines[row]) and textf.stored_cursor_pos >= len(
                doc.lines[row]) - int(len(doc.lines[row]) / width) * width:
            textf.buffer.cursor_position = doc._line_start_indexes[row + 1] - 1
        else:  # Move to a different line
            textf.buffer.cursor_position = min(
                doc._line_start_indexes[row + 1] + nextlinelen,
                doc._line_start_indexes[row + 1] + textf.stored_cursor_pos)

    textf = TextArea()
    bottom_bar_text = FormattedTextControl(
        text=
        '\nCurrently editing. Press Ctrl+Q, Alt+Enter or Esc + Enter to exit.')
    bottom_bar = Window(content=bottom_bar_text)

    root_container = HSplit([
        textf,
        bottom_bar,
    ])

    layout = Layout(root_container)

    app = Application(key_bindings=kb,
                      layout=layout,
                      enable_page_navigation_bindings=True,
                      full_screen=False)
    textf.freezestore = False
    textf.text = default_text
    textf.buffer.cursor_position = len(textf.buffer.text)

    # Find the row the cursor is at
    # My own function, in fear of race conditions
    def cursor_row():
        i = 0
        while i < len(
                textf.document._line_start_indexes
        ) and textf.buffer.cursor_position >= textf.document._line_start_indexes[
                i]:
            i += 1
        return i - 1

    # Find the column the cursor is at
    # There is a built-in function, but I think there's some kind of a race condition if it's used
    def cursor_col():
        i = textf.buffer.cursor_position - 1
        while i >= 0 and textf.text[i] != '\n':
            i -= 1
        return textf.buffer.cursor_position - i - 1

    def update_stored_pos(event):
        if not event:
            textf.freezestore = False
        if textf.freezestore:
            textf.freezestore = False
            return
        width = getTermWidth()
        col = cursor_col()
        textf.stored_cursor_pos = col - int(col / width) * width

    textf.buffer.on_cursor_position_changed += update_stored_pos
    update_stored_pos(None)

    text = app.run()

    clear_lines(1)

    return text
Exemple #30
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
Exemple #31
0
def main():
    """Entrypoint for first interaction with user. Ask user to choose type of pypackage.

    NOTE: We're using python-prompt-toolkit which is both powerful and complicated, so we try to document its use asmuch as possible.
    """
    ############################################################################
    # LIST OF APPLICATIONS
    ############################################################################
    # Here we list out all possible applications we have that will be presented
    # as radio buttons.
    package_radios = RadioList(values=[
        # Tuple format: ("Why is this used? This is presented to the user.")
        ("package_simple", "Simple Python App"),
        # ("package_flask", "Simple Flask App"),
        ("package_blueprints", "Flask App with Blueprints"),
    ])

    ############################################################################
    # KEY BINDINGS
    ############################################################################
    # Key bindings for this applications:
    # * radio buttons use key-bindings of up and down arrows for focus. (comes inbuilt)
    # * radio buttons use key-bindings of Enter to select. (comes inbuilt)
    # * tab and shift tab bindings to shift focus from one frame to the next.
    bindings = KeyBindings()
    bindings.add(Keys.Tab)(focus_next)
    bindings.add(Keys.BackTab)(focus_previous)

    # CTRL-C to quit the prompt-app.
    @bindings.add("c-c")
    def exit_c(event):
        """Ctrl-C to quit."""
        event.app.exit(result=False)

    # End App.
    def exit_app():
        get_app().exit(True)

    ############################################################################
    # Actually application container.
    ############################################################################
    # We use VSplit to not utilize the entire width of the window.
    root_container = VSplit([
        HSplit(
            [
                Frame(
                    title="Choose which package-type do you want?",
                    body=package_radios,
                    width=80,
                ),
                Button("Done", handler=exit_app),
            ],
            padding=1,
        )
    ])

    layout = Layout(root_container)

    app = Application(layout=layout, key_bindings=bindings, full_screen=False)

    ############################################################################
    # Actually application container.
    ############################################################################
    print(main_doc)
    result = app.run()

    if result:
        cli_package.main(package_radios.current_value)
    else:
        print("Aborted!")
        sys.exit(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()
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()
Exemple #34
0
def ui_table():
    print(table_header)
    ############################################################################
    # SETUP BINDINGS
    ############################################################################
    bindings = KeyBindings()
    bindings.add(Keys.Tab)(focus_next)
    bindings.add(Keys.Enter)(focus_next)
    bindings.add(Keys.BackTab)(focus_previous)

    # CTRL-C to quit the prompt-app.
    @bindings.add('c-c')
    def exit_c(event):
        """Ctrl-C to quit."""
        event.app.exit(result=False)

    def table_done():
        get_app().exit(result="table_done")

    ############################################################################
    # TABLE DETAILS
    ############################################################################
    table_name = TextArea(prompt='table_name                    : ', multiline=False)
    column_names = TextArea(prompt='column_names (comma separated): ', multiline=False)
    unique_columns = TextArea(prompt='collectively unique columns   : ', multiline=False)

    root_container = VSplit(
        width=80,
        children=[
            HSplit(
                padding=1,
                children=[
                    Frame(
                        title='Database Table Details:',
                        body=HSplit(
                            width=80,
                            children=[
                                table_name,
                                column_names,
                                unique_columns,
                            ]
                        ),
                    ),
                    VSplit(
                        children=[
                            Button('Done', handler=table_done, width=80),
                        ],
                    ),
                ],
            ),
        ]
    )

    layout = Layout(root_container)

    app = Application(layout=layout,
                      key_bindings=bindings,
                      full_screen=False)

    table_status = app.run()

    if not table_status:
        abort()

    return (table_status, table_name.text, column_names.text, unique_columns.text)
Exemple #35
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)
Exemple #36
0
def _(event: KeyPressEvent) -> None:
    event.app.exit()


application = Application(
    layout=Layout(root_container, focused_element=left_window),
    key_bindings=kb,
    mouse_support=True,
    full_screen=True,
)

o = StringIO()


async def tick():
    for i in range(100):
        print("tick", i, file=o)
        await asyncio.sleep(0.5)


async def redraw():
    while True:
        right_buffer.text = o.getvalue()
        right_buffer.auto_down()
        await asyncio.sleep(0.6)


application.create_background_task(tick())
application.create_background_task(redraw())
application.run()
Exemple #37
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