Search code examples
winformsrustimguiglium

Drag move flickers position of window


I'm implementing a Rust alternative to .NET's DragMove method however the result causes the application to flicker between two relative positions.

See screencast and sample project.

Code I'm using to perform the drag move:

let mut mouse_down = false;
let mut last_pos: Option<PhysicalPosition<f64>> = None;
event_loop.run(move |event, _, control_flow| match event {
Event::WindowEvent {
        event: WindowEvent::CursorMoved {
            position,
            ..
        },
        ..
    } => {
        let gl_window = display.gl_window();
        let window = gl_window.window();
        if mouse_down {
            if last_pos.is_some() {
                let previous_pos = last_pos.unwrap();
                let delta_x = previous_pos.x - position.x;
                let delta_y = previous_pos.y - position.y;
                window.set_outer_position(PhysicalPosition::new(position.x + delta_x, position.y + delta_y));
            }
            last_pos = Some(position);
        }
    }
    Event::WindowEvent {
        event: WindowEvent::MouseInput{
            state,
            button,
            ..
        },
        ..
    } => {
        mouse_down = button == MouseButton::Left && state == ElementState::Pressed;
        if !mouse_down {
            last_pos = None;
        }
    }
    _ => {}
});

Solution

  • CursorMoved reports

    (x,y) coords in pixels relative to the top-left corner of the window.

    When you're later using that position to set_outer_position, you are essentially reinterpreting window-relative coordinates as screen-relative.

    You should instead apply the offset to the position returned from outer_position.

    While that fixes the immediate problem, I'm not sure it is enough to account for the window movement. When you're handling the next CursorMoved event, the coordinates are still window-relative, but the window has since moved. That may produce artifacts all over.

    A more robust solution would store the window's position when the drag-move operation starts, and offset that position by the accumulated deltas.