annotate view/View.cpp @ 583:4c484636d5ec

Record and show any error that occurs during layer processing (e.g. spectrogram layer runs out of disc space for feature files)
author Chris Cannam
date Thu, 14 Apr 2011 15:21:21 +0100
parents bb1035a24958
children 1fe7951a61e8
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@456 67 std::cerr << "View::View(" << this << ")" << std::endl;
Chris@127 68 }
Chris@127 69
Chris@127 70 View::~View()
Chris@127 71 {
Chris@460 72 // std::cerr << "View::~View(" << this << ")" << std::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@127 277 // std::cerr << "View::toolModeChanged(" << m_manager->getToolMode() << ")" << std::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@354 362 std::cerr << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << std::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@133 677 connect(m_manager, SIGNAL(zoomWheelsEnabledChanged()),
Chris@133 678 this, SLOT(zoomWheelsEnabledChanged()));
Chris@127 679
Chris@211 680 connect(this, SIGNAL(centreFrameChanged(unsigned long, bool,
Chris@211 681 PlaybackFollowMode)),
Chris@211 682 m_manager, SLOT(viewCentreFrameChanged(unsigned long, bool,
Chris@211 683 PlaybackFollowMode)));
Chris@211 684
Chris@222 685 connect(this, SIGNAL(zoomLevelChanged(unsigned long, bool)),
Chris@222 686 m_manager, SLOT(viewZoomLevelChanged(unsigned long, bool)));
Chris@127 687
Chris@516 688 // setCentreFrame(m_manager->getViewInitialCentreFrame());
Chris@516 689
Chris@364 690 if (m_followPlay == PlaybackScrollPage) {
Chris@516 691 // std::cerr << "View::setViewManager: setting centre frame to global centre frame: " << m_manager->getGlobalCentreFrame() << std::endl;
Chris@364 692 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
Chris@364 693 } else if (m_followPlay == PlaybackScrollContinuous) {
Chris@516 694 // std::cerr << "View::setViewManager: setting centre frame to playback frame: " << m_manager->getPlaybackFrame() << std::endl;
Chris@236 695 setCentreFrame(m_manager->getPlaybackFrame(), false);
Chris@236 696 } else if (m_followPan) {
Chris@516 697 // std::cerr << "View::setViewManager: (follow pan) setting centre frame to global centre frame: " << m_manager->getGlobalCentreFrame() << std::endl;
Chris@236 698 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
Chris@236 699 }
Chris@516 700
Chris@236 701 if (m_followZoom) setZoomLevel(m_manager->getGlobalZoom());
Chris@236 702
Chris@511 703 movePlayPointer(getAlignedPlaybackFrame());
Chris@511 704
Chris@127 705 toolModeChanged();
Chris@127 706 }
Chris@127 707
Chris@127 708 void
Chris@516 709 View::setViewManager(ViewManager *vm, long initialCentreFrame)
Chris@516 710 {
Chris@516 711 setViewManager(vm);
Chris@516 712 setCentreFrame(initialCentreFrame, false);
Chris@516 713 }
Chris@516 714
Chris@516 715 void
Chris@127 716 View::setFollowGlobalPan(bool f)
Chris@127 717 {
Chris@127 718 m_followPan = f;
Chris@127 719 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 720 }
Chris@127 721
Chris@127 722 void
Chris@127 723 View::setFollowGlobalZoom(bool f)
Chris@127 724 {
Chris@127 725 m_followZoom = f;
Chris@127 726 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 727 }
Chris@127 728
Chris@127 729 void
Chris@267 730 View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style) const
Chris@127 731 {
Chris@127 732 if (style == OutlinedText) {
Chris@127 733
Chris@279 734 paint.save();
Chris@279 735
Chris@575 736 QColor penColour, surroundColour, boxColour;
Chris@279 737
Chris@287 738 penColour = getForeground();
Chris@287 739 surroundColour = getBackground();
Chris@575 740 boxColour = surroundColour;
Chris@575 741 boxColour.setAlpha(127);
Chris@575 742
Chris@575 743 paint.setPen(Qt::NoPen);
Chris@575 744 paint.setBrush(boxColour);
Chris@575 745 QRect r = paint.fontMetrics().boundingRect(text);
Chris@575 746 r.translate(QPoint(x, y));
Chris@575 747 // std::cerr << "drawVisibleText: r = " << r.x() << "," <<r.y() << " " << r.width() << "x" << r.height() << std::endl;
Chris@575 748 paint.drawRect(r);
Chris@575 749 paint.setBrush(Qt::NoBrush);
Chris@279 750
Chris@127 751 paint.setPen(surroundColour);
Chris@127 752
Chris@127 753 for (int dx = -1; dx <= 1; ++dx) {
Chris@127 754 for (int dy = -1; dy <= 1; ++dy) {
Chris@127 755 if (!(dx || dy)) continue;
Chris@127 756 paint.drawText(x + dx, y + dy, text);
Chris@127 757 }
Chris@127 758 }
Chris@127 759
Chris@127 760 paint.setPen(penColour);
Chris@127 761
Chris@127 762 paint.drawText(x, y, text);
Chris@287 763
Chris@279 764 paint.restore();
Chris@127 765
Chris@127 766 } else {
Chris@127 767
Chris@127 768 std::cerr << "ERROR: View::drawVisibleText: Boxed style not yet implemented!" << std::endl;
Chris@127 769 }
Chris@127 770 }
Chris@127 771
Chris@127 772 void
Chris@127 773 View::setPlaybackFollow(PlaybackFollowMode m)
Chris@127 774 {
Chris@127 775 m_followPlay = m;
Chris@127 776 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@127 777 }
Chris@127 778
Chris@127 779 void
Chris@127 780 View::modelChanged()
Chris@127 781 {
Chris@127 782 QObject *obj = sender();
Chris@127 783
Chris@127 784 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 785 std::cerr << "View(" << this << ")::modelChanged()" << std::endl;
Chris@127 786 #endif
Chris@127 787
Chris@127 788 // If the model that has changed is not used by any of the cached
Chris@127 789 // layers, we won't need to recreate the cache
Chris@127 790
Chris@127 791 bool recreate = false;
Chris@127 792
Chris@127 793 bool discard;
Chris@127 794 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@127 795 for (LayerList::const_iterator i = scrollables.begin();
Chris@127 796 i != scrollables.end(); ++i) {
Chris@127 797 if (*i == obj || (*i)->getModel() == obj) {
Chris@127 798 recreate = true;
Chris@127 799 break;
Chris@127 800 }
Chris@127 801 }
Chris@127 802
Chris@127 803 if (recreate) {
Chris@127 804 delete m_cache;
Chris@127 805 m_cache = 0;
Chris@127 806 }
Chris@127 807
Chris@336 808 emit layerModelChanged();
Chris@336 809
Chris@127 810 checkProgress(obj);
Chris@127 811
Chris@127 812 update();
Chris@127 813 }
Chris@127 814
Chris@127 815 void
Chris@127 816 View::modelChanged(size_t startFrame, size_t endFrame)
Chris@127 817 {
Chris@127 818 QObject *obj = sender();
Chris@127 819
Chris@127 820 long myStartFrame = getStartFrame();
Chris@127 821 size_t myEndFrame = getEndFrame();
Chris@127 822
Chris@127 823 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 824 std::cerr << "View(" << this << ")::modelChanged(" << startFrame << "," << endFrame << ") [me " << myStartFrame << "," << myEndFrame << "]" << std::endl;
Chris@127 825 #endif
Chris@127 826
Chris@127 827 if (myStartFrame > 0 && endFrame < size_t(myStartFrame)) {
Chris@127 828 checkProgress(obj);
Chris@127 829 return;
Chris@127 830 }
Chris@127 831 if (startFrame > myEndFrame) {
Chris@127 832 checkProgress(obj);
Chris@127 833 return;
Chris@127 834 }
Chris@127 835
Chris@127 836 // If the model that has changed is not used by any of the cached
Chris@127 837 // layers, we won't need to recreate the cache
Chris@127 838
Chris@127 839 bool recreate = false;
Chris@127 840
Chris@127 841 bool discard;
Chris@127 842 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@127 843 for (LayerList::const_iterator i = scrollables.begin();
Chris@127 844 i != scrollables.end(); ++i) {
Chris@127 845 if (*i == obj || (*i)->getModel() == obj) {
Chris@127 846 recreate = true;
Chris@127 847 break;
Chris@127 848 }
Chris@127 849 }
Chris@127 850
Chris@127 851 if (recreate) {
Chris@127 852 delete m_cache;
Chris@127 853 m_cache = 0;
Chris@127 854 }
Chris@127 855
Chris@127 856 if (long(startFrame) < myStartFrame) startFrame = myStartFrame;
Chris@127 857 if (endFrame > myEndFrame) endFrame = myEndFrame;
Chris@127 858
Chris@127 859 checkProgress(obj);
Chris@127 860
Chris@127 861 update();
Chris@127 862 }
Chris@127 863
Chris@127 864 void
Chris@127 865 View::modelCompletionChanged()
Chris@127 866 {
Chris@326 867 // std::cerr << "View(" << this << ")::modelCompletionChanged()" << std::endl;
Chris@301 868
Chris@127 869 QObject *obj = sender();
Chris@127 870 checkProgress(obj);
Chris@127 871 }
Chris@127 872
Chris@127 873 void
Chris@320 874 View::modelAlignmentCompletionChanged()
Chris@320 875 {
Chris@326 876 // std::cerr << "View(" << this << ")::modelAlignmentCompletionChanged()" << std::endl;
Chris@320 877
Chris@320 878 QObject *obj = sender();
Chris@320 879 checkProgress(obj);
Chris@320 880 }
Chris@320 881
Chris@320 882 void
Chris@127 883 View::modelReplaced()
Chris@127 884 {
Chris@127 885 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 886 std::cerr << "View(" << this << ")::modelReplaced()" << std::endl;
Chris@127 887 #endif
Chris@127 888 delete m_cache;
Chris@127 889 m_cache = 0;
Chris@127 890
Chris@127 891 update();
Chris@127 892 }
Chris@127 893
Chris@127 894 void
Chris@127 895 View::layerParametersChanged()
Chris@127 896 {
Chris@127 897 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@127 898
Chris@127 899 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 900 std::cerr << "View::layerParametersChanged()" << std::endl;
Chris@127 901 #endif
Chris@127 902
Chris@127 903 delete m_cache;
Chris@127 904 m_cache = 0;
Chris@127 905 update();
Chris@127 906
Chris@127 907 if (layer) {
Chris@127 908 emit propertyContainerPropertyChanged(layer);
Chris@127 909 }
Chris@127 910 }
Chris@127 911
Chris@127 912 void
Chris@197 913 View::layerParameterRangesChanged()
Chris@197 914 {
Chris@197 915 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@197 916 if (layer) emit propertyContainerPropertyRangeChanged(layer);
Chris@197 917 }
Chris@197 918
Chris@197 919 void
Chris@268 920 View::layerMeasurementRectsChanged()
Chris@268 921 {
Chris@268 922 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@268 923 if (layer) update();
Chris@268 924 }
Chris@268 925
Chris@268 926 void
Chris@127 927 View::layerNameChanged()
Chris@127 928 {
Chris@127 929 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@127 930 if (layer) emit propertyContainerNameChanged(layer);
Chris@127 931 }
Chris@127 932
Chris@127 933 void
Chris@333 934 View::globalCentreFrameChanged(unsigned long rf)
Chris@127 935 {
Chris@211 936 if (m_followPan) {
Chris@333 937 size_t f = alignFromReference(rf);
Chris@363 938 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@333 939 std::cerr << "View[" << this << "]::globalCentreFrameChanged(" << rf
Chris@333 940 << "): setting centre frame to " << f << std::endl;
Chris@363 941 #endif
Chris@333 942 setCentreFrame(f, false);
Chris@127 943 }
Chris@127 944 }
Chris@127 945
Chris@127 946 void
Chris@248 947 View::viewCentreFrameChanged(View *, unsigned long )
Chris@211 948 {
Chris@211 949 // We do nothing with this, but a subclass might
Chris@211 950 }
Chris@211 951
Chris@211 952 void
Chris@127 953 View::viewManagerPlaybackFrameChanged(unsigned long f)
Chris@127 954 {
Chris@127 955 if (m_manager) {
Chris@127 956 if (sender() != m_manager) return;
Chris@127 957 }
Chris@127 958
Chris@301 959 f = getAlignedPlaybackFrame();
Chris@301 960
Chris@511 961 movePlayPointer(f);
Chris@511 962 }
Chris@511 963
Chris@511 964 void
Chris@511 965 View::movePlayPointer(unsigned long newFrame)
Chris@511 966 {
Chris@511 967 if (m_playPointerFrame == newFrame) return;
Chris@511 968 bool visibleChange =
Chris@511 969 (getXForFrame(m_playPointerFrame) != getXForFrame(newFrame));
Chris@127 970 size_t oldPlayPointerFrame = m_playPointerFrame;
Chris@511 971 m_playPointerFrame = newFrame;
Chris@511 972 if (!visibleChange) return;
Chris@127 973
Chris@513 974 bool somethingGoingOn =
Chris@513 975 ((QApplication::mouseButtons() != Qt::NoButton) ||
Chris@513 976 (QApplication::keyboardModifiers() & Qt::AltModifier));
Chris@513 977
Chris@127 978 switch (m_followPlay) {
Chris@127 979
Chris@127 980 case PlaybackScrollContinuous:
Chris@513 981 if (!somethingGoingOn) {
Chris@511 982 setCentreFrame(m_playPointerFrame, false);
Chris@127 983 }
Chris@127 984 break;
Chris@127 985
Chris@127 986 case PlaybackScrollPage:
Chris@127 987 {
Chris@127 988 int xold = getXForFrame(oldPlayPointerFrame);
Chris@127 989 update(xold - 1, 0, 3, height());
Chris@127 990
Chris@127 991 long w = getEndFrame() - getStartFrame();
Chris@127 992 w -= w/5;
Chris@511 993 long sf = (m_playPointerFrame / w) * w - w/8;
Chris@127 994
Chris@127 995 if (m_manager &&
Chris@127 996 m_manager->isPlaying() &&
Chris@127 997 m_manager->getPlaySelectionMode()) {
Chris@127 998 MultiSelection::SelectionList selections = m_manager->getSelections();
Chris@127 999 if (!selections.empty()) {
Chris@127 1000 size_t selectionStart = selections.begin()->getStartFrame();
Chris@127 1001 if (sf < long(selectionStart) - w / 10) {
Chris@127 1002 sf = long(selectionStart) - w / 10;
Chris@127 1003 }
Chris@127 1004 }
Chris@127 1005 }
Chris@127 1006
Chris@127 1007 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@511 1008 std::cerr << "PlaybackScrollPage: f = " << m_playPointerFrame << ", sf = " << sf << ", start frame "
Chris@127 1009 << getStartFrame() << std::endl;
Chris@127 1010 #endif
Chris@127 1011
Chris@127 1012 // We don't consider scrolling unless the pointer is outside
Chris@127 1013 // the clearly visible range already
Chris@127 1014
Chris@127 1015 int xnew = getXForFrame(m_playPointerFrame);
Chris@127 1016
Chris@127 1017 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1018 std::cerr << "xnew = " << xnew << ", width = " << width() << std::endl;
Chris@127 1019 #endif
Chris@127 1020
Chris@127 1021 if (xnew < width()/8 || xnew > (width()*7)/8) {
Chris@513 1022 if (!somethingGoingOn) {
Chris@127 1023 long offset = getFrameForX(width()/2) - getStartFrame();
Chris@127 1024 long newCentre = sf + offset;
Chris@127 1025 bool changed = setCentreFrame(newCentre, false);
Chris@127 1026 if (changed) {
Chris@127 1027 xold = getXForFrame(oldPlayPointerFrame);
Chris@127 1028 update(xold - 1, 0, 3, height());
Chris@127 1029 }
Chris@127 1030 }
Chris@127 1031 }
Chris@127 1032
Chris@127 1033 update(xnew - 1, 0, 3, height());
Chris@127 1034
Chris@127 1035 break;
Chris@127 1036 }
Chris@127 1037
Chris@127 1038 case PlaybackIgnore:
Chris@511 1039 if (long(m_playPointerFrame) >= getStartFrame() &&
Chris@511 1040 m_playPointerFrame < getEndFrame()) {
Chris@127 1041 update();
Chris@127 1042 }
Chris@127 1043 break;
Chris@127 1044 }
Chris@127 1045 }
Chris@127 1046
Chris@127 1047 void
Chris@222 1048 View::viewZoomLevelChanged(View *p, unsigned long z, bool locked)
Chris@127 1049 {
Chris@244 1050 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@244 1051 std::cerr << "View[" << this << "]: viewZoomLevelChanged(" << p << ", " << z << ", " << locked << ")" << std::endl;
Chris@244 1052 #endif
Chris@127 1053 if (m_followZoom && p != this && locked) {
Chris@222 1054 setZoomLevel(z);
Chris@127 1055 }
Chris@127 1056 }
Chris@127 1057
Chris@127 1058 void
Chris@127 1059 View::selectionChanged()
Chris@127 1060 {
Chris@127 1061 if (m_selectionCached) {
Chris@127 1062 delete m_cache;
Chris@127 1063 m_cache = 0;
Chris@127 1064 m_selectionCached = false;
Chris@127 1065 }
Chris@127 1066 update();
Chris@127 1067 }
Chris@127 1068
Chris@127 1069 size_t
Chris@222 1070 View::getFirstVisibleFrame() const
Chris@222 1071 {
Chris@222 1072 long f0 = getStartFrame();
Chris@222 1073 size_t f = getModelsStartFrame();
Chris@222 1074 if (f0 < 0 || f0 < long(f)) return f;
Chris@222 1075 return f0;
Chris@222 1076 }
Chris@222 1077
Chris@222 1078 size_t
Chris@222 1079 View::getLastVisibleFrame() const
Chris@222 1080 {
Chris@222 1081 size_t f0 = getEndFrame();
Chris@222 1082 size_t f = getModelsEndFrame();
Chris@222 1083 if (f0 > f) return f;
Chris@222 1084 return f0;
Chris@222 1085 }
Chris@222 1086
Chris@222 1087 size_t
Chris@127 1088 View::getModelsStartFrame() const
Chris@127 1089 {
Chris@127 1090 bool first = true;
Chris@127 1091 size_t startFrame = 0;
Chris@127 1092
Chris@127 1093 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1094
Chris@127 1095 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1096
Chris@127 1097 size_t thisStartFrame = (*i)->getModel()->getStartFrame();
Chris@127 1098
Chris@127 1099 if (first || thisStartFrame < startFrame) {
Chris@127 1100 startFrame = thisStartFrame;
Chris@127 1101 }
Chris@127 1102 first = false;
Chris@127 1103 }
Chris@127 1104 }
Chris@127 1105 return startFrame;
Chris@127 1106 }
Chris@127 1107
Chris@127 1108 size_t
Chris@127 1109 View::getModelsEndFrame() const
Chris@127 1110 {
Chris@127 1111 bool first = true;
Chris@127 1112 size_t endFrame = 0;
Chris@127 1113
Chris@127 1114 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1115
Chris@127 1116 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1117
Chris@127 1118 size_t thisEndFrame = (*i)->getModel()->getEndFrame();
Chris@127 1119
Chris@127 1120 if (first || thisEndFrame > endFrame) {
Chris@127 1121 endFrame = thisEndFrame;
Chris@127 1122 }
Chris@127 1123 first = false;
Chris@127 1124 }
Chris@127 1125 }
Chris@127 1126
Chris@127 1127 if (first) return getModelsStartFrame();
Chris@127 1128 return endFrame;
Chris@127 1129 }
Chris@127 1130
Chris@127 1131 int
Chris@127 1132 View::getModelsSampleRate() const
Chris@127 1133 {
Chris@127 1134 //!!! Just go for the first, for now. If we were supporting
Chris@127 1135 // multiple samplerates, we'd probably want to do frame/time
Chris@127 1136 // conversion in the model
Chris@127 1137
Chris@159 1138 //!!! nah, this wants to always return the sr of the main model!
Chris@159 1139
Chris@127 1140 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1141 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@127 1142 return (*i)->getModel()->getSampleRate();
Chris@127 1143 }
Chris@127 1144 }
Chris@127 1145 return 0;
Chris@127 1146 }
Chris@127 1147
Chris@315 1148 View::ModelSet
Chris@315 1149 View::getModels()
Chris@315 1150 {
Chris@315 1151 ModelSet models;
Chris@315 1152
Chris@315 1153 for (int i = 0; i < getLayerCount(); ++i) {
Chris@315 1154
Chris@315 1155 Layer *layer = getLayer(i);
Chris@315 1156
Chris@315 1157 if (dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@315 1158 continue;
Chris@315 1159 }
Chris@315 1160
Chris@315 1161 if (layer && layer->getModel()) {
Chris@315 1162 Model *model = layer->getModel();
Chris@315 1163 models.insert(model);
Chris@315 1164 }
Chris@315 1165 }
Chris@315 1166
Chris@315 1167 return models;
Chris@315 1168 }
Chris@315 1169
Chris@320 1170 Model *
Chris@320 1171 View::getAligningModel() const
Chris@301 1172 {
Chris@320 1173 if (!m_manager ||
Chris@320 1174 !m_manager->getAlignMode() ||
Chris@314 1175 !m_manager->getPlaybackModel()) {
Chris@320 1176 return 0;
Chris@314 1177 }
Chris@301 1178
Chris@320 1179 Model *anyModel = 0;
Chris@359 1180 Model *alignedModel = 0;
Chris@320 1181 Model *goodModel = 0;
Chris@301 1182
Chris@320 1183 for (LayerList::const_iterator i = m_layers.begin();
Chris@320 1184 i != m_layers.end(); ++i) {
Chris@320 1185
Chris@320 1186 Layer *layer = *i;
Chris@320 1187
Chris@320 1188 if (!layer) continue;
Chris@320 1189 if (dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@301 1190
Chris@301 1191 Model *model = (*i)->getModel();
Chris@301 1192 if (!model) continue;
Chris@301 1193
Chris@359 1194 anyModel = model;
Chris@359 1195
Chris@320 1196 if (model->getAlignmentReference()) {
Chris@359 1197 alignedModel = model;
Chris@320 1198 if (layer->isLayerOpaque() ||
Chris@320 1199 dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
Chris@320 1200 goodModel = model;
Chris@320 1201 }
Chris@301 1202 }
Chris@320 1203 }
Chris@301 1204
Chris@320 1205 if (goodModel) return goodModel;
Chris@359 1206 else if (alignedModel) return alignedModel;
Chris@320 1207 else return anyModel;
Chris@320 1208 }
Chris@320 1209
Chris@320 1210 size_t
Chris@320 1211 View::alignFromReference(size_t f) const
Chris@320 1212 {
Chris@321 1213 if (!m_manager->getAlignMode()) return f;
Chris@320 1214 Model *aligningModel = getAligningModel();
Chris@320 1215 if (!aligningModel) return f;
Chris@320 1216 return aligningModel->alignFromReference(f);
Chris@320 1217 }
Chris@320 1218
Chris@320 1219 size_t
Chris@320 1220 View::alignToReference(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->alignToReference(f);
Chris@320 1226 }
Chris@320 1227
Chris@320 1228 int
Chris@320 1229 View::getAlignedPlaybackFrame() const
Chris@320 1230 {
Chris@321 1231 int pf = m_manager->getPlaybackFrame();
Chris@321 1232 if (!m_manager->getAlignMode()) return pf;
Chris@321 1233
Chris@320 1234 Model *aligningModel = getAligningModel();
Chris@320 1235 if (!aligningModel) return pf;
Chris@333 1236 /*
Chris@320 1237 Model *pm = m_manager->getPlaybackModel();
Chris@301 1238
Chris@301 1239 // std::cerr << "View[" << this << "]::getAlignedPlaybackFrame: pf = " << pf;
Chris@301 1240
Chris@301 1241 if (pm) {
Chris@333 1242 pf = pm->alignToReference(pf);
Chris@301 1243 // std::cerr << " -> " << pf;
Chris@301 1244 }
Chris@333 1245 */
Chris@333 1246 int af = aligningModel->alignFromReference(pf);
Chris@301 1247
Chris@301 1248 // std::cerr << ", aligned = " << af << std::endl;
Chris@301 1249 return af;
Chris@301 1250 }
Chris@301 1251
Chris@127 1252 bool
Chris@127 1253 View::areLayersScrollable() const
Chris@127 1254 {
Chris@127 1255 // True iff all views are scrollable
Chris@127 1256 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1257 if (!(*i)->isLayerScrollable(this)) return false;
Chris@127 1258 }
Chris@127 1259 return true;
Chris@127 1260 }
Chris@127 1261
Chris@127 1262 View::LayerList
Chris@127 1263 View::getScrollableBackLayers(bool testChanged, bool &changed) const
Chris@127 1264 {
Chris@127 1265 changed = false;
Chris@127 1266
Chris@127 1267 // We want a list of all the scrollable layers that are behind the
Chris@127 1268 // backmost non-scrollable layer.
Chris@127 1269
Chris@127 1270 LayerList scrollables;
Chris@127 1271 bool metUnscrollable = false;
Chris@127 1272
Chris@127 1273 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@132 1274 // std::cerr << "View::getScrollableBackLayers: calling isLayerDormant on layer " << *i << std::endl;
Chris@132 1275 // std::cerr << "(name is " << (*i)->objectName().toStdString() << ")"
Chris@132 1276 // << std::endl;
Chris@132 1277 // std::cerr << "View::getScrollableBackLayers: I am " << this << std::endl;
Chris@127 1278 if ((*i)->isLayerDormant(this)) continue;
Chris@127 1279 if ((*i)->isLayerOpaque()) {
Chris@127 1280 // You can't see anything behind an opaque layer!
Chris@127 1281 scrollables.clear();
Chris@127 1282 if (metUnscrollable) break;
Chris@127 1283 }
Chris@127 1284 if (!metUnscrollable && (*i)->isLayerScrollable(this)) {
Chris@127 1285 scrollables.push_back(*i);
Chris@127 1286 } else {
Chris@127 1287 metUnscrollable = true;
Chris@127 1288 }
Chris@127 1289 }
Chris@127 1290
Chris@127 1291 if (testChanged && scrollables != m_lastScrollableBackLayers) {
Chris@127 1292 m_lastScrollableBackLayers = scrollables;
Chris@127 1293 changed = true;
Chris@127 1294 }
Chris@127 1295 return scrollables;
Chris@127 1296 }
Chris@127 1297
Chris@127 1298 View::LayerList
Chris@127 1299 View::getNonScrollableFrontLayers(bool testChanged, bool &changed) const
Chris@127 1300 {
Chris@127 1301 changed = false;
Chris@127 1302 LayerList nonScrollables;
Chris@127 1303
Chris@127 1304 // Everything in front of the first non-scrollable from the back
Chris@127 1305 // should also be considered non-scrollable
Chris@127 1306
Chris@127 1307 bool started = false;
Chris@127 1308
Chris@127 1309 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1310 if ((*i)->isLayerDormant(this)) continue;
Chris@127 1311 if (!started && (*i)->isLayerScrollable(this)) {
Chris@127 1312 continue;
Chris@127 1313 }
Chris@127 1314 started = true;
Chris@127 1315 if ((*i)->isLayerOpaque()) {
Chris@127 1316 // You can't see anything behind an opaque layer!
Chris@127 1317 nonScrollables.clear();
Chris@127 1318 }
Chris@127 1319 nonScrollables.push_back(*i);
Chris@127 1320 }
Chris@127 1321
Chris@127 1322 if (testChanged && nonScrollables != m_lastNonScrollableBackLayers) {
Chris@127 1323 m_lastNonScrollableBackLayers = nonScrollables;
Chris@127 1324 changed = true;
Chris@127 1325 }
Chris@127 1326
Chris@127 1327 return nonScrollables;
Chris@127 1328 }
Chris@127 1329
Chris@127 1330 size_t
Chris@127 1331 View::getZoomConstraintBlockSize(size_t blockSize,
Chris@127 1332 ZoomConstraint::RoundingDirection dir)
Chris@127 1333 const
Chris@127 1334 {
Chris@127 1335 size_t candidate = blockSize;
Chris@127 1336 bool haveCandidate = false;
Chris@127 1337
Chris@127 1338 PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
Chris@127 1339
Chris@127 1340 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@127 1341
Chris@127 1342 const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
Chris@127 1343 if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
Chris@127 1344
Chris@127 1345 size_t thisBlockSize =
Chris@127 1346 zoomConstraint->getNearestBlockSize(blockSize, dir);
Chris@127 1347
Chris@127 1348 // Go for the block size that's furthest from the one
Chris@127 1349 // passed in. Most of the time, that's what we want.
Chris@127 1350 if (!haveCandidate ||
Chris@127 1351 (thisBlockSize > blockSize && thisBlockSize > candidate) ||
Chris@127 1352 (thisBlockSize < blockSize && thisBlockSize < candidate)) {
Chris@127 1353 candidate = thisBlockSize;
Chris@127 1354 haveCandidate = true;
Chris@127 1355 }
Chris@127 1356 }
Chris@127 1357
Chris@127 1358 return candidate;
Chris@127 1359 }
Chris@127 1360
Chris@183 1361 bool
Chris@183 1362 View::areLayerColoursSignificant() const
Chris@183 1363 {
Chris@183 1364 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@287 1365 if ((*i)->getLayerColourSignificance() ==
Chris@287 1366 Layer::ColourHasMeaningfulValue) return true;
Chris@183 1367 if ((*i)->isLayerOpaque()) break;
Chris@183 1368 }
Chris@183 1369 return false;
Chris@183 1370 }
Chris@183 1371
Chris@217 1372 bool
Chris@217 1373 View::hasTopLayerTimeXAxis() const
Chris@217 1374 {
Chris@217 1375 LayerList::const_iterator i = m_layers.end();
Chris@217 1376 if (i == m_layers.begin()) return false;
Chris@217 1377 --i;
Chris@217 1378 return (*i)->hasTimeXAxis();
Chris@217 1379 }
Chris@217 1380
Chris@127 1381 void
Chris@127 1382 View::zoom(bool in)
Chris@127 1383 {
Chris@127 1384 int newZoomLevel = m_zoomLevel;
Chris@127 1385
Chris@127 1386 if (in) {
Chris@127 1387 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@127 1388 ZoomConstraint::RoundDown);
Chris@127 1389 } else {
Chris@127 1390 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@127 1391 ZoomConstraint::RoundUp);
Chris@127 1392 }
Chris@127 1393
Chris@127 1394 if (newZoomLevel != m_zoomLevel) {
Chris@127 1395 setZoomLevel(newZoomLevel);
Chris@127 1396 }
Chris@127 1397 }
Chris@127 1398
Chris@127 1399 void
Chris@510 1400 View::scroll(bool right, bool lots, bool e)
Chris@127 1401 {
Chris@127 1402 long delta;
Chris@127 1403 if (lots) {
Chris@127 1404 delta = (getEndFrame() - getStartFrame()) / 2;
Chris@127 1405 } else {
Chris@127 1406 delta = (getEndFrame() - getStartFrame()) / 20;
Chris@127 1407 }
Chris@127 1408 if (right) delta = -delta;
Chris@127 1409
Chris@127 1410 if (int(m_centreFrame) < delta) {
Chris@510 1411 setCentreFrame(0, e);
Chris@127 1412 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@510 1413 setCentreFrame(getModelsEndFrame(), e);
Chris@127 1414 } else {
Chris@510 1415 setCentreFrame(m_centreFrame - delta, e);
Chris@127 1416 }
Chris@127 1417 }
Chris@127 1418
Chris@127 1419 void
Chris@127 1420 View::checkProgress(void *object)
Chris@127 1421 {
Chris@127 1422 if (!m_showProgress) return;
Chris@127 1423
Chris@127 1424 int ph = height();
Chris@127 1425
Chris@555 1426 for (ProgressMap::iterator i = m_progressBars.begin();
Chris@127 1427 i != m_progressBars.end(); ++i) {
Chris@127 1428
Chris@555 1429 QProgressBar *pb = i->second.bar;
Chris@555 1430
Chris@127 1431 if (i->first == object) {
Chris@127 1432
Chris@555 1433 // The timer is used to test for stalls. If the progress
Chris@555 1434 // bar does not get updated for some length of time, the
Chris@555 1435 // timer prompts it to go back into "indeterminate" mode
Chris@555 1436 QTimer *timer = i->second.checkTimer;
Chris@555 1437
Chris@127 1438 int completion = i->first->getCompletion(this);
Chris@301 1439 QString text = i->first->getPropertyContainerName();
Chris@583 1440 QString error = i->first->getError(this);
Chris@583 1441
Chris@583 1442 if (error != "" && error != m_lastError) {
Chris@583 1443 QMessageBox::critical(this, tr("Layer rendering error"), error);
Chris@583 1444 m_lastError = error;
Chris@583 1445 }
Chris@301 1446
Chris@387 1447 Model *model = i->first->getModel();
Chris@387 1448 RangeSummarisableTimeValueModel *wfm =
Chris@387 1449 dynamic_cast<RangeSummarisableTimeValueModel *>(model);
Chris@387 1450
Chris@388 1451 if (completion > 0) {
Chris@555 1452 pb->setMaximum(100); // was 0, for indeterminate start
Chris@388 1453 }
Chris@388 1454
Chris@301 1455 if (completion >= 100) {
Chris@301 1456
Chris@301 1457 //!!!
Chris@326 1458 if (wfm ||
Chris@328 1459 (wfm = dynamic_cast<RangeSummarisableTimeValueModel *>
Chris@328 1460 (model->getSourceModel()))) {
Chris@301 1461 completion = wfm->getAlignmentCompletion();
Chris@406 1462 // std::cerr << "View::checkProgress: Alignment completion = " << completion << std::endl;
Chris@301 1463 if (completion < 100) {
Chris@301 1464 text = tr("Alignment");
Chris@301 1465 }
Chris@301 1466 }
Chris@387 1467
Chris@387 1468 } else if (wfm) {
Chris@387 1469 update(); // ensure duration &c gets updated
Chris@301 1470 }
Chris@127 1471
Chris@127 1472 if (completion >= 100) {
Chris@127 1473
Chris@555 1474 pb->hide();
Chris@555 1475 timer->stop();
Chris@127 1476
Chris@127 1477 } else {
Chris@127 1478
Chris@555 1479 // std::cerr << "progress = " << completion << std::endl;
Chris@555 1480
Chris@555 1481 if (!pb->isVisible()) {
Chris@555 1482 i->second.lastCheck = 0;
Chris@555 1483 timer->setInterval(2000);
Chris@555 1484 timer->start();
Chris@555 1485 }
Chris@555 1486
Chris@555 1487 pb->setValue(completion);
Chris@555 1488 pb->move(0, ph - pb->height());
Chris@555 1489
Chris@555 1490 pb->show();
Chris@555 1491 pb->update();
Chris@555 1492
Chris@555 1493 ph -= pb->height();
Chris@127 1494 }
Chris@127 1495 } else {
Chris@555 1496 if (pb->isVisible()) {
Chris@555 1497 ph -= pb->height();
Chris@127 1498 }
Chris@127 1499 }
Chris@127 1500 }
Chris@127 1501 }
Chris@127 1502
Chris@555 1503 void
Chris@555 1504 View::progressCheckStalledTimerElapsed()
Chris@555 1505 {
Chris@555 1506 QObject *s = sender();
Chris@555 1507 QTimer *t = qobject_cast<QTimer *>(s);
Chris@555 1508 if (!t) return;
Chris@555 1509 for (ProgressMap::iterator i = m_progressBars.begin();
Chris@555 1510 i != m_progressBars.end(); ++i) {
Chris@555 1511 if (i->second.checkTimer == t) {
Chris@555 1512 int value = i->second.bar->value();
Chris@555 1513 if (value > 0 && value == i->second.lastCheck) {
Chris@555 1514 i->second.bar->setMaximum(0); // indeterminate
Chris@555 1515 }
Chris@555 1516 i->second.lastCheck = value;
Chris@555 1517 return;
Chris@555 1518 }
Chris@555 1519 }
Chris@555 1520 }
Chris@555 1521
Chris@384 1522 int
Chris@384 1523 View::getProgressBarWidth() const
Chris@384 1524 {
Chris@384 1525 for (ProgressMap::const_iterator i = m_progressBars.begin();
Chris@384 1526 i != m_progressBars.end(); ++i) {
Chris@555 1527 if (i->second.bar && i->second.bar->isVisible()) {
Chris@555 1528 return i->second.bar->width();
Chris@555 1529 }
Chris@384 1530 }
Chris@384 1531
Chris@384 1532 return 0;
Chris@384 1533 }
Chris@384 1534
Chris@127 1535 void
Chris@339 1536 View::setPaintFont(QPainter &paint)
Chris@339 1537 {
Chris@339 1538 QFont font(paint.font());
Chris@339 1539 font.setPointSize(Preferences::getInstance()->getViewFontSize());
Chris@339 1540 paint.setFont(font);
Chris@339 1541 }
Chris@339 1542
Chris@339 1543 void
Chris@127 1544 View::paintEvent(QPaintEvent *e)
Chris@127 1545 {
Chris@127 1546 // Profiler prof("View::paintEvent", false);
Chris@236 1547 // std::cerr << "View::paintEvent: centre frame is " << m_centreFrame << std::endl;
Chris@127 1548
Chris@127 1549 if (m_layers.empty()) {
Chris@127 1550 QFrame::paintEvent(e);
Chris@127 1551 return;
Chris@127 1552 }
Chris@127 1553
Chris@127 1554 // ensure our constraints are met
Chris@137 1555
Chris@137 1556 /*!!! Should we do this only if we have layers that can't support other
Chris@137 1557 zoom levels?
Chris@137 1558
Chris@127 1559 m_zoomLevel = getZoomConstraintBlockSize(m_zoomLevel,
Chris@127 1560 ZoomConstraint::RoundUp);
Chris@137 1561 */
Chris@127 1562
Chris@127 1563 QPainter paint;
Chris@127 1564 bool repaintCache = false;
Chris@127 1565 bool paintedCacheRect = false;
Chris@127 1566
Chris@127 1567 QRect cacheRect(rect());
Chris@127 1568
Chris@127 1569 if (e) {
Chris@127 1570 cacheRect &= e->rect();
Chris@127 1571 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1572 std::cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
Chris@127 1573 << ", my rect " << width() << "x" << height() << std::endl;
Chris@127 1574 #endif
Chris@127 1575 }
Chris@127 1576
Chris@127 1577 QRect nonCacheRect(cacheRect);
Chris@127 1578
Chris@127 1579 // If not all layers are scrollable, but some of the back layers
Chris@127 1580 // are, we should store only those in the cache.
Chris@127 1581
Chris@127 1582 bool layersChanged = false;
Chris@127 1583 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
Chris@127 1584 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged);
Chris@127 1585 bool selectionCacheable = nonScrollables.empty();
Chris@127 1586 bool haveSelections = m_manager && !m_manager->getSelections().empty();
Chris@127 1587 bool selectionDrawn = false;
Chris@127 1588
Chris@127 1589 // If all the non-scrollable layers are non-opaque, then we draw
Chris@127 1590 // the selection rectangle behind them and cache it. If any are
Chris@127 1591 // opaque, however, we can't cache.
Chris@127 1592 //
Chris@127 1593 if (!selectionCacheable) {
Chris@127 1594 selectionCacheable = true;
Chris@127 1595 for (LayerList::const_iterator i = nonScrollables.begin();
Chris@127 1596 i != nonScrollables.end(); ++i) {
Chris@127 1597 if ((*i)->isLayerOpaque()) {
Chris@127 1598 selectionCacheable = false;
Chris@127 1599 break;
Chris@127 1600 }
Chris@127 1601 }
Chris@127 1602 }
Chris@127 1603
Chris@127 1604 if (selectionCacheable) {
Chris@127 1605 QPoint localPos;
Chris@127 1606 bool closeToLeft, closeToRight;
Chris@127 1607 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
Chris@127 1608 selectionCacheable = false;
Chris@127 1609 }
Chris@127 1610 }
Chris@127 1611
Chris@127 1612 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1613 std::cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
Chris@127 1614 << " scrollable back layers and " << nonScrollables.size()
Chris@127 1615 << " non-scrollable front layers" << std::endl;
Chris@127 1616 std::cerr << "haveSelections " << haveSelections << ", selectionCacheable "
Chris@127 1617 << selectionCacheable << ", m_selectionCached " << m_selectionCached << std::endl;
Chris@127 1618 #endif
Chris@127 1619
Chris@127 1620 if (layersChanged || scrollables.empty() ||
Chris@127 1621 (haveSelections && (selectionCacheable != m_selectionCached))) {
Chris@127 1622 delete m_cache;
Chris@127 1623 m_cache = 0;
Chris@127 1624 m_selectionCached = false;
Chris@127 1625 }
Chris@127 1626
Chris@127 1627 if (!scrollables.empty()) {
Chris@244 1628
Chris@244 1629 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@244 1630 std::cerr << "View(" << this << "): cache " << m_cache << ", cache zoom "
Chris@244 1631 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << std::endl;
Chris@244 1632 #endif
Chris@244 1633
Chris@127 1634 if (!m_cache ||
Chris@127 1635 m_cacheZoomLevel != m_zoomLevel ||
Chris@127 1636 width() != m_cache->width() ||
Chris@127 1637 height() != m_cache->height()) {
Chris@127 1638
Chris@127 1639 // cache is not valid
Chris@127 1640
Chris@127 1641 if (cacheRect.width() < width()/10) {
Chris@244 1642 delete m_cache;
Chris@244 1643 m_cache = 0;
Chris@127 1644 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1645 std::cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << std::endl;
Chris@127 1646 #endif
Chris@127 1647 } else {
Chris@127 1648 delete m_cache;
Chris@127 1649 m_cache = new QPixmap(width(), height());
Chris@127 1650 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1651 std::cerr << "View(" << this << ")::paintEvent: recreated cache" << std::endl;
Chris@127 1652 #endif
Chris@127 1653 cacheRect = rect();
Chris@127 1654 repaintCache = true;
Chris@127 1655 }
Chris@127 1656
Chris@127 1657 } else if (m_cacheCentreFrame != m_centreFrame) {
Chris@127 1658
Chris@127 1659 long dx =
Chris@127 1660 getXForFrame(m_cacheCentreFrame) -
Chris@127 1661 getXForFrame(m_centreFrame);
Chris@127 1662
Chris@127 1663 if (dx > -width() && dx < width()) {
Chris@548 1664 #ifdef PIXMAP_COPY_TO_SELF
Chris@548 1665 // This is not normally defined. Copying a pixmap to
Chris@548 1666 // itself doesn't work properly on Windows, Mac, or
Chris@548 1667 // X11 with the raster backend (it only works when
Chris@548 1668 // moving in one direction and then presumably only by
Chris@548 1669 // accident). It does actually seem to be fine on X11
Chris@548 1670 // with the native backend, but we prefer not to use
Chris@548 1671 // that anyway
Chris@548 1672 paint.begin(m_cache);
Chris@548 1673 paint.drawPixmap(dx, 0, *m_cache);
Chris@548 1674 paint.end();
Chris@548 1675 #else
Chris@127 1676 static QPixmap *tmpPixmap = 0;
Chris@127 1677 if (!tmpPixmap ||
Chris@127 1678 tmpPixmap->width() != width() ||
Chris@127 1679 tmpPixmap->height() != height()) {
Chris@127 1680 delete tmpPixmap;
Chris@127 1681 tmpPixmap = new QPixmap(width(), height());
Chris@127 1682 }
Chris@127 1683 paint.begin(tmpPixmap);
Chris@127 1684 paint.drawPixmap(0, 0, *m_cache);
Chris@127 1685 paint.end();
Chris@127 1686 paint.begin(m_cache);
Chris@127 1687 paint.drawPixmap(dx, 0, *tmpPixmap);
Chris@127 1688 paint.end();
Chris@127 1689 #endif
Chris@127 1690 if (dx < 0) {
Chris@127 1691 cacheRect = QRect(width() + dx, 0, -dx, height());
Chris@127 1692 } else {
Chris@127 1693 cacheRect = QRect(0, 0, dx, height());
Chris@127 1694 }
Chris@127 1695 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1696 std::cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << std::endl;
Chris@127 1697 #endif
Chris@127 1698 } else {
Chris@127 1699 cacheRect = rect();
Chris@127 1700 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1701 std::cerr << "View(" << this << ")::paintEvent: scrolling too far" << std::endl;
Chris@127 1702 #endif
Chris@127 1703 }
Chris@127 1704 repaintCache = true;
Chris@127 1705
Chris@127 1706 } else {
Chris@127 1707 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1708 std::cerr << "View(" << this << ")::paintEvent: cache is good" << std::endl;
Chris@127 1709 #endif
Chris@127 1710 paint.begin(this);
Chris@127 1711 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@127 1712 paint.end();
Chris@127 1713 QFrame::paintEvent(e);
Chris@127 1714 paintedCacheRect = true;
Chris@127 1715 }
Chris@127 1716
Chris@127 1717 m_cacheCentreFrame = m_centreFrame;
Chris@127 1718 m_cacheZoomLevel = m_zoomLevel;
Chris@127 1719 }
Chris@127 1720
Chris@127 1721 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1722 // std::cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << std::endl;
Chris@127 1723 #endif
Chris@127 1724
Chris@127 1725 // Scrollable (cacheable) items first
Chris@127 1726
Chris@127 1727 if (!paintedCacheRect) {
Chris@127 1728
Chris@127 1729 if (repaintCache) paint.begin(m_cache);
Chris@127 1730 else paint.begin(this);
Chris@339 1731 setPaintFont(paint);
Chris@127 1732 paint.setClipRect(cacheRect);
Chris@287 1733
Chris@287 1734 paint.setPen(getBackground());
Chris@287 1735 paint.setBrush(getBackground());
Chris@127 1736 paint.drawRect(cacheRect);
Chris@127 1737
Chris@287 1738 paint.setPen(getForeground());
Chris@127 1739 paint.setBrush(Qt::NoBrush);
Chris@127 1740
Chris@127 1741 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
Chris@127 1742 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@127 1743 paint.save();
Chris@127 1744 (*i)->paint(this, paint, cacheRect);
Chris@127 1745 paint.restore();
Chris@127 1746 }
Chris@127 1747
Chris@127 1748 if (haveSelections && selectionCacheable) {
Chris@127 1749 drawSelections(paint);
Chris@127 1750 m_selectionCached = repaintCache;
Chris@127 1751 selectionDrawn = true;
Chris@127 1752 }
Chris@127 1753
Chris@127 1754 paint.end();
Chris@127 1755
Chris@127 1756 if (repaintCache) {
Chris@127 1757 cacheRect |= (e ? e->rect() : rect());
Chris@127 1758 paint.begin(this);
Chris@127 1759 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@127 1760 paint.end();
Chris@127 1761 }
Chris@127 1762 }
Chris@127 1763
Chris@127 1764 // Now non-cacheable items. We always need to redraw the
Chris@127 1765 // non-cacheable items across at least the area we drew of the
Chris@127 1766 // cacheable items.
Chris@127 1767
Chris@127 1768 nonCacheRect |= cacheRect;
Chris@127 1769
Chris@127 1770 paint.begin(this);
Chris@127 1771 paint.setClipRect(nonCacheRect);
Chris@339 1772 setPaintFont(paint);
Chris@127 1773 if (scrollables.empty()) {
Chris@287 1774 paint.setPen(getBackground());
Chris@287 1775 paint.setBrush(getBackground());
Chris@127 1776 paint.drawRect(nonCacheRect);
Chris@127 1777 }
Chris@127 1778
Chris@287 1779 paint.setPen(getForeground());
Chris@127 1780 paint.setBrush(Qt::NoBrush);
Chris@127 1781
Chris@127 1782 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
Chris@127 1783 // Profiler profiler2("View::paintEvent non-cacheable");
Chris@127 1784 (*i)->paint(this, paint, nonCacheRect);
Chris@127 1785 }
Chris@127 1786
Chris@127 1787 paint.end();
Chris@127 1788
Chris@127 1789 paint.begin(this);
Chris@339 1790 setPaintFont(paint);
Chris@127 1791 if (e) paint.setClipRect(e->rect());
Chris@127 1792 if (!m_selectionCached) {
Chris@127 1793 drawSelections(paint);
Chris@127 1794 }
Chris@127 1795 paint.end();
Chris@127 1796
Chris@211 1797 bool showPlayPointer = true;
Chris@211 1798 if (m_followPlay == PlaybackScrollContinuous) {
Chris@211 1799 showPlayPointer = false;
Chris@211 1800 } else if (long(m_playPointerFrame) <= getStartFrame() ||
Chris@211 1801 m_playPointerFrame >= getEndFrame()) {
Chris@211 1802 showPlayPointer = false;
Chris@211 1803 } else if (m_manager && !m_manager->isPlaying()) {
Chris@211 1804 if (m_playPointerFrame == getCentreFrame() &&
Chris@211 1805 m_followPlay != PlaybackIgnore) {
Chris@211 1806 showPlayPointer = false;
Chris@211 1807 }
Chris@211 1808 }
Chris@211 1809
Chris@211 1810 if (showPlayPointer) {
Chris@127 1811
Chris@127 1812 paint.begin(this);
Chris@127 1813
Chris@211 1814 int playx = getXForFrame(m_playPointerFrame);
Chris@211 1815
Chris@287 1816 paint.setPen(getForeground());
Chris@211 1817 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
Chris@211 1818 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
Chris@211 1819 paint.drawPoint(playx, 0);
Chris@211 1820 paint.drawPoint(playx, height() - 1);
Chris@287 1821 paint.setPen(getBackground());
Chris@211 1822 paint.drawLine(playx, 1, playx, height() - 2);
Chris@127 1823
Chris@127 1824 paint.end();
Chris@127 1825 }
Chris@127 1826
Chris@127 1827 QFrame::paintEvent(e);
Chris@127 1828 }
Chris@127 1829
Chris@127 1830 void
Chris@127 1831 View::drawSelections(QPainter &paint)
Chris@127 1832 {
Chris@217 1833 if (!hasTopLayerTimeXAxis()) return;
Chris@217 1834
Chris@127 1835 MultiSelection::SelectionList selections;
Chris@127 1836
Chris@127 1837 if (m_manager) {
Chris@127 1838 selections = m_manager->getSelections();
Chris@127 1839 if (m_manager->haveInProgressSelection()) {
Chris@127 1840 bool exclusive;
Chris@127 1841 Selection inProgressSelection =
Chris@127 1842 m_manager->getInProgressSelection(exclusive);
Chris@127 1843 if (exclusive) selections.clear();
Chris@127 1844 selections.insert(inProgressSelection);
Chris@127 1845 }
Chris@127 1846 }
Chris@127 1847
Chris@127 1848 paint.save();
Chris@183 1849
Chris@183 1850 bool translucent = !areLayerColoursSignificant();
Chris@183 1851
Chris@183 1852 if (translucent) {
Chris@183 1853 paint.setBrush(QColor(150, 150, 255, 80));
Chris@183 1854 } else {
Chris@183 1855 paint.setBrush(Qt::NoBrush);
Chris@183 1856 }
Chris@127 1857
Chris@127 1858 int sampleRate = getModelsSampleRate();
Chris@127 1859
Chris@127 1860 QPoint localPos;
Chris@127 1861 long illuminateFrame = -1;
Chris@127 1862 bool closeToLeft, closeToRight;
Chris@127 1863
Chris@127 1864 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
Chris@127 1865 illuminateFrame = getFrameForX(localPos.x());
Chris@127 1866 }
Chris@127 1867
Chris@127 1868 const QFontMetrics &metrics = paint.fontMetrics();
Chris@127 1869
Chris@127 1870 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@127 1871 i != selections.end(); ++i) {
Chris@127 1872
Chris@333 1873 int p0 = getXForFrame(alignFromReference(i->getStartFrame()));
Chris@333 1874 int p1 = getXForFrame(alignFromReference(i->getEndFrame()));
Chris@127 1875
Chris@127 1876 if (p1 < 0 || p0 > width()) continue;
Chris@127 1877
Chris@127 1878 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@127 1879 std::cerr << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << std::endl;
Chris@127 1880 #endif
Chris@127 1881
Chris@127 1882 bool illuminateThis =
Chris@127 1883 (illuminateFrame >= 0 && i->contains(illuminateFrame));
Chris@127 1884
Chris@127 1885 paint.setPen(QColor(150, 150, 255));
Chris@183 1886
Chris@183 1887 if (translucent && shouldLabelSelections()) {
Chris@183 1888 paint.drawRect(p0, -1, p1 - p0, height() + 1);
Chris@183 1889 } else {
Chris@183 1890 // Make the top & bottom lines of the box visible if we
Chris@183 1891 // are lacking some of the other visual cues. There's no
Chris@183 1892 // particular logic to this, it's just a question of what
Chris@183 1893 // I happen to think looks nice.
Chris@183 1894 paint.drawRect(p0, 0, p1 - p0, height() - 1);
Chris@183 1895 }
Chris@127 1896
Chris@127 1897 if (illuminateThis) {
Chris@127 1898 paint.save();
Chris@287 1899 paint.setPen(QPen(getForeground(), 2));
Chris@127 1900 if (closeToLeft) {
Chris@127 1901 paint.drawLine(p0, 1, p1, 1);
Chris@127 1902 paint.drawLine(p0, 0, p0, height());
Chris@127 1903 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 1904 } else if (closeToRight) {
Chris@127 1905 paint.drawLine(p0, 1, p1, 1);
Chris@127 1906 paint.drawLine(p1, 0, p1, height());
Chris@127 1907 paint.drawLine(p0, height() - 1, p1, height() - 1);
Chris@127 1908 } else {
Chris@127 1909 paint.setBrush(Qt::NoBrush);
Chris@127 1910 paint.drawRect(p0, 1, p1 - p0, height() - 2);
Chris@127 1911 }
Chris@127 1912 paint.restore();
Chris@127 1913 }
Chris@127 1914
Chris@127 1915 if (sampleRate && shouldLabelSelections() && m_manager &&
Chris@189 1916 m_manager->shouldShowSelectionExtents()) {
Chris@127 1917
Chris@127 1918 QString startText = QString("%1 / %2")
Chris@127 1919 .arg(QString::fromStdString
Chris@127 1920 (RealTime::frame2RealTime
Chris@127 1921 (i->getStartFrame(), sampleRate).toText(true)))
Chris@127 1922 .arg(i->getStartFrame());
Chris@127 1923
Chris@127 1924 QString endText = QString(" %1 / %2")
Chris@127 1925 .arg(QString::fromStdString
Chris@127 1926 (RealTime::frame2RealTime
Chris@127 1927 (i->getEndFrame(), sampleRate).toText(true)))
Chris@127 1928 .arg(i->getEndFrame());
Chris@127 1929
Chris@127 1930 QString durationText = QString("(%1 / %2) ")
Chris@127 1931 .arg(QString::fromStdString
Chris@127 1932 (RealTime::frame2RealTime
Chris@127 1933 (i->getEndFrame() - i->getStartFrame(), sampleRate)
Chris@127 1934 .toText(true)))
Chris@127 1935 .arg(i->getEndFrame() - i->getStartFrame());
Chris@127 1936
Chris@127 1937 int sw = metrics.width(startText),
Chris@127 1938 ew = metrics.width(endText),
Chris@127 1939 dw = metrics.width(durationText);
Chris@127 1940
Chris@127 1941 int sy = metrics.ascent() + metrics.height() + 4;
Chris@127 1942 int ey = sy;
Chris@127 1943 int dy = sy + metrics.height();
Chris@127 1944
Chris@127 1945 int sx = p0 + 2;
Chris@127 1946 int ex = sx;
Chris@127 1947 int dx = sx;
Chris@127 1948
Chris@501 1949 bool durationBothEnds = true;
Chris@501 1950
Chris@127 1951 if (sw + ew > (p1 - p0)) {
Chris@127 1952 ey += metrics.height();
Chris@127 1953 dy += metrics.height();
Chris@501 1954 durationBothEnds = false;
Chris@127 1955 }
Chris@127 1956
Chris@127 1957 if (ew < (p1 - p0)) {
Chris@127 1958 ex = p1 - 2 - ew;
Chris@127 1959 }
Chris@127 1960
Chris@127 1961 if (dw < (p1 - p0)) {
Chris@127 1962 dx = p1 - 2 - dw;
Chris@127 1963 }
Chris@127 1964
Chris@127 1965 paint.drawText(sx, sy, startText);
Chris@127 1966 paint.drawText(ex, ey, endText);
Chris@127 1967 paint.drawText(dx, dy, durationText);
Chris@501 1968 if (durationBothEnds) {
Chris@501 1969 paint.drawText(sx, dy, durationText);
Chris@501 1970 }
Chris@127 1971 }
Chris@127 1972 }
Chris@127 1973
Chris@127 1974 paint.restore();
Chris@127 1975 }
Chris@127 1976
Chris@267 1977 void
Chris@270 1978 View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r,
Chris@270 1979 bool focus) const
Chris@267 1980 {
Chris@268 1981 // std::cerr << "View::drawMeasurementRect(" << r.x() << "," << r.y() << " "
Chris@268 1982 // << r.width() << "x" << r.height() << ")" << std::endl;
Chris@268 1983
Chris@267 1984 if (r.x() + r.width() < 0 || r.x() >= width()) return;
Chris@267 1985
Chris@270 1986 if (r.width() != 0 || r.height() != 0) {
Chris@270 1987 paint.save();
Chris@270 1988 if (focus) {
Chris@270 1989 paint.setPen(Qt::NoPen);
Chris@272 1990 QColor brushColour(Qt::black);
Chris@272 1991 brushColour.setAlpha(hasLightBackground() ? 15 : 40);
Chris@270 1992 paint.setBrush(brushColour);
Chris@270 1993 if (r.x() > 0) {
Chris@270 1994 paint.drawRect(0, 0, r.x(), height());
Chris@270 1995 }
Chris@270 1996 if (r.x() + r.width() < width()) {
Chris@270 1997 paint.drawRect(r.x() + r.width(), 0, width()-r.x()-r.width(), height());
Chris@270 1998 }
Chris@270 1999 if (r.y() > 0) {
Chris@270 2000 paint.drawRect(r.x(), 0, r.width(), r.y());
Chris@270 2001 }
Chris@270 2002 if (r.y() + r.height() < height()) {
Chris@270 2003 paint.drawRect(r.x(), r.y() + r.height(), r.width(), height()-r.y()-r.height());
Chris@270 2004 }
Chris@270 2005 paint.setBrush(Qt::NoBrush);
Chris@270 2006 }
Chris@270 2007 paint.setPen(Qt::green);
Chris@270 2008 paint.drawRect(r);
Chris@270 2009 paint.restore();
Chris@270 2010 } else {
Chris@270 2011 paint.save();
Chris@270 2012 paint.setPen(Qt::green);
Chris@270 2013 paint.drawPoint(r.x(), r.y());
Chris@270 2014 paint.restore();
Chris@270 2015 }
Chris@270 2016
Chris@270 2017 if (!focus) return;
Chris@270 2018
Chris@278 2019 paint.save();
Chris@278 2020 QFont fn = paint.font();
Chris@278 2021 if (fn.pointSize() > 8) {
Chris@278 2022 fn.setPointSize(fn.pointSize() - 1);
Chris@278 2023 paint.setFont(fn);
Chris@278 2024 }
Chris@278 2025
Chris@267 2026 int fontHeight = paint.fontMetrics().height();
Chris@267 2027 int fontAscent = paint.fontMetrics().ascent();
Chris@267 2028
Chris@267 2029 float v0, v1;
Chris@267 2030 QString u0, u1;
Chris@267 2031 bool b0 = false, b1 = false;
Chris@267 2032
Chris@267 2033 QString axs, ays, bxs, bys, dxs, dys;
Chris@267 2034
Chris@267 2035 int axx, axy, bxx, bxy, dxx, dxy;
Chris@267 2036 int aw = 0, bw = 0, dw = 0;
Chris@267 2037
Chris@267 2038 int labelCount = 0;
Chris@267 2039
Chris@362 2040 // top-left point, x-coord
Chris@362 2041
Chris@267 2042 if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) {
Chris@267 2043 axs = QString("%1 %2").arg(v0).arg(u0);
Chris@278 2044 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
Chris@278 2045 axs = QString("%1 (%2)").arg(axs)
Chris@278 2046 .arg(Pitch::getPitchLabelForFrequency(v0));
Chris@278 2047 }
Chris@267 2048 aw = paint.fontMetrics().width(axs);
Chris@267 2049 ++labelCount;
Chris@267 2050 }
Chris@362 2051
Chris@362 2052 // bottom-right point, x-coord
Chris@267 2053
Chris@267 2054 if (r.width() > 0) {
Chris@267 2055 if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) {
Chris@267 2056 bxs = QString("%1 %2").arg(v1).arg(u1);
Chris@278 2057 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
Chris@278 2058 bxs = QString("%1 (%2)").arg(bxs)
Chris@278 2059 .arg(Pitch::getPitchLabelForFrequency(v1));
Chris@278 2060 }
Chris@267 2061 bw = paint.fontMetrics().width(bxs);
Chris@267 2062 }
Chris@267 2063 }
Chris@362 2064
Chris@362 2065 // dimension, width
Chris@267 2066
Chris@283 2067 if (b0 && b1 && v1 != v0 && u0 == u1) {
Chris@362 2068 dxs = QString("[%1 %2]").arg(fabs(v1 - v0)).arg(u1);
Chris@267 2069 dw = paint.fontMetrics().width(dxs);
Chris@267 2070 }
Chris@267 2071
Chris@267 2072 b0 = false;
Chris@267 2073 b1 = false;
Chris@267 2074
Chris@362 2075 // top-left point, y-coord
Chris@362 2076
Chris@267 2077 if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) {
Chris@267 2078 ays = QString("%1 %2").arg(v0).arg(u0);
Chris@278 2079 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
Chris@278 2080 ays = QString("%1 (%2)").arg(ays)
Chris@278 2081 .arg(Pitch::getPitchLabelForFrequency(v0));
Chris@278 2082 }
Chris@267 2083 aw = std::max(aw, paint.fontMetrics().width(ays));
Chris@267 2084 ++labelCount;
Chris@267 2085 }
Chris@267 2086
Chris@362 2087 // bottom-right point, y-coord
Chris@362 2088
Chris@267 2089 if (r.height() > 0) {
Chris@267 2090 if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) {
Chris@267 2091 bys = QString("%1 %2").arg(v1).arg(u1);
Chris@278 2092 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
Chris@278 2093 bys = QString("%1 (%2)").arg(bys)
Chris@278 2094 .arg(Pitch::getPitchLabelForFrequency(v1));
Chris@278 2095 }
Chris@267 2096 bw = std::max(bw, paint.fontMetrics().width(bys));
Chris@267 2097 }
Chris@267 2098 }
Chris@274 2099
Chris@274 2100 bool bd = false;
Chris@274 2101 float dy = 0.f;
Chris@274 2102 QString du;
Chris@274 2103
Chris@362 2104 // dimension, height
Chris@362 2105
Chris@274 2106 if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(),
Chris@283 2107 dy, du)) &&
Chris@283 2108 dy != 0) {
Chris@274 2109 if (du != "") {
Chris@362 2110 if (du == "Hz") {
Chris@362 2111 int semis;
Chris@362 2112 float cents;
Chris@362 2113 semis = Pitch::getPitchForFrequencyDifference(v0, v1, &cents);
Chris@362 2114 dys = QString("[%1 %2 (%3)]")
Chris@362 2115 .arg(dy).arg(du)
Chris@362 2116 .arg(Pitch::getLabelForPitchRange(semis, cents));
Chris@362 2117 } else {
Chris@362 2118 dys = QString("[%1 %2]").arg(dy).arg(du);
Chris@362 2119 }
Chris@274 2120 } else {
Chris@362 2121 dys = QString("[%1]").arg(dy);
Chris@274 2122 }
Chris@267 2123 dw = std::max(dw, paint.fontMetrics().width(dys));
Chris@267 2124 }
Chris@267 2125
Chris@267 2126 int mw = r.width();
Chris@267 2127 int mh = r.height();
Chris@267 2128
Chris@267 2129 bool edgeLabelsInside = false;
Chris@267 2130 bool sizeLabelsInside = false;
Chris@267 2131
Chris@267 2132 if (mw < std::max(aw, std::max(bw, dw)) + 4) {
Chris@267 2133 // defaults stand
Chris@267 2134 } else if (mw < aw + bw + 4) {
Chris@267 2135 if (mh > fontHeight * labelCount * 3 + 4) {
Chris@267 2136 edgeLabelsInside = true;
Chris@267 2137 sizeLabelsInside = true;
Chris@267 2138 } else if (mh > fontHeight * labelCount * 2 + 4) {
Chris@267 2139 edgeLabelsInside = true;
Chris@267 2140 }
Chris@267 2141 } else if (mw < aw + bw + dw + 4) {
Chris@267 2142 if (mh > fontHeight * labelCount * 3 + 4) {
Chris@267 2143 edgeLabelsInside = true;
Chris@267 2144 sizeLabelsInside = true;
Chris@267 2145 } else if (mh > fontHeight * labelCount + 4) {
Chris@267 2146 edgeLabelsInside = true;
Chris@267 2147 }
Chris@267 2148 } else {
Chris@267 2149 if (mh > fontHeight * labelCount + 4) {
Chris@267 2150 edgeLabelsInside = true;
Chris@267 2151 sizeLabelsInside = true;
Chris@267 2152 }
Chris@267 2153 }
Chris@267 2154
Chris@267 2155 if (edgeLabelsInside) {
Chris@267 2156
Chris@267 2157 axx = r.x() + 2;
Chris@267 2158 axy = r.y() + fontAscent + 2;
Chris@267 2159
Chris@267 2160 bxx = r.x() + r.width() - bw - 2;
Chris@267 2161 bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
Chris@267 2162
Chris@267 2163 } else {
Chris@267 2164
Chris@267 2165 axx = r.x() - aw - 2;
Chris@267 2166 axy = r.y() + fontAscent;
Chris@267 2167
Chris@267 2168 bxx = r.x() + r.width() + 2;
Chris@267 2169 bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
Chris@267 2170 }
Chris@267 2171
Chris@267 2172 dxx = r.width()/2 + r.x() - dw/2;
Chris@267 2173
Chris@267 2174 if (sizeLabelsInside) {
Chris@267 2175
Chris@267 2176 dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
Chris@267 2177
Chris@267 2178 } else {
Chris@267 2179
Chris@267 2180 dxy = r.y() + r.height() + fontAscent + 2;
Chris@267 2181 }
Chris@267 2182
Chris@267 2183 if (axs != "") {
Chris@267 2184 drawVisibleText(paint, axx, axy, axs, OutlinedText);
Chris@267 2185 axy += fontHeight;
Chris@267 2186 }
Chris@267 2187
Chris@267 2188 if (ays != "") {
Chris@267 2189 drawVisibleText(paint, axx, axy, ays, OutlinedText);
Chris@267 2190 axy += fontHeight;
Chris@267 2191 }
Chris@267 2192
Chris@267 2193 if (bxs != "") {
Chris@267 2194 drawVisibleText(paint, bxx, bxy, bxs, OutlinedText);
Chris@267 2195 bxy += fontHeight;
Chris@267 2196 }
Chris@267 2197
Chris@267 2198 if (bys != "") {
Chris@267 2199 drawVisibleText(paint, bxx, bxy, bys, OutlinedText);
Chris@267 2200 bxy += fontHeight;
Chris@267 2201 }
Chris@267 2202
Chris@267 2203 if (dxs != "") {
Chris@267 2204 drawVisibleText(paint, dxx, dxy, dxs, OutlinedText);
Chris@267 2205 dxy += fontHeight;
Chris@267 2206 }
Chris@267 2207
Chris@267 2208 if (dys != "") {
Chris@267 2209 drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
Chris@267 2210 dxy += fontHeight;
Chris@267 2211 }
Chris@278 2212
Chris@278 2213 paint.restore();
Chris@267 2214 }
Chris@267 2215
Chris@227 2216 bool
Chris@229 2217 View::render(QPainter &paint, int xorigin, size_t f0, size_t f1)
Chris@227 2218 {
Chris@227 2219 size_t x0 = f0 / m_zoomLevel;
Chris@227 2220 size_t x1 = f1 / m_zoomLevel;
Chris@227 2221
Chris@227 2222 size_t w = x1 - x0;
Chris@227 2223
Chris@227 2224 size_t origCentreFrame = m_centreFrame;
Chris@227 2225
Chris@227 2226 bool someLayersIncomplete = false;
Chris@227 2227
Chris@227 2228 for (LayerList::iterator i = m_layers.begin();
Chris@227 2229 i != m_layers.end(); ++i) {
Chris@227 2230
Chris@227 2231 int c = (*i)->getCompletion(this);
Chris@227 2232 if (c < 100) {
Chris@227 2233 someLayersIncomplete = true;
Chris@227 2234 break;
Chris@227 2235 }
Chris@227 2236 }
Chris@227 2237
Chris@227 2238 if (someLayersIncomplete) {
Chris@227 2239
Chris@227 2240 QProgressDialog progress(tr("Waiting for layers to be ready..."),
Chris@227 2241 tr("Cancel"), 0, 100, this);
Chris@227 2242
Chris@227 2243 int layerCompletion = 0;
Chris@227 2244
Chris@227 2245 while (layerCompletion < 100) {
Chris@227 2246
Chris@227 2247 for (LayerList::iterator i = m_layers.begin();
Chris@227 2248 i != m_layers.end(); ++i) {
Chris@227 2249
Chris@227 2250 int c = (*i)->getCompletion(this);
Chris@227 2251 if (i == m_layers.begin() || c < layerCompletion) {
Chris@227 2252 layerCompletion = c;
Chris@227 2253 }
Chris@227 2254 }
Chris@227 2255
Chris@227 2256 if (layerCompletion >= 100) break;
Chris@227 2257
Chris@227 2258 progress.setValue(layerCompletion);
Chris@227 2259 qApp->processEvents();
Chris@227 2260 if (progress.wasCanceled()) {
Chris@227 2261 update();
Chris@227 2262 return false;
Chris@227 2263 }
Chris@227 2264
Chris@227 2265 usleep(50000);
Chris@227 2266 }
Chris@227 2267 }
Chris@227 2268
Chris@227 2269 QProgressDialog progress(tr("Rendering image..."),
Chris@227 2270 tr("Cancel"), 0, w / width(), this);
Chris@227 2271
Chris@227 2272 for (size_t x = 0; x < w; x += width()) {
Chris@227 2273
Chris@227 2274 progress.setValue(x / width());
Chris@227 2275 qApp->processEvents();
Chris@227 2276 if (progress.wasCanceled()) {
Chris@227 2277 m_centreFrame = origCentreFrame;
Chris@227 2278 update();
Chris@227 2279 return false;
Chris@227 2280 }
Chris@227 2281
Chris@229 2282 m_centreFrame = f0 + (x + width()/2) * m_zoomLevel;
Chris@227 2283
Chris@227 2284 QRect chunk(0, 0, width(), height());
Chris@227 2285
Chris@287 2286 paint.setPen(getBackground());
Chris@287 2287 paint.setBrush(getBackground());
Chris@227 2288
Chris@229 2289 paint.drawRect(QRect(xorigin + x, 0, width(), height()));
Chris@227 2290
Chris@287 2291 paint.setPen(getForeground());
Chris@227 2292 paint.setBrush(Qt::NoBrush);
Chris@227 2293
Chris@227 2294 for (LayerList::iterator i = m_layers.begin();
Chris@227 2295 i != m_layers.end(); ++i) {
dan@574 2296 if(!((*i)->isLayerDormant(this))){
dan@574 2297
dan@574 2298 paint.setRenderHint(QPainter::Antialiasing, false);
dan@574 2299
dan@574 2300 paint.save();
dan@574 2301 paint.translate(xorigin + x, 0);
dan@574 2302
dan@574 2303 std::cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << std::endl;
dan@574 2304
dan@574 2305 (*i)->setSynchronousPainting(true);
dan@574 2306
dan@574 2307 (*i)->paint(this, paint, chunk);
dan@574 2308
dan@574 2309 (*i)->setSynchronousPainting(false);
dan@574 2310
dan@574 2311 paint.restore();
dan@574 2312 }
Chris@227 2313 }
Chris@227 2314 }
Chris@227 2315
Chris@227 2316 m_centreFrame = origCentreFrame;
Chris@227 2317 update();
Chris@227 2318 return true;
Chris@227 2319 }
Chris@227 2320
Chris@227 2321 QImage *
Chris@227 2322 View::toNewImage()
Chris@227 2323 {
Chris@227 2324 size_t f0 = getModelsStartFrame();
Chris@227 2325 size_t f1 = getModelsEndFrame();
Chris@227 2326
Chris@229 2327 return toNewImage(f0, f1);
Chris@229 2328 }
Chris@229 2329
Chris@229 2330 QImage *
Chris@229 2331 View::toNewImage(size_t f0, size_t f1)
Chris@229 2332 {
Chris@227 2333 size_t x0 = f0 / getZoomLevel();
Chris@227 2334 size_t x1 = f1 / getZoomLevel();
Chris@227 2335
Chris@227 2336 QImage *image = new QImage(x1 - x0, height(), QImage::Format_RGB32);
Chris@227 2337
Chris@227 2338 QPainter *paint = new QPainter(image);
Chris@229 2339 if (!render(*paint, 0, f0, f1)) {
Chris@227 2340 delete paint;
Chris@227 2341 delete image;
Chris@227 2342 return 0;
Chris@227 2343 } else {
Chris@227 2344 delete paint;
Chris@227 2345 return image;
Chris@227 2346 }
Chris@227 2347 }
Chris@227 2348
Chris@229 2349 QSize
Chris@229 2350 View::getImageSize()
Chris@229 2351 {
Chris@229 2352 size_t f0 = getModelsStartFrame();
Chris@229 2353 size_t f1 = getModelsEndFrame();
Chris@229 2354
Chris@229 2355 return getImageSize(f0, f1);
Chris@229 2356 }
Chris@229 2357
Chris@229 2358 QSize
Chris@229 2359 View::getImageSize(size_t f0, size_t f1)
Chris@229 2360 {
Chris@229 2361 size_t x0 = f0 / getZoomLevel();
Chris@229 2362 size_t x1 = f1 / getZoomLevel();
Chris@229 2363
Chris@229 2364 return QSize(x1 - x0, height());
Chris@229 2365 }
Chris@229 2366
Chris@316 2367 void
Chris@316 2368 View::toXml(QTextStream &stream,
Chris@316 2369 QString indent, QString extraAttributes) const
Chris@127 2370 {
Chris@316 2371 stream << indent;
Chris@127 2372
Chris@316 2373 stream << QString("<view "
Chris@316 2374 "centre=\"%1\" "
Chris@316 2375 "zoom=\"%2\" "
Chris@316 2376 "followPan=\"%3\" "
Chris@316 2377 "followZoom=\"%4\" "
Chris@316 2378 "tracking=\"%5\" "
Chris@316 2379 " %6>\n")
Chris@127 2380 .arg(m_centreFrame)
Chris@127 2381 .arg(m_zoomLevel)
Chris@127 2382 .arg(m_followPan)
Chris@127 2383 .arg(m_followZoom)
Chris@127 2384 .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
Chris@127 2385 m_followPlay == PlaybackScrollPage ? "page" : "ignore")
Chris@127 2386 .arg(extraAttributes);
Chris@127 2387
Chris@127 2388 for (size_t i = 0; i < m_layers.size(); ++i) {
Chris@186 2389 bool visible = !m_layers[i]->isLayerDormant(this);
Chris@316 2390 m_layers[i]->toBriefXml(stream, indent + " ",
Chris@316 2391 QString("visible=\"%1\"")
Chris@316 2392 .arg(visible ? "true" : "false"));
Chris@127 2393 }
Chris@127 2394
Chris@316 2395 stream << indent + "</view>\n";
Chris@127 2396 }
Chris@127 2397
Chris@127 2398 ViewPropertyContainer::ViewPropertyContainer(View *v) :
Chris@127 2399 m_v(v)
Chris@127 2400 {
Chris@127 2401 connect(m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@127 2402 this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
Chris@127 2403 }
Chris@127 2404