panes: the dock preview counts a pane its drop reveals, and a side pane stays inside the host

With SidePolicy::OneSlot a drop can reveal a pane the frame hides, so the landing slot is
worked out from every open pane. A side pane is no wider than the room the panes outside it
leave, as the preview assumes; egui placed a wider one partly beyond the host's edge.
This commit is contained in:
aiongg committed 2026-10-25 05:50:40 +00:00
1 parent 950b9644e8
commit 4dc543cb44
2 files changed
+29 -3

No files matched your search

+9 -3
View File
@@ -205,6 +205,7 @@ struct DragOut {
canceled: bool,
}
#[derive(Clone)]
struct Shown<P> {
pane: P,
id: Id,
@@ -349,6 +350,8 @@ impl PaneHost {
states(pane).or_else(|| ctx.data(|data| data.get_temp::<PaneState>(id.with("state")))).unwrap_or_else(|| content.default_state(pane));
shown.push(Shown { pane: pane.clone(), id, state });
}
// Before the one-slot filter: a drop can reveal a pane this frame hides.
let open_panes = shown.clone();
self.one_slot(&mut shown, content);
let previous = memory.active.filter(|active| shown.iter().any(|s| s.id == *active));
@@ -379,12 +382,12 @@ impl PaneHost {
for edge in [Edge::Start, Edge::End, Edge::Bottom] {
for s in shown.iter().filter(|s| s.state.place == Place::Docked(edge)) {
let rect =
self.docked(ui, &shown, s, edge, content, &style, focus_target == Some(s.id), bounds, &mut memory, &preview, &mut requests);
self.docked(ui, &open_panes, s, edge, content, &style, focus_target == Some(s.id), bounds, &mut memory, &preview, &mut requests);
regions.push(Region { pane: s.id, rect, floating: None });
}
}
for s in shown.iter().filter(|s| s.state.place == Place::Floating) {
let (rect, layer) = self.floating(&ctx, &shown, s, content, &style, focus_target == Some(s.id), bounds, &preview, &mut requests);
let (rect, layer) = self.floating(&ctx, &open_panes, s, content, &style, focus_target == Some(s.id), bounds, &preview, &mut requests);
regions.push(Region { pane: s.id, rect, floating: Some(layer) });
}
@@ -546,7 +549,10 @@ impl PaneHost {
let side = self.side(edge);
let extent = if side == Side::Bottom { bounds.height() } else { bounds.width() };
let (min, max) = self.limits(content, &s.pane, extent);
let size = self.docked_size(content, s, edge, bounds);
// A side pane takes no more than the width the panes outside it leave: egui would place
// a wider one partly beyond the host's edge.
let room = if side == Side::Bottom { f32::INFINITY } else { ui.available_rect_before_wrap().width().max(0.0) };
let size = self.docked_size(content, s, edge, bounds).min(room);
let panel_id = s.id.with("panel");
let panel = match side {
Side::Left => egui::Panel::left(panel_id),
+20
View File
@@ -299,6 +299,26 @@ fn one_slot_previews_a_pane_beside_the_context_pane() {
assert_eq!(panel(&h, Pane::Styles), landing);
}
#[test]
fn one_slot_previews_the_room_a_pane_it_reveals_leaves() {
// Nav and Styles share the start slot, so only Styles shows. Moved to the end, it reveals
// Nav, which takes 500 of the host's 784 pt.
let mut app = App::new(&[Pane::Nav, Pane::Styles]);
app.policy = SidePolicy::OneSlot;
for pane in [Pane::Nav, Pane::Styles] {
app.states.insert(pane, PaneState::docked(Edge::Start, 500.0));
}
let mut h = harness(app);
let from = title(&h, Pane::Styles).center();
let to = pos2(R - 10.0, 300.0);
hold(&mut h, from, to);
let landing = Rect::from_x_y_ranges(L + 500.0..=R, 8.0..=592.0);
assert_eq!(previews(&h), vec![landing]);
send(&mut h, vec![button(to, false)]);
h.run_steps(2);
assert_eq!(panel(&h, Pane::Styles), landing);
}
#[test]
fn escape_and_focus_loss_restore_a_floating_pane_during_a_move() {
let mut app = App::new(&[Pane::Styles]);