Onion skin settings: move from floating window to the Info Panel

The standalone egui window didn't fit the UI. Replaced it with a collapsible
"Onion Skin" section at the bottom of the Info Panel (Enabled checkbox + frames
before/after + opacity), available regardless of selection. SharedPaneState carries
a mutable `onion_skin` ref for the controls (distinct from the gated `onion` copy
used by rendering).
This commit is contained in:
Skyler Lehmkuhl 2026-06-20 23:49:33 -04:00
parent 10b4aa481e
commit 7445ee919f
3 changed files with 32 additions and 20 deletions

View File

@ -6471,6 +6471,7 @@ impl eframe::App for EditorApp {
o.enabled = o.enabled && !self.is_playing;
o
},
onion_skin: &mut self.onion_skin,
tool_icon_cache: &mut self.tool_icon_cache,
icon_cache: &mut self.icon_cache,
selected_tool: &mut self.selected_tool,
@ -7032,26 +7033,6 @@ impl eframe::App for EditorApp {
}
// Onion skin settings window (shown only when onion skinning is enabled)
if self.onion_skin.enabled {
egui::Window::new("Onion Skin")
.resizable(false)
.collapsible(true)
.anchor(egui::Align2::RIGHT_TOP, [-10.0, 40.0])
.show(ctx, |ui| {
ui.label("Onion skin settings");
ui.horizontal(|ui| {
ui.label("Frames before:");
ui.add(egui::DragValue::new(&mut self.onion_skin.frames_before).range(0..=5));
});
ui.horizontal(|ui| {
ui.label("Frames after:");
ui.add(egui::DragValue::new(&mut self.onion_skin.frames_after).range(0..=5));
});
ui.add(egui::Slider::new(&mut self.onion_skin.opacity, 0.0..=1.0).text("Opacity"));
});
}
// Render custom cursor overlay (on top of everything including debug overlay)
custom_cursor::render_overlay(ctx, &mut self.cursor_cache);

View File

@ -1035,6 +1035,29 @@ impl InfopanelPane {
});
}
/// Render the onion-skinning view settings (global; not tied to selection).
fn render_onion_section(&mut self, ui: &mut Ui, path: &NodePath, shared: &mut SharedPaneState) {
egui::CollapsingHeader::new("Onion Skin")
.id_salt(("onion", path))
.default_open(shared.onion_skin.enabled)
.show(ui, |ui| {
ui.add_space(4.0);
ui.checkbox(&mut shared.onion_skin.enabled, "Enabled");
ui.add_enabled_ui(shared.onion_skin.enabled, |ui| {
ui.horizontal(|ui| {
ui.label("Frames before:");
ui.add(DragValue::new(&mut shared.onion_skin.frames_before).range(0..=5));
});
ui.horizontal(|ui| {
ui.label("Frames after:");
ui.add(DragValue::new(&mut shared.onion_skin.frames_after).range(0..=5));
});
ui.add(egui::Slider::new(&mut shared.onion_skin.opacity, 0.0..=1.0).text("Opacity"));
});
ui.add_space(4.0);
});
}
/// Render layer info section
fn render_layer_section(&self, ui: &mut Ui, path: &NodePath, shared: &SharedPaneState, layer_ids: &[Uuid]) {
let document = shared.action_executor.document();
@ -1478,6 +1501,12 @@ impl PaneRenderer for InfopanelPane {
}
}
}
// Onion-skinning view settings — always available, regardless of selection.
ui.add_space(8.0);
ui.separator();
ui.add_space(4.0);
self.render_onion_section(ui, path, shared);
});
}

View File

@ -177,6 +177,8 @@ impl OnionSkinSettings {
pub struct SharedPaneState<'a> {
/// Effective onion-skin settings (already gated to off during playback by main.rs).
pub onion: OnionSkinSettings,
/// The raw onion-skin settings, mutable — edited by the Info Panel's controls.
pub onion_skin: &'a mut OnionSkinSettings,
pub tool_icon_cache: &'a mut crate::ToolIconCache,
#[allow(dead_code)] // Used by pane chrome rendering in main.rs
pub icon_cache: &'a mut crate::IconCache,