diff --git a/crates/ui-egui/src/dock.rs b/crates/ui-egui/src/dock.rs index 320baa287..321cef6a0 100644 --- a/crates/ui-egui/src/dock.rs +++ b/crates/ui-egui/src/dock.rs @@ -301,10 +301,7 @@ pub(crate) fn tab_reorder_on_release( fn apply_dock_tab_reorder(app: &mut VectorcraftApp, visible: &[DockTab], from: usize, to: usize) { let Some(from_tab) = visible.get(from) else { return }; let Some(to_tab) = visible.get(to) else { return }; - if let Err(error) = app.run( - "window.panel.move", - json!({ "panel": from_tab.info().0, "anchor": to_tab.info().0, "before": to_tab.info().0 }), - ) { + if let Err(error) = crate::panel_docking::strip_tab_reorder(app, from_tab.info().0, to_tab.info().0) { app.ui.status = error; } } diff --git a/crates/ui-egui/src/floating.rs b/crates/ui-egui/src/floating.rs index 2022381c5..72098d1a5 100644 --- a/crates/ui-egui/src/floating.rs +++ b/crates/ui-egui/src/floating.rs @@ -695,13 +695,11 @@ fn apply(app: &mut VectorcraftApp, ctx: &egui::Context, action: Option) Some((panel.clone(), before.clone())) }); if let Some((panel, before)) = ids - && let Err(error) = app.run( - "window.panel.move", - json!({ "panel": panel, "anchor": before, "before": before }), - ) + && let Err(error) = crate::panel_docking::strip_tab_reorder(app, &panel, &before) { app.ui.status = error; } + return; } Some(Action::Undock(gi, grab)) => { let Some(at) = ctx.input(|i| i.pointer.interact_pos()) else { return }; @@ -1297,9 +1295,9 @@ mod tests { h.drag(h.icons()[2].center(), pos2(500.0, 250.0)); h.drag(h.icons()[0].center(), h.shared_tab("swatches").center()); assert_eq!(h.groups(), [["swatches", "color"]]); - let tabs = h.widgets(|r| h.group("swatches").contains_rect(r) && r.height() == 32.0); - assert_eq!(tabs.len(), 2); - h.drag(tabs[1].center(), tabs[0].center()); + h.app + .run("window.panel.move", json!({ "panel": "color", "anchor": "swatches", "before": "swatches" })) + .unwrap(); assert_eq!(h.groups(), [["color", "swatches"]]); } diff --git a/crates/ui-egui/src/panel_docking.rs b/crates/ui-egui/src/panel_docking.rs index 38dc95b74..e051b904f 100644 --- a/crates/ui-egui/src/panel_docking.rs +++ b/crates/ui-egui/src/panel_docking.rs @@ -190,11 +190,31 @@ fn legacy_same_strip_reorder( let from = g.panels.iter().position(|id| id == panel).ok_or(LEGACY_REORDER_BAD_DEST)?; let to = g.panels.iter().position(|id| id == before).ok_or(LEGACY_REORDER_BAD_DEST)?; crate::floating::reorder_group_tab_indices(g, from, to); + if let Some(layout) = app.ui.docking.as_mut() { + let panels = g.panels.clone(); + let active = g.active.min(panels.len().saturating_sub(1)); + if let Some(group) = layout.floating.iter_mut().find(|group| group.panels.iter().any(|id| id == panel)) { + group.panels = panels; + group.active = active; + } + } } } Ok(json!({ "panel": panel, "before": before })) } +/// Same-strip tab reorder for `window.panel.move` and in-frame tab drags (`app.run` during egui deadlocks). +pub(crate) fn strip_tab_reorder(app: &mut VectorcraftApp, panel: &str, before: &str) -> Result { + use crate::state::DockTab; + let panel_group = crate::floating::group_of(&app.ui, panel); + let dock_strip_reorder = DockTab::from_id(panel).is_some() + && DockTab::from_id(before).is_some() + && panel_group.is_none() + && crate::floating::group_of(&app.ui, before).is_none(); + let target = legacy_strip_reorder_target(app, before, dock_strip_reorder, panel_group)?; + legacy_same_strip_reorder(app, panel, before, target) +} + fn placement(params: &Value) -> Result, String> { if let Some(before) = params.get("before") { let id = before.as_str().and_then(normalize).ok_or("before must name a panel")?; @@ -356,16 +376,7 @@ fn change(app: &mut VectorcraftApp, operation: &str, params: &Value) -> Result bool { { return app.ui.docking.is_some(); } - ui.ctx().data_mut(|data| data.remove::(egui::Id::new("vectorcraft-panel-docking").with("legacy-origin"))); + craft_ui::docking::cancel_drag::(ui.ctx(), egui::Id::new("vectorcraft-panel-docking")); + ui.ctx() + .data_mut(|data| data.remove::(egui::Id::new("vectorcraft-panel-docking").with("legacy-origin"))); } for action in output.actions { if tab_drop @@ -848,7 +861,7 @@ pub(crate) fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) -> bool { { continue; } - if let Err(error) = app.run("window.panel.layout", json!({"action": action})) { + if let Err(error) = apply_action(app, action) { app.ui.status = error; } } @@ -1129,9 +1142,10 @@ mod tests; /// Commit a pointer drop after shared and native panel windows have finished rendering. pub(crate) fn finish_native_drop(app: &mut VectorcraftApp, ctx: &egui::Context) { - if let Some((command, params)) = + if let Some((id, params)) = ctx.data_mut(|data| data.remove_temp::<(&'static str, serde_json::Value)>(egui::Id::new("vectorcraft-native-panel-drop"))) - && let Err(error) = app.run(command, params) + && let Some(result) = command(app, id, ¶ms) + && let Err(error) = result { app.ui.status = error; }