annotate view/View.cpp @ 855:57efeb75880d

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