annotate view/View.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

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