diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..1d539a54e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,732 @@ + +# Makepad Project Guide + +## Important: When Converting Syntax + +**Always search for existing usage patterns in the NEW crates (widgets, code_editor, studio) before making syntax changes.** The old `widgets` and `live_design!` syntax is deprecated. When unsure about the correct syntax for something, grep for similar usage in `widgets/src/` to find the correct pattern. + +```bash +# Example: find how texture declarations work in new system +grep -r "texture_2d" widgets/src/ +``` + +**Critical: Always use `Name: value` syntax, never `Name = value`.** The old `Key = Value` syntax no longer works. For named widget instances, use `name := Type{...}` syntax. + +## Running UI Programs + +```bash +RUST_BACKTRACE=1 cargo run -p makepad-example-splash --release & PID=$!; sleep 15; kill $PID 2>/dev/null; echo "Process $PID killed" +``` + +## Cargo.toml Setup + +```toml +[package] +name = "makepad-example-myapp" +version = "0.1.0" +edition = "2021" + +[dependencies] +makepad-widgets = { path = "../../widgets" } +``` + + +## Widgets DSL (script_mod!) + +The new DSL uses `script_mod!` macro with runtime script evaluation instead of the old `live_design!` compile-time macros. + +### Imports and App Setup + +```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 + } + } + } + } +} + +impl App { + fn run(vm: &mut ScriptVm) -> Self { + crate::makepad_widgets::script_mod(vm); // Register all widgets + // Platform-specific initialization goes here (e.g., vm.cx().start_stdin_service() for macos) + App::from_script_mod(vm, self::script_mod) + } +} + +#[derive(Script, ScriptHook)] +pub struct App { + #[live] ui: WidgetRef, +} + +impl MatchEvent for App { + fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) { + // Handle widget actions + } +} + +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()); + } +} +``` + +### Available Widgets (widgets/src/lib.rs) + +Core: `View`, `SolidView`, `RoundedView`, `ScrollXView`, `ScrollYView`, `ScrollXYView` +Text: `Label`, `H1`, `H2`, `H3`, `LinkLabel`, `TextInput` +Buttons: `Button`, `ButtonFlat`, `ButtonFlatter` +Toggles: `CheckBox`, `Toggle`, `RadioButton` +Input: `Slider`, `DropDown` +Layout: `Splitter`, `FoldButton`, `FoldHeader`, `Hr` +Lists: `PortalList` +Navigation: `StackNavigation`, `ExpandablePanel` +Overlays: `Modal`, `Tooltip`, `PopupNotification` +Dock: `Dock`, `DockSplitter`, `DockTabs`, `DockTab` +Media: `Image`, `Icon`, `LoadingSpinner` +Special: `FileTree`, `PageFlip`, `CachedWidget` +Window: `Window`, `Root` +Markup: `Html`, `Markdown` (feature-gated) + +### Widget Definition Pattern + +```rust +// Rust struct +#[derive(Script, ScriptHook, Widget)] +pub struct MyWidget { + #[source] source: ScriptObjectRef, // Required for script integration + #[walk] walk: Walk, + #[layout] layout: Layout, + #[redraw] #[live] draw_bg: DrawQuad, + #[live] draw_text: DrawText, + #[rust] my_state: i32, // Runtime-only field +} + +// For widgets with animations, add Animator derive: +#[derive(Script, ScriptHook, Widget, Animator)] +pub struct AnimatedWidget { + #[source] source: ScriptObjectRef, + #[apply_default] animator: Animator, + // ... +} +``` + +### Script Module Structure + +```rust +script_mod!{ + use mod.prelude.widgets_internal.* // For internal widget definitions + use mod.widgets.* // Access other widgets + + // Register base widget (connects Rust struct to script) + mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm)) + + // Create styled variant with defaults + 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 + } + } +} +``` + +### Key Syntax Differences (Old vs New) + +| Old (live_design!) | New (script_mod!) | +|-------------------|-------------------| +| `` | `mod.widgets.BaseWidget{ }` | +| `{{StructName}}` | `#(Struct::register_widget(vm))` | +| `(THEME_COLOR_X)` | `theme.color_x` | +| `` | `theme.font_regular` | +| `instance hover: 0.0` | `hover: instance(0.0)` | +| `uniform color: #fff` | `color: uniform(#fff)` | +| `draw_bg: { }` (replace) | `draw_bg +: { }` (merge) | +| `default: off` | `default: @off` | +| `fn pixel(self)` | `pixel: fn()` | +| `item.apply_over(cx, live!{...})` | `script_apply_eval!(cx, item, {...})` | + +### Runtime Property Updates with script_apply_eval! + +Use `script_apply_eval!` macro to dynamically update widget properties at runtime: +```rust +// Old system (live! macro with apply_over) +item.apply_over(cx, live!{ + height: (height) + draw_bg: {is_even: (if is_even {1.0} else {0.0})} +}); + +// New system (script_apply_eval! macro) +script_apply_eval!(cx, item, { + height: #(height) + draw_bg: {is_even: #(if is_even {1.0} else {0.0})} +}); + +// For colors, use #(color) syntax +let color = self.color_focus; +script_apply_eval!(cx, item, { + draw_bg: { + color: #(color) + } +}); +``` + +Note: In `script_apply_eval!`, use `#(expr)` for Rust expression interpolation instead of `(expr)`. + +### Theme Access + +Always use `theme.` prefix: +```rust +color: theme.color_bg_app +padding: theme.space_2 +font_size: theme.font_size_p +text_style: theme.font_regular +``` + +### Property Merging with `+:` + +The `+:` operator merges with parent instead of replacing: +```rust +mod.widgets.MyButton = mod.widgets.Button{ + draw_bg +: { + color: #f00 // Only overrides color, keeps other draw_bg properties + } +} +``` + +### Shader Instance vs Uniform + +- `instance(value)` - Per-draw-call value (can vary per widget instance) +- `uniform(value)` - Shared across all instances using same shader + +```rust +draw_bg +: { + hover: instance(0.0) // Each button has its own hover state + color: uniform(theme.color_x) // Shared base color + color_hover: instance(theme.color_y) // Per-instance if color varies +} +``` + +### Animator Definition + +```rust +animator: Animator{ + hover: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.1}} + apply: { + draw_bg: {hover: 0.0} + draw_text: {hover: 0.0} + } + } + on: AnimatorState{ + from: {all: Snap} // Instant transition + apply: { + draw_bg: {hover: 1.0} + draw_text: {hover: 1.0} + } + } + } +} +``` + +### Shader Functions + +```rust +draw_bg +: { + pixel: fn() { + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + sdf.box(0.0, 0.0, self.rect_size.x, self.rect_size.y, 4.0) + sdf.fill(self.color.mix(self.color_hover, self.hover)) + return sdf.result + } +} +``` + +Note: Use `.method()` not `::method()` in shaders. + +### Color Mixing (Method Chaining) + +```rust +// Old nested style (avoid) +mix(mix(mix(color1, color2, hover), color3, down), color4, focus) + +// New chained style (preferred) +color1.mix(color2, hover).mix(color3, down).mix(color4, focus) +``` + +### App Structure Pattern + +```rust +script_mod!{ + use mod.prelude.widgets.* + + load_all_resources() do #(App::script_component(vm)){ + ui: Root{ + main_window := Window{ + window.inner_size: vec2(1000, 700) + body +: { + // Your UI here + MyWidget{} + } + } + } + } +} + +impl App { + fn run(vm: &mut ScriptVm) -> Self { + crate::makepad_widgets::script_mod(vm); + // Platform-specific initialization (e.g., vm.cx().start_stdin_service() for macos) + App::from_script_mod(vm, self::script_mod) + } +} + +#[derive(Script, ScriptHook)] +pub struct App { + #[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 ID References + +Use `:=` for named widget instances: +```rust +// In DSL +my_button := Button{text: "Click"} + +// In Rust code +self.ui.button(ids!(my_button)).clicked(actions) +``` + +### Template Definitions in Dock + +Templates inside Dock are local; use `let` bindings at script level for reusable components: +```rust +script_mod!{ + // Reusable at script level + let MyPanel = SolidView{ + width: Fill + height: Fill + // ... + } + + // Use directly + body +: { + MyPanel{} // Works because it's a let binding + } +} +``` + +### Custom Draw Widget Example + +```rust +#[derive(Script, ScriptHook, Widget)] +pub struct CustomDraw { + #[walk] walk: Walk, + #[layout] layout: Layout, + #[redraw] #[live] draw_quad: DrawQuad, + #[rust] area: Area, +} + +impl Widget for CustomDraw { + fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep { + cx.begin_turtle(walk, self.layout); + let rect = cx.turtle().rect(); + self.draw_quad.draw_abs(cx, rect); + cx.end_turtle_with_area(&mut self.area); + DrawStep::done() + } + + fn handle_event(&mut self, _cx: &mut Cx, _event: &Event, _scope: &mut Scope) {} +} +``` + +### Script Object Storage: map vs vec + +In script objects, properties are stored in two different places: +- **`map`**: Contains `key: value` pairs (regular properties) +- **`vec`**: Contains named template items (via `:=` syntax) + +This distinction is important when working with `on_after_apply` or inspecting script objects directly. + +### Templates in List Widgets (PortalList, FlatList) + +In list widgets, named IDs (using `:=`) define **templates** that are stored in the widget's `templates` HashMap. These are NOT regular properties - they go into the script object's vec and are collected via `on_after_apply`. + +```rust +// In script_mod! - defining templates for a list +my_list := PortalList { + // Regular properties (go into struct fields) + width: Fill + height: Fill + scroll_bar: mod.widgets.ScrollBar {} + + // Templates (named with :=) - stored in templates HashMap, NOT struct fields + Item := View { + height: 40 + title := Label { text: "Default" } + } + Header := View { + draw_bg: { color: #333 } + } +} +``` + +The templates are collected in `on_after_apply`: +```rust +impl ScriptHook for PortalList { + fn on_after_apply(&mut self, vm: &mut ScriptVm, apply: &Apply, scope: &mut Scope, value: ScriptValue) { + if let Some(obj) = value.as_object() { + vm.vec_with(obj, |_vm, vec| { + for kv in vec { + if let Some(id) = kv.key.as_id() { + self.templates.insert(id, kv.value); + } + } + }); + } + } +} +``` + +Then used during drawing: +```rust +while let Some(item_id) = list.next_visible_item(cx) { + let item = list.item(cx, item_id, id!(Item)); + item.label(ids!(title)).set_text(cx, &format!("Item {}", item_id)); + item.draw_all(cx, &mut Scope::empty()); +} +``` + +**Key distinction**: Regular properties like `scroll_bar: mod.widgets.ScrollBar {}` are applied directly to struct fields. Template definitions like `Item := View {...}` are stored separately for dynamic instantiation. + +### PortalList Usage + +```rust +#[derive(Script, ScriptHook, Widget)] +pub struct MyList { + #[deref] view: View, +} + +impl Widget for MyList { + fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { + while let Some(item) = self.view.draw_walk(cx, scope, walk).step() { + if let Some(mut list) = item.borrow_mut::() { + list.set_item_range(cx, 0, 100); // 100 items + + while let Some(item_id) = list.next_visible_item(cx) { + let item = list.item(cx, item_id, id!(Item)); + item.label(ids!(title)).set_text(cx, &format!("Item {}", item_id)); + item.draw_all(cx, &mut Scope::empty()); + } + } + } + DrawStep::done() + } +} +``` + +### FileTree Usage + +```rust +impl Widget for FileTreeDemo { + fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { + while self.file_tree.draw_walk(cx, scope, walk).is_step() { + self.file_tree.set_folder_is_open(cx, live_id!(root), true, Animate::No); + // Draw nodes recursively + self.draw_node(cx, live_id!(root)); + } + DrawStep::done() + } +} +``` + +### Registering Custom Draw Shaders + +For custom draw types with shader fields, use `script_shader`: + +```rust +script_mod!{ + use mod.prelude.widgets_internal.* + + // Register custom draw shader + set_type_default() do #(DrawMyShader::script_shader(vm)){ + ..mod.draw.DrawQuad // Inherit from DrawQuad + } + + // Register widget that uses it + mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm)) +} + +#[derive(Script, ScriptHook)] +#[repr(C)] +struct DrawMyShader { + #[deref] draw_super: DrawQuad, + #[live] my_param: f32, +} +``` + +### Registering Components (non-Widget) + +For structs that aren't full widgets but need script registration: + +```rust +script_mod!{ + // For components (not widgets) + mod.widgets.MyComponentBase = #(MyComponent::script_component(vm)) + + // For widgets (implements Widget trait) + mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm)) +} +``` + +### Script Prelude Modules + +Two prelude modules available: +- `mod.prelude.widgets_internal.*` - For internal widget library development +- `mod.prelude.widgets.*` - For app development (includes all widgets) + +```rust +script_mod!{ + // App development - use widgets prelude + use mod.prelude.widgets.* + + // Or for widget library internals + use mod.prelude.widgets_internal.* + use mod.widgets.* +} +``` + +### Default Enum Values + +For enums with a `None` variant that need `Default`, use standard Rust `#[default]` attribute instead of `DefaultNone` derive: + +```rust +// Correct - use #[default] attribute on the None variant +#[derive(Clone, Copy, Debug, PartialEq, Default)] +pub enum MyAction { + SomeAction, + AnotherAction, + #[default] + None, +} + +// Wrong - don't use DefaultNone derive +#[derive(Clone, Copy, Debug, PartialEq, DefaultNone)] // Don't do this +pub enum MyAction { + SomeAction, + None, +} +``` + +### Multi-Module Script Registration Pattern + +When refactoring a multi-file project (like studio) from `live_design!` to `script_mod!`: + +1. **Each widget module** defines its own `script_mod!` that registers to `mod.widgets.*`: +```rust +// In studio_editor.rs +script_mod! { + use mod.prelude.widgets_internal.* + use mod.widgets.* + + mod.widgets.StudioCodeEditorBase = #(StudioCodeEditor::register_widget(vm)) + mod.widgets.StudioCodeEditor = set_type_default() do mod.widgets.StudioCodeEditorBase { + editor := CodeEditor {} + } +} +``` + +2. **The lib.rs** aggregates all widget script_mods: +```rust +pub fn script_mod(vm: &mut ScriptVm) { + crate::module1::script_mod(vm); + crate::module2::script_mod(vm); + // ... all widget modules +} +``` + +3. **The app.rs** calls them in correct order: +```rust +impl App { + fn run(vm: &mut ScriptVm) -> Self { + crate::makepad_widgets::script_mod(vm); // Base widgets first + crate::script_mod(vm); // Your widget modules + crate::app_ui::script_mod(vm); // UI that uses the widgets + App::from_script_mod(vm, self::script_mod) + } +} +``` + +4. **The app_ui.rs** can then use registered widgets: +```rust +script_mod! { + use mod.prelude.widgets.* + // Now StudioCodeEditor is available from mod.widgets + + let EditorContent = View { + editor := StudioCodeEditor {} + } +} +``` + +### Cross-Module Sharing via `mod` Object + +**IMPORTANT**: `use crate.module.*` does NOT work in script_mod. The `crate.` prefix is not available. + +To share definitions between script_mod blocks in different files, store them in the `mod` object: + +```rust +// In app_ui.rs - export to mod.widgets namespace +script_mod! { + use mod.prelude.widgets.* + + // This makes AppUI available as mod.widgets.AppUI + mod.widgets.AppUI = Window{ + // ... + } +} + +// In app.rs - import via mod.widgets +script_mod! { + use mod.prelude.widgets.* + use mod.widgets.* // Now AppUI is in scope + + load_all_resources() do #(App::script_component(vm)){ + ui: Root{ AppUI{} } + } +} +``` + +The `mod` object is the only way to share data between script_mod blocks. + +### Prelude Alias Syntax + +When defining a prelude, use `name:mod.path` to create an alias: +```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 (just `mod.theme,`), the module is included but has no name - you can't access it! + +### Let Bindings are Local + +`let` bindings in script_mod are LOCAL to that script_mod block. They cannot be: +- Accessed from other script_mod blocks +- Used as property values directly (e.g., `content +: MyLetBinding` won't work) + +To use a `let` binding, instantiate it: `MyLetBinding{}` or store it in `mod.*` for cross-module access. + +### Debug Logging with `~` + +Use `~expression` to log the value of an expression during script evaluation: +```rust +script_mod! { + ~mod.theme // Logs the theme object + ~mod.prelude.widgets // Logs what's in the prelude + ~some_variable // Logs a variable's value (or "not found" error) +} +``` + +### Common Pitfalls + +**Widget ID references**: Named widget instances use `:=` in the DSL and plain names in Rust id macros: +- DSL defines `code_block := View { ... }` → Rust uses `id!(code_block)` +- DSL defines `my_button := Button { ... }` → Rust uses `ids!(my_button)` + +1. **Missing `#[source]`**: All Script-derived structs need `#[source] source: ScriptObjectRef` + +2. **Template scope**: Templates defined inside Dock aren't available outside; use `let` at script level + +3. **Uniform vs Instance**: Use `instance()` for per-widget varying colors (like hover states on backgrounds) + +4. **Forgot `+:`**: Without `+:`, you replace the entire property instead of merging + +5. **Theme access**: Always `theme.color_x`, never `THEME_COLOR_X` or `(theme.color_x)` + +6. **Missing widget registration**: Call `crate::makepad_widgets::script_mod(vm)` in `App::run()` before your own `script_mod`. Note: the old `live_design!` system and its crates are archived under `old/` + +7. **Draw shader repr**: Custom draw shaders need `#[repr(C)]` for correct memory layout + +8. **DefaultNone derive**: Don't use `DefaultNone` derive - use standard `#[derive(Default)]` with `#[default]` attribute on the `None` variant + +9. **Script_mod call order**: Widget modules must be registered BEFORE UI modules that use them. Always call `lib.rs::script_mod` before `app_ui::script_mod` + +10. **`pub` keyword invalid in script_mod**: Don't use `pub mod.widgets.X = ...`, just use `mod.widgets.X = ...`. Visibility is controlled by the Rust module system, not script_mod. + +11. **Syntax for Inset/Align/Walk**: Use constructor syntax - `margin: Inset{left: 10}` not `margin: {left: 10}`, `align: Align{x: 0.5 y: 0.5}` not `align: {x: 0.5, y: 0.5}` + +12. **Cursor values**: Use `cursor: MouseCursor.Hand` not `cursor: Hand` or `cursor: @Hand` + +13. **Resource paths**: Use `crate_resource("self://path")` not `dep("crate://self/path")` + +14. **Texture declarations in shaders**: Use `tex: texture_2d(float)` not `tex: texture2d` + +15. **Enums not exposed to script**: Some Rust enums like `PopupMenuPosition::BelowInput` may not be exposed to script. If you get "not found" errors on enum variants, just remove the property and use the default + +17. **Shader `mod` vs `modf`**: The Makepad shader language uses `modf(a, b)` for float modulo, NOT `mod(a, b)`. Similarly, use `atan2(y, x)` not `atan(y, x)` for two-argument arctangent. `atan(x)` (single arg) is also available. `fract(x)` works as expected. + +16. **Draw shader struct field ordering**: In `#[repr(C)]` draw shader structs that extend another draw shader via `#[deref]`, NEVER place `#[rust]` or other non-instance data AFTER `DrawVars` and the instance fields. The system uses an unsafe pointer trick in `DrawVars::as_slice()` that reads contiguously past the end of `dyn_instances` into the subsequent `#[live]` fields. Any non-instance data between `DrawVars` and the instance fields will corrupt the GPU instance buffer. Put all extra data (like `#[rust]`, `#[live]` non-instance fields such as resource handles, booleans, etc.) BEFORE the `#[deref]` field, and only `#[live]` instance fields (the ones that map to shader inputs) AFTER. + ```rust + // CORRECT - non-instance data before deref, instance fields after + #[derive(Script, ScriptHook)] + #[repr(C)] + pub struct MyDrawShader { + #[live] pub svg: Option, // non-instance, BEFORE deref + #[rust] my_state: bool, // non-instance, BEFORE deref + #[deref] pub draw_super: DrawVector, // contains DrawVars + base instance fields + #[live] pub tint: Vec4f, // instance field, AFTER deref - OK + } + + // WRONG - rust data after instance fields breaks the memory layout + #[derive(Script, ScriptHook)] + #[repr(C)] + pub struct MyDrawShader { + #[deref] pub draw_super: DrawVector, + #[live] pub tint: Vec4f, // instance field + #[rust] my_state: bool, // BAD: sits between tint and the next shader's fields + } + ``` + +18. **Don't put comments or blank lines before the first real code in `script!`/`script_mod!`**: Rust's proc macro token stream strips comments entirely — they produce no tokens. This shifts error column/line info because the span tracking starts from the first actual token. Always start with real code (e.g., `use mod.std.assert`) immediately after the opening brace. + +19. **WARNING: Hex colors containing the letter `e` in `script_mod!`**: The Rust tokenizer interprets `e` or `E` in hex color literals as a scientific notation exponent, causing parse errors like `expected at least one digit in exponent`. For example, `#2ecc71` fails because `2e` looks like the start of `2e`. **Use the `#x` prefix** to escape this: write `#x2ecc71` instead of `#x2ecc71`. This applies to any hex color where a digit is immediately followed by `e`/`E` (e.g., `#1e1e2e`, `#4466ee`, `#7799ee`, `#bb99ee`). Colors without `e` (like `#ff4444`, `#44cc44`) work fine with plain `#`. + +20. **Shader enums**: Prefer `match` on enum values with `_ =>` as the catch-all arm, not `if/else` chains over integer-like values. If enum `match` fails in shader compilation, treat it as a compiler bug: add or extend a `platform/script/test` case and fix the shader compiler path instead of rewriting shader logic to `if/else`. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c615b8cb7..518329b0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "ab_glyph_rasterizer" version = "0.1.8" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "accessory" @@ -66,7 +66,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -230,6 +230,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a" +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + [[package]] name = "askar-crypto" version = "0.3.7" @@ -482,7 +491,7 @@ dependencies = [ "hyper-util", "itoa", "matchit", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime", "percent-encoding", "pin-project-lite", @@ -560,7 +569,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr", "clang-sys", "itertools 0.13.0", @@ -569,16 +578,25 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 2.1.1", "shlex", "syn 2.0.106", ] [[package]] -name = "bitflags" -version = "1.3.2" +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -589,6 +607,11 @@ dependencies = [ "serde_core", ] +[[package]] +name = "bitflags" +version = "2.10.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "bitmaps" version = "3.2.1" @@ -704,9 +727,8 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +version = "1.25.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "byteorder" @@ -714,6 +736,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "bytes" version = "1.11.1" @@ -910,6 +937,15 @@ dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "unicode-width", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -923,7 +959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -934,7 +970,7 @@ checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64" dependencies = [ "compression-core", "flate2", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -985,7 +1021,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" dependencies = [ - "unicode-segmentation", + "unicode-segmentation 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1020,7 +1056,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1237,12 +1273,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" -[[package]] -name = "data-url" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" - [[package]] name = "date_header" version = "1.0.5" @@ -1438,7 +1468,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "objc2", ] @@ -1453,15 +1483,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading", -] - [[package]] name = "dotenvy" version = "0.15.7" @@ -1584,7 +1605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1598,15 +1619,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "euclid" -version = "0.22.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" -dependencies = [ - "num-traits", -] - [[package]] name = "event-listener" version = "5.4.1" @@ -1665,7 +1677,7 @@ dependencies = [ "futures-core", "imbl", "pin-project-lite", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1698,15 +1710,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - [[package]] name = "ff" version = "0.13.1" @@ -1739,12 +1742,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" - [[package]] name = "flume" version = "0.11.1" @@ -1921,7 +1918,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite", "pin-utils", "slab", @@ -1939,10 +1936,9 @@ dependencies = [ [[package]] name = "fxhash" version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "byteorder", + "byteorder 1.5.0 (git+https://github.com/makepad/makepad?branch=dev)", ] [[package]] @@ -2088,6 +2084,7 @@ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "num-traits", "zerocopy", ] @@ -2170,6 +2167,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "hilog-sys" version = "0.1.6" @@ -2241,7 +2244,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d347c0de239be20ba0982e4822de3124404281e119ae3e11f5d7425a414e1935" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "pastey", ] @@ -2262,7 +2265,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "150fa4a9462ef926824cf4519c84ed652ca8f4fbae34cb8af045b5cbcaf98822" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2327,7 +2330,7 @@ dependencies = [ "itoa", "pin-project-lite", "pin-utils", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "want", ] @@ -2453,7 +2456,7 @@ dependencies = [ "icu_normalizer_data", "icu_properties", "icu_provider", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "zerovec", ] @@ -2515,7 +2518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "utf8_iter", ] @@ -2529,12 +2532,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "imagesize" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" - [[package]] name = "imbl" version = "6.1.0" @@ -2640,7 +2637,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde", ] @@ -2775,17 +2772,6 @@ dependencies = [ "typewit", ] -[[package]] -name = "kurbo" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62" -dependencies = [ - "arrayvec", - "euclid", - "smallvec", -] - [[package]] name = "language-tags" version = "0.3.2" @@ -2814,7 +2800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.53.4", ] [[package]] @@ -2829,7 +2815,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc", "redox_syscall", ] @@ -2851,7 +2837,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dfa36d52c581e9ec783a7ce2a5e0143da6237be5811a0b3153fedfdbe9f780" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2965,34 +2951,43 @@ dependencies = [ ] [[package]] -name = "makepad-code-editor" +name = "makepad-apple-sys" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-widgets", + "makepad-objc-sys", ] [[package]] -name = "makepad-derive-live" +name = "makepad-base64" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + +[[package]] +name = "makepad-byteorder-lite" +version = "0.1.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + +[[package]] +name = "makepad-code-editor" +version = "2.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-live-id", - "makepad-micro-proc-macro", + "makepad-widgets", ] [[package]] name = "makepad-derive-wasm-bridge" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-proc-macro", ] [[package]] name = "makepad-derive-widget" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "2.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-live-id", "makepad-micro-proc-macro", @@ -3000,97 +2995,63 @@ dependencies = [ [[package]] name = "makepad-draw" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "2.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "ab_glyph_rasterizer", "fxhash", - "makepad-html", + "makepad-gltf", "makepad-live-id", "makepad-platform", - "makepad-rustybuzz", - "makepad-vector", - "png", + "makepad-svg", + "makepad-webp", + "makepad-zune-jpeg", + "makepad-zune-png", + "rustybuzz", "sdfer", - "serde", - "ttf-parser", - "unicode-bidi", + "unicode-bidi 0.3.18 (git+https://github.com/makepad/makepad?branch=dev)", "unicode-linebreak", - "unicode-segmentation", + "unicode-segmentation 1.12.0 (git+https://github.com/makepad/makepad?branch=dev)", ] [[package]] name = "makepad-error-log" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-serde", ] [[package]] -name = "makepad-fonts-chinese-bold" -version = "1.0.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-platform", -] - -[[package]] -name = "makepad-fonts-chinese-bold-2" -version = "1.0.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-platform", -] - -[[package]] -name = "makepad-fonts-chinese-regular" -version = "1.0.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-platform", -] - -[[package]] -name = "makepad-fonts-chinese-regular-2" -version = "1.0.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-platform", -] - -[[package]] -name = "makepad-fonts-emoji" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-platform", -] +name = "makepad-fast-inflate" +version = "0.1.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "makepad-futures" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "makepad-futures-legacy" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] -name = "makepad-html" +name = "makepad-gltf" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-live-id", + "makepad-base64", + "makepad-micro-serde", ] [[package]] -name = "makepad-http" +name = "makepad-html" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-script", + "makepad-live-id", ] [[package]] @@ -3100,46 +3061,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9775cbec5fa0647500c3e5de7c850280a88335d1d2d770e5aa2332b801ba7064" [[package]] -name = "makepad-live-compiler" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +name = "makepad-latex-math" +version = "0.1.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-derive-live", - "makepad-live-tokenizer", - "makepad-math", + "ttf-parser", ] [[package]] name = "makepad-live-id" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-live-id-macros", - "serde", ] [[package]] name = "makepad-live-id-macros" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-proc-macro", ] -[[package]] -name = "makepad-live-tokenizer" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "makepad-live-id", - "makepad-math", - "makepad-micro-serde", -] - [[package]] name = "makepad-math" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-serde", ] @@ -3147,12 +3095,12 @@ dependencies = [ [[package]] name = "makepad-micro-proc-macro" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "makepad-micro-serde" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-live-id", "makepad-micro-serde-derive", @@ -3161,153 +3109,174 @@ dependencies = [ [[package]] name = "makepad-micro-serde-derive" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-proc-macro", ] +[[package]] +name = "makepad-network" +version = "1.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "makepad-apple-sys", + "makepad-futures-legacy", + "makepad-live-id", + "makepad-micro-serde", + "makepad-script", + "windows 0.62.2", +] + [[package]] name = "makepad-objc-sys" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "makepad-platform" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "2.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "bitflags 2.10.0", + "ash", + "bitflags 2.10.0 (git+https://github.com/makepad/makepad?branch=dev)", "hilog-sys", "makepad-android-state", - "makepad-error-log", + "makepad-apple-sys", "makepad-futures", "makepad-futures-legacy", - "makepad-http", "makepad-jni-sys", + "makepad-network", "makepad-objc-sys", - "makepad-shader-compiler", + "makepad-script", "makepad-wasm-bridge", + "makepad-zune-png", + "naga", "napi-derive-ohos", "napi-ohos", "ohos-sys", - "smallvec", + "smallvec 1.15.1 (git+https://github.com/makepad/makepad?branch=dev)", "wayland-client", "wayland-egl", "wayland-protocols", - "windows 0.56.0", - "windows-core 0.56.0", + "windows 0.62.2", + "windows-core 0.62.2", "windows-targets 0.52.6", ] [[package]] -name = "makepad-rustybuzz" -version = "0.8.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" -dependencies = [ - "bitflags 1.3.2", - "bytemuck", - "makepad-ttf-parser", - "smallvec", - "unicode-bidi-mirroring", - "unicode-ccc", - "unicode-properties", - "unicode-script", -] +name = "makepad-regex" +version = "0.1.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "makepad-script" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-error-log", + "makepad-html", "makepad-live-id", "makepad-math", + "makepad-regex", "makepad-script-derive", - "smallvec", + "smallvec 1.15.1 (git+https://github.com/makepad/makepad?branch=dev)", ] [[package]] name = "makepad-script-derive" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-micro-proc-macro", ] [[package]] -name = "makepad-shader-compiler" +name = "makepad-splat" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-live-compiler", + "makepad-micro-serde", + "makepad-webp", + "makepad-zip-file", ] [[package]] -name = "makepad-ttf-parser" -version = "0.21.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" - -[[package]] -name = "makepad-vector" +name = "makepad-svg" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "makepad-ttf-parser", - "resvg", + "makepad-html", + "makepad-live-id", ] [[package]] name = "makepad-wasm-bridge" version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-derive-wasm-bridge", "makepad-live-id", ] +[[package]] +name = "makepad-webp" +version = "0.2.4" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "makepad-byteorder-lite", +] + [[package]] name = "makepad-widgets" -version = "1.0.0" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "2.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-derive-widget", "makepad-draw", - "makepad-fonts-chinese-bold", - "makepad-fonts-chinese-bold-2", - "makepad-fonts-chinese-regular", - "makepad-fonts-chinese-regular-2", - "makepad-fonts-emoji", "makepad-html", - "makepad-zune-jpeg", - "makepad-zune-png", + "makepad-latex-math", + "makepad-splat", "pulldown-cmark 0.12.2", - "serde", - "unicode-segmentation", + "ttf-parser", + "unicode-segmentation 1.12.0 (git+https://github.com/makepad/makepad?branch=dev)", +] + +[[package]] +name = "makepad-zip-file" +version = "1.0.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "makepad-fast-inflate", ] [[package]] name = "makepad-zune-core" -version = "0.2.14" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "0.5.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + +[[package]] +name = "makepad-zune-inflate" +version = "0.2.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "bitflags 2.10.0", + "simd-adler32", ] [[package]] name = "makepad-zune-jpeg" -version = "0.3.17" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "0.5.12" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "makepad-zune-core", ] [[package]] name = "makepad-zune-png" -version = "0.4.10" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +version = "0.5.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "zune-core", - "zune-inflate", + "makepad-zune-core", + "makepad-zune-inflate", ] [[package]] @@ -3442,7 +3411,7 @@ source = "git+https://github.com/matrix-org/matrix-rust-sdk?branch=main#d64c9906 dependencies = [ "as_variant", "async-trait", - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "decancer", "eyeball", "eyeball-im", @@ -3495,7 +3464,7 @@ dependencies = [ "as_variant", "async-trait", "bs58", - "byteorder", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if", "ctr", "eyeball", @@ -3612,7 +3581,7 @@ dependencies = [ "async-rx", "async-stream", "async_cell", - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", "emojis", "eyeball", @@ -3639,7 +3608,7 @@ dependencies = [ "tokio-stream", "tracing", "unicode-normalization", - "unicode-segmentation", + "unicode-segmentation 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3659,7 +3628,7 @@ dependencies = [ "sealed", "serde", "serde-wasm-bindgen", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 2.0.17", "tokio", "wasm-bindgen", @@ -3697,6 +3666,11 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memchr" +version = "2.7.6" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "mime" version = "0.3.17" @@ -3722,7 +3696,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -3746,6 +3719,32 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "naga" +version = "27.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.16.1", + "hexf-parse", + "indexmap 2.13.0", + "libm", + "log", + "num-traits", + "once_cell", + "rustc-hash 1.1.0", + "spirv", + "thiserror 2.0.17", + "unicode-ident", +] + [[package]] name = "napi-derive-backend-ohos" version = "0.0.7" @@ -3780,7 +3779,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad5a3bbb2ae61f345b8c11776f2e79fc2bb71d1901af9a5f81f03c9238a05d86" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ctor", "napi-sys-ohos", "once_cell", @@ -3830,7 +3829,7 @@ version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "minimal-lexical", ] @@ -3855,7 +3854,7 @@ dependencies = [ "num-iter", "num-traits", "rand 0.8.5", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize", ] @@ -3940,7 +3939,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "objc2", "objc2-foundation", ] @@ -3951,7 +3950,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "dispatch2", "objc2", ] @@ -3978,7 +3977,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "objc2", "objc2-core-foundation", ] @@ -3989,7 +3988,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "block2", "objc2", "objc2-foundation", @@ -4025,7 +4024,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if", "foreign-types", "libc", @@ -4118,7 +4117,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "windows-targets 0.52.6", ] @@ -4226,12 +4225,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -4271,19 +4264,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - [[package]] name = "poly1305" version = "0.8.0" @@ -4421,13 +4401,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "bitflags 2.10.0", - "memchr", - "pulldown-cmark-escape", - "unicase", + "bitflags 2.10.0 (git+https://github.com/makepad/makepad?branch=dev)", + "memchr 2.7.6 (git+https://github.com/makepad/makepad?branch=dev)", + "unicase 2.9.0", ] [[package]] @@ -4436,10 +4414,10 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "bitflags 2.10.0", - "memchr", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark-escape", - "unicase", + "unicase 2.8.1", ] [[package]] @@ -4448,15 +4426,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.9" @@ -4468,7 +4437,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "socket2", "thiserror 2.0.17", @@ -4489,7 +4458,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "slab", @@ -4623,7 +4592,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4664,7 +4633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata", "regex-syntax", ] @@ -4676,7 +4645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax", ] @@ -4734,20 +4703,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "resvg" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944d052815156ac8fa77eaac055220e95ba0b01fa8887108ca710c03805d9051" -dependencies = [ - "log", - "pico-args", - "rgb", - "svgtypes", - "tiny-skia", - "usvg", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -4758,15 +4713,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rgb" -version = "0.8.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" -dependencies = [ - "bytemuck", -] - [[package]] name = "ring" version = "0.17.14" @@ -4787,7 +4733,7 @@ version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" dependencies = [ - "byteorder", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits", "paste", ] @@ -4798,7 +4744,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" dependencies = [ - "byteorder", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rmp", "serde", ] @@ -4871,7 +4817,7 @@ version = "0.0.1-pre-alpha-4" dependencies = [ "anyhow", "aws-lc-rs", - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "blurhash", "bytesize", "chrono", @@ -4909,16 +4855,10 @@ dependencies = [ "tokio", "tracing-subscriber", "tsp_sdk", - "unicode-segmentation", + "unicode-segmentation 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "url", ] -[[package]] -name = "roxmltree" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" - [[package]] name = "rsa" version = "0.9.10" @@ -5113,14 +5053,20 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -5142,11 +5088,11 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5214,6 +5160,22 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rustybuzz" +version = "0.18.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "bitflags 2.10.0 (git+https://github.com/makepad/makepad?branch=dev)", + "bytemuck", + "makepad-error-log", + "smallvec 1.15.1 (git+https://github.com/makepad/makepad?branch=dev)", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties 0.1.4", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.20" @@ -5301,7 +5263,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdfer" version = "0.2.1" -source = "git+https://github.com/makepad/makepad?branch=dev#2898fb1367a95385df79141cd765bf8cf0719b8d" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "sealed" @@ -5333,7 +5295,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5346,7 +5308,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -5449,7 +5411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_core", "zmij", @@ -5599,18 +5561,8 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simplecss" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" -dependencies = [ - "log", -] +version = "0.3.8" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "siphasher" @@ -5633,6 +5585,11 @@ dependencies = [ "serde", ] +[[package]] +name = "smallvec" +version = "1.15.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "socket2" version = "0.6.0" @@ -5652,6 +5609,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spki" version = "0.7.3" @@ -5694,13 +5660,13 @@ dependencies = [ "hashlink", "indexmap 2.13.0", "log", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell", "percent-encoding", "serde", "serde_json", "sha2 0.10.9", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -5751,8 +5717,8 @@ source = "git+https://github.com/project-robius/sqlx.git?branch=update_libsqlite dependencies = [ "atoi", "base64", - "bitflags 2.10.0", - "byteorder", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes", "chrono", "crc", @@ -5770,7 +5736,7 @@ dependencies = [ "itoa", "log", "md-5", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell", "percent-encoding", "rand 0.8.5", @@ -5778,7 +5744,7 @@ dependencies = [ "serde", "sha1", "sha2 0.10.9", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "sqlx-core", "stringprep", "thiserror 2.0.17", @@ -5793,8 +5759,8 @@ source = "git+https://github.com/project-robius/sqlx.git?branch=update_libsqlite dependencies = [ "atoi", "base64", - "bitflags 2.10.0", - "byteorder", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", "crc", "dotenvy", @@ -5809,13 +5775,13 @@ dependencies = [ "itoa", "log", "md-5", - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell", "rand 0.8.5", "serde", "serde_json", "sha2 0.10.9", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "sqlx-core", "stringprep", "thiserror 2.0.17", @@ -5853,15 +5819,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -dependencies = [ - "float-cmp", -] - [[package]] name = "string_cache" version = "0.8.9" @@ -5893,9 +5850,9 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "unicode-bidi", + "unicode-bidi 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization", - "unicode-properties", + "unicode-properties 0.1.3", ] [[package]] @@ -5910,16 +5867,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "svgtypes" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" -dependencies = [ - "kurbo", - "siphasher", -] - [[package]] name = "syn" version = "1.0.109" @@ -5968,7 +5915,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5993,7 +5940,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6087,32 +6034,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-skia" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" -dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "log", - "png", - "tiny-skia-path", -] - -[[package]] -name = "tiny-skia-path" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" -dependencies = [ - "arrayref", - "bytemuck", - "strict-num", -] - [[package]] name = "tinystr" version = "0.8.1" @@ -6292,7 +6213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "async-compression", - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes", "futures-core", "futures-util", @@ -6375,7 +6296,7 @@ dependencies = [ "once_cell", "regex-automata", "sharded-slab", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local", "tracing", "tracing-core", @@ -6432,9 +6353,8 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +version = "0.24.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "tungstenite" @@ -6492,23 +6412,31 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +[[package]] +name = "unicase" +version = "2.9.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "unicode-bidi" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "unicode-bidi-mirroring" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" +version = "0.3.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "unicode-ccc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" +version = "0.3.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "unicode-ident" @@ -6519,8 +6447,7 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "unicode-normalization" @@ -6537,11 +6464,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "unicode-script" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" +version = "0.5.8" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" [[package]] name = "unicode-segmentation" @@ -6549,6 +6480,17 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -6601,28 +6543,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "usvg" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84ea542ae85c715f07b082438a4231c3760539d902e11d093847a0b22963032" -dependencies = [ - "base64", - "data-url", - "flate2", - "imagesize", - "kurbo", - "log", - "pico-args", - "roxmltree", - "simplecss", - "siphasher", - "strict-num", - "svgtypes", - "tiny-skia-path", - "xmlwriter", -] - [[package]] name = "utf-8" version = "0.7.6" @@ -6834,7 +6754,7 @@ dependencies = [ "fancy_constructor", "futures-core", "js-sys", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "wasm-bindgen", "web-sys", @@ -6842,35 +6762,30 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +version = "0.3.12" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "cc", "downcast-rs", - "rustix", + "libc", "scoped-tls", - "smallvec", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-sys", ] [[package]] name = "wayland-client" -version = "0.31.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +version = "0.31.12" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "bitflags 2.10.0", - "rustix", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", "wayland-backend", - "wayland-scanner", ] [[package]] name = "wayland-egl" -version = "0.32.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36232ee23ba3ea34a6835d68ca1af91d3ca3d6eddcf9c7147c4e0e66901b9fd" +version = "0.32.9" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ "wayland-backend", "wayland-sys", @@ -6878,34 +6793,19 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +version = "0.32.10" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-backend", "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" -dependencies = [ - "proc-macro2", - "quick-xml", - "quote", ] [[package]] name = "wayland-sys" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +version = "0.31.8" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" dependencies = [ - "dlib", "log", "pkg-config", ] @@ -6993,13 +6893,23 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", + "windows-collections 0.2.0", "windows-core 0.61.2", - "windows-future", + "windows-future 0.2.1", "windows-link 0.1.3", "windows-numerics", ] +[[package]] +name = "windows" +version = "0.62.2" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", +] + [[package]] name = "windows-collections" version = "0.2.0" @@ -7009,6 +6919,14 @@ dependencies = [ "windows-core 0.61.2", ] +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-core 0.62.2", +] + [[package]] name = "windows-core" version = "0.56.0" @@ -7031,7 +6949,17 @@ dependencies = [ "windows-interface 0.59.2", "windows-link 0.1.3", "windows-result 0.3.4", - "windows-strings", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -7045,6 +6973,14 @@ dependencies = [ "windows-threading", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-core 0.62.2", +] + [[package]] name = "windows-implement" version = "0.56.0" @@ -7101,6 +7037,11 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" + [[package]] name = "windows-numerics" version = "0.2.0" @@ -7119,7 +7060,7 @@ checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link 0.1.3", "windows-result 0.3.4", - "windows-strings", + "windows-strings 0.4.2", ] [[package]] @@ -7140,6 +7081,14 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -7149,6 +7098,14 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "git+https://github.com/makepad/makepad?branch=dev#8ac86f0666f65d24cbe3a146b9cd6011eecec0d2" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -7461,7 +7418,7 @@ version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ - "memchr", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -7488,12 +7445,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "xmlwriter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" - [[package]] name = "xxhash-rust" version = "0.8.15" @@ -7623,18 +7574,3 @@ name = "zmij" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] diff --git a/Cargo.toml b/Cargo.toml index 5c041614c..4072ac4c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,26 +1,22 @@ [package] name = "robrix" -authors = [ - "Kevin Boos ", - "Robius Project Maintainers", -] +authors = ["Kevin Boos ", "Robius Project Maintainers"] description = "A Matrix chat client written using Makepad + Robius app dev framework in Rust." documentation = "https://docs.rs/robrix" -edition = "2024" ## mostly just to allow let-chains +edition = "2024" ## mostly just to allow let-chains homepage = "https://robius.rs/" keywords = ["matrix", "chat", "client", "robius", "makepad"] license = "MIT" readme = "README.md" -categories = [ "gui" ] +categories = ["gui"] repository = "https://github.com/project-robius/robrix" version = "0.0.1-pre-alpha-4" metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q=" [dependencies] -makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "dev", features = ["serde"] } +makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "dev" } makepad-code-editor = { git = "https://github.com/makepad/makepad", branch = "dev" } - ## Including this crate automatically configures all `robius-*` crates to work with Makepad. robius-use-makepad = "0.1.1" robius-open = { git = "https://github.com/project-robius/robius" } @@ -36,9 +32,11 @@ chrono = "0.4" clap = { version = "4.0.16", features = ["derive"] } crossbeam-channel = "0.5.10" crossbeam-queue = "0.3.8" -eyeball = { version = "0.8.8", features = ["tracing"] } # same as matrix-sdk-ui -eyeball-im = { version = "0.8.0", features = ["tracing"] } # same as matrix-sdk-ui -imbl = { version = "6.1.0", features = ["serde"] } # same as matrix-sdk-ui +eyeball = { version = "0.8.8", features = ["tracing"] } # same as matrix-sdk-ui +eyeball-im = { version = "0.8.0", features = [ + "tracing", +] } # same as matrix-sdk-ui +imbl = { version = "6.1.0", features = ["serde"] } # same as matrix-sdk-ui futures-util = "0.3" hashbrown = { version = "0.16", features = ["raw-entry"] } htmlize = "1.0.5" @@ -46,14 +44,27 @@ indexmap = "2.6.0" imghdr = "0.7.0" linkify = "0.10.0" matrix-sdk-base = { git = "https://github.com/matrix-org/matrix-rust-sdk", branch = "main" } -matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", branch = "main", default-features = false, features = [ "e2e-encryption", "automatic-room-key-forwarding", "markdown", "sqlite", "rustls-tls", "bundled-sqlite", "sso-login" ] } -matrix-sdk-ui = { git = "https://github.com/matrix-org/matrix-rust-sdk", branch = "main", default-features = false, features = [ "rustls-tls" ] } +matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", branch = "main", default-features = false, features = [ + "e2e-encryption", + "automatic-room-key-forwarding", + "markdown", + "sqlite", + "rustls-tls", + "bundled-sqlite", + "sso-login", +] } +matrix-sdk-ui = { git = "https://github.com/matrix-org/matrix-rust-sdk", branch = "main", default-features = false, features = [ + "rustls-tls", +] } ## Use the same ruma version as what's specified in matrix-sdk's Cargo.toml. ## Enable a few extra features: ## * "compat-optional" feature to allow missing body field in m.room.tombstone event. ## * "compat-unset-avatar" feature to allow deleting the user's avatar to work properly. ## * Note: we need a feature like "compat-unset-display-name" to unset display names, but that doesn't exist yet. -ruma = { version = "0.14.1", features = ["compat-optional", "compat-unset-avatar"] } +ruma = { version = "0.14.1", features = [ + "compat-optional", + "compat-unset-avatar", +] } rand = "0.8.5" rangemap = "1.5.0" sanitize-filename = "0.6" @@ -70,7 +81,10 @@ url = "2.5.0" ## Commit "f0bc4625dcd729e07e4a36257df2f1d94c81cef4" is the most recent one without the invalid change to pin serde to 1.0.219. ## See my issue here: . ## However, that commit doesn't build.... yikes. So we have to use a slightly older commit in the "rev" field below. -tsp_sdk = { git = "https://github.com/openwallet-foundation-labs/tsp.git", rev = "1cd0cc9442e144ad7c01ccd30daffbb3a52c0f20", optional = true, features = ["async", "resolve"] } +tsp_sdk = { git = "https://github.com/openwallet-foundation-labs/tsp.git", rev = "1cd0cc9442e144ad7c01ccd30daffbb3a52c0f20", optional = true, features = [ + "async", + "resolve", +] } quinn = { version = "0.11", default-features = false, optional = true } ## We only include this such that we can specify the prebuilt-nasm features, ## which is required to build this on Windows x86_64 without having to install NASM separately. @@ -137,7 +151,7 @@ askar-storage = { git = "https://github.com/openwallet-foundation/askar.git" } ## and then we won't need to patch ruma-events anymore. ## But that is a significant amount of work, so for now we just patch ruma-events. ## -ruma = { git = "https://github.com/project-robius/ruma.git", branch = "tsp"} +ruma = { git = "https://github.com/project-robius/ruma.git", branch = "tsp" } [package.metadata.docs.rs] @@ -158,7 +172,7 @@ lto = "thin" [profile.distribution] inherits = "release" codegen-units = 1 -lto = "fat" +lto = "fat" ## For very fast compilation, not for creating an actual high-quality executable. ## This is primarily useful for CI builds. @@ -171,13 +185,15 @@ strip = true debug-assertions = false - ## Configuration for `cargo packager` [package.metadata.packager] product_name = "Robrix" identifier = "org.robius.robrix" category = "SocialNetworking" -authors = ["Project Robius ", "Kevin Boos "] +authors = [ + "Project Robius ", + "Kevin Boos ", +] publisher = "robius" license_file = "LICENSE-MIT" copyright = "Copyright 2023-202, Project Robius" @@ -221,7 +237,10 @@ robius-packaging-commands before-each-package \ """ deep_link_protocols = [ - { schemes = ["robrix", "matrix"], role = "viewer" }, ## `name` is left as default + { schemes = [ + "robrix", + "matrix", + ], role = "viewer" }, ## `name` is left as default ] [package.metadata.packager.deb] @@ -231,7 +250,7 @@ section = "utils" [package.metadata.packager.macos] minimum_system_version = "11.0" -frameworks = [ ] +frameworks = [] info_plist_path = "./packaging/Info.plist" entitlements = "./packaging/Entitlements.plist" signing_identity = "Developer ID Application: AppChef Inc. (SFVQ5V48GD)" diff --git a/SPLASH.md b/SPLASH.md new file mode 100644 index 000000000..88af44bba --- /dev/null +++ b/SPLASH.md @@ -0,0 +1,2362 @@ +# Splash Script Manual (Terse AI Reference) + +Splash is Makepad's UI scripting language. It is whitespace-delimited, but Robrix prefers either newlines or commas to separate properties, for readability's sake. +**Please always use newlines or commas to separate properties, not just whitespace.** + +**Do NOT use `Root{}` or `Window{}`** — those are host-level wrappers handled externally. Your output is the content inside a body/splash widget. + +--- + +## NAMING CHILDREN: Use `:=` for dynamic/list properties + +In Splash, when you declare a named child widget inside a `let` template (or any container), you use the `:=` operator. This marks the child as a **named/dynamic** property — addressable and overridable per-instance. + +- To declare: `label := Label{text: "default"}` +- To override: `MyTemplate{label.text: "new value"}` + +If you write `label:` (colon) instead of `label :=` (colon-equals), the child is a **static** property — not addressable, and overrides fail silently (text becomes invisible). + +**Use `:=` for any child you want to reference or override later:** `check :=`, `label :=`, `tag :=`, `title :=`, `body :=`, `icon :=`, `content :=`, etc. + +## COPY-PASTE REFERENCE: Todo list + +``` +let TodoItem = View{ + width: Fill height: Fit + padding: Inset{top: 8 bottom: 8 left: 12 right: 12} + flow: Right spacing: 10 + align: Align{y: 0.5} + check := CheckBox{text: ""} + label := Label{text: "task" draw_text.color: #ddd draw_text.text_style.font_size: 11} + Filler{} + tag := Label{text: "" draw_text.color: #888 draw_text.text_style.font_size: 9} +} + +RoundedView{ + width: 380 height: Fit + flow: Down spacing: 4 + padding: 16 + new_batch: true + draw_bg.color: #1e1e2e + draw_bg.border_radius: 10.0 + Label{text: "My Tasks" draw_text.color: #fff draw_text.text_style.font_size: 14} + Hr{} + TodoItem{label.text: "Buy groceries" tag.text: "errands"} + TodoItem{label.text: "Fix login bug" tag.text: "urgent"} + TodoItem{label.text: "Write unit tests" tag.text: "dev"} + TodoItem{label.text: "Call the dentist" tag.text: "personal"} +} +``` + +## COPY-PASTE REFERENCE: Card with title and body + +``` +let InfoCard = RoundedView{ + width: Fill height: Fit + padding: 16 flow: Down spacing: 6 + draw_bg.color: #2a2a3d + draw_bg.border_radius: 8.0 + title := Label{text: "Title" draw_text.color: #fff draw_text.text_style.font_size: 14} + body := Label{text: "Body" draw_text.color: #aaa draw_text.text_style.font_size: 11} +} + +View{ + flow: Down height: Fit spacing: 10 padding: 20 + InfoCard{title.text: "First card" body.text: "Some content here"} + InfoCard{title.text: "Second card" body.text: "More content here"} +} +``` + +--- + +## 🚫 DO NOT INVENT SYNTAX OR PROPERTIES 🚫 + +**ONLY use widgets, properties, and syntax documented in this manual.** This code must compile and run — do not: + +- Invent new properties (e.g., don't write `background_color:` — use `draw_bg.color:`) +- Guess at property names (e.g., don't write `font_size:` — use `draw_text.text_style.font_size:`) +- Make up new widgets that aren't listed here +- Suggest hypothetical features or syntax that "might work" +- Use CSS-like property names (no `border-radius`, use `draw_bg.border_radius`) + +If you're unsure whether a property exists, **don't use it**. Stick to the exact syntax shown in the examples. + +--- + +## 📝 OUTPUT FORMAT: CODE ONLY 📝 + +**When generating UI, output ONLY the Splash code.** Do not add: + +- Explanatory text before or after the code +- "Here's the UI:" or "This creates..." preambles +- Suggestions for improvements or alternatives +- Commentary about what the code does + +Just output the raw Splash script starting with `use mod.prelude.widgets.*` — nothing else. + +--- + +## ⛔⛔⛔ CRITICAL: YOU MUST SET `height: Fit` ON EVERY CONTAINER ⛔⛔⛔ + +**STOP. READ THIS. THE #1 MISTAKE IS FORGETTING `height: Fit`.** + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ EVERY View, SolidView, RoundedView MUST HAVE height: Fit │ +│ │ +│ ✅ View{ flow: Down height: Fit padding: 10 ... } │ +│ │ +│ If you forget height: Fit, your UI will be INVISIBLE (0px) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Why?** The default is `height: Fill`. Your output renders in a `Fit` container. `Fill` inside `Fit` = circular dependency = **0 height**. + +**ALWAYS write `height: Fit` immediately after the opening brace:** + +``` +View{ height: Fit flow: Down padding: 10 + Label{text: "Visible!"} +} + +SolidView{ height: Fit width: Fill draw_bg.color: #333 + Label{text: "Also visible!"} +} + +RoundedView{ height: Fit width: Fill flow: Down spacing: 8 + Label{text: "Card content"} +} +``` + +**Exceptions:** +1. Inside a fixed-height parent, `height: Fill` is OK: +``` +View{ height: 300 // Fixed parent + View{ height: Fill // OK here - fills the 300px + Label{text: "I fill the fixed 300px"} + } +} +``` +2. **MapView** — has no intrinsic height, so `height: Fit` also gives 0px. Use a **fixed pixel height**: `MapView{width: Fill height: 500}` + +**TEMPLATE: Copy this pattern for every container:** +``` +View{ height: Fit ...rest of properties... + ...children... +} +``` + +--- + +## ⛔⛔⛔ CRITICAL: USE `width: Fill` ON THE ROOT CONTAINER ⛔⛔⛔ + +**NEVER use a fixed pixel width (e.g., `width: 400`) on your outermost container.** Your output renders inside a container that provides available width — use `width: Fill` to fill it. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ The ROOT container MUST use width: Fill │ +│ │ +│ ✅ RoundedView{ width: Fill height: Fit ... } │ +│ ❌ RoundedView{ width: 400 height: Fit ... } │ +│ │ +│ Fixed widths make your UI a narrow sliver or completely broken │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Why?** A fixed width like `width: 400` does not adapt to the available space. Worse, if the parent container is narrower than 400, your content gets clipped. If a parse error occurs anywhere in the code, the entire layout can collapse to near-zero width. + +**ALWAYS use `width: Fill` on the root element:** +``` +RoundedView{ width: Fill height: Fit flow: Down + // your content +} +``` + +Fixed pixel widths are fine for **inner elements** like icons, avatars, or specific components — just never on the outermost container. + +--- + +## ⛔ CRITICAL: `draw_bg.border_radius` TAKES A FLOAT, NOT AN INSET ⛔ + +``` +✅ draw_bg.border_radius: 16.0 +❌ draw_bg.border_radius: Inset{top: 0 bottom: 16 left: 0 right: 0} +``` + +`border_radius` is a single `f32` value applied uniformly to all corners. Passing an `Inset` or object will cause a parse error that can **silently break your entire layout**. + +--- + +## ⚠️ USE STYLED VIEWS, NOT RAW `View{}` ⚠️ + +**Do NOT use `View{ show_bg: true ... }`** — the raw View has an ugly green test color as its background. + +Instead, use these pre-styled container widgets that have proper backgrounds: + +| Widget | Use for | +|--------|---------| +| `SolidView` | Simple solid color background | +| `RoundedView` | Rounded corners with optional border | +| `RectView` | Rectangle with optional border | +| `RoundedShadowView` | Rounded corners with drop shadow | +| `RectShadowView` | Rectangle with drop shadow | +| `CircleView` | Circular shape | +| `GradientXView` | Horizontal gradient | +| `GradientYView` | Vertical gradient | + +All have `show_bg: true` already set. Set color via `draw_bg.color`: + +``` +SolidView{ width: Fill height: Fit draw_bg.color: #334 + Label{text: "Content here"} +} + +RoundedView{ width: Fill height: Fit draw_bg.color: #445 draw_bg.border_radius: 8.0 + Label{text: "Rounded card"} +} + +RoundedShadowView{ width: Fill height: Fit draw_bg.color: #556 draw_bg.shadow_radius: 10.0 + Label{text: "Card with shadow"} +} +``` + +**Use raw `View{}` only when you need no background** (invisible layout container). + +--- + +## Script Structure + +Every splash script must start with a `use` statement to bring widgets into scope: + +``` +use mod.prelude.widgets.* + +// Now all widgets (View, Label, Button, etc.) are available +View{ + flow: Down + height: Fit // ← ALWAYS set height! Default is Fill which breaks in Fit containers + padding: 20 + Label{text: "Hello world"} +} +``` + +Without `use mod.prelude.widgets.*` at the top, widget names like `View`, `Label`, `Button` etc. will not be found. + +### Let bindings for reusable definitions + +Use `let` to define reusable widget templates. **`let` bindings must be defined ABOVE (before) the places where they are used.** They are local to the current scope. + +**When a template has children you want to customize per-instance, you MUST use `id :=` declarations.** See the critical rule below. + +``` +use mod.prelude.widgets.* + +// Simple template with NO per-instance children — just style overrides +let MyHeader = Label{ + draw_text.color: #fff + draw_text.text_style.font_size: 16 +} + +// Template WITH per-instance children — MUST use id := declarations +let MyCard = RoundedView{ + width: Fill height: Fit + padding: 15 flow: Down spacing: 8 + draw_bg.color: #334 + draw_bg.border_radius: 8.0 + title := Label{text: "default" draw_text.color: #fff draw_text.text_style.font_size: 16} + body := Label{text: "" draw_text.color: #aaa} +} + +// Override children using id.property syntax +View{ + flow: Down height: Fit + spacing: 12 padding: 20 + MyCard{title.text: "First Card" body.text: "Content here"} + MyCard{title.text: "Second Card" body.text: "More content"} +} +``` + +### Naming children in templates — the `:=` operator + +Children inside a `let` template that you want to override per-instance MUST be declared with `:=`. This is part of the syntax — `label :=` creates a named/dynamic child, `label:` does not. + +**Reusable todo/list item with multiple named children:** + +``` +let TodoItem = View{ + width: Fill height: Fit + padding: Inset{top: 8 bottom: 8 left: 12 right: 12} + flow: Right spacing: 8 + align: Align{y: 0.5} + check := CheckBox{text: ""} + label := Label{text: "task" draw_text.color: #ddd draw_text.text_style.font_size: 11} + Filler{} + tag := Label{text: "" draw_text.color: #888 draw_text.text_style.font_size: 9} +} + +View{ + flow: Down height: Fit spacing: 4 + TodoItem{label.text: "Walk the dog" tag.text: "personal"} + TodoItem{label.text: "Fix login bug" tag.text: "urgent"} + TodoItem{label.text: "Buy groceries" tag.text: "errands"} +} +``` + +You can override ANY property on an `id :=` child: `label.draw_text.color: #f00`, `icon.visible: false`, `subtitle.draw_text.text_style.font_size: 10`, etc. + +**⛔ Named children inside anonymous containers are UNREACHABLE.** If a `:=` child is nested inside an anonymous `View{}` (no `:=` on the View), the override path cannot find it. The override fails silently and the default text shows instead: + +Every container in the path from root to the child must have a `:=` name. Then use the full dot-path to override: +``` +let Item = View{ + flow: Right + texts := View{ // named with := + flow: Down + label := Label{text: "default"} + } +} +Item{texts.label.text: "new text"} // full path through named containers +``` + +## Syntax Fundamentals + +``` +// Property assignment +key: value + +// Nested object +key: Type{ prop1: val1 prop2: val2 } + +// Merge (extend parent, don't replace) +key +: { prop: val } + +// Dot-path shorthand +draw_bg.color: #f00 +// equivalent to: draw_bg +: { color: #f00 } + +// Named child (:= declares a dynamic/addressable child) +my_button := Button{ text: "Click" } + +// Anonymous child (no name) +Label{ text: "hello" } + +// Let binding (define BEFORE use, local to current scope) +let MyThing = View{ height: Fit width: Fill } + +// Instantiate let binding +MyThing{} + +// Inherit from existing widget type +MyView = RoundedView{ height: Fit draw_bg.color: #f00 } +``` + +## Colors + +``` +#f00 // RGB short +#ff0000 // RGB full +#ff0000ff // RGBA +#0000 // transparent black +vec4(1.0 0.0 0.0 1.0) // explicit RGBA +``` + +## Sizing (Size enum) + +``` +width: Fill // Fill available space (default) +width: Fit // Shrink to content +width: 200 // Fixed 200px (bare number = Fixed) +width: Fill{min: 100 max: 500} +width: Fit{max: Abs(300)} +height: Fill height: Fit height: 100 +``` + +## Layout + +### Flow (direction children are laid out) +``` +flow: Right // default, left-to-right (no wrap) +flow: Down // top-to-bottom +flow: Overlay // stacked on top of each other +flow: Flow.Right{wrap: true} // wrapping horizontal +flow: Flow.Down{wrap: true} // wrapping vertical +``` + +### Spacing/Padding/Margin +``` +spacing: 10 // gap between children +padding: 15 // uniform padding (bare number) +padding: Inset{top: 5 bottom: 5 left: 10 right: 10} +margin: Inset{top: 2 bottom: 2 left: 5 right: 5} +margin: 0. // uniform zero +``` + +### Alignment +``` +align: Center // Align{x:0.5 y:0.5} +align: HCenter // Align{x:0.5 y:0.0} +align: VCenter // Align{x:0.0 y:0.5} +align: TopLeft // Align{x:0.0 y:0.0} +align: Align{x: 1.0 y: 0.0} // top-right +align: Align{x: 0.0 y: 0.5} // center-left +``` + +### Clipping +``` +clip_x: true // default +clip_y: true // default +clip_x: false // overflow visible +``` + +## View Widgets (containers) + +All inherit from `ViewBase`. Default: no background. + +| Widget | Background | Shape | +|--------|-----------|-------| +| `View` | none | - | +| `SolidView` | flat color | rectangle | +| `RoundedView` | color | rounded rect (`border_radius`) | +| `RoundedAllView` | color | per-corner radius (`vec4`) | +| `RoundedXView` | color | left/right radius (`vec2`) | +| `RoundedYView` | color | top/bottom radius (`vec2`) | +| `RectView` | color | rectangle with border | +| `RectShadowView` | color+shadow | rectangle | +| `RoundedShadowView` | color+shadow | rounded rect | +| `CircleView` | color | circle | +| `HexagonView` | color | hexagon | +| `GradientXView` | horizontal gradient | rectangle | +| `GradientYView` | vertical gradient | rectangle | +| `CachedView` | texture-cached | rectangle | +| `CachedRoundedView` | texture-cached | rounded rect | + +### Scrollable Views +``` +ScrollXYView{} // scroll both axes +ScrollXView{} // horizontal scroll +ScrollYView{} // vertical scroll +``` + +### View Properties (all containers) +**⚠️ REMEMBER: Always set `height: Fit` (default is Fill which breaks in chat output!)** +``` +// Layout (inherited by all containers) +width: Fill // Size: Fill | Fit | +height: Fit // ⚠️ USE Fit! Default Fill breaks in Fit containers! +flow: Down // Flow: Right | Down | Overlay | Flow.Right{wrap:true} +spacing: 10 // gap between children +padding: 15 // Inset or bare number +margin: 0. // Inset or bare number +align: Center // Align preset or Align{x: y:} + +// Display +show_bg: true // enable background drawing (false by default) +visible: true +new_batch: true // see "Draw Batching" section below +cursor: MouseCursor.Hand +grab_key_focus: true +block_signal_event: false +capture_overload: false +clip_x: true +clip_y: true + +// Scrollbar (for ScrollXView/ScrollYView/ScrollXYView) +scroll_bars: ScrollBar{} +``` + +### Draw Batching and `new_batch: true` + +In Makepad, widgets that use the same shader are automatically collected into the same GPU draw call for performance. This means if you draw `Label{} SolidView{ Label{} }`, the second Label's text can end up **behind** the SolidView's background — because both Labels are batched into the same text draw call, which executes before the SolidView's background draw call. + +**Set `new_batch: true` on any View that has `show_bg: true` AND contains text children.** This tells the View to start a new draw batch, ensuring its background is drawn before its children's text. + +**⛔ CRITICAL for hover effects:** If a View has `show_bg: true` with a hover animator (background goes from transparent `#0000` to opaque on hover), you MUST set `new_batch: true` on that View. Without it, when the hover activates the background becomes opaque and covers the text — making text disappear on hover. This is the #1 mistake with hoverable list items. + +**When to use `new_batch: true`:** +- **Any View/SolidView/RoundedView with `show_bg: true` that contains Labels or other text** — always add `new_batch: true` +- **Hoverable items** — a View with `show_bg: true` + animator hover that contains text MUST have `new_batch: true` or text vanishes on hover +- **Container of repeated items** that each have their own background — the container itself also needs `new_batch: true` +- When text appears invisible despite having the correct color — this is almost always a batching issue + +``` +// Hoverable item: new_batch ensures text draws on top of hover bg +let HoverItem = View{ + width: Fill height: Fit + new_batch: true + show_bg: true + draw_bg +: { color: uniform(#0000) color_hover: uniform(#fff2) hover: instance(0.0) ... } + animator: Animator{ hover: { ... } } + label := Label{text: "item" draw_text.color: #fff} +} + +// Parent container of repeated items also needs new_batch +RoundedView{ + flow: Down height: Fit new_batch: true + HoverItem{label.text: "Walk the dog"} + HoverItem{label.text: "Do laundry"} +} +``` + +### draw_bg Properties (for SolidView, RoundedView, etc.) +``` +draw_bg +: { + color: instance(#334) // fill color + color_2: instance(vec4(-1)) // gradient end (-1 = disabled) + gradient_fill_horizontal: uniform(0.0) // 0=vertical, 1=horizontal + border_size: uniform(1.0) + border_radius: uniform(5.0) // for RoundedView + border_color: instance(#888) + border_inset: uniform(vec4(0)) + // Shadow views add: + shadow_color: instance(#0007) + shadow_radius: uniform(10.0) + shadow_offset: uniform(vec2(0 0)) +} +``` + +## Text Widgets + +### Label +Properties: `text`, `draw_text` (DrawText), `align`, `flow`, `padding`, `hover_actions_enabled` + +**⚠️ Label does NOT support `animator` or `cursor`.** Adding them has no effect — they are silently ignored. To make hoverable/clickable text, wrap a Label inside a `View` with animator+cursor (see Animator section for example). + +``` +Label{ text: "Hello" } +Label{ + width: Fit height: Fit + draw_text.color: #fff + draw_text.text_style.font_size: 12 + text: "Styled" +} +``` + +**⛔ CRITICAL: Default text color is WHITE.** All text widgets (Label, H1, H2, Button text, etc.) default to white (`#fff`). For light/white themes, you MUST explicitly set `draw_text.color` to a dark color on EVERY text element, or text will be invisible (white-on-white). Example: +For light themes, always set dark text explicitly: +``` +RoundedView{ draw_bg.color: #f5f5f5 height: Fit new_batch: true + Label{text: "Visible!" draw_text.color: #222} +} +``` + +### Label Variants +| Widget | Description | +|--------|-------------| +| `Label` | Default label | +| `Labelbold` | Bold font | +| `LabelGradientX` | Horizontal text gradient | +| `LabelGradientY` | Vertical text gradient | +| `TextBox` | Full-width, long-form text_style | +| `P` | Paragraph (like TextBox) | +| `Pbold` | Bold paragraph | + +### Headings +``` +H1{ text: "Title" } // font_size_1 +H2{ text: "Subtitle" } // font_size_2 +H3{ text: "Section" } // font_size_3 +H4{ text: "Subsection" } // font_size_4 +``` + +### draw_text Properties +``` +draw_text +: { + color: #fff + color_2: uniform(vec4(-1)) // gradient end (-1 = disabled) + color_dither: uniform(1.0) + gradient_fill_horizontal: uniform(0.0) + text_style: theme.font_regular{ font_size: 11 } +} +``` +Available fonts: `theme.font_regular`, `theme.font_bold`, `theme.font_italic`, `theme.font_bold_italic`, `theme.font_code`, `theme.font_icons` + +### TextInput +Properties: `is_password`, `is_read_only`, `is_numeric_only`, `empty_text`, `draw_bg`, `draw_text`, `draw_selection`, `draw_cursor`, `label_align` +``` +TextInput{ width: Fill height: Fit empty_text: "Placeholder" } +TextInputFlat{ width: Fill height: Fit empty_text: "Type here" } +TextInput{ is_password: true empty_text: "Password" } +TextInput{ is_read_only: true } +TextInput{ is_numeric_only: true } +``` + +### LinkLabel +Properties: same as Button (text, draw_text, draw_bg, icon_walk, label_walk) +``` +LinkLabel{ text: "Click me" } +``` + +### TextFlow (rich text container, used by Markdown/Html) +``` +TextFlow{ + width: Fill height: Fit + selectable: true + font_size: 10 +} +``` + +### Markdown / Html (feature-gated) +``` +Markdown{ + width: Fill height: Fit + selectable: true + body: "# Title\n\nParagraph with **bold**" +} +Html{ + width: Fill height: Fit + body: "

