annotate view/View.cpp @ 561:aced8ec09bc8

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