annotate view/View.cpp @ 640:c6d705bf1672

Merge from branch "qt5". This revision actually builds with Qt4 (late releases) or Qt5, though it will warn on configure with Qt4.
author Chris Cannam
date Tue, 14 May 2013 12:36:43 +0100
parents c3593bb2de6b
children 0aea4b9e4c3d
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@127 7 This file copyright 2006 Chris Cannam.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@128 16 #include "View.h"
Chris@128 17 #include "layer/Layer.h"
Chris@128 18 #include "data/model/Model.h"
Chris@127 19 #include "base/ZoomConstraint.h"
Chris@127 20 #include "base/Profiler.h"
Chris@278 21 #include "base/Pitch.h"
Chris@338 22 #include "base/Preferences.h"
Chris@127 23
Chris@301 24 #include "layer/TimeRulerLayer.h"
Chris@287 25 #include "layer/SingleColourLayer.h"
Chris@301 26 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
Chris@301 27 #include "data/model/RangeSummarisableTimeValueModel.h"
Chris@127 28
Chris@127 29 #include <QPainter>
Chris@127 30 #include <QPaintEvent>
Chris@127 31 #include <QRect>
Chris@127 32 #include <QApplication>
Chris@226 33 #include <QProgressDialog>
Chris@316 34 #include <QTextStream>
Chris@338 35 #include <QFont>
Chris@583 36 #include <QMessageBox>
Chris@127 37
Chris@127 38 #include <iostream>
Chris@127 39 #include <cassert>
Chris@520 40 #include <cmath>
Chris@127 41
Chris@545 42 #include <unistd.h>
Chris@545 43
Chris@127 44 //#define DEBUG_VIEW_WIDGET_PAINT 1
Chris@127 45
Chris@127 46 using std::cerr;
Chris@127 47 using std::endl;
Chris@127 48
Chris@127 49 View::View(QWidget *w, bool showProgress) :
Chris@127 50 QFrame(w),
Chris@127 51 m_centreFrame(0),
Chris@127 52 m_zoomLevel(1024),
Chris@127 53 m_followPan(true),
Chris@127 54 m_followZoom(true),
Chris@127 55 m_followPlay(PlaybackScrollPage),
Chris@153 56 m_playPointerFrame(0),
Chris@127 57 m_showProgress(showProgress),
Chris@127 58 m_cache(0),
Chris@127 59 m_cacheCentreFrame(0),
Chris@127 60 m_cacheZoomLevel(1024),
Chris@127 61 m_selectionCached(false),
Chris@127 62 m_deleting(false),
Chris@127 63 m_haveSelectedLayer(false),
Chris@127 64 m_manager(0),
Chris@127 65 m_propertyContainer(new ViewPropertyContainer(this))
Chris@127 66 {
Chris@587 67 SVDEBUG << "View::View(" << this << ")" << endl;
Chris@127 68 }
Chris@127 69
Chris@127 70 View::~View()
Chris@127 71 {
Chris@587 72 // SVDEBUG << "View::~View(" << this << ")" << endl;
Chris@127 73
Chris@127 74 m_deleting = true;
Chris@127 75 delete m_propertyContainer;
Chris@127 76 }
Chris@127 77
Chris@127 78 PropertyContainer::PropertyList
Chris@127 79 View::getProperties() const
Chris@127 80 {
Chris@127 81 PropertyContainer::PropertyList list;
Chris@127 82 list.push_back("Global Scroll");
Chris@127 83 list.push_back("Global Zoom");
Chris@127 84 list.push_back("Follow Playback");
Chris@127 85 return list;
Chris@127 86 }
Chris@127 87
Chris@127 88 QString
Chris@127 89 View::getPropertyLabel(const PropertyName &pn) const
Chris@127 90 {
Chris@127 91 if (pn == "Global Scroll") return tr("Global Scroll");
Chris@127 92 if (pn == "Global Zoom") return tr("Global Zoom");
Chris@127 93 if (pn == "Follow Playback") return tr("Follow Playback");
Chris@127 94 return "";
Chris@127 95 }
Chris@127 96
Chris@127 97 PropertyContainer::PropertyType
Chris@127 98 View::getPropertyType(const PropertyContainer::PropertyName &name) const
Chris@127 99 {
Chris@127 100 if (name == "Global Scroll") return PropertyContainer::ToggleProperty;
Chris@127 101 if (name == "Global Zoom") return PropertyContainer::ToggleProperty;
Chris@127 102 if (name == "Follow Playback") return PropertyContainer::ValueProperty;
Chris@127 103 return PropertyContainer::InvalidProperty;
Chris@127 104 }
Chris@127 105
Chris@127 106 int
Chris@127 107 View::getPropertyRangeAndValue(const PropertyContainer::PropertyName &name,
Chris@216 108 int *min, int *max, int *deflt) const
Chris@127 109 {
Chris@216 110 if (deflt) *deflt = 1;
Chris@127 111 if (name == "Global Scroll") return m_followPan;
Chris@127 112 if (name == "Global Zoom") return m_followZoom;
Chris@127 113 if (name == "Follow Playback") {
Chris@127 114 if (min) *min = 0;
Chris@127 115 if (max) *max = 2;
Chris@216 116 if (deflt) *deflt = int(PlaybackScrollPage);
Chris@127 117 return int(m_followPlay);
Chris@127 118 }
Chris@127 119 if (min) *min = 0;
Chris@127 120 if (max) *max = 0;
Chris@216 121 if (deflt) *deflt = 0;
Chris@127 122 return 0;
Chris@127 123 }
Chris@127 124
Chris@127 125 QString
Chris@127 126 View::getPropertyValueLabel(const PropertyContainer::PropertyName &name,
Chris@127 127 int value) const
Chris@127 128 {
Chris@127 129 if (name == "Follow Playback") {
Chris@127 130 switch (value) {
Chris@127 131 default:
Chris@127 132 case 0: return tr("Scroll");
Chris@127 133 case 1: return tr("Page");
Chris@127 134 case 2: return tr("Off");
Chris@127 135 }
Chris@127 136 }
Chris@127 137 return tr("<unknown>");
Chris@127 138 }
Chris@127 139
Chris@127 140 void
Chris@127 141 View::setProperty(const PropertyContainer::PropertyName &name, int value)
Chris@127 142 {
Chris@127 143 if (name == "Global Scroll") {
Chris@127 144 setFollowGlobalPan(value != 0);
Chris@127 145 } else if (name == "Global Zoom") {
Chris@127 146 setFollowGlobalZoom(value != 0);
Chris@127 147 } else if (name == "Follow Playback") {
Chris@127 148 switch (value) {
Chris@127 149 default:
Chris@127 150 case 0: setPlaybackFollow(PlaybackScrollContinuous); break;
Chris@127 151 case 1: setPlaybackFollow(PlaybackScrollPage); break;
Chris@127 152 case 2: setPlaybackFollow(PlaybackIgnore); break;
Chris@127 153 }
Chris@127 154 }
Chris@127 155 }
Chris@127 156
Chris@127 157 size_t
Chris@127 158 View::getPropertyContainerCount() const
Chris@127 159 {
Chris@127 160 return m_layers.size() + 1; // the 1 is for me
Chris@127 161 }
Chris@127 162
Chris@127 163 const PropertyContainer *
Chris@127 164 View::getPropertyContainer(size_t i) const
Chris@127 165 {
Chris@127 166 return (const PropertyContainer *)(((View *)this)->
Chris@127 167 getPropertyContainer(i));
Chris@127 168 }
Chris@127 169
Chris@127 170 PropertyContainer *
Chris@127 171 View::getPropertyContainer(size_t i)
Chris@127 172 {
Chris@127 173 if (i == 0) return m_propertyContainer;
Chris@127 174 return m_layers[i-1];
Chris@127 175 }
Chris@127 176
Chris@127 177 bool
Chris@127 178 View::getValueExtents(QString unit, float &min, float &max, bool &log) const
Chris@127 179 {
Chris@127 180 bool have = false;
Chris@127 181
Chris@127 182 for (LayerList::const_iterator i = m_layers.begin();
Chris@127 183 i != m_layers.end(); ++i) {
Chris@127 184
Chris@127 185 QString layerUnit;
Chris@127 186 float layerMin = 0.0, layerMax = 0.0;
Chris@127 187 float displayMin = 0.0, displayMax = 0.0;
Chris@127 188 bool layerLog = false;
Chris@127 189
Chris@127 190 if ((*i)->getValueExtents(layerMin, layerMax, layerLog, layerUnit) &&
Chris@127 191 layerUnit.toLower() == unit.toLower()) {
Chris@127 192
Chris@127 193 if ((*i)->getDisplayExtents(displayMin, displayMax)) {
Chris@127 194
Chris@127 195 min = displayMin;
Chris@127 196 max = displayMax;
Chris@127 197 log = layerLog;
Chris@127 198 have = true;
Chris@127 199 break;
Chris@127 200
Chris@127 201 } else {
Chris@127 202
Chris@127 203 if (!have || layerMin < min) min = layerMin;
Chris@127 204 if (!have || layerMax > max) max = layerMax;
Chris@127 205 if (layerLog) log = true;
Chris@127 206 have = true;
Chris@127 207 }
Chris@127 208 }
Chris@127 209 }
Chris@127 210
Chris@127 211 return have;
Chris@127 212 }
Chris@127 213
Chris@127 214 int
Chris@127 215 View::getTextLabelHeight(const Layer *layer, QPainter &paint) const
Chris@127 216 {
Chris@127 217 std::map<int, Layer *> sortedLayers;
Chris@127 218
Chris@127 219 for (LayerList::const_iterator i = m_layers.begin();
Chris@127 220 i != m_layers.end(); ++i) {
Chris@127 221 if ((*i)->needsTextLabelHeight()) {
Chris@127 222 sortedLayers[getObjectExportId(*i)] = *i;
Chris@127 223 }
Chris@127 224 }
Chris@127 225
Chris@127 226 int y = 15 + paint.fontMetrics().ascent();
Chris@127 227
Chris@127 228 for (std::map<int, Layer *>::const_iterator i = sortedLayers.begin();
Chris@127 229 i != sortedLayers.end(); ++i) {
Chris@127 230 if (i->second == layer) return y;
Chris@127 231 y += paint.fontMetrics().height();
Chris@127 232 }
Chris@127 233
Chris@127 234 return y;
Chris@127 235 }
Chris@127 236
Chris@127 237 void
Chris@127 238 View::propertyContainerSelected(View *client, PropertyContainer *pc)
Chris@127 239 {
Chris@127 240 if (client != this) return;
Chris@127 241
Chris@127 242 if (pc == m_propertyContainer) {
Chris@127 243 if (m_haveSelectedLayer) {
Chris@127 244 m_haveSelectedLayer = false;
Chris@127 245 update();
Chris@127 246 }
Chris@127 247 return;
Chris@127 248 }
Chris@127 249
Chris@127 250 delete m_cache;
Chris@127 251 m_cache = 0;
Chris@127 252
Chris@127 253 Layer *selectedLayer = 0;
Chris@127 254
Chris@127 255 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 256 if (*i == pc) {
Chris@127 257 selectedLayer = *i;
Chris@127 258 m_layers.erase(i);
Chris@127 259 break;
Chris@127 260 }
Chris@127 261 }
Chris@127 262
Chris@127 263 if (selectedLayer) {
Chris@127 264 m_haveSelectedLayer = true;
Chris@127 265 m_layers.push_back(selectedLayer);
Chris@127 266 update();
Chris@127 267 } else {
Chris@127 268 m_haveSelectedLayer = false;
Chris@127 269 }
Chris@298 270
Chris@298 271 emit propertyContainerSelected(pc);
Chris@127 272 }
Chris@127 273
Chris@127 274 void
Chris@127 275 View::toolModeChanged()
Chris@127 276 {
Chris@587 277 // SVDEBUG << "View::toolModeChanged(" << m_manager->getToolMode() << ")" << endl;
Chris@127 278 }
Chris@127 279
Chris@133 280 void
Chris@133 281 View::overlayModeChanged()
Chris@133 282 {
Chris@206 283 delete m_cache;
Chris@206 284 m_cache = 0;
Chris@133 285 update();
Chris@133 286 }
Chris@133 287
Chris@133 288 void
Chris@133 289 View::zoomWheelsEnabledChanged()
Chris@133 290 {
Chris@133 291 // subclass might override this
Chris@133 292 }
Chris@133 293
Chris@127 294 long
Chris@127 295 View::getStartFrame() const
Chris@127 296 {
Chris@313 297 return getFrameForX(0);
Chris@127 298 }
Chris@127 299
Chris@127 300 size_t
Chris@127 301 View::getEndFrame() const
Chris@127 302 {
Chris@127 303 return getFrameForX(width()) - 1;
Chris@127 304 }
Chris@127 305
Chris@127 306 void
Chris@127 307 View::setStartFrame(long f)
Chris@127 308 {
Chris@127 309 setCentreFrame(f + m_zoomLevel * (width() / 2));
Chris@127 310 }
Chris@127 311
Chris@127 312 bool
Chris@127 313 View::setCentreFrame(size_t f, bool e)
Chris@127 314 {
Chris@127 315 bool changeVisible = false;
Chris@127 316
Chris@127 317 if (m_centreFrame != f) {
Chris@127 318
Chris@127 319 int formerPixel = m_centreFrame / m_zoomLevel;
Chris@127 320
Chris@127 321 m_centreFrame = f;
Chris@127 322
Chris@127 323 int newPixel = m_centreFrame / m_zoomLevel;
Chris@127 324
Chris@127 325 if (newPixel != formerPixel) {
Chris@127 326
Chris@127 327 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 328 std::cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << std::endl;
Chris@127 329 #endif
Chris@127 330 update();
Chris@127 331
Chris@127 332 changeVisible = true;
Chris@127 333 }
Chris@127 334
Chris@333 335 if (e) {
Chris@333 336 size_t rf = alignToReference(f);
Chris@355 337 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@333 338 std::cerr << "View[" << this << "]::setCentreFrame(" << f
Chris@333 339 << "): emitting centreFrameChanged("
Chris@333 340 << rf << ")" << std::endl;
Chris@355 341 #endif
Chris@333 342 emit centreFrameChanged(rf, m_followPan, m_followPlay);
Chris@333 343 }
Chris@127 344 }
Chris@127 345
Chris@127 346 return changeVisible;
Chris@127 347 }
Chris@127 348
Chris@127 349 int
Chris@127 350 View::getXForFrame(long frame) const
Chris@127 351 {
Chris@127 352 return (frame - getStartFrame()) / m_zoomLevel;
Chris@127 353 }
Chris@127 354
Chris@127 355 long
Chris@127 356 View::getFrameForX(int x) const
Chris@127 357 {
Chris@313 358 long z = (long)m_zoomLevel;
Chris@313 359 long frame = m_centreFrame - (width()/2) * z;
Chris@354 360
Chris@355 361 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@587 362 SVDEBUG << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << endl;
Chris@355 363 #endif
Chris@354 364
Chris@313 365 frame = (frame / z) * z; // this is start frame
Chris@313 366 return frame + x * z;
Chris@127 367 }
Chris@127 368
Chris@127 369 float
Chris@127 370 View::getYForFrequency(float frequency,
Chris@127 371 float minf,
Chris@127 372 float maxf,
Chris@127 373 bool logarithmic) const
Chris@127 374 {
Chris@382 375 Profiler profiler("View::getYForFrequency");
Chris@382 376
Chris@127 377 int h = height();
Chris@127 378
Chris@127 379 if (logarithmic) {
Chris@127 380
Chris@127 381 static float lastminf = 0.0, lastmaxf = 0.0;
Chris@127 382 static float logminf = 0.0, logmaxf = 0.0;
Chris@127 383
Chris@127 384 if (lastminf != minf) {
Chris@127 385 lastminf = (minf == 0.0 ? 1.0 : minf);
Chris@127 386 logminf = log10f(minf);
Chris@127 387 }
Chris@127 388 if (lastmaxf != maxf) {
Chris@127 389 lastmaxf = (maxf < lastminf ? lastminf : maxf);
Chris@127 390 logmaxf = log10f(maxf);
Chris@127 391 }
Chris@127 392
Chris@127 393 if (logminf == logmaxf) return 0;
Chris@127 394 return h - (h * (log10f(frequency) - logminf)) / (logmaxf - logminf);
Chris@127 395
Chris@127 396 } else {
Chris@127 397
Chris@127 398 if (minf == maxf) return 0;
Chris@127 399 return h - (h * (frequency - minf)) / (maxf - minf);
Chris@127 400 }
Chris@127 401 }
Chris@127 402
Chris@127 403 float
Chris@127 404 View::getFrequencyForY(int y,
Chris@127 405 float minf,
Chris@127 406 float maxf,
Chris@127 407 bool logarithmic) const
Chris@127 408 {
Chris@127 409 int h = height();
Chris@127 410
Chris@127 411 if (logarithmic) {
Chris@127 412
Chris@127 413 static float lastminf = 0.0, lastmaxf = 0.0;
Chris@127 414 static float logminf = 0.0, logmaxf = 0.0;
Chris@127 415
Chris@127 416 if (lastminf != minf) {
Chris@127 417 lastminf = (minf == 0.0 ? 1.0 : minf);
Chris@127 418 logminf = log10f(minf);
Chris@127 419 }
Chris@127 420 if (lastmaxf != maxf) {
Chris@127 421 lastmaxf = (maxf < lastminf ? lastminf : maxf);
Chris@127 422 logmaxf = log10f(maxf);
Chris@127 423 }
Chris@127 424
Chris@127 425 if (logminf == logmaxf) return 0;
Chris@127 426 return pow(10.f, logminf + ((logmaxf - logminf) * (h - y)) / h);
Chris@127 427
Chris@127 428 } else {
Chris@127 429
Chris@127 430 if (minf == maxf) return 0;
Chris@127 431 return minf + ((h - y) * (maxf - minf)) / h;
Chris@127 432 }
Chris@127 433 }
Chris@127 434
Chris@127 435 int
Chris@127 436 View::getZoomLevel() const
Chris@127 437 {
Chris@127 438 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@244 439 // std::cout << "zoom level: " << m_zoomLevel << std::endl;
Chris@127 440 #endif
Chris@127 441 return m_zoomLevel;
Chris@127 442 }
Chris@127 443
Chris@127 444 void
Chris@127 445 View::setZoomLevel(size_t z)
Chris@127 446 {
Chris@462 447 if (z < 1) z = 1;
Chris@127 448 if (m_zoomLevel != int(z)) {
Chris@127 449 m_zoomLevel = z;
Chris@222 450 emit zoomLevelChanged(z, m_followZoom);
Chris@127 451 update();
Chris@127 452 }
Chris@127 453 }
Chris@127 454
Chris@224 455 bool
Chris@224 456 View::hasLightBackground() const
Chris@224 457 {
Chris@287 458 bool darkPalette = false;
Chris@292 459 if (m_manager) darkPalette = m_manager->getGlobalDarkBackground();
Chris@287 460
Chris@287 461 Layer::ColourSignificance maxSignificance = Layer::ColourAbsent;
Chris@287 462 bool mostSignificantHasDarkBackground = false;
Chris@287 463
Chris@224 464 for (LayerList::const_iterator i = m_layers.begin();
Chris@224 465 i != m_layers.end(); ++i) {
Chris@287 466
Chris@287 467 Layer::ColourSignificance s = (*i)->getLayerColourSignificance();
Chris@287 468 bool light = (*i)->hasLightBackground();
Chris@287 469
Chris@287 470 if (int(s) > int(maxSignificance)) {
Chris@287 471 maxSignificance = s;
Chris@287 472 mostSignificantHasDarkBackground = !light;
Chris@287 473 } else if (s == maxSignificance && !light) {
Chris@287 474 mostSignificantHasDarkBackground = true;
Chris@287 475 }
Chris@224 476 }
Chris@287 477
Chris@287 478 if (int(maxSignificance) >= int(Layer::ColourAndBackgroundSignificant)) {
Chris@287 479 return !mostSignificantHasDarkBackground;
Chris@287 480 } else {
Chris@287 481 return !darkPalette;
Chris@287 482 }
Chris@287 483 }
Chris@287 484
Chris@287 485 QColor
Chris@287 486 View::getBackground() const
Chris@287 487 {
Chris@287 488 bool light = hasLightBackground();
Chris@287 489
Chris@287 490 QColor widgetbg = palette().window().color();
Chris@287 491 bool widgetLight =
Chris@287 492 (widgetbg.red() + widgetbg.green() + widgetbg.blue()) > 384;
Chris@287 493
Chris@296 494 if (widgetLight == light) {
Chris@296 495 if (widgetLight) {
Chris@296 496 return widgetbg.light();
Chris@296 497 } else {
Chris@296 498 return widgetbg.dark();
Chris@296 499 }
Chris@296 500 }
Chris@287 501 else if (light) return Qt::white;
Chris@287 502 else return Qt::black;
Chris@287 503 }
Chris@287 504
Chris@287 505 QColor
Chris@287 506 View::getForeground() const
Chris@287 507 {
Chris@287 508 bool light = hasLightBackground();
Chris@287 509
Chris@287 510 QColor widgetfg = palette().text().color();
Chris@287 511 bool widgetLight =
Chris@287 512 (widgetfg.red() + widgetfg.green() + widgetfg.blue()) > 384;
Chris@287 513
Chris@287 514 if (widgetLight != light) return widgetfg;
Chris@287 515 else if (light) return Qt::black;
Chris@287 516 else return Qt::white;
Chris@224 517 }
Chris@224 518
Chris@127 519 View::LayerProgressBar::LayerProgressBar(QWidget *parent) :
Chris@127 520 QProgressBar(parent)
Chris@127 521 {
Chris@127 522 }
Chris@127 523
Chris@127 524 void
Chris@127 525 View::addLayer(Layer *layer)
Chris@127 526 {
Chris@127 527 delete m_cache;
Chris@127 528 m_cache = 0;
Chris@127 529
Chris@287 530 SingleColourLayer *scl = dynamic_cast<SingleColourLayer *>(layer);
Chris@287 531 if (scl) scl->setDefaultColourFor(this);
Chris@287 532
Chris@127 533 m_layers.push_back(layer);
Chris@127 534
Chris@555 535 QProgressBar *pb = new QProgressBar(this);
Chris@555 536 pb->setMinimum(0);
Chris@555 537 pb->setMaximum(0);
Chris@555 538 pb->setFixedWidth(80);
Chris@555 539 pb->setTextVisible(false);
Chris@555 540
Chris@555 541 ProgressBarRec pbr;
Chris@555 542 pbr.bar = pb;
Chris@555 543 pbr.lastCheck = 0;
Chris@555 544 pbr.checkTimer = new QTimer();
Chris@555 545 connect(pbr.checkTimer, SIGNAL(timeout()), this,
Chris@555 546 SLOT(progressCheckStalledTimerElapsed()));
Chris@555 547
Chris@555 548 m_progressBars[layer] = pbr;
Chris@555 549
Chris@555 550 QFont f(pb->font());
Chris@339 551 int fs = Preferences::getInstance()->getViewFontSize();
Chris@339 552 f.setPointSize(std::min(fs, int(ceil(fs * 0.85))));
Chris@339 553
Chris@555 554 pb->setFont(f);
Chris@555 555 pb->hide();
Chris@127 556
Chris@127 557 connect(layer, SIGNAL(layerParametersChanged()),
Chris@127 558 this, SLOT(layerParametersChanged()));
Chris@197 559 connect(layer, SIGNAL(layerParameterRangesChanged()),
Chris@197 560 this, SLOT(layerParameterRangesChanged()));
Chris@268 561 connect(layer, SIGNAL(layerMeasurementRectsChanged()),
Chris@268 562 this, SLOT(layerMeasurementRectsChanged()));
Chris@127 563 connect(layer, SIGNAL(layerNameChanged()),
Chris@127 564 this, SLOT(layerNameChanged()));
Chris@127 565 connect(layer, SIGNAL(modelChanged()),
Chris@127 566 this, SLOT(modelChanged()));
Chris@127 567 connect(layer, SIGNAL(modelCompletionChanged()),
Chris@127 568 this, SLOT(modelCompletionChanged()));
Chris@320 569 connect(layer, SIGNAL(modelAlignmentCompletionChanged()),
Chris@320 570 this, SLOT(modelAlignmentCompletionChanged()));
Chris@127 571 connect(layer, SIGNAL(modelChanged(size_t, size_t)),
Chris@127 572 this, SLOT(modelChanged(size_t, size_t)));
Chris@127 573 connect(layer, SIGNAL(modelReplaced()),
Chris@127 574 this, SLOT(modelReplaced()));
Chris@127 575
Chris@127 576 update();
Chris@127 577
Chris@127 578 emit propertyContainerAdded(layer);
Chris@127 579 }
Chris@127 580
Chris@127 581 void
Chris@127 582 View::removeLayer(Layer *layer)
Chris@127 583 {
Chris@127 584 if (m_deleting) {
Chris@127 585 return;
Chris@127 586 }
Chris@127 587
Chris@127 588 delete m_cache;
Chris@127 589 m_cache = 0;
Chris@127 590
Chris@127 591 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 592 if (*i == layer) {
Chris@127 593 m_layers.erase(i);
Chris@127 594 if (m_progressBars.find(layer) != m_progressBars.end()) {
Chris@555 595 delete m_progressBars[layer].bar;
Chris@555 596 delete m_progressBars[layer].checkTimer;
Chris@127 597 m_progressBars.erase(layer);
Chris@127 598 }
Chris@127 599 break;
Chris@127 600 }
Chris@127 601 }
Chris@127 602
Chris@197 603 disconnect(layer, SIGNAL(layerParametersChanged()),
Chris@197 604 this, SLOT(layerParametersChanged()));
Chris@197 605 disconnect(layer, SIGNAL(layerParameterRangesChanged()),
Chris@197 606 this, SLOT(layerParameterRangesChanged()));
Chris@197 607 disconnect(layer, SIGNAL(layerNameChanged()),
Chris@197 608 this, SLOT(layerNameChanged()));
Chris@197 609 disconnect(layer, SIGNAL(modelChanged()),
Chris@197 610 this, SLOT(modelChanged()));
Chris@197 611 disconnect(layer, SIGNAL(modelCompletionChanged()),
Chris@197 612 this, SLOT(modelCompletionChanged()));
Chris@320 613 disconnect(layer, SIGNAL(modelAlignmentCompletionChanged()),
Chris@320 614 this, SLOT(modelAlignmentCompletionChanged()));
Chris@197 615 disconnect(layer, SIGNAL(modelChanged(size_t, size_t)),
Chris@197 616 this, SLOT(modelChanged(size_t, size_t)));
Chris@197 617 disconnect(layer, SIGNAL(modelReplaced()),
Chris@197 618 this, SLOT(modelReplaced()));
Chris@197 619
Chris@127 620 update();
Chris@127 621
Chris@127 622 emit propertyContainerRemoved(layer);
Chris@127 623 }
Chris@127 624
Chris@127 625 Layer *
Chris@127 626 View::getSelectedLayer()
Chris@127 627 {
Chris@127 628 if (m_haveSelectedLayer && !m_layers.empty()) {
Chris@127 629 return getLayer(getLayerCount() - 1);
Chris@127 630 } else {
Chris@127 631 return 0;
Chris@127 632 }
Chris@127 633 }
Chris@127 634
Chris@127 635 const Layer *
Chris@127 636 View::getSelectedLayer() const
Chris@127 637 {
Chris@127 638 return const_cast<const Layer *>(const_cast<View *>(this)->getSelectedLayer());
Chris@127 639 }
Chris@127 640
Chris@127 641 void
Chris@127 642 View::setViewManager(ViewManager *manager)
Chris@127 643 {
Chris@127 644 if (m_manager) {
Chris@211 645 m_manager->disconnect(this, SLOT(globalCentreFrameChanged(unsigned long)));
Chris@211 646 m_manager->disconnect(this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
Chris@211 647 m_manager->disconnect(this, SLOT(viewManagerPlaybackFrameChanged(unsigned long)));
Chris@222 648 m_manager->disconnect(this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
Chris@211 649 m_manager->disconnect(this, SLOT(toolModeChanged()));
Chris@211 650 m_manager->disconnect(this, SLOT(selectionChanged()));
Chris@211 651 m_manager->disconnect(this, SLOT(overlayModeChanged()));
Chris@211 652 m_manager->disconnect(this, SLOT(zoomWheelsEnabledChanged()));
Chris@222 653 disconnect(m_manager, SLOT(viewCentreFrameChanged(unsigned long, bool, PlaybackFollowMode)));
Chris@222 654 disconnect(m_manager, SLOT(zoomLevelChanged(unsigned long, bool)));
Chris@127 655 }
Chris@127 656
Chris@127 657 m_manager = manager;
Chris@127 658
Chris@211 659 connect(m_manager, SIGNAL(globalCentreFrameChanged(unsigned long)),
Chris@211 660 this, SLOT(globalCentreFrameChanged(unsigned long)));
Chris@213 661 connect(m_manager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
Chris@211 662 this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
Chris@127 663 connect(m_manager, SIGNAL(playbackFrameChanged(unsigned long)),
Chris@127 664 this, SLOT(viewManagerPlaybackFrameChanged(unsigned long)));
Chris@211 665
Chris@222 666 connect(m_manager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
Chris@222 667 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
Chris@211 668
Chris@127 669 connect(m_manager, SIGNAL(toolModeChanged()),
Chris@127 670 this, SLOT(toolModeChanged()));
Chris@127 671 connect(m_manager, SIGNAL(selectionChanged()),
Chris@127 672 this, SLOT(selectionChanged()));
Chris@127 673 connect(m_manager, SIGNAL(inProgressSelectionChanged()),
Chris@127 674 this, SLOT(selectionChanged()));
Chris@127 675 connect(m_manager, SIGNAL(overlayModeChanged()),
Chris@133 676 this, SLOT(overlayModeChanged()));
Chris@607 677 connect(m_manager, SIGNAL(showCentreLineChanged()),
Chris@607 678 this, SLOT(overlayModeChanged()));
Chris@133 679 connect(m_manager, SIGNAL(zoomWheelsEnabledChanged()),
Chris@133 680 this, SLOT(zoomWheelsEnabledChanged()));
Chris@127 681
Chris@211 682 connect(this, SIGNAL(centreFrameChanged(unsigned long, bool,
Chris@211 683 PlaybackFollowMode)),
Chris@211 684 m_manager, SLOT(viewCentreFrameChanged(unsigned long, bool,
Chris@211 685 PlaybackFollowMode)));
Chris@211 686
Chris@222 687 connect(this, SIGNAL(zoomLevelChanged(unsigned long, bool)),
Chris@222 688 m_manager, SLOT(viewZoomLevelChanged(unsigned long, bool)));
Chris@127 689
Chris@516 690 // setCentreFrame(m_manager->getViewInitialCentreFrame());
Chris@516 691
Chris@364 692 if (m_followPlay == PlaybackScrollPage) {
Chris@587 693 // SVDEBUG << "View::setViewManager: setting centre frame to global centre frame: " << m_manager->getGlobalCentreFrame() << endl;
Chris@364 694 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
Chris@364 695 } else if (m_followPlay == PlaybackScrollContinuous) {
Chris@587 696 // SVDEBUG << "View::setViewManager: setting centre frame to playback frame: " << m_manager->getPlaybackFrame() << endl;
Chris@236 697 setCentreFrame(m_manager->getPlaybackFrame(), false);
Chris@236 698 } else if (m_followPan) {
Chris@587 699 // SVDEBUG << "View::setViewManager: (follow pan) setting centre frame to global centre frame: " << m_manager->getGlobalCentreFrame() << endl;
Chris@236 700 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
Chris@236 701 }
Chris@516 702
Chris@236 703 if (m_followZoom) setZoomLevel(m_manager->getGlobalZoom());
Chris@236 704
Chris@511 705 movePlayPointer(getAlignedPlaybackFrame());
Chris@511 706
Chris@127 707 toolModeChanged();
Chris@127 708 }
Chris@127 709
Chris@127 710 void
Chris@516 711 View::setViewManager(ViewManager *vm, long initialCentreFrame)
Chris@516 712 {
Chris@516 713 setViewManager(vm);
Chris@516 714 setCentreFrame(initialCentreFrame, false);
Chris@516 715 }
Chris@516 716
Chris@516 717 void
Chris@127 718 View::setFollowGlobalPan(bool f)
Chris@127 719 {
Chris@127 720 m_followPan = f;
Chris@127 721 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 722 }
Chris@127 723
Chris@127 724 void
Chris@127 725 View::setFollowGlobalZoom(bool f)
Chris@127 726 {
Chris@127 727 m_followZoom = f;
Chris@127 728 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 729 }
Chris@127 730
Chris@127 731 void
Chris@267 732 View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style) const
Chris@127 733 {
Chris@630 734 if (style == OutlinedText || style == OutlinedItalicText) {
Chris@127 735
Chris@279 736 paint.save();
Chris@279 737
Chris@630 738 if (style == OutlinedItalicText) {
Chris@630 739 QFont f(paint.font());
Chris@630 740 f.setItalic(true);
Chris@630 741 paint.setFont(f);
Chris@630 742 }
Chris@630 743
Chris@575 744 QColor penColour, surroundColour, boxColour;
Chris@279 745
Chris@287 746 penColour = getForeground();
Chris@287 747 surroundColour = getBackground();
Chris@575 748 boxColour = surroundColour;
Chris@575 749 boxColour.setAlpha(127);
Chris@575 750
Chris@575 751 paint.setPen(Qt::NoPen);
Chris@575 752 paint.setBrush(boxColour);
Chris@630 753
Chris@575 754 QRect r = paint.fontMetrics().boundingRect(text);
Chris@575 755 r.translate(QPoint(x, y));
Chris@575 756 // std::cerr << "drawVisibleText: r = " << r.x() << "," <<r.y() << " " << r.width() << "x" << r.height() << std::endl;
Chris@575 757 paint.drawRect(r);
Chris@575 758 paint.setBrush(Qt::NoBrush);
Chris@279 759
Chris@127 760 paint.setPen(surroundColour);
Chris@127 761
Chris@127 762 for (int dx = -1; dx <= 1; ++dx) {
Chris@127 763 for (int dy = -1; dy <= 1; ++dy) {
Chris@127 764 if (!(dx || dy)) continue;
Chris@127 765 paint.drawText(x + dx, y + dy, text);
Chris@127 766 }
Chris@127 767 }
Chris@127 768
Chris@127 769 paint.setPen(penColour);
Chris@127 770
Chris@127 771 paint.drawText(x, y, text);
Chris@287 772
Chris@279 773 paint.restore();
Chris@127 774
Chris@127 775 } else {
Chris@127 776
Chris@127 777 std::cerr << "ERROR: View::drawVisibleText: Boxed style not yet implemented!" << std::endl;
Chris@127 778 }
Chris@127 779 }
Chris@127 780
Chris@127 781 void
Chris@127 782 View::setPlaybackFollow(PlaybackFollowMode m)
Chris@127 783 {
Chris@127 784 m_followPlay = m;
Chris@127 785 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 786 }
Chris@127 787
Chris@127 788 void
Chris@127 789 View::modelChanged()
Chris@127 790 {
Chris@127 791 QObject *obj = sender();
Chris@127 792
Chris@127 793 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 794 std::cerr << "View(" << this << ")::modelChanged()" << std::endl;
Chris@127 795 #endif
Chris@127 796
Chris@127 797 // If the model that has changed is not used by any of the cached
Chris@127 798 // layers, we won't need to recreate the cache
Chris@127 799
Chris@127 800 bool recreate = false;
Chris@127 801
Chris@127 802 bool discard;
Chris@127 803 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@127 804 for (LayerList::const_iterator i = scrollables.begin();
Chris@127 805 i != scrollables.end(); ++i) {
Chris@127 806 if (*i == obj || (*i)->getModel() == obj) {
Chris@127 807 recreate = true;
Chris@127 808 break;
Chris@127 809 }
Chris@127 810 }
Chris@127 811
Chris@127 812 if (recreate) {
Chris@127 813 delete m_cache;
Chris@127 814 m_cache = 0;
Chris@127 815 }
Chris@127 816
Chris@336 817 emit layerModelChanged();
Chris@336 818
Chris@127 819 checkProgress(obj);
Chris@127 820
Chris@127 821 update();
Chris@127 822 }
Chris@127 823
Chris@127 824 void
Chris@127 825 View::modelChanged(size_t startFrame, size_t endFrame)
Chris@127 826 {
Chris@127 827 QObject *obj = sender();
Chris@127 828
Chris@127 829 long myStartFrame = getStartFrame();
Chris@127 830 size_t myEndFrame = getEndFrame();
Chris@127 831
Chris@127 832 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 833 std::cerr << "View(" << this << ")::modelChanged(" << startFrame << "," << endFrame << ") [me " << myStartFrame << "," << myEndFrame << "]" << std::endl;
Chris@127 834 #endif
Chris@127 835
Chris@127 836 if (myStartFrame > 0 && endFrame < size_t(myStartFrame)) {
Chris@127 837 checkProgress(obj);
Chris@127 838 return;
Chris@127 839 }
Chris@127 840 if (startFrame > myEndFrame) {
Chris@127 841 checkProgress(obj);
Chris@127 842 return;
Chris@127 843 }
Chris@127 844
Chris@127 845 // If the model that has changed is not used by any of the cached
Chris@127 846 // layers, we won't need to recreate the cache
Chris@127 847
Chris@127 848 bool recreate = false;
Chris@127 849
Chris@127 850 bool discard;
Chris@127 851 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@127 852 for (LayerList::const_iterator i = scrollables.begin();
Chris@127 853 i != scrollables.end(); ++i) {
Chris@127 854 if (*i == obj || (*i)->getModel() == obj) {
Chris@127 855 recreate = true;
Chris@127 856 break;
Chris@127 857 }
Chris@127 858 }
Chris@127 859
Chris@127 860 if (recreate) {
Chris@127 861 delete m_cache;
Chris@127 862 m_cache = 0;
Chris@127 863 }
Chris@127 864
Chris@127 865 if (long(startFrame) < myStartFrame) startFrame = myStartFrame;
Chris@127 866 if (endFrame > myEndFrame) endFrame = myEndFrame;
Chris@127 867
Chris@127 868 checkProgress(obj);
Chris@127 869
Chris@127 870 update();
Chris@127 871 }
Chris@127 872
Chris@127 873 void
Chris@127 874 View::modelCompletionChanged()
Chris@127 875 {
Chris@326 876 // std::cerr << "View(" << this << ")::modelCompletionChanged()" << std::endl;
Chris@301 877
Chris@127 878 QObject *obj = sender();
Chris@127 879 checkProgress(obj);
Chris@127 880 }
Chris@127 881
Chris@127 882 void
Chris@320 883 View::modelAlignmentCompletionChanged()
Chris@320 884 {
Chris@326 885 // std::cerr << "View(" << this << ")::modelAlignmentCompletionChanged()" << std::endl;
Chris@320 886
Chris@320 887 QObject *obj = sender();
Chris@320 888 checkProgress(obj);
Chris@320 889 }
Chris@320 890
Chris@320 891 void
Chris@127 892 View::modelReplaced()
Chris@127 893 {
Chris@127 894 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 895 std::cerr << "View(" << this << ")::modelReplaced()" << std::endl;
Chris@127 896 #endif
Chris@127 897 delete m_cache;
Chris@127 898 m_cache = 0;
Chris@127 899
Chris@127 900 update();
Chris@127 901 }
Chris@127 902
Chris@127 903 void
Chris@127 904 View::layerParametersChanged()
Chris@127 905 {
Chris@127 906 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@127 907
Chris@127 908 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@587 909 SVDEBUG << "View::layerParametersChanged()" << endl;
Chris@127 910 #endif
Chris@127 911
Chris@127 912 delete m_cache;
Chris@127 913 m_cache = 0;
Chris@127 914 update();
Chris@127 915
Chris@127 916 if (layer) {
Chris@127 917 emit propertyContainerPropertyChanged(layer);
Chris@127 918 }
Chris@127 919 }
Chris@127 920
Chris@127 921 void
Chris@197 922 View::layerParameterRangesChanged()
Chris@197 923 {
Chris@197 924 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@197 925 if (layer) emit propertyContainerPropertyRangeChanged(layer);
Chris@197 926 }
Chris@197 927
Chris@197 928 void
Chris@268 929 View::layerMeasurementRectsChanged()
Chris@268 930 {
Chris@268 931 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@268 932 if (layer) update();
Chris@268 933 }
Chris@268 934
Chris@268 935 void
Chris@127 936 View::layerNameChanged()
Chris@127 937 {
Chris@127 938 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@127 939 if (layer) emit propertyContainerNameChanged(layer);
Chris@127 940 }
Chris@127 941
Chris@127 942 void
Chris@333 943 View::globalCentreFrameChanged(unsigned long rf)
Chris@127 944 {
Chris@211 945 if (m_followPan) {
Chris@333 946 size_t f = alignFromReference(rf);
Chris@363 947 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@333 948 std::cerr << "View[" << this << "]::globalCentreFrameChanged(" << rf
Chris@333 949 << "): setting centre frame to " << f << std::endl;
Chris@363 950 #endif
Chris@333 951 setCentreFrame(f, false);
Chris@127 952 }
Chris@127 953 }
Chris@127 954
Chris@127 955 void
Chris@248 956 View::viewCentreFrameChanged(View *, unsigned long )
Chris@211 957 {
Chris@211 958 // We do nothing with this, but a subclass might
Chris@211 959 }
Chris@211 960
Chris@211 961 void
Chris@127 962 View::viewManagerPlaybackFrameChanged(unsigned long f)
Chris@127 963 {
Chris@127 964 if (m_manager) {
Chris@127 965 if (sender() != m_manager) return;
Chris@127 966 }
Chris@127 967
Chris@301 968 f = getAlignedPlaybackFrame();
Chris@301 969
Chris@511 970 movePlayPointer(f);
Chris@511 971 }
Chris@511 972
Chris@511 973 void
Chris@511 974 View::movePlayPointer(unsigned long newFrame)
Chris@511 975 {
Chris@511 976 if (m_playPointerFrame == newFrame) return;
Chris@511 977 bool visibleChange =
Chris@511 978 (getXForFrame(m_playPointerFrame) != getXForFrame(newFrame));
Chris@127 979 size_t oldPlayPointerFrame = m_playPointerFrame;
Chris@511 980 m_playPointerFrame = newFrame;
Chris@511 981 if (!visibleChange) return;
Chris@127 982
Chris@513 983 bool somethingGoingOn =
Chris@513 984 ((QApplication::mouseButtons() != Qt::NoButton) ||
Chris@513 985 (QApplication::keyboardModifiers() & Qt::AltModifier));
Chris@513 986
Chris@127 987 switch (m_followPlay) {
Chris@127 988
Chris@127 989 case PlaybackScrollContinuous:
Chris@513 990 if (!somethingGoingOn) {
Chris@511 991 setCentreFrame(m_playPointerFrame, false);
Chris@127 992 }
Chris@127 993 break;
Chris@127 994
Chris@127 995 case PlaybackScrollPage:
Chris@127 996 {
Chris@127 997 int xold = getXForFrame(oldPlayPointerFrame);
Chris@127 998 update(xold - 1, 0, 3, height());
Chris@127 999
Chris@127 1000 long w = getEndFrame() - getStartFrame();
Chris@127 1001 w -= w/5;
Chris@511 1002 long sf = (m_playPointerFrame / w) * w - w/8;
Chris@127 1003
Chris@127 1004 if (m_manager &&
Chris@127 1005 m_manager->isPlaying() &&
Chris@127 1006 m_manager->getPlaySelectionMode()) {
Chris@127 1007 MultiSelection::SelectionList selections = m_manager->getSelections();
Chris@127 1008 if (!selections.empty()) {
Chris@127 1009 size_t selectionStart = selections.begin()->getStartFrame();
Chris@127 1010 if (sf < long(selectionStart) - w / 10) {
Chris@127 1011 sf = long(selectionStart) - w / 10;
Chris@127 1012 }
Chris@127 1013 }
Chris@127 1014 }
Chris@127 1015
Chris@127 1016 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@511 1017 std::cerr << "PlaybackScrollPage: f = " << m_playPointerFrame << ", sf = " << sf << ", start frame "
Chris@127 1018 << getStartFrame() << std::endl;
Chris@127 1019 #endif
Chris@127 1020
Chris@127 1021 // We don't consider scrolling unless the pointer is outside
Chris@127 1022 // the clearly visible range already
Chris@127 1023
Chris@127 1024 int xnew = getXForFrame(m_playPointerFrame);
Chris@127 1025
Chris@127 1026 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1027 std::cerr << "xnew = " << xnew << ", width = " << width() << std::endl;
Chris@127 1028 #endif
Chris@127 1029
Chris@127 1030 if (xnew < width()/8 || xnew > (width()*7)/8) {
Chris@513 1031 if (!somethingGoingOn) {
Chris@127 1032 long offset = getFrameForX(width()/2) - getStartFrame();
Chris@127 1033 long newCentre = sf + offset;
Chris@127 1034 bool changed = setCentreFrame(newCentre, false);
Chris@127 1035 if (changed) {
Chris@127 1036 xold = getXForFrame(oldPlayPointerFrame);
Chris@127 1037 update(xold - 1, 0, 3, height());
Chris@127 1038 }
Chris@127 1039 }
Chris@127 1040 }
Chris@127 1041
Chris@127 1042 update(xnew - 1, 0, 3, height());
Chris@127 1043
Chris@127 1044 break;
Chris@127 1045 }
Chris@127 1046
Chris@127 1047 case PlaybackIgnore:
Chris@511 1048 if (long(m_playPointerFrame) >= getStartFrame() &&
Chris@511 1049 m_playPointerFrame < getEndFrame()) {
Chris@127 1050 update();
Chris@127 1051 }
Chris@127 1052 break;
Chris@127 1053 }
Chris@127 1054 }
Chris@127 1055
Chris@127 1056 void
Chris@222 1057 View::viewZoomLevelChanged(View *p, unsigned long z, bool locked)
Chris@127 1058 {
Chris@244 1059 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@244 1060 std::cerr << "View[" << this << "]: viewZoomLevelChanged(" << p << ", " << z << ", " << locked << ")" << std::endl;
Chris@244 1061 #endif
Chris@127 1062 if (m_followZoom && p != this && locked) {
Chris@222 1063 setZoomLevel(z);
Chris@127 1064 }
Chris@127 1065 }
Chris@127 1066
Chris@127 1067 void
Chris@127 1068 View::selectionChanged()
Chris@127 1069 {
Chris@127 1070 if (m_selectionCached) {
Chris@127 1071 delete m_cache;
Chris@127 1072 m_cache = 0;
Chris@127 1073 m_selectionCached = false;
Chris@127 1074 }
Chris@127 1075 update();
Chris@127 1076 }
Chris@127 1077
Chris@127 1078 size_t
Chris@222 1079 View::getFirstVisibleFrame() const
Chris@222 1080 {
Chris@222 1081 long f0 = getStartFrame();
Chris@222 1082 size_t f = getModelsStartFrame();
Chris@222 1083 if (f0 < 0 || f0 < long(f)) return f;
Chris@222 1084 return f0;
Chris@222 1085 }
Chris@222 1086
Chris@222 1087 size_t
Chris@222 1088 View::getLastVisibleFrame() const
Chris@222 1089 {
Chris@222 1090 size_t f0 = getEndFrame();
Chris@222 1091 size_t f = getModelsEndFrame();
Chris@222 1092 if (f0 > f) return f;
Chris@222 1093 return f0;
Chris@222 1094 }
Chris@222 1095
Chris@222 1096 size_t
Chris@127 1097 View::getModelsStartFrame() const
Chris@127 1098 {
Chris@127 1099 bool first = true;
Chris@127 1100 size_t startFrame = 0;
Chris@127 1101
Chris@127 1102 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1103
Chris@127 1104 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1105
Chris@127 1106 size_t thisStartFrame = (*i)->getModel()->getStartFrame();
Chris@127 1107
Chris@127 1108 if (first || thisStartFrame < startFrame) {
Chris@127 1109 startFrame = thisStartFrame;
Chris@127 1110 }
Chris@127 1111 first = false;
Chris@127 1112 }
Chris@127 1113 }
Chris@127 1114 return startFrame;
Chris@127 1115 }
Chris@127 1116
Chris@127 1117 size_t
Chris@127 1118 View::getModelsEndFrame() const
Chris@127 1119 {
Chris@127 1120 bool first = true;
Chris@127 1121 size_t endFrame = 0;
Chris@127 1122
Chris@127 1123 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1124
Chris@127 1125 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1126
Chris@127 1127 size_t thisEndFrame = (*i)->getModel()->getEndFrame();
Chris@127 1128
Chris@127 1129 if (first || thisEndFrame > endFrame) {
Chris@127 1130 endFrame = thisEndFrame;
Chris@127 1131 }
Chris@127 1132 first = false;
Chris@127 1133 }
Chris@127 1134 }
Chris@127 1135
Chris@127 1136 if (first) return getModelsStartFrame();
Chris@127 1137 return endFrame;
Chris@127 1138 }
Chris@127 1139
Chris@127 1140 int
Chris@127 1141 View::getModelsSampleRate() const
Chris@127 1142 {
Chris@127 1143 //!!! Just go for the first, for now. If we were supporting
Chris@127 1144 // multiple samplerates, we'd probably want to do frame/time
Chris@127 1145 // conversion in the model
Chris@127 1146
Chris@159 1147 //!!! nah, this wants to always return the sr of the main model!
Chris@159 1148
Chris@127 1149 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1150 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1151 return (*i)->getModel()->getSampleRate();
Chris@127 1152 }
Chris@127 1153 }
Chris@127 1154 return 0;
Chris@127 1155 }
Chris@127 1156
Chris@315 1157 View::ModelSet
Chris@315 1158 View::getModels()
Chris@315 1159 {
Chris@315 1160 ModelSet models;
Chris@315 1161
Chris@315 1162 for (int i = 0; i < getLayerCount(); ++i) {
Chris@315 1163
Chris@315 1164 Layer *layer = getLayer(i);
Chris@315 1165
Chris@315 1166 if (dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@315 1167 continue;
Chris@315 1168 }
Chris@315 1169
Chris@315 1170 if (layer && layer->getModel()) {
Chris@315 1171 Model *model = layer->getModel();
Chris@315 1172 models.insert(model);
Chris@315 1173 }
Chris@315 1174 }
Chris@315 1175
Chris@315 1176 return models;
Chris@315 1177 }
Chris@315 1178
Chris@320 1179 Model *
Chris@320 1180 View::getAligningModel() const
Chris@301 1181 {
Chris@320 1182 if (!m_manager ||
Chris@320 1183 !m_manager->getAlignMode() ||
Chris@314 1184 !m_manager->getPlaybackModel()) {
Chris@320 1185 return 0;
Chris@314 1186 }
Chris@301 1187
Chris@320 1188 Model *anyModel = 0;
Chris@359 1189 Model *alignedModel = 0;
Chris@320 1190 Model *goodModel = 0;
Chris@301 1191
Chris@320 1192 for (LayerList::const_iterator i = m_layers.begin();
Chris@320 1193 i != m_layers.end(); ++i) {
Chris@320 1194
Chris@320 1195 Layer *layer = *i;
Chris@320 1196
Chris@320 1197 if (!layer) continue;
Chris@320 1198 if (dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@301 1199
Chris@301 1200 Model *model = (*i)->getModel();
Chris@301 1201 if (!model) continue;
Chris@301 1202
Chris@359 1203 anyModel = model;
Chris@359 1204
Chris@320 1205 if (model->getAlignmentReference()) {
Chris@359 1206 alignedModel = model;
Chris@320 1207 if (layer->isLayerOpaque() ||
Chris@320 1208 dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
Chris@320 1209 goodModel = model;
Chris@320 1210 }
Chris@301 1211 }
Chris@320 1212 }
Chris@301 1213
Chris@320 1214 if (goodModel) return goodModel;
Chris@359 1215 else if (alignedModel) return alignedModel;
Chris@320 1216 else return anyModel;
Chris@320 1217 }
Chris@320 1218
Chris@320 1219 size_t
Chris@320 1220 View::alignFromReference(size_t f) const
Chris@320 1221 {
Chris@321 1222 if (!m_manager->getAlignMode()) return f;
Chris@320 1223 Model *aligningModel = getAligningModel();
Chris@320 1224 if (!aligningModel) return f;
Chris@320 1225 return aligningModel->alignFromReference(f);
Chris@320 1226 }
Chris@320 1227
Chris@320 1228 size_t
Chris@320 1229 View::alignToReference(size_t f) const
Chris@320 1230 {
Chris@321 1231 if (!m_manager->getAlignMode()) return f;
Chris@320 1232 Model *aligningModel = getAligningModel();
Chris@320 1233 if (!aligningModel) return f;
Chris@320 1234 return aligningModel->alignToReference(f);
Chris@320 1235 }
Chris@320 1236
Chris@320 1237 int
Chris@320 1238 View::getAlignedPlaybackFrame() const
Chris@320 1239 {
Chris@321 1240 int pf = m_manager->getPlaybackFrame();
Chris@321 1241 if (!m_manager->getAlignMode()) return pf;
Chris@321 1242
Chris@320 1243 Model *aligningModel = getAligningModel();
Chris@320 1244 if (!aligningModel) return pf;
Chris@333 1245 /*
Chris@320 1246 Model *pm = m_manager->getPlaybackModel();
Chris@301 1247
Chris@301 1248 // std::cerr << "View[" << this << "]::getAlignedPlaybackFrame: pf = " << pf;
Chris@301 1249
Chris@301 1250 if (pm) {
Chris@333 1251 pf = pm->alignToReference(pf);
Chris@301 1252 // std::cerr << " -> " << pf;
Chris@301 1253 }
Chris@333 1254 */
Chris@333 1255 int af = aligningModel->alignFromReference(pf);
Chris@301 1256
Chris@301 1257 // std::cerr << ", aligned = " << af << std::endl;
Chris@301 1258 return af;
Chris@301 1259 }
Chris@301 1260
Chris@127 1261 bool
Chris@127 1262 View::areLayersScrollable() const
Chris@127 1263 {
Chris@127 1264 // True iff all views are scrollable
Chris@127 1265 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1266 if (!(*i)->isLayerScrollable(this)) return false;
Chris@127 1267 }
Chris@127 1268 return true;
Chris@127 1269 }
Chris@127 1270
Chris@127 1271 View::LayerList
Chris@127 1272 View::getScrollableBackLayers(bool testChanged, bool &changed) const
Chris@127 1273 {
Chris@127 1274 changed = false;
Chris@127 1275
Chris@127 1276 // We want a list of all the scrollable layers that are behind the
Chris@127 1277 // backmost non-scrollable layer.
Chris@127 1278
Chris@127 1279 LayerList scrollables;
Chris@127 1280 bool metUnscrollable = false;
Chris@127 1281
Chris@127 1282 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@587 1283 // SVDEBUG << "View::getScrollableBackLayers: calling isLayerDormant on layer " << *i << endl;
Chris@584 1284 // std::cerr << "(name is " << (*i)->objectName() << ")"
Chris@132 1285 // << std::endl;
Chris@587 1286 // SVDEBUG << "View::getScrollableBackLayers: I am " << this << endl;
Chris@127 1287 if ((*i)->isLayerDormant(this)) continue;
Chris@127 1288 if ((*i)->isLayerOpaque()) {
Chris@127 1289 // You can't see anything behind an opaque layer!
Chris@127 1290 scrollables.clear();
Chris@127 1291 if (metUnscrollable) break;
Chris@127 1292 }
Chris@127 1293 if (!metUnscrollable && (*i)->isLayerScrollable(this)) {
Chris@127 1294 scrollables.push_back(*i);
Chris@127 1295 } else {
Chris@127 1296 metUnscrollable = true;
Chris@127 1297 }
Chris@127 1298 }
Chris@127 1299
Chris@127 1300 if (testChanged && scrollables != m_lastScrollableBackLayers) {
Chris@127 1301 m_lastScrollableBackLayers = scrollables;
Chris@127 1302 changed = true;
Chris@127 1303 }
Chris@127 1304 return scrollables;
Chris@127 1305 }
Chris@127 1306
Chris@127 1307 View::LayerList
Chris@127 1308 View::getNonScrollableFrontLayers(bool testChanged, bool &changed) const
Chris@127 1309 {
Chris@127 1310 changed = false;
Chris@127 1311 LayerList nonScrollables;
Chris@127 1312
Chris@127 1313 // Everything in front of the first non-scrollable from the back
Chris@127 1314 // should also be considered non-scrollable
Chris@127 1315
Chris@127 1316 bool started = false;
Chris@127 1317
Chris@127 1318 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1319 if ((*i)->isLayerDormant(this)) continue;
Chris@127 1320 if (!started && (*i)->isLayerScrollable(this)) {
Chris@127 1321 continue;
Chris@127 1322 }
Chris@127 1323 started = true;
Chris@127 1324 if ((*i)->isLayerOpaque()) {
Chris@127 1325 // You can't see anything behind an opaque layer!
Chris@127 1326 nonScrollables.clear();
Chris@127 1327 }
Chris@127 1328 nonScrollables.push_back(*i);
Chris@127 1329 }
Chris@127 1330
Chris@127 1331 if (testChanged && nonScrollables != m_lastNonScrollableBackLayers) {
Chris@127 1332 m_lastNonScrollableBackLayers = nonScrollables;
Chris@127 1333 changed = true;
Chris@127 1334 }
Chris@127 1335
Chris@127 1336 return nonScrollables;
Chris@127 1337 }
Chris@127 1338
Chris@127 1339 size_t
Chris@127 1340 View::getZoomConstraintBlockSize(size_t blockSize,
Chris@127 1341 ZoomConstraint::RoundingDirection dir)
Chris@127 1342 const
Chris@127 1343 {
Chris@127 1344 size_t candidate = blockSize;
Chris@127 1345 bool haveCandidate = false;
Chris@127 1346
Chris@127 1347 PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
Chris@127 1348
Chris@127 1349 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1350
Chris@127 1351 const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
Chris@127 1352 if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
Chris@127 1353
Chris@127 1354 size_t thisBlockSize =
Chris@127 1355 zoomConstraint->getNearestBlockSize(blockSize, dir);
Chris@127 1356
Chris@127 1357 // Go for the block size that's furthest from the one
Chris@127 1358 // passed in. Most of the time, that's what we want.
Chris@127 1359 if (!haveCandidate ||
Chris@127 1360 (thisBlockSize > blockSize && thisBlockSize > candidate) ||
Chris@127 1361 (thisBlockSize < blockSize && thisBlockSize < candidate)) {
Chris@127 1362 candidate = thisBlockSize;
Chris@127 1363 haveCandidate = true;
Chris@127 1364 }
Chris@127 1365 }
Chris@127 1366
Chris@127 1367 return candidate;
Chris@127 1368 }
Chris@127 1369
Chris@183 1370 bool
Chris@183 1371 View::areLayerColoursSignificant() const
Chris@183 1372 {
Chris@183 1373 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@287 1374 if ((*i)->getLayerColourSignificance() ==
Chris@287 1375 Layer::ColourHasMeaningfulValue) return true;
Chris@183 1376 if ((*i)->isLayerOpaque()) break;
Chris@183 1377 }
Chris@183 1378 return false;
Chris@183 1379 }
Chris@183 1380
Chris@217 1381 bool
Chris@217 1382 View::hasTopLayerTimeXAxis() const
Chris@217 1383 {
Chris@217 1384 LayerList::const_iterator i = m_layers.end();
Chris@217 1385 if (i == m_layers.begin()) return false;
Chris@217 1386 --i;
Chris@217 1387 return (*i)->hasTimeXAxis();
Chris@217 1388 }
Chris@217 1389
Chris@127 1390 void
Chris@127 1391 View::zoom(bool in)
Chris@127 1392 {
Chris@127 1393 int newZoomLevel = m_zoomLevel;
Chris@127 1394
Chris@127 1395 if (in) {
Chris@127 1396 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@127 1397 ZoomConstraint::RoundDown);
Chris@127 1398 } else {
Chris@127 1399 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@127 1400 ZoomConstraint::RoundUp);
Chris@127 1401 }
Chris@127 1402
Chris@127 1403 if (newZoomLevel != m_zoomLevel) {
Chris@127 1404 setZoomLevel(newZoomLevel);
Chris@127 1405 }
Chris@127 1406 }
Chris@127 1407
Chris@127 1408 void
Chris@510 1409 View::scroll(bool right, bool lots, bool e)
Chris@127 1410 {
Chris@127 1411 long delta;
Chris@127 1412 if (lots) {
Chris@127 1413 delta = (getEndFrame() - getStartFrame()) / 2;
Chris@127 1414 } else {
Chris@127 1415 delta = (getEndFrame() - getStartFrame()) / 20;
Chris@127 1416 }
Chris@127 1417 if (right) delta = -delta;
Chris@127 1418
Chris@127 1419 if (int(m_centreFrame) < delta) {
Chris@510 1420 setCentreFrame(0, e);
Chris@127 1421 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@510 1422 setCentreFrame(getModelsEndFrame(), e);
Chris@127 1423 } else {
Chris@510 1424 setCentreFrame(m_centreFrame - delta, e);
Chris@127 1425 }
Chris@127 1426 }
Chris@127 1427
Chris@127 1428 void
Chris@127 1429 View::checkProgress(void *object)
Chris@127 1430 {
Chris@127 1431 if (!m_showProgress) return;
Chris@127 1432
Chris@127 1433 int ph = height();
Chris@127 1434
Chris@555 1435 for (ProgressMap::iterator i = m_progressBars.begin();
Chris@127 1436 i != m_progressBars.end(); ++i) {
Chris@127 1437
Chris@555 1438 QProgressBar *pb = i->second.bar;
Chris@555 1439
Chris@127 1440 if (i->first == object) {
Chris@127 1441
Chris@555 1442 // The timer is used to test for stalls. If the progress
Chris@555 1443 // bar does not get updated for some length of time, the
Chris@555 1444 // timer prompts it to go back into "indeterminate" mode
Chris@555 1445 QTimer *timer = i->second.checkTimer;
Chris@555 1446
Chris@127 1447 int completion = i->first->getCompletion(this);
Chris@301 1448 QString text = i->first->getPropertyContainerName();
Chris@583 1449 QString error = i->first->getError(this);
Chris@583 1450
Chris@583 1451 if (error != "" && error != m_lastError) {
Chris@583 1452 QMessageBox::critical(this, tr("Layer rendering error"), error);
Chris@583 1453 m_lastError = error;
Chris@583 1454 }
Chris@301 1455
Chris@387 1456 Model *model = i->first->getModel();
Chris@387 1457 RangeSummarisableTimeValueModel *wfm =
Chris@387 1458 dynamic_cast<RangeSummarisableTimeValueModel *>(model);
Chris@387 1459
Chris@388 1460 if (completion > 0) {
Chris@555 1461 pb->setMaximum(100); // was 0, for indeterminate start
Chris@388 1462 }
Chris@388 1463
Chris@301 1464 if (completion >= 100) {
Chris@301 1465
Chris@301 1466 //!!!
Chris@326 1467 if (wfm ||
Chris@328 1468 (wfm = dynamic_cast<RangeSummarisableTimeValueModel *>
Chris@328 1469 (model->getSourceModel()))) {
Chris@301 1470 completion = wfm->getAlignmentCompletion();
Chris@587 1471 // SVDEBUG << "View::checkProgress: Alignment completion = " << completion << endl;
Chris@301 1472 if (completion < 100) {
Chris@301 1473 text = tr("Alignment");
Chris@301 1474 }
Chris@301 1475 }
Chris@387 1476
Chris@387 1477 } else if (wfm) {
Chris@387 1478 update(); // ensure duration &c gets updated
Chris@301 1479 }
Chris@127 1480
Chris@127 1481 if (completion >= 100) {
Chris@127 1482
Chris@555 1483 pb->hide();
Chris@555 1484 timer->stop();
Chris@127 1485
Chris@127 1486 } else {
Chris@127 1487
Chris@555 1488 // std::cerr << "progress = " << completion << std::endl;
Chris@555 1489
Chris@555 1490 if (!pb->isVisible()) {
Chris@555 1491 i->second.lastCheck = 0;
Chris@555 1492 timer->setInterval(2000);
Chris@555 1493 timer->start();
Chris@555 1494 }
Chris@555 1495
Chris@555 1496 pb->setValue(completion);
Chris@555 1497 pb->move(0, ph - pb->height());
Chris@555 1498
Chris@555 1499 pb->show();
Chris@555 1500 pb->update();
Chris@555 1501
Chris@555 1502 ph -= pb->height();
Chris@127 1503 }
Chris@127 1504 } else {
Chris@555 1505 if (pb->isVisible()) {
Chris@555 1506 ph -= pb->height();
Chris@127 1507 }
Chris@127 1508 }
Chris@127 1509 }
Chris@127 1510 }
Chris@127 1511
Chris@555 1512 void
Chris@555 1513 View::progressCheckStalledTimerElapsed()
Chris@555 1514 {
Chris@555 1515 QObject *s = sender();
Chris@555 1516 QTimer *t = qobject_cast<QTimer *>(s);
Chris@555 1517 if (!t) return;
Chris@555 1518 for (ProgressMap::iterator i = m_progressBars.begin();
Chris@555 1519 i != m_progressBars.end(); ++i) {
Chris@555 1520 if (i->second.checkTimer == t) {
Chris@555 1521 int value = i->second.bar->value();
Chris@555 1522 if (value > 0 && value == i->second.lastCheck) {
Chris@555 1523 i->second.bar->setMaximum(0); // indeterminate
Chris@555 1524 }
Chris@555 1525 i->second.lastCheck = value;
Chris@555 1526 return;
Chris@555 1527 }
Chris@555 1528 }
Chris@555 1529 }
Chris@555 1530
Chris@384 1531 int
Chris@384 1532 View::getProgressBarWidth() const
Chris@384 1533 {
Chris@384 1534 for (ProgressMap::const_iterator i = m_progressBars.begin();
Chris@384 1535 i != m_progressBars.end(); ++i) {
Chris@555 1536 if (i->second.bar && i->second.bar->isVisible()) {
Chris@555 1537 return i->second.bar->width();
Chris@555 1538 }
Chris@384 1539 }
Chris@384 1540
Chris@384 1541 return 0;
Chris@384 1542 }
Chris@384 1543
Chris@127 1544 void
Chris@339 1545 View::setPaintFont(QPainter &paint)
Chris@339 1546 {
Chris@339 1547 QFont font(paint.font());
Chris@339 1548 font.setPointSize(Preferences::getInstance()->getViewFontSize());
Chris@339 1549 paint.setFont(font);
Chris@339 1550 }
Chris@339 1551
Chris@339 1552 void
Chris@127 1553 View::paintEvent(QPaintEvent *e)
Chris@127 1554 {
Chris@127 1555 // Profiler prof("View::paintEvent", false);
Chris@587 1556 // SVDEBUG << "View::paintEvent: centre frame is " << m_centreFrame << endl;
Chris@127 1557
Chris@127 1558 if (m_layers.empty()) {
Chris@127 1559 QFrame::paintEvent(e);
Chris@127 1560 return;
Chris@127 1561 }
Chris@127 1562
Chris@127 1563 // ensure our constraints are met
Chris@137 1564
Chris@137 1565 /*!!! Should we do this only if we have layers that can't support other
Chris@137 1566 zoom levels?
Chris@137 1567
Chris@127 1568 m_zoomLevel = getZoomConstraintBlockSize(m_zoomLevel,
Chris@127 1569 ZoomConstraint::RoundUp);
Chris@137 1570 */
Chris@127 1571
Chris@127 1572 QPainter paint;
Chris@127 1573 bool repaintCache = false;
Chris@127 1574 bool paintedCacheRect = false;
Chris@127 1575
Chris@127 1576 QRect cacheRect(rect());
Chris@127 1577
Chris@127 1578 if (e) {
Chris@127 1579 cacheRect &= e->rect();
Chris@127 1580 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1581 std::cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
Chris@127 1582 << ", my rect " << width() << "x" << height() << std::endl;
Chris@127 1583 #endif
Chris@127 1584 }
Chris@127 1585
Chris@127 1586 QRect nonCacheRect(cacheRect);
Chris@127 1587
Chris@127 1588 // If not all layers are scrollable, but some of the back layers
Chris@127 1589 // are, we should store only those in the cache.
Chris@127 1590
Chris@127 1591 bool layersChanged = false;
Chris@127 1592 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
Chris@127 1593 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged);
Chris@127 1594 bool selectionCacheable = nonScrollables.empty();
Chris@127 1595 bool haveSelections = m_manager && !m_manager->getSelections().empty();
Chris@127 1596 bool selectionDrawn = false;
Chris@127 1597
Chris@127 1598 // If all the non-scrollable layers are non-opaque, then we draw
Chris@127 1599 // the selection rectangle behind them and cache it. If any are
Chris@127 1600 // opaque, however, we can't cache.
Chris@127 1601 //
Chris@127 1602 if (!selectionCacheable) {
Chris@127 1603 selectionCacheable = true;
Chris@127 1604 for (LayerList::const_iterator i = nonScrollables.begin();
Chris@127 1605 i != nonScrollables.end(); ++i) {
Chris@127 1606 if ((*i)->isLayerOpaque()) {
Chris@127 1607 selectionCacheable = false;
Chris@127 1608 break;
Chris@127 1609 }
Chris@127 1610 }
Chris@127 1611 }
Chris@127 1612
Chris@127 1613 if (selectionCacheable) {
Chris@127 1614 QPoint localPos;
Chris@127 1615 bool closeToLeft, closeToRight;
Chris@127 1616 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
Chris@127 1617 selectionCacheable = false;
Chris@127 1618 }
Chris@127 1619 }
Chris@127 1620
Chris@127 1621 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1622 std::cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
Chris@127 1623 << " scrollable back layers and " << nonScrollables.size()
Chris@127 1624 << " non-scrollable front layers" << std::endl;
Chris@127 1625 std::cerr << "haveSelections " << haveSelections << ", selectionCacheable "
Chris@127 1626 << selectionCacheable << ", m_selectionCached " << m_selectionCached << std::endl;
Chris@127 1627 #endif
Chris@127 1628
Chris@127 1629 if (layersChanged || scrollables.empty() ||
Chris@127 1630 (haveSelections && (selectionCacheable != m_selectionCached))) {
Chris@127 1631 delete m_cache;
Chris@127 1632 m_cache = 0;
Chris@127 1633 m_selectionCached = false;
Chris@127 1634 }
Chris@127 1635
Chris@127 1636 if (!scrollables.empty()) {
Chris@244 1637
Chris@244 1638 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@244 1639 std::cerr << "View(" << this << "): cache " << m_cache << ", cache zoom "
Chris@244 1640 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << std::endl;
Chris@244 1641 #endif
Chris@244 1642
Chris@127 1643 if (!m_cache ||
Chris@127 1644 m_cacheZoomLevel != m_zoomLevel ||
Chris@127 1645 width() != m_cache->width() ||
Chris@127 1646 height() != m_cache->height()) {
Chris@127 1647
Chris@127 1648 // cache is not valid
Chris@127 1649
Chris@127 1650 if (cacheRect.width() < width()/10) {
Chris@244 1651 delete m_cache;
Chris@244 1652 m_cache = 0;
Chris@127 1653 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1654 std::cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << std::endl;
Chris@127 1655 #endif
Chris@127 1656 } else {
Chris@127 1657 delete m_cache;
Chris@127 1658 m_cache = new QPixmap(width(), height());
Chris@127 1659 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1660 std::cerr << "View(" << this << ")::paintEvent: recreated cache" << std::endl;
Chris@127 1661 #endif
Chris@127 1662 cacheRect = rect();
Chris@127 1663 repaintCache = true;
Chris@127 1664 }
Chris@127 1665
Chris@127 1666 } else if (m_cacheCentreFrame != m_centreFrame) {
Chris@127 1667
Chris@127 1668 long dx =
Chris@127 1669 getXForFrame(m_cacheCentreFrame) -
Chris@127 1670 getXForFrame(m_centreFrame);
Chris@127 1671
Chris@127 1672 if (dx > -width() && dx < width()) {
Chris@548 1673 #ifdef PIXMAP_COPY_TO_SELF
Chris@548 1674 // This is not normally defined. Copying a pixmap to
Chris@548 1675 // itself doesn't work properly on Windows, Mac, or
Chris@548 1676 // X11 with the raster backend (it only works when
Chris@548 1677 // moving in one direction and then presumably only by
Chris@548 1678 // accident). It does actually seem to be fine on X11
Chris@548 1679 // with the native backend, but we prefer not to use
Chris@548 1680 // that anyway
Chris@548 1681 paint.begin(m_cache);
Chris@548 1682 paint.drawPixmap(dx, 0, *m_cache);
Chris@548 1683 paint.end();
Chris@548 1684 #else
Chris@127 1685 static QPixmap *tmpPixmap = 0;
Chris@127 1686 if (!tmpPixmap ||
Chris@127 1687 tmpPixmap->width() != width() ||
Chris@127 1688 tmpPixmap->height() != height()) {
Chris@127 1689 delete tmpPixmap;
Chris@127 1690 tmpPixmap = new QPixmap(width(), height());
Chris@127 1691 }
Chris@127 1692 paint.begin(tmpPixmap);
Chris@127 1693 paint.drawPixmap(0, 0, *m_cache);
Chris@127 1694 paint.end();
Chris@127 1695 paint.begin(m_cache);
Chris@127 1696 paint.drawPixmap(dx, 0, *tmpPixmap);
Chris@127 1697 paint.end();
Chris@127 1698 #endif
Chris@127 1699 if (dx < 0) {
Chris@127 1700 cacheRect = QRect(width() + dx, 0, -dx, height());
Chris@127 1701 } else {
Chris@127 1702 cacheRect = QRect(0, 0, dx, height());
Chris@127 1703 }
Chris@127 1704 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1705 std::cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << std::endl;
Chris@127 1706 #endif
Chris@127 1707 } else {
Chris@127 1708 cacheRect = rect();
Chris@127 1709 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1710 std::cerr << "View(" << this << ")::paintEvent: scrolling too far" << std::endl;
Chris@127 1711 #endif
Chris@127 1712 }
Chris@127 1713 repaintCache = true;
Chris@127 1714
Chris@127 1715 } else {
Chris@127 1716 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1717 std::cerr << "View(" << this << ")::paintEvent: cache is good" << std::endl;
Chris@127 1718 #endif
Chris@127 1719 paint.begin(this);
Chris@127 1720 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@127 1721 paint.end();
Chris@127 1722 QFrame::paintEvent(e);
Chris@127 1723 paintedCacheRect = true;
Chris@127 1724 }
Chris@127 1725
Chris@127 1726 m_cacheCentreFrame = m_centreFrame;
Chris@127 1727 m_cacheZoomLevel = m_zoomLevel;
Chris@127 1728 }
Chris@127 1729
Chris@127 1730 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1731 // std::cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << std::endl;
Chris@127 1732 #endif
Chris@127 1733
Chris@127 1734 // Scrollable (cacheable) items first
Chris@127 1735
Chris@127 1736 if (!paintedCacheRect) {
Chris@127 1737
Chris@127 1738 if (repaintCache) paint.begin(m_cache);
Chris@127 1739 else paint.begin(this);
Chris@339 1740 setPaintFont(paint);
Chris@127 1741 paint.setClipRect(cacheRect);
Chris@287 1742
Chris@287 1743 paint.setPen(getBackground());
Chris@287 1744 paint.setBrush(getBackground());
Chris@127 1745 paint.drawRect(cacheRect);
Chris@127 1746
Chris@287 1747 paint.setPen(getForeground());
Chris@127 1748 paint.setBrush(Qt::NoBrush);
Chris@127 1749
Chris@127 1750 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
Chris@127 1751 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@127 1752 paint.save();
Chris@127 1753 (*i)->paint(this, paint, cacheRect);
Chris@127 1754 paint.restore();
Chris@127 1755 }
Chris@127 1756
Chris@127 1757 if (haveSelections && selectionCacheable) {
Chris@127 1758 drawSelections(paint);
Chris@127 1759 m_selectionCached = repaintCache;
Chris@127 1760 selectionDrawn = true;
Chris@127 1761 }
Chris@127 1762
Chris@127 1763 paint.end();
Chris@127 1764
Chris@127 1765 if (repaintCache) {
Chris@127 1766 cacheRect |= (e ? e->rect() : rect());
Chris@127 1767 paint.begin(this);
Chris@127 1768 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@127 1769 paint.end();
Chris@127 1770 }
Chris@127 1771 }
Chris@127 1772
Chris@127 1773 // Now non-cacheable items. We always need to redraw the
Chris@127 1774 // non-cacheable items across at least the area we drew of the
Chris@127 1775 // cacheable items.
Chris@127 1776
Chris@127 1777 nonCacheRect |= cacheRect;
Chris@127 1778
Chris@127 1779 paint.begin(this);
Chris@127 1780 paint.setClipRect(nonCacheRect);
Chris@339 1781 setPaintFont(paint);
Chris@127 1782 if (scrollables.empty()) {
Chris@287 1783 paint.setPen(getBackground());
Chris@287 1784 paint.setBrush(getBackground());
Chris@127 1785 paint.drawRect(nonCacheRect);
Chris@127 1786 }
Chris@127 1787
Chris@287 1788 paint.setPen(getForeground());
Chris@127 1789 paint.setBrush(Qt::NoBrush);
Chris@127 1790
Chris@127 1791 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
Chris@127 1792 // Profiler profiler2("View::paintEvent non-cacheable");
Chris@127 1793 (*i)->paint(this, paint, nonCacheRect);
Chris@127 1794 }
Chris@127 1795
Chris@127 1796 paint.end();
Chris@127 1797
Chris@127 1798 paint.begin(this);
Chris@339 1799 setPaintFont(paint);
Chris@127 1800 if (e) paint.setClipRect(e->rect());
Chris@127 1801 if (!m_selectionCached) {
Chris@127 1802 drawSelections(paint);
Chris@127 1803 }
Chris@127 1804 paint.end();
Chris@127 1805
Chris@211 1806 bool showPlayPointer = true;
Chris@211 1807 if (m_followPlay == PlaybackScrollContinuous) {
Chris@211 1808 showPlayPointer = false;
Chris@211 1809 } else if (long(m_playPointerFrame) <= getStartFrame() ||
Chris@211 1810 m_playPointerFrame >= getEndFrame()) {
Chris@211 1811 showPlayPointer = false;
Chris@211 1812 } else if (m_manager && !m_manager->isPlaying()) {
Chris@211 1813 if (m_playPointerFrame == getCentreFrame() &&
Chris@211 1814 m_followPlay != PlaybackIgnore) {
Chris@211 1815 showPlayPointer = false;
Chris@211 1816 }
Chris@211 1817 }
Chris@211 1818
Chris@211 1819 if (showPlayPointer) {
Chris@127 1820
Chris@127 1821 paint.begin(this);
Chris@127 1822
Chris@211 1823 int playx = getXForFrame(m_playPointerFrame);
Chris@211 1824
Chris@287 1825 paint.setPen(getForeground());
Chris@211 1826 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
Chris@211 1827 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
Chris@211 1828 paint.drawPoint(playx, 0);
Chris@211 1829 paint.drawPoint(playx, height() - 1);
Chris@287 1830 paint.setPen(getBackground());
Chris@211 1831 paint.drawLine(playx, 1, playx, height() - 2);
Chris@127 1832
Chris@127 1833 paint.end();
Chris@127 1834 }
Chris@127 1835
Chris@127 1836 QFrame::paintEvent(e);
Chris@127 1837 }
Chris@127 1838
Chris@127 1839 void
Chris@127 1840 View::drawSelections(QPainter &paint)
Chris@127 1841 {
Chris@217 1842 if (!hasTopLayerTimeXAxis()) return;
Chris@217 1843
Chris@127 1844 MultiSelection::SelectionList selections;
Chris@127 1845
Chris@127 1846 if (m_manager) {
Chris@127 1847 selections = m_manager->getSelections();
Chris@127 1848 if (m_manager->haveInProgressSelection()) {
Chris@127 1849 bool exclusive;
Chris@127 1850 Selection inProgressSelection =
Chris@127 1851 m_manager->getInProgressSelection(exclusive);
Chris@127 1852 if (exclusive) selections.clear();
Chris@127 1853 selections.insert(inProgressSelection);
Chris@127 1854 }
Chris@127 1855 }
Chris@127 1856
Chris@127 1857 paint.save();
Chris@183 1858
Chris@183 1859 bool translucent = !areLayerColoursSignificant();
Chris@183 1860
Chris@183 1861 if (translucent) {
Chris@183 1862 paint.setBrush(QColor(150, 150, 255, 80));
Chris@183 1863 } else {
Chris@183 1864 paint.setBrush(Qt::NoBrush);
Chris@183 1865 }
Chris@127 1866
Chris@127 1867 int sampleRate = getModelsSampleRate();
Chris@127 1868
Chris@127 1869 QPoint localPos;
Chris@127 1870 long illuminateFrame = -1;
Chris@127 1871 bool closeToLeft, closeToRight;
Chris@127 1872
Chris@127 1873 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
Chris@127 1874 illuminateFrame = getFrameForX(localPos.x());
Chris@127 1875 }
Chris@127 1876
Chris@127 1877 const QFontMetrics &metrics = paint.fontMetrics();
Chris@127 1878
Chris@127 1879 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@127 1880 i != selections.end(); ++i) {
Chris@127 1881
Chris@333 1882 int p0 = getXForFrame(alignFromReference(i->getStartFrame()));
Chris@333 1883 int p1 = getXForFrame(alignFromReference(i->getEndFrame()));
Chris@127 1884
Chris@127 1885 if (p1 < 0 || p0 > width()) continue;
Chris@127 1886
Chris@127 1887 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@587 1888 SVDEBUG << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << endl;
Chris@127 1889 #endif
Chris@127 1890
Chris@127 1891 bool illuminateThis =
Chris@127 1892 (illuminateFrame >= 0 && i->contains(illuminateFrame));
Chris@127 1893
Chris@127 1894 paint.setPen(QColor(150, 150, 255));
Chris@183 1895
Chris@183 1896 if (translucent && shouldLabelSelections()) {
Chris@183 1897 paint.drawRect(p0, -1, p1 - p0, height() + 1);
Chris@183 1898 } else {
Chris@183 1899 // Make the top & bottom lines of the box visible if we
Chris@183 1900 // are lacking some of the other visual cues. There's no
Chris@183 1901 // particular logic to this, it's just a question of what
Chris@183 1902 // I happen to think looks nice.
Chris@183 1903 paint.drawRect(p0, 0, p1 - p0, height() - 1);
Chris@183 1904 }
Chris@127 1905
Chris@127 1906 if (illuminateThis) {
Chris@127 1907 paint.save();
Chris@287 1908 paint.setPen(QPen(getForeground(), 2));
Chris@127 1909 if (closeToLeft) {
Chris@127 1910 paint.drawLine(p0, 1, p1, 1);
Chris@127 1911 paint.drawLine(p0, 0, p0, height());
Chris@127 1912 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 1913 } else if (closeToRight) {
Chris@127 1914 paint.drawLine(p0, 1, p1, 1);
Chris@127 1915 paint.drawLine(p1, 0, p1, height());
Chris@127 1916 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 1917 } else {
Chris@127 1918 paint.setBrush(Qt::NoBrush);
Chris@127 1919 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@127 1920 }
Chris@127 1921 paint.restore();
Chris@127 1922 }
Chris@127 1923
Chris@127 1924 if (sampleRate && shouldLabelSelections() && m_manager &&
Chris@189 1925 m_manager->shouldShowSelectionExtents()) {
Chris@127 1926
Chris@127 1927 QString startText = QString("%1 / %2")
Chris@127 1928 .arg(QString::fromStdString
Chris@127 1929 (RealTime::frame2RealTime
Chris@127 1930 (i->getStartFrame(), sampleRate).toText(true)))
Chris@127 1931 .arg(i->getStartFrame());
Chris@127 1932
Chris@127 1933 QString endText = QString(" %1 / %2")
Chris@127 1934 .arg(QString::fromStdString
Chris@127 1935 (RealTime::frame2RealTime
Chris@127 1936 (i->getEndFrame(), sampleRate).toText(true)))
Chris@127 1937 .arg(i->getEndFrame());
Chris@127 1938
Chris@127 1939 QString durationText = QString("(%1 / %2) ")
Chris@127 1940 .arg(QString::fromStdString
Chris@127 1941 (RealTime::frame2RealTime
Chris@127 1942 (i->getEndFrame() - i->getStartFrame(), sampleRate)
Chris@127 1943 .toText(true)))
Chris@127 1944 .arg(i->getEndFrame() - i->getStartFrame());
Chris@127 1945
Chris@127 1946 int sw = metrics.width(startText),
Chris@127 1947 ew = metrics.width(endText),
Chris@127 1948 dw = metrics.width(durationText);
Chris@127 1949
Chris@127 1950 int sy = metrics.ascent() + metrics.height() + 4;
Chris@127 1951 int ey = sy;
Chris@127 1952 int dy = sy + metrics.height();
Chris@127 1953
Chris@127 1954 int sx = p0 + 2;
Chris@127 1955 int ex = sx;
Chris@127 1956 int dx = sx;
Chris@127 1957
Chris@501 1958 bool durationBothEnds = true;
Chris@501 1959
Chris@127 1960 if (sw + ew > (p1 - p0)) {
Chris@127 1961 ey += metrics.height();
Chris@127 1962 dy += metrics.height();
Chris@501 1963 durationBothEnds = false;
Chris@127 1964 }
Chris@127 1965
Chris@127 1966 if (ew < (p1 - p0)) {
Chris@127 1967 ex = p1 - 2 - ew;
Chris@127 1968 }
Chris@127 1969
Chris@127 1970 if (dw < (p1 - p0)) {
Chris@127 1971 dx = p1 - 2 - dw;
Chris@127 1972 }
Chris@127 1973
Chris@127 1974 paint.drawText(sx, sy, startText);
Chris@127 1975 paint.drawText(ex, ey, endText);
Chris@127 1976 paint.drawText(dx, dy, durationText);
Chris@501 1977 if (durationBothEnds) {
Chris@501 1978 paint.drawText(sx, dy, durationText);
Chris@501 1979 }
Chris@127 1980 }
Chris@127 1981 }
Chris@127 1982
Chris@127 1983 paint.restore();
Chris@127 1984 }
Chris@127 1985
Chris@267 1986 void
Chris@270 1987 View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r,
Chris@270 1988 bool focus) const
Chris@267 1989 {
Chris@587 1990 // SVDEBUG << "View::drawMeasurementRect(" << r.x() << "," << r.y() << " "
Chris@585 1991 // << r.width() << "x" << r.height() << ")" << endl;
Chris@268 1992
Chris@267 1993 if (r.x() + r.width() < 0 || r.x() >= width()) return;
Chris@267 1994
Chris@270 1995 if (r.width() != 0 || r.height() != 0) {
Chris@270 1996 paint.save();
Chris@270 1997 if (focus) {
Chris@270 1998 paint.setPen(Qt::NoPen);
Chris@272 1999 QColor brushColour(Qt::black);
Chris@272 2000 brushColour.setAlpha(hasLightBackground() ? 15 : 40);
Chris@270 2001 paint.setBrush(brushColour);
Chris@270 2002 if (r.x() > 0) {
Chris@270 2003 paint.drawRect(0, 0, r.x(), height());
Chris@270 2004 }
Chris@270 2005 if (r.x() + r.width() < width()) {
Chris@270 2006 paint.drawRect(r.x() + r.width(), 0, width()-r.x()-r.width(), height());
Chris@270 2007 }
Chris@270 2008 if (r.y() > 0) {
Chris@270 2009 paint.drawRect(r.x(), 0, r.width(), r.y());
Chris@270 2010 }
Chris@270 2011 if (r.y() + r.height() < height()) {
Chris@270 2012 paint.drawRect(r.x(), r.y() + r.height(), r.width(), height()-r.y()-r.height());
Chris@270 2013 }
Chris@270 2014 paint.setBrush(Qt::NoBrush);
Chris@270 2015 }
Chris@270 2016 paint.setPen(Qt::green);
Chris@270 2017 paint.drawRect(r);
Chris@270 2018 paint.restore();
Chris@270 2019 } else {
Chris@270 2020 paint.save();
Chris@270 2021 paint.setPen(Qt::green);
Chris@270 2022 paint.drawPoint(r.x(), r.y());
Chris@270 2023 paint.restore();
Chris@270 2024 }
Chris@270 2025
Chris@270 2026 if (!focus) return;
Chris@270 2027
Chris@278 2028 paint.save();
Chris@278 2029 QFont fn = paint.font();
Chris@278 2030 if (fn.pointSize() > 8) {
Chris@278 2031 fn.setPointSize(fn.pointSize() - 1);
Chris@278 2032 paint.setFont(fn);
Chris@278 2033 }
Chris@278 2034
Chris@267 2035 int fontHeight = paint.fontMetrics().height();
Chris@267 2036 int fontAscent = paint.fontMetrics().ascent();
Chris@267 2037
Chris@267 2038 float v0, v1;
Chris@267 2039 QString u0, u1;
Chris@267 2040 bool b0 = false, b1 = false;
Chris@267 2041
Chris@267 2042 QString axs, ays, bxs, bys, dxs, dys;
Chris@267 2043
Chris@267 2044 int axx, axy, bxx, bxy, dxx, dxy;
Chris@267 2045 int aw = 0, bw = 0, dw = 0;
Chris@267 2046
Chris@267 2047 int labelCount = 0;
Chris@267 2048
Chris@362 2049 // top-left point, x-coord
Chris@362 2050
Chris@267 2051 if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) {
Chris@267 2052 axs = QString("%1 %2").arg(v0).arg(u0);
Chris@278 2053 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
Chris@278 2054 axs = QString("%1 (%2)").arg(axs)
Chris@278 2055 .arg(Pitch::getPitchLabelForFrequency(v0));
Chris@278 2056 }
Chris@267 2057 aw = paint.fontMetrics().width(axs);
Chris@267 2058 ++labelCount;
Chris@267 2059 }
Chris@362 2060
Chris@362 2061 // bottom-right point, x-coord
Chris@267 2062
Chris@267 2063 if (r.width() > 0) {
Chris@267 2064 if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) {
Chris@267 2065 bxs = QString("%1 %2").arg(v1).arg(u1);
Chris@278 2066 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
Chris@278 2067 bxs = QString("%1 (%2)").arg(bxs)
Chris@278 2068 .arg(Pitch::getPitchLabelForFrequency(v1));
Chris@278 2069 }
Chris@267 2070 bw = paint.fontMetrics().width(bxs);
Chris@267 2071 }
Chris@267 2072 }
Chris@362 2073
Chris@362 2074 // dimension, width
Chris@267 2075
Chris@283 2076 if (b0 && b1 && v1 != v0 && u0 == u1) {
Chris@362 2077 dxs = QString("[%1 %2]").arg(fabs(v1 - v0)).arg(u1);
Chris@267 2078 dw = paint.fontMetrics().width(dxs);
Chris@267 2079 }
Chris@267 2080
Chris@267 2081 b0 = false;
Chris@267 2082 b1 = false;
Chris@267 2083
Chris@362 2084 // top-left point, y-coord
Chris@362 2085
Chris@267 2086 if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) {
Chris@267 2087 ays = QString("%1 %2").arg(v0).arg(u0);
Chris@278 2088 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
Chris@278 2089 ays = QString("%1 (%2)").arg(ays)
Chris@278 2090 .arg(Pitch::getPitchLabelForFrequency(v0));
Chris@278 2091 }
Chris@267 2092 aw = std::max(aw, paint.fontMetrics().width(ays));
Chris@267 2093 ++labelCount;
Chris@267 2094 }
Chris@267 2095
Chris@362 2096 // bottom-right point, y-coord
Chris@362 2097
Chris@267 2098 if (r.height() > 0) {
Chris@267 2099 if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) {
Chris@267 2100 bys = QString("%1 %2").arg(v1).arg(u1);
Chris@278 2101 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
Chris@278 2102 bys = QString("%1 (%2)").arg(bys)
Chris@278 2103 .arg(Pitch::getPitchLabelForFrequency(v1));
Chris@278 2104 }
Chris@267 2105 bw = std::max(bw, paint.fontMetrics().width(bys));
Chris@267 2106 }
Chris@267 2107 }
Chris@274 2108
Chris@274 2109 bool bd = false;
Chris@274 2110 float dy = 0.f;
Chris@274 2111 QString du;
Chris@274 2112
Chris@362 2113 // dimension, height
Chris@362 2114
Chris@274 2115 if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(),
Chris@283 2116 dy, du)) &&
Chris@283 2117 dy != 0) {
Chris@274 2118 if (du != "") {
Chris@362 2119 if (du == "Hz") {
Chris@362 2120 int semis;
Chris@362 2121 float cents;
Chris@362 2122 semis = Pitch::getPitchForFrequencyDifference(v0, v1, &cents);
Chris@362 2123 dys = QString("[%1 %2 (%3)]")
Chris@362 2124 .arg(dy).arg(du)
Chris@362 2125 .arg(Pitch::getLabelForPitchRange(semis, cents));
Chris@362 2126 } else {
Chris@362 2127 dys = QString("[%1 %2]").arg(dy).arg(du);
Chris@362 2128 }
Chris@274 2129 } else {
Chris@362 2130 dys = QString("[%1]").arg(dy);
Chris@274 2131 }
Chris@267 2132 dw = std::max(dw, paint.fontMetrics().width(dys));
Chris@267 2133 }
Chris@267 2134
Chris@267 2135 int mw = r.width();
Chris@267 2136 int mh = r.height();
Chris@267 2137
Chris@267 2138 bool edgeLabelsInside = false;
Chris@267 2139 bool sizeLabelsInside = false;
Chris@267 2140
Chris@267 2141 if (mw < std::max(aw, std::max(bw, dw)) + 4) {
Chris@267 2142 // defaults stand
Chris@267 2143 } else if (mw < aw + bw + 4) {
Chris@267 2144 if (mh > fontHeight * labelCount * 3 + 4) {
Chris@267 2145 edgeLabelsInside = true;
Chris@267 2146 sizeLabelsInside = true;
Chris@267 2147 } else if (mh > fontHeight * labelCount * 2 + 4) {
Chris@267 2148 edgeLabelsInside = true;
Chris@267 2149 }
Chris@267 2150 } else if (mw < aw + bw + dw + 4) {
Chris@267 2151 if (mh > fontHeight * labelCount * 3 + 4) {
Chris@267 2152 edgeLabelsInside = true;
Chris@267 2153 sizeLabelsInside = true;
Chris@267 2154 } else if (mh > fontHeight * labelCount + 4) {
Chris@267 2155 edgeLabelsInside = true;
Chris@267 2156 }
Chris@267 2157 } else {
Chris@267 2158 if (mh > fontHeight * labelCount + 4) {
Chris@267 2159 edgeLabelsInside = true;
Chris@267 2160 sizeLabelsInside = true;
Chris@267 2161 }
Chris@267 2162 }
Chris@267 2163
Chris@267 2164 if (edgeLabelsInside) {
Chris@267 2165
Chris@267 2166 axx = r.x() + 2;
Chris@267 2167 axy = r.y() + fontAscent + 2;
Chris@267 2168
Chris@267 2169 bxx = r.x() + r.width() - bw - 2;
Chris@267 2170 bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
Chris@267 2171
Chris@267 2172 } else {
Chris@267 2173
Chris@267 2174 axx = r.x() - aw - 2;
Chris@267 2175 axy = r.y() + fontAscent;
Chris@267 2176
Chris@267 2177 bxx = r.x() + r.width() + 2;
Chris@267 2178 bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
Chris@267 2179 }
Chris@267 2180
Chris@267 2181 dxx = r.width()/2 + r.x() - dw/2;
Chris@267 2182
Chris@267 2183 if (sizeLabelsInside) {
Chris@267 2184
Chris@267 2185 dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
Chris@267 2186
Chris@267 2187 } else {
Chris@267 2188
Chris@267 2189 dxy = r.y() + r.height() + fontAscent + 2;
Chris@267 2190 }
Chris@267 2191
Chris@267 2192 if (axs != "") {
Chris@267 2193 drawVisibleText(paint, axx, axy, axs, OutlinedText);
Chris@267 2194 axy += fontHeight;
Chris@267 2195 }
Chris@267 2196
Chris@267 2197 if (ays != "") {
Chris@267 2198 drawVisibleText(paint, axx, axy, ays, OutlinedText);
Chris@267 2199 axy += fontHeight;
Chris@267 2200 }
Chris@267 2201
Chris@267 2202 if (bxs != "") {
Chris@267 2203 drawVisibleText(paint, bxx, bxy, bxs, OutlinedText);
Chris@267 2204 bxy += fontHeight;
Chris@267 2205 }
Chris@267 2206
Chris@267 2207 if (bys != "") {
Chris@267 2208 drawVisibleText(paint, bxx, bxy, bys, OutlinedText);
Chris@267 2209 bxy += fontHeight;
Chris@267 2210 }
Chris@267 2211
Chris@267 2212 if (dxs != "") {
Chris@267 2213 drawVisibleText(paint, dxx, dxy, dxs, OutlinedText);
Chris@267 2214 dxy += fontHeight;
Chris@267 2215 }
Chris@267 2216
Chris@267 2217 if (dys != "") {
Chris@267 2218 drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
Chris@267 2219 dxy += fontHeight;
Chris@267 2220 }
Chris@278 2221
Chris@278 2222 paint.restore();
Chris@267 2223 }
Chris@267 2224
Chris@227 2225 bool
Chris@229 2226 View::render(QPainter &paint, int xorigin, size_t f0, size_t f1)
Chris@227 2227 {
Chris@227 2228 size_t x0 = f0 / m_zoomLevel;
Chris@227 2229 size_t x1 = f1 / m_zoomLevel;
Chris@227 2230
Chris@227 2231 size_t w = x1 - x0;
Chris@227 2232
Chris@227 2233 size_t origCentreFrame = m_centreFrame;
Chris@227 2234
Chris@227 2235 bool someLayersIncomplete = false;
Chris@227 2236
Chris@227 2237 for (LayerList::iterator i = m_layers.begin();
Chris@227 2238 i != m_layers.end(); ++i) {
Chris@227 2239
Chris@227 2240 int c = (*i)->getCompletion(this);
Chris@227 2241 if (c < 100) {
Chris@227 2242 someLayersIncomplete = true;
Chris@227 2243 break;
Chris@227 2244 }
Chris@227 2245 }
Chris@227 2246
Chris@227 2247 if (someLayersIncomplete) {
Chris@227 2248
Chris@227 2249 QProgressDialog progress(tr("Waiting for layers to be ready..."),
Chris@227 2250 tr("Cancel"), 0, 100, this);
Chris@227 2251
Chris@227 2252 int layerCompletion = 0;
Chris@227 2253
Chris@227 2254 while (layerCompletion < 100) {
Chris@227 2255
Chris@227 2256 for (LayerList::iterator i = m_layers.begin();
Chris@227 2257 i != m_layers.end(); ++i) {
Chris@227 2258
Chris@227 2259 int c = (*i)->getCompletion(this);
Chris@227 2260 if (i == m_layers.begin() || c < layerCompletion) {
Chris@227 2261 layerCompletion = c;
Chris@227 2262 }
Chris@227 2263 }
Chris@227 2264
Chris@227 2265 if (layerCompletion >= 100) break;
Chris@227 2266
Chris@227 2267 progress.setValue(layerCompletion);
Chris@227 2268 qApp->processEvents();
Chris@227 2269 if (progress.wasCanceled()) {
Chris@227 2270 update();
Chris@227 2271 return false;
Chris@227 2272 }
Chris@227 2273
Chris@227 2274 usleep(50000);
Chris@227 2275 }
Chris@227 2276 }
Chris@227 2277
Chris@227 2278 QProgressDialog progress(tr("Rendering image..."),
Chris@227 2279 tr("Cancel"), 0, w / width(), this);
Chris@227 2280
Chris@227 2281 for (size_t x = 0; x < w; x += width()) {
Chris@227 2282
Chris@227 2283 progress.setValue(x / width());
Chris@227 2284 qApp->processEvents();
Chris@227 2285 if (progress.wasCanceled()) {
Chris@227 2286 m_centreFrame = origCentreFrame;
Chris@227 2287 update();
Chris@227 2288 return false;
Chris@227 2289 }
Chris@227 2290
Chris@229 2291 m_centreFrame = f0 + (x + width()/2) * m_zoomLevel;
Chris@227 2292
Chris@227 2293 QRect chunk(0, 0, width(), height());
Chris@227 2294
Chris@287 2295 paint.setPen(getBackground());
Chris@287 2296 paint.setBrush(getBackground());
Chris@227 2297
Chris@229 2298 paint.drawRect(QRect(xorigin + x, 0, width(), height()));
Chris@227 2299
Chris@287 2300 paint.setPen(getForeground());
Chris@227 2301 paint.setBrush(Qt::NoBrush);
Chris@227 2302
Chris@227 2303 for (LayerList::iterator i = m_layers.begin();
Chris@227 2304 i != m_layers.end(); ++i) {
dan@574 2305 if(!((*i)->isLayerDormant(this))){
dan@574 2306
dan@574 2307 paint.setRenderHint(QPainter::Antialiasing, false);
dan@574 2308
dan@574 2309 paint.save();
dan@574 2310 paint.translate(xorigin + x, 0);
dan@574 2311
dan@574 2312 std::cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << std::endl;
dan@574 2313
dan@574 2314 (*i)->setSynchronousPainting(true);
dan@574 2315
dan@574 2316 (*i)->paint(this, paint, chunk);
dan@574 2317
dan@574 2318 (*i)->setSynchronousPainting(false);
dan@574 2319
dan@574 2320 paint.restore();
dan@574 2321 }
Chris@227 2322 }
Chris@227 2323 }
Chris@227 2324
Chris@227 2325 m_centreFrame = origCentreFrame;
Chris@227 2326 update();
Chris@227 2327 return true;
Chris@227 2328 }
Chris@227 2329
Chris@227 2330 QImage *
Chris@227 2331 View::toNewImage()
Chris@227 2332 {
Chris@227 2333 size_t f0 = getModelsStartFrame();
Chris@227 2334 size_t f1 = getModelsEndFrame();
Chris@227 2335
Chris@229 2336 return toNewImage(f0, f1);
Chris@229 2337 }
Chris@229 2338
Chris@229 2339 QImage *
Chris@229 2340 View::toNewImage(size_t f0, size_t f1)
Chris@229 2341 {
Chris@227 2342 size_t x0 = f0 / getZoomLevel();
Chris@227 2343 size_t x1 = f1 / getZoomLevel();
Chris@227 2344
Chris@227 2345 QImage *image = new QImage(x1 - x0, height(), QImage::Format_RGB32);
Chris@227 2346
Chris@227 2347 QPainter *paint = new QPainter(image);
Chris@229 2348 if (!render(*paint, 0, f0, f1)) {
Chris@227 2349 delete paint;
Chris@227 2350 delete image;
Chris@227 2351 return 0;
Chris@227 2352 } else {
Chris@227 2353 delete paint;
Chris@227 2354 return image;
Chris@227 2355 }
Chris@227 2356 }
Chris@227 2357
Chris@229 2358 QSize
Chris@229 2359 View::getImageSize()
Chris@229 2360 {
Chris@229 2361 size_t f0 = getModelsStartFrame();
Chris@229 2362 size_t f1 = getModelsEndFrame();
Chris@229 2363
Chris@229 2364 return getImageSize(f0, f1);
Chris@229 2365 }
Chris@229 2366
Chris@229 2367 QSize
Chris@229 2368 View::getImageSize(size_t f0, size_t f1)
Chris@229 2369 {
Chris@229 2370 size_t x0 = f0 / getZoomLevel();
Chris@229 2371 size_t x1 = f1 / getZoomLevel();
Chris@229 2372
Chris@229 2373 return QSize(x1 - x0, height());
Chris@229 2374 }
Chris@229 2375
Chris@316 2376 void
Chris@316 2377 View::toXml(QTextStream &stream,
Chris@316 2378 QString indent, QString extraAttributes) const
Chris@127 2379 {
Chris@316 2380 stream << indent;
Chris@127 2381
Chris@316 2382 stream << QString("<view "
Chris@316 2383 "centre=\"%1\" "
Chris@316 2384 "zoom=\"%2\" "
Chris@316 2385 "followPan=\"%3\" "
Chris@316 2386 "followZoom=\"%4\" "
Chris@316 2387 "tracking=\"%5\" "
Chris@316 2388 " %6>\n")
Chris@127 2389 .arg(m_centreFrame)
Chris@127 2390 .arg(m_zoomLevel)
Chris@127 2391 .arg(m_followPan)
Chris@127 2392 .arg(m_followZoom)
Chris@127 2393 .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
Chris@127 2394 m_followPlay == PlaybackScrollPage ? "page" : "ignore")
Chris@127 2395 .arg(extraAttributes);
Chris@127 2396
Chris@127 2397 for (size_t i = 0; i < m_layers.size(); ++i) {
Chris@186 2398 bool visible = !m_layers[i]->isLayerDormant(this);
Chris@316 2399 m_layers[i]->toBriefXml(stream, indent + " ",
Chris@316 2400 QString("visible=\"%1\"")
Chris@316 2401 .arg(visible ? "true" : "false"));
Chris@127 2402 }
Chris@127 2403
Chris@316 2404 stream << indent + "</view>\n";
Chris@127 2405 }
Chris@127 2406
Chris@127 2407 ViewPropertyContainer::ViewPropertyContainer(View *v) :
Chris@127 2408 m_v(v)
Chris@127 2409 {
Chris@127 2410 connect(m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@127 2411 this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
Chris@127 2412 }
Chris@127 2413