Title

Content

" +} +``` + +## Button Widgets + +Properties: `text`, `draw_bg` (DrawQuad), `draw_text` (DrawText), `draw_icon` (DrawSvg), `icon_walk`, `label_walk`, `grab_key_focus`, `animator` + +``` +Button{ text: "Standard" } +ButtonFlat{ text: "Flat" } // no bevel border +ButtonFlatter{ text: "Minimal" } // invisible bg + +// With icon +Button{ + text: "Save" + icon_walk: Walk{width: 16 height: 16} + draw_icon.color: #fff + draw_icon.svg: crate_resource("self://path/to/icon.svg") +} + +// Customize colors +ButtonFlat{ + text: "Custom" + draw_bg +: { + color: uniform(#336) + color_hover: uniform(#449) + color_down: uniform(#225) + } + draw_text +: { + color: #fff + } +} +``` + +### Button draw_bg Instance Variables +These are per-instance floats driven by the animator: +`hover`, `down`, `focus`, `disabled` + +Color uniforms (each with `_hover`, `_down`, `_focus`, `_disabled` variants): +`color`, `color_2`, `border_color`, `border_color_2` + +Other: `border_size`, `border_radius`, `color_dither`, `gradient_fill_horizontal`, `gradient_border_horizontal` + +## Toggle Widgets + +CheckBox/Toggle share a base. Properties: `text`, `draw_bg`, `draw_text`, `draw_icon`, `icon_walk`, `label_walk`, `label_align`, `animator` + +``` +CheckBox{ text: "Enable" } +CheckBoxFlat{ text: "Flat style" } +Toggle{ text: "Dark mode" } +ToggleFlat{ text: "Flat toggle" } +CheckBoxCustom{ text: "Custom" } +``` + +### CheckBox draw_bg Instance Variables +Animator-driven: `hover`, `down`, `focus`, `active`, `disabled` +Uniforms: `size`, `border_size`, `border_radius` +Color uniforms (each with `_hover`, `_down`, `_active`, `_focus`, `_disabled`): `color`, `border_color`, `mark_color` +Also: `mark_size` + +### RadioButton +Properties: same as CheckBox +``` +RadioButton{ text: "Option A" } +RadioButtonFlat{ text: "Option A" } +``` + +## Input Widgets + +### Slider +Properties: `text`, `min`, `max`, `step`, `default`, `precision`, `axis` (DragAxis), `label_walk`, `label_align`, `draw_bg`, `draw_text`, `bind` +``` +Slider{ width: Fill text: "Volume" min: 0.0 max: 100.0 default: 50.0 } +SliderMinimal{ text: "Value" min: 0.0 max: 1.0 step: 0.01 precision: 2 } +``` + +### DropDown +Properties: `labels` (string array), `draw_bg`, `draw_text`, `popup_menu`, `bind`, `bind_enum` +``` +DropDown{ labels: ["Option A" "Option B" "Option C"] } +DropDownFlat{ labels: ["Small" "Medium" "Large"] } +``` + +## Media + +### Image +Properties: `draw_bg` (DrawImage), `fit` (ImageFit), `min_width`, `min_height`, `width_scale`, `animation` (ImageAnimation) +``` +Image{ width: 200 height: 150 fit: ImageFit.Stretch } +// ImageFit: Stretch | Horizontal | Vertical | Smallest | Biggest | Size +// ImageAnimation: Stop | Once | Loop | Bounce | OnceFps(60) | LoopFps(25) | BounceFps(25) +``` + +### DrawImage Properties +``` +draw_bg +: { + opacity: 1.0 + image_scale: vec2(1.0 1.0) + image_pan: vec2(0.0 0.0) + image_texture: texture_2d(float) +} +``` + +### Icon +Properties: `draw_bg`, `draw_icon` (DrawSvg), `icon_walk` +``` +Icon{ + draw_icon.svg: crate_resource("self://resources/icons/my_icon.svg") + draw_icon.color: #0ff + icon_walk: Walk{width: 32 height: 32} +} +``` + +### LoadingSpinner +A View with animated arc shader. Properties: `color`, `rotation_speed`, `border_size`, `stroke_width`, `max_gap_ratio`, `min_gap_ratio` +``` +LoadingSpinner{ width: 40 height: 40 } +``` + +## Layout Widgets + +### Hr / Vr (dividers) +``` +Hr{} // horizontal rule +Vr{} // vertical rule +``` + +### Filler (spacer) +``` +Filler{} // View{width: Fill height: Fill} - pushes siblings apart +``` + +**⛔ Do NOT use `Filler{}` next to a `width: Fill` sibling in `flow: Right`.** Both compete for remaining space and split it 50/50, causing text to be clipped halfway. Instead, give the content element `width: Fill` — it naturally pushes `width: Fit` siblings to the edge. Only use `Filler{}` between `width: Fit` siblings: +``` +// Filler between Fit siblings — correct use +View{ flow: Right + Label{text: "left"} + Filler{} + Label{text: "right"} +} + +// width: Fill takes remaining space, pushes Fit siblings right — no Filler needed +View{ flow: Right + texts := View{ width: Fill height: Fit flow: Down + label := Label{text: "title"} + sub := Label{text: "subtitle"} + } + tag := Label{text: "tag"} +} +``` + +### Splitter +Properties: `axis` (SplitterAxis), `align` (SplitterAlign), `a`, `b`, `size`, `min_horizontal`, `max_horizontal`, `min_vertical`, `max_vertical`, `draw_bg` +``` +Splitter{ + axis: SplitterAxis.Horizontal // Horizontal | Vertical + align: SplitterAlign.FromA(250.0) // FromA(px) | FromB(px) | Weighted(0.5) + a := left_panel + b := right_panel +} +``` +Note: `a` and `b` reference named children — use `a := left_panel` (the `:=` operator) to bind them. + +### FoldHeader (collapsible section) +Properties: `body_walk`, `animator` (with `active` group: `on`/`off` states controlling `opened` float) +``` +FoldHeader{ + header: View{ height: Fit + flow: Right align: Align{y: 0.5} spacing: 8 + FoldButton{} + Label{text: "Section Title"} + } + body: View{ height: Fit + flow: Down padding: Inset{left: 23} spacing: 8 + // content + } +} +``` + +## List Widgets + +### PortalList (virtualized list) +Properties: `flow`, `scroll_bar`, `capture_overload`, `selectable`, `drag_scrolling`, `auto_tail` +Define templates with `:=` declarations. Templates are instantiated by host code at draw time. +``` +list := PortalList{ + width: Fill height: Fill + flow: Down + scroll_bar: ScrollBar{} + Item := View{ + width: Fill height: Fit + title := Label{text: ""} + } + Header := View{ height: Fit ... } +} +``` + +### FlatList (non-virtualized) +``` +FlatList{ + width: Fill height: Fill + flow: Down + Item := View{ height: Fit ... } +} +``` + +### ScrollBar +Properties: `bar_size`, `bar_side_margin`, `min_handle_size`, `draw_bg` +``` +ScrollBar{ + bar_size: 10.0 + bar_side_margin: 3.0 + min_handle_size: 30.0 +} +``` + +## Dock System + +The Dock is a tabbed panel layout with splitters, tabs, and content templates. Three sections: +1. **`tab_bar +:`** — define tab header templates (appearance of tab buttons) +2. **`root :=`** — the layout tree of DockSplitter/DockTabs +3. **Content templates** — `Name := Widget{}` defines content instantiated by tabs + +### Dock Properties +`tab_bar` (TabBar widget for tab headers), `splitter` (Splitter widget), `round_corner`, `drag_target_preview`, `padding` + +### DockSplitter +`axis` (SplitterAxis), `align` (SplitterAlign), `a` (LiveId ref), `b` (LiveId ref) + +### DockTabs +`tabs` (array of tab refs), `selected` (index), `closable` + +### DockTab +`name` (string), `template` (ref to tab_bar template), `kind` (ref to content template) + +### Complete Dock Example (from Makepad Studio) +``` +Dock{ + width: Fill height: Fill + + // 1. Tab header templates (how tab buttons look) + tab_bar +: { + FilesTab := IconTab{ + draw_icon +: { + color: #80FFBF + svg: crate_resource("self://resources/icons/icon_file.svg") + } + } + EditTab := IconTab{ + draw_icon +: { + color: #FFB368 + svg: crate_resource("self://resources/icons/icon_editor.svg") + } + } + LogTab := IconTab{ + draw_icon +: { + color: #80FFBF + svg: crate_resource("self://resources/icons/icon_log.svg") + } + } + } + + // 2. Layout tree + root := DockSplitter{ + axis: SplitterAxis.Horizontal + align: SplitterAlign.FromA(250.0) + a := left_tabs + b := right_split + } + + right_split := DockSplitter{ + axis: SplitterAxis.Vertical + align: SplitterAlign.FromB(200.0) + a := center_tabs + b := bottom_tabs + } + + left_tabs := DockTabs{ + tabs: [@files_tab] + selected: 0 + } + + center_tabs := DockTabs{ + tabs: [@edit_tab] + selected: 0 + } + + bottom_tabs := DockTabs{ + tabs: [@log_tab] + selected: 0 + } + + // 3. Tab definitions (connect header template to content template) + files_tab := DockTab{ + name: "Files" + template := FilesTab // references tab_bar template + kind := FileTreeContent // references content template + } + + edit_tab := DockTab{ + name: "Editor" + template := EditTab + kind := EditorContent + } + + log_tab := DockTab{ + name: "Log" + template := LogTab + kind := LogContent + } + + // 4. Content templates (instantiated when tab is shown) + FileTreeContent := View{ + flow: Down + width: Fill height: Fill + Label{text: "File tree here"} + } + + EditorContent := View{ + flow: Down + width: Fill height: Fill + Label{text: "Editor here"} + } + + LogContent := View{ + flow: Down + width: Fill height: Fill + Label{text: "Log here"} + } +} +``` + +Dock variants: `Dock` (rounded corners), `DockFlat` (flat style) + +## Navigation + +### Modal +Properties: inherits View (flow: Overlay, align: Center). Contains `bg_view` (backdrop) and `content` (dialog body), both declared with `:=`. +``` +my_modal := Modal{ + content +: { + width: 300 height: Fit + RoundedView{ height: Fit + padding: 20 flow: Down spacing: 10 + draw_bg.color: #333 + Label{text: "Dialog Title"} + close := ButtonFlat{text: "Close"} + } + } +} +``` + +### Tooltip +``` +tooltip := Tooltip{} +``` + +### PopupNotification +``` +popup := PopupNotification{ + align: Align{x: 1.0 y: 0.0} + content +: { ... } +} +``` + +### SlidePanel +Properties: `side` (SlideSide), inherits View. Animated `active` float. +``` +panel := SlidePanel{ + side: SlideSide.Left // Left | Right | Top + width: 200 + height: Fill + // child content +} +``` + +### ExpandablePanel +Properties: `initial_offset`, inherits View (flow: Overlay). First child = background, `panel` (declared with `:=`) = draggable overlay. +``` +ExpandablePanel{ + width: Fill height: Fill + initial_offset: 100.0 + View{ height: Fit ... } // background + panel := View{ height: Fit ... } // draggable panel +} +``` + +### PageFlip +Properties: `active_page` (LiveId), `lazy_init`. Children are page templates declared with `:=`. +``` +PageFlip{ + active_page := page1 + page1 := View{ height: Fit ... } + page2 := View{ height: Fit ... } +} +``` + +### StackNavigation +``` +StackNavigation{ + root_view := View{ height: Fit ... } + // StackNavigationViews added as children +} +``` + +### SlidesView +``` +SlidesView{ + slide1 := Slide{ + title := H1{text: "Title"} + SlideBody{text: "Content"} + } + slide2 := SlideChapter{ + title := H1{text: "Chapter"} + } +} +``` + +### FileTree +``` +FileTree{} +// Driven programmatically: begin_folder/end_folder/file +``` + +## Shader System + +### Instance vs Uniform +``` +draw_bg +: { + hover: instance(0.0) // per-draw-call, animatable by Animator + color: uniform(#fff) // shared across all instances of this shader variant + tex: texture_2d(float) // texture sampler + my_var: varying(vec2(0)) // vertex→pixel interpolated (set in vertex shader) +} +``` +**When to use each:** +- `instance()` — state that varies per widget (hover, down, focus, active, disabled), per-widget colors, scale/pan. Driven by the Animator system. +- `uniform()` — theme constants shared by all instances (border_size, border_radius, theme colors). Cannot be animated. + +### Pixel Shader +``` +draw_bg +: { + pixel: fn() { + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + sdf.box(0. 0. self.rect_size.x self.rect_size.y 4.0) + sdf.fill(#f00) + return sdf.result // already premultiplied by sdf.fill(), no Pal.premul() needed + } +} +``` + +**⛔ CRITICAL: Premultiply colors returned from pixel()!** When you hand-code a `pixel: fn()` that returns a color (not via `sdf.result`), you MUST premultiply the alpha. Without this, colors with alpha (e.g. `#ffffff08`) will render as bright white instead of a subtle tint. Always wrap your return value in `Pal.premul()`: +``` +pixel: fn(){ + return Pal.premul(self.color.mix(self.color_hover, self.hover)) +} +``` +Note: `sdf.fill()` / `sdf.stroke()` already premultiply internally, so `return sdf.result` is safe without extra `Pal.premul()`. + +**Common pattern — fill + border stroke:** +``` +pixel: fn() { + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + sdf.box(1. 1. self.rect_size.x - 2. self.rect_size.y - 2. 4.0) + sdf.fill_keep(self.color) // fill the shape, keep it for stroke + sdf.stroke(self.border_color, 1.0) // stroke the same shape's outline + return sdf.result +} +``` + +### SDF Primitives +``` +sdf.circle(cx cy radius) +sdf.rect(x y w h) +sdf.box(x y w h border_radius) +sdf.box_all(x y w h r_lt r_rt r_rb r_lb) // per-corner radius +sdf.box_x(x y w h r_left r_right) +sdf.box_y(x y w h r_top r_bottom) +sdf.hexagon(cx cy radius) +sdf.hline(y half_height) +sdf.arc_round_caps(cx cy radius start_angle end_angle thickness) +sdf.arc_flat_caps(cx cy radius start_angle end_angle thickness) +``` + +### SDF Path Operations +``` +sdf.move_to(x y) +sdf.line_to(x y) +sdf.close_path() +``` + +### SDF Combinators + +These operate on the **current** shape and the **previous** shape. Draw two primitives, then combine: +``` +sdf.union() // merge shapes together (min of distances) +sdf.intersect() // keep only overlap (max of distances) +sdf.subtract() // cut current shape from previous shape +sdf.gloop(k) // smooth/gooey union with rounding factor k +sdf.blend(k) // linear blend: 0.0 = previous shape, 1.0 = current shape +``` +Example — ring (circle with hole): +``` +sdf.circle(cx cy outer_radius) +sdf.circle(cx cy inner_radius) +sdf.subtract() +sdf.fill(#fff) +``` +Example — blend for toggle animation: +``` +sdf.circle(x y r) // ring shape (from subtract above) +sdf.circle(x y r) // solid circle +sdf.blend(self.active) // animate between ring (0) and solid (1) +``` + +### SDF Drawing +``` +sdf.fill(color) // fill and reset shape +sdf.fill_keep(color) // fill, keep shape for subsequent stroke +sdf.stroke(color width) // stroke and reset shape +sdf.stroke_keep(color w) // stroke, keep shape +sdf.glow(color width) // additive glow around shape, reset +sdf.glow_keep(color w) // additive glow, keep shape +sdf.clear(color) // clear result buffer with color +``` + +### SDF Transforms +``` +sdf.translate(x y) +sdf.rotate(angle cx cy) +sdf.scale(factor cx cy) +``` + +### Built-in Shader Variables +``` +self.pos // vec2: normalized position [0,1] (computed from clipping in vertex shader) +self.rect_size // vec2: pixel size of the drawn rect +self.rect_pos // vec2: pixel position of the drawn rect +self.dpi_factor // float: display DPI factor for high-DPI screens +self.draw_pass.time // float: elapsed time in seconds (for continuous animation) +self.draw_pass.dpi_dilate // float: DPI dilation factor for pixel-perfect strokes +self.draw_depth // float: base depth for z-ordering +self.draw_zbias // float: z-bias offset added to depth +self.geom_pos // vec2: raw geometry position [0,1] (before clipping) +``` + +### Vertex Shader + +Most widgets use the default vertex shader from DrawQuad. You can override it for custom geometry expansion (e.g., shadows) or DPI-aware texture coordinates: +``` +draw_bg +: { + // custom varying to pass data from vertex to pixel shader + my_scale: varying(vec2(0)) + + vertex: fn() { + let dpi = self.dpi_factor + let ceil_size = ceil(self.rect_size * dpi) / dpi + self.my_scale = self.rect_size / ceil_size + return self.clip_and_transform_vertex(self.rect_pos self.rect_size) + } + pixel: fn() { + // my_scale is available here, interpolated from vertex + return Pal.premul(self.color) + } +} +``` +`self.clip_and_transform_vertex(rect_pos rect_size)` is the standard helper that handles clipping, view shift (scrolling), and camera projection. Always call it in custom vertex shaders. + +### Custom Shader Functions + +You can define named functions on a draw shader for reuse: +``` +draw_bg +: { + get_color: fn() { + return self.color + .mix(self.color_hover, self.hover) + .mix(self.color_down, self.down) + } + pixel: fn() { + return Pal.premul(self.get_color()) + } +} +``` +Functions with parameters: +``` +draw_bg +: { + get_color_at: fn(scale: vec2, pan: vec2) { + return self.my_texture.sample(self.pos * scale + pan) + } +} +``` + +### Mutable Variables + +Use `let mut` to declare mutable variables in shader code: +``` +pixel: fn() { + let mut color = self.color + if self.hover > 0.5 { + color = self.color_hover + } + return Pal.premul(color) +} +``` + +### Conditionals and Match + +Shaders support `if`/`else` and `match` on enum instance variables: +``` +pixel: fn() { + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + if self.is_vertical > 0.5 { + sdf.box(1. self.rect_size.y * self.scroll_pos 8. self.rect_size.y * self.handle_size 2.) + } else { + sdf.box(self.rect_size.x * self.scroll_pos 1. self.rect_size.x * self.handle_size 8. 2.) + } + sdf.fill(self.color) + return sdf.result +} +``` + +### Texture Sampling + +Declare texture samplers and sample them in pixel shaders: +``` +draw_bg +: { + my_tex: texture_2d(float) + pixel: fn() { + let color = self.my_tex.sample(self.pos) // standard 2D sampling + return Pal.premul(color) + } +} +``` +Alternative sampling functions: +``` +sample2d(self.my_tex, uv) // free-function form of texture sampling +sample2d_rt(self.image, uv) // sample from render-target texture (handles Y-flip on some platforms) +``` + +### Color Operations +``` +mix(color1 color2 factor) // linear interpolation (free function) +color1.mix(color2 factor) // method chaining form +#f00.mix(#0f0 0.5).mix(#00f hover) // multi-chain for state interpolation +Pal.premul(color) // premultiply alpha — REQUIRED when returning from pixel()! +Pal.hsv2rgb(vec4(h s v 1.0)) // HSV to RGB conversion +Pal.rgb2hsv(color) // RGB to HSV conversion +Pal.iq(t a b c d) // Inigo Quilez cosine color palette +Pal.iq0(t) .. Pal.iq7(t) // pre-built cosine color palettes +``` +⚠️ Always wrap your final color in `Pal.premul()` when returning from `pixel: fn()` (unless returning `sdf.result` which is already premultiplied). + +**Gradient pattern** — use `vec4(-1.0, -1.0, -1.0, -1.0)` as a sentinel for "no gradient", then check with `if self.color_2.x > -0.5`: +``` +color_2: uniform(vec4(-1.0, -1.0, -1.0, -1.0)) // sentinel: no gradient +pixel: fn() { + let mut fill = self.color + if self.color_2.x > -0.5 { + let dither = Math.random_2d(self.pos.xy) * 0.04 + let dir = self.pos.y + dither + fill = mix(self.color, self.color_2, dir) + } + return Pal.premul(fill) +} +``` + +### SDF Anti-aliasing + +The `sdf.aa` field controls anti-aliasing sharpness. Default is computed from viewport. Set higher for sharper edges: +``` +pixel: fn() { + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + sdf.aa = sdf.aa * 3.0 // sharper edges (useful for small icons) + sdf.move_to(c.x - sz, c.y - sz) + sdf.line_to(c.x + sz, c.y + sz) + sdf.stroke(#fff, 0.5 + 0.5 * self.draw_pass.dpi_dilate) + return sdf.result +} +``` + +### SDF fill_premul / fill_keep_premul + +When filling with a color that is already premultiplied (e.g., from a texture sample or render target): +``` +sdf.fill_premul(color) // fill with premultiplied color, reset shape +sdf.fill_keep_premul(color) // fill with premultiplied color, keep shape +``` + +### GaussShadow (box shadows) +``` +GaussShadow.box_shadow(lower upper point sigma) // fast rectangular shadow +GaussShadow.rounded_box_shadow(lower upper point sigma corner) // rounded rectangle shadow +``` +Used in shadow view variants (`RectShadowView`, `RoundedShadowView`) to render drop shadows efficiently. + +### Math Utilities +``` +// Custom Makepad functions +Math.random_2d(vec2) // pseudo-random 0-1 from vec2 seed (for dithering) +Math.rotate_2d(v angle) // 2D rotation of vector by angle + +// Constants +PI // 3.14159... +E // 2.71828... +TORAD // degrees→radians multiplier (0.01745...) +GOLDEN // golden ratio (1.61803...) + +// Standard GLSL math (all work on float, vec2, vec3, vec4) +sin(x) cos(x) tan(x) asin(x) acos(x) atan(y x) +pow(x y) sqrt(x) exp(x) exp2(x) log(x) log2(x) +abs(x) sign(x) floor(x) ceil(x) fract(x) mod(x y) +min(x y) max(x y) clamp(x min max) +step(edge x) smoothstep(edge0 edge1 x) + +// Vector operations +length(v) distance(a b) dot(a b) cross(a b) normalize(v) + +// Fragment-only (for advanced anti-aliasing) +dFdx(v) dFdy(v) // partial derivatives (used in text SDF rendering) +``` + +## Animator + +The animator drives `instance()` variables on draw shaders over time, enabling hover effects, transitions, and looping animations. + +### ⛔ CRITICAL: Only Certain Widgets Support Animator ⛔ + +**NOT all widgets have an `animator` field.** If you add `animator: Animator{...}` to a widget that doesn't support it, the definition is **silently ignored** — no error, no hover, nothing happens. + +**Widgets that SUPPORT animator:** `View`, `SolidView`, `RoundedView`, `ScrollXView`, `ScrollYView`, `ScrollXYView`, `Button`, `ButtonFlat`, `ButtonFlatter`, `CheckBox`, `Toggle`, `RadioButton`, `LinkLabel`, `TextInput` + +**Widgets that DO NOT support animator:** `Label`, `H1`–`H4`, `P`, `TextBox`, `Image`, `Icon`, `Markdown`, `Html`, `Slider`, `DropDown`, `Splitter`, `Hr`, `Filler` + +**To make a Label hoverable, wrap it in a View:** +``` +View{ + width: Fill height: Fit + cursor: MouseCursor.Hand + show_bg: true + draw_bg +: { + color: uniform(#0000) + color_hover: uniform(#fff2) + hover: instance(0.0) + pixel: fn(){ + return Pal.premul(self.color.mix(self.color_hover, self.hover)) + } + } + animator: Animator{ + hover: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.15}} + apply: {draw_bg: {hover: 0.0}} + } + on: AnimatorState{ + from: {all: Forward {duration: 0.15}} + apply: {draw_bg: {hover: 1.0}} + } + } + } + Label{text: "hoverable item" draw_text.color: #fff} +} +``` + +### Structure + +``` +animator: Animator{ + : { + default: @ // initial state (@ prefix required) + : AnimatorState{ + from: { ... } // transition timing + ease: // optional ease override + redraw: true // optional: force redraw each frame + apply: { ... } // target values + } + : AnimatorState{ ... } + } + : { ... } // multiple groups allowed +} +``` + +### Groups +Each group is an independent animation track (e.g. `hover`, `focus`, `active`, `disabled`, `time`). Multiple groups animate simultaneously without interfering. + +### The `from` Block +Controls when/how the transition plays. Keys are state names being transitioned FROM, or `all` as catch-all: +``` +from: {all: Forward {duration: 0.2}} // from any state +from: {all: Snap} // instant from any state +from: { + all: Forward {duration: 0.1} // default + down: Forward {duration: 0.01} // faster when coming from "down" +} +``` + +### The `apply` Block +Target values to animate TO. The structure mirrors the widget's property tree. Keys are the widget's sub-objects (like `draw_bg`, `draw_text`), values are the shader instance variables to animate: + +``` +apply: { + draw_bg: {hover: 1.0} // animate draw_bg.hover to 1.0 + draw_text: {hover: 1.0} // animate draw_text.hover to 1.0 +} +``` + +Multiple properties in one block: +``` +apply: { + draw_bg: {down: 1.0, hover: 0.5} + draw_text: {down: 1.0, hover: 0.5} +} +``` + +For non-draw properties (e.g. a float field on the widget itself): +``` +apply: { + opened: 1.0 // animate widget's own "opened" field + active: 0.0 // animate widget's own "active" field +} +``` + +### snap() — Instant Jump +Wrapping a value in `snap()` makes it jump instantly instead of interpolating: +``` +apply: { + draw_bg: {down: snap(1.0), hover: 1.0} // down jumps, hover interpolates +} +``` + +### timeline() — Keyframes +Animate through multiple values over the duration using time/value pairs (times 0.0–1.0): +``` +apply: { + draw_bg: {anim_time: timeline(0.0 0.0 1.0 1.0)} // linear 0→1 +} +``` + +### Complete Button Animator Example +``` +animator: Animator{ + disabled: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.}} + apply: { + draw_bg: {disabled: 0.0} + draw_text: {disabled: 0.0} + } + } + on: AnimatorState{ + from: {all: Forward {duration: 0.2}} + apply: { + draw_bg: {disabled: 1.0} + draw_text: {disabled: 1.0} + } + } + } + hover: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.1}} + apply: { + draw_bg: {down: 0.0, hover: 0.0} + draw_text: {down: 0.0, hover: 0.0} + } + } + on: AnimatorState{ + from: { + all: Forward {duration: 0.1} + down: Forward {duration: 0.01} + } + apply: { + draw_bg: {down: 0.0, hover: snap(1.0)} + draw_text: {down: 0.0, hover: snap(1.0)} + } + } + down: AnimatorState{ + from: {all: Forward {duration: 0.2}} + apply: { + draw_bg: {down: snap(1.0), hover: 1.0} + draw_text: {down: snap(1.0), hover: 1.0} + } + } + } + focus: { + default: @off + off: AnimatorState{ + from: {all: Snap} + apply: { + draw_bg: {focus: 0.0} + draw_text: {focus: 0.0} + } + } + on: AnimatorState{ + from: {all: Snap} + apply: { + draw_bg: {focus: 1.0} + draw_text: {focus: 1.0} + } + } + } + time: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.}} + apply: {} + } + on: AnimatorState{ + from: {all: Loop {duration: 1.0, end: 1000000000.0}} + apply: { + draw_bg: {anim_time: timeline(0.0 0.0 1.0 1.0)} + } + } + } +} +``` + +### Play Types (transition modes) +``` +Forward {duration: 0.2} // play once forward +Snap // instant (no interpolation) +Reverse {duration: 0.2, end: 1.0} // play in reverse +Loop {duration: 1.0, end: 1000000000.0} // repeat forward +ReverseLoop {duration: 1.0, end: 1.0} // repeat in reverse +BounceLoop {duration: 1.0, end: 1.0} // bounce back and forth +``` + +### Ease Functions +``` +Linear // default +InQuad OutQuad InOutQuad +InCubic OutCubic InOutCubic +InQuart OutQuart InOutQuart +InQuint OutQuint InOutQuint +InSine OutSine InOutSine +InExp OutExp InOutExp +InCirc OutCirc InOutCirc +InElastic OutElastic InOutElastic +InBack OutBack InOutBack +InBounce OutBounce InOutBounce +ExpDecay {d1: 0.82, d2: 0.97, max: 100} +Pow {begin: 0.0, end: 1.0} +Bezier {cp0: 0.0, cp1: 0.0, cp2: 1.0, cp3: 1.0} +``` + +## Theme Variables (prefix: `theme.`) + +### Spacing +`space_1` `space_2` `space_3` + +### Inset Presets +`mspace_1` `mspace_2` `mspace_3` (uniform) +`mspace_h_1` `mspace_h_2` `mspace_h_3` (horizontal only) +`mspace_v_1` `mspace_v_2` `mspace_v_3` (vertical only) + +### Dimensions +`corner_radius` `beveling` `tab_height` `splitter_size` `container_corner_radius` `dock_border_size` + +### Colors (key ones) +`color_bg_app` `color_fg_app` `color_bg_container` `color_bg_even` `color_bg_odd` +`color_text` `color_text_hl` `color_text_disabled` +`color_label_inner` `color_label_outer` (+ `_hover` `_down` `_focus` `_active` `_disabled`) +`color_inset` (+ variants) `color_outset` (+ variants) +`color_bevel` (+ variants) +`color_shadow` `color_highlight` `color_makepad` (#FF5C39) +`color_white` `color_black` +`color_error` `color_warning` `color_panic` +`color_selection_focus` `color_cursor` +`color_u_1`..`color_u_6` (light scale) `color_d_1`..`color_d_5` (dark scale) +`color_u_hidden` `color_d_hidden` (transparent) +`color_drag_target_preview` +`color_val` `color_handle` (+ `_hover` `_focus` `_drag` `_disabled`) — slider colors +`color_mark_off` `color_mark_active` (+ variants) — check/radio marks +`color_app_caption_bar` + +### Typography +`font_size_1`..`font_size_4` `font_size_p` `font_size_code` `font_size_base` +`font_regular` `font_bold` `font_italic` `font_bold_italic` `font_code` `font_icons` +`font_wdgt_line_spacing` `font_longform_line_spacing` + +## Enums Reference + +### MouseCursor +`Default` `Hand` `Arrow` `Text` `Move` `Wait` `Help` `NotAllowed` `Crosshair` `Grab` `Grabbing` `NResize` `EResize` `SResize` `WResize` `NsResize` `EwResize` `ColResize` `RowResize` `Hidden` +Usage: `cursor: MouseCursor.Hand` + +### ImageFit +`Stretch` `Horizontal` `Vertical` `Smallest` `Biggest` `Size` + +### SplitterAxis +`Horizontal` `Vertical` + +### SplitterAlign +`FromA(250.0)` `FromB(200.0)` `Weighted(0.5)` + +### SlideSide +`Left` `Right` `Top` + +### DragAxis (for Slider) +`Horizontal` `Vertical` + +### ImageAnimation +`Stop` `Once` `Loop` `Bounce` `Frame(0.0)` `Factor(0.0)` `OnceFps(60.0)` `LoopFps(60.0)` `BounceFps(60.0)` + +## Common Patterns + +**REMINDER: Every container below uses `height: Fit` — you must too!** + +### Colored card +``` +RoundedView{ + width: Fill height: Fit + padding: 15 flow: Down spacing: 8 + draw_bg.color: #445 + draw_bg.border_radius: 8.0 + Label{text: "Card Title" draw_text.color: #fff} +} +``` + +### Sidebar + content +``` +View{ + width: Fill height: Fill + flow: Right + SolidView{ + width: 250 height: Fill + draw_bg.color: #222 + flow: Down padding: 10 + } + View{ + width: Fill height: Fill + flow: Down padding: 15 + } +} +``` + +### Sidebar + content using Splitter +``` +Splitter{ + axis: SplitterAxis.Horizontal + align: SplitterAlign.FromA(250.0) + a := sidebar + b := main +} +sidebar := View{ width: Fill height: Fill flow: Down padding: 10 } +main := View{ width: Fill height: Fill flow: Down padding: 15 } +``` + +### Overlay (modal/tooltip pattern) +``` +View{ height: Fit + flow: Overlay + View{ height: Fit width: Fill ... } // base content + View{ height: Fit align: Center ... } // overlay on top +} +``` + +### Scrollable list +``` +ScrollYView{ + width: Fill height: Fill + flow: Down padding: 10 spacing: 8 + Label{text: "Item 1"} + Label{text: "Item 2"} +} +``` + +### Custom shader widget +Note: `View{ show_bg: true }` is OK here because we provide a complete custom `pixel` shader that overrides the ugly default. +``` +View{ + width: 200 height: 200 + show_bg: true + draw_bg +: { + pixel: fn(){ + let sdf = Sdf2d.viewport(self.pos * self.rect_size) + sdf.circle( + self.rect_size.x * 0.5 + self.rect_size.y * 0.5 + min(self.rect_size.x self.rect_size.y) * 0.4 + ) + sdf.fill(#f80) + return sdf.result // already premultiplied by sdf.fill(), no Pal.premul() needed + } + } +} +``` + +### Hoverable list item +Label does NOT support animator. Wrap it in a View to get hover effects. Use `label :=` to declare the inner Label so each instance can override its text via `label.text:`: +``` +let HoverItem = View{ + width: Fill height: Fit + padding: 8 + cursor: MouseCursor.Hand + new_batch: true + show_bg: true + draw_bg +: { + color: uniform(#0000) + color_hover: uniform(#fff2) + hover: instance(0.0) + pixel: fn(){ + return self.color.mix(self.color_hover, self.hover) + } + } + animator: Animator{ + hover: { + default: @off + off: AnimatorState{ + from: {all: Forward {duration: 0.15}} + apply: {draw_bg: {hover: 0.0}} + } + on: AnimatorState{ + from: {all: Forward {duration: 0.15}} + apply: {draw_bg: {hover: 1.0}} + } + } + } + label := Label{text: "item" draw_text.color: #fff} +} + +RoundedView{ + width: 300 height: Fit + padding: 10 flow: Down spacing: 4 + new_batch: true + draw_bg.color: #222 + draw_bg.border_radius: 5.0 + Label{text: "Todo Items" draw_text.color: #fff} + HoverItem{label.text: "Walk the dog"} + HoverItem{label.text: "Do laundry"} + HoverItem{label.text: "Buy groceries"} +} +``` + +### Toolbar pattern +``` +RectShadowView{ + width: Fill height: 38. + flow: Down padding: theme.mspace_2 + draw_bg +: { + shadow_color: theme.color_shadow + shadow_radius: 7.5 + color: theme.color_fg_app + } + content := View{ + height: Fit width: Fill + flow: Right spacing: theme.space_2 + align: Align{x: 0. y: 0.5} + ButtonFlatter{text: "File"} + ButtonFlatter{text: "Edit"} + Filler{} + ButtonFlat{text: "Run"} + } +} +``` + +## HTTP Requests (`net.http_request`) + +Make async HTTP requests from script. Responses arrive via callbacks. + +### GET request +``` +let req = net.HttpRequest{ + url: "https://html.duckduckgo.com/html/?q=rust+programming" + method: net.HttpMethod.GET + headers: {"User-Agent": "MakepadApp/1.0"} +} +net.http_request(req) do net.HttpEvents{ + on_response: |res| { + let text = res.body.to_string() // body as string + let json = res.body.parse_json() // or parse as JSON + // res.status_code // HTTP status (200, 404, etc.) + } + on_error: |e| { + // e.message // error description + } +} +``` + +### POST request with JSON body +``` +let req = net.HttpRequest{ + url: "https://api.example.com/data" + method: net.HttpMethod.POST + headers: {"Content-Type": "application/json"} + body: {key: "value" count: 42}.to_json() +} +net.http_request(req) do net.HttpEvents{ + on_response: |res| { /* ... */ } + on_error: |e| { /* ... */ } +} +``` + +### Streaming response +``` +let req = net.HttpRequest{ + url: "https://api.example.com/stream" + method: net.HttpMethod.POST + is_streaming: true + body: {stream: true}.to_json() +} +var total = "" +net.http_request(req) do net.HttpEvents{ + on_stream: |res| { + total += res.body.to_string() // called per chunk + } + on_complete: |res| { + // stream finished, total has all data + } + on_error: |e| { /* ... */ } +} +``` + +### HttpMethod values +`net.HttpMethod.GET`, `POST`, `PUT`, `DELETE`, `HEAD`, `PATCH`, `OPTIONS` + +### Cookie-free search endpoints +DuckDuckGo provides HTML endpoints that return static HTML — no cookies, no JS, no API key: +- `https://html.duckduckgo.com/html/?q=QUERY` — div-based, CSS classes for results +- `https://lite.duckduckgo.com/lite/?q=QUERY` — table-based, ~10kB compressed + +Both require a `User-Agent` header. Results can be parsed with `parse_html()`. + +--- + +## HTML Parsing (`parse_html`) + +Parse an HTML string and query it with CSS-like selectors. Call `.parse_html()` on any string. + +### Basic usage +``` +let html = "

