# Step 1 — GUI Skeleton ## What Was Built The main window layout for the LIN Master Simulator using PyQt6 (Python). ## Architecture ``` MainWindow (QMainWindow) ├── Menu Bar │ ├── File → Load LDF... (Ctrl+O), Exit (Ctrl+Q) │ └── View → Toggle Connection panel ├── LDF Toolbar (top, fixed) │ ├── LDF File path (read-only QLineEdit) │ ├── Browse button → opens file dialog │ └── Auto-reload checkbox (default: on) ├── Central Widget │ └── QSplitter (vertical, resizable) │ ├── Tx Panel (QGroupBox) │ │ └── QTableWidget: Frame Name | Frame ID | Length | Interval (ms) | Data | Signals | Action │ └── Rx Panel (QGroupBox) │ └── QTableWidget: Timestamp | Frame Name | Frame ID | Data | Signals ├── Connection Dock (QDockWidget, left side, detachable) │ ├── Device dropdown + Refresh button │ ├── Baud Rate label (read-only, auto-detected from LDF's LIN_speed field) │ ├── Connect / Disconnect buttons │ ├── Status label (red "Disconnected") │ └── Device info label ├── Control Bar (bottom toolbar, fixed) │ ├── Schedule table dropdown │ ├── Global Rate (ms) spinbox (1-10000ms, default 50ms) │ ├── Start / Stop / Pause buttons (disabled) │ └── Send Selected Frame button (disabled) └── Status Bar ├── Temporary messages (left) └── Connection indicator (right, permanent) ``` ## Send Rate Hierarchy When the scheduler runs, each frame's send interval is determined by priority: 1. **Per-frame interval** (Tx table "Interval (ms)" column) — highest priority, user override 2. **Global send rate** (Control bar spinbox) — default fallback for frames with no per-frame interval 3. **LDF schedule table** — auto-fills per-frame intervals when LDF is loaded ## Key Concepts Introduced ### PyQt6 Widget Tree Every visible element is a QWidget. Widgets contain other widgets via layouts. The root widget is QMainWindow which provides menu, toolbars, dock areas, and status bar for free. ### Layouts - **QVBoxLayout**: stacks widgets vertically - **QHBoxLayout**: stacks widgets horizontally - **QSplitter**: like a layout but with a draggable divider ### Signals & Slots Qt's event system. A signal (e.g., `button.clicked`) connects to a slot (any Python function). Example: `self.btn_browse_ldf.clicked.connect(self._on_load_ldf)` ### QDockWidget A panel that can be dragged to any window edge, floated, or hidden. Used for the Connection panel so users can maximize table space during monitoring. ### Initial Widget States Controls that require prerequisites (LDF loaded, device connected) start **disabled**. This prevents users from triggering actions that would fail. We enable them as preconditions are met. ## Files | File | Purpose | |------|---------| | `python/src/main.py` | Application entry point — creates QApplication, shows MainWindow | | `python/src/main_window.py` | MainWindow class — all panel creation and layout | | `python/tests/test_main_window.py` | 26 tests verifying widget tree structure and initial states | ## Running ```bash # Launch the GUI cd python/src && python main.py # Run tests cd python && python -m pytest tests/test_main_window.py -v ``` ## Test Results - 32 tests, all passing - Tests cover: window properties, menu bar, toolbar, Tx/Rx tables (incl. Interval column), connection dock (incl. baud rate label), control bar (incl. global rate), status bar