annotate view/View.cpp @ 959:2633a1d73e39

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