#pragma once #include #include #include #include #include #include #include #include class ZoomGraphicsView : public QtNodes::GraphicsView { public: explicit ZoomGraphicsView(QtNodes::BasicGraphicsScene *scene, QWidget *parent = nullptr) : QtNodes::GraphicsView(scene, parent) { setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); setCacheMode(QGraphicsView::CacheNone); } void setZoomSensitivity(double sensitivity) { m_sensitivity = sensitivity; } double zoomSensitivity() const { return m_sensitivity; } void updateProxyCacheMode() { if (!scene()) return; const double zoom = transform().m11(); const bool highZoom = zoom > 1.4; if (highZoom == m_proxiesCached) return; m_proxiesCached = highZoom; auto cacheMode = highZoom ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache; for (QGraphicsItem *item : scene()->items()) { if (item->type() == QGraphicsProxyWidget::Type) item->setCacheMode(cacheMode); } } protected: void wheelEvent(QWheelEvent *event) override { const double dy = event->angleDelta().y(); if (dy == 0.0) { event->ignore(); return; } static constexpr double kTickUnits = 120.0; const double exponent = dy / kTickUnits; const double factor = std::pow(m_sensitivity, exponent); const double proposed = transform().m11() * factor; setupScale(proposed); } void mousePressEvent(QMouseEvent *event) override { if (event->button() == Qt::LeftButton) { m_panActive = true; m_panStart = event->pos(); } QGraphicsView::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { if (m_panActive && (event->buttons() & Qt::LeftButton) && !(event->modifiers() & Qt::ShiftModifier) && !scene()->mouseGrabberItem()) { QPoint delta = event->pos() - m_panStart; m_panStart = event->pos(); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); return; } QGraphicsView::mouseMoveEvent(event); } void mouseReleaseEvent(QMouseEvent *event) override { if (event->button() == Qt::LeftButton) m_panActive = false; QGraphicsView::mouseReleaseEvent(event); } void drawBackground(QPainter *painter, const QRectF &r) override { QGraphicsView::drawBackground(painter, r); const double zoom = transform().m11(); auto const &style = QtNodes::StyleCollection::flowViewStyle(); static constexpr double kBaseFine = 15.0; static constexpr double kBaseCoarse = 150.0; static constexpr double kMinPixelSpacing = 10.0; double fineStep = kBaseFine; while (fineStep * zoom < kMinPixelSpacing) fineStep *= 2.0; double coarseStep = kBaseCoarse; while (coarseStep * zoom < kMinPixelSpacing * 5.0) coarseStep *= 2.0; auto drawGrid = [&](double gridStep) { QRect windowRect = rect(); QPointF tl = mapToScene(windowRect.topLeft()); QPointF br = mapToScene(windowRect.bottomRight()); double left = std::floor(tl.x() / gridStep - 0.5); double right = std::floor(br.x() / gridStep + 1.0); double bottom = std::floor(tl.y() / gridStep - 0.5); double top = std::floor(br.y() / gridStep + 1.0); for (int xi = int(left); xi <= int(right); ++xi) painter->drawLine(QLineF(xi * gridStep, bottom * gridStep, xi * gridStep, top * gridStep)); for (int yi = int(bottom); yi <= int(top); ++yi) painter->drawLine(QLineF(left * gridStep, yi * gridStep, right * gridStep, yi * gridStep)); }; painter->setPen(QPen(style.FineGridColor, 1.0)); drawGrid(fineStep); painter->setPen(QPen(style.CoarseGridColor, 1.0)); drawGrid(coarseStep); } private: double m_sensitivity = 1.2; bool m_proxiesCached = false; bool m_panActive = false; QPoint m_panStart; };