annotate view/View.cpp @ 1212:a1ee3108d1d3 3.0-integration

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