#include "graphicsview.h" #include "graphicsscene.h" #include #include #include #include #include GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView (parent) { setDragMode(QGraphicsView::ScrollHandDrag); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setResizeAnchor(QGraphicsView::AnchorUnderMouse); setStyleSheet("background-color: rgba(0, 0, 0, 220);" "border-radius: 3px;"); setAcceptDrops(true); setCheckerboardEnabled(false); } void GraphicsView::showImage(const QPixmap &pixmap) { resetTransform(); scene()->showImage(pixmap); checkAndDoFitInView(); } void GraphicsView::showText(const QString &text) { resetTransform(); scene()->showText(text); checkAndDoFitInView(); } void GraphicsView::showSvg(const QString &filepath) { resetTransform(); scene()->showSvg(filepath); checkAndDoFitInView(); } void GraphicsView::showGif(const QString &filepath) { resetTransform(); scene()->showGif(filepath); checkAndDoFitInView(); } GraphicsScene *GraphicsView::scene() const { return qobject_cast(QGraphicsView::scene()); } void GraphicsView::setScene(GraphicsScene *scene) { return QGraphicsView::setScene(scene); } void GraphicsView::toggleCheckerboard() { setCheckerboardEnabled(!m_checkerboardEnabled); } void GraphicsView::mousePressEvent(QMouseEvent *event) { if (shouldIgnoreMousePressMoveEvent(event)) { event->ignore(); // blumia: return here, or the QMouseEvent event transparency won't // work if we set a QGraphicsView::ScrollHandDrag drag mode. return; } return QGraphicsView::mousePressEvent(event); } void GraphicsView::mouseMoveEvent(QMouseEvent *event) { if (shouldIgnoreMousePressMoveEvent(event)) { event->ignore(); } return QGraphicsView::mouseMoveEvent(event); } void GraphicsView::mouseReleaseEvent(QMouseEvent *event) { QGraphicsItem *item = itemAt(event->pos()); if (!item) { event->ignore(); } return QGraphicsView::mouseReleaseEvent(event); } void GraphicsView::wheelEvent(QWheelEvent *event) { m_enableFitInView = false; if (event->delta() > 0) { scale(1.25, 1.25); } else { scale(0.8, 0.8); } } void GraphicsView::resizeEvent(QResizeEvent *event) { if (m_enableFitInView) { if (isThingSmallerThanWindowWith(QTransform()) && transform().m11() >= 1) { // no longer need to do fitInView() // but we leave the m_enableFitInView value unchanged in case // user resize down the window again. } else { fitInView(sceneRect(), Qt::KeepAspectRatio); } } return QGraphicsView::resizeEvent(event); } void GraphicsView::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls() || event->mimeData()->hasImage() || event->mimeData()->hasText()) { event->acceptProposedAction(); } else { event->ignore(); } qDebug() << event->mimeData() << "Drag Enter Event" << event->mimeData()->hasUrls() << event->mimeData()->hasImage() << event->mimeData()->formats() << event->mimeData()->hasFormat("text/uri-list"); return QGraphicsView::dragEnterEvent(event); } void GraphicsView::dragMoveEvent(QDragMoveEvent *event) { Q_UNUSED(event); // by default, QGraphicsView/Scene will ignore the action if there are no QGraphicsItem under cursor. // We actually doesn't care and would like to keep the drag event as-is, so just do nothing here. } void GraphicsView::dropEvent(QDropEvent *event) { event->acceptProposedAction(); const QMimeData * mimeData = event->mimeData(); if (mimeData->hasUrls()) { if (mimeData->urls().isEmpty()) { // yeah, it's possible. dragging QQ's original sticker will trigger this, for example. showText("File url list is empty"); return; } QUrl url(mimeData->urls().first()); QString filePath(url.toLocalFile()); if (filePath.endsWith(".svg")) { showSvg(filePath); } else if (filePath.endsWith(".gif")) { showGif(filePath); } else { QImageReader imageReader(filePath); QImage::Format imageFormat = imageReader.imageFormat(); if (imageFormat == QImage::Format_Invalid) { showText("File is not a valid image"); } else { showImage(QPixmap::fromImageReader(&imageReader)); } } } else if (mimeData->hasImage()) { QImage img = qvariant_cast(mimeData->imageData()); QPixmap pixmap = QPixmap::fromImage(img); if (pixmap.isNull()) { showText("Image data is invalid"); } else { showImage(pixmap); } } else if (mimeData->hasText()) { showText(mimeData->text()); } else { showText("Not supported mimedata: " + mimeData->formats().first()); } } bool GraphicsView::isThingSmallerThanWindowWith(const QTransform &transform) const { return rect().size().expandedTo(transform.mapRect(sceneRect()).size().toSize()) == rect().size(); } bool GraphicsView::shouldIgnoreMousePressMoveEvent(const QMouseEvent *event) const { if (isThingSmallerThanWindowWith(transform())) { return true; } QGraphicsItem *item = itemAt(event->pos()); if (!item) { return true; } return false; } void GraphicsView::checkAndDoFitInView() { if (!isThingSmallerThanWindowWith(transform())) { m_enableFitInView = true; fitInView(sceneRect(), Qt::KeepAspectRatio); } } void GraphicsView::setCheckerboardEnabled(bool enabled) { m_checkerboardEnabled = enabled; if (m_checkerboardEnabled) { // Prepare background check-board pattern QPixmap tilePixmap(0x20, 0x20); tilePixmap.fill(QColor(30, 30, 30, 100)); QPainter tilePainter(&tilePixmap); QColor color(40, 40, 40, 100); tilePainter.fillRect(0, 0, 0x10, 0x10, color); tilePainter.fillRect(0x10, 0x10, 0x10, 0x10, color); tilePainter.end(); setBackgroundBrush(tilePixmap); } else { setBackgroundBrush(Qt::transparent); } }