From 04c81c6ba05bac2a2a0f8b0d3323912945f64075 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 20:11:24 -0700 Subject: [PATCH] Splash: reapply_text reconciles host-generated UI into existing widgets A host that regenerates a Splash body from declarative data (Rinx's L0 mini apps) must keep focus, selection and scroll state in the named widgets it already has. reapply_text evaluates the new body with Apply::Reload into the existing view; set_text still tears the instance down. From #32 (its Splash part), on main. Co-Authored-By: Claude Opus 5.5 (1M context) --- widgets/src/splash.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/widgets/src/splash.rs b/widgets/src/splash.rs index 53db34c044..4b92e6200c 100644 --- a/widgets/src/splash.rs +++ b/widgets/src/splash.rs @@ -201,6 +201,10 @@ impl Splash { fn eval_body(&mut self, cx: &mut Cx) {self.eval_styled_body(cx,false);} fn eval_styled_body(&mut self,cx:&mut Cx,preserve:bool) { + self.eval_styled_body_with_apply(cx, preserve, &Apply::ScriptReapply); + } + + fn eval_styled_body_with_apply(&mut self, cx: &mut Cx, preserve: bool, apply: &Apply) { if self.body.as_ref().is_empty() { return; } @@ -318,7 +322,7 @@ impl Splash { let view = if !value.is_err() && !value.is_nil() { if preserve { let walk=self.view.walk; - self.view.script_apply(vm,&Apply::ScriptReapply,&mut Scope::empty(),value); + self.view.script_apply(vm,apply,&mut Scope::empty(),value); self.view.walk=walk; None } else {Some(View::script_from_value(vm, value))} @@ -942,6 +946,24 @@ impl SplashRef { } } + /// Reconcile a host-generated UI into its existing named widgets. This + /// keeps focus, selection and scroll state while declarative data changes. + /// Use set_text("") to tear down the instance and revoke its callbacks. + pub fn reapply_text(&self, cx: &mut Cx, body: &str) { + if let Some(mut inner) = self.borrow_mut() { + if inner.vm_id == MAIN_SPLASH_VM_ID || body.is_empty() { + inner.set_text(cx, body); + } else if inner.body.as_ref() != body { + inner.body.set(body); + // This is new declarative source, not a stylesheet reapply. + // Reload updates label data while reconciling named widgets; + // their Rust focus/selection/scroll state remains in place. + inner.eval_styled_body_with_apply(cx, true, &Apply::Reload); + inner.redraw(cx); + } + } + } + /// See [`Splash::set_sandbox_dir`]. pub fn set_sandbox_dir(&self, cx: &mut Cx, dir: Option) { if let Some(mut inner) = self.borrow_mut() {