Skip to content
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

Navigating back from a nested submenu forgets the widget selection in the parent menu #471

Open
ahmadaal opened this issue Aug 6, 2023 · 2 comments
Labels

Comments

@ahmadaal
Copy link

ahmadaal commented Aug 6, 2023

Environment information
Describe your environment information, such as:

  • OS: MacOS 12.6.3
  • python version: v3.8.17
  • pygame version: v2.2.0
  • pygame-menu version: v4.4.3

Describe the bug
When you have a nested menu structure that is more than one level deep, the parent menu "forgets" which widget was selected before you navigated into a submenu. This means that when you navigate back to the parent, the 0th widget is always selected. This creates a usability issue because the user's selection is not remembered.

To Reproduce
Run the sample code here. This has 2 levels of nesting, and has some extra buttons so that the bug doesn't get hidden because the 0th button itself is the one that should be "remembered" :)

menu
-> sub
  -> sub2

To trigger the bug, press "Sub", and then press "Sub2". Then navigate back by either pressing the "Back" button, or F1. You will see that instead of the selection of the "Sub2" button being remembered, the selection has reset to the "Back" button. I would expect it not to reset like this.

Note that doing only one level of navigation does NOT trigger this bug. Meaning, if you simply press "Sub" and then go back to the root menu, the selection is remembered. I believe this because for the root menu only, self._top == self.

import pygame_menu
import pygame
import pdb


def show():
    pygame.init()
    screen = pygame.display.set_mode((400, 400))
    clock = pygame.time.Clock()
    pygame_menu.controls.KEY_BACK = pygame.K_F1

    menu = pygame_menu.Menu("test", 400, 400)  # the main menu
    sub = pygame_menu.Menu("sub", 400, 400)  # sub is nested under menu
    sub2 = pygame_menu.Menu("sub2", 400, 400)  # sub2 is nested under sub

    # Add "sub" as a link within "menu"
    sub_link = menu.add.menu_link(sub)
    sub.add.button("Back", pygame_menu.events.BACK)

    # Add "sub2" as a link within "sub"
    sub2_link = sub.add.menu_link(sub2)
    sub2.add.button("Back", pygame_menu.events.BACK)

    def opensub(menu=menu, sub=sub, sub2=sub2, sub_link=sub_link):
        print(
            f"BEFORE: current={menu.get_current().get_title()} link_menu={sub_link._menu.get_title()} menu: {menu._index}/{len(menu._widgets)}, sub={sub._index}/{len(sub._widgets)}, sub2={sub2._index}/{len(sub2._widgets)})"
        )

        # pdb.set_trace()
        sub_link.open()
        print(
            f"AFTER: current={menu.get_current().get_title()} link_menu={sub_link._menu.get_title()} menu: {menu._index}/{len(menu._widgets)}, sub={sub._index}/{len(sub._widgets)}, sub2={sub2._index}/{len(sub2._widgets)})"
        )

    def opensub2(menu=menu, sub=sub, sub2=sub2, sub2_link=sub2_link):
        print(
            f"BEFORE: current={menu.get_current().get_title()} link_menu={sub2_link._menu.get_title()} menu: {menu._index}/{len(menu._widgets)}, sub={sub._index}/{len(sub._widgets)}, sub2={sub2._index}/{len(sub2._widgets)})"
        )

        # pdb.set_trace()
        sub2_link.open()
        print(
            f"AFTER: current={menu.get_current().get_title()} link_menu={sub2_link._menu.get_title()} menu: {menu._index}/{len(menu._widgets)}, sub={sub._index}/{len(sub._widgets)}, sub2={sub2._index}/{len(sub2._widgets)})"
        )

    menu.add.button("No-op Button")

    # To see logging/breakpoints replace with:
    # menu.add.button("Sub", opensub)
    menu.add.button("Sub", sub_link.open)

    # To see logging/breakpoints replace with:
    # sub.add.button("Sub2", opensub2)
    sub.add.button("Sub2", sub2_link.open)

    running = True

    while running:
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT or (
                event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE
            ):
                running = False

        screen.fill("black")
        menu.update(events)
        menu.draw(screen)
        pygame.display.flip()
        clock.tick(60)

    pygame.quit()


if __name__ == "__main__":
    show()

Expected behavior
When I navigate into a submenu, and then navigate back out to to the parent, the parent should always remember which widget was selected before the navigation took place.

Additional context
I suspect this bug may be because of this line in _open() in menu.py:3556:
self._current._select(0, 1, SELECT_OPEN, False, update_mouse_position=False)
I won't speculate too much about the purpose of this line of code since I'm not very familiar with the codebase, but if I hack this and change it to self._top._current._select(...) it does seem to fix the issue. I don't know if that's the correct fix though.

It seems that the lines right before attempt to change the current menu to be the one that is about to be opened by doing:

self._top._current = menu._current

but does the following _select() call on self._current (vs self._top._current or even menu._current), which is still the parent menu, thus selecting the 0th widget of the parent menu before opening the child.

And in the root case, self._top == self. Thus setting self._top._current actually sets self._current. Thus self._current IS actually the submenu (not the parent), and thus the submenu is the one who's widget index gets reset.

@ahmadaal ahmadaal added the bug label Aug 6, 2023
@ahmadaal
Copy link
Author

ahmadaal commented Aug 7, 2023

@ppizarror , have any thoughts? :)

@ahmadaal
Copy link
Author

ahmadaal commented Aug 7, 2023

I also wonder if I may just be doing something wrong with how I set up the menu hierarchy...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant