mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 18:27:02 -06:00
Fix floating tab reorder deadlock by calling strip_tab_reorder in-frame.
Route dock and floating strip reorders through shared logic, sync layout.floating order, and assert reorder via window.panel.move in the harness test. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Cursor
parent
951d1705e3
commit
571ac32362
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,13 +695,11 @@ fn apply(app: &mut VectorcraftApp, ctx: &egui::Context, action: Option<Action>)
|
||||
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"]]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Value, String> {
|
||||
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<Placement<String>, 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<V
|
||||
&& panel_group.is_none()
|
||||
&& crate::floating::group_of(&app.ui, before).is_none();
|
||||
if app.ui.docking.is_none() || panel_group.is_some() || dock_strip_reorder {
|
||||
let target = legacy_strip_reorder_target(app, before, dock_strip_reorder, panel_group)?;
|
||||
let mirror_native_tabs = panel_group
|
||||
.and_then(|i| app.ui.floating_panels.get(i))
|
||||
.is_some_and(decorated);
|
||||
let snapshot = app.ui.clone();
|
||||
let result = legacy_same_strip_reorder(app, panel, before, target);
|
||||
if mirror_native_tabs && app.ui.docking.is_some() && result.is_ok() {
|
||||
reconcile_native(app, snapshot)?;
|
||||
}
|
||||
return result;
|
||||
return strip_tab_reorder(app, panel, before);
|
||||
}
|
||||
}
|
||||
if app.ui.docking.as_ref().is_some_and(|layout| !valid(layout)) {
|
||||
@@ -840,7 +851,9 @@ pub(crate) fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) -> bool {
|
||||
{
|
||||
return app.ui.docking.is_some();
|
||||
}
|
||||
ui.ctx().data_mut(|data| data.remove::<LegacyDrag>(egui::Id::new("vectorcraft-panel-docking").with("legacy-origin")));
|
||||
craft_ui::docking::cancel_drag::<String>(ui.ctx(), egui::Id::new("vectorcraft-panel-docking"));
|
||||
ui.ctx()
|
||||
.data_mut(|data| data.remove::<LegacyDrag>(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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user