annotate view/View.cpp @ 1024:3bce4c45b681 spectrogram-minor-refactor

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