Skip to content

Graphik.drawButton re-invokes its callback on every frame the mouse is held over it #22

Description

@dmccoystephenson

Summary

Graphik.drawButton (graphik.py:42-51) invokes its function argument from inside the draw call, guarded only by the mouse's current position and the current state of button 1:

mouse = pygame.mouse.get_pos()
if (xpos + width > mouse[0] > xpos and ypos + height > mouse[1] > ypos):
    click = pygame.mouse.get_pressed()
    if click[0] == 1:
        function()

pygame.mouse.get_pressed() reports whether the button is currently held, not whether a press occurred since the last frame. Because drawButton is called once per frame from a render loop, holding the mouse over the button fires function() once per frame for as long as the button stays down — potentially hundreds of times for a single perceived click.

Scope

drawButton has no caller in this repository today; main.py uses only drawRectangle and drawText. The defect is therefore latent rather than currently observable, but Graphik is presented as a reusable rendering component (see #5, #11), so the first caller written against this method will hit it.

Related

The uncapped render loop tracked in #19 makes the repeat rate unbounded, so the two interact: with a frame cap in place a held click would fire at the cap rate, and without one it fires as fast as the machine can redraw.

Suggested resolution

Edge-detect the press rather than sampling the held state. Two options:

  • Track the previous frame's button state on the Graphik instance and fire only on the up -> down transition.
  • Move click handling out of the draw call entirely and drive it from pygame.MOUSEBUTTONDOWN events, which are already edge-triggered. This fits the event-handler registration surface proposed for RenderWindow in Create a RenderWindow class to manage Pygame initialization #6, and keeps drawButton purely a drawing operation.

The second option is the cleaner separation and is the one recommended here, though it changes the method's signature and so warrants a decision before implementation.

Acceptance criteria

  • A single press-and-hold over a button results in exactly one invocation of the callback.
  • The behavior is covered by a unit test under tests/ with pygame mocked, driving several frames with the button held.

This issue body was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions