diff --git a/solitaire_engine/src/game_plugin/mod.rs b/solitaire_engine/src/game_plugin/mod.rs index b9579db..9a46862 100644 --- a/solitaire_engine/src/game_plugin/mod.rs +++ b/solitaire_engine/src/game_plugin/mod.rs @@ -86,6 +86,14 @@ pub struct NewGameRequestWriters; #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] pub struct UndoRequestWriters; +/// Self-ambiguous set for writers of `DrawRequestEvent` — same rationale as +/// [`NewGameRequestWriters`]: consumers drain the queue, append order is +/// meaningless (#143). Members: keyboard `D`/`Space`, stock click, touch +/// stock tap (input_plugin), and the touch action bar's Draw button +/// (hud_plugin, Phase F). +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct DrawRequestWriters; + /// Self-ambiguous set for writers of `InfoToastEvent` — toasts queue in /// arrival order and any same-frame order is fine (#143). #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] diff --git a/solitaire_engine/src/hud_plugin/interaction.rs b/solitaire_engine/src/hud_plugin/interaction.rs index 128200c..e2cf890 100644 --- a/solitaire_engine/src/hud_plugin/interaction.rs +++ b/solitaire_engine/src/hud_plugin/interaction.rs @@ -30,6 +30,86 @@ pub(super) fn handle_undo_button( } } +/// Seconds the Undo button must be continuously held before hold-to-repeat +/// kicks in. Long enough that a normal tap (press + release inside one or +/// two frames) never triggers a second undo. +const UNDO_HOLD_INITIAL_DELAY_SECS: f32 = 0.45; + +/// Interval between repeated undos while the hold continues. ~5.5 undos/s — +/// fast enough to unwind a long line, slow enough to release in time when +/// the board reaches the state the player wants. +const UNDO_HOLD_REPEAT_INTERVAL_SECS: f32 = 0.18; + +/// Hold-to-repeat undo (Phase F): while the Undo button stays pressed, +/// fire additional [`UndoRequestEvent`]s after an initial delay, one per +/// repeat interval. The plain tap path stays in [`handle_undo_button`] +/// (its `Changed` filter fires exactly once per press); +/// this system only adds events once the hold outlives the delay, so a +/// tap never double-undoes. +/// +/// Each repeat goes through the normal request queue — the scoring +/// penalty and No-Undo-mode gating in the consumer apply to every step. +pub(super) fn repeat_undo_on_hold( + time: Res