makepad-2.0-dsl
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMakepad 2.0 DSL Syntax Skill
Makepad 2.0 DSL 语法技能
Overview
概述
Makepad 2.0 replaced the compile-time macro with the runtime macro, powered by the Splash scripting language. This skill covers the complete DSL syntax, property system, registration patterns, and common pitfalls.
live_design!script_mod!Makepad 2.0 使用运行时的宏替代了编译时的宏,该宏由Splash脚本语言提供支持。本技能涵盖完整的DSL语法、属性系统、注册模式以及常见陷阱。
script_mod!live_design!Key Syntax Rules
核心语法规则
Property Assignment: Colon, NOT Equals
属性赋值:使用冒号,而非等号
key: value // CORRECT - colon syntax
key = value // WRONG - old 1.x syntax, no longer worksProperties are whitespace/newline separated. No commas between siblings.
View{
width: Fill
height: Fit
flow: Down
spacing: 10
padding: 15
}key: value // CORRECT - colon syntax
key = value // WRONG - old 1.x syntax, no longer works属性使用空格/换行分隔,同级属性之间无需逗号。
View{
width: Fill
height: Fit
flow: Down
spacing: 10
padding: 15
}Named Instances: :=
Operator
:=命名实例::=
操作符
:=Use to create addressable, named widget instances:
:=my_button := Button{ text: "Click me" }
title := Label{ text: "Hello" }Named instances are:
- Addressable from Rust code via or
id!(my_button)ids!(my_button) - Overridable via dot-path syntax:
MyTemplate{ title.text: "New text" } - Stored in the script object's (not
vec)map
Regular properties use and go into :
:mapwidth: Fill // regular property -> map
label := Label{} // named child -> vec使用创建可寻址的命名组件实例:
:=my_button := Button{ text: "Click me" }
title := Label{ text: "Hello" }命名实例具备以下特性:
- 可通过Rust代码中的或
id!(my_button)进行寻址ids!(my_button) - 可通过点路径语法覆盖属性:
MyTemplate{ title.text: "New text" } - 存储在脚本对象的中(而非
vec)map
常规属性使用并存储在中:
:mapwidth: Fill // regular property -> map
label := Label{} // named child -> vecMerge Operator: +:
+:合并操作符:+:
+:The operator extends/merges with the parent instead of replacing:
+:draw_bg +: {
color: #f00 // Only overrides color, keeps all other draw_bg properties
}Without , you REPLACE the entire property:
+:draw_bg: { color: #f00 } // REPLACES all of draw_bg - loses hover, border, etc.
draw_bg +: { color: #f00 } // MERGES - only changes color, keeps everything else+:draw_bg +: {
color: #f00 // 仅覆盖color属性,保留draw_bg的其他所有属性
}如果不使用, 会完全替换整个属性:
+:draw_bg: { color: #f00 } // 替换整个draw_bg属性 - 丢失hover、border等样式
draw_bg +: { color: #f00 } // 合并属性 - 仅修改color,保留其他所有内容Dot-Path Shorthand
点路径简写
Dot-path is syntactic sugar for merge:
draw_bg.color: #f00
// is equivalent to:
draw_bg +: { color: #f00 }
draw_text.text_style.font_size: 14
// is equivalent to:
draw_text +: { text_style +: { font_size: 14 } }点路径是合并操作的语法糖:
draw_bg.color: #f00
// 等价于:
draw_bg +: { color: #f00 }
draw_text.text_style.font_size: 14
// 等价于:
draw_text +: { text_style +: { font_size: 14 } }Let Bindings: Local Templates
Let绑定:本地模板
letscript_mod!let MyCard = RoundedView{
width: Fill height: Fit
padding: 16 flow: Down spacing: 8
draw_bg.color: #2a2a3d
draw_bg.border_radius: 8.0
title := Label{ text: "Default Title" draw_text.color: #fff }
body := Label{ text: "" draw_text.color: #aaa }
}
// Instantiate and override:
MyCard{ title.text: "Card 1" body.text: "Content here" }
MyCard{ title.text: "Card 2" body.text: "More content" }IMPORTANT: bindings are LOCAL to the block. They cannot be accessed from other blocks. To share across modules, store in .
letscript_mod!script_mod!mod.widgets.*letscript_mod!let MyCard = RoundedView{
width: Fill height: Fit
padding: 16 flow: Down spacing: 8
draw_bg.color: #2a2a3d
draw_bg.border_radius: 8.0
title := Label{ text: "Default Title" draw_text.color: #fff }
body := Label{ text: "" draw_text.color: #aaa }
}
// 实例化并覆盖属性:
MyCard{ title.text: "Card 1" body.text: "Content here" }
MyCard{ title.text: "Card 2" body.text: "More content" }重要提示:绑定仅在当前块内有效,无法从其他块访问。如需跨模块共享,请存储至。
letscript_mod!script_mod!mod.widgets.*Spread Operator: ..
..扩展操作符:..
..Inherit all properties from another definition:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}继承另一个定义的所有属性:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // 继承DrawQuad的所有属性
}Script Module Structure
脚本模块结构
Basic App Structure
基础应用结构
rust
use makepad_widgets::*;
app_main!(App);
script_mod!{
use mod.prelude.widgets.*
load_all_resources() do #(App::script_component(vm)){
ui: Root{
main_window := Window{
window.inner_size: vec2(800, 600)
body +: {
// UI content here
my_button := Button{ text: "Click" }
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. Register base widgets
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[source] source: ScriptObjectRef, // REQUIRED for Script-derived structs
#[live] ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(ids!(my_button)).clicked(actions) {
log!("Button clicked!");
}
}
}
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}rust
use makepad_widgets::*;
app_main!(App);
script_mod!{
use mod.prelude.widgets.*
load_all_resources() do #(App::script_component(vm)){
ui: Root{
main_window := Window{
window.inner_size: vec2(800, 600)
body +: {
// UI内容写在这里
my_button := Button{ text: "Click" }
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. 先注册基础组件
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[source] source: ScriptObjectRef, // Script派生结构体必须包含该字段
#[live] ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(ids!(my_button)).clicked(actions) {
log!("Button clicked!");
}
}
}
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}Widget Definition Module
组件定义模块
rust
script_mod!{
use mod.prelude.widgets_internal.* // For widget library internals
use mod.widgets.* // Access other registered widgets
// Step 1: Register the Rust struct as a widget base
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
// Step 2: Create a styled variant with default properties
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill
height: Fit
padding: theme.space_2
draw_bg +: {
color: theme.color_bg_app
}
}
}rust
script_mod!{
use mod.prelude.widgets_internal.* // 用于组件库内部开发
use mod.widgets.* // 访问其他已注册组件
// 步骤1:将Rust结构体注册为组件基类
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
// 步骤2:创建带默认属性的样式变体
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill
height: Fit
padding: theme.space_2
draw_bg +: {
color: theme.color_bg_app
}
}
}Registration Patterns
注册模式
Widget Registration
组件注册
For structs that implement the trait:
Widgetrust
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))Rust side:
rust
#[derive(Script, ScriptHook, Widget)]
pub struct MyWidget {
#[source] source: ScriptObjectRef, // REQUIRED
#[walk] walk: Walk,
#[layout] layout: Layout,
#[redraw] #[live] draw_bg: DrawQuad,
#[live] draw_text: DrawText,
#[rust] my_state: i32, // Runtime-only, not exposed to script
}对于实现 trait的结构体:
Widgetrust
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))Rust端代码:
rust
#[derive(Script, ScriptHook, Widget)]
pub struct MyWidget {
#[source] source: ScriptObjectRef, // 必须包含
#[walk] walk: Walk,
#[layout] layout: Layout,
#[redraw] #[live] draw_bg: DrawQuad,
#[live] draw_text: DrawText,
#[rust] my_state: i32, // 仅运行时有效,不暴露给脚本
}Component Registration
组件注册(非组件结构体)
For non-widget structs that need script integration:
rust
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))对于需要脚本集成的非组件结构体:
rust
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))Draw Shader Registration
绘制着色器注册
For custom draw types with shader fields:
rust
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}Rust side:
rust
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
#[deref] draw_super: DrawQuad,
#[live] my_param: f32,
}对于带着色器字段的自定义绘制类型:
rust
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // 继承DrawQuad的属性
}Rust端代码:
rust
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
#[deref] draw_super: DrawQuad,
#[live] my_param: f32,
}Setting Type Defaults
设置类型默认值
rust
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill height: Fit
draw_bg +: { color: theme.color_bg_app }
}rust
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill height: Fit
draw_bg +: { color: theme.color_bg_app }
}Registration Order (CRITICAL)
注册顺序(至关重要)
Widget modules MUST be registered BEFORE UI modules that use them:
rust
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. Base widgets FIRST
crate::my_widgets::script_mod(vm); // 2. Custom widgets SECOND
crate::app_ui::script_mod(vm); // 3. UI using widgets THIRD
App::from_script_mod(vm, self::script_mod) // 4. App component LAST
}
}组件模块必须在使用它们的UI模块之前注册:
rust
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. 先注册基础组件
crate::my_widgets::script_mod(vm); // 2. 再注册自定义组件
crate::app_ui::script_mod(vm); // 3. 最后注册使用组件的UI
App::from_script_mod(vm, self::script_mod) // 4. 最后注册应用组件
}
}Multi-Module Aggregation (lib.rs pattern)
多模块聚合(lib.rs模式)
rust
pub fn script_mod(vm: &mut ScriptVm) {
crate::module_a::script_mod(vm);
crate::module_b::script_mod(vm);
// ... all widget modules
}rust
pub fn script_mod(vm: &mut ScriptVm) {
crate::module_a::script_mod(vm);
crate::module_b::script_mod(vm);
// ... 所有组件模块
}Prelude System
预导入系统
Available Preludes
可用预导入包
| Prelude | Use Case |
|---|---|
| App development - includes all standard widgets |
| Widget library internal development |
| 预导入包 | 使用场景 |
|---|---|
| 应用开发 - 包含所有标准组件 |
| 组件库内部开发 |
Prelude Alias Syntax
预导入别名语法
rust
mod.prelude.widgets = {
..mod.std, // Spread all of mod.std into scope
theme:mod.theme, // Create 'theme' as alias for mod.theme
draw:mod.draw, // Create 'draw' as alias for mod.draw
}Without the alias ( without ), the module is included but has no accessible name.
mod.theme,theme:rust
mod.prelude.widgets = {
..mod.std, // 将mod.std的所有内容扩展到当前作用域
theme:mod.theme, // 创建theme作为mod.theme的别名
draw:mod.draw, // 创建draw作为mod.draw的别名
}如果不使用别名(比如不带前缀),模块会被导入但无法通过名称访问。
mod.theme,theme:Cross-Module Sharing
跨模块共享
The mod
Object is the ONLY Way to Share
modmod
对象是唯一的共享方式
modrust
// In widget_module.rs - export to mod.widgets namespace
script_mod!{
use mod.prelude.widgets_internal.*
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{ ... }
}
// In app_ui.rs - import via mod.widgets
script_mod!{
use mod.prelude.widgets.*
use mod.widgets.* // Now MyWidget is in scope
// ...
MyWidget{}
}use crate.module.*crate.rust
// 在widget_module.rs中 - 导出到mod.widgets命名空间
script_mod!{
use mod.prelude.widgets_internal.*
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{ ... }
}
// 在app_ui.rs中 - 通过mod.widgets导入
script_mod!{
use mod.prelude.widgets.*
use mod.widgets.* // 现在MyWidget已在作用域内
// ...
MyWidget{}
}use crate.module.*crate.Runtime Property Updates
运行时属性更新
Use instead of the old + :
script_apply_eval!apply_overlive!rust
// Old system
item.apply_over(cx, live!{ height: (height) });
// New system - use #(expr) for Rust expression interpolation
script_apply_eval!(cx, item, {
height: #(height)
draw_bg: { is_even: #(if is_even { 1.0 } else { 0.0 }) }
});使用替代旧的 + :
script_apply_eval!apply_overlive!rust
// 旧系统
item.apply_over(cx, live!{ height: (height) });
// 新系统 - 使用#(expr)插值Rust表达式
script_apply_eval!(cx, item, {
height: #(height)
draw_bg: { is_even: #(if is_even { 1.0 } else { 0.0 }) }
});Debug Logging
调试日志
Use to log values during script evaluation:
~expressionrust
script_mod!{
~mod.theme // Logs the theme object
~mod.prelude.widgets // Logs what's in the prelude
~some_variable // Logs a variable's value
}使用在脚本执行期间记录值:
~expressionrust
script_mod!{
~mod.theme // 记录theme对象
~mod.prelude.widgets // 记录预导入包中的内容
~some_variable // 记录变量的值
}Common Pitfalls
常见陷阱
1. Missing #[source] source: ScriptObjectRef
#[source] source: ScriptObjectRef1. 缺少#[source] source: ScriptObjectRef
#[source] source: ScriptObjectRefAll -derived structs MUST have this field:
Scriptrust
#[derive(Script, ScriptHook)]
pub struct MyStruct {
#[source] source: ScriptObjectRef, // REQUIRED - will fail without it
// ...
}所有派生的结构体必须包含该字段:
Scriptrust
#[derive(Script, ScriptHook)]
pub struct MyStruct {
#[source] source: ScriptObjectRef, // 必须包含 - 缺少会导致错误
// ...
}2. Missing height: Fit
on Containers
height: Fit2. 容器组件缺少height: Fit
height: FitDefault height is . In a parent, creates a circular dependency = 0 height = invisible:
FillFitFill// WRONG - invisible!
View{ flow: Down
Label{ text: "You can't see me" }
}
// CORRECT
View{ height: Fit flow: Down
Label{ text: "Visible!" }
}默认高度为。在父容器中,会导致循环依赖,最终高度为0,组件不可见:
FillFitFill// 错误 - 不可见!
View{ flow: Down
Label{ text: "你看不到我" }
}
// 正确
View{ height: Fit flow: Down
Label{ text: "可见!" }
}3. Confusing :
vs :=
::=3. 混淆:
和 :=
::=- -- sets a property (stored in map)
key: value - -- creates a named, addressable child (stored in vec)
name := Widget{} - -- named, overridable via
label := Label{ text: "x" }Template{ label.text: "y" } - -- anonymous, NOT addressable, overrides fail silently
label: Label{ text: "x" }
- -- 设置属性(存储在map中)
key: value - -- 创建可寻址的命名子组件(存储在vec中)
name := Widget{} - -- 命名组件,可通过
label := Label{ text: "x" }覆盖属性Template{ label.text: "y" } - -- 匿名组件,不可寻址,覆盖操作会静默失败
label: Label{ text: "x" }
4. Forgetting +:
Merge Operator
+:4. 忘记使用+:
合并操作符
+:// WRONG - replaces ALL of draw_bg (loses hover, border, animations)
draw_bg: { color: #f00 }
// CORRECT - merges, only changes color
draw_bg +: { color: #f00 }// 错误 - 替换整个draw_bg(丢失hover、border、动画)
draw_bg: { color: #f00 }
// 正确 - 合并属性,仅修改color
draw_bg +: { color: #f00 }5. Wrong Theme Access
5. 主题访问方式错误
// WRONG
color: THEME_COLOR_BG // old 1.x constant syntax
color: (THEME_COLOR_BG) // old 1.x parenthesized reference
// CORRECT
color: theme.color_bg_app
padding: theme.space_2
font_size: theme.font_size_p// 错误
color: THEME_COLOR_BG // 旧1.x常量语法
color: (THEME_COLOR_BG) // 旧1.x括号引用语法
// 正确
color: theme.color_bg_app
padding: theme.space_2
font_size: theme.font_size_p6. Hex Colors Containing 'e' Need #x
Prefix
#x6. 包含'e'的十六进制颜色需要#x
前缀
#xThe Rust tokenizer interprets / in hex literals as scientific notation exponent:
eE// WRONG - Rust parse error: "expected at least one digit in exponent"
color: #2ecc71
color: #1e1e2e
// CORRECT - use #x prefix
color: #x2ecc71
color: #x1e1e2e
// Colors without 'e' work fine with plain #
color: #ff4444 // OK
color: #44cc44 // OKRust分词器会将十六进制字面量中的'e'/'E'解析为科学计数法的指数:
// 错误 - Rust解析错误:"expected at least one digit in exponent"
color: #2ecc71
color: #1e1e2e
// 正确 - 使用#x前缀
color: #x2ecc71
color: #x1e1e2e
// 不含'e'的颜色使用普通#即可
color: #ff4444 // 正常
color: #44cc44 // 正常7. pub
Keyword Invalid in script_mod
pub7. pub
关键字在script_mod中无效
pub// WRONG
pub mod.widgets.MyWidget = ...
// CORRECT - visibility is controlled by Rust module system
mod.widgets.MyWidget = ...// 错误
pub mod.widgets.MyWidget = ...
// 正确 - 可见性由Rust模块系统控制
mod.widgets.MyWidget = ...8. Inset{...}
Constructor Syntax for Margins/Padding
Inset{...}8. 边距/内边距使用Inset{...}
构造函数语法
Inset{...}// WRONG
margin: { left: 10 }
align: { x: 0.5 y: 0.5 }
// CORRECT - use constructor syntax
margin: Inset{ left: 10 }
align: Align{ x: 0.5 y: 0.5 }
padding: Inset{ top: 5 bottom: 5 left: 10 right: 10 }
// Bare number for uniform values is OK
padding: 15
margin: 0.// 错误
margin: { left: 10 }
align: { x: 0.5 y: 0.5 }
// 正确 - 使用构造函数语法
margin: Inset{ left: 10 }
align: Align{ x: 0.5 y: 0.5 }
padding: Inset{ top: 5 bottom: 5 left: 10 right: 10 }
// 统一值可以直接写数字
padding: 15
margin: 0.9. Draw Shader Struct Field Ordering with #[repr(C)]
#[repr(C)]9. 带#[repr(C)]
的绘制着色器结构体字段顺序
#[repr(C)]Non-instance data (, non-instance fields) MUST go BEFORE . Only instance fields (shader inputs) go AFTER:
#[rust]#[live]#[deref]rust
// CORRECT
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
#[live] pub svg: Option<ScriptHandleRef>, // non-instance, BEFORE deref
#[rust] my_state: bool, // non-instance, BEFORE deref
#[deref] pub draw_super: DrawQuad, // contains DrawVars + base instances
#[live] pub tint: Vec4f, // instance field, AFTER deref - OK
}
// WRONG - #[rust] after instance fields corrupts GPU buffer
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
#[deref] pub draw_super: DrawQuad,
#[live] pub tint: Vec4f,
#[rust] my_state: bool, // BAD: between instance fields
}非实例数据(、非实例字段)必须放在之前。只有实例字段(着色器输入)可以放在之后:
#[rust]#[live]#[deref]rust
// 正确
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
#[live] pub svg: Option<ScriptHandleRef>, // 非实例字段,放在deref之前
#[rust] my_state: bool, // 非实例字段,放在deref之前
#[deref] pub draw_super: DrawQuad, // 包含DrawVars和基础实例
#[live] pub tint: Vec4f, // 实例字段,放在deref之后 - 正确
}
// 错误 - #[rust]放在实例字段之间会破坏GPU缓冲区
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
#[deref] pub draw_super: DrawQuad,
#[live] pub tint: Vec4f,
#[rust] my_state: bool, // 错误:位于实例字段之间
}10. No Comments Before First Code in script_mod!
10. script_mod首行不能是注释!
Rust proc macro token stream strips comments, which shifts error positions:
rust
// WRONG
script_mod!{
// This comment shifts error line info
use mod.prelude.widgets.*
}
// CORRECT - start with real code immediately
script_mod!{
use mod.prelude.widgets.*
// Comments after first code are fine
}Rust过程宏的令牌流会移除注释,导致错误位置偏移:
rust
// 错误
script_mod!{
// 该注释会导致错误行号偏移
use mod.prelude.widgets.*
}
// 正确 - 直接以有效代码开头
script_mod!{
use mod.prelude.widgets.*
// 首行代码之后的注释没问题
}Additional Pitfalls
其他陷阱
- Cursor values: Use not
cursor: MouseCursor.Handorcursor: Handcursor: @Hand - Resource paths: Use not
crate_resource("self://path")dep("crate://self/path") - Texture declarations: Use not
tex: texture_2d(float)tex: texture2d - Shader vs
mod: Usemodffor float modulo, NOTmodf(a, b)mod(a, b) - Enum defaults: Use with
default: @offprefix for enum default values@ - DefaultNone derive: Don't use derive; use
DefaultNonewith#[derive(Default)]attribute#[default] - Method chaining in shaders: Use not
.method()(e.g.,::method())Sdf2d.viewport(...) - Color mixing: Prefer chaining over nested
color1.mix(color2, hover)callsmix() - Missing widget registration: Call in
crate::makepad_widgets::script_mod(vm)BEFORE your own modulesApp::run()
- 光标值:使用而非
cursor: MouseCursor.Hand或cursor: Handcursor: @Hand - 资源路径:使用而非
crate_resource("self://path")dep("crate://self/path") - 纹理声明:使用而非
tex: texture_2d(float)tex: texture2d - 着色器中的与
mod:使用modf进行浮点数取模,而非modf(a, b)mod(a, b) - 枚举默认值:枚举默认值使用,带
default: @off前缀@ - DefaultNone派生:不要使用派生;使用
DefaultNone搭配#[derive(Default)]属性#[default] - 着色器中的方法链:使用而非
.method()(例如::method())Sdf2d.viewport(...) - 颜色混合:优先使用链式调用,而非嵌套
color1.mix(color2, hover)调用mix() - 组件注册缺失:在中,调用
App::run()必须早于自定义模块crate::makepad_widgets::script_mod(vm)
Syntax Quick Reference
语法速查
| Old (live_design!) | New (script_mod!) |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 旧语法(live_design!) | 新语法(script_mod!) |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
Reference Files
参考文档
- DSL Syntax Reference -- Complete syntax grammar and examples
- Property System -- Walk, Layout, Draw, and shader properties
- DSL语法参考 -- 完整语法规则与示例
- 属性系统 -- Walk、Layout、Draw及着色器属性说明