annotate view/View.cpp @ 607:5b72899d692b

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