//! # GUI Components Module //! //! This module implements all the individual GUI components for the Intel MCS-4 emulator. //! Each component is responsible for rendering its specific section of the interface //! and handling user interactions within that section. //! //! ## Component Architecture //! //! The GUI is organized into several specialized components: //! //! - **`GuiComponents`**: Main container managing all components //! - **`ControlPanel`**: System control buttons and actions //! - **`MemoryViewer`**: RAM content display and inspection //! - **`RegisterViewer`**: CPU register state visualization //! - **`RomLoader`**: File dialog integration for ROM loading //! - **`StatusBar`**: System status and component health display //! //! ## Design Principles //! //! ### Separation of Concerns //! Each component handles only its specific functionality: //! - State management is centralized in `GuiState` //! - Components receive immutable references where possible //! - User interactions trigger state changes through controlled interfaces //! //! ### Performance Optimization //! - Components minimize allocations and cloning //! - State updates are batched and efficient //! - UI layout uses egui's immediate mode for optimal performance //! //! ### User Experience //! - Consistent visual design across all components //! - Clear visual feedback for user actions //! - Intuitive layout and component organization //! //! ## Component Communication //! //! Components communicate through the shared `GuiState`: //! - Read-only access to state for display components //! - Controlled mutation through specific methods //! - Thread-safe state sharing with the emulator system //! //! ## Error Handling //! //! Components handle errors gracefully: //! - Invalid states are displayed to users //! - Failed operations show clear error messages //! - Recovery options are provided where applicable use super::state::GuiState; use crate::system_config::{ConfigurableSystem, SystemController}; use crate::virtual_clock::SimulationMode; use eframe::egui; use parking_lot::Mutex; use std::sync::Arc; /// Container for all GUI components /// /// This structure manages the lifecycle and coordination of all GUI components. /// It acts as a facade, providing a clean interface for rendering different /// sections of the user interface while maintaining proper separation of concerns. /// /// ## Component Management /// /// The container is responsible for: /// - Component initialization and configuration /// - Render orchestration and layout management /// - State distribution to appropriate components /// - Component lifecycle and cleanup /// /// ## Performance Considerations /// /// - Components are created once and reused across frames /// - State references are passed efficiently without cloning /// - Layout is managed centrally for consistent spacing pub struct GuiComponents { /// System control and management interface control_panel: ControlPanel, /// Timing/speed/mode/step controls timing_controls: TimingControls, /// RAM content inspection and visualization memory_viewer: MemoryViewer, /// ROM content inspection and visualization rom_viewer: RomViewer, /// CPU register state display register_viewer: RegisterViewer, /// ROM file loading and management #[allow(dead_code)] // RomLoader is currently a placeholder implementation rom_loader: RomLoader, /// System status and health monitoring status_bar: StatusBar, } impl GuiComponents { /// Create a new GUI components container with all components initialized /// /// This constructor sets up all GUI components with their default configurations. /// Components are ready to use immediately after creation. /// /// # Returns /// A fully initialized `GuiComponents` instance /// /// # Example /// ```rust,no_run /// use rusty_emu::gui::components::GuiComponents; /// /// let mut components = GuiComponents::new(); /// // Components are ready to render /// ``` pub fn new() -> Self { Self { control_panel: ControlPanel::new(), timing_controls: TimingControls::new(), memory_viewer: MemoryViewer::new(), rom_viewer: RomViewer::new(), register_viewer: RegisterViewer::new(), rom_loader: RomLoader::new(), status_bar: StatusBar::new(), } } /// Render the control panel component /// /// The control panel provides system management functionality including /// start/stop/reset controls and ROM loading capabilities. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state for control operations /// * `system` - Optional reference to the emulator system for actual control pub fn render_control_panel( &mut self, ui: &mut egui::Ui, state: &mut GuiState, system: Option<&Arc>>, ) { self.control_panel.render(ui, state, system); } /// Render the timing controls component /// /// Displays simulation speed, mode, step controls, and virtual time. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state for display and interaction /// * `system` - Optional reference to the emulator system for clock control pub fn render_timing_controls( &mut self, ui: &mut egui::Ui, state: &mut GuiState, system: Option<&Arc>>, ) { self.timing_controls.render(ui, state, system); } /// Render the memory viewer component /// /// Displays RAM contents in a tabular format with bank selection /// and hex/decimal viewing options. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state for display and interaction pub fn render_memory_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) { self.memory_viewer.render(ui, state); } /// Render the ROM viewer component /// /// Displays ROM contents in a tabular format with address selection /// and hex/decimal viewing options. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state for display and interaction pub fn render_rom_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) { self.rom_viewer.render(ui, state); } /// Render the register viewer component /// /// Shows CPU register state including accumulator, program counter, /// index registers, and system flags. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state for display and interaction pub fn render_register_viewer(&self, ui: &mut egui::Ui, state: &mut GuiState) { self.register_viewer.render(ui, state); } /// Render the status bar component /// /// Displays system health, component status, cycle counts, /// and any error conditions. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Immutable reference to GUI state for display pub fn render_status_bar(&self, ui: &mut egui::Ui, state: &GuiState) { self.status_bar.render(ui, state); } } /// Control panel component for system control buttons and operations /// /// The control panel provides the primary interface for managing the emulator system. /// It offers intuitive controls for starting, stopping, and resetting the emulation, /// along with system configuration and file management capabilities. /// /// ## Features /// /// - **System Lifecycle Management**: Start, stop, and reset emulator execution /// - **Visual State Feedback**: Dynamic button states reflecting current system status /// - **Error Handling**: Clear error display and recovery mechanisms /// - **Application Control**: Window management and application termination /// /// ## Button States /// /// The control panel adapts its interface based on system state: /// - **Stopped**: Shows "Start System" button, disabled stop/reset buttons /// - **Running**: Shows "System Running..." text, enabled stop/reset buttons /// - **Error**: Displays error messages with option to clear them pub struct ControlPanel { /// Dynamic text for the start/stop button based on system state start_button_text: String, /// Whether the stop button should be enabled stop_button_enabled: bool, /// Whether the reset button should be enabled reset_button_enabled: bool, } impl ControlPanel { /// Create a new control panel with default state /// /// Initializes the control panel in the "stopped" state with appropriate /// button configurations for a system that's ready to start. /// /// # Returns /// A new `ControlPanel` instance ready for system control pub fn new() -> Self { Self { start_button_text: "Start System".to_string(), stop_button_enabled: false, reset_button_enabled: false, } } /// Render the control panel interface /// /// Creates a horizontal layout with all control buttons and handles /// user interactions. The interface adapts dynamically based on system state. /// /// # Arguments /// * `ui` - egui UI context for rendering and interaction /// * `state` - Mutable reference to GUI state for system control /// /// # Layout /// ```text /// ┌─────────────────────────────────────────────────┐ /// │ System Control ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ │ /// │ [Load ROM] [Start System] [Stop] [Reset] [Close] │ /// └─────────────────────────────────────────────────┘ /// ``` pub fn render( &mut self, ui: &mut egui::Ui, state: &mut GuiState, system: Option<&Arc>>, ) { ui.horizontal(|ui| { // Section header ui.heading("System Control"); // ROM loading button if ui.button("Load ROM").clicked() { // ROM loading will be handled by RomLoader component state.set_error("ROM loader not yet implemented".to_string()); } // Start/Stop system button (context-sensitive) if ui.button(&self.start_button_text).clicked() { if !state.system_running { self.start_system(state, system); } } // Stop system button (only enabled when running) if ui.button("Stop System").clicked() && state.system_running { self.stop_system(state, system); } // Reset system button if ui.button("Reset System").clicked() { self.reset_system(state, system); } // Application close button if ui.button("Close").clicked() { // Stop the system before closing if available if let Some(sys) = system { let mut sys_guard = sys.lock(); // Use the SystemController trait method explicitly let _ = SystemController::stop(&mut *sys_guard); } // Close application - handled by eframe ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); } }); ui.separator(); } /// Start the emulator system /// /// Transitions the system from stopped to running state and updates /// all related UI elements to reflect the new state. /// /// # Arguments /// * `state` - Mutable reference to GUI state /// * `system` - Optional reference to the emulator system fn start_system( &mut self, state: &mut GuiState, system: Option<&Arc>>, ) { // Actually start the system if available if let Some(sys) = system { let mut sys_guard = sys.lock(); // Use the SystemController trait method explicitly let result = SystemController::start(&mut *sys_guard); match result { Ok(()) => { state.system_running = true; self.start_button_text = "System Running...".to_string(); self.stop_button_enabled = true; self.reset_button_enabled = true; state.clear_error(); } Err(e) => { state.set_error(format!("Failed to start system: {}", e)); } } } else { // No system available - just update UI state state.system_running = true; self.start_button_text = "System Running...".to_string(); self.stop_button_enabled = true; self.reset_button_enabled = true; state.clear_error(); } } /// Stop the emulator system /// /// Transitions the system from running to stopped state and updates /// UI elements accordingly. /// /// # Arguments /// * `state` - Mutable reference to GUI state /// * `system` - Optional reference to the emulator system fn stop_system( &mut self, state: &mut GuiState, system: Option<&Arc>>, ) { // Actually stop the system if available if let Some(sys) = system { let mut sys_guard = sys.lock(); // Use the SystemController trait method explicitly let result = SystemController::stop(&mut *sys_guard); match result { Ok(()) => { state.system_running = false; self.start_button_text = "Start System".to_string(); self.stop_button_enabled = false; state.clear_error(); } Err(e) => { state.set_error(format!("Failed to stop system: {}", e)); } } } else { // No system available - just update UI state state.system_running = false; self.start_button_text = "Start System".to_string(); self.stop_button_enabled = false; state.clear_error(); } } /// Reset the emulator system /// /// Performs a complete system reset, stopping execution and clearing /// all state including cycle counts and error conditions. /// /// # Arguments /// * `state` - Mutable reference to GUI state /// * `system` - Optional reference to the emulator system fn reset_system( &mut self, state: &mut GuiState, system: Option<&Arc>>, ) { // Stop the system first if available if let Some(sys) = system { let mut sys_guard = sys.lock(); // Use the SystemController trait method explicitly let _ = SystemController::stop(&mut *sys_guard); } // Reset UI state state.system_running = false; state.cycle_count = 0; self.start_button_text = "Start System".to_string(); self.stop_button_enabled = false; self.reset_button_enabled = false; state.clear_error(); } } /// Timing controls component for simulation speed, mode, and step management. /// /// This component provides controls for the virtual clock system: /// - **Speed slider**: Logarithmic scale from 0.001× to 100× /// - **Mode selector**: RealTime / MaxSpeed / SingleStep radio buttons /// - **Step button**: Advance one tick in SingleStep mode /// - **Virtual time display**: Current time, tick count, actual vs target speed /// /// ## Logarithmic Slider Mapping /// /// The slider position `t` (0.0 to 1.0) maps to speed via: /// `speed = 10^(t * 5 - 3)` giving range [0.001, 100.0] pub struct TimingControls { /// Current slider position (0.0 to 1.0), mapped logarithmically to speed speed_slider_pos: f32, } impl TimingControls { /// Create a new timing controls component pub fn new() -> Self { // Default: 1.0x speed → log10(1.0) = 0, so t = (0 + 3) / 5 = 0.6 Self { speed_slider_pos: 0.6, } } /// Convert slider position (0..1) to speed multiplier using logarithmic scale. /// /// Range: 0.001× (position 0.0) to 100.0× (position 1.0) /// Formula: speed = 10^(pos * 5 - 3) fn pos_to_speed(pos: f32) -> f64 { let pos = pos.clamp(0.0, 1.0) as f64; 10f64.powf(pos * 5.0 - 3.0) } /// Convert speed multiplier to slider position (0..1) using logarithmic scale. /// /// Formula: pos = (log10(speed) + 3) / 5 fn speed_to_pos(speed: f64) -> f32 { if speed <= 0.0 { return 0.0; } let pos = (speed.log10() + 3.0) / 5.0; pos.clamp(0.0, 1.0) as f32 } /// Render the timing controls interface. /// /// # Layout /// ```text /// ┌──────────────────────────────────────────────────────────────────┐ /// │ Timing Controls │ /// │ Speed: [========●===========] 1.00× (actual: 0.98×) │ /// │ Mode: (●) RealTime ( ) MaxSpeed ( ) SingleStep [Step] │ /// │ Virtual Time: 1.23 ms | Ticks: 3,690 | Paused: No │ /// └──────────────────────────────────────────────────────────────────┘ /// ``` pub fn render( &mut self, ui: &mut egui::Ui, state: &mut GuiState, system: Option<&Arc>>, ) { // Sync slider position from actual clock speed so external changes // (e.g., console "speed 0.1" command) are reflected in the GUI. self.speed_slider_pos = Self::speed_to_pos(state.timing_state.target_speed); ui.vertical(|ui| { ui.heading("Timing Controls"); // Speed slider row ui.horizontal(|ui| { ui.label("Speed:"); let slider = egui::Slider::new(&mut self.speed_slider_pos, 0.0..=1.0) .show_value(false) .step_by(0.001); let response = ui.add(slider); if response.changed() { let new_speed = Self::pos_to_speed(self.speed_slider_pos); if let Some(sys) = system { let sys_guard = sys.lock(); let clock = sys_guard.get_virtual_clock(); clock.set_speed_multiplier(new_speed); // If in MaxSpeed mode, switch back to RealTime when slider moves if clock.mode() == SimulationMode::MaxSpeed { clock.set_mode(SimulationMode::RealTime); } } } // Show current target speed let speed_text = state.timing_state.format_speed(); ui.label(format!("Target: {}", speed_text)); // Show actual speed let actual_text = state.timing_state.format_actual_speed(); ui.label(format!("Actual: {}", actual_text)); }); // Mode selector and step button row ui.horizontal(|ui| { ui.label("Mode:"); let current_mode = state.timing_state.mode.as_str(); let is_realtime = current_mode == "RealTime"; let is_maxspeed = current_mode == "MaxSpeed"; let is_singlestep = current_mode == "SingleStep"; // RealTime radio if ui.radio(is_realtime, "RealTime").clicked() { self.apply_mode(system, SimulationMode::RealTime); } // MaxSpeed radio if ui.radio(is_maxspeed, "MaxSpeed").clicked() { self.apply_mode(system, SimulationMode::MaxSpeed); } // SingleStep radio if ui.radio(is_singlestep, "SingleStep").clicked() { self.apply_mode(system, SimulationMode::SingleStep); } ui.separator(); // Step button (enabled only in SingleStep mode) let step_pending = state.timing_state.step_pending; let step_button = ui.add_enabled( is_singlestep && !step_pending, egui::Button::new("Step"), ); if step_button.clicked() { if let Some(sys) = system { let sys_guard = sys.lock(); let clock = sys_guard.get_virtual_clock(); clock.trigger_step(); } } if is_singlestep && step_pending { ui.colored_label(egui::Color32::YELLOW, "⏳ Step pending..."); } }); // Virtual time display row ui.horizontal(|ui| { ui.label("Virtual Time:"); ui.strong(state.timing_state.format_virtual_time()); ui.separator(); ui.label("Ticks:"); ui.strong(format!("{}", state.timing_state.tick_count)); ui.separator(); // Paused indicator if state.timing_state.paused { ui.colored_label(egui::Color32::YELLOW, "⏸ Paused"); } else if state.system_running { ui.colored_label(egui::Color32::GREEN, "▶ Running"); } else { ui.colored_label(egui::Color32::RED, "⏹ Stopped"); } }); }); ui.separator(); } /// Apply a simulation mode change to the virtual clock. fn apply_mode( &mut self, system: Option<&Arc>>, mode: SimulationMode, ) { if let Some(sys) = system { let sys_guard = sys.lock(); let clock = sys_guard.get_virtual_clock(); clock.set_mode(mode); } } } /// Memory viewer component for displaying RAM contents and state /// /// The memory viewer provides comprehensive RAM inspection capabilities, /// allowing users to examine memory contents across different banks with /// flexible display options and intuitive navigation. /// /// ## Features /// /// - **Multi-Bank Display**: View RAM contents across 4 banks simultaneously /// - **Flexible Formatting**: Toggle between hexadecimal and decimal display /// - **Interactive Bank Selection**: Choose which memory bank to inspect /// - **Scrollable Interface**: Navigate through memory contents efficiently /// - **Real-time Updates**: Live memory content updates during emulation /// /// ## Display Format /// /// The memory viewer shows data in a structured grid: /// - **Address Column**: Memory addresses in hexadecimal format /// - **Bank Columns**: B0-B3 showing contents of each memory bank /// - **Value Display**: Configurable hex or decimal representation /// /// ## Memory Organization /// /// The Intel 4002 RAM has the following structure: /// - **4 Banks**: Independent memory banks (B0-B3) /// - **4 Bytes per Bank**: Addresses 0x00-0x03 in each bank /// - **4-bit Values**: Each memory location stores a 4-bit nibble pub struct MemoryViewer { /// Number of bytes to display per row (currently fixed at 16) #[allow(dead_code)] // bytes_per_row is currently fixed at 16 but kept for future flexibility bytes_per_row: usize, } impl MemoryViewer { /// Create a new memory viewer with default configuration /// /// Initializes the viewer with standard layout optimized for the Intel 4002 RAM structure. /// /// # Returns /// A new `MemoryViewer` instance ready for RAM content display pub fn new() -> Self { Self { bytes_per_row: 16 } } /// Render the memory viewer interface /// /// Creates a comprehensive memory inspection interface with bank selection, /// display options, and a scrollable memory contents grid. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state containing memory data /// /// # Layout Structure /// ```text /// ┌─────────────────────────────────────────────────┐ /// │ Memory Viewer [─] [□] │ /// │ Bank: [0] □ Hex View │ /// ├─────────────────────────────────────────────────┤ /// │ Address B0 B1 B2 B3 │ /// │ [00] [12] [34] [56] [78] │ /// │ [01] [9A] [BC] [DE] [F0] │ /// │ [02] [11] [22] [33] [44] │ /// │ [03] [55] [66] [77] [88] │ /// └─────────────────────────────────────────────────┘ /// ``` pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) { ui.vertical(|ui| { // Section header ui.heading("Memory Viewer"); // Control bar with bank selection and display options ui.horizontal(|ui| { ui.label("Bank:"); // Bank selector (0-3 for Intel 4002) ui.add( egui::DragValue::new(&mut state.memory_state.selected_bank).clamp_range(0..=3), ); ui.checkbox(&mut state.memory_state.show_hex, "Hex View"); }); ui.separator(); // Memory contents in scrollable area egui::ScrollArea::vertical().show(ui, |ui| { egui::Grid::new("memory_grid").striped(true).show(ui, |ui| { // Header row with bank labels ui.label("Address"); for i in 0..4 { ui.label(format!("B{}", i)); } ui.end_row(); // Memory contents rows for addr in 0..4 { // Address column ui.label(format!("{:02X}", addr)); // Bank data columns for bank in 0..4 { let value = state.memory_state.ram_contents[bank][addr]; if state.memory_state.show_hex { ui.label(format!("{:02X}", value)); } else { ui.label(format!("{}", value)); } } ui.end_row(); } }); }); }); ui.separator(); } } /// Register viewer component for displaying CPU register state /// /// The register viewer provides comprehensive CPU state visualization, /// showing all key registers, flags, and pointers that define the current /// execution state of the Intel 4004 microprocessor. /// /// ## Features /// /// - **Complete Register Set**: Display all 16 index registers (R0-R15) /// - **Core CPU State**: Accumulator, program counter, stack pointer /// - **Flag Visualization**: Carry flag status with clear indicators /// - **Interactive Selection**: Choose which index register to highlight /// - **Dual Format Display**: Hexadecimal and decimal representations /// - **Real-time Updates**: Live register state during emulation /// /// ## Intel 4004 Register Architecture /// /// The Intel 4004 has the following register structure: /// - **Accumulator**: Main arithmetic register (4 bits) /// - **Index Registers**: 16 general-purpose registers (R0-R15) /// - **Program Counter**: 12-bit address pointer /// - **Stack Pointer**: 4-bit stack address register /// - **Carry Flag**: Arithmetic carry/borrow indicator /// /// ## Display Organization /// /// Registers are organized in a clear hierarchy: /// - **Primary Registers**: Most frequently used (accumulator, PC, stack) /// - **Flags**: System status indicators /// - **Index Registers**: General-purpose register file pub struct RegisterViewer { // No internal state - all UI state is stored in GuiState } impl RegisterViewer { /// Create a new register viewer with default configuration /// /// Initializes the viewer with standard display formatting optimized /// for the Intel 4004 architecture. /// /// # Returns /// A new `RegisterViewer` instance ready for CPU state display pub fn new() -> Self { Self {} } /// Render the register viewer interface /// /// Creates a comprehensive register inspection interface with organized /// display of all CPU state elements and interactive index register selection. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state containing register data /// /// # Layout Structure /// ```text /// ┌─────────────────────────────────────────────────┐ /// │ CPU Registers [─] [□] │ /// │ Index Register: [0] │ /// ├─────────────────────────────────────────────────┤ /// │ Register │ Value (Hex) │ Value (Dec) │ /// │ Accumulator │ 0F │ 15 │ /// │ Carry Flag │ 1 │ Set │ /// │ Program Counter│ 123 │ 291 │ /// │ Index R0 │ 2A │ 42 │ /// │ Stack Pointer │ 08 │ 8 │ /// └─────────────────────────────────────────────────┘ /// ``` pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) { ui.vertical(|ui| { // Section header ui.heading("CPU Registers"); // Index register selector ui.horizontal(|ui| { ui.label("Index Register:"); ui.add( egui::DragValue::new(&mut state.register_state.selected_register) .clamp_range(0..=15), ); }); ui.separator(); // Register display grid egui::Grid::new("register_grid") .striped(true) .show(ui, |ui| { // Header row ui.label("Register"); ui.label("Value (Hex)"); ui.label("Value (Dec)"); ui.end_row(); // Core CPU registers ui.label("Accumulator"); ui.label(format!("{:X}", state.register_state.accumulator)); ui.label(format!("{}", state.register_state.accumulator)); ui.end_row(); // System flags ui.label("Carry Flag"); ui.label(if state.register_state.carry_flag { "1" } else { "0" }); ui.label(if state.register_state.carry_flag { "Set" } else { "Clear" }); ui.end_row(); // Program execution state ui.label("Program Counter"); ui.label(format!("{:03X}", state.register_state.program_counter)); ui.label(format!("{}", state.register_state.program_counter)); ui.end_row(); // Selected index register (highlighted) let selected = state.register_state.selected_register; ui.label(format!("Index R{}", selected)); ui.label(format!( "{:X}", state.register_state.index_registers[selected] )); ui.label(format!( "{}", state.register_state.index_registers[selected] )); ui.end_row(); // Stack management ui.label("Stack Pointer"); ui.label(format!("{:X}", state.register_state.stack_pointer)); ui.label(format!("{}", state.register_state.stack_pointer)); ui.end_row(); }); }); ui.separator(); } } /// ROM viewer component for displaying ROM contents /// /// The ROM viewer provides comprehensive ROM inspection capabilities, /// allowing users to examine program memory contents with flexible /// display options and intuitive navigation. /// /// ## Features /// /// - **Program Memory Display**: View ROM contents from Intel 4001 chips /// - **Flexible Formatting**: Toggle between hexadecimal and decimal display /// - **Address Navigation**: Jump to specific memory addresses /// - **Scrollable Interface**: Navigate through memory contents efficiently /// - **Real-time Updates**: Live ROM content display /// /// ## Display Format /// /// The ROM viewer shows data in a structured grid: /// - **Address Column**: Memory addresses in hexadecimal format /// - **Data Columns**: 16 bytes per row for easy viewing /// - **Value Display**: Configurable hex or decimal representation /// /// ## Memory Organization /// /// The Intel 4001 ROM has the following structure: /// - **256 Bytes**: Total ROM capacity per chip /// - **8-bit Values**: Each memory location stores a full byte pub struct RomViewer { /// Number of bytes to display per row bytes_per_row: usize, } impl RomViewer { /// Create a new ROM viewer with default configuration /// /// Initializes the viewer with standard layout optimized for the Intel 4001 ROM structure. /// /// # Returns /// A new `RomViewer` instance ready for ROM content display pub fn new() -> Self { Self { bytes_per_row: 16 } } /// Render the ROM viewer interface /// /// Creates a comprehensive ROM inspection interface with address navigation, /// display options, and a scrollable memory contents grid. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Mutable reference to GUI state containing ROM data /// /// # Layout Structure /// ```text /// ┌─────────────────────────────────────────────────┐ /// │ ROM Viewer (Chip: ROM_4001_1) [─] [□] │ /// │ □ Hex View │ /// ├─────────────────────────────────────────────────┤ /// │ Address 00 01 02 03 04 05 06 07 08 09 0A 0B... │ /// │ 0x000 D4 C3 B2 A1 00 11 22 33 44 55 66 77... │ /// │ 0x010 88 99 AA BB CC DD EE FF 00 11 22 33... │ /// │ ... │ /// └─────────────────────────────────────────────────┘ /// ``` pub fn render(&self, ui: &mut egui::Ui, state: &mut GuiState) { ui.vertical(|ui| { // Section header with chip name let header = if state.rom_state.chip_name.is_empty() { "ROM Viewer".to_string() } else { format!("ROM Viewer ({})", state.rom_state.chip_name) }; ui.heading(header); // Control bar with display options ui.horizontal(|ui| { ui.checkbox(&mut state.rom_state.show_hex, "Hex View"); }); ui.separator(); // ROM contents in scrollable area egui::ScrollArea::vertical() .max_height(200.0) .show(ui, |ui| { egui::Grid::new("rom_grid").striped(true).show(ui, |ui| { // Header row with column labels ui.label("Addr"); for i in 0..self.bytes_per_row { ui.label(format!("{:02X}", i)); } ui.end_row(); // ROM contents rows let total_rows = (state.rom_state.rom_contents.len() + self.bytes_per_row - 1) / self.bytes_per_row; for row in 0..total_rows { let addr = row * self.bytes_per_row; // Address column ui.label(format!("{:03X}", addr)); // Data columns for col in 0..self.bytes_per_row { let idx = addr + col; if idx < state.rom_state.rom_contents.len() { let value = state.rom_state.rom_contents[idx]; if state.rom_state.show_hex { ui.label(format!("{:02X}", value)); } else { ui.label(format!("{:3}", value)); } } else { ui.label("--"); } } ui.end_row(); } }); }); }); ui.separator(); } } /// ROM loader component for file dialog integration and program management /// /// The ROM loader handles program file selection, loading, and management. /// It provides the interface for users to load Intel 4001 ROM files and /// binary programs into the emulator system. /// /// ## Features /// /// - **File Dialog Integration**: Native file browser for program selection /// - **Program Validation**: Basic file format and size validation /// - **Load Feedback**: Visual confirmation of successful loads /// - **Error Handling**: Clear error messages for failed operations /// - **Future Extensions**: Support for multiple ROM chips and formats /// /// ## Supported Formats /// /// - **Binary Files**: Raw binary program data (.bin) /// - **Intel 4001 Format**: MCS-4 ROM file format (planned) /// - **Configuration Files**: System configuration integration (planned) /// /// ## Integration Notes /// /// Currently shows placeholder for file dialog implementation. /// Production version should integrate with native file dialogs using: /// - **rfd** crate for cross-platform file dialogs /// - **async** operations for non-blocking file I/O /// - **Progress feedback** for large file operations pub struct RomLoader { /// Whether to show the file selection dialog show_file_dialog: bool, /// Currently selected file path (if any) selected_file: Option, } impl RomLoader { /// Create a new ROM loader with default state /// /// Initializes the loader with no file selected and dialog closed. /// Ready to handle user file selection requests. /// /// # Returns /// A new `RomLoader` instance ready for file operations pub fn new() -> Self { Self { show_file_dialog: false, selected_file: None, } } /// Render the ROM loader interface /// /// Creates the file management interface with load button and /// file selection dialog integration. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `_state` - GUI state (currently unused but reserved for future integration) /// /// # Layout Structure /// ```text /// ┌─────────────────────────────────────────────────┐ /// │ ROM Management [─] [□]│ /// │ [Load ROM File...] │ /// │ Selected: /path/to/program.bin │ /// │ │ /// │ [File Dialog Placeholder] │ /// └─────────────────────────────────────────────────┘ /// ``` pub fn render(&mut self, ui: &mut egui::Ui, _state: &mut GuiState) { ui.vertical(|ui| { ui.heading("ROM Management"); // Load button to trigger file selection if ui.button("Load ROM File...").clicked() { self.show_file_dialog = true; } // Display currently selected file if let Some(ref file) = self.selected_file { ui.label(format!("Selected: {}", file)); } // File dialog implementation (placeholder) if self.show_file_dialog { // Placeholder for file dialog ui.label("File dialog would open here"); if ui.button("Cancel").clicked() { self.show_file_dialog = false; } } }); ui.separator(); } } /// Status bar component for system status display and health monitoring /// /// The status bar provides comprehensive system health information, /// component status indicators, and real-time performance metrics. /// It serves as the primary location for system state overview. /// /// ## Features /// /// - **System Status**: Running/stopped state with visual indicators /// - **Performance Metrics**: Cycle count and execution speed /// - **Component Health**: Individual component status monitoring /// - **Error Display**: Real-time error message display /// - **System Information**: CPU speed, component count, and configuration /// /// ## Visual Design /// /// - **Color Coding**: Green for healthy, red for errors/stopped /// - **Layout Organization**: Status on left, errors on right /// - **Real-time Updates**: Live status changes during operation /// - **Compact Display**: Information-dense but readable layout /// /// ## Component Status Indicators /// /// Monitors the health of all major system components: /// - **CPU**: Intel 4004 execution status /// - **RAM**: Intel 4002 memory operations /// - **ROM**: Intel 4001 program storage /// - **CLK**: System clock generation pub struct StatusBar; impl StatusBar { /// Create a new status bar component /// /// Initializes a stateless status bar ready to display /// current system health and performance information. /// /// # Returns /// A new `StatusBar` instance pub fn new() -> Self { Self } /// Render the status bar interface /// /// Creates a comprehensive status display with system information, /// component health indicators, and error reporting. /// /// # Arguments /// * `ui` - egui UI context for rendering /// * `state` - Immutable reference to GUI state for status information /// /// # Layout Structure /// ```text /// ┌─────────────────────────────────────────────────────────────┐ /// │ Status: ● Running │ Cycles: 12345 │ CPU: 0.7 MHz │ /// │ Components: 4 │ CPU RAM ROM CLK │ Error: Connection │ /// └─────────────────────────────────────────────────────────────┘ /// ``` pub fn render(&self, ui: &mut egui::Ui, state: &GuiState) { ui.separator(); ui.horizontal(|ui| { // Left side: Status information and metrics ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| { // System running status ui.label("Status:"); if state.system_running { ui.colored_label(egui::Color32::GREEN, "● Running"); } else { ui.colored_label(egui::Color32::RED, "● Stopped"); } ui.separator(); // Performance metrics ui.label(format!("Cycles: {}", state.cycle_count)); ui.separator(); // System information if let Some(ref info) = state.system_info { ui.label(format!("CPU: {:.1} MHz", info.cpu_speed / 1_000_000.0)); ui.label(format!("Components: {}", info.component_count)); } ui.separator(); // Component status indicators ui.label("Components:"); ui.colored_label( if state.component_states.cpu_running { egui::Color32::GREEN } else { egui::Color32::RED }, "CPU", ); ui.colored_label( if state.component_states.ram_running { egui::Color32::GREEN } else { egui::Color32::RED }, "RAM", ); ui.colored_label( if state.component_states.rom_running { egui::Color32::GREEN } else { egui::Color32::RED }, "ROM", ); ui.colored_label( if state.component_states.clock_running { egui::Color32::GREEN } else { egui::Color32::RED }, "CLK", ); }); // Right side: Error messages ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { if let Some(ref error) = state.last_error { ui.colored_label(egui::Color32::RED, format!("Error: {}", error)); } }); }); } }