mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 14:49:06 -04:00
Window: move only by dragging title bar (#8183)
* Part of https://github.com/emilk/egui/issues/8180 So far, you've been able to move any `egui::Window` by dragging anywhere on it. This makes sense on touch screens with thick fingers, but less so on non-touch-screens. With this PR, you can now control it with a new enum `WindowDrag`
This commit is contained in:
195
tests/egui_tests/tests/test_window_drag.rs
Normal file
195
tests/egui_tests/tests/test_window_drag.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
//! Tests for [`Window::drag_area`] and [`Window::movable`].
|
||||
//!
|
||||
//! Each test sets up a window with a particular drag configuration, drags
|
||||
//! either inside or outside the title bar, and asserts on the area rect's
|
||||
//! delta. `WindowDrag::OnTouch` is not exercised here since it just resolves
|
||||
//! to `TitleBar` (no touch screen in headless tests).
|
||||
|
||||
use egui::{Id, Pos2, Sense, Vec2, Window, WindowDrag};
|
||||
use egui_kittest::Harness;
|
||||
|
||||
struct State {
|
||||
drag_area: WindowDrag,
|
||||
movable: bool,
|
||||
}
|
||||
|
||||
fn build(state: State) -> Harness<'static, State> {
|
||||
let mut harness = Harness::builder()
|
||||
.with_size(Vec2::new(500.0, 400.0))
|
||||
.with_max_steps(40) // Area requests a repaint every frame while pressed.
|
||||
.build_ui_state(
|
||||
move |ui, state: &mut State| {
|
||||
Window::new("test_win")
|
||||
.id(Id::new("test_win"))
|
||||
.drag_area(state.drag_area)
|
||||
.movable(state.movable)
|
||||
.default_pos([100.0, 80.0])
|
||||
.default_size([180.0, 140.0])
|
||||
.show(ui.ctx(), |ui| {
|
||||
// A passive widget fills the body; it has no drag sense
|
||||
// of its own, so the Area / title-bar widget is what
|
||||
// decides whether a drag moves the window.
|
||||
ui.allocate_response(ui.available_size(), Sense::hover());
|
||||
});
|
||||
},
|
||||
state,
|
||||
);
|
||||
// Let the window settle (auto-position / size, then idle).
|
||||
harness.run_steps(4);
|
||||
harness
|
||||
}
|
||||
|
||||
fn window_rect(harness: &Harness<'_, State>) -> egui::Rect {
|
||||
egui::AreaState::load(&harness.ctx, Id::new("test_win"))
|
||||
.expect("window area should be persisted after the first frame")
|
||||
.rect()
|
||||
}
|
||||
|
||||
/// Drag the pointer from `from` to `to` over multiple frames; release at the end.
|
||||
fn drag(harness: &mut Harness<'_, State>, from: Pos2, to: Pos2) {
|
||||
harness.drag_at(from);
|
||||
harness.run_steps(4);
|
||||
harness.hover_at(to);
|
||||
harness.run_steps(4);
|
||||
harness.drop_at(to);
|
||||
harness.run_steps(4);
|
||||
}
|
||||
|
||||
fn titlebar_pos(rect: egui::Rect) -> Pos2 {
|
||||
// Just inside the title bar:
|
||||
Pos2::new(rect.center().x, rect.top() + 8.0)
|
||||
}
|
||||
|
||||
fn body_pos(rect: egui::Rect) -> Pos2 {
|
||||
// Well below the title bar:
|
||||
Pos2::new(rect.center().x, rect.bottom() - 30.0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn title_bar_drag_on_titlebar_moves_window() {
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::TitleBar,
|
||||
movable: true,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = titlebar_pos(before);
|
||||
let to = from + Vec2::new(60.0, 40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
20.0 < moved.x && 20.0 < moved.y,
|
||||
"TitleBar + drag on titlebar should move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn title_bar_drag_outside_titlebar_keeps_window_put() {
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::TitleBar,
|
||||
movable: true,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = body_pos(before);
|
||||
let to = from + Vec2::new(60.0, -40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
moved.length() < 1.0,
|
||||
"TitleBar + drag in the body should NOT move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anywhere_drag_in_body_moves_window() {
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::Anywhere,
|
||||
movable: true,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = body_pos(before);
|
||||
let to = from + Vec2::new(60.0, -40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
20.0 < moved.x && moved.y < -20.0,
|
||||
"Anywhere + drag anywhere should move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn movable_false_keeps_window_put_even_on_titlebar() {
|
||||
// Regression: a `movable(false)` window used to still move when the user
|
||||
// dragged the title bar in `TitleBar` mode.
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::TitleBar,
|
||||
movable: false,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = titlebar_pos(before);
|
||||
let to = from + Vec2::new(60.0, 40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
moved.length() < 1.0,
|
||||
"TitleBar + movable(false) should NOT move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn off_keeps_window_put_on_body_drag() {
|
||||
// `WindowDrag::Off` should freeze the window regardless of `movable`.
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::Off,
|
||||
movable: true,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = body_pos(before);
|
||||
let to = from + Vec2::new(60.0, -40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
moved.length() < 1.0,
|
||||
"Off + drag in the body should NOT move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn off_keeps_window_put_on_titlebar_drag() {
|
||||
let mut harness = build(State {
|
||||
drag_area: WindowDrag::Off,
|
||||
movable: true,
|
||||
});
|
||||
|
||||
let before = window_rect(&harness);
|
||||
let from = titlebar_pos(before);
|
||||
let to = from + Vec2::new(60.0, 40.0);
|
||||
|
||||
drag(&mut harness, from, to);
|
||||
|
||||
let after = window_rect(&harness);
|
||||
let moved = after.min - before.min;
|
||||
assert!(
|
||||
moved.length() < 1.0,
|
||||
"Off + drag on titlebar should NOT move the window (delta = {moved:?})"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user