/** * @file PlotWidget.h * @brief Oscilloscope plot panel (custom QPainter), one per grid cell. * * Mirrors the ImGui PlotPanel: fixed +/-4 division Y space, wall-clock live X * window, LTTB decimation, normal/digital/mixed normalization, A/B cursors, * scroll/drag zoom + pan, zoom history, hi-res WS zoom + history zoom, and a * trigger-capture view rendered in [-pre, +post]. */ #pragma once #include "Model.h" #include #include #include #include #include class QHBoxLayout; class QToolButton; class QLabel; namespace shq { class Hub; /** View state shared (synchronised) across all plots; owned by MainWindow. */ struct GlobalView { double windowSec = 10.0; /* live scroll window width */ bool paused = false; /* global pause */ bool cursorsOn = false; double cursorA = 0.0; double cursorB = 0.0; bool trigView = false; /* trigger bar open → render capture */ }; class PlotCanvas; class PlotWidget : public QWidget { Q_OBJECT public: PlotWidget(Hub* hub, GlobalView* gv, int plotIdx, QWidget* parent = nullptr); std::vector& slots() { return slots_; } void addAssignment(int sourceIdx, int signalIdx); /** Called by MainWindow when sources/config change so badges refresh. */ void onModelChanged(); /** Called by MainWindow when global pause toggles. */ void onPauseChanged(); /** Reset zoom/live state (e.g. when entering/leaving history mode). */ void setLive(bool live); bool isLive() const { return live_; } void setStoredX(double mn, double mx); double xMin() const { return plotXMin_; } double xMax() const { return plotXMax_; } int plotIdx() const { return plotIdx_; } public Q_SLOTS: void onZoomReceived(int plotIdx); void onHistoryZoomReceived(int plotIdx); void onCaptureReceived(); void tick(); /* ~60 Hz repaint + throttled zoom requests */ private: friend class PlotCanvas; void rebuildHeader(); void showBadgeMenu(int slotIdx, const QPoint& globalPos); void pushZoomHist(); void initPlotX(double tMax); Hub* hub_; GlobalView* gv_; int plotIdx_; PlotCanvas* canvas_ = nullptr; QHBoxLayout* headerLay_ = nullptr; QWidget* header_ = nullptr; QLabel* cursorLbl_ = nullptr; std::vector slots_; bool live_ = true; bool paused_ = false; double plotXMin_ = 0.0; double plotXMax_ = 0.0; int vMode_ = 0; /* 0 normal 1 digital 2 mixed */ int activeSlot_ = -1; bool trigZoomed_ = false; std::vector> zoomHist_; /* Paused view snapshot (double buffer). */ struct Snapshot { bool valid = false; std::vector keys; std::vector> t, v; } snap_; /* Throttle timers (ms wall clock). */ double lastLiveZoomMs_ = 0.0; double rangeChangedMs_ = 0.0; double lastT0_ = 0.0, lastT1_ = 0.0; double lastHistPushMs_ = 0.0; }; } /* namespace shq */