annotate view/View.cpp @ 738:d26545a2a02d tonioni

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