test(ui): verify floating frame compatibility and resize constraints

This commit is contained in:
KotovGGG
2026-11-01 12:39:28 +03:00
parent 3685bae898
commit 71e5ecf285
3 changed files with 103 additions and 0 deletions
+13
View File
@@ -34,6 +34,19 @@ only. `FloatingFrame::resize_axes` defaults to both axes and preserves an enable
axis at corners when the other is disabled. A host with its own title bar can
disable the separate top gutter through `reserve_top_resize_band(false)`.
Compatibility and target-size audit: before these hooks, resizable frames already
reserved a 4 pt top band. That remains the default; `false` is the new host opt-out.
The unchanged stock edge hit bands are 4 pt thick; corners are at most 12 pt.
They do **not** meet a 24-by-24 logical-pixel target at 1x. This PR preserves
those hit rectangles and does not claim accessibility compliance. Focused
resize handles also support arrow keys (8 pt steps). Enlarging pointer targets
needs separate overlap, title-bar and viewport-edge acceptance checks.
`chrome::compatibility_tests::defaults_preserve_pre_host_hook_frame_geometry`
locks down the pre-hook hit rectangles/defaults. `host_hooks_tests` exercises all
four axis settings with actual corner and side pointer drags, minimum/maximum
sizes, the viewport edge, and top-gutter opt-out geometry.
Exhaustive `DockStyle` struct literals need `dock_gap: None`; constructors such
as `from_ui` and `from_visuals` supply the compatible default.
+30
View File
@@ -520,3 +520,33 @@ pub fn live_move(ctx: &Context, bar: &Response, rect: Rect, bounds: Rect) -> Opt
forget();
None
}
#[cfg(test)]
mod compatibility_tests {
use super::*;
#[test]
fn defaults_preserve_pre_host_hook_frame_geometry() {
let rect = Rect::from_min_size(pos2(100.0, 100.0), vec2(300.0, 200.0));
let frame = FloatingFrame::new(Id::unique("defaults"), rect);
assert_eq!(frame.resize_axes, [true, true]);
assert!(frame.reserve_top_resize_band);
assert!(frame.resizable);
// Literal pre-PR hit rectangles: preserve these rather than silently enlarging them.
let expected = [
[388.0, 288.0, 400.0, 300.0],
[100.0, 112.0, 104.0, 288.0],
[396.0, 112.0, 400.0, 288.0],
[112.0, 296.0, 388.0, 300.0],
[100.0, 288.0, 112.0, 300.0],
[112.0, 100.0, 388.0, 104.0],
[100.0, 100.0, 112.0, 104.0],
[388.0, 100.0, 400.0, 104.0],
];
for ((_, hit, _), [x0, y0, x1, y1]) in handles(rect).into_iter().zip(expected) {
assert_eq!(hit, Rect::from_min_max(pos2(x0, y0), pos2(x1, y1)));
// Audit result: legacy targets do NOT meet a 24-by-24 logical-pixel target.
assert!(hit.width() < 24.0 || hit.height() < 24.0);
}
}
}
+60
View File
@@ -363,3 +363,63 @@ fn owned_minimized_groups_skip_the_trailing_stock_target() {
assert_eq!(group_drop, !owned, "owned={owned}: {:?}", out.actions);
}
}
#[test]
fn disabled_edge_axes_ignore_pointer_drags_and_enabled_edges_obey_limits() {
for axes in [[true, true], [true, false], [false, true], [false, false]] {
for horizontal in [true, false] {
for grow in [true, false] {
let ctx = Context::default();
let rect = Rect::from_min_size(pos2(400.0, 300.0), vec2(300.0, 200.0));
let bounds = Rect::from_min_max(pos2(0.0, 0.0), pos2(720.0, 520.0));
let frame = |events| {
let mut resized = None;
ctx.run_ui(input(events), |ui| {
let style = chrome::ChromeStyle::from_ui(ui);
resized = chrome::FloatingFrame::new(Id::unique("edge-axis"), rect)
.resize_axes(axes)
.bounds(bounds)
.limits(PanelLimits { min: vec2(160.0, 120.0), max: vec2(310.0, 210.0) })
.show(ui.ctx(), &style, |_, _| ())
.resized;
})
.drop_without_applying_deltas();
resized
};
frame(vec![]);
frame(vec![]);
let from = if horizontal { pos2(rect.right() - 2.0, rect.center().y) } else { pos2(rect.center().x, rect.bottom() - 2.0) };
frame(vec![Event::PointerMoved(from), button(from, true)]);
let delta = if horizontal { vec2(10.0, 0.0) } else { vec2(0.0, 10.0) };
frame(vec![Event::PointerMoved(from + delta)]);
let result = frame(vec![Event::PointerMoved(from + delta * if grow { 100.0 } else { -100.0 })]);
let enabled = if horizontal { axes[0] } else { axes[1] };
let expected = if horizontal { vec2(if grow { 310.0 } else { 160.0 }, 200.0) } else { vec2(300.0, if grow { 210.0 } else { 120.0 }) };
assert_eq!(result, enabled.then(|| Rect::from_min_size(rect.min, expected)), "{axes:?} horizontal={horizontal} grow={grow}");
}
}
}
}
#[test]
fn frame_at_viewport_edge_cannot_resize_beyond_it() {
let ctx = Context::default();
let rect = Rect::from_min_max(pos2(400.0, 300.0), pos2(800.0, 600.0));
let frame = |events| {
let mut result = None;
ctx.run_ui(input(events), |ui| {
let style = chrome::ChromeStyle::from_ui(ui);
let response = chrome::FloatingFrame::new(Id::unique("viewport-edge"), rect).show(ui.ctx(), &style, |_, _| ());
assert_eq!(response.rect, rect);
result = response.resized;
})
.drop_without_applying_deltas();
result
};
frame(vec![]);
frame(vec![]);
let from = rect.max - vec2(2.0, 2.0);
frame(vec![Event::PointerMoved(from), button(from, true)]);
frame(vec![Event::PointerMoved(from + vec2(10.0, 10.0))]);
assert_eq!(frame(vec![Event::PointerMoved(from + vec2(100.0, 100.0))]), None);
}