# Phase 8: Speed/Step Controls for GUI and Console ## Overview Add simulation speed, mode, and step controls to both the egui-based GUI and the ratatui-based console interface. These controls leverage the existing `VirtualClock` and `RealTimeGovernor` APIs. ## Files to Modify 1. **`src/gui/state.rs`** — Add `TimingState` struct to `GuiState` for virtual time display data 2. **`src/gui/components.rs`** — Add `TimingControls` component (speed slider, mode selector, step button, time display) 3. **`src/gui/mod.rs`** — Integrate `TimingControls` into the main render loop 4. **`src/gui/console.rs`** — Add console commands: `speed`, `mode`, `step`, `time` ## Detailed Design ### 1. GUI State (`src/gui/state.rs`) Add a `TimingState` struct to `GuiState`: ```rust pub struct TimingState { /// Current virtual time in nanoseconds pub virtual_time_ns: u64, /// Total ticks elapsed pub tick_count: u64, /// Current speed multiplier (from VirtualClock) pub target_speed: f64, /// Actual measured speed (from RealTimeGovernor snapshots) pub actual_speed: f64, /// Current simulation mode: "RealTime", "MaxSpeed", "SingleStep" pub mode: String, /// Whether a step is pending (SingleStep mode) pub step_pending: bool, } ``` The `update_from_system()` method will be extended to: - Access `ConfigurableSystem::get_virtual_clock()` → `Arc` - Read `clock.now_ns()`, `clock.tick_count()`, `clock.speed_multiplier()`, `clock.mode()`, `clock.is_step_pending()` - Compute actual speed using `RealTimeGovernor::take_speed_snapshot()` / `compute_speed()` across frames To support speed snapshot computation across frames, `GuiState` will hold two `SpeedSnapshot` instances: ```rust pub speed_snap_prev: Option, pub speed_snap_curr: Option, ``` ### 2. TimingControls Component (`src/gui/components.rs`) New component `TimingControls` with: #### Speed Slider (Logarithmic Scale) - Slider range: logarithmic from 0.001× to 100.0× - Uses `egui::Slider` with custom logarithmic mapping - Position 0.0 → 0.001×, position 1.0 → 100.0× - Special "MaxSpeed" position at the far right - Calls `clock.set_speed_multiplier()` on change - Display: "Speed: 1.00× (actual: 0.98×)" #### Mode Selector - Three radio buttons: RealTime / MaxSpeed / SingleStep - Calls `clock.set_mode()` on selection change #### Step Controls - "Step" button, enabled only in SingleStep mode - Calls `clock.trigger_step()` on click - Shows "Step pending..." indicator when step is pending #### Virtual Time Display - Human-readable format: auto-selects µs, ms, or s - Shows tick count - Shows target vs actual speed ### 3. Integration (`src/gui/mod.rs`) Add `timing_controls: TimingControls` to `GuiComponents` and call `render_timing_controls()` between the control panel and memory sections. ### 4. Console Commands (`src/gui/console.rs`) New commands in `execute_command()`: | Command | Description | |---------|-------------| | `speed ` | Set speed multiplier (e.g., `speed 0.5`) | | `speed` | Show current speed | | `mode ` | Set simulation mode | | `mode` | Show current mode | | `step` | Trigger a single step (SingleStep mode) | | `time` | Show virtual time and tick count | Also add keyboard shortcuts: - `+`/`-` already exist for frequency; add new shortcuts for speed: - Keep existing `+`/`-` for frequency control (unchanged) ### Logarithmic Slider Mapping The slider position `t` (0.0 to 1.0) maps to speed multiplier via: ``` t=0.00 → 0.001× t=0.25 → 0.01× t=0.50 → 0.1× t=0.75 → 1.0× t=0.90 → 10.0× t=1.00 → 100.0× ``` Formula: `speed = 10^(t * 5 - 3)` gives range [0.001, 100.0] For MaxSpeed mode, we'll use a separate toggle rather than a slider position. ## Implementation Order 1. Add `TimingState` to `src/gui/state.rs` 2. Add `TimingControls` component to `src/gui/components.rs` 3. Integrate into `src/gui/mod.rs` 4. Add console commands to `src/gui/console.rs` 5. Build and test