From b10e1a5a870c68376e8f36df9688df7c098f8c53 Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 29 Apr 2026 22:52:16 +0000 Subject: [PATCH] fix(engine): resize cards along with the rest of the layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first resize-jitter fix (366fd6d) only snapped card transforms, not the Sprite::custom_size. Cards stayed at the old size after a window resize until the next StateChangedEvent (move, draw, undo, new-game) refreshed them via sync_cards_on_change. Reported during smoke testing: "the placeholder grey boxes change size but the cards do not until I make an update to the window". Replace the manual transform-only loop in snap_cards_on_window_resize with a call to sync_cards(slide_secs = 0.0). update_card_entity unconditionally inserts a fresh Sprite via card_sprite() with the current layout.card_size, so cards now visibly resize. With slide_secs=0 it also takes the snap branch (no CardAnim slide), so the underlying jitter fix from 366fd6d is preserved. apply_stock_empty_indicator is still called separately because sync_cards doesn't touch the stock-empty "↺" label. Co-Authored-By: Claude Opus 4.7 (1M context) --- solitaire_engine/src/card_plugin.rs | 43 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/solitaire_engine/src/card_plugin.rs b/solitaire_engine/src/card_plugin.rs index ae65ad7..6acb39a 100644 --- a/solitaire_engine/src/card_plugin.rs +++ b/solitaire_engine/src/card_plugin.rs @@ -1116,7 +1116,8 @@ fn update_stock_empty_indicator( ); } -/// Snaps every card sprite to its target position when the window is resized. +/// Snaps every card sprite to its target position and size when the window +/// is resized. /// /// This replaces the old "fire `StateChangedEvent` from `on_window_resized`" /// path. That path went through `sync_cards_on_change` → `update_card_entity`, @@ -1125,10 +1126,11 @@ fn update_stock_empty_indicator( /// retargeted the tween from the card's mid-slide position, so cards never /// reached steady state — the visible "snap back and forth" jitter. /// -/// Cards now snap directly (no slide), matching the instant repositioning -/// already used for backgrounds and pile markers in -/// `table_plugin::on_window_resized`. Any in-flight `CardAnim` is removed so -/// it cannot keep writing the old target translation after the snap. +/// Calls `sync_cards` with `slide_secs = 0.0` so `update_card_entity` snaps +/// instantly (line `(cur - target).length() > 1.0 && slide_secs > 0.0` falls +/// to the snap branch), refreshes the `Sprite` with the new +/// `layout.card_size` (so cards visibly resize, not just reposition), and +/// removes any in-flight `CardAnim`. /// /// The "↺" stock-empty label's `font_size` is derived from /// `layout.card_size.x`, so this system also reapplies the stock indicator — @@ -1137,13 +1139,15 @@ fn update_stock_empty_indicator( /// /// Scheduled `.after(LayoutSystem::UpdateOnResize)` so `LayoutResource` has /// been refreshed by `table_plugin::on_window_resized` before this runs. -#[allow(clippy::type_complexity)] +#[allow(clippy::too_many_arguments)] fn snap_cards_on_window_resize( mut events: MessageReader, mut commands: Commands, game: Option>, layout: Option>, - mut entities: Query<(Entity, &CardEntity, &mut Transform)>, + settings: Option>, + card_images: Option>, + entities: Query<(Entity, &CardEntity, &Transform)>, mut pile_markers: Query<(Entity, &PileMarker, &mut Sprite)>, label_children: Query<(Entity, &ChildOf), With>, ) { @@ -1153,16 +1157,21 @@ fn snap_cards_on_window_resize( let Some(game) = game else { return }; let Some(layout) = layout else { return }; - let mut targets: HashMap = HashMap::new(); - for (card, pos, z) in card_positions(&game.0, &layout.0) { - targets.insert(card.id, (pos, z)); - } - for (entity, marker, mut transform) in &mut entities { - if let Some(&(pos, z)) = targets.get(&marker.card_id) { - transform.translation = Vec3::new(pos.x, pos.y, z); - commands.entity(entity).remove::(); - } - } + let selected_back = settings.as_ref().map_or(0, |s| s.0.selected_card_back); + let back_colour = card_back_colour(selected_back); + let color_blind = settings.as_ref().is_some_and(|s| s.0.color_blind_mode); + + sync_cards( + commands.reborrow(), + &game.0, + &layout.0, + 0.0, + back_colour, + color_blind, + &entities, + card_images.as_deref(), + selected_back, + ); apply_stock_empty_indicator( &mut commands,