prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.13k stars 716 forks source link

Creating and maintaining evenly-spaced columns on full-application #1235

Open mindset-team opened 3 years ago

mindset-team commented 3 years ago

is it possible to create a [vertically] evenly-spaced layout, which stays evenly spaced, even when dynamically changing content of window children?

Below is some sample code. Pressing c injects some content into the two windows' FormattedTextControl's, relative width changes (vertical divider moved with each press..). Columns are not evenly spaced even on initialization on narrow terminal when user_msg instructions are initially displayed (namely, application doesn't even start evenly spaced on a narrow terminal).

from random import randint

from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import VSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.layout.layout import Layout

user_msg = "press 'c' to change, 'q' to quit"

body = VSplit(
    [
        Window(
            FormattedTextControl(text=user_msg),
            width=D(weight=1),
            wrap_lines=True,
        ),
        Window(width=1, char="|"),
        Window(FormattedTextControl(), width=D(weight=1), wrap_lines=True),
    ]
)

kb = KeyBindings()

@kb.add("c")
def change_content(event):
    for w in event.app.layout.find_all_windows():
        prev_width = f"prev_width: {w.render_info.window_width}"
        rand_str = "*" * randint(1, 150)
        w.content.text = "\n".join([prev_width, rand_str])

@kb.add("q")
def quit(event):
    event.app.exit()

layout = Layout(body)
app = Application(layout=layout, key_bindings=kb, full_screen=True)
app.run()
jonathanslenders commented 3 years ago

Hi @mindset-team,

The Window object has an ignore_content_width parameter. This seems to do the job in your case, if you pass it to both windows.

What is harder, is to have evenly spaced columns, where the content is not a Window, but any other Container object. I think at this point, there is no clean way to do that.

I'd probably accept a patch that takes a ignore_content_{width,height} argument in {H,V}Split, and fixes _divide_{widths,heights} to make this work.