Ok so...
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
[...]
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:
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)
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...