Prevent drift when resizing and moving windows (#7709)

* Follows https://github.com/emilk/egui/pull/7708
* Related to #202 

This fixes a particular issue where resizing a window would move it, and
resizing it back would not restore it.

You can still move a window by resizing it (I didn't focus on that bug
here), but at least now the window will return to its original position
when you move back the mouse.
This commit is contained in:
Emil Ernerfeldt 2025-11-12 22:40:04 +01:00
parent 5ae6d6d901
commit 33cc8ef180
2 changed files with 30 additions and 9 deletions

View File

@ -525,11 +525,21 @@ impl Area {
true, true,
); );
// Used to prevent drift
let pivot_at_start_of_drag_id = id.with("pivot_at_drag_start");
if movable if movable
&& move_response.dragged() && move_response.dragged()
&& let Some(pivot_pos) = &mut state.pivot_pos && let Some(pivot_pos) = &mut state.pivot_pos
{ {
*pivot_pos += move_response.drag_delta(); let pivot_at_start_of_drag = ctx.data_mut(|data| {
*data.get_temp_mut_or::<Pos2>(pivot_at_start_of_drag_id, *pivot_pos)
});
*pivot_pos =
pivot_at_start_of_drag + move_response.total_drag_delta().unwrap_or_default();
} else {
ctx.data_mut(|data| data.remove::<Pos2>(pivot_at_start_of_drag_id));
} }
if (move_response.dragged() || move_response.clicked()) if (move_response.dragged() || move_response.clicked())

View File

@ -825,7 +825,7 @@ fn resize_response(
area: &mut area::Prepared, area: &mut area::Prepared,
resize_id: Id, resize_id: Id,
) { ) {
let Some(mut new_rect) = move_and_resize_window(ctx, &resize_interaction) else { let Some(mut new_rect) = move_and_resize_window(ctx, resize_id, &resize_interaction) else {
return; return;
}; };
@ -847,27 +847,38 @@ fn resize_response(
} }
/// Acts on outer rect (outside the stroke) /// Acts on outer rect (outside the stroke)
fn move_and_resize_window(ctx: &Context, interaction: &ResizeInteraction) -> Option<Rect> { fn move_and_resize_window(ctx: &Context, id: Id, interaction: &ResizeInteraction) -> Option<Rect> {
// Used to prevent drift
let rect_at_start_of_drag_id = id.with("window_rect_at_drag_start");
if !interaction.any_dragged() { if !interaction.any_dragged() {
ctx.data_mut(|data| {
data.remove::<Rect>(rect_at_start_of_drag_id);
});
return None; return None;
} }
let pointer_pos = ctx.input(|i| i.pointer.interact_pos())?; let total_drag_delta = ctx.input(|i| i.pointer.total_drag_delta())?;
let mut rect = interaction.outer_rect; // prevent drift
let rect_at_start_of_drag = ctx.data_mut(|data| {
*data.get_temp_mut_or::<Rect>(rect_at_start_of_drag_id, interaction.outer_rect)
});
let mut rect = rect_at_start_of_drag; // prevent drift
// Put the rect in the center of the stroke: // Put the rect in the center of the stroke:
rect = rect.shrink(interaction.window_frame.stroke.width / 2.0); rect = rect.shrink(interaction.window_frame.stroke.width / 2.0);
if interaction.left.drag { if interaction.left.drag {
rect.min.x = pointer_pos.x; rect.min.x += total_drag_delta.x;
} else if interaction.right.drag { } else if interaction.right.drag {
rect.max.x = pointer_pos.x; rect.max.x += total_drag_delta.x;
} }
if interaction.top.drag { if interaction.top.drag {
rect.min.y = pointer_pos.y; rect.min.y += total_drag_delta.y;
} else if interaction.bottom.drag { } else if interaction.bottom.drag {
rect.max.y = pointer_pos.y; rect.max.y += total_drag_delta.y;
} }
// Return to having the rect outside the stroke: // Return to having the rect outside the stroke: