/** * @file PlotGrid.h * @brief Resizable grid of PlotWidgets realising the selected PlotLayout. * * Built from nested QSplitters (rows of columns) so cells are user-resizable, * mirroring the ImGui draggable separators. Holds up to kMaxPlotSlots plots, * fans out the 60 Hz tick / model / pause notifications, and drives the * history navigation (live ⇄ stored-X) for all visible plots. */ #pragma once #include "Model.h" #include #include namespace shq { class Hub; struct GlobalView; class PlotWidget; class PlotGrid : public QWidget { Q_OBJECT public: PlotGrid(Hub* hub, GlobalView* gv, QWidget* parent = nullptr); void setLayout(PlotLayout l); PlotLayout layout() const { return layout_; } int numSlots() const { return layoutSlots(layout_); } /** Visible plots (size == numSlots()). */ const std::vector& plots() const { return plots_; } public Q_SLOTS: void onModelChanged(); void onPauseChanged(); void tick(); /** History navigation helpers (operate on all visible plots). */ void goLive(); void setAllStoredX(double t0, double t1); void panAll(double frac); /* +right / -left, frac of span */ void jumpAllAgo(double secAgo); /* set window ending secAgo before now */ bool anyNonLive() const; /** Current stored range of the first non-live plot (false if all live). */ bool currentRange(double& t0, double& t1) const; private: void rebuild(); Hub* hub_; GlobalView* gv_; PlotLayout layout_ = PlotLayout::k1x1; std::vector plots_; /* currently mounted (== numSlots) */ std::vector pool_; /* all kMaxPlotSlots, persistent */ }; } /* namespace shq */