annotate widgets/Pane.cpp @ 4:ce747045a023

* Invalidate cache when model replaced
author Chris Cannam
date Thu, 12 Jan 2006 13:43:15 +0000
parents 2a4f26e85b4c
children 37b110168acf
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@0 5 Chris Cannam, Queen Mary University of London, 2005
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "widgets/Pane.h"
Chris@0 11 #include "base/Layer.h"
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/ZoomConstraint.h"
Chris@0 14 #include "base/RealTime.h"
Chris@0 15 #include "base/Profiler.h"
Chris@0 16
Chris@0 17 #include <QPaintEvent>
Chris@0 18 #include <QPainter>
Chris@0 19 #include <iostream>
Chris@0 20 #include <cmath>
Chris@0 21
Chris@0 22 using std::cerr;
Chris@0 23 using std::endl;
Chris@0 24
Chris@0 25 Pane::Pane(QWidget *w) :
Chris@0 26 View(w, true),
Chris@0 27 m_identifyFeatures(false),
Chris@0 28 m_clickedInRange(false),
Chris@0 29 m_shiftPressed(false),
Chris@0 30 m_centreLineVisible(true)
Chris@0 31 {
Chris@0 32 setObjectName("Pane");
Chris@0 33 setMouseTracking(true);
Chris@0 34 }
Chris@0 35
Chris@0 36 bool
Chris@0 37 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos)
Chris@0 38 {
Chris@0 39 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@0 40 --vi;
Chris@0 41 if (layer != *vi) return false;
Chris@0 42 pos = m_identifyPoint;
Chris@0 43 return m_identifyFeatures;
Chris@0 44 }
Chris@0 45
Chris@0 46 return false;
Chris@0 47 }
Chris@0 48
Chris@0 49 void
Chris@0 50 Pane::setCentreLineVisible(bool visible)
Chris@0 51 {
Chris@0 52 m_centreLineVisible = visible;
Chris@0 53 update();
Chris@0 54 }
Chris@0 55
Chris@0 56 void
Chris@0 57 Pane::paintEvent(QPaintEvent *e)
Chris@0 58 {
Chris@0 59 QPainter paint;
Chris@0 60
Chris@0 61 QRect r(rect());
Chris@0 62
Chris@0 63 if (e) {
Chris@0 64 r = e->rect();
Chris@0 65 }
Chris@0 66 /*
Chris@0 67 paint.begin(this);
Chris@0 68 paint.setClipRect(r);
Chris@0 69
Chris@0 70 if (hasLightBackground()) {
Chris@0 71 paint.setPen(Qt::white);
Chris@0 72 paint.setBrush(Qt::white);
Chris@0 73 } else {
Chris@0 74 paint.setPen(Qt::black);
Chris@0 75 paint.setBrush(Qt::black);
Chris@0 76 }
Chris@0 77 paint.drawRect(r);
Chris@0 78
Chris@0 79 paint.end();
Chris@0 80 */
Chris@0 81 View::paintEvent(e);
Chris@0 82
Chris@0 83 paint.begin(this);
Chris@0 84
Chris@0 85 if (e) {
Chris@0 86 paint.setClipRect(r);
Chris@0 87 }
Chris@0 88
Chris@0 89 for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
Chris@0 90 --vi;
Chris@0 91
Chris@0 92 int sw = (*vi)->getVerticalScaleWidth(paint);
Chris@0 93
Chris@0 94 if (sw > 0 && r.left() < sw) {
Chris@0 95
Chris@0 96 // Profiler profiler("Pane::paintEvent - painting vertical scale", true);
Chris@0 97
Chris@0 98 // std::cerr << "Pane::paintEvent: calling paint.save() in vertical scale block" << std::endl;
Chris@0 99 paint.save();
Chris@0 100
Chris@0 101 paint.setPen(Qt::black);
Chris@0 102 paint.setBrush(Qt::white);
Chris@0 103 paint.drawRect(0, 0, sw, height());
Chris@0 104
Chris@0 105 paint.setBrush(Qt::NoBrush);
Chris@0 106 (*vi)->paintVerticalScale(paint, QRect(0, 0, sw, height()));
Chris@0 107
Chris@0 108 paint.restore();
Chris@0 109 }
Chris@0 110
Chris@0 111 if (m_identifyFeatures) {
Chris@0 112 QRect descRect = (*vi)->getFeatureDescriptionRect(paint,
Chris@0 113 m_identifyPoint);
Chris@0 114 if (descRect.width() > 0 && descRect.height() > 0 &&
Chris@0 115 r.left() + r.width() >= width() - descRect.width() &&
Chris@0 116 r.top() < descRect.height()) {
Chris@0 117
Chris@0 118 // Profiler profiler("Pane::paintEvent - painting local feature description", true);
Chris@0 119
Chris@0 120 // std::cerr << "Pane::paintEvent: calling paint.save() in feature description block" << std::endl;
Chris@0 121 paint.save();
Chris@0 122
Chris@0 123 paint.setPen(Qt::black);
Chris@0 124 paint.setBrush(Qt::white);
Chris@0 125
Chris@0 126 QRect rect(width() - descRect.width() - 1, 0,
Chris@0 127 descRect.width(), descRect.height());
Chris@0 128
Chris@0 129 paint.drawRect(rect);
Chris@0 130
Chris@0 131 paint.setBrush(Qt::NoBrush);
Chris@0 132 (*vi)->paintLocalFeatureDescription(paint, rect, m_identifyPoint);
Chris@0 133
Chris@0 134 paint.restore();
Chris@0 135 }
Chris@0 136 }
Chris@0 137
Chris@0 138 break;
Chris@0 139 }
Chris@0 140
Chris@0 141 if (m_centreLineVisible) {
Chris@0 142
Chris@0 143 if (hasLightBackground()) {
Chris@0 144 paint.setPen(QColor(50, 50, 50));
Chris@0 145 } else {
Chris@0 146 paint.setPen(QColor(200, 200, 200));
Chris@0 147 }
Chris@0 148 paint.setBrush(Qt::NoBrush);
Chris@0 149 paint.drawLine(width() / 2, 0, width() / 2, height() - 1);
Chris@0 150
Chris@0 151 // QFont font(paint.font());
Chris@0 152 // font.setBold(true);
Chris@0 153 // paint.setFont(font);
Chris@0 154
Chris@0 155 int sampleRate = getModelsSampleRate();
Chris@0 156 int y = height() - paint.fontMetrics().height()
Chris@0 157 + paint.fontMetrics().ascent() - 6;
Chris@0 158
Chris@0 159 LayerList::iterator vi = m_layers.end();
Chris@0 160
Chris@0 161 if (vi != m_layers.begin()) {
Chris@0 162
Chris@0 163 switch ((*--vi)->getPreferredFrameCountPosition()) {
Chris@0 164
Chris@0 165 case Layer::PositionTop:
Chris@0 166 y = paint.fontMetrics().ascent() + 6;
Chris@0 167 break;
Chris@0 168
Chris@0 169 case Layer::PositionMiddle:
Chris@0 170 y = (height() - paint.fontMetrics().height()) / 2
Chris@0 171 + paint.fontMetrics().ascent();
Chris@0 172 break;
Chris@0 173
Chris@0 174 case Layer::PositionBottom:
Chris@0 175 // y already set correctly
Chris@0 176 break;
Chris@0 177 }
Chris@0 178 }
Chris@0 179
Chris@0 180 if (sampleRate) {
Chris@0 181
Chris@0 182 QString text(QString::fromStdString
Chris@0 183 (RealTime::frame2RealTime
Chris@0 184 (m_centreFrame, sampleRate).toText(true)));
Chris@0 185
Chris@0 186 int tw = paint.fontMetrics().width(text);
Chris@0 187 int x = width()/2 - 4 - tw;
Chris@0 188
Chris@0 189 if (hasLightBackground()) {
Chris@0 190 paint.setPen(palette().background().color());
Chris@0 191 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 192 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 193 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 194 paint.drawText(x + dx, y + dy, text);
Chris@0 195 }
Chris@0 196 }
Chris@0 197 paint.setPen(QColor(50, 50, 50));
Chris@0 198 } else {
Chris@0 199 paint.setPen(QColor(200, 200, 200));
Chris@0 200 }
Chris@0 201
Chris@0 202 paint.drawText(x, y, text);
Chris@0 203 }
Chris@0 204
Chris@0 205 QString text = QString("%1").arg(m_centreFrame);
Chris@0 206
Chris@0 207 int tw = paint.fontMetrics().width(text);
Chris@0 208 int x = width()/2 + 4;
Chris@0 209
Chris@0 210 if (hasLightBackground()) {
Chris@0 211 paint.setPen(palette().background().color());
Chris@0 212 for (int dx = -1; dx <= 1; ++dx) {
Chris@0 213 for (int dy = -1; dy <= 1; ++dy) {
Chris@0 214 if ((dx && dy) || !(dx || dy)) continue;
Chris@0 215 paint.drawText(x + dx, y + dy, text);
Chris@0 216 }
Chris@0 217 }
Chris@0 218 paint.setPen(QColor(50, 50, 50));
Chris@0 219 } else {
Chris@0 220 paint.setPen(QColor(200, 200, 200));
Chris@0 221 }
Chris@0 222 paint.drawText(x, y, text);
Chris@0 223 }
Chris@0 224
Chris@0 225 if (m_clickedInRange && m_shiftPressed) {
Chris@0 226 paint.setPen(Qt::blue);
Chris@0 227 paint.drawRect(m_clickPos.x(), m_clickPos.y(),
Chris@0 228 m_mousePos.x() - m_clickPos.x(),
Chris@0 229 m_mousePos.y() - m_clickPos.y());
Chris@0 230 }
Chris@0 231
Chris@0 232 paint.end();
Chris@0 233 }
Chris@0 234
Chris@0 235 void
Chris@0 236 Pane::mousePressEvent(QMouseEvent *e)
Chris@0 237 {
Chris@0 238 m_clickPos = e->pos();
Chris@0 239 m_clickedInRange = true;
Chris@0 240 m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
Chris@0 241 m_dragCentreFrame = m_centreFrame;
Chris@0 242
Chris@0 243 emit paneInteractedWith();
Chris@0 244 }
Chris@0 245
Chris@0 246 void
Chris@0 247 Pane::mouseReleaseEvent(QMouseEvent *e)
Chris@0 248 {
Chris@0 249 if (m_clickedInRange) {
Chris@0 250 mouseMoveEvent(e);
Chris@0 251 }
Chris@0 252 if (m_shiftPressed) {
Chris@0 253
Chris@0 254 int x0 = std::min(m_clickPos.x(), m_mousePos.x());
Chris@0 255 int x1 = std::max(m_clickPos.x(), m_mousePos.x());
Chris@0 256 int w = x1 - x0;
Chris@0 257
Chris@0 258 long newStartFrame = getStartFrame() + m_zoomLevel * x0;
Chris@0 259
Chris@0 260 if (newStartFrame <= -long(width() * m_zoomLevel)) {
Chris@0 261 newStartFrame = -long(width() * m_zoomLevel) + 1;
Chris@0 262 }
Chris@0 263
Chris@0 264 if (newStartFrame >= long(getModelsEndFrame())) {
Chris@0 265 newStartFrame = getModelsEndFrame() - 1;
Chris@0 266 }
Chris@0 267
Chris@0 268 float ratio = float(w) / float(width());
Chris@0 269 // std::cerr << "ratio: " << ratio << std::endl;
Chris@0 270 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
Chris@0 271 if (newZoomLevel < 1) newZoomLevel = 1;
Chris@0 272
Chris@0 273 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
Chris@0 274 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
Chris@0 275 setStartFrame(newStartFrame);
Chris@0 276
Chris@0 277 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
Chris@0 278 // update();
Chris@0 279 }
Chris@0 280 m_clickedInRange = false;
Chris@0 281
Chris@0 282 emit paneInteractedWith();
Chris@0 283 }
Chris@0 284
Chris@0 285 void
Chris@0 286 Pane::mouseMoveEvent(QMouseEvent *e)
Chris@0 287 {
Chris@0 288 if (!m_clickedInRange) {
Chris@0 289
Chris@0 290 // std::cerr << "Pane: calling identifyLocalFeatures" << std::endl;
Chris@0 291
Chris@0 292 //!!! identifyLocalFeatures(true, e->x(), e->y());
Chris@0 293
Chris@0 294 bool previouslyIdentifying = m_identifyFeatures;
Chris@0 295 QPoint prevPoint = m_identifyPoint;
Chris@0 296
Chris@0 297 m_identifyFeatures = true;
Chris@0 298 m_identifyPoint = e->pos();
Chris@0 299
Chris@0 300 if (m_identifyFeatures != previouslyIdentifying ||
Chris@0 301 m_identifyPoint != prevPoint) {
Chris@0 302 update();
Chris@0 303 }
Chris@0 304
Chris@0 305 } else if (m_shiftPressed) {
Chris@0 306
Chris@0 307 m_mousePos = e->pos();
Chris@0 308 update();
Chris@0 309
Chris@0 310 } else {
Chris@0 311
Chris@0 312 long xoff = int(e->x()) - int(m_clickPos.x());
Chris@0 313 long frameOff = xoff * m_zoomLevel;
Chris@0 314
Chris@0 315 size_t newCentreFrame = m_dragCentreFrame;
Chris@0 316
Chris@0 317 if (frameOff < 0) {
Chris@0 318 newCentreFrame -= frameOff;
Chris@0 319 } else if (newCentreFrame >= size_t(frameOff)) {
Chris@0 320 newCentreFrame -= frameOff;
Chris@0 321 } else {
Chris@0 322 newCentreFrame = 0;
Chris@0 323 }
Chris@0 324
Chris@0 325 if (newCentreFrame >= getModelsEndFrame()) {
Chris@0 326 newCentreFrame = getModelsEndFrame();
Chris@0 327 if (newCentreFrame > 0) --newCentreFrame;
Chris@0 328 }
Chris@0 329
Chris@0 330 if (std::max(m_centreFrame, newCentreFrame) -
Chris@0 331 std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
Chris@0 332 setCentreFrame(newCentreFrame);
Chris@0 333 }
Chris@0 334 }
Chris@0 335 }
Chris@0 336
Chris@0 337 void
Chris@0 338 Pane::mouseDoubleClickEvent(QMouseEvent *e)
Chris@0 339 {
Chris@0 340 std::cerr << "mouseDoubleClickEvent" << std::endl;
Chris@0 341 }
Chris@0 342
Chris@0 343 void
Chris@0 344 Pane::leaveEvent(QEvent *)
Chris@0 345 {
Chris@0 346 bool previouslyIdentifying = m_identifyFeatures;
Chris@0 347 m_identifyFeatures = false;
Chris@0 348 if (previouslyIdentifying) update();
Chris@0 349 }
Chris@0 350
Chris@0 351 void
Chris@0 352 Pane::wheelEvent(QWheelEvent *e)
Chris@0 353 {
Chris@0 354 //std::cerr << "wheelEvent, delta " << e->delta() << std::endl;
Chris@0 355
Chris@0 356 int newZoomLevel = m_zoomLevel;
Chris@0 357
Chris@0 358 int count = e->delta();
Chris@0 359
Chris@0 360 if (count > 0) {
Chris@0 361 if (count >= 120) count /= 120;
Chris@0 362 else count = 1;
Chris@0 363 }
Chris@0 364
Chris@0 365 if (count < 0) {
Chris@0 366 if (count <= -120) count /= 120;
Chris@0 367 else count = -1;
Chris@0 368 }
Chris@0 369
Chris@0 370 while (count > 0) {
Chris@0 371 if (newZoomLevel <= 2) {
Chris@0 372 newZoomLevel = 1;
Chris@0 373 break;
Chris@0 374 }
Chris@0 375 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@0 376 ZoomConstraint::RoundDown);
Chris@0 377 --count;
Chris@0 378 }
Chris@0 379
Chris@0 380 while (count < 0) {
Chris@0 381 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@0 382 ZoomConstraint::RoundUp);
Chris@0 383 ++count;
Chris@0 384 }
Chris@0 385
Chris@0 386 if (newZoomLevel != m_zoomLevel) {
Chris@0 387 setZoomLevel(newZoomLevel);
Chris@0 388 }
Chris@0 389
Chris@0 390 emit paneInteractedWith();
Chris@0 391 }
Chris@0 392
Chris@0 393
Chris@0 394 #ifdef INCLUDE_MOCFILES
Chris@0 395 #include "Pane.moc.cpp"
Chris@0 396 #endif
Chris@0 397