[Solved] Repeat button action on mouse down

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
goldo
Regular
Posts: 127
Joined: Mon Jan 23, 2017 8:23 am
Contact:

[Solved] Repeat button action on mouse down

#1 Post by goldo »

Hi, so I have a couple of buttons that the user can click to increase or decrease a numerical value. I would like to let the player simply hold their mouse button down to keep increasing/decreasing the value instead of clicking repeatedly. But I'm not sure if it's achievable with the behavior of Ren'py buttons.

Is their a built-in way to configure buttons to repeat their action on mouse down?
Last edited by goldo on Fri Apr 05, 2024 10:40 am, edited 1 time in total.


jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Repeat button action on mouse down

#3 Post by jeffster »

goldo wrote: Wed Apr 03, 2024 4:57 pm Hi, so I have a couple of buttons that the user can click to increase or decrease a numerical value. I would like to let the player simply hold their mouse button down to keep increasing/decreasing the value instead of clicking repeatedly. But I'm not sure if it's achievable with the behavior of Ren'py buttons.

Is their a built-in way to configure buttons to repeat their action on mouse down?
We can use "mousedown_1" (left-click started) and "mouseup_1" (left-click ended).
https://www.renpy.org/doc/html/keymap.html

We can connect them to "action" and "alternate" properties of a button.
https://www.renpy.org/doc/html/screens.html#button
(As that documentation says, on a touch-based platform long-press would mean "alternate" action, so I don't know, it might require separate handling).

"Button pressed" can be coded as a screen variable that would run a timer.
https://www.renpy.org/doc/html/screens.html#timer

Example:

Code: Select all

default target = 0

screen hold_it():
    default held = False
    if held:
        timer 0.25 action SetVariable("target", target+1) repeat True

    text "[target]" align (0.5, 0.5)

    button:
        background "#008"
        text "Click and Hold me"
        keysym           'mousedown_1'
        alternate_keysym 'mouseup_1'
        action    SetScreenVariable("held", True)
        alternate SetScreenVariable("held", False)

    button:
        background "#800"
        text "Quit"
        align (1.0, 0.0)
        action Return()

label start:
    call screen hold_it
    "OK [target]"
    jump start

goldo
Regular
Posts: 127
Joined: Mon Jan 23, 2017 8:23 am
Contact:

Re: Repeat button action on mouse down

#4 Post by goldo »

Thank you for your messages, it put me on the right track!

The above implementation has a flaw in that a click anywhere on the screen will increase the value (because keysym doesn't care if you're actually hovering the button). Here is what I came up with:

Code: Select all

screen change_value():
    default v = 0
    default min_v = 0
    default max_v = 100

    default is_pressed = False
    default is_hovered = False

    hbox align 0.5, 0.5:
        textbutton "-" action SetScreenVariable("is_pressed", True) alternate SetScreenVariable("is_pressed", False) keysym 'mousedown_1' alternate_keysym 'mouseup_1' hovered SetScreenVariable("is_hovered", "-") unhovered SetScreenVariable("is_hovered", False)
        text str(v)
        textbutton "+" action SetScreenVariable("is_pressed", True) alternate SetScreenVariable("is_pressed", False)  keysym 'mousedown_1' alternate_keysym 'mouseup_1' hovered SetScreenVariable("is_hovered", "+") unhovered SetScreenVariable("is_hovered", False)

    timer 0.25 repeat True:
        if is_pressed:
            if is_hovered == "+" and v < max_v:
                action SetScreenVariable("v", v+1)
            elif is_hovered == "-" and v > min_v:
                action SetScreenVariable("v", v-1)

label start:
    call screen change_value
    ""
    jump start
Still seems way more complicated than it should be but, hey, it works.

Thank you!


Edit:

Here is a slightly better implementation, abstracting the button to make it reusable in the UI. Still awkward that 'is_pressed' and 'is_hovered' must exist in the parent screen scope, but that's the only way to make it work AFAIK (if you replace 'SetScreenVariable' with 'SetLocalVariable' below, it won't work).

Code: Select all

screen continuous_button:

    default is_pressed = False
    default is_hovered = False

    textbutton _caption:
        action SetScreenVariable("is_pressed", True) keysym 'mousedown_1' 
        alternate SetScreenVariable("is_pressed", False) alternate_keysym 'mouseup_1' 
        hovered SetScreenVariable("is_hovered", _caption)
        unhovered SetScreenVariable("is_hovered", False)
        sensitive _condition

    timer 0.15 repeat True:
        if is_pressed and is_hovered == _caption and _condition:
            action _action

screen change_value():
    default v = 0
    default min_v = 0
    default max_v = 10

    hbox align 0.5, 0.5:
        use continuous_button(_caption="-", _action=SetScreenVariable("v", v-1), _condition= v>min_v)
        text str(v)
        use continuous_button(_caption="+", _action=SetScreenVariable("v", v+1), _condition= v<max_v)

label start:
    call screen change_value
    ""
    jump start

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Repeat button action on mouse down

#5 Post by jeffster »

goldo wrote: Fri Apr 05, 2024 10:38 am The above implementation has a flaw in that a click anywhere on the screen will increase the value (because keysym doesn't care if you're actually hovering the button).
Indeed.
Here is a slightly better implementation, abstracting the button to make it reusable in the UI.
Activation of continuous_button with keyboard can have a side effect: is_pressed becomes True and doesn't return to False when the button_select key is released. To prevent that, we can set

Code: Select all

        alternate_keysym ['mouseup_1', 'keyup_K_RETURN', 'keyup_K_KP_ENTER', 'keyup_K_SELECT']
Then pressing and holding Enter etc works the same way, raising the value until the key is released.

(Of course for keyboard, unlike mouse, the same effect could be achieved easily by using prefix "any").
https://www.renpy.org/doc/html/keymap.html

PS. Another problem is that short single clicks can be "lost" (canceling the timer before it does its job).

goldo
Regular
Posts: 127
Joined: Mon Jan 23, 2017 8:23 am
Contact:

Re: [Solved] Repeat button action on mouse down

#6 Post by goldo »

Thanks! I think adding _action to the list of actions that happen when clicking could fix the latter problem, although you'd need to check for the _condition first in some way to avoid problems.

Post Reply

Who is online

Users browsing this forum: No registered users