annotate view/View.cpp @ 333:e74b56f07c73

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