annotate src/panned.cpp @ 679:ad3e5693cb76 scale-alternative

Alternative, and much simpler, approach to scaling
author Chris Cannam
date Thu, 06 Dec 2018 15:55:20 +0000
parents ce29dc775650
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
cannam@45 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 "panned.h"
Chris@131 19 #include "debug.h"
cannam@45 20
cannam@45 21 #include <QScrollBar>
Chris@53 22 #include <QWheelEvent>
Chris@168 23 #include <QTimer>
Chris@168 24
Chris@168 25 #include <cmath>
cannam@45 26
cannam@45 27 #include <iostream>
cannam@45 28
Chris@168 29 Panned::Panned() :
Chris@168 30 m_dragging(false)
cannam@45 31 {
Chris@168 32 m_dragTimer = new QTimer(this);
Chris@168 33 m_dragTimerMs = 50;
Chris@168 34 connect(m_dragTimer, SIGNAL(timeout()), this, SLOT(dragTimerTimeout()));
Chris@56 35 setRenderHints(QPainter::Antialiasing |
Chris@56 36 QPainter::TextAntialiasing);
Chris@679 37
Chris@679 38 double baseEm;
Chris@679 39 #ifdef Q_OS_MAC
Chris@679 40 baseEm = 17.0;
Chris@679 41 #else
Chris@679 42 baseEm = 15.0;
Chris@679 43 #endif
Chris@679 44 double em = QFontMetrics(QFont()).height();
Chris@679 45 double ratio = em / baseEm;
Chris@679 46
Chris@679 47 QMatrix m = matrix();
Chris@679 48 m.scale(ratio, ratio);
Chris@679 49 setMatrix(m);
cannam@45 50 }
cannam@45 51
cannam@45 52 void
cannam@45 53 Panned::resizeEvent(QResizeEvent *ev)
cannam@45 54 {
Chris@131 55 DEBUG << "Panned::resizeEvent()" << endl;
Chris@131 56
Chris@60 57 QPointF nearpt = mapToScene(0, 0);
Chris@60 58 QPointF farpt = mapToScene(width(), height());
Chris@60 59 QSizeF sz(farpt.x()-nearpt.x(), farpt.y()-nearpt.y());
Chris@60 60 QRectF pr(nearpt, sz);
cannam@45 61
Chris@132 62 QGraphicsView::resizeEvent(ev);
Chris@132 63
cannam@45 64 if (pr != m_pannedRect) {
Chris@132 65 DEBUG << "Panned: setting panned rect to " << pr << endl;
cannam@45 66 m_pannedRect = pr;
Chris@133 67 centerOn(pr.center());
Chris@133 68 emit pannedRectChanged(pr);
Chris@133 69 }
Chris@133 70 }
Chris@133 71
Chris@133 72 void
Chris@133 73 Panned::setScene(QGraphicsScene *s)
Chris@133 74 {
Chris@133 75 if (!scene()) {
Chris@133 76 QGraphicsView::setScene(s);
Chris@133 77 return;
Chris@133 78 }
Chris@133 79
Chris@133 80 QPointF nearpt = mapToScene(0, 0);
Chris@133 81 QPointF farpt = mapToScene(width(), height());
Chris@133 82 QSizeF sz(farpt.x()-nearpt.x(), farpt.y()-nearpt.y());
Chris@133 83 QRectF pr(nearpt, sz);
Chris@133 84
Chris@133 85 QGraphicsView::setScene(s);
Chris@133 86
Chris@133 87 DEBUG << "Panned::setScene: pr = " << pr << ", sceneRect = " << sceneRect() << endl;
Chris@133 88
Chris@133 89 if (scene() && sceneRect().intersects(pr)) {
Chris@133 90 DEBUG << "Panned::setScene: restoring old rect " << pr << endl;
Chris@133 91 m_pannedRect = pr;
Chris@133 92 centerOn(pr.center());
cannam@45 93 emit pannedRectChanged(pr);
cannam@45 94 }
cannam@45 95 }
cannam@45 96
cannam@45 97 void
cannam@45 98 Panned::paintEvent(QPaintEvent *e)
cannam@45 99 {
cannam@45 100 QGraphicsView::paintEvent(e);
cannam@45 101 }
cannam@45 102
cannam@45 103 void
Chris@671 104 Panned::drawForeground(QPainter *, const QRectF &)
cannam@45 105 {
Chris@60 106 QPointF nearpt = mapToScene(0, 0);
Chris@60 107 QPointF farpt = mapToScene(width(), height());
Chris@60 108 QSizeF sz(farpt.x()-nearpt.x(), farpt.y()-nearpt.y());
Chris@60 109 QRectF pr(nearpt, sz);
cannam@45 110
cannam@45 111 if (pr != m_pannedRect) {
Chris@133 112 DEBUG << "Panned::drawForeground: visible rect " << pr << " differs from panned rect " << m_pannedRect << ", updating panned rect" <<endl;
cannam@45 113 if (pr.x() != m_pannedRect.x()) emit pannedContentsScrolled();
cannam@45 114 m_pannedRect = pr;
cannam@45 115 emit pannedRectChanged(pr);
cannam@45 116 }
cannam@45 117 }
cannam@45 118
cannam@45 119 void
Chris@53 120 Panned::zoomIn()
Chris@53 121 {
Chris@53 122 QMatrix m = matrix();
Chris@53 123 m.scale(1.0 / 1.1, 1.0 / 1.1);
Chris@53 124 setMatrix(m);
Chris@53 125 }
Chris@53 126
Chris@53 127 void
Chris@53 128 Panned::zoomOut()
Chris@53 129 {
Chris@53 130 QMatrix m = matrix();
Chris@53 131 m.scale(1.1, 1.1);
Chris@53 132 setMatrix(m);
Chris@53 133 }
Chris@53 134
Chris@53 135 void
cannam@45 136 Panned::slotSetPannedRect(QRectF pr)
cannam@45 137 {
cannam@45 138 centerOn(pr.center());
cannam@45 139 // setSceneRect(pr);
cannam@45 140 // m_pannedRect = pr;
cannam@45 141 }
cannam@45 142
cannam@45 143 void
cannam@45 144 Panned::wheelEvent(QWheelEvent *ev)
cannam@45 145 {
Chris@53 146 if (ev->modifiers() & Qt::ControlModifier) {
Chris@53 147 int d = ev->delta();
Chris@53 148 if (d > 0) {
Chris@53 149 while (d > 0) {
Chris@53 150 zoomOut();
Chris@53 151 d -= 120;
Chris@53 152 }
Chris@53 153 } else {
Chris@53 154 while (d < 0) {
Chris@53 155 zoomIn();
Chris@53 156 d += 120;
Chris@53 157 }
Chris@53 158 }
Chris@53 159 } else {
Chris@53 160 emit wheelEventReceived(ev);
Chris@53 161 QGraphicsView::wheelEvent(ev);
Chris@53 162 }
cannam@45 163 }
cannam@45 164
cannam@45 165 void
cannam@45 166 Panned::slotEmulateWheelEvent(QWheelEvent *ev)
cannam@45 167 {
cannam@45 168 QGraphicsView::wheelEvent(ev);
cannam@45 169 }
cannam@45 170
cannam@45 171 void
Chris@168 172 Panned::mousePressEvent(QMouseEvent *ev)
Chris@168 173 {
Chris@168 174 if (dragMode() != QGraphicsView::ScrollHandDrag ||
Chris@168 175 ev->button() != Qt::LeftButton) {
Chris@168 176 QGraphicsView::mousePressEvent(ev);
Chris@168 177 return;
Chris@168 178 }
Chris@168 179
Chris@168 180 DEBUG << "Panned::mousePressEvent: have left button in drag mode" << endl;
Chris@168 181
Chris@168 182 setDragMode(QGraphicsView::NoDrag);
Chris@168 183 QGraphicsView::mousePressEvent(ev);
Chris@168 184 setDragMode(QGraphicsView::ScrollHandDrag);
Chris@168 185
Chris@168 186 if (!ev->isAccepted()) {
Chris@168 187 ev->accept();
Chris@168 188 m_dragging = true;
Chris@168 189 m_lastDragPos = ev->pos();
Chris@403 190 m_lastDragStart = ev->pos();
Chris@168 191 m_lastOrigin = QPoint(horizontalScrollBar()->value(),
Chris@168 192 verticalScrollBar()->value());
Chris@168 193 m_velocity = QPointF(0, 0);
Chris@168 194 m_dragTimer->start(m_dragTimerMs);
Chris@403 195 m_dragDirection = UnknownDrag;
Chris@403 196 }
Chris@403 197 }
Chris@403 198
Chris@403 199 void
Chris@403 200 Panned::updateDragDirection(QPoint pos)
Chris@403 201 {
Chris@403 202 if (m_dragDirection == FreeDrag) {
Chris@403 203 return;
Chris@168 204 }
Chris@168 205
Chris@403 206 QPoint overall = pos - m_lastDragStart;
Chris@403 207
Chris@403 208 int smallThreshold = 10;
Chris@403 209 int largeThreshold = 30;
Chris@403 210 int dx = qAbs(overall.x());
Chris@403 211 int dy = qAbs(overall.y());
Chris@403 212
Chris@403 213 switch (m_dragDirection) {
Chris@403 214
Chris@403 215 case UnknownDrag:
Chris@403 216 if (dx > smallThreshold) {
Chris@403 217 if (dy > smallThreshold) {
Chris@403 218 m_dragDirection = FreeDrag;
Chris@403 219 } else {
Chris@403 220 m_dragDirection = HorizontalDrag;
Chris@403 221 }
Chris@403 222 } else if (dy > smallThreshold) {
Chris@403 223 m_dragDirection = VerticalDrag;
Chris@403 224 }
Chris@403 225 break;
Chris@403 226
Chris@403 227 case HorizontalDrag:
Chris@403 228 if (dy > largeThreshold) {
Chris@403 229 m_dragDirection = FreeDrag;
Chris@403 230 }
Chris@403 231 break;
Chris@403 232
Chris@403 233 case VerticalDrag:
Chris@403 234 if (dx > largeThreshold) {
Chris@403 235 m_dragDirection = FreeDrag;
Chris@403 236 }
Chris@403 237 break;
Chris@671 238
Chris@671 239 case FreeDrag:
Chris@671 240 // stick with it
Chris@671 241 break;
Chris@403 242 };
Chris@168 243 }
Chris@168 244
Chris@168 245 void
Chris@168 246 Panned::mouseMoveEvent(QMouseEvent *ev)
Chris@168 247 {
Chris@168 248 if (!m_dragging) {
Chris@168 249 QGraphicsView::mouseMoveEvent(ev);
Chris@168 250 return;
Chris@168 251 }
Chris@168 252 DEBUG << "Panned::mouseMoveEvent: dragging" << endl;
Chris@168 253 ev->accept();
Chris@403 254 updateDragDirection(ev->pos());
Chris@168 255 QScrollBar *hBar = horizontalScrollBar();
Chris@168 256 QScrollBar *vBar = verticalScrollBar();
Chris@168 257 QPoint delta = ev->pos() - m_lastDragPos;
Chris@403 258 if (m_dragDirection != VerticalDrag) {
Chris@403 259 hBar->setValue(hBar->value() +
Chris@403 260 (isRightToLeft() ? delta.x() : -delta.x()));
Chris@403 261 }
Chris@403 262 if (m_dragDirection != HorizontalDrag) {
Chris@403 263 vBar->setValue(vBar->value() - delta.y());
Chris@403 264 }
Chris@168 265 m_lastDragPos = ev->pos();
Chris@168 266 }
Chris@168 267
Chris@168 268 void
Chris@168 269 Panned::mouseReleaseEvent(QMouseEvent *ev)
Chris@168 270 {
Chris@168 271 if (!m_dragging) {
Chris@168 272 QGraphicsView::mouseReleaseEvent(ev);
Chris@168 273 return;
Chris@168 274 }
Chris@168 275 DEBUG << "Panned::mouseReleaseEvent: dragging" << endl;
Chris@168 276 ev->accept();
Chris@168 277 m_dragging = false;
Chris@168 278 }
Chris@168 279
Chris@168 280 void
Chris@168 281 Panned::dragTimerTimeout()
Chris@168 282 {
Chris@168 283 QPoint origin = QPoint(horizontalScrollBar()->value(),
Chris@168 284 verticalScrollBar()->value());
Chris@168 285 if (m_dragging) {
Chris@168 286 m_velocity = QPointF
Chris@168 287 (float(origin.x() - m_lastOrigin.x()) / m_dragTimerMs,
Chris@168 288 float(origin.y() - m_lastOrigin.y()) / m_dragTimerMs);
Chris@168 289 m_lastOrigin = origin;
Chris@168 290 DEBUG << "Panned::dragTimerTimeout: velocity = " << m_velocity << endl;
Chris@168 291 } else {
Chris@168 292 if (origin == m_lastOrigin) {
Chris@168 293 m_dragTimer->stop();
Chris@168 294 }
Chris@168 295 float x = m_velocity.x(), y = m_velocity.y();
Chris@168 296 if (fabsf(x) > 1.0/m_dragTimerMs) x = x * 0.9f;
Chris@168 297 else x = 0.f;
Chris@168 298 if (fabsf(y) > 1.0/m_dragTimerMs) y = y * 0.9f;
Chris@168 299 else y = 0.f;
Chris@168 300 m_velocity = QPointF(x, y);
Chris@168 301 DEBUG << "Panned::dragTimerTimeout: velocity adjusted to " << m_velocity << endl;
Chris@168 302 m_lastOrigin = origin;
Chris@168 303 //!!! need to store origin in floats
Chris@403 304 if (m_dragDirection != VerticalDrag) {
Chris@403 305 horizontalScrollBar()->setValue(m_lastOrigin.x() +
Chris@403 306 m_velocity.x() * m_dragTimerMs);
Chris@403 307 }
Chris@403 308 if (m_dragDirection != HorizontalDrag) {
Chris@403 309 verticalScrollBar()->setValue(m_lastOrigin.y() +
Chris@403 310 m_velocity.y() * m_dragTimerMs);
Chris@403 311 }
Chris@168 312 }
Chris@168 313 }
Chris@168 314
Chris@168 315 void
cannam@45 316 Panned::leaveEvent(QEvent *)
cannam@45 317 {
cannam@45 318 emit mouseLeaves();
cannam@45 319 }