Atlas / Skills / zhanghandong / Makepad 2.0 Events

Makepad 2.0 EventsSAFE

skills/zhanghandong/makepad-2-0-events

Build App with Makepad and AI skills

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
—
Hosts
—
License
—
Stars
748
01

Overview

Build App with Makepad and AI skills

Read from source at commit 7cbc563d4f32OBSERVED · 2026-10-12
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: makepad-2.0-events
description: |
  CRITICAL: Use for Makepad 2.0 event and action handling. Triggers on:
  makepad event, makepad action, MatchEvent, handle_event, handle_actions,
  on_click, on_render, on_return, on_startup, script_eval!, script_apply_eval!,
  button clicked, text changed, slider changed, checkbox toggled,
  Hit, FingerDown, FingerUp, KeyDown, KeyUp, Focus, ids!,
  TextCopy, TextCut, SelectionHandleDrag, PopupDismissed, clipboard, selection,
  IME, ImeAction, popup window events, video inputs, camera events,
  事件, 动作, 点击, 输入, 回调, 交互, 事件处理, 剪贴板, 选择, 弹出窗口
---

# Makepad 2.0 Event & Action System

## Overview

Makepad 2.0 uses a **two-layer event system**:

1. **Splash Layer** -- Inline event handlers written directly in `script_mod!` Splash code
   (`on_click`, `on_render`, `on_return`, `on_startup`). These handle UI interactions
   declaratively inside the script, close to the widget definitions.

2. **Rust Layer** -- The `MatchEvent` trait with `handle_actions`, `handle_timer`,
   `handle_http_response`, etc. These handle business logic, external I/O, and
   anything that needs full Rust power.

Both layers communicate through two bridge macros:
- `script_eval!(cx, { ... })` -- Execute Splash code from Rust (update state, trigger renders)
- `script_apply_eval!(cx, widget_ref, { ... })` -- Patch widget properties from Rust at runtime

---

## 1. Splash Inline Event Handlers

Event handlers are attached directly to widgets inside `script_mod!` blocks. They use
closure syntax with `||` for no arguments or `|arg|` for callbacks that receive a value.

### on_click -- Button/widget click

Fires when the user clicks a button or clickable widget. No arguments for plain buttons,
or `|checked|` for CheckBox which passes the new boolean state.

```splash
// Plain button click
add_button := Button{
    text: "Add"
    on_click: ||{
        let text = ui.todo_input.text()
        if text != "" {
            add_todo(text, "")
            ui.todo_input.set_text("")
        }
    }
}

// CheckBox click with checked state argument
check.on_click: |checked| toggle_todo(i, checked)

// Inline delete with closure capturing loop variable
delete.on_click: || delete_todo(i)

// Calling another widget's click programmatically
clear_done := ButtonFlatter{
    text: "Clear completed"
    on_click: ||{
        todos.retain(|todo| !todo.done)
        ui.todo_list.render()
    }
}
```

### on_render -- Dynamic rendering

Fires when `.render()` is called on the target view. This is the primary mechanism for
dynamic content. The body replaces the previous draw content of the view.

```splash
main_view := View{
    width: Fill
    height: Fill
    on_render: ||{
        counter_label := Label{
            text: "Count: " + state.counter
            draw_text.text_style.font_size: 24
        }
    }
}

// List rendering with for loop and per-item event handlers
todo_list := ScrollYView{
    width: Fill height: Fill
    new_batch: true
    on_render: ||{
        if todos.len() == 0
            EmptyState{}
        else for i, todo in todos {
            TodoItem{
                label.text: todo.text
                check.active: todo.done
                check.on_click: |checked| toggle_todo(i, checked)
                delete.on_click: || delete_todo(i)
            }
        }
    }
    EmptyState{}
}
```

**Key point**: `on_render` is NOT called automatically. You must call `ui.widget_name.render()`
to trigger it. The `new_batch: true` property on a view tells the system to clear previous
draw content before re-rendering.

### on_return -- TextInput enter key

Fires when the user presses Enter/Return inside a TextInput. Commonly used to submit forms.

```splash
todo_input := TextInput{
    width: Fill height: 9. * theme.space_1
    empty_text: "What needs to be done?"
    on_return: || ui.add_button.on_click()
}
```

### on_startup -- App startup

Fires once when the application starts. Defined at the `Root` level. Commonly used
to trigger initial renders.

```splash
ui: Root{
    on_startup: ||{
        ui.main_view.render()
    }
    main_window := Window{
        // ...
    }
}
```

### Event handler capabilities

Inside event handlers you can:
- Call Splash functions: `add_todo(text, "dev")`
- Read widget values: `let text = ui.todo_input.text()`
- Set widget values: `ui.todo_input.set_text("")`
- Trigger re-renders: `ui.todo_list.render()`
- Trigger other widget clicks: `ui.add_button.on_click()`
- Modify state variables: `state.counter += 1`
- Use array methods: `todos.push({text: "new", done: false})`
- Use control flow: `if text != "" { ... }`

---

## 2. Rust Event Handling -- MatchEvent Trait

The `MatchEvent` trait is the Rust-side event dispatcher. It receives platform events
and widget actions through a set of handler methods.

### Core trait definition (from `draw/src/match_event.rs`)

```rust
pub trait MatchEvent {
    // Lifecycle
    fn handle_startup(&mut self, _cx: &mut Cx) {}
    fn handle_shutdown(&mut self, _cx: &mut Cx) {}
    fn handle_foreground(&mut self, _cx: &mut Cx) {}
    fn handle_background(&mut self, _cx: &mut Cx) {}
    fn handle_pause(&mut self, _cx: &mut Cx) {}
    fn handle_resume(&mut self, _cx: &mut Cx) {}

    // Window focus
    fn handle_window_got_focus(&mut self, _cx: &mut Cx, _window_id: &WindowId) {}
    fn handle_window_lost_focus(&mut self, _cx: &mut Cx, _window_id: &WindowId) {}

    // Frame
    fn handle_next_frame(&mut self, _cx: &mut Cx, _e: &NextFrameEvent) {}

    // Widget actions (most commonly used)
    fn handle_action(&mut self, _cx: &mut Cx, _e: &Action) {}
    fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
        for action in actions {
            self.handle_action(cx, action);
        }
    }

    // Input
    fn handle_key_down(&mut self, _cx: &mut Cx, _e: &KeyEvent) {}
    fn handle_key_up(&mut self, _cx: &mut Cx, _e: &KeyEvent) {}
    fn handle_back_pressed(&mut self, _cx: &mut Cx) -> bool { false }

    /
03

Trust audit

SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (1)

LOWInventory / provenance · inv.no_license · CWE-1104
Why it matters. no LICENSE file and no repo licence
Fix. add a licence

Gates applied: no_behavioural_pass, no_license.

Audited 2026-10-12 · audit v0.4.1 · source sha 7cbc563d4f32full audit observations/trust-audit/skill/zhanghandong__makepad-2.0-events.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-127cbc563d4f32SAFEB89first audit
05

Questions

What does the Makepad 2.0 Events skill do?

Build App with Makepad and AI skills

Is Makepad 2.0 Events safe to install?

The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.

What can Makepad 2.0 Events access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (7cbc563d4f32), read on 2026-10-12. The repository is watched, and a new audit runs when it changes — this is the first audit.

Advertisement