annotate view/View.cpp @ 454:e2a40fdadd8c

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