| name | robius-event-action |
| description | CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自 |
Robius Event and Action Patterns Skill
Best practices for event handling and action patterns in Makepad applications based on Robrix and Moly codebases.
Source codebases:
- Robrix: Matrix chat client - MessageAction, RoomsListAction, AppStateAction
- Moly: AI chat application - StoreAction, ChatAction, NavigationAction, Timer patterns
Triggers
Use this skill when:
- Implementing custom actions in Makepad
- Handling events in widgets
- Centralizing action handling in App
- Widget-to-widget communication
- Keywords: makepad action, makepad event, widget action, handle_actions, cx.widget_action
Custom Action Pattern
Defining Domain-Specific Actions
use makepad_widgets::*;
#[derive(Clone, DefaultNone, Debug)]
pub enum MessageAction {
React { details: MessageDetails, reaction: String },
Reply(MessageDetails),
Edit(MessageDetails),
Delete(MessageDetails),
OpenContextMenu { details: MessageDetails, abs_pos: DVec2 },
None,
}
#[derive(Clone, Debug)]
pub struct MessageDetails {
pub room_id: OwnedRoomId,
pub event_id: OwnedEventId,
pub content: String,
pub sender_id: OwnedUserId,
}
Emitting Actions from Widgets
impl Widget for Message {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope);
let area = self.view.area();
match event.hits(cx, area) {
Hit::FingerDown(_fe) => {
cx.set_key_focus(area);
}
Hit::FingerUp(fe) => {
if fe.is_over && fe.is_primary_hit() && fe.was_tap() {
cx.widget_action(
self.widget_uid(),
&scope.path,
MessageAction::Reply(self.get_details()),
);
}
}
Hit::FingerLongPress(lpe) => {
cx.widget_action(
self.widget_uid(),
&scope.path,
MessageAction::OpenContextMenu {
details: self.get_details(),
abs_pos: lpe.abs,
},
);
}
_ => {}
}
}
}
Centralized Action Handling in App
Using MatchEvent Trait
impl MatchEvent for App {
fn handle_startup(&mut self, cx: &mut Cx) {
self.initialize(cx);
}
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
for action in actions {
if let Some(action) = action.downcast_ref::<LoginAction>() {
match action {
LoginAction::LoginSuccess => {
self.app_state.logged_in = true;
self.update_ui_visibility(cx);
}
LoginAction::LoginFailure(error) => {
self.show_error(cx, error);
}
}
continue;
}
if let MessageAction::OpenContextMenu { details, abs_pos } =
action.as_widget_action().cast()
{
self.show_context_menu(cx, details, abs_pos);
;
}
action.() {
(AppStateAction::(room)) => {
.app_state.selected_room = (room.());
;
}
(AppStateAction::NavigateToRoom { destination }) => {
.(cx, destination);
;
}
_ => {}
}
action.() {
(ModalAction::Open { kind }) => {
.ui.(ids!(my_modal)).(cx);
;
}
(ModalAction::Close { was_internal }) => {
*was_internal {
.ui.(ids!(my_modal)).(cx);
}
;
}
_ => {}
}
}
}
}
{
(& , cx: & Cx, event: &Event) {
.match_even