annotate view/View.cpp @ 1160:a429b2acb45d 3.0-integration

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