Implemented qt port + e2e

This commit is contained in:
Martino Ferrari
2026-06-26 09:11:10 +02:00
parent 0d7d8f396b
commit 4702d0a217
146 changed files with 57272 additions and 128 deletions
+63
View File
@@ -498,6 +498,69 @@ cmake --build build -j$(nproc)
---
## 7b. Qt Desktop Client
`Client/streamhub-qt/` is a **native Qt Widgets desktop oscilloscope** — a
feature/UX-equivalent alternative to the ImGui client, speaking the identical
StreamHub WebSocket protocol. It targets deployments that prefer a system Qt
runtime over bundled ImGui/SDL2/OpenGL, and it builds against either Qt6
(preferred) or Qt5 for old-Linux back-compatibility.
### Technology Stack
| Component | Library | Notes |
|-----------|---------|-------|
| UI framework | Qt Widgets | Autodetect Qt6 → Qt5 via `find_package(QT NAMES Qt6 Qt5 ...)`, then `Qt${QT_VERSION_MAJOR}::` targets |
| Time-series plots | Custom `QPainter` (`PlotWidget`) | No QtCharts/QCustomPlot — for ImPlot parity, zero extra deps, EUPL-clean |
| WebSocket client | `QtWebSockets` `QWebSocket` (`WsClient`) | Signals delivered on the GUI thread |
| Wire layer | Reused verbatim from `../streamhub/` | `Protocol.{h,cpp}`, `SignalBuffer.h` (framework-free C++17) |
### Threading & keyword model
- **Single GUI thread.** `QWebSocket` text/binary signals arrive on the GUI
thread, so no locks are needed (unlike the ImGui client's background receive
thread + drain). A 60 Hz `QTimer` (16 ms) drives repaint and panel refresh.
- **`QT_NO_KEYWORDS`.** The reused `Protocol.h`/`Model.h` structs have members
named `signals` (e.g. `ZoomResponse::signals`), which collide with Qt's
`signals`/`slots`/`emit` macros. The build defines `QT_NO_KEYWORDS`; all Qt
classes here use `Q_SIGNALS:` / `Q_SLOTS:` / `Q_EMIT` instead. This keeps the
shared wire layer unmodified.
### Components
| File | Responsibility |
|------|----------------|
| `Hub.{h,cpp}` | Domain model + command builders; owns `WsClient`; re-emits parsed events as Qt signals |
| `WsClient.{h,cpp}` | `QWebSocket` wrapper; auto-reconnect (3 s timer) |
| `PlotWidget.{h,cpp}` | One QPainter plot; live/stored/trigger modes, cursors, zoom cache |
| `PlotGrid.{h,cpp}` | Persistent pool of 8 `PlotWidget`s mounted into nested `QSplitter`s per layout |
| `SourceSidebar.{h,cpp}` | `QTreeWidget` of sources/signals; drag source = mime `application/x-shq-signal` carrying `qint32[2]` {srcIdx, sigIdx} (LittleEndian) |
| `TriggerBar.{h,cpp}` | Trigger config/arm controls + state badge |
| `StatsDialog.{h,cpp}` | Per-source stats table + 20-bin QPainter histogram |
| `HistoryBar.{h,cpp}` | Live / pan / jump-ago / show-all history navigation |
| `MainWindow.{h,cpp}` | Toolbars, docks, layout menu, connection controls, 60 Hz tick |
### Build & run
```bash
cd Client/streamhub-qt
cmake -B build # autodetects Qt6, falls back to Qt5
cmake --build build -j$(nproc)
# Produces: build/StreamHubQtClient
# Run (StreamHub must already be running on port 8090)
./build/StreamHubQtClient --host 127.0.0.1 --port 8090
```
> Use long `--host`/`--port` (or short `-H`/`-p`). A single-dash `-host` is
> misparsed by `QCommandLineParser` as clustered short flags.
Verified: builds and links cleanly against both Qt6 (6.11) and Qt5 (5.15); the
Qt6 binary connects to a live StreamHub (server logs *"WebSocket client
connected"*) and runs without error.
---
## 8. Go Client Packages
### `Common/Client/go/udpsprotocol`