annotate base/View.cpp @ 33:51e158b505da

* Rearrange spectrogram cacheing so that gain, normalization, instantaneous frequency calculations etc can be done from the cached data (increasing the size of the cache, but also the usability).
author Chris Cannam
date Thu, 23 Feb 2006 18:01:31 +0000
parents 4afaf0df4d51
children aaf73f7309f2
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@1 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "base/View.h"
Chris@0 11 #include "base/Layer.h"
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/ZoomConstraint.h"
Chris@0 14 #include "base/Profiler.h"
Chris@0 15
Chris@0 16 #include "layer/TimeRulerLayer.h" //!!! damn, shouldn't be including that here
Chris@25 17 #include "model/PowerOfSqrtTwoZoomConstraint.h" //!!! likewise
Chris@0 18
Chris@0 19 #include <QPainter>
Chris@0 20 #include <QPaintEvent>
Chris@0 21 #include <QRect>
Chris@0 22 #include <QApplication>
Chris@0 23
Chris@0 24 #include <iostream>
Chris@16 25 #include <cassert>
Chris@0 26
Chris@18 27 //#define DEBUG_VIEW_WIDGET_PAINT 1
Chris@0 28
Chris@0 29 using std::cerr;
Chris@0 30 using std::endl;
Chris@0 31
Chris@0 32 View::View(QWidget *w, bool showProgress) :
Chris@0 33 QFrame(w),
Chris@0 34 m_centreFrame(0),
Chris@0 35 m_zoomLevel(1024),
Chris@0 36 m_followPan(true),
Chris@0 37 m_followZoom(true),
Chris@0 38 m_followPlay(PlaybackScrollPage),
Chris@0 39 m_lightBackground(true),
Chris@0 40 m_showProgress(showProgress),
Chris@0 41 m_cache(0),
Chris@0 42 m_cacheCentreFrame(0),
Chris@0 43 m_cacheZoomLevel(1024),
Chris@9 44 m_selectionCached(false),
Chris@0 45 m_deleting(false),
Chris@8 46 m_haveSelectedLayer(false),
Chris@29 47 m_manager(0),
Chris@29 48 m_propertyContainer(new ViewPropertyContainer(this))
Chris@0 49 {
Chris@0 50 // QWidget::setAttribute(Qt::WA_PaintOnScreen);
Chris@0 51 }
Chris@0 52
Chris@0 53 View::~View()
Chris@0 54 {
Chris@0 55 m_deleting = true;
Chris@0 56
Chris@0 57 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 58 delete *i;
Chris@0 59 }
Chris@29 60
Chris@29 61 delete m_propertyContainer;
Chris@0 62 }
Chris@0 63
Chris@0 64 PropertyContainer::PropertyList
Chris@0 65 View::getProperties() const
Chris@0 66 {
Chris@29 67 PropertyContainer::PropertyList list;
Chris@0 68 list.push_back(tr("Global Scroll"));
Chris@0 69 list.push_back(tr("Global Zoom"));
Chris@0 70 list.push_back(tr("Follow Playback"));
Chris@0 71 return list;
Chris@0 72 }
Chris@0 73
Chris@0 74 PropertyContainer::PropertyType
Chris@29 75 View::getPropertyType(const PropertyContainer::PropertyName &name) const
Chris@0 76 {
Chris@29 77 if (name == tr("Global Scroll")) return PropertyContainer::ToggleProperty;
Chris@29 78 if (name == tr("Global Zoom")) return PropertyContainer::ToggleProperty;
Chris@29 79 if (name == tr("Follow Playback")) return PropertyContainer::ValueProperty;
Chris@29 80 return PropertyContainer::InvalidProperty;
Chris@0 81 }
Chris@0 82
Chris@0 83 int
Chris@29 84 View::getPropertyRangeAndValue(const PropertyContainer::PropertyName &name,
Chris@29 85 int *min, int *max) const
Chris@0 86 {
Chris@0 87 if (name == tr("Global Scroll")) return m_followPan;
Chris@0 88 if (name == tr("Global Zoom")) return m_followZoom;
Chris@29 89 if (name == tr("Follow Playback")) {
Chris@29 90 if (min) *min = 0;
Chris@29 91 if (max) *max = 2;
Chris@29 92 return int(m_followPlay);
Chris@29 93 }
Chris@29 94 if (min) *min = 0;
Chris@29 95 if (max) *max = 0;
Chris@29 96 return 0;
Chris@0 97 }
Chris@0 98
Chris@0 99 QString
Chris@29 100 View::getPropertyValueLabel(const PropertyContainer::PropertyName &name,
Chris@29 101 int value) const
Chris@0 102 {
Chris@0 103 if (name == tr("Follow Playback")) {
Chris@0 104 switch (value) {
Chris@0 105 default:
Chris@0 106 case 0: return tr("Scroll");
Chris@0 107 case 1: return tr("Page");
Chris@0 108 case 2: return tr("Off");
Chris@0 109 }
Chris@0 110 }
Chris@0 111 return tr("<unknown>");
Chris@0 112 }
Chris@0 113
Chris@0 114 void
Chris@29 115 View::setProperty(const PropertyContainer::PropertyName &name, int value)
Chris@0 116 {
Chris@0 117 if (name == tr("Global Scroll")) {
Chris@0 118 setFollowGlobalPan(value != 0);
Chris@0 119 } else if (name == tr("Global Zoom")) {
Chris@0 120 setFollowGlobalZoom(value != 0);
Chris@0 121 } else if (name == tr("Follow Playback")) {
Chris@0 122 switch (value) {
Chris@0 123 default:
Chris@0 124 case 0: setPlaybackFollow(PlaybackScrollContinuous); break;
Chris@0 125 case 1: setPlaybackFollow(PlaybackScrollPage); break;
Chris@0 126 case 2: setPlaybackFollow(PlaybackIgnore); break;
Chris@0 127 }
Chris@0 128 }
Chris@0 129 }
Chris@0 130
Chris@0 131 size_t
Chris@0 132 View::getPropertyContainerCount() const
Chris@0 133 {
Chris@0 134 return m_layers.size() + 1; // the 1 is for me
Chris@0 135 }
Chris@0 136
Chris@0 137 const PropertyContainer *
Chris@0 138 View::getPropertyContainer(size_t i) const
Chris@0 139 {
Chris@0 140 return (const PropertyContainer *)(((View *)this)->
Chris@0 141 getPropertyContainer(i));
Chris@0 142 }
Chris@0 143
Chris@0 144 PropertyContainer *
Chris@0 145 View::getPropertyContainer(size_t i)
Chris@0 146 {
Chris@29 147 if (i == 0) return m_propertyContainer;
Chris@0 148 return m_layers[i-1];
Chris@0 149 }
Chris@0 150
Chris@0 151 void
Chris@0 152 View::propertyContainerSelected(PropertyContainer *pc)
Chris@0 153 {
Chris@29 154 if (pc == m_propertyContainer) {
Chris@8 155 if (m_haveSelectedLayer) {
Chris@8 156 m_haveSelectedLayer = false;
Chris@8 157 update();
Chris@8 158 }
Chris@8 159 return;
Chris@8 160 }
Chris@0 161
Chris@0 162 delete m_cache;
Chris@0 163 m_cache = 0;
Chris@0 164
Chris@0 165 Layer *selectedLayer = 0;
Chris@0 166
Chris@0 167 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 168 if (*i == pc) {
Chris@0 169 selectedLayer = *i;
Chris@0 170 m_layers.erase(i);
Chris@0 171 break;
Chris@0 172 }
Chris@0 173 }
Chris@0 174
Chris@0 175 if (selectedLayer) {
Chris@8 176 m_haveSelectedLayer = true;
Chris@0 177 m_layers.push_back(selectedLayer);
Chris@0 178 update();
Chris@8 179 } else {
Chris@8 180 m_haveSelectedLayer = false;
Chris@0 181 }
Chris@0 182 }
Chris@0 183
Chris@8 184 void
Chris@8 185 View::toolModeChanged()
Chris@8 186 {
Chris@8 187 std::cerr << "View::toolModeChanged(" << m_manager->getToolMode() << ")" << std::endl;
Chris@8 188 }
Chris@8 189
Chris@0 190 long
Chris@0 191 View::getStartFrame() const
Chris@0 192 {
Chris@0 193 size_t w2 = (width() / 2) * m_zoomLevel;
Chris@0 194 size_t frame = m_centreFrame;
Chris@0 195 if (frame >= w2) {
Chris@0 196 frame -= w2;
Chris@0 197 return (frame / m_zoomLevel * m_zoomLevel);
Chris@0 198 } else {
Chris@0 199 frame = w2 - frame;
Chris@0 200 frame = frame / m_zoomLevel * m_zoomLevel;
Chris@0 201 return -(long)frame - m_zoomLevel;
Chris@0 202 }
Chris@0 203 }
Chris@0 204
Chris@0 205 size_t
Chris@0 206 View::getEndFrame() const
Chris@0 207 {
Chris@16 208 return getFrameForX(width()) - 1;
Chris@0 209 }
Chris@0 210
Chris@0 211 void
Chris@0 212 View::setStartFrame(long f)
Chris@0 213 {
Chris@0 214 setCentreFrame(f + m_zoomLevel * (width() / 2));
Chris@0 215 }
Chris@0 216
Chris@10 217 bool
Chris@0 218 View::setCentreFrame(size_t f, bool e)
Chris@0 219 {
Chris@10 220 bool changeVisible = false;
Chris@10 221
Chris@0 222 if (m_centreFrame != f) {
Chris@0 223
Chris@0 224 int formerPixel = m_centreFrame / m_zoomLevel;
Chris@0 225
Chris@0 226 m_centreFrame = f;
Chris@0 227
Chris@0 228 int newPixel = m_centreFrame / m_zoomLevel;
Chris@0 229
Chris@0 230 if (newPixel != formerPixel) {
Chris@0 231
Chris@0 232 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 233 std::cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << std::endl;
Chris@0 234 #endif
Chris@0 235 update();
Chris@10 236
Chris@10 237 changeVisible = true;
Chris@0 238 }
Chris@0 239
Chris@0 240 if (e) emit centreFrameChanged(this, f, m_followPan);
Chris@0 241 }
Chris@10 242
Chris@10 243 return changeVisible;
Chris@0 244 }
Chris@0 245
Chris@15 246 int
Chris@15 247 View::getXForFrame(long frame) const
Chris@15 248 {
Chris@15 249 return (frame - getStartFrame()) / m_zoomLevel;
Chris@15 250 }
Chris@15 251
Chris@15 252 long
Chris@15 253 View::getFrameForX(int x) const
Chris@15 254 {
Chris@15 255 return (long(x) * long(m_zoomLevel)) + getStartFrame();
Chris@15 256 }
Chris@15 257
Chris@33 258 float
Chris@33 259 View::getYForFrequency(float frequency,
Chris@33 260 float minf,
Chris@33 261 float maxf,
Chris@33 262 bool logarithmic) const
Chris@33 263 {
Chris@33 264 int h = height();
Chris@33 265
Chris@33 266 if (logarithmic) {
Chris@33 267
Chris@33 268 static float lastminf = 0.0, lastmaxf = 0.0;
Chris@33 269 static float logminf = 0.0, logmaxf = 0.0;
Chris@33 270
Chris@33 271 if (lastminf != minf) {
Chris@33 272 lastminf = (minf == 0.0 ? 1.0 : minf);
Chris@33 273 logminf = log10f(minf);
Chris@33 274 }
Chris@33 275 if (lastmaxf != maxf) {
Chris@33 276 lastmaxf = (maxf < lastminf ? lastminf : maxf);
Chris@33 277 logmaxf = log10f(maxf);
Chris@33 278 }
Chris@33 279
Chris@33 280 if (logminf == logmaxf) return 0;
Chris@33 281 return h - (h * (log10f(frequency) - logminf)) / (logmaxf - logminf);
Chris@33 282
Chris@33 283 } else {
Chris@33 284
Chris@33 285 if (minf == maxf) return 0;
Chris@33 286 return h - (h * (frequency - minf)) / (maxf - minf);
Chris@33 287 }
Chris@33 288 }
Chris@33 289
Chris@33 290 float
Chris@33 291 View::getFrequencyForY(int y,
Chris@33 292 float minf,
Chris@33 293 float maxf,
Chris@33 294 bool logarithmic) const
Chris@33 295 {
Chris@33 296 int h = height();
Chris@33 297
Chris@33 298 if (logarithmic) {
Chris@33 299
Chris@33 300 static float lastminf = 0.0, lastmaxf = 0.0;
Chris@33 301 static float logminf = 0.0, logmaxf = 0.0;
Chris@33 302
Chris@33 303 if (lastminf != minf) {
Chris@33 304 lastminf = (minf == 0.0 ? 1.0 : minf);
Chris@33 305 logminf = log10f(minf);
Chris@33 306 }
Chris@33 307 if (lastmaxf != maxf) {
Chris@33 308 lastmaxf = (maxf < lastminf ? lastminf : maxf);
Chris@33 309 logmaxf = log10f(maxf);
Chris@33 310 }
Chris@33 311
Chris@33 312 if (logminf == logmaxf) return 0;
Chris@33 313 return pow(10.f, logminf + ((logmaxf - logminf) * (h - y)) / h);
Chris@33 314
Chris@33 315 } else {
Chris@33 316
Chris@33 317 if (minf == maxf) return 0;
Chris@33 318 return minf + ((h - y) * (maxf - minf)) / h;
Chris@33 319 }
Chris@33 320 }
Chris@33 321
Chris@22 322 int
Chris@22 323 View::getZoomLevel() const
Chris@22 324 {
Chris@22 325 return m_zoomLevel;
Chris@22 326 }
Chris@22 327
Chris@0 328 void
Chris@0 329 View::setZoomLevel(size_t z)
Chris@0 330 {
Chris@0 331 if (m_zoomLevel != int(z)) {
Chris@0 332 m_zoomLevel = z;
Chris@0 333 emit zoomLevelChanged(this, z, m_followZoom);
Chris@0 334 update();
Chris@0 335 }
Chris@0 336 }
Chris@0 337
Chris@16 338 View::LayerProgressBar::LayerProgressBar(QWidget *parent) :
Chris@16 339 QProgressBar(parent)
Chris@16 340 {
Chris@16 341 QFont f(font());
Chris@16 342 f.setPointSize(f.pointSize() * 8 / 10);
Chris@16 343 setFont(f);
Chris@16 344 }
Chris@16 345
Chris@0 346 void
Chris@0 347 View::addLayer(Layer *layer)
Chris@0 348 {
Chris@0 349 delete m_cache;
Chris@0 350 m_cache = 0;
Chris@0 351
Chris@0 352 m_layers.push_back(layer);
Chris@0 353
Chris@0 354 m_progressBars[layer] = new LayerProgressBar(this);
Chris@0 355 m_progressBars[layer]->setMinimum(0);
Chris@0 356 m_progressBars[layer]->setMaximum(100);
Chris@0 357 m_progressBars[layer]->setMinimumWidth(80);
Chris@0 358 m_progressBars[layer]->hide();
Chris@16 359
Chris@0 360 connect(layer, SIGNAL(layerParametersChanged()),
Chris@0 361 this, SLOT(layerParametersChanged()));
Chris@0 362 connect(layer, SIGNAL(layerNameChanged()),
Chris@0 363 this, SLOT(layerNameChanged()));
Chris@0 364 connect(layer, SIGNAL(modelChanged()),
Chris@0 365 this, SLOT(modelChanged()));
Chris@0 366 connect(layer, SIGNAL(modelCompletionChanged()),
Chris@0 367 this, SLOT(modelCompletionChanged()));
Chris@0 368 connect(layer, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 369 this, SLOT(modelChanged(size_t, size_t)));
Chris@0 370 connect(layer, SIGNAL(modelReplaced()),
Chris@0 371 this, SLOT(modelReplaced()));
Chris@0 372
Chris@0 373 update();
Chris@0 374
Chris@0 375 emit propertyContainerAdded(layer);
Chris@0 376 }
Chris@0 377
Chris@0 378 void
Chris@0 379 View::removeLayer(Layer *layer)
Chris@0 380 {
Chris@0 381 if (m_deleting) {
Chris@0 382 return;
Chris@0 383 }
Chris@0 384
Chris@0 385 delete m_cache;
Chris@0 386 m_cache = 0;
Chris@0 387
Chris@0 388 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 389 if (*i == layer) {
Chris@0 390 m_layers.erase(i);
Chris@0 391 if (m_progressBars.find(layer) != m_progressBars.end()) {
Chris@0 392 delete m_progressBars[layer];
Chris@0 393 m_progressBars.erase(layer);
Chris@0 394 }
Chris@0 395 break;
Chris@0 396 }
Chris@0 397 }
Chris@0 398
Chris@0 399 update();
Chris@0 400
Chris@0 401 emit propertyContainerRemoved(layer);
Chris@0 402 }
Chris@0 403
Chris@8 404 Layer *
Chris@8 405 View::getSelectedLayer()
Chris@8 406 {
Chris@8 407 if (m_haveSelectedLayer && !m_layers.empty()) {
Chris@8 408 return getLayer(getLayerCount() - 1);
Chris@8 409 } else {
Chris@8 410 return 0;
Chris@8 411 }
Chris@8 412 }
Chris@8 413
Chris@0 414 void
Chris@0 415 View::setViewManager(ViewManager *manager)
Chris@0 416 {
Chris@0 417 if (m_manager) {
Chris@0 418 m_manager->disconnect(this, SLOT(viewManagerCentreFrameChanged(void *, unsigned long, bool)));
Chris@0 419 m_manager->disconnect(this, SLOT(viewManagerZoomLevelChanged(void *, unsigned long, bool)));
Chris@0 420 disconnect(m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool)));
Chris@0 421 disconnect(m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)));
Chris@8 422 disconnect(m_manager, SIGNAL(toolModeChanged()));
Chris@8 423 disconnect(m_manager, SIGNAL(selectionChanged()));
Chris@9 424 disconnect(m_manager, SIGNAL(inProgressSelectionChanged()));
Chris@0 425 }
Chris@0 426
Chris@0 427 m_manager = manager;
Chris@0 428 if (m_followPan) setCentreFrame(m_manager->getGlobalCentreFrame(), false);
Chris@0 429 if (m_followZoom) setZoomLevel(m_manager->getGlobalZoom());
Chris@0 430
Chris@0 431 connect(m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool)),
Chris@0 432 this, SLOT(viewManagerCentreFrameChanged(void *, unsigned long, bool)));
Chris@0 433 connect(m_manager, SIGNAL(playbackFrameChanged(unsigned long)),
Chris@0 434 this, SLOT(viewManagerPlaybackFrameChanged(unsigned long)));
Chris@0 435 connect(m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)),
Chris@0 436 this, SLOT(viewManagerZoomLevelChanged(void *, unsigned long, bool)));
Chris@8 437 connect(m_manager, SIGNAL(toolModeChanged()),
Chris@8 438 this, SLOT(toolModeChanged()));
Chris@8 439 connect(m_manager, SIGNAL(selectionChanged()),
Chris@9 440 this, SLOT(selectionChanged()));
Chris@9 441 connect(m_manager, SIGNAL(inProgressSelectionChanged()),
Chris@9 442 this, SLOT(selectionChanged()));
Chris@0 443
Chris@0 444 connect(this, SIGNAL(centreFrameChanged(void *, unsigned long, bool)),
Chris@0 445 m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool)));
Chris@0 446 connect(this, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)),
Chris@0 447 m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)));
Chris@8 448
Chris@8 449 toolModeChanged();
Chris@0 450 }
Chris@0 451
Chris@0 452 void
Chris@0 453 View::setFollowGlobalPan(bool f)
Chris@0 454 {
Chris@0 455 m_followPan = f;
Chris@29 456 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@0 457 }
Chris@0 458
Chris@0 459 void
Chris@0 460 View::setFollowGlobalZoom(bool f)
Chris@0 461 {
Chris@0 462 m_followZoom = f;
Chris@29 463 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@0 464 }
Chris@0 465
Chris@0 466 void
Chris@0 467 View::setPlaybackFollow(PlaybackFollowMode m)
Chris@0 468 {
Chris@0 469 m_followPlay = m;
Chris@29 470 emit propertyContainerPropertyChanged(m_propertyContainer);
Chris@0 471 }
Chris@0 472
Chris@0 473 void
Chris@0 474 View::modelChanged()
Chris@0 475 {
Chris@0 476 QObject *obj = sender();
Chris@0 477
Chris@0 478 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@1 479 std::cerr << "View(" << this << ")::modelChanged()" << std::endl;
Chris@0 480 #endif
Chris@31 481
Chris@31 482 // If the model that has changed is not used by any of the cached
Chris@31 483 // layers, we won't need to recreate the cache
Chris@31 484
Chris@31 485 bool recreate = false;
Chris@31 486
Chris@31 487 bool discard;
Chris@31 488 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@31 489 for (LayerList::const_iterator i = scrollables.begin();
Chris@31 490 i != scrollables.end(); ++i) {
Chris@31 491 if (*i == obj || (*i)->getModel() == obj) {
Chris@31 492 recreate = true;
Chris@31 493 break;
Chris@31 494 }
Chris@31 495 }
Chris@31 496
Chris@31 497 if (recreate) {
Chris@31 498 delete m_cache;
Chris@31 499 m_cache = 0;
Chris@31 500 }
Chris@0 501
Chris@0 502 checkProgress(obj);
Chris@0 503
Chris@0 504 update();
Chris@0 505 }
Chris@0 506
Chris@0 507 void
Chris@0 508 View::modelChanged(size_t startFrame, size_t endFrame)
Chris@0 509 {
Chris@0 510 QObject *obj = sender();
Chris@0 511
Chris@0 512 long myStartFrame = getStartFrame();
Chris@0 513 size_t myEndFrame = getEndFrame();
Chris@0 514
Chris@1 515 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@1 516 std::cerr << "View(" << this << ")::modelChanged(" << startFrame << "," << endFrame << ") [me " << myStartFrame << "," << myEndFrame << "]" << std::endl;
Chris@1 517 #endif
Chris@1 518
Chris@0 519 if (myStartFrame > 0 && endFrame < size_t(myStartFrame)) {
Chris@0 520 checkProgress(obj);
Chris@0 521 return;
Chris@0 522 }
Chris@0 523 if (startFrame > myEndFrame) {
Chris@0 524 checkProgress(obj);
Chris@0 525 return;
Chris@0 526 }
Chris@0 527
Chris@31 528 // If the model that has changed is not used by any of the cached
Chris@31 529 // layers, we won't need to recreate the cache
Chris@31 530
Chris@31 531 bool recreate = false;
Chris@31 532
Chris@31 533 bool discard;
Chris@31 534 LayerList scrollables = getScrollableBackLayers(false, discard);
Chris@31 535 for (LayerList::const_iterator i = scrollables.begin();
Chris@31 536 i != scrollables.end(); ++i) {
Chris@31 537 if (*i == obj || (*i)->getModel() == obj) {
Chris@31 538 recreate = true;
Chris@31 539 break;
Chris@31 540 }
Chris@31 541 }
Chris@31 542
Chris@31 543 if (recreate) {
Chris@31 544 delete m_cache;
Chris@31 545 m_cache = 0;
Chris@31 546 }
Chris@0 547
Chris@0 548 if (long(startFrame) < myStartFrame) startFrame = myStartFrame;
Chris@0 549 if (endFrame > myEndFrame) endFrame = myEndFrame;
Chris@0 550
Chris@15 551 int x0 = getXForFrame(startFrame);
Chris@15 552 int x1 = getXForFrame(endFrame + 1);
Chris@15 553 if (x1 < x0) x1 = x0;
Chris@0 554
Chris@0 555 checkProgress(obj);
Chris@0 556
Chris@31 557 update();
Chris@31 558 //!! update(x0, 0, x1 - x0 + 1, height());
Chris@0 559 }
Chris@0 560
Chris@0 561 void
Chris@0 562 View::modelCompletionChanged()
Chris@0 563 {
Chris@0 564 QObject *obj = sender();
Chris@0 565 checkProgress(obj);
Chris@0 566 }
Chris@0 567
Chris@0 568 void
Chris@0 569 View::modelReplaced()
Chris@0 570 {
Chris@0 571 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@1 572 std::cerr << "View(" << this << ")::modelReplaced()" << std::endl;
Chris@0 573 #endif
Chris@1 574 delete m_cache;
Chris@1 575 m_cache = 0;
Chris@1 576
Chris@0 577 update();
Chris@0 578 }
Chris@0 579
Chris@0 580 void
Chris@0 581 View::layerParametersChanged()
Chris@0 582 {
Chris@0 583 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@0 584
Chris@0 585 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 586 std::cerr << "View::layerParametersChanged()" << std::endl;
Chris@0 587 #endif
Chris@0 588
Chris@0 589 delete m_cache;
Chris@0 590 m_cache = 0;
Chris@0 591 update();
Chris@0 592
Chris@0 593 if (layer) {
Chris@0 594 emit propertyContainerPropertyChanged(layer);
Chris@0 595 }
Chris@0 596 }
Chris@0 597
Chris@0 598 void
Chris@0 599 View::layerNameChanged()
Chris@0 600 {
Chris@0 601 Layer *layer = dynamic_cast<Layer *>(sender());
Chris@0 602 if (layer) emit propertyContainerNameChanged(layer);
Chris@0 603 }
Chris@0 604
Chris@0 605 void
Chris@0 606 View::viewManagerCentreFrameChanged(void *p, unsigned long f, bool locked)
Chris@0 607 {
Chris@0 608 if (m_followPan && p != this && locked) {
Chris@0 609 if (m_manager && (sender() == m_manager)) {
Chris@0 610 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 611 std::cerr << this << ": manager frame changed " << f << " from " << p << std::endl;
Chris@0 612 #endif
Chris@0 613 setCentreFrame(f);
Chris@0 614 if (p == this) repaint();
Chris@0 615 }
Chris@0 616 }
Chris@0 617 }
Chris@0 618
Chris@0 619 void
Chris@0 620 View::viewManagerPlaybackFrameChanged(unsigned long f)
Chris@0 621 {
Chris@0 622 if (m_manager) {
Chris@0 623 if (sender() != m_manager) return;
Chris@0 624 }
Chris@0 625
Chris@0 626 if (m_playPointerFrame == f) return;
Chris@15 627 bool visible = (getXForFrame(m_playPointerFrame) != getXForFrame(f));
Chris@0 628 size_t oldPlayPointerFrame = m_playPointerFrame;
Chris@0 629 m_playPointerFrame = f;
Chris@0 630 if (!visible) return;
Chris@0 631
Chris@21 632 bool modifierPressed = // we only care about these ones
Chris@21 633 ((QApplication::keyboardModifiers() & Qt::ShiftModifier) ||
Chris@21 634 (QApplication::keyboardModifiers() & Qt::ControlModifier));
Chris@20 635
Chris@0 636 switch (m_followPlay) {
Chris@0 637
Chris@0 638 case PlaybackScrollContinuous:
Chris@10 639 if (QApplication::mouseButtons() == Qt::NoButton &&
Chris@21 640 !modifierPressed) {
Chris@0 641 setCentreFrame(f, false);
Chris@0 642 }
Chris@0 643 break;
Chris@0 644
Chris@0 645 case PlaybackScrollPage:
Chris@0 646 {
Chris@15 647 int xold = getXForFrame(oldPlayPointerFrame);
Chris@10 648 repaint(xold - 1, 0, 3, height());
Chris@10 649
Chris@15 650 long w = getEndFrame() - getStartFrame();
Chris@0 651 w -= w/5;
Chris@0 652 long sf = (f / w) * w - w/8;
Chris@10 653
Chris@10 654 if (m_manager &&
Chris@10 655 m_manager->isPlaying() &&
Chris@10 656 m_manager->getPlaySelectionMode()) {
Chris@24 657 MultiSelection::SelectionList selections = m_manager->getSelections();
Chris@10 658 if (!selections.empty()) {
Chris@10 659 size_t selectionStart = selections.begin()->getStartFrame();
Chris@10 660 if (sf < long(selectionStart) - w / 10) {
Chris@10 661 sf = long(selectionStart) - w / 10;
Chris@10 662 }
Chris@10 663 }
Chris@10 664 }
Chris@10 665
Chris@0 666 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 667 std::cerr << "PlaybackScrollPage: f = " << f << ", sf = " << sf << ", start frame "
Chris@0 668 << getStartFrame() << std::endl;
Chris@0 669 #endif
Chris@10 670
Chris@15 671 // We don't consider scrolling unless the pointer is outside
Chris@15 672 // the clearly visible range already
Chris@15 673
Chris@15 674 int xnew = getXForFrame(m_playPointerFrame);
Chris@15 675
Chris@18 676 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@18 677 std::cerr << "xnew = " << xnew << ", width = " << width() << std::endl;
Chris@18 678 #endif
Chris@18 679
Chris@15 680 if (xnew < width()/8 || xnew > (width()*7)/8) {
Chris@15 681 if (QApplication::mouseButtons() == Qt::NoButton &&
Chris@21 682 !modifierPressed) {
Chris@15 683 long offset = getFrameForX(width()/2) - getStartFrame();
Chris@15 684 long newCentre = sf + offset;
Chris@15 685 bool changed = setCentreFrame(newCentre, false);
Chris@15 686 if (changed) {
Chris@15 687 xold = getXForFrame(oldPlayPointerFrame);
Chris@15 688 update(xold - 1, 0, 3, height());
Chris@15 689 }
Chris@10 690 }
Chris@10 691 }
Chris@10 692
Chris@0 693 update(xnew - 1, 0, 3, height());
Chris@10 694
Chris@0 695 break;
Chris@0 696 }
Chris@0 697
Chris@0 698 case PlaybackIgnore:
Chris@0 699 if (long(f) >= getStartFrame() && f < getEndFrame()) {
Chris@0 700 update();
Chris@0 701 }
Chris@0 702 break;
Chris@0 703 }
Chris@0 704 }
Chris@0 705
Chris@0 706 void
Chris@0 707 View::viewManagerZoomLevelChanged(void *p, unsigned long z, bool locked)
Chris@0 708 {
Chris@0 709 if (m_followZoom && p != this && locked) {
Chris@0 710 if (m_manager && (sender() == m_manager)) {
Chris@0 711 setZoomLevel(z);
Chris@0 712 if (p == this) repaint();
Chris@0 713 }
Chris@0 714 }
Chris@0 715 }
Chris@0 716
Chris@9 717 void
Chris@9 718 View::selectionChanged()
Chris@9 719 {
Chris@9 720 if (m_selectionCached) {
Chris@9 721 delete m_cache;
Chris@9 722 m_cache = 0;
Chris@9 723 m_selectionCached = false;
Chris@9 724 }
Chris@9 725 update();
Chris@9 726 }
Chris@9 727
Chris@0 728 size_t
Chris@0 729 View::getModelsStartFrame() const
Chris@0 730 {
Chris@0 731 bool first = true;
Chris@0 732 size_t startFrame = 0;
Chris@0 733
Chris@0 734 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 735
Chris@0 736 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@0 737
Chris@0 738 size_t thisStartFrame = (*i)->getModel()->getStartFrame();
Chris@0 739
Chris@0 740 if (first || thisStartFrame < startFrame) {
Chris@0 741 startFrame = thisStartFrame;
Chris@0 742 }
Chris@0 743 first = false;
Chris@0 744 }
Chris@0 745 }
Chris@0 746 return startFrame;
Chris@0 747 }
Chris@0 748
Chris@0 749 size_t
Chris@0 750 View::getModelsEndFrame() const
Chris@0 751 {
Chris@0 752 bool first = true;
Chris@0 753 size_t endFrame = 0;
Chris@0 754
Chris@0 755 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 756
Chris@0 757 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@0 758
Chris@0 759 size_t thisEndFrame = (*i)->getModel()->getEndFrame();
Chris@0 760
Chris@0 761 if (first || thisEndFrame > endFrame) {
Chris@0 762 endFrame = thisEndFrame;
Chris@0 763 }
Chris@0 764 first = false;
Chris@0 765 }
Chris@0 766 }
Chris@0 767
Chris@0 768 if (first) return getModelsStartFrame();
Chris@0 769 return endFrame;
Chris@0 770 }
Chris@0 771
Chris@0 772 int
Chris@0 773 View::getModelsSampleRate() const
Chris@0 774 {
Chris@0 775 //!!! Just go for the first, for now. If we were supporting
Chris@0 776 // multiple samplerates, we'd probably want to do frame/time
Chris@0 777 // conversion in the model
Chris@0 778
Chris@0 779 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 780 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
Chris@0 781 return (*i)->getModel()->getSampleRate();
Chris@0 782 }
Chris@0 783 }
Chris@0 784 return 0;
Chris@0 785 }
Chris@0 786
Chris@0 787 bool
Chris@0 788 View::areLayersScrollable() const
Chris@0 789 {
Chris@0 790 // True iff all views are scrollable
Chris@0 791 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 792 if (!(*i)->isLayerScrollable()) return false;
Chris@0 793 }
Chris@0 794 return true;
Chris@0 795 }
Chris@0 796
Chris@0 797 View::LayerList
Chris@31 798 View::getScrollableBackLayers(bool testChanged, bool &changed) const
Chris@0 799 {
Chris@0 800 changed = false;
Chris@0 801
Chris@0 802 LayerList scrollables;
Chris@0 803 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@29 804 if ((*i)->isLayerDormant()) continue;
Chris@0 805 if ((*i)->isLayerScrollable()) scrollables.push_back(*i);
Chris@0 806 else {
Chris@31 807 if (testChanged && scrollables != m_lastScrollableBackLayers) {
Chris@0 808 m_lastScrollableBackLayers = scrollables;
Chris@0 809 changed = true;
Chris@0 810 }
Chris@0 811 return scrollables;
Chris@0 812 }
Chris@0 813 }
Chris@0 814
Chris@0 815 if (scrollables.size() == 1 &&
Chris@0 816 dynamic_cast<TimeRulerLayer *>(*scrollables.begin())) {
Chris@0 817
Chris@0 818 // If only the ruler is scrollable, it's not worth the bother
Chris@0 819 // -- it probably redraws as quickly as it refreshes from
Chris@0 820 // cache
Chris@0 821 scrollables.clear();
Chris@0 822 }
Chris@0 823
Chris@31 824 if (testChanged && scrollables != m_lastScrollableBackLayers) {
Chris@0 825 m_lastScrollableBackLayers = scrollables;
Chris@0 826 changed = true;
Chris@0 827 }
Chris@0 828 return scrollables;
Chris@0 829 }
Chris@0 830
Chris@0 831 View::LayerList
Chris@31 832 View::getNonScrollableFrontLayers(bool testChanged, bool &changed) const
Chris@0 833 {
Chris@0 834 changed = false;
Chris@31 835 LayerList scrollables = getScrollableBackLayers(testChanged, changed);
Chris@0 836 LayerList nonScrollables;
Chris@0 837
Chris@0 838 // Everything in front of the first non-scrollable from the back
Chris@0 839 // should also be considered non-scrollable
Chris@0 840
Chris@0 841 size_t count = 0;
Chris@0 842 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@29 843 if ((*i)->isLayerDormant()) continue;
Chris@0 844 if (count < scrollables.size()) {
Chris@0 845 ++count;
Chris@0 846 continue;
Chris@0 847 }
Chris@0 848 nonScrollables.push_back(*i);
Chris@0 849 }
Chris@0 850
Chris@31 851 if (testChanged && nonScrollables != m_lastNonScrollableBackLayers) {
Chris@0 852 m_lastNonScrollableBackLayers = nonScrollables;
Chris@0 853 changed = true;
Chris@0 854 }
Chris@0 855
Chris@0 856 return nonScrollables;
Chris@0 857 }
Chris@0 858
Chris@0 859 size_t
Chris@0 860 View::getZoomConstraintBlockSize(size_t blockSize,
Chris@0 861 ZoomConstraint::RoundingDirection dir)
Chris@0 862 const
Chris@0 863 {
Chris@0 864 size_t candidate = blockSize;
Chris@0 865 bool haveCandidate = false;
Chris@0 866
Chris@25 867 PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
Chris@25 868
Chris@0 869 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@0 870
Chris@25 871 const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
Chris@25 872 if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
Chris@0 873
Chris@25 874 size_t thisBlockSize =
Chris@25 875 zoomConstraint->getNearestBlockSize(blockSize, dir);
Chris@0 876
Chris@25 877 // Go for the block size that's furthest from the one
Chris@25 878 // passed in. Most of the time, that's what we want.
Chris@25 879 if (!haveCandidate ||
Chris@25 880 (thisBlockSize > blockSize && thisBlockSize > candidate) ||
Chris@25 881 (thisBlockSize < blockSize && thisBlockSize < candidate)) {
Chris@25 882 candidate = thisBlockSize;
Chris@25 883 haveCandidate = true;
Chris@0 884 }
Chris@0 885 }
Chris@0 886
Chris@0 887 return candidate;
Chris@0 888 }
Chris@0 889
Chris@0 890 void
Chris@0 891 View::zoom(bool in)
Chris@0 892 {
Chris@0 893 int newZoomLevel = m_zoomLevel;
Chris@0 894
Chris@0 895 if (in) {
Chris@0 896 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
Chris@0 897 ZoomConstraint::RoundDown);
Chris@0 898 } else {
Chris@0 899 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
Chris@0 900 ZoomConstraint::RoundUp);
Chris@0 901 }
Chris@0 902
Chris@0 903 if (newZoomLevel != m_zoomLevel) {
Chris@0 904 setZoomLevel(newZoomLevel);
Chris@0 905 }
Chris@0 906 }
Chris@0 907
Chris@0 908 void
Chris@12 909 View::scroll(bool right, bool lots)
Chris@12 910 {
Chris@12 911 long delta;
Chris@12 912 if (lots) {
Chris@15 913 delta = (getEndFrame() - getStartFrame()) / 2;
Chris@12 914 } else {
Chris@15 915 delta = (getEndFrame() - getStartFrame()) / 20;
Chris@12 916 }
Chris@12 917 if (right) delta = -delta;
Chris@12 918
Chris@12 919 if (int(m_centreFrame) < delta) {
Chris@12 920 setCentreFrame(0);
Chris@12 921 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
Chris@12 922 setCentreFrame(getModelsEndFrame());
Chris@12 923 } else {
Chris@12 924 setCentreFrame(m_centreFrame - delta);
Chris@12 925 }
Chris@12 926 }
Chris@12 927
Chris@12 928 void
Chris@0 929 View::checkProgress(void *object)
Chris@0 930 {
Chris@0 931 if (!m_showProgress) return;
Chris@0 932
Chris@0 933 int ph = height();
Chris@0 934
Chris@0 935 for (ProgressMap::const_iterator i = m_progressBars.begin();
Chris@0 936 i != m_progressBars.end(); ++i) {
Chris@0 937
Chris@0 938 if (i->first == object) {
Chris@0 939
Chris@0 940 int completion = i->first->getCompletion();
Chris@0 941
Chris@0 942 if (completion >= 100) {
Chris@0 943
Chris@0 944 i->second->hide();
Chris@0 945
Chris@0 946 } else {
Chris@0 947
Chris@0 948 i->second->setText(i->first->getPropertyContainerName());
Chris@0 949 i->second->setValue(completion);
Chris@0 950 i->second->move(0, ph - i->second->height());
Chris@0 951
Chris@0 952 i->second->show();
Chris@0 953 i->second->update();
Chris@0 954
Chris@0 955 ph -= i->second->height();
Chris@0 956 }
Chris@0 957 } else {
Chris@0 958 if (i->second->isVisible()) {
Chris@0 959 ph -= i->second->height();
Chris@0 960 }
Chris@0 961 }
Chris@0 962 }
Chris@0 963 }
Chris@0 964
Chris@0 965 void
Chris@0 966 View::paintEvent(QPaintEvent *e)
Chris@0 967 {
Chris@0 968 // Profiler prof("View::paintEvent", true);
Chris@0 969 // std::cerr << "View::paintEvent" << std::endl;
Chris@0 970
Chris@0 971 if (m_layers.empty()) {
Chris@0 972 QFrame::paintEvent(e);
Chris@0 973 return;
Chris@0 974 }
Chris@0 975
Chris@0 976 // ensure our constraints are met
Chris@0 977 m_zoomLevel = getZoomConstraintBlockSize(m_zoomLevel,
Chris@0 978 ZoomConstraint::RoundUp);
Chris@0 979
Chris@0 980 QPainter paint;
Chris@0 981 bool repaintCache = false;
Chris@0 982 bool paintedCacheRect = false;
Chris@0 983
Chris@0 984 QRect cacheRect(rect());
Chris@0 985
Chris@0 986 if (e) {
Chris@0 987 cacheRect &= e->rect();
Chris@0 988 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 989 std::cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
Chris@0 990 << ", my rect " << width() << "x" << height() << std::endl;
Chris@0 991 #endif
Chris@0 992 }
Chris@0 993
Chris@0 994 QRect nonCacheRect(cacheRect);
Chris@0 995
Chris@0 996 // If not all layers are scrollable, but some of the back layers
Chris@0 997 // are, we should store only those in the cache
Chris@0 998
Chris@0 999 bool layersChanged = false;
Chris@31 1000 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
Chris@31 1001 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged);
Chris@9 1002 bool selectionCacheable = nonScrollables.empty();
Chris@9 1003 bool haveSelections = m_manager && !m_manager->getSelections().empty();
Chris@9 1004 bool selectionDrawn = false;
Chris@0 1005
Chris@10 1006 if (!selectionCacheable) {
Chris@10 1007 selectionCacheable = true;
Chris@10 1008 for (LayerList::const_iterator i = nonScrollables.begin();
Chris@10 1009 i != nonScrollables.end(); ++i) {
Chris@10 1010 if ((*i)->isLayerOpaque()) {
Chris@10 1011 selectionCacheable = false;
Chris@10 1012 break;
Chris@10 1013 }
Chris@10 1014 }
Chris@10 1015 }
Chris@10 1016
Chris@0 1017 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1018 std::cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
Chris@0 1019 << " scrollable back layers and " << nonScrollables.size()
Chris@0 1020 << " non-scrollable front layers" << std::endl;
Chris@9 1021 std::cerr << "haveSelections " << haveSelections << ", selectionCacheable "
Chris@9 1022 << selectionCacheable << ", m_selectionCached " << m_selectionCached << std::endl;
Chris@0 1023 #endif
Chris@0 1024
Chris@9 1025 if (layersChanged || scrollables.empty() ||
Chris@9 1026 (haveSelections && (selectionCacheable != m_selectionCached))) {
Chris@0 1027 delete m_cache;
Chris@0 1028 m_cache = 0;
Chris@9 1029 m_selectionCached = false;
Chris@0 1030 }
Chris@0 1031
Chris@0 1032 if (!scrollables.empty()) {
Chris@0 1033 if (!m_cache ||
Chris@0 1034 m_cacheZoomLevel != m_zoomLevel ||
Chris@0 1035 width() != m_cache->width() ||
Chris@0 1036 height() != m_cache->height()) {
Chris@0 1037
Chris@0 1038 // cache is not valid
Chris@0 1039
Chris@0 1040 if (cacheRect.width() < width()/10) {
Chris@0 1041 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1042 std::cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << std::endl;
Chris@0 1043 #endif
Chris@0 1044 } else {
Chris@0 1045 delete m_cache;
Chris@0 1046 m_cache = new QPixmap(width(), height());
Chris@0 1047 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1048 std::cerr << "View(" << this << ")::paintEvent: recreated cache" << std::endl;
Chris@0 1049 #endif
Chris@0 1050 cacheRect = rect();
Chris@0 1051 repaintCache = true;
Chris@0 1052 }
Chris@0 1053
Chris@0 1054 } else if (m_cacheCentreFrame != m_centreFrame) {
Chris@0 1055
Chris@15 1056 long dx =
Chris@15 1057 getXForFrame(m_cacheCentreFrame) -
Chris@15 1058 getXForFrame(m_centreFrame);
Chris@0 1059
Chris@0 1060 if (dx > -width() && dx < width()) {
Chris@0 1061 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC)
Chris@0 1062 // Copying a pixmap to itself doesn't work properly on Windows
Chris@0 1063 // or Mac (it only works when moving in one direction)
Chris@0 1064 static QPixmap *tmpPixmap = 0;
Chris@0 1065 if (!tmpPixmap ||
Chris@0 1066 tmpPixmap->width() != width() ||
Chris@0 1067 tmpPixmap->height() != height()) {
Chris@0 1068 delete tmpPixmap;
Chris@0 1069 tmpPixmap = new QPixmap(width(), height());
Chris@0 1070 }
Chris@0 1071 paint.begin(tmpPixmap);
Chris@0 1072 paint.drawPixmap(0, 0, *m_cache);
Chris@0 1073 paint.end();
Chris@0 1074 paint.begin(m_cache);
Chris@0 1075 paint.drawPixmap(dx, 0, *tmpPixmap);
Chris@0 1076 paint.end();
Chris@0 1077 #else
Chris@0 1078 // But it seems to be fine on X11
Chris@0 1079 paint.begin(m_cache);
Chris@0 1080 paint.drawPixmap(dx, 0, *m_cache);
Chris@0 1081 paint.end();
Chris@0 1082 #endif
Chris@0 1083
Chris@0 1084 if (dx < 0) {
Chris@0 1085 cacheRect = QRect(width() + dx, 0, -dx, height());
Chris@0 1086 } else {
Chris@0 1087 cacheRect = QRect(0, 0, dx, height());
Chris@0 1088 }
Chris@0 1089 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1090 std::cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << std::endl;
Chris@0 1091 #endif
Chris@0 1092 } else {
Chris@0 1093 cacheRect = rect();
Chris@0 1094 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1095 std::cerr << "View(" << this << ")::paintEvent: scrolling too far" << std::endl;
Chris@0 1096 #endif
Chris@0 1097 }
Chris@0 1098 repaintCache = true;
Chris@0 1099
Chris@0 1100 } else {
Chris@0 1101 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1102 std::cerr << "View(" << this << ")::paintEvent: cache is good" << std::endl;
Chris@0 1103 #endif
Chris@0 1104 paint.begin(this);
Chris@0 1105 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@0 1106 paint.end();
Chris@0 1107 QFrame::paintEvent(e);
Chris@0 1108 paintedCacheRect = true;
Chris@0 1109 }
Chris@0 1110
Chris@0 1111 m_cacheCentreFrame = m_centreFrame;
Chris@0 1112 m_cacheZoomLevel = m_zoomLevel;
Chris@0 1113 }
Chris@0 1114
Chris@0 1115 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@0 1116 // std::cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << std::endl;
Chris@0 1117 #endif
Chris@0 1118
Chris@0 1119 // Scrollable (cacheable) items first
Chris@0 1120
Chris@0 1121 if (!paintedCacheRect) {
Chris@0 1122
Chris@0 1123 if (repaintCache) paint.begin(m_cache);
Chris@0 1124 else paint.begin(this);
Chris@0 1125
Chris@0 1126 paint.setClipRect(cacheRect);
Chris@0 1127
Chris@0 1128 if (hasLightBackground()) {
Chris@0 1129 paint.setPen(Qt::white);
Chris@0 1130 paint.setBrush(Qt::white);
Chris@0 1131 } else {
Chris@0 1132 paint.setPen(Qt::black);
Chris@0 1133 paint.setBrush(Qt::black);
Chris@0 1134 }
Chris@0 1135 paint.drawRect(cacheRect);
Chris@0 1136
Chris@0 1137 paint.setPen(Qt::black);
Chris@0 1138 paint.setBrush(Qt::NoBrush);
Chris@0 1139
Chris@0 1140 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
Chris@8 1141 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@8 1142 paint.save();
Chris@0 1143 (*i)->paint(paint, cacheRect);
Chris@8 1144 paint.restore();
Chris@0 1145 }
Chris@9 1146
Chris@9 1147 if (haveSelections && selectionCacheable) {
Chris@9 1148 drawSelections(paint);
Chris@9 1149 m_selectionCached = repaintCache;
Chris@9 1150 selectionDrawn = true;
Chris@9 1151 }
Chris@0 1152
Chris@0 1153 paint.end();
Chris@0 1154
Chris@0 1155 if (repaintCache) {
Chris@0 1156 cacheRect |= (e ? e->rect() : rect());
Chris@0 1157 paint.begin(this);
Chris@0 1158 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
Chris@0 1159 paint.end();
Chris@0 1160 }
Chris@0 1161 }
Chris@0 1162
Chris@0 1163 // Now non-cacheable items. We always need to redraw the
Chris@0 1164 // non-cacheable items across at least the area we drew of the
Chris@0 1165 // cacheable items.
Chris@0 1166
Chris@0 1167 nonCacheRect |= cacheRect;
Chris@0 1168
Chris@0 1169 paint.begin(this);
Chris@0 1170 paint.setClipRect(nonCacheRect);
Chris@0 1171
Chris@0 1172 if (scrollables.empty()) {
Chris@0 1173 if (hasLightBackground()) {
Chris@0 1174 paint.setPen(Qt::white);
Chris@0 1175 paint.setBrush(Qt::white);
Chris@0 1176 } else {
Chris@0 1177 paint.setPen(Qt::black);
Chris@0 1178 paint.setBrush(Qt::black);
Chris@0 1179 }
Chris@0 1180 paint.drawRect(nonCacheRect);
Chris@0 1181 }
Chris@0 1182
Chris@0 1183 paint.setPen(Qt::black);
Chris@0 1184 paint.setBrush(Qt::NoBrush);
Chris@0 1185
Chris@0 1186 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
Chris@0 1187 (*i)->paint(paint, nonCacheRect);
Chris@0 1188 }
Chris@0 1189
Chris@9 1190 paint.end();
Chris@8 1191
Chris@9 1192 paint.begin(this);
Chris@9 1193 if (e) paint.setClipRect(e->rect());
Chris@9 1194 if (!m_selectionCached) {
Chris@9 1195 drawSelections(paint);
Chris@8 1196 }
Chris@0 1197 paint.end();
Chris@0 1198
Chris@0 1199 if (m_followPlay != PlaybackScrollContinuous) {
Chris@0 1200
Chris@0 1201 paint.begin(this);
Chris@0 1202
Chris@0 1203 if (long(m_playPointerFrame) > getStartFrame() &&
Chris@0 1204 m_playPointerFrame < getEndFrame()) {
Chris@0 1205
Chris@15 1206 int playx = getXForFrame(m_playPointerFrame);
Chris@0 1207
Chris@0 1208 paint.setPen(Qt::black);
Chris@0 1209 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
Chris@0 1210 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
Chris@0 1211 paint.drawPoint(playx, 0);
Chris@0 1212 paint.drawPoint(playx, height() - 1);
Chris@0 1213 paint.setPen(Qt::white);
Chris@0 1214 paint.drawLine(playx, 1, playx, height() - 2);
Chris@0 1215 }
Chris@0 1216
Chris@0 1217 paint.end();
Chris@0 1218 }
Chris@0 1219
Chris@0 1220 QFrame::paintEvent(e);
Chris@0 1221 }
Chris@0 1222
Chris@9 1223 void
Chris@9 1224 View::drawSelections(QPainter &paint)
Chris@9 1225 {
Chris@24 1226 MultiSelection::SelectionList selections;
Chris@9 1227
Chris@9 1228 if (m_manager) {
Chris@9 1229 selections = m_manager->getSelections();
Chris@9 1230 if (m_manager->haveInProgressSelection()) {
Chris@9 1231 bool exclusive;
Chris@9 1232 Selection inProgressSelection =
Chris@9 1233 m_manager->getInProgressSelection(exclusive);
Chris@9 1234 if (exclusive) selections.clear();
Chris@9 1235 selections.insert(inProgressSelection);
Chris@9 1236 }
Chris@9 1237 }
Chris@9 1238
Chris@9 1239 paint.save();
Chris@9 1240 paint.setPen(QColor(150, 150, 255));
Chris@9 1241 paint.setBrush(QColor(150, 150, 255, 80));
Chris@9 1242
Chris@10 1243 int sampleRate = getModelsSampleRate();
Chris@10 1244
Chris@10 1245 const QFontMetrics &metrics = paint.fontMetrics();
Chris@10 1246
Chris@24 1247 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@9 1248 i != selections.end(); ++i) {
Chris@9 1249
Chris@15 1250 int p0 = getXForFrame(i->getStartFrame());
Chris@15 1251 int p1 = getXForFrame(i->getEndFrame());
Chris@9 1252
Chris@10 1253 if (p1 < 0 || p0 > width()) continue;
Chris@9 1254
Chris@9 1255 #ifdef DEBUG_VIEW_WIDGET_PAINT
Chris@9 1256 std::cerr << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << std::endl;
Chris@9 1257 #endif
Chris@9 1258
Chris@9 1259 paint.drawRect(p0, -1, p1 - p0, height() + 1);
Chris@10 1260
Chris@10 1261 if (sampleRate && shouldLabelSelections()) {
Chris@10 1262
Chris@10 1263 QString startText = QString("%1 / %2")
Chris@10 1264 .arg(QString::fromStdString
Chris@10 1265 (RealTime::frame2RealTime
Chris@10 1266 (i->getStartFrame(), sampleRate).toText(true)))
Chris@10 1267 .arg(i->getStartFrame());
Chris@10 1268
Chris@10 1269 QString endText = QString(" %1 / %2")
Chris@10 1270 .arg(QString::fromStdString
Chris@10 1271 (RealTime::frame2RealTime
Chris@10 1272 (i->getEndFrame(), sampleRate).toText(true)))
Chris@10 1273 .arg(i->getEndFrame());
Chris@10 1274
Chris@10 1275 QString durationText = QString("(%1 / %2) ")
Chris@10 1276 .arg(QString::fromStdString
Chris@10 1277 (RealTime::frame2RealTime
Chris@10 1278 (i->getEndFrame() - i->getStartFrame(), sampleRate)
Chris@10 1279 .toText(true)))
Chris@10 1280 .arg(i->getEndFrame() - i->getStartFrame());
Chris@10 1281
Chris@10 1282 int sw = metrics.width(startText),
Chris@10 1283 ew = metrics.width(endText),
Chris@10 1284 dw = metrics.width(durationText);
Chris@10 1285
Chris@10 1286 int sy = metrics.ascent() + metrics.height() + 4;
Chris@10 1287 int ey = sy;
Chris@10 1288 int dy = sy + metrics.height();
Chris@10 1289
Chris@10 1290 int sx = p0 + 2;
Chris@10 1291 int ex = sx;
Chris@10 1292 int dx = sx;
Chris@10 1293
Chris@10 1294 if (sw + ew > (p1 - p0)) {
Chris@10 1295 ey += metrics.height();
Chris@10 1296 dy += metrics.height();
Chris@10 1297 }
Chris@10 1298
Chris@10 1299 if (ew < (p1 - p0)) {
Chris@10 1300 ex = p1 - 2 - ew;
Chris@10 1301 }
Chris@10 1302
Chris@10 1303 if (dw < (p1 - p0)) {
Chris@10 1304 dx = p1 - 2 - dw;
Chris@10 1305 }
Chris@10 1306
Chris@10 1307 paint.drawText(sx, sy, startText);
Chris@10 1308 paint.drawText(ex, ey, endText);
Chris@10 1309 paint.drawText(dx, dy, durationText);
Chris@10 1310 }
Chris@9 1311 }
Chris@9 1312
Chris@9 1313 paint.restore();
Chris@9 1314 }
Chris@9 1315
Chris@3 1316 QString
Chris@3 1317 View::toXmlString(QString indent, QString extraAttributes) const
Chris@3 1318 {
Chris@3 1319 QString s;
Chris@3 1320
Chris@3 1321 s += indent;
Chris@3 1322
Chris@3 1323 s += QString("<view "
Chris@3 1324 "centre=\"%1\" "
Chris@3 1325 "zoom=\"%2\" "
Chris@3 1326 "followPan=\"%3\" "
Chris@3 1327 "followZoom=\"%4\" "
Chris@3 1328 "tracking=\"%5\" "
Chris@3 1329 "light=\"%6\" %7>\n")
Chris@3 1330 .arg(m_centreFrame)
Chris@3 1331 .arg(m_zoomLevel)
Chris@3 1332 .arg(m_followPan)
Chris@3 1333 .arg(m_followZoom)
Chris@3 1334 .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
Chris@3 1335 m_followPlay == PlaybackScrollPage ? "page" : "ignore")
Chris@3 1336 .arg(m_lightBackground)
Chris@3 1337 .arg(extraAttributes);
Chris@3 1338
Chris@3 1339 for (size_t i = 0; i < m_layers.size(); ++i) {
Chris@3 1340 s += m_layers[i]->toXmlString(indent + " ");
Chris@3 1341 }
Chris@3 1342
Chris@4 1343 s += indent + "</view>\n";
Chris@3 1344
Chris@3 1345 return s;
Chris@3 1346 }
Chris@3 1347
Chris@29 1348 ViewPropertyContainer::ViewPropertyContainer(View *v) :
Chris@29 1349 m_v(v)
Chris@29 1350 {
Chris@29 1351 connect(m_v, SIGNAL(propertyChanged(PropertyName)),
Chris@29 1352 this, SIGNAL(propertyChanged(PropertyName)));
Chris@29 1353 }
Chris@3 1354
Chris@0 1355 #ifdef INCLUDE_MOCFILES
Chris@0 1356 #include "View.moc.cpp"
Chris@0 1357 #endif
Chris@0 1358