aegirhall / console-menu

A simple Python menu system for building terminal user interfaces.
MIT License
365 stars 58 forks source link

Dynamic Menu Items #83

Open jason-technology opened 1 year ago

jason-technology commented 1 year ago

I am trying to make a menu dynamic, such that menu items can be conditionally displayed.

I have tried using append_item and remove_item within my code.

I can use logic while building the menu, however, the menu rendering is never re-evaluated.

Maybe I just need a command for re-rendering the menu?

If dynamically updating menus is possible, please provide an example that demonstrates.

Jon-117 commented 5 months ago

Hi, @jason-technology. Did you ever figure this one out? Trying to accomplish the similar now.

Was able to get it to refresh after fully exiting the (sub)menu and then re-entering, but having a hell of a time figuring how to refresh when either a.) using a function item or b.) returning to a previous menu.

truthless-dev commented 4 months ago

@Jon-117 - for what it's worth, here's a rough example of how I've been handling this issue in my apps.

from consolemenu import ConsoleMenu, MenuItem

class DynamicMenu(ConsoleMenu):
    """
    ConsoleMenu whose appearance can conditionally change

    Override `.pre_draw()` in your subclasses with the logic needed to rearrange the menu.
    """
    def pre_draw(self) -> None:
        pass

    def draw(self) -> None:
        """
        Do any necessary preparation and then draw the menu
        """
        self.pre_draw()
        super().draw()

class MainMenu(DynamicMenu):
    """
    Application main menu
    """
    def __init__(self) -> None:
        super().__init__(title="Main Menu")
        self.static_item1 = MenuItem("Item 1")
        self.conditional_item = MenuItem("Conditional")
        self.append_item(self.static_item)
        self.show_conditional_item = True
        self.show()

    def pre_draw(self) -> None:
        # Here's where we optionally display or hide the dynamic item,
        # based on `show_conditional_item`, which could be set to True
        # or False by some other method somewhere else in the ap.
        if self.show_conditional_item:
            self.append_item(self.conditional_item)
        else:
            self.remove_item(self.conditional_item)

def main():
    MainMenu()

if __name__ == "__main__":
    main()

I hope that helps. I've actually written some enhancements that should make this particular issue much easier to deal with, but I'm currently waiting on another smaller PR to be reviewed first.