#1985: a panel closed while floating opens again floating where it was

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
irgendwasmitfelix
2026-10-19 14:51:33 +02:00
co-authored by Claude Opus 5.5
parent 6c3948a36c
commit 5510a52a06
4 changed files with 48 additions and 0 deletions
+11
View File
@@ -97,6 +97,11 @@ impl FilmcraftApp {
Action::Activate { panel } => Some(*panel),
_ => None,
};
// a panel closed while floating remembers where; closed while docked, it forgets (#1985)
let closing = match &action {
Action::Close { panel } => Some((*panel, self.ui.floating.iter().find(|g| g.panels.contains(panel)).map(|g| g.rect))),
_ => None,
};
self.commit_dock(|shared| {
crate::dock_shared::check_last_docked(shared, &action)?;
shared.apply(action).map_err(|error| error.to_string())
@@ -104,6 +109,12 @@ impl FilmcraftApp {
if let Some(panel) = reveal {
self.pending_panel_raise = Some(panel);
}
if let Some((panel, rect)) = closing {
self.ui.closed_floating.retain(|(p, _)| *p != panel);
if let Some(rect) = rect {
self.ui.closed_floating.push((panel, rect));
}
}
if relocating
|| self.ui.keys.maximized.is_some_and(|panel| !self.ui.dock.contains(panel) && !self.ui.floating.iter().any(|group| group.panels.contains(&panel)))
{
+10
View File
@@ -872,6 +872,16 @@ impl FilmcraftApp {
_ => PanelKind::Project,
};
self.ui.dock.open_near(p, near);
// closed while floating: it floats again where it was (#1985)
if let Some(i) = self.ui.closed_floating.iter().position(|(k, _)| *k == p) {
let (_, rect) = self.ui.closed_floating.remove(i);
if rect.iter().all(|v| v.is_finite()) {
let rect = [rect[0], rect[1], rect[2].max(160.0), rect[3].max(120.0)];
if let Err(e) = self.apply_dock(craft_ui::docking::Action::Float { panel: p, rect }) {
log::warn!("could not float {} again: {e}", p.id());
}
}
}
}
let _ = self.apply_dock(craft_ui::docking::Action::Activate { panel: p });
self.ui.focused = p;
+5
View File
@@ -436,6 +436,10 @@ pub struct UiState {
pub dock: DockNode,
#[serde(default)]
pub floating: Vec<crate::dock::Floating>,
/// Where each panel closed while floating was ([x, y, width, height]): opening it again
/// brings it back there, floating, instead of docked (#1985).
#[serde(default)]
pub closed_floating: Vec<(PanelKind, [f32; 4])>,
/// Focused panel (blue outline, receives shortcuts).
pub focused: PanelKind,
pub timeline: TimelineView,
@@ -960,6 +964,7 @@ impl Default for UiState {
mode: Mode::Edit,
workspace: "Editing".into(),
floating: vec![],
closed_floating: vec![],
dock: crate::dock::workspace("Editing"),
focused: PanelKind::Timeline,
timeline: TimelineView::default(),
+22
View File
@@ -559,3 +559,25 @@ fn narration_selection_reveals_covered_floating_tts_once_without_editing_the_pro
assert_eq!(h.state().ui.tts, draft);
assert!(std::sync::Arc::ptr_eq(&project, &h.state().session.project));
}
/// #1985: a panel closed while floating came back docked when opened again from the Window menu;
/// it now floats again where it was. Closed while docked, it opens docked as before.
#[test]
fn a_panel_closed_while_floating_reopens_floating_where_it_was() {
let mut app = FilmcraftApp::new(Session::default());
let ctx = egui::Context::default();
menus::invoke(&mut app, &ctx, "window.floatPanel", json!({"panel": "Info", "rect": [45, 65, 420, 320]})).unwrap();
let rect = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Info)).unwrap().rect;
menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Info"})).unwrap();
assert!(!app.ui.dock.contains(PanelKind::Info) && !app.ui.floating.iter().any(|g| g.panels.contains(&PanelKind::Info)));
menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Info), json!({})).unwrap();
let back = app.ui.floating.iter().find(|g| g.panels.contains(&PanelKind::Info)).expect("Info floats again");
assert_eq!(back.rect, rect, "where it was");
assert!(!app.ui.dock.contains(PanelKind::Info));
// docked, then closed: it opens docked
menus::invoke(&mut app, &ctx, "window.dockPanel", json!({"panel": "Info", "anchor": "Project"})).unwrap();
menus::invoke(&mut app, &ctx, "window.closePanel", json!({"panel": "Info"})).unwrap();
menus::invoke(&mut app, &ctx, &menus::panel_command_id(PanelKind::Info), json!({})).unwrap();
assert!(app.ui.dock.contains(PanelKind::Info));
assert!(!app.ui.floating.iter().any(|g| g.panels.contains(&PanelKind::Info)));
}