From 4a9ccc6fe35614c3427592ff54c8bedc793d6dbb Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 4 Nov 2026 03:04:31 -0800 Subject: [PATCH] Preferences: a Render Threads change before the first UI pass restarts the canvas renderer The first UI pass applies the saved preferences again (#4837) by removing the record of what was last applied. A Render Threads change made by a control request between an earlier tick and that pass was then applied with no previous value to compare, so the canvas renderer kept its old thread count. The pass now forces the theme refresh and keeps the record, so the thread change still restarts the renderer. --- crates/ui-egui/src/prefs_dialog.rs | 16 +++++++++++----- crates/ui-egui/src/prefs_dialog/tests.rs | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/prefs_dialog.rs b/crates/ui-egui/src/prefs_dialog.rs index b91c149f4..20502f0f6 100644 --- a/crates/ui-egui/src/prefs_dialog.rs +++ b/crates/ui-egui/src/prefs_dialog.rs @@ -109,6 +109,12 @@ fn canvas_color(key: &str) -> Option { /// Per frame: push UI-side preferences into egui / the renderer when they change. pub fn apply_runtime(app: &mut VectorcraftApp, ctx: &egui::Context) { + apply(app, ctx, false); +} + +/// [`apply_runtime`]; with `force`, the preferences are pushed into `ctx` even when nothing changed +/// since the last push. +fn apply(app: &mut VectorcraftApp, ctx: &egui::Context, force: bool) { let p = &app.session.prefs; if let Some(b) = Brightness::parse(&p.ui_brightness) && b != app.ui.brightness @@ -127,7 +133,7 @@ pub fn apply_runtime(app: &mut VectorcraftApp, ctx: &egui::Context) { }; let id = applied_id(); let prev: Option = ctx.data(|d| d.get_temp::>(id)).flatten(); - if prev != Some(want) { + if force || prev != Some(want) { theme::apply_with(ctx, want.brightness, want.accent, want.scheme); // General › Show Tool Tips: off, no button or field shows its tool tip (they never come // due), whichever widget asks for one. @@ -165,11 +171,11 @@ fn applied_id() -> egui::Id { egui::Id::unique("dc-applied-prefs") } -/// [`apply_runtime`] with nothing recorded as applied, so the theme (brightness, accent, color -/// scheme and canvas color) and the other UI-side preferences are pushed into `ctx` again. +/// [`apply_runtime`] even when nothing changed, so the theme (brightness, accent, color scheme and +/// canvas color) and the other UI-side preferences are pushed into `ctx` again. The record of what +/// was last applied stays, so a Render Threads change since then still restarts the renderer. pub(crate) fn reapply(app: &mut VectorcraftApp, ctx: &egui::Context) { - ctx.data_mut(|d| d.remove::>(applied_id())); - apply_runtime(app, ctx); + apply(app, ctx, true); } pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { diff --git a/crates/ui-egui/src/prefs_dialog/tests.rs b/crates/ui-egui/src/prefs_dialog/tests.rs index 2e4711505..cbc429b5f 100644 --- a/crates/ui-egui/src/prefs_dialog/tests.rs +++ b/crates/ui-egui/src/prefs_dialog/tests.rs @@ -79,6 +79,23 @@ fn saved_scheme_accent_and_canvas_color_show_from_the_first_frame() { } } +/// A Render Threads change made after the preferences were applied, and before the first UI pass +/// applies them again, still restarts the canvas renderer. +#[test] +fn reapply_restarts_the_renderer_after_a_render_threads_change() { + let mut app = app(); + let ctx = egui::Context::default(); + apply_runtime(&mut app, &ctx); + app.canvas.worker_started = true; + // The automatic count as an explicit value: the process-wide count other tests read stays the same. + let threads = vectorcraft_render::default_threads(); + app.run("prefs.set", json!({"key": "renderThreads", "value": threads})).unwrap(); + reapply(&mut app, &ctx); + let restarted = !app.canvas.worker_started; + app.run("prefs.set", json!({"key": "renderThreads", "value": -1})).unwrap(); + assert!(restarted, "the canvas renderer kept its old thread count"); +} + fn app() -> VectorcraftApp { VectorcraftApp::new(Session::new(), Services::default()) }