New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I create a menu? #281

Closed
obeleh opened this Issue May 5, 2016 · 3 comments

Comments

Projects
None yet
2 participants
@obeleh

obeleh commented May 5, 2016

I've got so far as the code below but the cursor is not moving. Am I heading in the wrong direction?

from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import TokenListControl
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.token import Token
from prompt_toolkit.keys import Keys
from prompt_toolkit.filters.utils import to_cli_filter
from prompt_toolkit.application import Application
from prompt_toolkit.shortcuts import create_eventloop
from prompt_toolkit.interface import CommandLineInterface


manager = KeyBindingManager()


def getItemList(cli):
    tokens = []
    for i in range(100):
        tokens.append((Token.Item, str(i)))
        tokens.append((Token.NewLine, '\n'))
    return tokens


@manager.registry.add_binding(Keys.ControlQ, eager=True)
def _(event):
    event.cli.set_return_value(None)

itemsControl = TokenListControl(get_tokens=getItemList, has_focus=True)


@manager.registry.add_binding(Keys.Down, eager=True)
def onArrowDown(cli):
    itemsControl.move_cursor_down(cli)

display_arrows = to_cli_filter(True)

app = Application(
    layout=Window(content=itemsControl, right_margins=[ScrollbarMargin(display_arrows=display_arrows)]),
    buffers={},
    key_bindings_registry=manager.registry,
    mouse_support=True,
    use_alternate_screen=True
)

eventloop = create_eventloop()
cli = CommandLineInterface(application=app, eventloop=eventloop)
cli.run()
@jonathanslenders

This comment has been minimized.

Show comment
Hide comment
@jonathanslenders

jonathanslenders May 5, 2016

Owner

Hi @obeleh,

TokenListControl is not meant to contain a scrollable region of text. It can do that, but it involves a lot of manual work, like keeping track of the cursor position, and defining manual key bindings. Most of the time, I use it when in the UI I need a static control displaying some info, not much or very custom user interaction is desired.

Probably, what you are looking for is a BufferControl. It is a visualisation of the content of a Buffer, and a Buffer has a document that contains the text + cursor position.

from __future__ import unicode_literals
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.interface import CommandLineInterface
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.shortcuts import create_eventloop


manager = KeyBindingManager()

def get_default_text():
    return '\n'.join('%s' % i for i in range(100))


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

app = Application(
    layout=Window(
        content=BufferControl(buffer_name=DEFAULT_BUFFER),
        right_margins=[ScrollbarMargin(display_arrows=True)]),
    buffers={
        DEFAULT_BUFFER: Buffer(
            initial_document=Document(get_default_text(), 0))
    },
    key_bindings_registry=manager.registry,
    mouse_support=True,
    use_alternate_screen=True
)

eventloop = create_eventloop()
try:
    cli = CommandLineInterface(application=app, eventloop=eventloop)
    cli.run(reset_current_buffer=False)
finally:
    eventloop.close()

edit: if you want to make a menu, like a widget to select an item from a list of items, then maybe a TokenListControl could be a solution. I'm using it in the source code of ptpython. In that case, you have to define a variable that defines the current selected item and increase/decrease that in the Up/Down key bindings. Further, use Token.SetCursorPosition to tell the TokenListControl where to put its cursor. The TokenListControl.move_cursor_down is not implemented and does nothing by default, but this is used to have scroll wheel support. The scroll event will be send to the user control which is then responsible for updating the cursor position. Have a look at the ptpython source code for an example.

Owner

jonathanslenders commented May 5, 2016

Hi @obeleh,

TokenListControl is not meant to contain a scrollable region of text. It can do that, but it involves a lot of manual work, like keeping track of the cursor position, and defining manual key bindings. Most of the time, I use it when in the UI I need a static control displaying some info, not much or very custom user interaction is desired.

Probably, what you are looking for is a BufferControl. It is a visualisation of the content of a Buffer, and a Buffer has a document that contains the text + cursor position.

from __future__ import unicode_literals
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.interface import CommandLineInterface
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.shortcuts import create_eventloop


manager = KeyBindingManager()

def get_default_text():
    return '\n'.join('%s' % i for i in range(100))


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

app = Application(
    layout=Window(
        content=BufferControl(buffer_name=DEFAULT_BUFFER),
        right_margins=[ScrollbarMargin(display_arrows=True)]),
    buffers={
        DEFAULT_BUFFER: Buffer(
            initial_document=Document(get_default_text(), 0))
    },
    key_bindings_registry=manager.registry,
    mouse_support=True,
    use_alternate_screen=True
)

eventloop = create_eventloop()
try:
    cli = CommandLineInterface(application=app, eventloop=eventloop)
    cli.run(reset_current_buffer=False)
finally:
    eventloop.close()

edit: if you want to make a menu, like a widget to select an item from a list of items, then maybe a TokenListControl could be a solution. I'm using it in the source code of ptpython. In that case, you have to define a variable that defines the current selected item and increase/decrease that in the Up/Down key bindings. Further, use Token.SetCursorPosition to tell the TokenListControl where to put its cursor. The TokenListControl.move_cursor_down is not implemented and does nothing by default, but this is used to have scroll wheel support. The scroll event will be send to the user control which is then responsible for updating the cursor position. Have a look at the ptpython source code for an example.

@obeleh

This comment has been minimized.

Show comment
Hide comment
@obeleh

obeleh May 5, 2016

Ah thanks :)
How would I highlight the current line?

obeleh commented May 5, 2016

Ah thanks :)
How would I highlight the current line?

@jonathanslenders

This comment has been minimized.

Show comment
Hide comment
@jonathanslenders

jonathanslenders May 5, 2016

Owner

The latest prompt-toolkit (from Github; not on Pypi yet) has a cursorline attribute for the Window.
https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/prompt_toolkit/layout/containers.py#L877

By default, it underlines the current line, but you can style it as you want, by passing in a custom style.

Owner

jonathanslenders commented May 5, 2016

The latest prompt-toolkit (from Github; not on Pypi yet) has a cursorline attribute for the Window.
https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/prompt_toolkit/layout/containers.py#L877

By default, it underlines the current line, but you can style it as you want, by passing in a custom style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment