warp-pipe/gui/ZoomGraphicsView.h

142 lines
4.3 KiB
C++

#pragma once
#include <QtNodes/GraphicsView>
#include <QtNodes/StyleCollection>
#include <QGraphicsProxyWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QScrollBar>
#include <QWheelEvent>
#include <QtNodes/internal/ConnectionGraphicsObject.hpp>
#include <cmath>
class ZoomGraphicsView : public QtNodes::GraphicsView {
public:
explicit ZoomGraphicsView(QtNodes::BasicGraphicsScene *scene,
QWidget *parent = nullptr)
: QtNodes::GraphicsView(scene, parent) {
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
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->type() == QtNodes::ConnectionGraphicsObject::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;
};