annotate src/panner.cpp @ 571:012ba1b83328

Show cancel button with progress bar only when running an operation that it makes sense to cancel (we don't really want people cancelling e.g. initial folder scan because it would leave things in an inconsistent state)
author Chris Cannam
date Thu, 01 Mar 2012 22:53:54 +0000
parents 533519ebc0cb
children ae67ea0af696
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@560 8 Copyright (c) 2012 Chris Cannam
Chris@560 9 Copyright (c) 2012 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@113 62 DEBUG << "Panner: fit mode " << 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