annotate view/View.cpp @ 299:5c59c433b358

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