fix(engine): resize pile-marker outline and watermark children on relayout #131
@@ -362,7 +362,15 @@ fn on_window_resized(
|
||||
(&mut Sprite, &mut Transform),
|
||||
(With<TableBackground>, Without<PileMarker>),
|
||||
>,
|
||||
mut markers: Query<(&PileMarker, &mut Sprite, &mut Transform), Without<TableBackground>>,
|
||||
mut markers: Query<
|
||||
(&PileMarker, &mut Sprite, &mut Transform, Option<&Children>),
|
||||
Without<TableBackground>,
|
||||
>,
|
||||
mut marker_outlines: Query<
|
||||
&mut Sprite,
|
||||
(Without<PileMarker>, Without<TableBackground>, Without<Text2d>),
|
||||
>,
|
||||
mut marker_labels: Query<&mut TextFont, With<Text2d>>,
|
||||
) {
|
||||
let Some(ev) = events.read().last() else {
|
||||
return;
|
||||
@@ -373,6 +381,14 @@ fn on_window_resized(
|
||||
let safe_area_top = insets.top / scale;
|
||||
let safe_area_bottom = insets.bottom / scale;
|
||||
let hud_visible = hud_vis.as_deref().copied().unwrap_or_default() == HudVisibility::Visible;
|
||||
// Android surface sizes after fold/unfold are unreliable (winit does not
|
||||
// forward every content-rect change), so make each relayout observable
|
||||
// in logcat — this is the primary evidence channel for foldable bugs.
|
||||
#[cfg(target_os = "android")]
|
||||
info!(
|
||||
"layout: resize to {:.0}x{:.0} (insets top={:.0} bottom={:.0}, hud={hud_visible})",
|
||||
window_size.x, window_size.y, insets.top, insets.bottom
|
||||
);
|
||||
let mut new_layout = compute_layout(window_size, safe_area_top, safe_area_bottom, hud_visible);
|
||||
|
||||
// compute_layout sizes the fan for a worst-case column; refine it to the
|
||||
@@ -394,11 +410,27 @@ fn on_window_resized(
|
||||
transform.translation.y = 0.0;
|
||||
}
|
||||
|
||||
for (marker, mut sprite, mut transform) in &mut markers {
|
||||
for (marker, mut sprite, mut transform, children) in &mut markers {
|
||||
if let Some(pos) = new_layout.pile_positions.get(&marker.0) {
|
||||
sprite.custom_size = Some(new_layout.card_size);
|
||||
transform.translation.x = pos.x;
|
||||
transform.translation.y = pos.y;
|
||||
// Children carry the outline frame and the "A"/"K" watermark.
|
||||
// They are sized at spawn from that layout's card size, so they
|
||||
// must be re-derived here too or a resize (fold/unfold, rotation)
|
||||
// leaves them at the stale size — visible as oversized grey
|
||||
// frames on empty piles.
|
||||
let outline_size =
|
||||
new_layout.card_size + Vec2::splat(PILE_MARKER_OUTLINE_WIDTH * 2.0);
|
||||
let font_size = new_layout.card_size.x * 0.28;
|
||||
for child in children.into_iter().flatten() {
|
||||
if let Ok(mut outline) = marker_outlines.get_mut(*child) {
|
||||
outline.custom_size = Some(outline_size);
|
||||
}
|
||||
if let Ok(mut label) = marker_labels.get_mut(*child) {
|
||||
label.font_size = font_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,6 +655,58 @@ mod tests {
|
||||
assert_eq!(types.len(), 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resize_updates_marker_outline_and_watermark_children() {
|
||||
// Regression (found on Galaxy Fold 7, v0.41.0): `on_window_resized`
|
||||
// resized the marker fill sprite but never its children, so after a
|
||||
// fold/unfold the outline frame and "A"/"K" watermark stayed at
|
||||
// spawn-time size — rendering as oversized grey slabs on empty piles.
|
||||
let mut app = headless_app();
|
||||
// Shrink the window well below the 1280×800 spawn default.
|
||||
app.world_mut().write_message(WindowResized {
|
||||
window: Entity::PLACEHOLDER,
|
||||
width: 640.0,
|
||||
height: 480.0,
|
||||
});
|
||||
app.update();
|
||||
|
||||
let card_size = app.world().resource::<LayoutResource>().0.card_size;
|
||||
let expected_outline = card_size + Vec2::splat(PILE_MARKER_OUTLINE_WIDTH * 2.0);
|
||||
let expected_font = card_size.x * 0.28;
|
||||
|
||||
let marker_children: Vec<Entity> = {
|
||||
let mut q = app.world_mut().query::<(&PileMarker, &Children)>();
|
||||
q.iter(app.world())
|
||||
.flat_map(|(_, c)| c.iter().collect::<Vec<_>>())
|
||||
.collect()
|
||||
};
|
||||
assert!(
|
||||
!marker_children.is_empty(),
|
||||
"pile markers must have outline/watermark children"
|
||||
);
|
||||
let mut outlines = 0;
|
||||
let mut labels = 0;
|
||||
for child in marker_children {
|
||||
if let Some(sprite) = app.world().entity(child).get::<Sprite>() {
|
||||
assert_eq!(
|
||||
sprite.custom_size,
|
||||
Some(expected_outline),
|
||||
"outline child must track the resized card size",
|
||||
);
|
||||
outlines += 1;
|
||||
}
|
||||
if let Some(font) = app.world().entity(child).get::<TextFont>() {
|
||||
assert!(
|
||||
(font.font_size - expected_font).abs() < 0.01,
|
||||
"watermark font must track the resized card size",
|
||||
);
|
||||
labels += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(outlines, 12, "all 12 markers carry an outline child");
|
||||
assert!(labels >= 11, "tableau + foundation markers carry watermarks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pile_markers_hide_when_pile_is_occupied() {
|
||||
// After a fresh deal: the 7 tableau piles + the stock pile are
|
||||
|
||||
Reference in New Issue
Block a user