annotate view/View.cpp @ 317:e251c3599ea8

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