annotate src/panner.cpp @ 737:4f3a8aa8d384 tip

Markdown
author Chris Cannam
date Wed, 28 Aug 2019 17:40:54 +0100
parents 88061103b878
children
rev   line source
Chris@57 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@45 2
cannam@45 3 /*
Chris@57 4 EasyMercurial
Chris@57 5
Chris@57 6 Based on HgExplorer by Jari Korhonen
Chris@57 7 Copyright (c) 2010 Jari Korhonen
Chris@644 8 Copyright (c) 2013 Chris Cannam
Chris@644 9 Copyright (c) 2013 Queen Mary, University of London
Chris@57 10
cannam@45 11 This program is free software; you can redistribute it and/or
cannam@45 12 modify it under the terms of the GNU General Public License as
cannam@45 13 published by the Free Software Foundation; either version 2 of the
cannam@45 14 License, or (at your option) any later version. See the file
cannam@45 15 COPYING included with this distribution for more information.
cannam@45 16 */
cannam@45 17
cannam@45 18 #include "panner.h"
cannam@45 19 #include "panned.h"
Chris@113 20 #include "debug.h"
cannam@45 21
cannam@45 22 #include <QPolygon>
cannam@45 23 #include <QMouseEvent>
cannam@45 24 #include <QColor>
cannam@45 25
cannam@45 26 #include <iostream>
cannam@45 27
cannam@45 28 class PannerScene : public QGraphicsScene
cannam@45 29 {
cannam@45 30 public:
cannam@45 31 friend class Panner;
cannam@45 32 };
cannam@45 33
cannam@45 34 Panner::Panner() :
Chris@389 35 m_clicked(false),
Chris@389 36 m_moved(false)
cannam@45 37 {
cannam@45 38 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
cannam@45 39 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@48 40 setOptimizationFlags(QGraphicsView::DontSavePainterState |
Chris@48 41 QGraphicsView::IndirectPainting);
cannam@45 42 setMouseTracking(true);
cannam@45 43 setInteractive(false);
cannam@45 44 }
cannam@45 45
cannam@45 46 void
Chris@113 47 Panner::fit(QRectF r)
Chris@113 48 {
Chris@113 49 Qt::AspectRatioMode m = Qt::IgnoreAspectRatio;
Chris@113 50 if (height() > width()) {
Chris@113 51 // Our panner is vertical; if the source is not tall,
Chris@113 52 // don't stretch it to fit in the height, it'd look weird
Chris@113 53 if (r.height() < height() * 2) {
Chris@113 54 m = Qt::KeepAspectRatio;
Chris@113 55 }
Chris@113 56 } else {
Chris@113 57 // Similarly, but horizontal
Chris@113 58 if (r.width() < width() * 2) {
Chris@113 59 m = Qt::KeepAspectRatio;
Chris@113 60 }
Chris@113 61 }
Chris@665 62 DEBUG << "Panner: fit mode " << int(m) << endl;
Chris@113 63 fitInView(r, m);
Chris@113 64 }
Chris@113 65
Chris@113 66 void
cannam@45 67 Panner::setScene(QGraphicsScene *s)
cannam@45 68 {
cannam@45 69 if (scene()) {
Chris@133 70 disconnect(scene(), SIGNAL(changed(const QList<QRectF> &)),
Chris@132 71 this, SLOT(slotSceneChanged(const QList<QRectF> &)));
cannam@45 72 disconnect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
cannam@45 73 this, SLOT(slotSceneRectChanged(const QRectF &)));
cannam@45 74 }
cannam@45 75 QGraphicsView::setScene(s);
Chris@136 76 m_cache = QPixmap();
Chris@113 77 if (scene()) {
Chris@113 78 QRectF r = sceneRect();
Chris@113 79 DEBUG << "scene rect: " << r << ", my rect " << rect() << endl;
Chris@113 80 fit(r);
Chris@136 81 connect(scene(), SIGNAL(changed(const QList<QRectF> &)),
Chris@136 82 this, SLOT(slotSceneChanged(const QList<QRectF> &)));
Chris@136 83 connect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
Chris@136 84 this, SLOT(slotSceneRectChanged(const QRectF &)));
Chris@113 85 }
cannam@45 86 }
cannam@45 87
cannam@45 88 void
cannam@45 89 Panner::connectToPanned(Panned *p)
cannam@45 90 {
cannam@45 91 connect(p, SIGNAL(pannedRectChanged(QRectF)),
cannam@45 92 this, SLOT(slotSetPannedRect(QRectF)));
cannam@45 93
cannam@45 94 connect(this, SIGNAL(pannedRectChanged(QRectF)),
cannam@45 95 p, SLOT(slotSetPannedRect(QRectF)));
Chris@53 96
Chris@53 97 connect(this, SIGNAL(zoomIn()),
Chris@53 98 p, SLOT(zoomIn()));
Chris@53 99
Chris@53 100 connect(this, SIGNAL(zoomOut()),
Chris@53 101 p, SLOT(zoomOut()));
cannam@45 102 }
cannam@45 103
cannam@45 104 void
cannam@45 105 Panner::slotSetPannedRect(QRectF rect)
cannam@45 106 {
cannam@45 107 m_pannedRect = rect;
cannam@45 108 viewport()->update();
cannam@45 109 }
cannam@45 110
cannam@45 111 void
cannam@45 112 Panner::resizeEvent(QResizeEvent *)
cannam@45 113 {
Chris@250 114 DEBUG << "Panner::resizeEvent" << endl;
Chris@113 115 if (scene()) fit(sceneRect());
cannam@45 116 m_cache = QPixmap();
cannam@45 117 }
cannam@45 118
cannam@45 119 void
cannam@45 120 Panner::slotSceneRectChanged(const QRectF &newRect)
cannam@45 121 {
Chris@250 122 DEBUG << "Panner::slotSceneRectChanged" << endl;
cannam@45 123 if (!scene()) return; // spurious
Chris@113 124 fit(newRect);
cannam@45 125 m_cache = QPixmap();
cannam@45 126 viewport()->update();
cannam@45 127 }
cannam@45 128
cannam@45 129 void
Chris@132 130 Panner::slotSceneChanged(const QList<QRectF> &)
Chris@132 131 {
Chris@250 132 DEBUG << "Panner::slotSceneChanged" << endl;
Chris@132 133 if (!scene()) return; // spurious
Chris@132 134 m_cache = QPixmap();
Chris@132 135 viewport()->update();
Chris@132 136 }
Chris@132 137
Chris@132 138 void
cannam@45 139 Panner::paintEvent(QPaintEvent *e)
cannam@45 140 {
cannam@45 141 QPaintEvent *e2 = new QPaintEvent(e->region().boundingRect());
cannam@45 142 QGraphicsView::paintEvent(e2);
cannam@45 143
cannam@45 144 QPainter paint;
cannam@45 145 paint.begin(viewport());
cannam@45 146 paint.setClipRegion(e->region());
cannam@45 147
cannam@45 148 QPainterPath path;
cannam@45 149 path.addRect(rect());
cannam@45 150 path.addPolygon(mapFromScene(m_pannedRect));
cannam@45 151
cannam@45 152 QColor c(QColor::fromHsv(211, 194, 238));
cannam@45 153 c.setAlpha(80);
cannam@45 154 paint.setPen(Qt::NoPen);
cannam@45 155 paint.setBrush(c);
cannam@45 156 paint.drawPath(path);
cannam@45 157
cannam@45 158 paint.setBrush(Qt::NoBrush);
cannam@45 159 paint.setPen(QPen(QColor::fromHsv(211, 194, 238), 0));
cannam@45 160 paint.drawConvexPolygon(mapFromScene(m_pannedRect));
cannam@45 161
cannam@45 162 paint.end();
cannam@45 163
cannam@45 164 emit pannerChanged(m_pannedRect);
cannam@45 165 }
cannam@45 166
cannam@45 167 void
cannam@45 168 Panner::updateScene(const QList<QRectF> &rects)
cannam@45 169 {
Chris@250 170 DEBUG << "Panner::updateScene" << endl;
Chris@250 171 // if (!m_cache.isNull()) m_cache = QPixmap();
cannam@45 172 QGraphicsView::updateScene(rects);
cannam@45 173 }
cannam@45 174
cannam@45 175 void
cannam@45 176 Panner::drawItems(QPainter *painter, int numItems,
cannam@45 177 QGraphicsItem *items[],
cannam@45 178 const QStyleOptionGraphicsItem options[])
cannam@45 179 {
cannam@45 180 if (m_cache.size() != viewport()->size()) {
cannam@45 181
Chris@131 182 DEBUG << "Panner: cache size " << m_cache.size() << " != viewport size " << viewport()->size() << ": recreating cache" << endl;
Chris@48 183
cannam@45 184 QGraphicsScene *s = scene();
cannam@45 185 if (!s) return;
cannam@45 186 PannerScene *ps = static_cast<PannerScene *>(s);
cannam@45 187
cannam@45 188 m_cache = QPixmap(viewport()->size());
cannam@45 189 m_cache.fill(Qt::transparent);
cannam@45 190 QPainter cachePainter;
cannam@45 191 cachePainter.begin(&m_cache);
cannam@45 192 cachePainter.setTransform(viewportTransform());
cannam@45 193 ps->drawItems(&cachePainter, numItems, items, options);
cannam@45 194 cachePainter.end();
Chris@250 195
Chris@250 196 DEBUG << "done" << endl;
cannam@45 197 }
cannam@45 198
cannam@45 199 painter->save();
cannam@45 200 painter->setTransform(QTransform());
cannam@45 201 painter->drawPixmap(0, 0, m_cache);
cannam@45 202 painter->restore();
cannam@45 203 }
cannam@45 204
cannam@45 205 void
cannam@45 206 Panner::mousePressEvent(QMouseEvent *e)
cannam@45 207 {
cannam@45 208 if (e->button() != Qt::LeftButton) {
cannam@45 209 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 210 return;
cannam@45 211 }
cannam@45 212 m_clicked = true;
Chris@389 213 m_moved = false;
cannam@45 214 m_clickedRect = m_pannedRect;
cannam@45 215 m_clickedPoint = e->pos();
cannam@45 216 }
cannam@45 217
cannam@45 218 void
cannam@45 219 Panner::mouseDoubleClickEvent(QMouseEvent *e)
cannam@45 220 {
cannam@45 221 if (e->button() != Qt::LeftButton) {
cannam@45 222 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 223 return;
cannam@45 224 }
cannam@45 225
cannam@45 226 moveTo(e->pos());
cannam@45 227 }
cannam@45 228
cannam@45 229 void
cannam@45 230 Panner::mouseMoveEvent(QMouseEvent *e)
cannam@45 231 {
cannam@45 232 if (!m_clicked) return;
cannam@45 233 QPointF cp = mapToScene(m_clickedPoint);
cannam@45 234 QPointF mp = mapToScene(e->pos());
cannam@45 235 QPointF delta = mp - cp;
Chris@389 236 if (!m_moved) {
Chris@389 237 if ((m_clickedPoint - e->pos()).manhattanLength() > 2) {
Chris@389 238 m_moved = true;
Chris@389 239 } else {
Chris@389 240 return;
Chris@389 241 }
Chris@389 242 }
cannam@45 243 QRectF nr = m_clickedRect;
cannam@45 244 nr.translate(delta);
Chris@173 245 m_pannedRect = nr;
cannam@45 246 emit pannedRectChanged(m_pannedRect);
cannam@45 247 viewport()->update();
cannam@45 248 }
cannam@45 249
cannam@45 250 void
cannam@45 251 Panner::mouseReleaseEvent(QMouseEvent *e)
cannam@45 252 {
cannam@45 253 if (e->button() != Qt::LeftButton) {
cannam@45 254 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 255 return;
cannam@45 256 }
cannam@45 257
cannam@45 258 if (m_clicked) {
Chris@389 259 if (m_moved) {
Chris@389 260 mouseMoveEvent(e);
Chris@389 261 } else {
Chris@389 262 moveTo(e->pos());
Chris@389 263 }
cannam@45 264 }
cannam@45 265
cannam@45 266 m_clicked = false;
cannam@45 267 viewport()->update();
cannam@45 268 }
cannam@45 269
cannam@45 270 void
cannam@45 271 Panner::wheelEvent(QWheelEvent *e)
cannam@45 272 {
Chris@53 273 int d = e->delta();
Chris@53 274 if (d > 0) {
Chris@53 275 while (d > 0) {
Chris@53 276 emit zoomOut();
Chris@53 277 d -= 120;
Chris@53 278 }
cannam@45 279 } else {
Chris@53 280 while (d < 0) {
Chris@53 281 emit zoomIn();
Chris@53 282 d += 120;
Chris@53 283 }
cannam@45 284 }
cannam@45 285 }
cannam@45 286
cannam@45 287 void
cannam@45 288 Panner::moveTo(QPoint p)
cannam@45 289 {
cannam@45 290 QPointF sp = mapToScene(p);
cannam@45 291 QRectF nr = m_pannedRect;
Chris@389 292 double dx = sp.x() - nr.center().x();
Chris@389 293 double dy = sp.y() - nr.center().y();
Chris@389 294 nr.translate(dx, dy);
cannam@45 295 slotSetPannedRect(nr);
cannam@45 296 emit pannedRectChanged(m_pannedRect);
cannam@45 297 viewport()->update();
cannam@45 298 }
cannam@45 299