Floating panels: no widget ID clash when dragged past the window edge [skip ci]
The floating group's title strip used the same id as its Area's own background widget, and the Area was shifted back into the window while the group's rect kept moving, so the two no longer overlapped and egui painted "Double use of widget ID" over the panel. The strip has its own id and the group is drawn where its rect says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
470ea7a3af
commit
e91b19f2a5
|
|
@ -330,12 +330,15 @@ impl EffectcraftApp {
|
|||
));
|
||||
let id = egui::Id::new(("floating-panel", f.panels.first().map(|p| p.id()).unwrap_or_default()));
|
||||
let mut group = None;
|
||||
egui::Area::new(id).order(egui::Order::Middle).fixed_pos(rect.min).interactable(true).show(ctx, |ui| {
|
||||
// Not constrained to the window: the group is drawn where its rect says (the clamp above
|
||||
// keeps its strip reachable), so it follows the pointer past the window's edges.
|
||||
egui::Area::new(id).order(egui::Order::Middle).fixed_pos(rect.min).constrain(false).interactable(true).show(ctx, |ui| {
|
||||
let (r, _) = ui.allocate_exact_size(rect.size(), Sense::hover());
|
||||
ui.painter().rect_filled(r.expand(1.0), t.radius, Color32::from_black_alpha(90));
|
||||
let strip = Rect::from_min_size(r.min, vec2(r.width(), t.tab_h));
|
||||
// Move by the strip (tabs, registered later, take precedence over it).
|
||||
let mv = ui.interact(strip, id.with("move"), Sense::drag());
|
||||
// (`id.with("move")` is the id of the `Area`'s own background widget.)
|
||||
let mv = ui.interact(strip, id.with("strip"), Sense::drag());
|
||||
self.auto.add(&format!("panel.float.{i}.move"), strip, "Move floating panel");
|
||||
let mut nr = r;
|
||||
if mv.dragged() {
|
||||
|
|
|
|||
|
|
@ -273,6 +273,29 @@ fn float_command_rejects_malformed_rectangles_atomically() {
|
|||
assert!(!app.edit_layout(|layout| layout.apply(Action::Float { panel: PanelKind::Project, rect: [1.0, 2.0, 300.0, 200.0] }).is_ok()));
|
||||
}
|
||||
|
||||
/// A floating panel dragged past the window's bottom edge is drawn where its rect says: it was
|
||||
/// shifted back into the window while its rect kept moving, and its strip then clashed with the
|
||||
/// floating area's own widget ("Double use of widget ID").
|
||||
#[test]
|
||||
fn floating_panel_dragged_past_the_window_edge_is_drawn_at_its_rect() {
|
||||
let mut h = Harness::builder().with_size(vec2(1600.0, 1000.0)).build_eframe(|_| EffectcraftApp::new(Session::default()));
|
||||
h.run_steps(3);
|
||||
let ctx = h.ctx.clone();
|
||||
effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "window.floatPanel", json!({"panel": "Preview", "rect": [600.0, 400.0, 360.0, 300.0]})).unwrap();
|
||||
h.run_steps(3);
|
||||
let strip = rect(&h, "panel.float.0.move");
|
||||
let from = pos2(strip.right() - 24.0, strip.center().y);
|
||||
drag(&mut h, from, from + vec2(40.0, 420.0), Modifiers::NONE);
|
||||
let moved = h.state().ui.floating[0].rect;
|
||||
assert!(moved[1] + moved[3] > 1000.0, "the panel hangs past the bottom edge: {moved:?}");
|
||||
let strip = rect(&h, "panel.float.0.move");
|
||||
assert_eq!([strip.min.x, strip.min.y], [moved[0], moved[1]]);
|
||||
// The strip still moves it from there.
|
||||
let from = pos2(strip.right() - 24.0, strip.center().y);
|
||||
drag(&mut h, from, from - vec2(30.0, 200.0), Modifiers::NONE);
|
||||
assert_eq!(h.state().ui.floating[0].rect[1], moved[1] - 200.0);
|
||||
}
|
||||
|
||||
fn action_state(h: &Harness<'_, EffectcraftApp>, action: &str) -> serde_json::Value {
|
||||
json!({"action": action, "dock": h.state().ui.dock, "floating": h.state().ui.floating, "focused": h.state().ui.focused})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue