diff src/panner.cpp @ 370:b9c153e00e84

Move source files to src/
author Chris Cannam
date Thu, 24 Mar 2011 10:27:51 +0000
parents panner.cpp@be483734bde5
children 496f2042155a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/panner.cpp	Thu Mar 24 10:27:51 2011 +0000
@@ -0,0 +1,285 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    EasyMercurial
+
+    Based on HgExplorer by Jari Korhonen
+    Copyright (c) 2010 Jari Korhonen
+    Copyright (c) 2011 Chris Cannam
+    Copyright (c) 2011 Queen Mary, University of London
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "panner.h"
+#include "panned.h"
+#include "debug.h"
+
+#include <QPolygon>
+#include <QMouseEvent>
+#include <QColor>
+
+#include <iostream>
+
+class PannerScene : public QGraphicsScene
+{
+public:
+    friend class Panner;
+};
+
+Panner::Panner() :
+    m_clicked(false)
+{
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    setOptimizationFlags(QGraphicsView::DontSavePainterState |
+                         QGraphicsView::IndirectPainting);
+    setMouseTracking(true);
+    setInteractive(false);
+}
+
+void
+Panner::fit(QRectF r)
+{
+    Qt::AspectRatioMode m = Qt::IgnoreAspectRatio;
+    if (height() > width()) {
+        // Our panner is vertical; if the source is not tall,
+        // don't stretch it to fit in the height, it'd look weird
+        if (r.height() < height() * 2) {
+            m = Qt::KeepAspectRatio;
+        }
+    } else {
+        // Similarly, but horizontal
+        if (r.width() < width() * 2) {
+            m = Qt::KeepAspectRatio;
+        }
+    }
+    DEBUG << "Panner: fit mode " << m << endl;
+    fitInView(r, m);
+}
+
+void
+Panner::setScene(QGraphicsScene *s)
+{
+    if (scene()) {
+        disconnect(scene(), SIGNAL(changed(const QList<QRectF> &)),
+                   this, SLOT(slotSceneChanged(const QList<QRectF> &)));
+        disconnect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
+                   this, SLOT(slotSceneRectChanged(const QRectF &)));
+    }
+    QGraphicsView::setScene(s);
+    m_cache = QPixmap();
+    if (scene()) {
+        QRectF r = sceneRect();
+        DEBUG << "scene rect: " << r << ", my rect " << rect() << endl;
+        fit(r);
+        connect(scene(), SIGNAL(changed(const QList<QRectF> &)),
+                this, SLOT(slotSceneChanged(const QList<QRectF> &)));
+        connect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
+                this, SLOT(slotSceneRectChanged(const QRectF &)));
+    }
+}
+
+void
+Panner::connectToPanned(Panned *p)
+{
+    connect(p, SIGNAL(pannedRectChanged(QRectF)),
+            this, SLOT(slotSetPannedRect(QRectF)));
+
+    connect(this, SIGNAL(pannedRectChanged(QRectF)),
+            p, SLOT(slotSetPannedRect(QRectF)));
+
+    connect(this, SIGNAL(zoomIn()),
+            p, SLOT(zoomIn()));
+
+    connect(this, SIGNAL(zoomOut()),
+            p, SLOT(zoomOut()));
+}
+
+void
+Panner::slotSetPannedRect(QRectF rect) 
+{
+    m_pannedRect = rect;
+    viewport()->update();
+}
+
+void
+Panner::resizeEvent(QResizeEvent *)
+{
+    DEBUG << "Panner::resizeEvent" << endl;
+    if (scene()) fit(sceneRect());
+    m_cache = QPixmap();
+}
+
+void
+Panner::slotSceneRectChanged(const QRectF &newRect)
+{
+    DEBUG << "Panner::slotSceneRectChanged" << endl;
+    if (!scene()) return; // spurious
+    fit(newRect);
+    m_cache = QPixmap();
+    viewport()->update();
+}
+
+void
+Panner::slotSceneChanged(const QList<QRectF> &)
+{
+    DEBUG << "Panner::slotSceneChanged" << endl;
+    if (!scene()) return; // spurious
+    m_cache = QPixmap();
+    viewport()->update();
+}
+
+void
+Panner::paintEvent(QPaintEvent *e)
+{
+    QPaintEvent *e2 = new QPaintEvent(e->region().boundingRect());
+    QGraphicsView::paintEvent(e2);
+
+    QPainter paint;
+    paint.begin(viewport());
+    paint.setClipRegion(e->region());
+
+    QPainterPath path;
+    path.addRect(rect());
+    path.addPolygon(mapFromScene(m_pannedRect));
+
+    QColor c(QColor::fromHsv(211, 194, 238));
+    c.setAlpha(80);
+    paint.setPen(Qt::NoPen);
+    paint.setBrush(c);
+    paint.drawPath(path);
+
+    paint.setBrush(Qt::NoBrush);
+    paint.setPen(QPen(QColor::fromHsv(211, 194, 238), 0));
+    paint.drawConvexPolygon(mapFromScene(m_pannedRect));
+
+    paint.end();
+
+    emit pannerChanged(m_pannedRect);
+}
+
+void
+Panner::updateScene(const QList<QRectF> &rects)
+{
+    DEBUG << "Panner::updateScene" << endl;
+//    if (!m_cache.isNull()) m_cache = QPixmap();
+    QGraphicsView::updateScene(rects);
+}
+
+void
+Panner::drawItems(QPainter *painter, int numItems,
+                  QGraphicsItem *items[],
+                  const QStyleOptionGraphicsItem options[])
+{
+    if (m_cache.size() != viewport()->size()) {
+
+        DEBUG << "Panner: cache size " << m_cache.size() << " != viewport size " << viewport()->size() << ": recreating cache" << endl;
+
+        QGraphicsScene *s = scene();
+        if (!s) return;
+        PannerScene *ps = static_cast<PannerScene *>(s);
+
+        m_cache = QPixmap(viewport()->size());
+        m_cache.fill(Qt::transparent);
+        QPainter cachePainter;
+        cachePainter.begin(&m_cache);
+        cachePainter.setTransform(viewportTransform());
+        ps->drawItems(&cachePainter, numItems, items, options);
+        cachePainter.end();
+
+        DEBUG << "done" << endl;
+    }
+
+    painter->save();
+    painter->setTransform(QTransform());
+    painter->drawPixmap(0, 0, m_cache);
+    painter->restore();
+}
+ 
+void
+Panner::mousePressEvent(QMouseEvent *e)
+{
+    if (e->button() != Qt::LeftButton) {
+        QGraphicsView::mouseDoubleClickEvent(e);
+        return;
+    }
+    m_clicked = true;
+    m_clickedRect = m_pannedRect;
+    m_clickedPoint = e->pos();
+}
+
+void
+Panner::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    if (e->button() != Qt::LeftButton) {
+        QGraphicsView::mouseDoubleClickEvent(e);
+        return;
+    }
+
+    moveTo(e->pos());
+}
+
+void
+Panner::mouseMoveEvent(QMouseEvent *e)
+{
+    if (!m_clicked) return;
+    QPointF cp = mapToScene(m_clickedPoint);
+    QPointF mp = mapToScene(e->pos());
+    QPointF delta = mp - cp;
+    QRectF nr = m_clickedRect;
+    nr.translate(delta);
+    m_pannedRect = nr;
+    emit pannedRectChanged(m_pannedRect);
+    viewport()->update();
+}
+
+void
+Panner::mouseReleaseEvent(QMouseEvent *e)
+{
+    if (e->button() != Qt::LeftButton) {
+        QGraphicsView::mouseDoubleClickEvent(e);
+        return;
+    }
+
+    if (m_clicked) {
+        mouseMoveEvent(e);
+    }
+
+    m_clicked = false;
+    viewport()->update();
+}
+
+void
+Panner::wheelEvent(QWheelEvent *e)
+{
+    int d = e->delta();
+    if (d > 0) {
+        while (d > 0) {
+            emit zoomOut();
+            d -= 120;
+        }
+    } else {
+        while (d < 0) {
+            emit zoomIn();
+            d += 120;
+        }
+    }
+}
+
+void
+Panner::moveTo(QPoint p)
+{
+    QPointF sp = mapToScene(p);
+    QRectF nr = m_pannedRect;
+    double d = sp.x() - nr.center().x();
+    nr.translate(d, 0);
+    slotSetPannedRect(nr);
+    emit pannedRectChanged(m_pannedRect);
+    viewport()->update();
+}
+