Hello

World

" +let doc = html.parse_html() +``` + +### Querying elements +``` +doc.query("p") // all

elements (returns html handle) +doc.query("p[0]") // first

element +doc.query("#main") // element with id "main" +doc.query("p.bold") //

with class "bold" +doc.query("div > p") // direct children +doc.query("div p") // descendants +doc.query("div > *") // all direct children (wildcard) +doc.query("div").query("p") // chained queries +``` + +### Extracting data +``` +doc.query("p[0]").text // text content: "Hello" +doc.query("div@class") // attribute value: "box" +doc.query("div@id") // attribute value: "main" +doc.query("p.text") // array of text from all

: ["Hello", "World"] +doc.query("p@class") // array of class attrs from all

+``` + +### Properties on html handles +``` +handle.length // number of matched elements +handle.text // text content (concatenated) +handle.html // reconstructed HTML string +handle.attr("name") // attribute value (string or nil) +handle.array() // convert to array of element handles +``` + +### Iterating results +``` +let items = doc.query("a.result__a").array() +for item, i in items { + let title = item.text + let href = item.attr("href") + // ... use title and href +} +``` + +### Full example: search DuckDuckGo and parse results +``` +fn do_search(query) { + let req = net.HttpRequest{ + url: "https://html.duckduckgo.com/html/?q=" + query + method: net.HttpMethod.GET + headers: {"User-Agent": "MakepadApp/1.0"} + } + net.http_request(req) do net.HttpEvents{ + on_response: |res| { + let doc = res.body.to_string().parse_html() + let links = doc.query("a.result__a").array() + let snippets = doc.query("a.result__snippet").array() + for link, i in links { + let title = link.text + let url = link.attr("href") + let snippet = if i < snippets.len() snippets[i].text else "" + // ... build result list + } + } + on_error: |e| { /* handle error */ } + } +} +``` + +--- + +## Notes + +- **⛔ Default text color is WHITE.** For light/white themes, set `draw_text.color` to a dark color (e.g. `#222`, `#333`) on ALL text elements. Otherwise text is invisible (white-on-white). +- **⛔ Set `new_batch: true` on ANY View with `show_bg: true` that contains text.** Makepad batches same-shader widgets into one draw call. Without `new_batch: true`, text renders behind backgrounds (invisible text). This is especially critical for **hoverable items** — text vanishes on hover when the background becomes opaque. Set it on BOTH the item template AND the parent container. +- **⚠️ ALWAYS set `height: Fit` on containers!** The default is `height: Fill` which causes 0-height (invisible UI) in this context. +- **⛔ Named children in `let` templates MUST use `:=`:** `label := Label{...}`, `tag := Label{...}`, `check := CheckBox{...}`. Override with `Item{label.text: "x"}`. Without `:=`, text is invisible. +- **⛔ Named children inside anonymous Views are UNREACHABLE.** If `label :=` is inside an unnamed `View{}`, `Item{label.text: "x"}` fails silently. Give the View a name: `texts := View{ label := Label{...} }` then override with `Item{texts.label.text: "x"}`. +- **🚫 DO NOT invent properties or syntax.** Only use what's documented in this manual. No guessing. +- No commas between sibling properties (space or newline separated) +- **Use commas when values contain negative numbers or could be parsed as expressions**: `vec4(-1.0, -1.0, -1.0, -1.0)` NOT `vec4(-1.0 -1.0 -1.0 -1.0)` (the parser would see `-1.0 -1.0` as subtraction). Safe rule: always use commas inside `vec2()`, `vec4()`, and array literals when any value is negative or an expression +- `+:` merges with parent; without it, replaces entirely +- `:=` declares named/dynamic/template children (e.g. `label := Label{...}`) +- Bare numbers for Size become `Fixed(n)`: `width: 200` = `width: Size.Fixed(200)` +- Resources: `crate_resource("self://relative/path")` +- Function args in shaders: space-separated, no commas: `sdf.box(0. 0. 100. 100. 5.0)` +- `if` in shaders: `if condition { ... } else { ... }` (no parens around condition) +- `for` in shaders: `for i in 0..4 { ... }` +- `match` in shaders: `match self.block_type { Type.A => { ... } Type.B => { ... } }` +- Inherit + override: `theme.mspace_1{left: theme.space_2}` — takes mspace_1 but overrides left +- Strings use double quotes only: `text: "Hello"`. No single quotes, no backticks. + +## Guidelines + +- Use runsplash blocks for anything visual: UI mockups, styled cards, layouts, color palettes, shader demos, button groups, form layouts, etc. +- You can have multiple runsplash blocks in a single response, mixed with normal markdown text. +- Keep splash blocks focused — one concept per block when possible. +- Use `let` bindings at the top of a block to define reusable styled components, then instantiate them below. +- Use theme variables (theme.color_bg_app, theme.space_2, etc.) for consistent styling. +- For simple text answers, just use normal markdown without runsplash blocks. + +## Vector Widget (SVG-like Drawing) + +The `Vector{}` widget renders SVG-like vector graphics declaratively in Splash. It supports paths, shapes, gradients, filters, groups, transforms, and animations — all without loading external SVG files. + +### Basic Usage + +``` +Vector{width: 200 height: 200 viewbox: vec4(0 0 200 200) + Rect{x: 10 y: 10 w: 80 h: 60 rx: 5 ry: 5 fill: #f80} + Circle{cx: 150 cy: 50 r: 30 fill: #08f} + Line{x1: 10 y1: 150 x2: 190 y2: 150 stroke: #fff stroke_width: 2} +} +``` + +The `viewbox` property defines the coordinate space as `vec4(x y width height)`. The widget sizes itself to fit the viewbox when `width: Fit` and `height: Fit` (the defaults), or you can set explicit pixel dimensions. + +### Shape Types + +All shapes support these common style properties: + +| Property | Type | Default | Notes | +|----------|------|---------|-------| +| `fill` | color, Gradient, RadGradient, Tween, or `false` | inherited | `false` = no fill | +| `fill_opacity` | f32 | 1.0 | multiplied with fill alpha | +| `stroke` | color, Gradient, or Tween | none | outline color | +| `stroke_width` | f32 or Tween | 0.0 | outline thickness | +| `stroke_opacity` | f32 or Tween | 1.0 | outline alpha | +| `opacity` | f32 or Tween | 1.0 | overall shape opacity | +| `stroke_linecap` | string | "butt" | "butt", "round", "square" | +| `stroke_linejoin` | string | "miter" | "miter", "round", "bevel" | +| `transform` | Transform or array | identity | see Transforms section | +| `filter` | Filter ref | none | see Filters section | +| `shader_id` | f32 | 0.0 | for custom GPU effects on Svg widget | + +#### Path — SVG path data +``` +Path{d: "M 10 10 L 100 100 C 50 50 200 200 300 300 Z" fill: #f00 stroke: #000 stroke_width: 2} +``` +The `d` property accepts standard SVG path data strings (M, L, C, Q, A, Z, etc.). + +#### Rect — Rectangle +``` +Rect{x: 10 y: 20 w: 100 h: 50 rx: 5 ry: 5 fill: #f80 stroke: #fff stroke_width: 1} +``` + +#### Circle +``` +Circle{cx: 50 cy: 50 r: 40 fill: #08f} +``` + +#### Ellipse +``` +Ellipse{cx: 100 cy: 50 rx: 80 ry: 40 fill: #0f8} +``` + +#### Line +``` +Line{x1: 10 y1: 10 x2: 190 y2: 190 stroke: #fff stroke_width: 2 stroke_linecap: "round"} +``` + +#### Polyline — open connected segments +``` +Polyline{pts: [10 10 50 80 100 20 150 90] fill: false stroke: #ff0 stroke_width: 2} +``` + +#### Polygon — closed connected segments +``` +Polygon{pts: [100 10 40 198 190 78 10 78 160 198] fill: #f0f stroke: #fff stroke_width: 1} +``` + +### Groups + +`Group{}` composes shapes and applies shared styles/transforms to all children: + +``` +Vector{width: 200 height: 200 viewbox: vec4(0 0 200 200) + Group{opacity: 0.7 transform: Rotate{deg: 15} + Rect{x: 20 y: 20 w: 60 h: 60 fill: #f00} + Circle{cx: 130 cy: 50 r: 30 fill: #0f0} + } +} +``` + +Groups can be nested. Style properties on a Group (fill, stroke, etc.) apply to its children. + +### Gradients + +Define gradients as `let` bindings and reference them in `fill` or `stroke`: + +#### Linear Gradient +``` +let my_grad = Gradient{x1: 0 y1: 0 x2: 1 y2: 1 + Stop{offset: 0 color: #ff0000} + Stop{offset: 0.5 color: #00ff00} + Stop{offset: 1 color: #0000ff} +} + +Vector{width: 200 height: 100 viewbox: vec4(0 0 200 100) + Rect{x: 0 y: 0 w: 200 h: 100 fill: my_grad} +} +``` + +Gradient coordinates (`x1`, `y1`, `x2`, `y2`) are in the range 0–1 (object bounding box). `Stop` children define color stops with `offset` (0–1), `color`, and optional `opacity`. + +#### Radial Gradient +``` +let radial = RadGradient{cx: 0.5 cy: 0.5 r: 0.5 + Stop{offset: 0 color: #fff} + Stop{offset: 1 color: #000} +} + +Vector{width: 200 height: 200 viewbox: vec4(0 0 200 200) + Circle{cx: 100 cy: 100 r: 90 fill: radial} +} +``` + +RadGradient properties: `cx`, `cy` (center, default 0.5), `r` (radius, default 0.5), `fx`, `fy` (focal point, defaults to center). + +#### Gradient stops with opacity +``` +let glass = Gradient{x1: 0 y1: 0 x2: 1 y2: 1 + Stop{offset: 0 color: #xffffff opacity: 0.35} + Stop{offset: 0.4 color: #xffffff opacity: 0.08} + Stop{offset: 1 color: #xffffff opacity: 0.2} +} +``` + +### Filters + +Define a `Filter` with `DropShadow` effects: + +``` +let shadow = Filter{ + DropShadow{dx: 2 dy: 4 blur: 6 color: #000000 opacity: 0.5} +} + +Vector{width: 200 height: 200 viewbox: vec4(0 0 200 200) + Rect{x: 40 y: 40 w: 120 h: 120 rx: 10 ry: 10 fill: #445 filter: shadow} +} +``` + +DropShadow properties: `dx` (x offset), `dy` (y offset), `blur` (blur radius), `color`, `opacity`. + +### Transforms + +Transforms can be applied to any shape or group via the `transform` property. Use a single transform or an array of transforms (composed left-to-right): + +#### Static transforms +``` +// Single transform +Rect{x: 0 y: 0 w: 50 h: 50 fill: #f00 transform: Rotate{deg: 45}} + +// Multiple transforms (composed left-to-right) +Group{transform: [Translate{x: 100 y: 50} Scale{x: 2 y: 2} Rotate{deg: 30}] + Circle{cx: 0 cy: 0 r: 20 fill: #0ff} +} +``` + +Available transforms: +- `Rotate{deg: 45}` — rotation in degrees. Optional `cx`, `cy` for rotation center +- `Scale{x: 2 y: 1.5}` — scale factors. If only `x` is given, `y` defaults to the same value +- `Translate{x: 100 y: 50}` — translation offset +- `SkewX{deg: 30}` — horizontal skew +- `SkewY{deg: 15}` — vertical skew + +#### Animated transforms +Add `dur`, `from`, `to` (or `values`), and optionally `loop_` and `begin` to animate: + +``` +// Continuously rotating shape +Circle{cx: 100 cy: 100 r: 30 fill: #0ff + transform: Rotate{deg: 0 dur: 2.0 from: 0 to: 360 loop_: true} +} + +// Animated scale +Rect{x: 50 y: 50 w: 40 h: 40 fill: #f80 + transform: Scale{x: 1 dur: 1.5 from: 1 to: 2 loop_: true} +} +``` + +### Tween (Property Animation) + +Use `Tween{}` to animate individual shape properties (fill, stroke, d, x, y, r, etc.): + +``` +// Animated path morphing +Path{d: Tween{ + dur: 2.0 loop_: true + values: ["M 10 80 Q 50 10 100 80" "M 10 80 Q 50 150 100 80"] +} fill: #f0f} + +// Animated fill color +Circle{cx: 50 cy: 50 r: 30 + fill: Tween{dur: 1.5 loop_: true from: #ff0000 to: #0000ff} +} + +// Animated stroke width +Rect{x: 10 y: 10 w: 80 h: 80 + fill: false stroke: #fff + stroke_width: Tween{dur: 2.0 loop_: true from: 1 to: 5} +} +``` + +Tween properties: +- `from`, `to` — start and end values +- `values` — array of keyframe values (alternative to from/to) +- `dur` — duration in seconds +- `begin` — start delay in seconds +- `loop_` — `true` for indefinite, or a number for repeat count +- `calc` — "linear" (default), "discrete", "paced", "spline" +- `fill_mode` — "remove" (default) or "freeze" + +### Complete Example: App Icon with Gradients, Groups, and Filters + +This example from the splash demo recreates the Makepad app icon using Vector: + +``` +// Define gradients +let glass_bg = Gradient{x1: 0 y1: 0 x2: 1 y2: 1 + Stop{offset: 0 color: #x556677 opacity: 0.45} + Stop{offset: 1 color: #x334455 opacity: 0.35} +} +let brain_grad = Gradient{x1: 0.5 y1: 0 x2: 0.5 y2: 1 + Stop{offset: 0 color: #x77ccff} + Stop{offset: 0.4 color: #x7799ee} + Stop{offset: 0.75 color: #x8866dd} + Stop{offset: 1 color: #x9944cc} +} +let brain_glow = RadGradient{cx: 0.5 cy: 0.45 r: 0.45 + Stop{offset: 0 color: #x4466ee opacity: 0.4} + Stop{offset: 1 color: #x4466dd opacity: 0.0} +} + +// Define filter +let icon_shadow = Filter{ + DropShadow{dx: 0 dy: 4 blur: 6 color: #x000000 opacity: 0.5} +} + +Vector{width: 256 height: 256 viewbox: vec4(0 0 256 256) + // Glass background with shadow + Rect{x: 16 y: 16 w: 224 h: 224 rx: 44 ry: 44 + fill: glass_bg filter: icon_shadow} + + // Brain glow + Circle{cx: 128 cy: 95 r: 80 fill: brain_glow} + + // Brain paths (scaled and translated group) + Group{transform: [Translate{x: 36.8 y: 11.4} Scale{x: 7.6 y: 7.6}] + Path{d: "M15.5 13a3.5 3.5 0 0 0 -3.5 3.5v1a3.5 3.5 0 0 0 7 0v-1.8" + fill: false stroke: brain_grad stroke_width: 0.35 + stroke_linecap: "round" stroke_linejoin: "round"} + Path{d: "M8.5 13a3.5 3.5 0 0 1 3.5 3.5v1a3.5 3.5 0 0 1 -7 0v-1.8" + fill: false stroke: brain_grad stroke_width: 0.35 + stroke_linecap: "round" stroke_linejoin: "round"} + } + + // Keyboard keys + Rect{x: 73 y: 190 w: 9 h: 6 rx: 1 ry: 1 fill: #xffffff fill_opacity: 0.18} + Rect{x: 85 y: 190 w: 9 h: 6 rx: 1 ry: 1 fill: #xffffff fill_opacity: 0.18} +} +``` + +### SVG Icons in Vector + +Simple SVG icons can be embedded directly as `Path` shapes: + +``` +// File icon (from icon_file.svg) +Vector{width: 32 height: 32 viewbox: vec4(0 0 49 49) + Path{d: "M12.069,11.678c0,-2.23 1.813,-4.043 4.043,-4.043l10.107,0l0,8.086c0,1.118 0.903,2.021 2.021,2.021l8.086,0l0,18.193c0,2.23 -1.813,4.043 -4.043,4.043l-16.171,0c-2.23,0 -4.043,-1.813 -4.043,-4.043l0,-24.257Zm24.257,4.043l-8.086,0l0,-8.086l8.086,8.086Z"} +} + +// Folder icon +Vector{width: 32 height: 32 viewbox: vec4(0 0 49 49) + Path{d: "M11.884,37.957l24.257,0c2.23,0 4.043,-1.813 4.043,-4.043l0,-16.172c0,-2.23 -1.813,-4.042 -4.043,-4.042l-10.107,0c-0.638,0 -1.238,-0.297 -1.617,-0.809l-1.213,-1.617c-0.765,-1.017 -1.965,-1.617 -3.235,-1.617l-8.085,0c-2.23,0 -4.043,1.813 -4.043,4.043l0,20.214c0,2.23 1.813,4.043 4.043,4.043Z"} +} +``` + +### Vector vs Svg Widget + +| | `Vector{}` | `Svg{}` | +|---|---|---| +| **Input** | Declarative shapes in Splash script | External `.svg` file via resource handle | +| **Use case** | Programmatic/inline vector graphics | Loading pre-made SVG assets | +| **Gradients** | `let` bindings, referenced by name | Parsed from SVG `` | +| **Animation** | `Tween{}` on properties, animated transforms | Parsed from SVG `` elements | +| **Custom shaders** | `shader_id` + custom `get_color` on Svg | Same mechanism via `draw_svg +:` | +| **Syntax** | `Vector{viewbox: ... Path{} Rect{}}` | `Svg{draw_svg +: {svg: crate_resource("self://file.svg")}}` | + +Use `Vector{}` when you want to define graphics inline in your UI script. Use `Svg{}` when loading existing SVG files as assets. + +### Hex Color Escaping Reminder + +When using hex colors containing the letter `e` inside `script_mod!`, use the `#x` prefix to avoid parse errors: +``` +// These need #x prefix (contain 'e' adjacent to digits) +fill: #x2ecc71 +fill: #x1e1e2e +fill: #x4466ee + +// These are fine without #x (no 'e' issue) +fill: #ff4444 +fill: #00ff00 +``` + +## MathView Widget (LaTeX Math Rendering) + +The `MathView{}` widget renders LaTeX mathematical equations using vector glyph rendering with the NewCMMath font. + +### Basic Usage + +``` +MathView{text: "x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}" font_size: 14.0} +``` + +### Properties + +| Property | Type | Default | Notes | +|----------|------|---------|-------| +| `text` | string | "" | LaTeX math expression | +| `font_size` | f64 | 11.0 | Font size in points | +| `color` | vec4 | #fff | Color of rendered math | +| `width` | Size | Fit | Widget width | +| `height` | Size | Fit | Widget height | + +### Examples + +``` +// Inline in a layout +View{flow: Down height: Fit spacing: 12 padding: 15 + + Label{text: "Quadratic Formula" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}" font_size: 14.0} + + Label{text: "Euler's Identity" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "e^{i\\pi} + 1 = 0" font_size: 16.0} + + Label{text: "Integral" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}" font_size: 14.0} + + Label{text: "Matrix" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}" font_size: 14.0} + + Label{text: "Sum" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "\\sum_{n=1}^{\\infty} \\frac{1}{n^2} = \\frac{\\pi^2}{6}" font_size: 14.0} + + Label{text: "Maxwell's Equations" draw_text.color: #aaa draw_text.text_style.font_size: 10} + MathView{text: "\\nabla \\times \\mathbf{E} = -\\frac{\\partial \\mathbf{B}}{\\partial t}" font_size: 14.0} +} +``` + +### Different Sizes + +``` +View{width: Fill height: Fit flow: Right spacing: 15 align: Align{y: 0.5}} +MathView{text: "\\alpha + \\beta" font_size: 8.0} +MathView{text: "\\alpha + \\beta" font_size: 12.0} +MathView{text: "\\alpha + \\beta" font_size: 18.0} +MathView{text: "\\alpha + \\beta" font_size: 24.0} +``` + +### Supported LaTeX + +**Fractions & Roots:** +`\frac{a}{b}`, `\dfrac{a}{b}`, `\tfrac{a}{b}`, `\sqrt{x}`, `\sqrt[n]{x}` + +**Subscripts & Superscripts:** +`x_i`, `x^2`, `x_i^2`, `a_{n+1}` + +**Greek Letters (lowercase):** +`\alpha`, `\beta`, `\gamma`, `\delta`, `\epsilon`, `\zeta`, `\eta`, `\theta`, `\lambda`, `\mu`, `\nu`, `\xi`, `\pi`, `\rho`, `\sigma`, `\tau`, `\phi`, `\chi`, `\psi`, `\omega` + +**Greek Letters (uppercase):** +`\Gamma`, `\Delta`, `\Theta`, `\Lambda`, `\Xi`, `\Pi`, `\Sigma`, `\Phi`, `\Psi`, `\Omega` + +**Big Operators:** +`\sum`, `\prod`, `\int`, `\iint`, `\iiint`, `\oint`, `\bigcup`, `\bigcap`, `\bigoplus`, `\bigotimes` + +**Relations:** +`=`, `\neq`, `<`, `>`, `\leq`, `\geq`, `\sim`, `\approx`, `\equiv`, `\subset`, `\supset`, `\in`, `\notin` + +**Arrows:** +`\leftarrow`, `\rightarrow`, `\leftrightarrow`, `\Leftarrow`, `\Rightarrow`, `\Leftrightarrow`, `\mapsto` + +**Accents:** +`\hat{x}`, `\bar{x}`, `\tilde{x}`, `\vec{x}`, `\dot{x}`, `\ddot{x}`, `\overline{x}`, `\underline{x}` + +**Delimiters (auto-sizing with \left...\right):** +`\left( \right)`, `\left[ \right]`, `\left\{ \right\}`, `\left| \right|`, `\langle \rangle`, `\lfloor \rfloor`, `\lceil \rceil` + +**Matrices:** +``` +\begin{pmatrix} a & b \\ c & d \end{pmatrix} % parentheses +\begin{bmatrix} a & b \\ c & d \end{bmatrix} % brackets +\begin{vmatrix} a & b \\ c & d \end{vmatrix} % determinant bars +\begin{cases} a & \text{if } x > 0 \\ b & \text{otherwise} \end{cases} +``` + +**Styles:** +`\mathbf{x}` (bold), `\mathit{x}` (italic), `\mathrm{x}` (roman), `\mathcal{x}` (calligraphic), `\mathbb{R}` (blackboard bold), `\mathfrak{g}` (fraktur) + +**Spacing:** +`\,` (thin), `\:` (medium), `\;` (thick), `\!` (negative thin), `\quad`, `\qquad` + +**Text & Operators:** +`\text{...}`, `\sin`, `\cos`, `\tan`, `\log`, `\ln`, `\exp`, `\lim`, `\min`, `\max`, `\det` + +**Dots:** +`\ldots`, `\cdots`, `\vdots`, `\ddots` + +**Misc Symbols:** +`\infty`, `\partial`, `\nabla`, `\forall`, `\exists`, `\emptyset`, `\pm`, `\mp`, `\times`, `\div`, `\cdot` + +### Notes + +- MathView is read-only — no selection or editing +- Uses Display math style (large operators centered) +- Backslashes must be escaped as `\\` in Splash strings +- The widget sizes itself to fit the rendered equation by default (`width: Fit`, `height: Fit`) +- An empty `text` produces no output + diff --git a/resources/icons/search.svg b/resources/icons/search.svg index 52f7f3ff4..a685692b8 100644 --- a/resources/icons/search.svg +++ b/resources/icons/search.svg @@ -1,5 +1,3 @@ - - - - + + diff --git a/resources/icons/settings.svg b/resources/icons/settings.svg index 302f3e489..f047ec0cd 100644 --- a/resources/icons/settings.svg +++ b/resources/icons/settings.svg @@ -1,12 +1,3 @@ - - - - - - - - - - \ No newline at end of file + + + diff --git a/resources/img/default_avatar.png b/resources/img/default_avatar.png deleted file mode 100644 index bbd4fc661..000000000 Binary files a/resources/img/default_avatar.png and /dev/null differ diff --git a/src/app.rs b/src/app.rs index d3ea88bdc..3a1665b82 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use std::{cell::RefCell, collections::HashMap}; use makepad_widgets::*; +use crate::ApplyOverCompat; use matrix_sdk::{RoomState, ruma::{OwnedEventId, OwnedRoomId, RoomId}}; use serde::{Deserialize, Serialize}; use crate::{ @@ -11,171 +12,128 @@ use crate::{ event_source_modal::{EventSourceModalAction, EventSourceModalWidgetRefExt}, invite_modal::{InviteModalAction, InviteModalWidgetRefExt}, main_desktop_ui::MainDesktopUiAction, navigation_tab_bar::{NavigationBarAction, SelectedTab}, new_message_context_menu::NewMessageContextMenuWidgetRefExt, room_context_menu::RoomContextMenuWidgetRefExt, room_screen::{InviteAction, MessageAction, clear_timeline_states}, rooms_list::{RoomsListAction, RoomsListRef, RoomsListUpdate, clear_all_invited_rooms, enqueue_rooms_list_update} }, join_leave_room_modal::{ JoinLeaveModalKind, JoinLeaveRoomModalAction, JoinLeaveRoomModalWidgetRefExt - }, login::login_screen::LoginAction, logout::logout_confirm_modal::{LogoutAction, LogoutConfirmModalAction, LogoutConfirmModalWidgetRefExt}, persistence, profile::user_profile_cache::clear_user_profile_cache, room::BasicRoomDetails, shared::{callout_tooltip::{ - CalloutTooltipWidgetRefExt, - TooltipAction, - }, confirmation_modal::{ConfirmationModalContent, ConfirmationModalWidgetRefExt}, image_viewer::{ImageViewerAction, LoadState}, popup_list::{PopupKind, enqueue_popup_notification}}, sliding_sync::{DirectMessageRoomAction, MatrixRequest, current_user_id, submit_async_request}, utils::RoomNameId, verification::VerificationAction, verification_modal::{ + }, login::login_screen::LoginAction, logout::logout_confirm_modal::{LogoutAction, LogoutConfirmModalAction, LogoutConfirmModalWidgetRefExt}, persistence, profile::user_profile_cache::clear_user_profile_cache, room::BasicRoomDetails, shared::{confirmation_modal::{ConfirmationModalContent, ConfirmationModalWidgetRefExt}, image_viewer::{ImageViewerAction, LoadState}, popup_list::{PopupKind, enqueue_popup_notification}}, sliding_sync::{DirectMessageRoomAction, MatrixRequest, current_user_id, submit_async_request}, utils::RoomNameId, verification::VerificationAction, verification_modal::{ VerificationModalAction, VerificationModalWidgetRefExt, } }; -live_design! { - use link::theme::*; - use link::shaders::*; - use link::widgets::*; - - use crate::shared::styles::*; - use crate::home::home_screen::HomeScreen; - use crate::verification_modal::VerificationModal; - use crate::join_leave_room_modal::JoinLeaveRoomModal; - use crate::login::login_screen::LoginScreen; - use crate::logout::logout_confirm_modal::LogoutConfirmModal; - use crate::shared::confirmation_modal::*; - use crate::shared::popup_list::*; - use crate::home::new_message_context_menu::*; - use crate::home::room_context_menu::*; - use crate::home::invite_modal::InviteModal; - use crate::home::event_source_modal::EventSourceModal; - use crate::shared::callout_tooltip::CalloutTooltip; - use crate::shared::image_viewer::ImageViewer; - use link::tsp_link::TspVerificationModal; - - - App = {{App}} { - ui: { - main_window = { - window: {inner_size: vec2(1280, 800), title: "Robrix"}, - pass: {clear_color: #FFFFFF00} - caption_bar = { - caption_label = { - label = { - margin: {left: 65}, - align: {x: 0.5}, - text: "Robrix", - draw_text: {color: (COLOR_TEXT)} +script_mod! { + use mod.prelude.widgets.* + use mod.widgets.* + + load_all_resources() do #(App::script_component(vm)) { + ui: Root { + main_window := Window { + window.inner_size: vec2(1280, 800) + window.title: "Robrix" + pass.clear_color: #FFFFFF00 + caption_bar: { + caption_label: { + label: { + margin: Inset{left: 65}, + align: Align{x: 0.5}, + text: "Robrix" } } - windows_buttons = { - // Note: these are the background colors of the buttons used in Windows: - // * idle: Clear, for all three buttons. - // * hover: #E9E9E9 for minimize and maximize, #E81123 for close. - // * down: either darker (on light mode) or lighter (on dark mode). - // - // However, the DesktopButton widget doesn't support drawing a background color yet, - // so these colors are the colors of the icon itself, not the background highlight. - // When it supports that, we will keep the icon color always black, - // and change the background color instead based on the above colors. - min = { draw_bg: {color: #0, color_hover: #9, color_down: #3} } - max = { draw_bg: {color: #0, color_hover: #9, color_down: #3} } - close = { draw_bg: {color: #0, color_hover: #E81123, color_down: #FF0015} } - } - draw_bg: {color: #F3F3F3}, } - body = { + body +: { padding: 0, - { + View { width: Fill, height: Fill, flow: Overlay, - home_screen_view = { + home_screen_view := View { visible: false - home_screen = {} + home_screen := HomeScreen {} } - join_leave_modal = { - content: { - join_leave_modal_inner = {} + join_leave_modal := Modal { + content +: { + join_leave_modal_inner := JoinLeaveRoomModal {} } } - login_screen_view = { + login_screen_view := View { visible: true - login_screen = {} + login_screen := LoginScreen {} } - image_viewer_modal = { - content: { + image_viewer_modal := Modal { + content +: { width: Fill, height: Fill, - image_viewer_modal_inner = {} + image_viewer_modal_inner := ImageViewer {} } } // Context menus should be shown in front of other UI elements, // but behind verification modals. - new_message_context_menu = { } - room_context_menu = { } + new_message_context_menu := NewMessageContextMenu { } + room_context_menu := RoomContextMenu { } // A modal to confirm sending out an invite to a room. - invite_confirmation_modal = { - content: { - invite_confirmation_modal_inner = { - wrapper = { buttons_view = { accept_button = { - draw_icon: { - svg_file: (ICON_INVITE), - } - icon_walk: {width: 28, height: Fit, margin: {left: -10} } - } } } - } + invite_confirmation_modal := Modal { + content +: { + invite_confirmation_modal_inner := PositiveConfirmationModal {} } } // A modal to invite a user to a room. - invite_modal = { - content: { - invite_modal_inner = {} + invite_modal := Modal { + content +: { + invite_modal_inner := InviteModal {} } } // Show the logout confirmation modal. - logout_confirm_modal = { - content: { - logout_confirm_modal_inner = {} + logout_confirm_modal := Modal { + content +: { + logout_confirm_modal_inner := LogoutConfirmModal {} } } // Show the event source modal (View Source for messages). - event_source_modal = { - content: { + event_source_modal := Modal { + content +: { height: Fill, width: Fill, - align: {x: 0.5, y: 0.5}, - event_source_modal_inner = {} + align: Align{x: 0.5, y: 0.5}, + event_source_modal_inner := EventSourceModal {} } } // Show incoming verification requests in front of the aforementioned UI elements. - verification_modal = { - content: { - verification_modal_inner = {} + verification_modal := Modal { + content +: { + verification_modal_inner := VerificationModal {} } } - tsp_verification_modal = { - content: { - tsp_verification_modal_inner = {} + tsp_verification_modal := Modal { + content +: { + tsp_verification_modal_inner := TspVerificationModal {} } } // A generic modal to confirm any positive action. - positive_confirmation_modal = { - content: { - positive_confirmation_modal_inner = { } + positive_confirmation_modal := Modal { + content +: { + positive_confirmation_modal_inner := PositiveConfirmationModal { } } } // A modal to confirm any deletion/removal action. - delete_confirmation_modal = { - content: { - delete_confirmation_modal_inner = { } + delete_confirmation_modal := Modal { + content +: { + delete_confirmation_modal_inner := NegativeConfirmationModal { } } } - {} + PopupList {} // Tooltips must be shown in front of all other UI elements, // since they can be shown as a hover atop any other widget. - app_tooltip = {} + app_tooltip := CalloutTooltip {} } } // end of body } @@ -185,7 +143,7 @@ live_design! { app_main!(App); -#[derive(Live)] +#[derive(Script, ScriptHook)] pub struct App { #[live] ui: WidgetRef, /// The top-level app state, shared across various parts of the app. @@ -196,52 +154,32 @@ pub struct App { #[rust] waiting_to_navigate_to_room: Option<(BasicRoomDetails, Option)>, } -impl LiveRegister for App { - fn live_register(cx: &mut Cx) { - // Order matters here, as some widget definitions depend on others. - // The main `makepad_widgets` crate must be registered first, - // then other first-party makepad crates (like `makepad_code_editor`), - // then `shared`` widgets (in which styles are defined), - // then other modules widgets. - makepad_widgets::live_design(cx); - makepad_code_editor::live_design(cx); - // Override Makepad's default desktop dark theme with the desktop light theme. - cx.link(id!(theme), id!(theme_desktop_light)); - crate::shared::live_design(cx); - - // If the `tsp` cargo feature is enabled, we create a new "tsp_link" DSL namespace - // and link it to the real `tsp_enabled` DSL namespace, which contains real TSP widgets. - // If the `tsp` feature is not enabled, link the "tsp_link" DSL namespace - // to the `tsp_disabled` DSL namespace instead, which defines dummy placeholder widgets. - #[cfg(feature = "tsp")] { - crate::tsp::live_design(cx); - cx.link(id!(tsp_link), id!(tsp_enabled)); - } - #[cfg(not(feature = "tsp"))] { - crate::tsp_dummy::live_design(cx); - cx.link(id!(tsp_link), id!(tsp_disabled)); - } - - crate::settings::live_design(cx); - crate::room::live_design(cx); - crate::join_leave_room_modal::live_design(cx); - crate::verification_modal::live_design(cx); - crate::home::live_design(cx); - crate::profile::live_design(cx); - crate::login::live_design(cx); - crate::logout::live_design(cx); - } -} - -impl LiveHook for App { - fn after_update_from_doc(&mut self, cx: &mut Cx) { - self.update_login_visibility(cx); - } - - fn after_new_from_doc(&mut self, cx: &mut Cx) { - // Here we set the global singleton for the PopupList widget, - // which is used to access PopupList Widget from anywhere in the app. - crate::shared::popup_list::set_global_popup_list(cx, &self.ui); +impl App { + fn run(vm: &mut ScriptVm) -> Self { + // Order matters: base widgets first, then app widgets, then app UI. + makepad_widgets::script_mod(vm); + makepad_code_editor::script_mod(vm); + crate::shared::script_mod(vm); + + #[cfg(feature = "tsp")] + crate::tsp::script_mod(vm); + #[cfg(not(feature = "tsp"))] + crate::tsp_dummy::script_mod(vm); + + crate::settings::script_mod(vm); + // RoomInputBar depends on these Home widgets; preload them before room::script_mod. + crate::home::location_preview::script_mod(vm); + crate::home::tombstone_footer::script_mod(vm); + crate::home::editing_pane::script_mod(vm); + crate::room::script_mod(vm); + crate::join_leave_room_modal::script_mod(vm); + crate::verification_modal::script_mod(vm); + crate::profile::script_mod(vm); + crate::home::script_mod(vm); + crate::login::script_mod(vm); + crate::logout::script_mod(vm); + + App::from_script_mod(vm, self::script_mod) } } @@ -268,7 +206,10 @@ impl MatchEvent for App { let _app_data_dir = crate::app_data_dir(); log!("App::handle_startup(): app_data_dir: {:?}", _app_data_dir); - if let Err(e) = persistence::load_window_state(self.ui.window(ids!(main_window)), cx) { + // Set the global singleton for PopupList so other modules can enqueue toasts. + crate::shared::popup_list::set_global_popup_list(cx, &self.ui); + + if let Err(e) = persistence::load_window_state(self.ui.window(cx, ids!(main_window)), cx) { error!("Failed to load window state: {}", e); } @@ -284,31 +225,31 @@ impl MatchEvent for App { } fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) { - let invite_confirmation_modal_inner = self.ui.confirmation_modal(ids!(invite_confirmation_modal_inner)); + let invite_confirmation_modal_inner = self.ui.confirmation_modal(cx, ids!(invite_confirmation_modal_inner)); if let Some(_accepted) = invite_confirmation_modal_inner.closed(actions) { - self.ui.modal(ids!(invite_confirmation_modal)).close(cx); + self.ui.modal(cx, ids!(invite_confirmation_modal)).close(cx); } - let delete_confirmation_modal_inner = self.ui.confirmation_modal(ids!(delete_confirmation_modal_inner)); + let delete_confirmation_modal_inner = self.ui.confirmation_modal(cx, ids!(delete_confirmation_modal_inner)); if let Some(_accepted) = delete_confirmation_modal_inner.closed(actions) { - self.ui.modal(ids!(delete_confirmation_modal)).close(cx); + self.ui.modal(cx, ids!(delete_confirmation_modal)).close(cx); } - let positive_confirmation_modal_inner = self.ui.confirmation_modal(ids!(positive_confirmation_modal_inner)); + let positive_confirmation_modal_inner = self.ui.confirmation_modal(cx, ids!(positive_confirmation_modal_inner)); if let Some(_accepted) = positive_confirmation_modal_inner.closed(actions) { - self.ui.modal(ids!(positive_confirmation_modal)).close(cx); + self.ui.modal(cx, ids!(positive_confirmation_modal)).close(cx); } for action in actions { match action.downcast_ref() { Some(LogoutConfirmModalAction::Open) => { - self.ui.logout_confirm_modal(ids!(logout_confirm_modal_inner)).reset_state(cx); - self.ui.modal(ids!(logout_confirm_modal)).open(cx); + self.ui.logout_confirm_modal(cx, ids!(logout_confirm_modal_inner)).reset_state(cx); + self.ui.modal(cx, ids!(logout_confirm_modal)).open(cx); continue; }, Some(LogoutConfirmModalAction::Close { was_internal, .. }) => { if *was_internal { - self.ui.modal(ids!(logout_confirm_modal)).close(cx); + self.ui.modal(cx, ids!(logout_confirm_modal)).close(cx); } continue; }, @@ -318,7 +259,7 @@ impl MatchEvent for App { match action.downcast_ref() { Some(LogoutAction::LogoutSuccess) => { self.app_state.logged_in = false; - self.ui.modal(ids!(logout_confirm_modal)).close(cx); + self.ui.modal(cx, ids!(logout_confirm_modal)).close(cx); self.update_login_visibility(cx); self.ui.redraw(cx); continue; @@ -344,15 +285,15 @@ impl MatchEvent for App { // Handle an action requesting to open the new message context menu. if let MessageAction::OpenMessageContextMenu { details, abs_pos } = action.as_widget_action().cast() { - self.ui.callout_tooltip(ids!(app_tooltip)).hide(cx); - let new_message_context_menu = self.ui.new_message_context_menu(ids!(new_message_context_menu)); + self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx); + let new_message_context_menu = self.ui.new_message_context_menu(cx, ids!(new_message_context_menu)); let expected_dimensions = new_message_context_menu.show(cx, details); // Ensure the context menu does not spill over the window's bounds. - let rect = self.ui.window(ids!(main_window)).area().rect(cx); - let pos_x = min(abs_pos.x, rect.size.x - expected_dimensions.x); - let pos_y = min(abs_pos.y, rect.size.y - expected_dimensions.y); + let rect = self.ui.window(cx, ids!(main_window)).area().rect(cx); + let _pos_x = min(abs_pos.x, rect.size.x - expected_dimensions.x); + let _pos_y = min(abs_pos.y, rect.size.y - expected_dimensions.y); new_message_context_menu.apply_over(cx, live! { - main_content = { margin: { left: (pos_x), top: (pos_y) } } + main_content: { margin: { left: (pos_x), top: (pos_y) } } }); self.ui.redraw(cx); continue; @@ -360,15 +301,15 @@ impl MatchEvent for App { // Handle an action requesting to open the room context menu. if let RoomsListAction::OpenRoomContextMenu { details, pos } = action.as_widget_action().cast() { - self.ui.callout_tooltip(ids!(app_tooltip)).hide(cx); - let room_context_menu = self.ui.room_context_menu(ids!(room_context_menu)); + self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx); + let room_context_menu = self.ui.room_context_menu(cx, ids!(room_context_menu)); let expected_dimensions = room_context_menu.show(cx, details); // Ensure the context menu does not spill over the window's bounds. - let rect = self.ui.window(ids!(main_window)).area().rect(cx); - let pos_x = min(pos.x, rect.size.x - expected_dimensions.x); - let pos_y = min(pos.y, rect.size.y - expected_dimensions.y); + let rect = self.ui.window(cx, ids!(main_window)).area().rect(cx); + let _pos_x = min(pos.x, rect.size.x - expected_dimensions.x); + let _pos_y = min(pos.y, rect.size.y - expected_dimensions.y); room_context_menu.apply_over(cx, live! { - main_content = { margin: { left: (pos_x), top: (pos_y) } } + main_content: { margin: { left: (pos_x), top: (pos_y) } } }); self.ui.redraw(cx); continue; @@ -378,15 +319,14 @@ impl MatchEvent for App { if let RoomsListAction::Selected(selected_room) = action.as_widget_action().cast() { // Set the Stack Navigation header to show the name of the newly-selected room. self.ui - .label(ids!(main_content_view.header.content.title_container.title)) + .label(cx, ids!(main_content_view.header.content.title_container.title)) .set_text(cx, &selected_room.display_name()); self.app_state.selected_room = Some(selected_room); // Navigate to the main content view cx.widget_action( - self.ui.widget_uid(), - &HeapLiveIdPath::default(), + self.ui.widget_uid(), StackNavigationAction::Push(id!(main_content_view)) ); self.ui.redraw(cx); @@ -445,11 +385,11 @@ impl MatchEvent for App { match action.as_widget_action().cast() { TooltipAction::HoverIn { text, widget_rect, options } => { // Don't show any tooltips if the message context menu is currently shown. - if self.ui.new_message_context_menu(ids!(new_message_context_menu)).is_currently_shown(cx) { - self.ui.callout_tooltip(ids!(app_tooltip)).hide(cx); + if self.ui.new_message_context_menu(cx, ids!(new_message_context_menu)).is_currently_shown(cx) { + self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx); } else { - self.ui.callout_tooltip(ids!(app_tooltip)).show_with_options( + self.ui.callout_tooltip(cx, ids!(app_tooltip)).show_with_options( cx, &text, widget_rect, @@ -459,7 +399,7 @@ impl MatchEvent for App { continue; } TooltipAction::HoverOut => { - self.ui.callout_tooltip(ids!(app_tooltip)).hide(cx); + self.ui.callout_tooltip(cx, ids!(app_tooltip)).hide(cx); continue; } _ => {} @@ -469,14 +409,14 @@ impl MatchEvent for App { match action.downcast_ref() { Some(JoinLeaveRoomModalAction::Open { kind, show_tip }) => { self.ui - .join_leave_room_modal(ids!(join_leave_modal_inner)) + .join_leave_room_modal(cx, ids!(join_leave_modal_inner)) .set_kind(cx, kind.clone(), *show_tip); - self.ui.modal(ids!(join_leave_modal)).open(cx); + self.ui.modal(cx, ids!(join_leave_modal)).open(cx); continue; } Some(JoinLeaveRoomModalAction::Close { was_internal, .. }) => { if *was_internal { - self.ui.modal(ids!(join_leave_modal)).close(cx); + self.ui.modal(cx, ids!(join_leave_modal)).close(cx); } continue; } @@ -488,22 +428,22 @@ impl MatchEvent for App { // // Note: other verification actions are handled by the verification modal itself. if let Some(VerificationAction::RequestReceived(state)) = action.downcast_ref() { - self.ui.verification_modal(ids!(verification_modal_inner)) + self.ui.verification_modal(cx, ids!(verification_modal_inner)) .initialize_with_data(cx, state.clone()); - self.ui.modal(ids!(verification_modal)).open(cx); + self.ui.modal(cx, ids!(verification_modal)).open(cx); continue; } if let Some(VerificationModalAction::Close) = action.downcast_ref() { - self.ui.modal(ids!(verification_modal)).close(cx); + self.ui.modal(cx, ids!(verification_modal)).close(cx); continue; } match action.downcast_ref() { Some(ImageViewerAction::Show(LoadState::Loading(_, _))) => { - self.ui.modal(ids!(image_viewer_modal)).open(cx); + self.ui.modal(cx, ids!(image_viewer_modal)).open(cx); continue; } Some(ImageViewerAction::Hide) => { - self.ui.modal(ids!(image_viewer_modal)).close(cx); + self.ui.modal(cx, ids!(image_viewer_modal)).close(cx); continue; } _ => {} @@ -514,13 +454,13 @@ impl MatchEvent for App { use crate::tsp::{tsp_verification_modal::{TspVerificationModalAction, TspVerificationModalWidgetRefExt}, TspIdentityAction}; if let Some(TspIdentityAction::ReceivedDidAssociationRequest { details, wallet_db }) = action.downcast_ref() { - self.ui.tsp_verification_modal(ids!(tsp_verification_modal_inner)) + self.ui.tsp_verification_modal(cx, ids!(tsp_verification_modal_inner)) .initialize_with_details(cx, details.clone(), wallet_db.deref().clone()); - self.ui.modal(ids!(tsp_verification_modal)).open(cx); + self.ui.modal(cx, ids!(tsp_verification_modal)).open(cx); continue; } if let Some(TspVerificationModalAction::Close) = action.downcast_ref() { - self.ui.modal(ids!(tsp_verification_modal)).close(cx); + self.ui.modal(cx, ids!(tsp_verification_modal)).close(cx); continue; } } @@ -529,7 +469,7 @@ impl MatchEvent for App { if let Some(InviteAction::ShowInviteConfirmationModal(content_opt)) = action.downcast_ref() { if let Some(content) = content_opt.borrow_mut().take() { invite_confirmation_modal_inner.show(cx, content); - self.ui.modal(ids!(invite_confirmation_modal)).open(cx); + self.ui.modal(cx, ids!(invite_confirmation_modal)).open(cx); } continue; } @@ -538,7 +478,7 @@ impl MatchEvent for App { if let Some(PositiveConfirmationModalAction::Show(content_opt)) = action.downcast_ref() { if let Some(content) = content_opt.borrow_mut().take() { positive_confirmation_modal_inner.show(cx, content); - self.ui.modal(ids!(positive_confirmation_modal)).open(cx); + self.ui.modal(cx, ids!(positive_confirmation_modal)).open(cx); } continue; } @@ -546,8 +486,8 @@ impl MatchEvent for App { // Handle a request to show the delete confirmation modal. if let Some(ConfirmDeleteAction::Show(content_opt)) = action.downcast_ref() { if let Some(content) = content_opt.borrow_mut().take() { - self.ui.confirmation_modal(ids!(delete_confirmation_modal_inner)).show(cx, content); - self.ui.modal(ids!(delete_confirmation_modal)).open(cx); + self.ui.confirmation_modal(cx, ids!(delete_confirmation_modal_inner)).show(cx, content); + self.ui.modal(cx, ids!(delete_confirmation_modal)).open(cx); } continue; } @@ -555,12 +495,12 @@ impl MatchEvent for App { // Handle InviteModalAction to open/close the invite modal. match action.downcast_ref() { Some(InviteModalAction::Open(room_name_id)) => { - self.ui.invite_modal(ids!(invite_modal_inner)).show(cx, room_name_id.clone()); - self.ui.modal(ids!(invite_modal)).open(cx); + self.ui.invite_modal(cx, ids!(invite_modal_inner)).show(cx, room_name_id.clone()); + self.ui.modal(cx, ids!(invite_modal)).open(cx); continue; } Some(InviteModalAction::Close) => { - self.ui.modal(ids!(invite_modal)).close(cx); + self.ui.modal(cx, ids!(invite_modal)).close(cx); continue; } _ => {} @@ -569,13 +509,13 @@ impl MatchEvent for App { // Handle EventSourceModalAction to open/close the event source modal. match action.downcast_ref() { Some(EventSourceModalAction::Open { room_id, event_id, original_json }) => { - self.ui.event_source_modal(ids!(event_source_modal_inner)) + self.ui.event_source_modal(cx, ids!(event_source_modal_inner)) .show(cx, room_id.clone(), event_id.clone(), original_json.clone()); - self.ui.modal(ids!(event_source_modal)).open(cx); + self.ui.modal(cx, ids!(event_source_modal)).open(cx); continue; } Some(EventSourceModalAction::Close) => { - self.ui.modal(ids!(event_source_modal)).close(cx); + self.ui.modal(cx, ids!(event_source_modal)).close(cx); continue; } _ => {} @@ -621,7 +561,7 @@ impl MatchEvent for App { ..Default::default() }, ); - self.ui.modal(ids!(positive_confirmation_modal)).open(cx); + self.ui.modal(cx, ids!(positive_confirmation_modal)).open(cx); } Some(DirectMessageRoomAction::FailedToCreate { user_profile, error }) => { enqueue_popup_notification( @@ -651,7 +591,7 @@ fn clear_all_app_state(cx: &mut Cx) { impl AppMain for App { fn handle_event(&mut self, cx: &mut Cx, event: &Event) { if let Event::Shutdown = event { - let window_ref = self.ui.window(ids!(main_window)); + let window_ref = self.ui.window(cx, ids!(main_window)); if let Err(e) = persistence::save_window_state(window_ref, cx) { error!("Failed to save window state. Error: {e}"); } @@ -701,7 +641,7 @@ impl AppMain for App { // We check which overlay views are visible in the order of those views' z-ordering, // such that the top-most views get a chance to handle the event first. - let new_message_context_menu = self.ui.new_message_context_menu(ids!(new_message_context_menu)); + let new_message_context_menu = self.ui.new_message_context_menu(cx, ids!(new_message_context_menu)); let is_interactive_hit = utils::is_interactive_hit_event(event); let is_pane_shown: bool; if new_message_context_menu.is_currently_shown(cx) { @@ -726,11 +666,11 @@ impl App { let show_login = !self.app_state.logged_in; if !show_login { self.ui - .modal(ids!(login_screen_view.login_screen.login_status_modal)) + .modal(cx, ids!(login_screen_view.login_screen.login_status_modal)) .close(cx); } - self.ui.view(ids!(login_screen_view)).set_visible(cx, show_login); - self.ui.view(ids!(home_screen_view)).set_visible(cx, !show_login); + self.ui.view(cx, ids!(login_screen_view)).set_visible(cx, show_login); + self.ui.view(cx, ids!(home_screen_view)).set_visible(cx, !show_login); } /// Navigates to the given `destination_room`, optionally closing the `room_to_close`. @@ -746,8 +686,7 @@ impl App { let widget_uid = self.ui.widget_uid(); move |cx: &mut Cx| { cx.widget_action( - widget_uid, - &HeapLiveIdPath::default(), + widget_uid, DockAction::TabCloseWasPressed(tab_id), ); enqueue_rooms_list_update(RoomsListUpdate::HideRoom { room_id: to_close.clone() }); @@ -755,7 +694,15 @@ impl App { }); let destination_room_id = destination_room.room_id(); - let new_selected_room = match cx.get_global::().get_room_state(destination_room_id) { + if !cx.has_global::() { + error!( + "navigate_to_room: missing RoomsListRef global for room {}", + destination_room_id + ); + return; + } + let room_state = cx.get_global::().get_room_state(destination_room_id); + let new_selected_room = match room_state { Some(RoomState::Joined) => SelectedRoom::JoinedRoom { room_name_id: destination_room.room_name_id().clone(), }, @@ -792,8 +739,7 @@ impl App { cx.action(NavigationBarAction::GoToHome); } cx.widget_action( - self.ui.widget_uid(), - &HeapLiveIdPath::default(), + self.ui.widget_uid(), RoomsListAction::Selected(new_selected_room), ); // Select and scroll to the destination room in the rooms list. @@ -835,8 +781,10 @@ pub struct AppState { #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct SavedDockState { /// All items contained in the dock, keyed by their room or space ID. + #[serde(skip, default)] pub dock_items: HashMap, /// The rooms that are currently open, keyed by their room or space ID. + #[serde(skip, default)] pub open_rooms: HashMap, /// The order in which the rooms were opened, in chronological order /// from first opened (at the beginning) to last opened (at the end). diff --git a/src/home/add_room.rs b/src/home/add_room.rs index 65c138639..2e165a34d 100644 --- a/src/home/add_room.rs +++ b/src/home/add_room.rs @@ -7,52 +7,46 @@ use ruma::{IdParseError, MatrixToUri, MatrixUri, OwnedRoomOrAliasId, OwnedServer use crate::{app::AppStateAction, home::invite_screen::JoinRoomResultAction, room::{FetchedRoomAvatar, FetchedRoomPreview, RoomPreviewAction}, shared::{avatar::AvatarWidgetRefExt, popup_list::{PopupKind, enqueue_popup_notification}}, sliding_sync::{MatrixRequest, submit_async_request}, utils}; -live_design! { - use link::theme::*; - use link::shaders::*; - use link::widgets::*; +script_mod! { + use mod.prelude.widgets.* + use mod.widgets.* - use crate::shared::styles::*; - use crate::shared::helpers::*; - use crate::shared::avatar::*; - use crate::shared::icon_button::*; - use crate::shared::html_or_plaintext::*; // The main view that allows the user to add (join) or explore new rooms/spaces. - pub AddRoomScreen = {{AddRoomScreen}} { + mod.widgets.AddRoomScreen = #(AddRoomScreen::register_widget(vm)) { width: Fill, height: Fill, flow: Down, - padding: {top: 5, left: 15, right: 15, bottom: 0}, + padding: Inset{top: 5, left: 15, right: 15, bottom: 0}, // show_bg: true - // draw_bg: { + // draw_bg +: { // color: (COLOR_PRIMARY) // } - title = { - flow: RightWrap, - draw_text: { - text_style: {font_size: 13}, + title := TitleLabel { + flow: Flow.Right{wrap: true}, + draw_text +: { + text_style: TITLE_TEXT {font_size: 13}, color: #000 - wrap: Word + flow: Flow.Right{wrap: true} } text: "Add/Explore Rooms and Spaces" - draw_text: { - text_style: {font_size: 18}, + draw_text +: { + text_style: theme.font_regular {font_size: 18}, } } - { padding: 10, margin: {top: 10, right: 2} } + LineH { padding: 10, margin: Inset{top: 10, right: 2} } - { + SubsectionLabel { text: "Join an existing room or space:" } // TODO: support showing/hiding this help with a collapsible widget wrapper // (Accordion widget, once it's added to Makepad upstream) - help_info = { + help_info := MessageHtml { padding: 7 width: Fill, height: Fit font_size: 10. @@ -66,225 +60,229 @@ live_design! { " } - join_room_view = { + join_room_view := View { width: Fill, height: Fit, - margin: { top: 3 } - align: {y: 0.5} + margin: Inset{ top: 3 } + align: Align{y: 0.5} spacing: 5 flow: Right - room_alias_id_input = { - margin: {top: 0, left: 5, right: 5, bottom: 0}, + room_alias_id_input := SimpleTextInput { + margin: Inset{top: 0, left: 5, right: 5, bottom: 0}, width: Fill { max: 400 } // same width as the above `help_info` height: Fit empty_text: "Enter alias, ID, or Matrix link..." } - search_for_room_button = { - padding: {top: 10, bottom: 10, left: 12, right: 14} + search_for_room_button := RobrixIconButton { + padding: Inset{top: 10, bottom: 10, left: 12, right: 14} height: Fit - margin: { bottom: 4 }, - draw_bg: { - color: (COLOR_ACTIVE_PRIMARY) + margin: Inset{ bottom: 4 }, + draw_bg +: { + color: instance((COLOR_ACTIVE_PRIMARY)) } - draw_icon: { - svg_file: (ICON_SEARCH) + draw_icon +: { + svg: (ICON_SEARCH) color: (COLOR_PRIMARY) } - draw_text: { + draw_text +: { color: (COLOR_PRIMARY) - text_style: {} + text_style: REGULAR_TEXT {} } - icon_walk: {width: 16, height: 16} + icon_walk: Walk{width: 16, height: 16} text: "Go" } } - loading_room_view = { + loading_room_view := View { visible: false spacing: 5, padding: 10, width: Fill height: Fit - align: {y: 0.5} + align: Align{y: 0.5} flow: Right - loading_spinner = { + loading_spinner := LoadingSpinner { width: 25, height: 25, - draw_bg: { - color: (COLOR_ACTIVE_PRIMARY) + draw_bg +: { + color: instance((COLOR_ACTIVE_PRIMARY)) border_size: 3.0, } } - loading_text = No topic set"), ); - let room_summary = fetched_room_summary.label(ids!(room_summary)); - let join_room_button = fetched_room_summary.button(ids!(join_room_button)); + let room_summary = fetched_room_summary.label(cx, ids!(room_summary)); + let join_room_button = fetched_room_summary.button(cx, ids!(join_room_button)); let join_function = match (&frp.state, &frp.join_rule) { (Some(RoomState::Joined), _) => { room_summary.set_text(cx, &format!("You have already joined this {room_or_space_lc}.")); @@ -762,7 +760,7 @@ impl Widget for AddRoomScreen { join_room_button.set_enabled(cx, !matches!(join_function, JoinButtonFunction::None)); self.join_function = join_function; join_room_button.reset_hover(cx); - fetched_room_summary.button(ids!(cancel_button)).reset_hover(cx); + fetched_room_summary.button(cx, ids!(cancel_button)).reset_hover(cx); } AddRoomState::Knocked { .. } => { room_summary.set_text(cx, &format!("You have knocked on this {room_or_space_lc} and must now wait for someone to invite you in.")); diff --git a/src/home/edited_indicator.rs b/src/home/edited_indicator.rs index 91911a3df..07fb24f0d 100644 --- a/src/home/edited_indicator.rs +++ b/src/home/edited_indicator.rs @@ -11,35 +11,33 @@ use chrono::{DateTime, Local}; use makepad_widgets::*; use matrix_sdk_ui::timeline::EventTimelineItem; -use crate::{shared::callout_tooltip::{CalloutTooltipOptions, TooltipAction, TooltipPosition}, utils::unix_time_millis_to_datetime}; +use crate::utils::unix_time_millis_to_datetime; -live_design! { - use link::theme::*; - use link::shaders::*; - use link::widgets::*; +script_mod! { + use mod.prelude.widgets.* + use mod.widgets.* - use crate::shared::styles::*; - pub EDITED_INDICATOR_FONT_SIZE = 9.5 - pub EDITED_INDICATOR_FONT_COLOR = #666666 + mod.widgets.EDITED_INDICATOR_FONT_SIZE = 9.5 + mod.widgets.EDITED_INDICATOR_FONT_COLOR = #666666 - pub EditedIndicator = {{EditedIndicator}} { + mod.widgets.EditedIndicator = #(EditedIndicator::register_widget(vm)) { visible: false, // default to hidden width: Fit, height: Fit flow: Right, padding: 0, - margin: { top: 5 } + margin: Inset{ top: 5 } // TODO: re-enable this once we have implemented the edit history modal - // cursor: Hand, + // cursor: MouseCursor.Hand, - edit_html = { + edit_html := Html { width: Fit, height: Fit flow: Right, // do not wrap padding: 0, margin: 0, - font_size: (EDITED_INDICATOR_FONT_SIZE), + font_size: (mod.widgets.EDITED_INDICATOR_FONT_SIZE), font_color: (COLOR_ROBRIX_PURPLE), body: "(edited)", } @@ -47,7 +45,7 @@ live_design! { } /// A interactive label that indicates a message has been edited. -#[derive(Live, LiveHook, Widget)] +#[derive(Script, ScriptHook, Widget)] pub struct EditedIndicator { #[deref] view: View, #[rust] latest_edit_ts: Option>, @@ -67,7 +65,7 @@ impl Widget for EditedIndicator { // false // }, Hit::FingerHoverOut(_) => { - cx.widget_action(self.widget_uid(), &scope.path, TooltipAction::HoverOut); + cx.widget_action(self.widget_uid(), TooltipAction::HoverOut); false } _ => false, @@ -81,8 +79,7 @@ impl Widget for EditedIndicator { "Last edit time unknown".to_string() }; cx.widget_action( - self.widget_uid(), - &scope.path, + self.widget_uid(), TooltipAction::HoverIn { text, widget_rect: area.rect(cx), @@ -125,10 +122,11 @@ impl EditedIndicatorRef { /// Actions emitted by an `EditedIndicator` widget. -#[derive(Clone, Debug, DefaultNone)] +#[derive(Clone, Debug, Default)] pub enum EditedIndicatorAction { /// The indicator was clicked, and thus we should open /// a modal/dialog showing the message's full edit history. ShowEditHistory, + #[default] None, } diff --git a/src/home/editing_pane.rs b/src/home/editing_pane.rs index 842682adf..f65f5dfe1 100644 --- a/src/home/editing_pane.rs +++ b/src/home/editing_pane.rs @@ -16,123 +16,117 @@ use crate::{ sliding_sync::{submit_async_request, MatrixRequest, TimelineKind}, }; -live_design! { - use link::theme::*; - use link::shaders::*; - use link::widgets::*; - - use crate::shared::helpers::*; - use crate::shared::styles::*; - use crate::shared::avatar::*; - use crate::shared::icon_button::*; - use crate::shared::mentionable_text_input::MentionableTextInput; - - EditingContent = { +script_mod! { + use mod.prelude.widgets.* + use mod.widgets.* + + + mod.widgets.EditingContent = View { width: Fill, - height: Fit { max: Rel { base: Full, factor: 0.625 } } - align: {x: 0.5, y: 1.0}, // centered horizontally, bottom-aligned - padding: { left: 20, right: 20, top: 10, bottom: 10 } - margin: {top: 2} + height: Fit + align: Align{x: 0.5, y: 1.0}, // centered horizontally, bottom-aligned + padding: Inset{ left: 20, right: 20, top: 10, bottom: 10 } + margin: Inset{top: 2} spacing: 10, flow: Down, show_bg: false // don't cover up the RoomInputBar - { + View { width: Fill, height: Fit flow: Right - align: {y: 0.5} - padding: {left: 5, right: 5} + align: Align{y: 0.5} + padding: Inset{left: 5, right: 5} -