diff --git a/.gitignore b/.gitignore index 95a33f9..402cf37 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ Cargo.lock # Visual-QA screenshots (regenerate with tools/visual-qa.sh) tools/qa-shots/ + +# makepad studio state +.makepad/ diff --git a/Cargo.toml b/Cargo.toml index a65499a..92da105 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ makepad-widgets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "8c23d5779f643228004fd27e651ae19be9b14ab4" } makepad-script = { git = "https://github.com/OctoSense-org/makepad.git", rev = "8c23d5779f643228004fd27e651ae19be9b14ab4" } # The VM-independent Octoscript node model, from the Octoscript repo itself. -octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", branch = "main" } +octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", branch = "rename/fix-language-review-20260904" } [profile.release] opt-level = 3 diff --git a/README.md b/README.md index 1f97860..611f534 100644 --- a/README.md +++ b/README.md @@ -81,20 +81,34 @@ Building + running the `kit-host` against upstream surfaced exactly **one** thin ## Relationship to makepad -Makepad ships everything this needs — the `makepad-script` VM (`platform/script`) and the `Splash` runtime-mount widget. The whole workspace takes them from **one pinned revision** of [`guofoo/makepad`](https://github.com/guofoo/makepad) (a fork of upstream `dev`), declared once in the root `Cargo.toml` under `[workspace.dependencies]`: - -- The **core crates** depend on `makepad-script` from that pin. -- **`octoscript-widgets`** and the kit apps depend on `makepad-widgets` from the same pin, so `makepad-script` stays aligned with `octoscript-render`'s. -- The pin is the revision [OctoSense-org/octosense](https://github.com/OctoSense-org/octosense) builds against; bump both together so an app never carries two makepad lineages. -- `octoscript-ui-l0` (the VM-independent node model) comes by git from [OctoSense-org/Octoscript](https://github.com/OctoSense-org/Octoscript), branch `main`. +The workspace uses the checked-out sibling `../makepad`: `octoscript-render` takes +`platform/script`, and the native widget crates and apps take `widgets`. Keep that checkout +at the parent repository's pinned revision; the bounded evaluator also uses its +`ScriptVm::eval_checked` API. The L0 integration tests use sibling `../octoscript`. ## Build +### L0 design-kit validation + +The lab's `octoscript-beauty-host` Studio runnable mounts L0 cards through +`l0::prepare` and `to_makepad_l0_ui`. This preserves the L0 kit's resolved +Card/Chip presentation; `to_makepad_ui` remains the Material semantic entry +point. The preview uses a standalone native window so Studio's pane size +cannot change the design frame. HTTP image resources and host fixture data +are exercised by the pipeline, alongside checked native widget construction. + +See [the Taskplan runbook](../lab/sketch/TASKPLAN-VALIDATION.md) for commands, +capture hashes, fill/vision judgments and known fidelity limits. The new +runnable is independent of the older Material catalog shell. + +With the `makepad`, `octoscript` and `octoscript-makepad` checkouts present: + ```sh -cargo test # builds + tests the portable core (octoscript-render, octoscript-makepad) +cargo test --release -p octoscript-render -p octoscript-makepad ``` -`octoscript-widgets` is excluded from the default workspace build (it needs the full upstream-makepad build); wire it into an app's makepad workspace to use it — call `octoscript_widgets::widgets_mod(vm)` in place of `makepad_widgets::widgets_mod(vm)`. +This tests the portable renderer and translator without building the native applications. +The native applications are workspace members and have separate platform build requirements. ## Status diff --git a/apps/flutter-samples/resources/Roboto-Regular.ttf b/apps/flutter-samples/resources/Roboto-Regular.ttf new file mode 100644 index 0000000..f608454 Binary files /dev/null and b/apps/flutter-samples/resources/Roboto-Regular.ttf differ diff --git a/apps/flutter-samples/resources/coffee/cup_large.png b/apps/flutter-samples/resources/coffee/cup_large.png new file mode 100644 index 0000000..7f89b60 Binary files /dev/null and b/apps/flutter-samples/resources/coffee/cup_large.png differ diff --git a/apps/flutter-samples/resources/coffee/cup_small.png b/apps/flutter-samples/resources/coffee/cup_small.png new file mode 100644 index 0000000..1b5a624 Binary files /dev/null and b/apps/flutter-samples/resources/coffee/cup_small.png differ diff --git a/apps/flutter-samples/resources/coffee/hero.png b/apps/flutter-samples/resources/coffee/hero.png new file mode 100644 index 0000000..5a41542 Binary files /dev/null and b/apps/flutter-samples/resources/coffee/hero.png differ diff --git a/apps/flutter-samples/src/lib.rs b/apps/flutter-samples/src/lib.rs index ba51cf4..db34697 100644 --- a/apps/flutter-samples/src/lib.rs +++ b/apps/flutter-samples/src/lib.rs @@ -161,8 +161,55 @@ pub struct App { /// Seconds since startup, fed to the kit as `st.t`. #[rust] clock: f64, + /// SELF-DRIVE: commands loaded from /data/local/tmp/fs_cmd.txt — the phone + /// taps and captures ITSELF; no adb input, no adb screencap. `tap X Y` + /// (physical px), `shot `, `wait `. + #[rust] + drive_cmds: Vec, + #[rust] + drive_at: usize, + #[rust] + drive_delay: u32, + /// A Stop touch waiting to follow its Start. + #[rust] + drive_stop: Option<(f64, f64, u64)>, + #[rust] + drive_uid: u64, + #[rust] + drive_last_file: String, + /// Frames remaining on an active capture (env var set). + #[rust] + drive_shot: u32, } +/// One synthetic touch through the REAL input pipeline: the same channel and +/// coalescing the JNI layer uses, physical coords, converted by the same +/// handler. The phone touching its own screen. +#[cfg(target_os = "android")] +fn self_tap(x: f64, y: f64, uid: u64, down: bool) { + use makepad_widgets::makepad_platform::os::linux::android::android_jni; + use makepad_widgets::makepad_platform::event::{TouchPoint, TouchState}; + use makepad_widgets::makepad_platform::Area; + let t = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs_f64()) + .unwrap_or(0.0); + let touch = TouchPoint { + state: if down { TouchState::Start } else { TouchState::Stop }, + abs: makepad_widgets::makepad_platform::math_f64::dvec2(x, y), + time: t, + uid, + rotation_angle: 0.0, + force: 1.0, + radius: makepad_widgets::makepad_platform::math_f64::dvec2(1.0, 1.0), + handled: std::cell::Cell::new(Area::Empty), + sweep_lock: std::cell::Cell::new(Area::Empty), + }; + android_jni::send_from_java_message(android_jni::FromJavaMessage::Touch(vec![touch])); +} +#[cfg(not(target_os = "android"))] +fn self_tap(_x: f64, _y: f64, _uid: u64, _down: bool) {} + impl App { fn current_source() -> String { std::fs::read_to_string(DEVICE_PATH).unwrap_or_else(|_| BAKED.to_string()) @@ -201,7 +248,34 @@ impl App { if let Some(node) = built { let ui = octoscript_makepad::to_makepad_ui(&node); diag.push_str(&format!(" nodes={} ui_len={}", node.count(), ui.len())); - self.ui.widget(cx, ids!(host)).set_text(cx, &ui); + // On the APP VM, with THIS crate as the module identity — not as + // text into the `Splash` isolate. Two reasons, both found blank on + // a real 6T and both already documented in kit-host's mount: + // · `crate_resource("self:…")` resolves against the module that + // evaluated the body. On the isolate that is makepad_widgets, + // which ships no Roboto — so every text node silently dropped + // while the chips and sliders drew fine. + // · the emitted `on_click` calls the `NAV` global, which only + // the app VM registers — on the isolate every tap was dead. + let code = format!("use mod.prelude.widgets.*\nView{{height:Fit, {ui}"); + let script_mod = ScriptMod { + cargo_manifest_path: env!("CARGO_MANIFEST_DIR").to_string(), + module_path: module_path!().to_string(), + file: file!().to_string(), + line: 1, + column: 0, + code: String::new(), + values: Vec::new(), + }; + let built_view = cx.with_vm(|vm| { + let value = vm.eval_with_append_source(script_mod, &code, octoscript_render::makepad_script::ScriptValue::NIL.into()); + (!value.is_err() && !value.is_nil()).then(|| View::script_from_value(vm, value)) + }); + if let Some(view) = built_view { + if let Some(mut host) = self.ui.widget(cx, ids!(host)).borrow_mut::() { + host.view = view; + } + } } // `log!`, not a file write: the OHOS app sandbox blocks /data/local/tmp, // so the earlier file-based diagnostic produced nothing. @@ -209,6 +283,30 @@ impl App { } } +/// Taps land here. The emitted body's `on_click` calls `NAV(t: "…")` — the +/// same channel kit-host uses, because the body now evaluates on the APP VM +/// (see `mount`), where `ui.nav_signal` does not exist. +static TAPS: std::sync::Mutex> = std::sync::Mutex::new(Vec::new()); + +fn take_tap() -> Option { + TAPS.lock().ok().and_then(|mut q| if q.is_empty() { None } else { Some(q.remove(0)) }) +} + +fn register_nav(vm: &mut ScriptVm) { + let f_nav = octoscript_render::add_global_fn( + vm, + &[(live_id!(t), octoscript_render::makepad_script::ScriptValue::NIL)], + |vm, a| { + let t = octoscript_render::string_prop(vm, a, live_id!(t)).unwrap_or_default(); + if let Ok(mut q) = TAPS.lock() { + q.push(t); + } + octoscript_render::makepad_script::ScriptValue::NIL + }, + ); + vm.set_injected_global(live_id!(NAV), f_nav); +} + impl MatchEvent for App {} impl AppMain for App { @@ -219,6 +317,10 @@ impl AppMain for App { }); // Fork-free themed widgets, against upstream makepad. octoscript_widgets::widgets_mod(vm); + // The body mounts on THIS VM now (see `mount`), so its tap handlers + // need `NAV` here — unregistered, every tap raises "variable NAV not + // found" and dies silently. + register_nav(vm); self::script_mod(vm) } @@ -256,10 +358,48 @@ impl AppMain for App { } if self.next_frame.is_event(event).is_some() { self.tick = self.tick.wrapping_add(1); - let nav_raw = self.ui.widget(cx, ids!(nav_signal)).text(); + // SELF-DRIVE executor: one command at a time, frame-paced. + if let Some((x, y, uid)) = self.drive_stop.take() { + self_tap(x, y, uid, false); + } else if self.drive_shot > 0 { + self.drive_shot -= 1; + if self.drive_shot == 0 { + std::env::remove_var("MAKEPAD_WRITE_FRAMEBUFFER_PNG"); + } + } else if self.drive_delay > 0 { + self.drive_delay -= 1; + } else if self.drive_at < self.drive_cmds.len() { + let cmd = self.drive_cmds[self.drive_at].clone(); + self.drive_at += 1; + let parts: Vec<&str> = cmd.split_whitespace().collect(); + match parts.as_slice() { + ["tap", x, y] => { + if let (Ok(x), Ok(y)) = (x.parse::(), y.parse::()) { + self.drive_uid += 1; + self_tap(x, y, self.drive_uid, true); + self.drive_stop = Some((x, y, self.drive_uid)); + self.drive_delay = 30; + } + } + ["shot", path] => { + std::env::set_var("MAKEPAD_WRITE_FRAMEBUFFER_PNG", path); + self.drive_shot = 3; + self.drive_delay = 6; + } + ["wait", n] => self.drive_delay = n.parse().unwrap_or(30), + _ => {} + } + let done = self.drive_at >= self.drive_cmds.len(); + let _ = std::fs::write( + "/storage/emulated/0/Android/data/dev.makepad.flutter_samples/files/fs_cmd_done.txt", + format!("{} {}/{}{}\n", cmd, self.drive_at, self.drive_cmds.len(), + if done { " DONE" } else { "" }), + ); + if done { log!("SELFDRIVE done"); } + } + let nav_raw = take_tap().unwrap_or_default(); let nav = nav_raw.trim(); if !nav.is_empty() { - self.ui.widget(cx, ids!(nav_signal)).set_text(cx, ""); if nav == "theme:toggle" { self.dark = !self.dark; } else if octoscript_render::state::apply(nav) { @@ -278,6 +418,19 @@ impl AppMain for App { } self.mount(cx); } else if self.tick % 10 == 0 { + // SELF-DRIVE: load a new command file (mtime-independent — the + // file's CONTENT is the identity; clear it to re-arm). + if let Ok(txt) = std::fs::read_to_string("/data/local/tmp/fs_cmd.txt") { + if !txt.trim().is_empty() && txt != self.drive_last_file { + self.drive_last_file = txt.clone(); + self.drive_cmds = + txt.lines().map(|l| l.trim().to_string()).filter(|l| !l.is_empty()).collect(); + self.drive_at = 0; + self.drive_delay = 0; + let _ = std::fs::write("/storage/emulated/0/Android/data/dev.makepad.flutter_samples/files/fs_cmd_done.txt", "LOADED\n"); + log!("SELFDRIVE loaded {} cmds", self.drive_cmds.len()); + } + } // A route written to ROUTE_PATH wins over whatever was tapped, // so the QA sweep can drive every screen from adb. Checked // independently of the source, so pushing an edited kit still diff --git a/apps/kit-host/Cargo.toml b/apps/kit-host/Cargo.toml index d055815..b6a1499 100644 --- a/apps/kit-host/Cargo.toml +++ b/apps/kit-host/Cargo.toml @@ -9,7 +9,9 @@ description = "Generic app shell rendering a Octoscript component kit as native # on serde_json alone — it carries no makepad lineage, which is what makes it # safe here and is why it was extracted from octoscript-core. octoscript-ui-l0 = { workspace = true } -serde_json = "1" +serde_json = { version = "1", features = ["float_roundtrip"] } +sha2 = "0.10" +makepad-plot = { path = "../../crates/makepad-plot" } makepad-widgets = { workspace = true } octoscript-widgets = { path = "../../crates/octoscript-widgets" } @@ -19,3 +21,7 @@ octoscript-makepad = { path = "../../crates/octoscript-makepad" } [[bin]] name = "kit-host" path = "src/main.rs" + +[[bin]] +name = "beauty-host" +path = "src/beauty.rs" diff --git a/apps/kit-host/resources/atro/Montserrat-Bold.ttf b/apps/kit-host/resources/atro/Montserrat-Bold.ttf new file mode 100644 index 0000000..9a425b9 Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat-Bold.ttf differ diff --git a/apps/kit-host/resources/atro/Montserrat-Light.ttf b/apps/kit-host/resources/atro/Montserrat-Light.ttf new file mode 100644 index 0000000..a3cf5f5 Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat-Light.ttf differ diff --git a/apps/kit-host/resources/atro/Montserrat-Medium.ttf b/apps/kit-host/resources/atro/Montserrat-Medium.ttf new file mode 100644 index 0000000..db5b1af Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat-Medium.ttf differ diff --git a/apps/kit-host/resources/atro/Montserrat-Regular.ttf b/apps/kit-host/resources/atro/Montserrat-Regular.ttf new file mode 100644 index 0000000..2a2b2aa Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat-Regular.ttf differ diff --git a/apps/kit-host/resources/atro/Montserrat-SemiBold.ttf b/apps/kit-host/resources/atro/Montserrat-SemiBold.ttf new file mode 100644 index 0000000..0ecc667 Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat-SemiBold.ttf differ diff --git a/apps/kit-host/resources/atro/Montserrat.ttf b/apps/kit-host/resources/atro/Montserrat.ttf new file mode 100644 index 0000000..c97aca1 Binary files /dev/null and b/apps/kit-host/resources/atro/Montserrat.ttf differ diff --git a/apps/kit-host/resources/atro/OFL.txt b/apps/kit-host/resources/atro/OFL.txt new file mode 100644 index 0000000..fe576a2 --- /dev/null +++ b/apps/kit-host/resources/atro/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2024 The Montserrat.Git Project Authors (https://github.com/JulietaUla/Montserrat.git) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/apps/kit-host/resources/camo/DMSans-Bold.ttf b/apps/kit-host/resources/camo/DMSans-Bold.ttf new file mode 100644 index 0000000..7fd94a2 Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-Bold.ttf differ diff --git a/apps/kit-host/resources/camo/DMSans-BoldItalic.ttf b/apps/kit-host/resources/camo/DMSans-BoldItalic.ttf new file mode 100644 index 0000000..6e1f861 Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-BoldItalic.ttf differ diff --git a/apps/kit-host/resources/camo/DMSans-Italic.ttf b/apps/kit-host/resources/camo/DMSans-Italic.ttf new file mode 100644 index 0000000..bdda5a7 Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-Italic.ttf differ diff --git a/apps/kit-host/resources/camo/DMSans-Medium.ttf b/apps/kit-host/resources/camo/DMSans-Medium.ttf new file mode 100644 index 0000000..ded3caf Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-Medium.ttf differ diff --git a/apps/kit-host/resources/camo/DMSans-MediumItalic.ttf b/apps/kit-host/resources/camo/DMSans-MediumItalic.ttf new file mode 100644 index 0000000..8a2b876 Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-MediumItalic.ttf differ diff --git a/apps/kit-host/resources/camo/DMSans-Regular.ttf b/apps/kit-host/resources/camo/DMSans-Regular.ttf new file mode 100644 index 0000000..b3c3eda Binary files /dev/null and b/apps/kit-host/resources/camo/DMSans-Regular.ttf differ diff --git a/apps/kit-host/resources/taskplan/Inter.ttf b/apps/kit-host/resources/taskplan/Inter.ttf new file mode 100644 index 0000000..047c92f Binary files /dev/null and b/apps/kit-host/resources/taskplan/Inter.ttf differ diff --git a/apps/kit-host/resources/taskplan/PlusJakartaSans.ttf b/apps/kit-host/resources/taskplan/PlusJakartaSans.ttf new file mode 100644 index 0000000..0cb13a9 Binary files /dev/null and b/apps/kit-host/resources/taskplan/PlusJakartaSans.ttf differ diff --git a/apps/kit-host/resources/taskplan/Poppins-Medium.ttf b/apps/kit-host/resources/taskplan/Poppins-Medium.ttf new file mode 100644 index 0000000..a590f5c Binary files /dev/null and b/apps/kit-host/resources/taskplan/Poppins-Medium.ttf differ diff --git a/apps/kit-host/resources/taskplan/Poppins-Regular.ttf b/apps/kit-host/resources/taskplan/Poppins-Regular.ttf new file mode 100644 index 0000000..0bda228 Binary files /dev/null and b/apps/kit-host/resources/taskplan/Poppins-Regular.ttf differ diff --git a/apps/kit-host/resources/taskplan/Poppins-SemiBold.ttf b/apps/kit-host/resources/taskplan/Poppins-SemiBold.ttf new file mode 100644 index 0000000..c30ad10 Binary files /dev/null and b/apps/kit-host/resources/taskplan/Poppins-SemiBold.ttf differ diff --git a/apps/kit-host/resources/taskplan/inter-OFL.txt b/apps/kit-host/resources/taskplan/inter-OFL.txt new file mode 100644 index 0000000..21f6aff --- /dev/null +++ b/apps/kit-host/resources/taskplan/inter-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/kit-host/resources/taskplan/plusjakartasans-OFL.txt b/apps/kit-host/resources/taskplan/plusjakartasans-OFL.txt new file mode 100644 index 0000000..ea69b0c --- /dev/null +++ b/apps/kit-host/resources/taskplan/plusjakartasans-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Plus Jakarta Sans Project Authors (https://github.com/tokotype/PlusJakartaSans) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/kit-host/resources/taskplan/poppins-OFL.txt b/apps/kit-host/resources/taskplan/poppins-OFL.txt new file mode 100644 index 0000000..76df3b5 --- /dev/null +++ b/apps/kit-host/resources/taskplan/poppins-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/kit-host/resources/ux/Inter-200.ttf b/apps/kit-host/resources/ux/Inter-200.ttf new file mode 100644 index 0000000..4a1ee02 Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-200.ttf differ diff --git a/apps/kit-host/resources/ux/Inter-300.ttf b/apps/kit-host/resources/ux/Inter-300.ttf new file mode 100644 index 0000000..1a4ce00 Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-300.ttf differ diff --git a/apps/kit-host/resources/ux/Inter-400.ttf b/apps/kit-host/resources/ux/Inter-400.ttf new file mode 100644 index 0000000..89821d0 Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-400.ttf differ diff --git a/apps/kit-host/resources/ux/Inter-500.ttf b/apps/kit-host/resources/ux/Inter-500.ttf new file mode 100644 index 0000000..f9b8060 Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-500.ttf differ diff --git a/apps/kit-host/resources/ux/Inter-600.ttf b/apps/kit-host/resources/ux/Inter-600.ttf new file mode 100644 index 0000000..e06c20f Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-600.ttf differ diff --git a/apps/kit-host/resources/ux/Inter-700.ttf b/apps/kit-host/resources/ux/Inter-700.ttf new file mode 100644 index 0000000..e6ee76a Binary files /dev/null and b/apps/kit-host/resources/ux/Inter-700.ttf differ diff --git a/apps/kit-host/resources/ux/Roboto-Bold.ttf b/apps/kit-host/resources/ux/Roboto-Bold.ttf new file mode 100644 index 0000000..70def3f Binary files /dev/null and b/apps/kit-host/resources/ux/Roboto-Bold.ttf differ diff --git a/apps/kit-host/resources/ux/Roboto-Light.ttf b/apps/kit-host/resources/ux/Roboto-Light.ttf new file mode 100644 index 0000000..3a03044 Binary files /dev/null and b/apps/kit-host/resources/ux/Roboto-Light.ttf differ diff --git a/apps/kit-host/resources/ux/Roboto-Medium.ttf b/apps/kit-host/resources/ux/Roboto-Medium.ttf new file mode 100644 index 0000000..284b1ba Binary files /dev/null and b/apps/kit-host/resources/ux/Roboto-Medium.ttf differ diff --git a/apps/kit-host/resources/ux/Roboto-Regular.ttf b/apps/kit-host/resources/ux/Roboto-Regular.ttf new file mode 100644 index 0000000..500b104 Binary files /dev/null and b/apps/kit-host/resources/ux/Roboto-Regular.ttf differ diff --git a/apps/kit-host/resources/ux/Roboto-Thin.ttf b/apps/kit-host/resources/ux/Roboto-Thin.ttf new file mode 100644 index 0000000..0c7d50b Binary files /dev/null and b/apps/kit-host/resources/ux/Roboto-Thin.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-200.ttf b/apps/kit-host/resources/ux/RobotoCondensed-200.ttf new file mode 100644 index 0000000..e0b4fcf Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-200.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-300.ttf b/apps/kit-host/resources/ux/RobotoCondensed-300.ttf new file mode 100644 index 0000000..aa35e4b Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-300.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-400.ttf b/apps/kit-host/resources/ux/RobotoCondensed-400.ttf new file mode 100644 index 0000000..39ad791 Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-400.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-500.ttf b/apps/kit-host/resources/ux/RobotoCondensed-500.ttf new file mode 100644 index 0000000..111f72c Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-500.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-600.ttf b/apps/kit-host/resources/ux/RobotoCondensed-600.ttf new file mode 100644 index 0000000..ed2e520 Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-600.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-700.ttf b/apps/kit-host/resources/ux/RobotoCondensed-700.ttf new file mode 100644 index 0000000..b36f604 Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-700.ttf differ diff --git a/apps/kit-host/resources/ux/RobotoCondensed-OFL.txt b/apps/kit-host/resources/ux/RobotoCondensed-OFL.txt new file mode 100644 index 0000000..2096249 --- /dev/null +++ b/apps/kit-host/resources/ux/RobotoCondensed-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/kit-host/resources/ux/RobotoCondensed-variable.ttf b/apps/kit-host/resources/ux/RobotoCondensed-variable.ttf new file mode 100644 index 0000000..2210555 Binary files /dev/null and b/apps/kit-host/resources/ux/RobotoCondensed-variable.ttf differ diff --git a/apps/kit-host/src/beauty.rs b/apps/kit-host/src/beauty.rs new file mode 100644 index 0000000..becd56a --- /dev/null +++ b/apps/kit-host/src/beauty.rs @@ -0,0 +1,330 @@ +//! Native, chrome-free preview of the lab's L0 cards through octoscript-makepad. +pub use makepad_widgets; +use makepad_widgets::*; +use octoscript_widgets::design::*; +mod beauty_semantics; +use beauty_semantics::Session as SemanticSession; + +app_main!(App); + +script_mod! { + use mod.prelude.widgets.* + startup() do #(App::script_component(vm)) { + ui: Root { + main_window := Window { + show_caption_bar: false + window.inner_size: vec2(393, 852) + body +: { + flow: Overlay + host := Splash { width: Fill height: Fill } + } + } + } + } +} + +#[derive(Script, ScriptHook)] +pub struct App { + #[live] + ui: WidgetRef, + // Keep the previous subtree's GPU resources alive through the replacement + // draw. Its old draw lists may still be consumed by an in-flight frame. + #[rust] + retired_view: Option, + #[rust] + timer: Timer, + #[rust] + last_request: String, + #[rust] + inspection_ids: Vec, + #[rust] + layout_path: String, + #[rust] + pending_focus: Option, + #[rust] + action_log: String, + #[rust] + semantic_actions: Vec, + #[rust] + semantic: SemanticSession, +} + +impl App { + fn mount_request(&mut self, cx: &mut Cx) -> Result<(), String> { + let path = std::env::var("BEAUTY_REQUEST").map_err(|e| e.to_string())?; + let request = std::fs::read_to_string(path).map_err(|e| e.to_string())?; + if request == self.last_request { + return Ok(()); + } + // A failed request is recorded too, so a bad input cannot spam a log. + self.last_request = request.clone(); + let r: serde_json::Value = serde_json::from_str(&request).map_err(|e| e.to_string())?; + let read = |key: &str| -> Result { + std::fs::read_to_string(r[key].as_str().ok_or_else(|| format!("missing {key}"))?) + .map_err(|e| e.to_string()) + }; + let card = read("card")?; + let first_mount = self.inspection_ids.is_empty(); + let data = serde_json::from_str(&read("data")?).map_err(|e| e.to_string())?; + let mut measured = r["format"].as_str() == Some("design"); + let mut tree = if measured { + octoscript_makepad::design::prepare(&card)? + } else { + let prepared = octoscript_makepad::l0::prepare( + &card, + &data, + std::path::Path::new(r["kit_dir"].as_str().ok_or("missing kit_dir")?), + )?; + measured = prepared.native_components; + prepared.tree + }; + let elements = octoscript_makepad::l0::inspectable(&mut tree); + let focused: Vec<_> = elements + .iter() + .filter(|e| e["focused"].as_i64() == Some(1)) + .collect(); + if focused.len() > 1 { + return Err("a design cannot focus multiple native inputs".into()); + } + self.pending_focus = focused + .first() + .and_then(|e| e["id"].as_str().map(str::to_owned)); + cx.set_key_focus(Area::Empty); + self.inspection_ids = elements + .iter() + .filter_map(|e| e["id"].as_str().map(str::to_owned)) + .collect(); + self.layout_path = r["layout"].as_str().unwrap_or_default().to_owned(); + self.action_log = r["actions"].as_str().unwrap_or_default().to_owned(); + self.semantic_actions.clear(); + if !self.action_log.is_empty() {std::fs::write(&self.action_log,"[]").map_err(|e|e.to_string())?;} + let ui = if measured { + octoscript_makepad::design::to_makepad_ui(&tree)? + } else { + octoscript_makepad::to_makepad_l0_ui(&tree) + }; + let code = format!( + "use mod.prelude.widgets.*\nlet root = View{{width:Fill height:Fill flow:Overlay {ui}}}\nroot" + ); + let sm = ScriptMod { + cargo_manifest_path: env!("CARGO_MANIFEST_DIR").into(), + module_path: module_path!().into(), + file: file!().into(), + line: 1, + column: 0, + code, + values: Vec::new(), + }; + let view = cx.with_vm(|vm| { + let value = octoscript_render::eval_checked(vm, sm, 2_000_000) + .ok_or("native VM rejected the widget tree")?; + Ok::<_, String>(View::script_from_value(vm, value)) + })?; + let width = r["width"].as_f64().ok_or("missing width")?; + let height = r["height"].as_f64().ok_or("missing height")?; + self.ui.window(cx, ids!(main_window)).configure_window( + cx, + dvec2(width, height), + dvec2(80.0, 80.0), + false, + "Octoscript beauty preview".into(), + ); + if !first_mount { + self.ui + .window(cx, ids!(main_window)) + .resize(cx, dvec2(width, height)); + } + let host = self.ui.widget(cx, ids!(host)); + let mut host = host + .borrow_mut::() + .ok_or("missing native Splash mount")?; + cx.set_key_focus(Area::Empty); + self.retired_view=Some(std::mem::replace(&mut host.view,view)); + // Retain GPU resources through the replacement frame, but detach their + // overlay drawing immediately. Nested old overlays can otherwise keep + // the same stale parent redraw id and survive into the next screen. + fn retire_overlay(cx:&mut Cx,widget:WidgetRef) { + octoscript_widgets::kit::retire_overlay(cx,&widget); + let list=widget.borrow::().and_then(|v|v.draw_list.as_ref().map(|l|l.id())) + .or_else(||widget.borrow::().and_then(|v|v.draw_list.as_ref().map(|l|l.id()))); + if let Some(id)=list {cx.draw_lists[id].clear_draw_items(cx.redraw_id);} + let mut children=Vec::new(); + widget.children(&mut |_,child|children.push(child)); + for child in children {retire_overlay(cx,child);} + } + if let Some(retired)=&self.retired_view { + for (_,child) in &retired.children {retire_overlay(cx,child.clone());} + } + let uid = host.widget_uid(); + let mut children = Vec::new(); + host.children(&mut |id, child| children.push((id, child))); + drop(host); + // Replacing a dynamic subtree must invalidate Studio's cached index. + // Deep registration also reparents nodes created under the temporary + // standalone View during script evaluation before mounting into Octoscript. + for (id, child) in children { + cx.widget_tree_insert_child_deep(uid, id, child); + } + cx.widget_tree_mark_dirty(uid); + for element in &elements { + if element["kind"].as_str()==Some("Radio") { + if let Some(id)=element["id"].as_str() { + self.ui.radio_button(cx,&[LiveId::from_str(id)]).set_active( + cx,element["on"].as_i64()==Some(1),Animate::No); + } + } + if let (Some(id),Some(enabled))=(element["id"].as_str(),element["enabled"].as_i64()) { + self.ui.widget(cx,&[LiveId::from_str(id)]).set_disabled(cx,enabled==0); + } + } + if let Some(updates)=r["updates"].as_array() { + for update in updates { + let id=update["id"].as_str().ok_or("missing component update ID")?; + if !self.inspection_ids.iter().any(|known|known==id) {return Err("unknown component update ID".into());} + let text=update["text"].as_str().ok_or("missing component text")?; + self.ui.widget(cx,&[LiveId::from_str(id)]).set_text(cx,text); + } + } + self.semantic.mount(cx,&self.ui,&r,&elements)?; + cx.redraw_all(); + let evidence = serde_json::json!({"ok":true, "request":r, + "nodes":tree.count(), "texts":octoscript_makepad::l0::texts(&tree), + "elements": elements}); + if let Some(path) = r["result"].as_str() { + std::fs::write(path, evidence.to_string()).map_err(|e| e.to_string())?; + } + log!("BEAUTY_MOUNT {}", evidence); + Ok(()) + } + + fn measure_layout(&mut self, cx: &mut Cx) { + if self.layout_path.is_empty() { + return; + } + let mut rows = Vec::new(); + let mut pending = Vec::new(); + for (index,id) in self.inspection_ids.iter().enumerate() { + let widget = self.ui.widget(cx, &[LiveId::from_str(id)]); + let area = widget.area(); + if !area.is_valid(cx) { + pending.push(serde_json::json!({"id":id,"reason":"missing drawn area"})); + continue; + } + let raw = area.rect(cx); + let clipped = area.clipped_rect(cx); + if index==0 && (clipped.pos.x>raw.pos.x+0.5 || clipped.pos.y>raw.pos.y+0.5 || + clipped.size.x().map(|svg| { + svg.draw_svg.svg_doc.is_some() && !svg.draw_svg.cached_indices.is_empty() + }).or_else(||widget.borrow::().map(|glass|glass.svg.draw_svg.svg_doc.is_some()&&!glass.svg.draw_svg.cached_indices.is_empty())); + let glass_ready=widget.borrow::().map(|glass|glass.snapshot_ready) + .or_else(||widget.borrow::().map(|glass|glass.snapshot_ready)); + if glass_ready==Some(false) { + pending.push(serde_json::json!({"id":id,"reason":"native backdrop texture not ready"})); + } + if vector_ready == Some(false) { + pending.push(serde_json::json!({"id":id,"reason":"SVG geometry not ready"})); + } + let text_layout = widget.borrow::