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