Events¶
Every element can have Python callbacks attached to its DOM events with
RmlElement.add_event_listener(). The first argument is the event name
as RmlUi spells it – click, mousedown, mouseover, mouseout,
keydown, change, submit, focus, blur, scroll, … –
and the second a callable that receives one RmlEvent.
def on_resume(event):
print("clicked at", event.mouse_x, event.mouse_y)
self.resume_game()
doc.get_element_by_id("resume").add_event_listener("click", on_resume)
Several listeners may be attached to one element; they fire in the order they were added. A listener belongs to the RmlUi element and lives as long as it does, whatever happens to the Python handle that added it.
The event object¶
RmlEvent is valid only for the duration of the callback; read what
you need from it there.
event_type– the name the listener was registered for.get_parameter(),get_parameter_int(),get_parameter_float(),has_parameter()– RmlUi’s event parameters by name:buttonandmouse_x/mouse_yfor mouse events,key_identifierfor key events,valueforchange, and the form’s fields forsubmit.mouse_x,mouse_y– the common case, as properties.get_target_element()– the element the event was dispatched to;get_current_element()– the element whose listener is running, as the event bubbles up the tree. Both are non-owning wrappers, valid during the callback.stop_propagation()– stop the event from bubbling further.
Firing events from code¶
RmlElement.click() dispatches a click on the element as if the user
had clicked it, which is how menus are driven from a gamepad and how tests
press buttons. The listeners run before click returns; what they changed
in the document is laid out on the context’s next update, which the region
performs every frame – a test calls RmlContext.update() itself.
Rules for callbacks¶
A callback runs inside RmlUi’s event dispatch, in the middle of the engine’s frame. Two things must not happen there:
Do not end the program from a callback: no
sys.exit(), nobase.userExit(). Schedule it instead, for example withtaskMgr.doMethodLater(0, ...).Do not destroy the region, context or document that is delivering the event. Set a flag or schedule a task; tear the interface down from there.
Both leave RmlUi mid-dispatch on freed objects. Deferring through the task manager costs one frame and is always safe.
Who gets the click?¶
A shown document with a <body> that covers the region takes every mouse
event over it, so the 3D scene beneath sees nothing. For a HUD that should let
clicks through, give the body pointer-events: none in its style sheet and
let interactive elements opt back in with pointer-events: auto. Code that
handles clicks in the scene can also ask
RmlContext.is_mouse_interacting() whether the pointer is currently over
an interactive part of the interface.