MyreMylar / pygame_gui

A GUI system for pygame.
MIT License
678 stars 76 forks source link

Mouse event handling is in drawing Z order when it should be reversed? #609

Open retsyx opened 2 months ago

retsyx commented 2 months ago

Describe the bug

Given two overlapping elements, the bottom element gets precedence for mouse press events, when the topmost element should.

To Reproduce Steps to reproduce the behaviour:

  1. Create two overlapping buttons.
  2. Click the visible button
  3. See that the button underneath gets mouse events, and reports click events.

Expected behaviour Drawing should be back to front (as it is). Event handling should be front to back.

Screenshots

N/A

Platform and software (please complete the following information):

Additional context

Code to reproduce the issue. Prints button click events to stdout.

import pygame
import pygame_gui
from pygame_gui import UIManager
from pygame_gui.elements import UIButton

def main():
    pygame.init()
    resolution = (800, 480)
    btn_rect1 = pygame.Rect((100, 100), (200, 100))
    btn_rect2 = pygame.Rect((200, 100), (200, 100))
    background_surface = pygame.Surface(resolution)
    window_surface = pygame.display.set_mode(resolution,
                            pygame.FULLSCREEN)
    clock = pygame.time.Clock()
    ui_manager = UIManager(resolution)
    background_surface.fill(ui_manager.get_theme().get_colour('dark_bg'))

    btn1 = UIButton(btn_rect1,
                    "Thief",
                    ui_manager,
                    object_id='thief')

    btn2 = UIButton(btn_rect2,
                    "Click me",
                    ui_manager,
                    object_id='visible')

    while True:
        time_delta = clock.tick(30) / 1000.0
        for event in pygame.event.get():
            ui_manager.process_events(event)
            if event.type == pygame_gui.UI_BUTTON_PRESSED:
                print(f'Pressed button {event.ui_element.text}')
        ui_manager.update(time_delta)
        window_surface.blit(background_surface, (0, 0))
        ui_manager.draw_ui(window_surface)
        pygame.display.update()

main()
violet4 commented 1 month ago

It appears that it can be fixed with only this change:

pygame_gui/core/layered_gui_group.py

     def update_visibility(self):
         """
         Update the list of what is currently visible.

         Called when we add or remove elements from the group or when an element is hidden or shown.
         """
         self.visible = [spr.blit_data
-                        for spr in self._spritelist
+                        for spr in self._spritelist
                         if spr.image is not None and spr.visible][::-1]

I've submitted a PR 🤞

@retsyx your test case made it super easy to reproduce and test this! Thank you!

violet4 commented 1 month ago

Well, that's embarrassing. it turns out that my "fix" also changed the draw order. If I really want to submit a PR I should check more carefully 😅️.. going to close my PR for the moment.