bczsalba / pytermgui

Python TUI framework with mouse support, modular widget system, customizable and rapid terminal markup language and more!
https://ptg.bczsalba.com
MIT License
2.25k stars 56 forks source link

[REQUEST] WindowManager.add unexpected behvaiour with slot names #147

Closed guyguy2001 closed 1 month ago

guyguy2001 commented 4 months ago

Is your feature request related to a problem? Please describe. Tl;dr: manager.add(..., assign="Console") turns the slot name to lowercase, unlike the add_slot "constructor", which is unintuitive.

I wanted to structure my app with a console at the bottom (like vscode's default), a main screen, and an inventory to the right. I couldn't find in the documentation how to structure my app's layout, but I found this example on reddit - https://www.reddit.com/r/Python/comments/uot805/detailing_pytermguis_brand_new_layout_system/, so I tried applying it to what I understood. I tried running the following code:

def main3():
    def macro_time(fmt: str) -> str:
        return time.strftime(fmt)

    ptg.tim.define("!time", macro_time)  # type: ignore
    with ptg.WindowManager() as manager:
        manager.layout.add_slot("Header", height=5)
        manager.layout.add_slot("Header Left", width=0.2)

        manager.layout.add_break()

        manager.layout.add_slot("Body", width=0.7)
        manager.layout.add_slot("Body Right")

        manager.layout.add_break()

        manager.layout.add_slot("Console", height=3)

        manager.add(
            ptg.Window("[bold]The current time is:[/]\n\n[!time 75]%c", box="EMPTY"),
            assign="Console",
        )

But it complained that there was no slot named Console:

  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/guy/projects/fl-fangame/fl_fangame/__main__.py", line 3, in <module>
    from fl_fangame.cli import main  # pragma: no cover
  File "/home/guy/projects/fl-fangame/fl_fangame/cli.py", line 10, in <module>
    main3()
  File "/home/guy/projects/fl-fangame/fl_fangame/window.py", line 80, in main3
    with ptg.WindowManager() as manager:
  File "/home/guy/projects/fl-fangame/venv/lib/python3.10/site-packages/pytermgui/window_manager/manager.py", line 121, in __exit__
    raise exception
  File "/home/guy/projects/fl-fangame/fl_fangame/window.py", line 93, in main3
    manager.add(
  File "/home/guy/projects/fl-fangame/venv/lib/python3.10/site-packages/pytermgui/window_manager/manager.py", line 227, in add
    getattr(self.layout, assign).content = window
  File "/home/guy/projects/fl-fangame/venv/lib/python3.10/site-packages/pytermgui/window_manager/layouts.py", line 391, in __getattr__
    raise AttributeError(f"Slot with name {attr!r} could not be found.")
AttributeError: Slot with name 'Console' could not be found.

Only by looking at the source (Layout's __getattr__) did I find that I had to pass it in lowercase - and not like how I passed the slot name when creating it.

In addition, it took me a while to find the assign argument - I didn't find it by ctrl-F ing "Layout" in the documentation, although in hindsight I could have found it by looking at the docstring

Describe the solution you'd like Assuming the features I tried to use aren't too low level:

If the layout feature is lower-level than what I needed, manager.layout should have a docstring warning of that.

There's a very good change I'm missing a lot of the reasons why the current state is good because of how it interacts with the rest of pytermgui, or because layouts aren't supposed to be used by users - but as a TUI beginner trying to jump in by doing, I came out very confused by them.

Describe alternatives you've considered I gave whatever alternatives I thought of in the above section

bczsalba commented 1 month ago

Sorry for the delay, thanks for the detailed report!

Admittedly the snakification of slot names is arbitrary (the only reason it exists is so you can write layout.top_left IIRC), and it should definitely be documented better (which I will do in a moment).

The whole system is a bit confusing all around, so it's not like you're the first person to have issues with it. I'm not sure what could be done to make it simpler to understand, but for what it's worth it is supposed to be a very static, high level system you only really interact with once per application lifetime. I'll consider these points though, and if you have any changes you feel would make it better (be it in code or documentation) I'm open!