/** * @file PlotGrid.cpp */ #include "PlotGrid.h" #include "PlotWidget.h" #include "Hub.h" #include #include #include namespace shq { static double nowSec() { return QDateTime::currentMSecsSinceEpoch() / 1000.0; } PlotGrid::PlotGrid(Hub* hub, GlobalView* gv, QWidget* parent) : QWidget(parent), hub_(hub), gv_(gv) { /* Persistent pool: one PlotWidget per slot, fixed plotIdx (== zoom cache * index). Plots beyond the current layout are simply not mounted. */ pool_.reserve(kMaxPlotSlots); for (int i = 0; i < kMaxPlotSlots; i++) { auto* p = new PlotWidget(hub_, gv_, i, this); connect(hub_, &Hub::zoomReceived, p, &PlotWidget::onZoomReceived); connect(hub_, &Hub::historyZoomReceived, p, &PlotWidget::onHistoryZoomReceived); connect(hub_, &Hub::captureReceived, p, &PlotWidget::onCaptureReceived); p->setParent(nullptr); p->hide(); pool_.push_back(p); } auto* lay = new QVBoxLayout(this); lay->setContentsMargins(0, 0, 0, 0); rebuild(); } void PlotGrid::setLayout(PlotLayout l) { if (l == layout_) { return; } layout_ = l; rebuild(); } void PlotGrid::rebuild() { /* Detach every pooled plot from any previous splitter. */ for (auto* p : pool_) { p->setParent(this); p->hide(); } /* Drop the old root splitter (if any). */ QLayout* lay = this->QWidget::layout(); QLayoutItem* item; while ((item = lay->takeAt(0)) != nullptr) { if (QWidget* w = item->widget()) { if (qobject_cast(w)) { w->deleteLater(); } } delete item; } int cols, rows; layoutDims(layout_, cols, rows); auto* outer = new QSplitter(Qt::Vertical, this); outer->setChildrenCollapsible(false); outer->setHandleWidth(5); plots_.clear(); for (int r = 0; r < rows; r++) { QSplitter* rowSplit = outer; if (cols > 1) { rowSplit = new QSplitter(Qt::Horizontal, outer); rowSplit->setChildrenCollapsible(false); rowSplit->setHandleWidth(5); } for (int c = 0; c < cols; c++) { int idx = r * cols + c; PlotWidget* p = pool_[idx]; p->setParent(rowSplit); p->show(); if (cols > 1) { rowSplit->addWidget(p); } else { outer->addWidget(p); } plots_.push_back(p); } if (cols > 1) { outer->addWidget(rowSplit); } } lay->addWidget(outer); onModelChanged(); } void PlotGrid::onModelChanged() { for (auto* p : plots_) { p->onModelChanged(); } } void PlotGrid::onPauseChanged() { for (auto* p : plots_) { p->onPauseChanged(); } } void PlotGrid::tick() { for (auto* p : plots_) { p->tick(); } } void PlotGrid::goLive() { for (auto* p : plots_) { p->setLive(true); } } void PlotGrid::setAllStoredX(double t0, double t1) { if (t1 <= t0) { return; } for (auto* p : plots_) { p->setLive(false); p->setStoredX(t0, t1); } } bool PlotGrid::anyNonLive() const { for (auto* p : plots_) { if (!p->isLive()) { return true; } } return false; } bool PlotGrid::currentRange(double& t0, double& t1) const { for (auto* p : plots_) { if (!p->isLive()) { t0 = p->xMin(); t1 = p->xMax(); return true; } } return false; } void PlotGrid::panAll(double frac) { const double wallNow = nowSec(); for (auto* p : plots_) { if (p->isLive()) { continue; } double span = p->xMax() - p->xMin(); if (span <= 0.0) { continue; } double d = span * frac; double mn = p->xMin() + d, mx = p->xMax() + d; if (mx > wallNow) { mx = wallNow; mn = mx - span; } p->setStoredX(mn, mx); } } void PlotGrid::jumpAllAgo(double secAgo) { const double wallNow = nowSec(); for (auto* p : plots_) { double span = p->xMax() - p->xMin(); if (span <= 0.0) { span = gv_->windowSec; } p->setLive(false); p->setStoredX(wallNow - secAgo - span, wallNow - secAgo); } } } /* namespace shq */