annotate panner.cpp @ 131:2550aaa09240

* Add connecting line to uncommitted item; turn Revert icon blue; cut down menus to things that actually work (well, mostly)
author Chris Cannam
date Tue, 30 Nov 2010 11:17:30 +0000
parents 5fc7b4fc77a8
children 16ceeee30e2a
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@57 8 Copyright (c) 2010 Chris Cannam
Chris@57 9 Copyright (c) 2010 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() :
cannam@45 35 m_clicked(false)
cannam@45 36 {
cannam@45 37 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
cannam@45 38 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@48 39 setOptimizationFlags(QGraphicsView::DontSavePainterState |
Chris@48 40 QGraphicsView::IndirectPainting);
cannam@45 41 setMouseTracking(true);
cannam@45 42 setInteractive(false);
cannam@45 43 }
cannam@45 44
cannam@45 45 void
Chris@113 46 Panner::fit(QRectF r)
Chris@113 47 {
Chris@113 48 Qt::AspectRatioMode m = Qt::IgnoreAspectRatio;
Chris@113 49 if (height() > width()) {
Chris@113 50 // Our panner is vertical; if the source is not tall,
Chris@113 51 // don't stretch it to fit in the height, it'd look weird
Chris@113 52 if (r.height() < height() * 2) {
Chris@113 53 m = Qt::KeepAspectRatio;
Chris@113 54 }
Chris@113 55 } else {
Chris@113 56 // Similarly, but horizontal
Chris@113 57 if (r.width() < width() * 2) {
Chris@113 58 m = Qt::KeepAspectRatio;
Chris@113 59 }
Chris@113 60 }
Chris@113 61 DEBUG << "Panner: fit mode " << m << endl;
Chris@113 62 fitInView(r, m);
Chris@113 63 }
Chris@113 64
Chris@113 65 void
cannam@45 66 Panner::setScene(QGraphicsScene *s)
cannam@45 67 {
cannam@45 68 if (scene()) {
cannam@45 69 disconnect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
cannam@45 70 this, SLOT(slotSceneRectChanged(const QRectF &)));
cannam@45 71 }
cannam@45 72 QGraphicsView::setScene(s);
Chris@113 73 if (scene()) {
Chris@113 74 QRectF r = sceneRect();
Chris@113 75 DEBUG << "scene rect: " << r << ", my rect " << rect() << endl;
Chris@113 76 fit(r);
Chris@113 77 }
cannam@45 78 m_cache = QPixmap();
cannam@45 79 connect(scene(), SIGNAL(sceneRectChanged(const QRectF &)),
cannam@45 80 this, SLOT(slotSceneRectChanged(const QRectF &)));
cannam@45 81 }
cannam@45 82
cannam@45 83 void
cannam@45 84 Panner::connectToPanned(Panned *p)
cannam@45 85 {
cannam@45 86 connect(p, SIGNAL(pannedRectChanged(QRectF)),
cannam@45 87 this, SLOT(slotSetPannedRect(QRectF)));
cannam@45 88
cannam@45 89 connect(this, SIGNAL(pannedRectChanged(QRectF)),
cannam@45 90 p, SLOT(slotSetPannedRect(QRectF)));
Chris@53 91
Chris@53 92 connect(this, SIGNAL(zoomIn()),
Chris@53 93 p, SLOT(zoomIn()));
Chris@53 94
Chris@53 95 connect(this, SIGNAL(zoomOut()),
Chris@53 96 p, SLOT(zoomOut()));
cannam@45 97 }
cannam@45 98
cannam@45 99 void
cannam@45 100 Panner::slotSetPannedRect(QRectF rect)
cannam@45 101 {
cannam@45 102 m_pannedRect = rect;
cannam@45 103 viewport()->update();
cannam@45 104 }
cannam@45 105
cannam@45 106 void
cannam@45 107 Panner::resizeEvent(QResizeEvent *)
cannam@45 108 {
Chris@113 109 if (scene()) fit(sceneRect());
cannam@45 110 m_cache = QPixmap();
cannam@45 111 }
cannam@45 112
cannam@45 113 void
cannam@45 114 Panner::slotSceneRectChanged(const QRectF &newRect)
cannam@45 115 {
cannam@45 116 if (!scene()) return; // spurious
Chris@113 117 fit(newRect);
cannam@45 118 m_cache = QPixmap();
cannam@45 119 viewport()->update();
cannam@45 120 }
cannam@45 121
cannam@45 122 void
cannam@45 123 Panner::paintEvent(QPaintEvent *e)
cannam@45 124 {
cannam@45 125 QPaintEvent *e2 = new QPaintEvent(e->region().boundingRect());
cannam@45 126 QGraphicsView::paintEvent(e2);
cannam@45 127
cannam@45 128 QPainter paint;
cannam@45 129 paint.begin(viewport());
cannam@45 130 paint.setClipRegion(e->region());
cannam@45 131
cannam@45 132 QPainterPath path;
cannam@45 133 path.addRect(rect());
cannam@45 134 path.addPolygon(mapFromScene(m_pannedRect));
cannam@45 135
cannam@45 136 QColor c(QColor::fromHsv(211, 194, 238));
cannam@45 137 c.setAlpha(80);
cannam@45 138 paint.setPen(Qt::NoPen);
cannam@45 139 paint.setBrush(c);
cannam@45 140 paint.drawPath(path);
cannam@45 141
cannam@45 142 paint.setBrush(Qt::NoBrush);
cannam@45 143 paint.setPen(QPen(QColor::fromHsv(211, 194, 238), 0));
cannam@45 144 paint.drawConvexPolygon(mapFromScene(m_pannedRect));
cannam@45 145
cannam@45 146 paint.end();
cannam@45 147
cannam@45 148 emit pannerChanged(m_pannedRect);
cannam@45 149 }
cannam@45 150
cannam@45 151 void
cannam@45 152 Panner::updateScene(const QList<QRectF> &rects)
cannam@45 153 {
cannam@45 154 if (!m_cache.isNull()) m_cache = QPixmap();
cannam@45 155 QGraphicsView::updateScene(rects);
cannam@45 156 }
cannam@45 157
cannam@45 158 void
cannam@45 159 Panner::drawItems(QPainter *painter, int numItems,
cannam@45 160 QGraphicsItem *items[],
cannam@45 161 const QStyleOptionGraphicsItem options[])
cannam@45 162 {
cannam@45 163 if (m_cache.size() != viewport()->size()) {
cannam@45 164
Chris@131 165 DEBUG << "Panner: cache size " << m_cache.size() << " != viewport size " << viewport()->size() << ": recreating cache" << endl;
Chris@48 166
cannam@45 167 QGraphicsScene *s = scene();
cannam@45 168 if (!s) return;
cannam@45 169 PannerScene *ps = static_cast<PannerScene *>(s);
cannam@45 170
cannam@45 171 m_cache = QPixmap(viewport()->size());
cannam@45 172 m_cache.fill(Qt::transparent);
cannam@45 173 QPainter cachePainter;
cannam@45 174 cachePainter.begin(&m_cache);
cannam@45 175 cachePainter.setTransform(viewportTransform());
cannam@45 176 ps->drawItems(&cachePainter, numItems, items, options);
cannam@45 177 cachePainter.end();
cannam@45 178 }
cannam@45 179
cannam@45 180 painter->save();
cannam@45 181 painter->setTransform(QTransform());
cannam@45 182 painter->drawPixmap(0, 0, m_cache);
cannam@45 183 painter->restore();
cannam@45 184 }
cannam@45 185
cannam@45 186 void
cannam@45 187 Panner::mousePressEvent(QMouseEvent *e)
cannam@45 188 {
cannam@45 189 if (e->button() != Qt::LeftButton) {
cannam@45 190 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 191 return;
cannam@45 192 }
cannam@45 193 m_clicked = true;
cannam@45 194 m_clickedRect = m_pannedRect;
cannam@45 195 m_clickedPoint = e->pos();
cannam@45 196 }
cannam@45 197
cannam@45 198 void
cannam@45 199 Panner::mouseDoubleClickEvent(QMouseEvent *e)
cannam@45 200 {
cannam@45 201 if (e->button() != Qt::LeftButton) {
cannam@45 202 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 203 return;
cannam@45 204 }
cannam@45 205
cannam@45 206 moveTo(e->pos());
cannam@45 207 }
cannam@45 208
cannam@45 209 void
cannam@45 210 Panner::mouseMoveEvent(QMouseEvent *e)
cannam@45 211 {
cannam@45 212 if (!m_clicked) return;
cannam@45 213 QPointF cp = mapToScene(m_clickedPoint);
cannam@45 214 QPointF mp = mapToScene(e->pos());
cannam@45 215 QPointF delta = mp - cp;
cannam@45 216 QRectF nr = m_clickedRect;
cannam@45 217 nr.translate(delta);
cannam@45 218 slotSetPannedRect(nr);
cannam@45 219 emit pannedRectChanged(m_pannedRect);
cannam@45 220 viewport()->update();
cannam@45 221 }
cannam@45 222
cannam@45 223 void
cannam@45 224 Panner::mouseReleaseEvent(QMouseEvent *e)
cannam@45 225 {
cannam@45 226 if (e->button() != Qt::LeftButton) {
cannam@45 227 QGraphicsView::mouseDoubleClickEvent(e);
cannam@45 228 return;
cannam@45 229 }
cannam@45 230
cannam@45 231 if (m_clicked) {
cannam@45 232 mouseMoveEvent(e);
cannam@45 233 }
cannam@45 234
cannam@45 235 m_clicked = false;
cannam@45 236 viewport()->update();
cannam@45 237 }
cannam@45 238
cannam@45 239 void
cannam@45 240 Panner::wheelEvent(QWheelEvent *e)
cannam@45 241 {
Chris@53 242 int d = e->delta();
Chris@53 243 if (d > 0) {
Chris@53 244 while (d > 0) {
Chris@53 245 emit zoomOut();
Chris@53 246 d -= 120;
Chris@53 247 }
cannam@45 248 } else {
Chris@53 249 while (d < 0) {
Chris@53 250 emit zoomIn();
Chris@53 251 d += 120;
Chris@53 252 }
cannam@45 253 }
cannam@45 254 }
cannam@45 255
cannam@45 256 void
cannam@45 257 Panner::moveTo(QPoint p)
cannam@45 258 {
cannam@45 259 QPointF sp = mapToScene(p);
cannam@45 260 QRectF nr = m_pannedRect;
cannam@45 261 double d = sp.x() - nr.center().x();
cannam@45 262 nr.translate(d, 0);
cannam@45 263 slotSetPannedRect(nr);
cannam@45 264 emit pannedRectChanged(m_pannedRect);
cannam@45 265 viewport()->update();
cannam@45 266 }
cannam@45 267