diff --git a/src/ui/pages/overview/preview.rs b/src/ui/pages/overview/preview.rs index 43bda28..36bd8e5 100644 --- a/src/ui/pages/overview/preview.rs +++ b/src/ui/pages/overview/preview.rs @@ -224,6 +224,48 @@ impl PreviewSessionWidgets { } } +#[derive(Clone)] +struct PreviewStudioControlWidgets { + scene_dropdown: gtk4::DropDown, + fps_spin: gtk4::SpinButton, + particle_count_spin: gtk4::SpinButton, + particle_size_spin: gtk4::SpinButton, + gpu_passes_spin: gtk4::SpinButton, + interaction_spin: gtk4::SpinButton, + vram_spin: gtk4::SpinButton, + vsync_switch: gtk4::Switch, + pause_switch: gtk4::Switch, + width_spin: gtk4::SpinButton, + height_spin: gtk4::SpinButton, +} + +impl PreviewStudioControlWidgets { + fn apply_studio_runtime(&self, studio: &PreviewStudioOptions) { + if let Some(index) = StudioScene::all() + .iter() + .position(|scene| *scene == studio.scene) + { + self.scene_dropdown.set_selected(index as u32); + } + self.fps_spin.set_value(studio.fps_cap.unwrap_or(0) as f64); + self.particle_count_spin + .set_value(studio.particle_count as f64); + self.particle_size_spin + .set_value(studio.particle_size as f64); + self.gpu_passes_spin.set_value(studio.gpu_passes as f64); + self.interaction_spin + .set_value(studio.interaction_steps as f64); + self.vram_spin.set_value(studio.vram_pressure_mb as f64); + self.vsync_switch.set_active(studio.vsync); + self.pause_switch.set_active(studio.paused); + } + + fn apply_window_size(&self, width: i32, height: i32) { + self.width_spin.set_value(width as f64); + self.height_spin.set_value(height as f64); + } +} + pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let panel = gtk4::Box::new(gtk4::Orientation::Vertical, 10); panel.add_css_class("dashboard-stack"); @@ -640,6 +682,20 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { interaction_row.append(&interaction_controls); cpu_body.append(&interaction_row); + let control_widgets = PreviewStudioControlWidgets { + scene_dropdown: scene_dropdown.clone(), + fps_spin: fps_spin.clone(), + particle_count_spin: particle_count_spin.clone(), + particle_size_spin: particle_size_spin.clone(), + gpu_passes_spin: gpu_passes_spin.clone(), + interaction_spin: interaction_spin.clone(), + vram_spin: vram_spin.clone(), + vsync_switch: vsync_switch.clone(), + pause_switch: pause_switch.clone(), + width_spin: width_spin.clone(), + height_spin: height_spin.clone(), + }; + let (setup_group, setup_body) = preview_group( "Preview setups", "Apply a built-in workload shape quickly, or reset everything back to the Studio defaults.", @@ -658,35 +714,12 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let preview_controls = preview_controls.clone(); let studio_defaults = studio_defaults.clone(); let control_sync = control_sync.clone(); - let scene_dropdown = scene_dropdown.clone(); - let fps_spin = fps_spin.clone(); - let particle_count_spin = particle_count_spin.clone(); - let particle_size_spin = particle_size_spin.clone(); - let gpu_passes_spin = gpu_passes_spin.clone(); - let interaction_spin = interaction_spin.clone(); - let vram_spin = vram_spin.clone(); - let vsync_switch = vsync_switch.clone(); - let pause_switch = pause_switch.clone(); + let control_widgets = control_widgets.clone(); button.connect_clicked(move |_| { let studio = profile.studio(); studio_defaults.replace(studio.clone()); persist_studio_options(&studio); - control_sync.set(true); - if let Some(index) = StudioScene::all() - .iter() - .position(|scene| *scene == studio.scene) - { - scene_dropdown.set_selected(index as u32); - } - fps_spin.set_value(studio.fps_cap.unwrap_or(0) as f64); - particle_count_spin.set_value(studio.particle_count as f64); - particle_size_spin.set_value(studio.particle_size as f64); - gpu_passes_spin.set_value(studio.gpu_passes as f64); - interaction_spin.set_value(studio.interaction_steps as f64); - vram_spin.set_value(studio.vram_pressure_mb as f64); - vsync_switch.set_active(studio.vsync); - pause_switch.set_active(studio.paused); - control_sync.set(false); + apply_preview_control_state(&control_sync, &control_widgets, &studio, None); maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio); }); profile_rows.attach(&button, (index % 2) as i32, (index / 2) as i32, 1, 1); @@ -697,17 +730,7 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let preview_controls_reset = preview_controls.clone(); let studio_defaults_reset = studio_defaults.clone(); let control_sync_reset = control_sync.clone(); - let scene_dropdown_reset = scene_dropdown.clone(); - let fps_spin_reset = fps_spin.clone(); - let particle_count_spin_reset = particle_count_spin.clone(); - let particle_size_spin_reset = particle_size_spin.clone(); - let gpu_passes_spin_reset = gpu_passes_spin.clone(); - let interaction_spin_reset = interaction_spin.clone(); - let vram_spin_reset = vram_spin.clone(); - let vsync_switch_reset = vsync_switch.clone(); - let pause_switch_reset = pause_switch.clone(); - let width_spin_reset = width_spin.clone(); - let height_spin_reset = height_spin.clone(); + let control_widgets_reset = control_widgets.clone(); reset_preview_button.connect_clicked(move |_| { let studio = PreviewStudioOptions::default(); let (default_width, default_height) = default_preview_window_size(); @@ -715,24 +738,12 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { persist_studio_options(&studio); persist_preview_window_width(default_width); persist_preview_window_height(default_height); - control_sync_reset.set(true); - if let Some(index) = StudioScene::all() - .iter() - .position(|scene| *scene == studio.scene) - { - scene_dropdown_reset.set_selected(index as u32); - } - fps_spin_reset.set_value(studio.fps_cap.unwrap_or(0) as f64); - particle_count_spin_reset.set_value(studio.particle_count as f64); - particle_size_spin_reset.set_value(studio.particle_size as f64); - gpu_passes_spin_reset.set_value(studio.gpu_passes as f64); - interaction_spin_reset.set_value(studio.interaction_steps as f64); - vram_spin_reset.set_value(studio.vram_pressure_mb as f64); - vsync_switch_reset.set_active(studio.vsync); - pause_switch_reset.set_active(studio.paused); - width_spin_reset.set_value(default_width as f64); - height_spin_reset.set_value(default_height as f64); - control_sync_reset.set(false); + apply_preview_control_state( + &control_sync_reset, + &control_widgets_reset, + &studio, + Some((default_width, default_height)), + ); maybe_restart_active_preview(&ctx_reset, &preview_controls_reset, studio); }); setup_body.append(&profile_rows); @@ -753,19 +764,22 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); scene_dropdown.connect_selected_notify(move |dropdown| { - if control_sync.get() { - return; - } let Some(scene) = StudioScene::all() .get(dropdown.selected() as usize) .copied() else { return; }; - let mut studio = studio_defaults.borrow_mut(); - studio.scene = scene; - persist_preview_studio_scene(scene); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.scene = scene; + persist_preview_studio_scene(scene); + }, + ); }); } @@ -775,14 +789,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); fps_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let value = spin.value().round().clamp(0.0, 1000.0) as i32; - let mut studio = studio_defaults.borrow_mut(); - studio.fps_cap = if value <= 0 { None } else { Some(value as u32) }; - persist_studio_fps_cap(value); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.fps_cap = if value <= 0 { None } else { Some(value as u32) }; + persist_studio_fps_cap(value); + }, + ); }); } @@ -792,14 +809,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); particle_count_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let count = spin.value().round().clamp(100.0, 500_000.0) as i32; - let mut studio = studio_defaults.borrow_mut(); - studio.particle_count = count as u32; - persist_studio_particle_count(count); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.particle_count = count as u32; + persist_studio_particle_count(count); + }, + ); }); } @@ -809,14 +829,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); particle_size_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let size = spin.value().clamp(0.01, 5.0); - let mut studio = studio_defaults.borrow_mut(); - studio.particle_size = size as f32; - persist_studio_particle_size(size); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.particle_size = size as f32; + persist_studio_particle_size(size); + }, + ); }); } @@ -826,14 +849,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); gpu_passes_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let passes = spin.value().round().clamp(1.0, 64.0) as i32; - let mut studio = studio_defaults.borrow_mut(); - studio.gpu_passes = passes as u32; - persist_studio_gpu_passes(passes); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.gpu_passes = passes as u32; + persist_studio_gpu_passes(passes); + }, + ); }); } @@ -843,14 +869,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); interaction_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let steps = spin.value().round().clamp(0.0, 256.0) as i32; - let mut studio = studio_defaults.borrow_mut(); - studio.interaction_steps = steps as u32; - persist_studio_interaction_steps(steps); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.interaction_steps = steps as u32; + persist_studio_interaction_steps(steps); + }, + ); }); } @@ -860,14 +889,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); vram_spin.connect_value_changed(move |spin| { - if control_sync.get() { - return; - } let mb = spin.value().round().clamp(0.0, 4096.0) as i32; - let mut studio = studio_defaults.borrow_mut(); - studio.vram_pressure_mb = mb as u32; - persist_studio_vram_pressure(mb); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.vram_pressure_mb = mb as u32; + persist_studio_vram_pressure(mb); + }, + ); }); } @@ -877,13 +909,17 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); vsync_switch.connect_active_notify(move |switch| { - if control_sync.get() { - return; - } - let mut studio = studio_defaults.borrow_mut(); - studio.vsync = switch.is_active(); - persist_preview_vsync(switch.is_active()); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + let active = switch.is_active(); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.vsync = active; + persist_preview_vsync(active); + }, + ); }); } @@ -893,12 +929,16 @@ pub(crate) fn build_preview_panel(ctx: &PageBuildContext) -> gtk4::Box { let ctx = ctx.clone(); let preview_controls = preview_controls.clone(); pause_switch.connect_active_notify(move |switch| { - if control_sync.get() { - return; - } - let mut studio = studio_defaults.borrow_mut(); - studio.paused = switch.is_active(); - maybe_apply_studio_preview_runtime(&ctx, &preview_controls, studio.clone()); + let active = switch.is_active(); + update_studio_runtime_setting( + &control_sync, + &ctx, + &preview_controls, + &studio_defaults, + move |studio| { + studio.paused = active; + }, + ); }); } @@ -1163,6 +1203,36 @@ fn persist_preview_vsync(enabled: bool) { } } +fn apply_preview_control_state( + control_sync: &Cell, + controls: &PreviewStudioControlWidgets, + studio: &PreviewStudioOptions, + window_size: Option<(i32, i32)>, +) { + control_sync.set(true); + controls.apply_studio_runtime(studio); + if let Some((width, height)) = window_size { + controls.apply_window_size(width, height); + } + control_sync.set(false); +} + +fn update_studio_runtime_setting( + control_sync: &Cell, + ctx: &PageBuildContext, + preview_controls: &PreviewSessionWidgets, + studio_defaults: &Rc>, + update: impl FnOnce(&mut PreviewStudioOptions), +) { + if control_sync.get() { + return; + } + + let mut studio = studio_defaults.borrow_mut(); + update(&mut studio); + maybe_apply_studio_preview_runtime(ctx, preview_controls, studio.clone()); +} + pub(super) fn preview_window_settings( _scene: PreviewScene, config: &AnnotatedConfig,