annotate view/View.cpp @ 789:9fd1bdf214dd tonioni

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