Apologies if this has been covered, I could find an answer to this problem researching the forum.
I am trying to implement an inventory system where items could be equipped/unequipped clickly by double-clicking a button (I'm talking about a run-of-the-mill button or imagebutton).
I know alternate allows one to specify a different action for right-clicking. Is there an equivalent for double-clicking? If not, can it be done in another way?
Finally, if double-clicking is impossible to implement or too tricky, is adding shift-clicking (or ctrl-clicking, or whatever...) possible instead?
Double-clicking or shift-clicking a button
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.
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.
Re: Double-clicking or shift-clicking a button
Both are "tricky" indeed. It's not that either way is particularly challenging to implement. It's that there is no clean, smooth and intuitive way of doing so.
Re: Double-clicking or shift-clicking a button
I see...
What's a dirty way then? I imagine something along the line of switching a local variable on the first click, and triggering the event if a second click happens less than a half-second later or something? This would imply setting some sort of timer to reset the variable... I'm not sure how to do that, though.
What's a dirty way then? I imagine something along the line of switching a local variable on the first click, and triggering the event if a second click happens less than a half-second later or something? This would imply setting some sort of timer to reset the variable... I'm not sure how to do that, though.
Re: Double-clicking or shift-clicking a button
It's not "dirty," it's just using an undocumented method.
You write a class that inherits from the Button and instantiates it in the same way. Then you copy event method from the original and try to expand it to do work as you see fit.
But it's both advanced Python and Ren'Py. You could cook something up as you describe but that's not something I'd tolerate in my project. Custom Button or even an entirely new CDD would be my only considerations.
You write a class that inherits from the Button and instantiates it in the same way. Then you copy event method from the original and try to expand it to do work as you see fit.
But it's both advanced Python and Ren'Py. You could cook something up as you describe but that's not something I'd tolerate in my project. Custom Button or even an entirely new CDD would be my only considerations.
Re: Double-clicking or shift-clicking a button
Aw... Those are precisely the areas of Ren'py and python I know nothing about... I could never figure out the underlying concepts of the Renpy screen system...
I can and will teach myself all those concepts over time but if I'm looking for a quick fix, I was wondering if something like this might work:
I'll try it and report on what happens...
I can and will teach myself all those concepts over time but if I'm looking for a quick fix, I was wondering if something like this might work:
Code: Select all
import time
screen mybutton(): # A button which returns True on a double click
default click_time = 0
button:
if time.time() - click_time <= 0.5: # Checks if there was a click less than half a second ago
action (Return(True), SetScreenVariable("click_time", 0)) # SetScreenVariable is there to avoid triple clicks, not sure if that could be an issue
else:
action SetScreenVariable("click_time", time.time())
Re: Double-clicking or shift-clicking a button
Yeah, it doesn't work... ^^
Re: Double-clicking or shift-clicking a button
Ok so...
After a lot of digging, I found this code somewhere in 'renpy/display/behavior.rpy' which seems to govern buttons:
I'm guessing the event method is what I should be looking at. Basically my idea is to create a new class MyButton(Button) which would inherit from this class, and replace the event method.
But... My problem is that I can't understand the code here. Adding double clicking seems like a complex proposition because I don't know how to differenciate a simple click from a double one... Adding shift-clicking "should" be easier I guess... Maybe a variation on 'keysim'?
But this code is mysterious to me:
The 'and' clause seems to imply that it already does what I want (i.e. detect a key + a click), but... It can't be that simple, can it?
*sigh* I've got some experimenting to do...
After a lot of digging, I found this code somewhere in 'renpy/display/behavior.rpy' which seems to govern buttons:
Code: Select all
##############################################################################
# Button
KEY_EVENTS = (
pygame.KEYDOWN,
pygame.KEYUP,
pygame.TEXTEDITING,
pygame.TEXTINPUT
)
class Button(renpy.display.layout.Window):
keymap = { }
action = None
alternate = None
longpress_start = None
longpress_x = None
longpress_y = None
role_parameter = None
keysym = None
alternate_keysym = None
def __init__(self, child=None, style='button', clicked=None,
hovered=None, unhovered=None, action=None, role=None,
time_policy=None, keymap={}, alternate=None,
selected=None, sensitive=None, keysym=None, alternate_keysym=None,
**properties):
[...]
def event(self, ev, x, y, st):
def handle_click(action):
renpy.exports.play(self.style.activate_sound)
rv = run(action)
if rv is not None:
return rv
else:
raise renpy.display.core.IgnoreEvent()
# Call self.action.periodic()
timeout = run_periodic(self.action, st)
if timeout is not None:
renpy.game.interface.timeout(timeout)
# If we have a child, try passing the event to it. (For keyboard
# events, this only happens if we're focused.)
if (not (ev.type in KEY_EVENTS)) or self.style.key_events:
rv = super(Button, self).event(ev, x, y, st)
if rv is not None:
return rv
if (self.keysym is not None) and (self.clicked is not None):
if map_event(ev, self.keysym):
return handle_click(self.clicked)
if (self.alternate_keysym is not None) and (self.alternate is not None):
if map_event(ev, self.alternate_keysym):
return handle_click(self.alternate)
# If not focused, ignore all events.
if not self.is_focused():
return None
# Check the keymap.
for name, action in self.keymap.iteritems():
if map_event(ev, name):
return run(action)
# Handle the longpress event, if necessary.
if (self.alternate is not None) and renpy.display.touch:
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
self.longpress_start = st
self.longpress_x = x
self.longpress_y = y
renpy.game.interface.timeout(renpy.config.longpress_duration)
if self.longpress_start is not None:
if math.hypot(x - self.longpress_x, y - self.longpress_y) > renpy.config.longpress_radius:
self.longpress_start = None
elif st >= (self.longpress_start + renpy.config.longpress_duration):
renpy.exports.vibrate(renpy.config.longpress_vibrate)
renpy.display.interface.after_longpress()
return handle_click(self.alternate)
# Ignore as appropriate:
if (self.clicked is not None) and map_event(ev, "button_ignore"):
raise renpy.display.core.IgnoreEvent()
if (self.clicked is not None) and map_event(ev, "button_alternate_ignore"):
raise renpy.display.core.IgnoreEvent()
# If clicked,
if (self.clicked is not None) and map_event(ev, "button_select"):
return handle_click(self.clicked)
if (self.alternate is not None) and map_event(ev, "button_alternate"):
return handle_click(self.alternate)
return None
[...]
But... My problem is that I can't understand the code here. Adding double clicking seems like a complex proposition because I don't know how to differenciate a simple click from a double one... Adding shift-clicking "should" be easier I guess... Maybe a variation on 'keysim'?
But this code is mysterious to me:
Code: Select all
if (self.keysym is not None) and (self.clicked is not None):
if map_event(ev, self.keysym):
return handle_click(self.clicked)
*sigh* I've got some experimenting to do...
Who is online
Users browsing this forum: No registered users