00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "View.h"
00017 #include "layer/Layer.h"
00018 #include "data/model/Model.h"
00019 #include "base/ZoomConstraint.h"
00020 #include "base/Profiler.h"
00021 #include "base/Pitch.h"
00022 #include "base/Preferences.h"
00023
00024 #include "layer/TimeRulerLayer.h"
00025 #include "layer/SingleColourLayer.h"
00026 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
00027 #include "data/model/RangeSummarisableTimeValueModel.h"
00028
00029 #include <QPainter>
00030 #include <QPaintEvent>
00031 #include <QRect>
00032 #include <QApplication>
00033 #include <QProgressDialog>
00034 #include <QTextStream>
00035 #include <QFont>
00036
00037 #include <iostream>
00038 #include <cassert>
00039 #include <math.h>
00040
00041
00042
00043 using std::cerr;
00044 using std::endl;
00045
00046 View::View(QWidget *w, bool showProgress) :
00047 QFrame(w),
00048 m_centreFrame(0),
00049 m_zoomLevel(1024),
00050 m_followPan(true),
00051 m_followZoom(true),
00052 m_followPlay(PlaybackScrollPage),
00053 m_playPointerFrame(0),
00054 m_showProgress(showProgress),
00055 m_cache(0),
00056 m_cacheCentreFrame(0),
00057 m_cacheZoomLevel(1024),
00058 m_selectionCached(false),
00059 m_deleting(false),
00060 m_haveSelectedLayer(false),
00061 m_manager(0),
00062 m_propertyContainer(new ViewPropertyContainer(this))
00063 {
00064 }
00065
00066 View::~View()
00067 {
00068
00069
00070 m_deleting = true;
00071 delete m_propertyContainer;
00072 }
00073
00074 PropertyContainer::PropertyList
00075 View::getProperties() const
00076 {
00077 PropertyContainer::PropertyList list;
00078 list.push_back("Global Scroll");
00079 list.push_back("Global Zoom");
00080 list.push_back("Follow Playback");
00081 return list;
00082 }
00083
00084 QString
00085 View::getPropertyLabel(const PropertyName &pn) const
00086 {
00087 if (pn == "Global Scroll") return tr("Global Scroll");
00088 if (pn == "Global Zoom") return tr("Global Zoom");
00089 if (pn == "Follow Playback") return tr("Follow Playback");
00090 return "";
00091 }
00092
00093 PropertyContainer::PropertyType
00094 View::getPropertyType(const PropertyContainer::PropertyName &name) const
00095 {
00096 if (name == "Global Scroll") return PropertyContainer::ToggleProperty;
00097 if (name == "Global Zoom") return PropertyContainer::ToggleProperty;
00098 if (name == "Follow Playback") return PropertyContainer::ValueProperty;
00099 return PropertyContainer::InvalidProperty;
00100 }
00101
00102 int
00103 View::getPropertyRangeAndValue(const PropertyContainer::PropertyName &name,
00104 int *min, int *max, int *deflt) const
00105 {
00106 if (deflt) *deflt = 1;
00107 if (name == "Global Scroll") return m_followPan;
00108 if (name == "Global Zoom") return m_followZoom;
00109 if (name == "Follow Playback") {
00110 if (min) *min = 0;
00111 if (max) *max = 2;
00112 if (deflt) *deflt = int(PlaybackScrollPage);
00113 return int(m_followPlay);
00114 }
00115 if (min) *min = 0;
00116 if (max) *max = 0;
00117 if (deflt) *deflt = 0;
00118 return 0;
00119 }
00120
00121 QString
00122 View::getPropertyValueLabel(const PropertyContainer::PropertyName &name,
00123 int value) const
00124 {
00125 if (name == "Follow Playback") {
00126 switch (value) {
00127 default:
00128 case 0: return tr("Scroll");
00129 case 1: return tr("Page");
00130 case 2: return tr("Off");
00131 }
00132 }
00133 return tr("<unknown>");
00134 }
00135
00136 void
00137 View::setProperty(const PropertyContainer::PropertyName &name, int value)
00138 {
00139 if (name == "Global Scroll") {
00140 setFollowGlobalPan(value != 0);
00141 } else if (name == "Global Zoom") {
00142 setFollowGlobalZoom(value != 0);
00143 } else if (name == "Follow Playback") {
00144 switch (value) {
00145 default:
00146 case 0: setPlaybackFollow(PlaybackScrollContinuous); break;
00147 case 1: setPlaybackFollow(PlaybackScrollPage); break;
00148 case 2: setPlaybackFollow(PlaybackIgnore); break;
00149 }
00150 }
00151 }
00152
00153 size_t
00154 View::getPropertyContainerCount() const
00155 {
00156 return m_layers.size() + 1;
00157 }
00158
00159 const PropertyContainer *
00160 View::getPropertyContainer(size_t i) const
00161 {
00162 return (const PropertyContainer *)(((View *)this)->
00163 getPropertyContainer(i));
00164 }
00165
00166 PropertyContainer *
00167 View::getPropertyContainer(size_t i)
00168 {
00169 if (i == 0) return m_propertyContainer;
00170 return m_layers[i-1];
00171 }
00172
00173 bool
00174 View::getValueExtents(QString unit, float &min, float &max, bool &log) const
00175 {
00176 bool have = false;
00177
00178 for (LayerList::const_iterator i = m_layers.begin();
00179 i != m_layers.end(); ++i) {
00180
00181 QString layerUnit;
00182 float layerMin = 0.0, layerMax = 0.0;
00183 float displayMin = 0.0, displayMax = 0.0;
00184 bool layerLog = false;
00185
00186 if ((*i)->getValueExtents(layerMin, layerMax, layerLog, layerUnit) &&
00187 layerUnit.toLower() == unit.toLower()) {
00188
00189 if ((*i)->getDisplayExtents(displayMin, displayMax)) {
00190
00191 min = displayMin;
00192 max = displayMax;
00193 log = layerLog;
00194 have = true;
00195 break;
00196
00197 } else {
00198
00199 if (!have || layerMin < min) min = layerMin;
00200 if (!have || layerMax > max) max = layerMax;
00201 if (layerLog) log = true;
00202 have = true;
00203 }
00204 }
00205 }
00206
00207 return have;
00208 }
00209
00210 int
00211 View::getTextLabelHeight(const Layer *layer, QPainter &paint) const
00212 {
00213 std::map<int, Layer *> sortedLayers;
00214
00215 for (LayerList::const_iterator i = m_layers.begin();
00216 i != m_layers.end(); ++i) {
00217 if ((*i)->needsTextLabelHeight()) {
00218 sortedLayers[getObjectExportId(*i)] = *i;
00219 }
00220 }
00221
00222 int y = 15 + paint.fontMetrics().ascent();
00223
00224 for (std::map<int, Layer *>::const_iterator i = sortedLayers.begin();
00225 i != sortedLayers.end(); ++i) {
00226 if (i->second == layer) return y;
00227 y += paint.fontMetrics().height();
00228 }
00229
00230 return y;
00231 }
00232
00233 void
00234 View::propertyContainerSelected(View *client, PropertyContainer *pc)
00235 {
00236 if (client != this) return;
00237
00238 if (pc == m_propertyContainer) {
00239 if (m_haveSelectedLayer) {
00240 m_haveSelectedLayer = false;
00241 update();
00242 }
00243 return;
00244 }
00245
00246 delete m_cache;
00247 m_cache = 0;
00248
00249 Layer *selectedLayer = 0;
00250
00251 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
00252 if (*i == pc) {
00253 selectedLayer = *i;
00254 m_layers.erase(i);
00255 break;
00256 }
00257 }
00258
00259 if (selectedLayer) {
00260 m_haveSelectedLayer = true;
00261 m_layers.push_back(selectedLayer);
00262 update();
00263 } else {
00264 m_haveSelectedLayer = false;
00265 }
00266
00267 emit propertyContainerSelected(pc);
00268 }
00269
00270 void
00271 View::toolModeChanged()
00272 {
00273
00274 }
00275
00276 void
00277 View::overlayModeChanged()
00278 {
00279 delete m_cache;
00280 m_cache = 0;
00281 update();
00282 }
00283
00284 void
00285 View::zoomWheelsEnabledChanged()
00286 {
00287
00288 }
00289
00290 long
00291 View::getStartFrame() const
00292 {
00293 return getFrameForX(0);
00294 }
00295
00296 size_t
00297 View::getEndFrame() const
00298 {
00299 return getFrameForX(width()) - 1;
00300 }
00301
00302 void
00303 View::setStartFrame(long f)
00304 {
00305 setCentreFrame(f + m_zoomLevel * (width() / 2));
00306 }
00307
00308 bool
00309 View::setCentreFrame(size_t f, bool e)
00310 {
00311 bool changeVisible = false;
00312
00313 if (m_centreFrame != f) {
00314
00315 int formerPixel = m_centreFrame / m_zoomLevel;
00316
00317 m_centreFrame = f;
00318
00319 int newPixel = m_centreFrame / m_zoomLevel;
00320
00321 if (newPixel != formerPixel) {
00322
00323 #ifdef DEBUG_VIEW_WIDGET_PAINT
00324 std::cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << std::endl;
00325 #endif
00326 update();
00327
00328 changeVisible = true;
00329 }
00330
00331 if (e) {
00332 size_t rf = alignToReference(f);
00333 #ifdef DEBUG_VIEW_WIDGET_PAINT
00334 std::cerr << "View[" << this << "]::setCentreFrame(" << f
00335 << "): emitting centreFrameChanged("
00336 << rf << ")" << std::endl;
00337 #endif
00338 emit centreFrameChanged(rf, m_followPan, m_followPlay);
00339 }
00340 }
00341
00342 return changeVisible;
00343 }
00344
00345 int
00346 View::getXForFrame(long frame) const
00347 {
00348 return (frame - getStartFrame()) / m_zoomLevel;
00349 }
00350
00351 long
00352 View::getFrameForX(int x) const
00353 {
00354 long z = (long)m_zoomLevel;
00355 long frame = m_centreFrame - (width()/2) * z;
00356
00357 #ifdef DEBUG_VIEW_WIDGET_PAINT
00358 std::cerr << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << std::endl;
00359 #endif
00360
00361 frame = (frame / z) * z;
00362 return frame + x * z;
00363 }
00364
00365 float
00366 View::getYForFrequency(float frequency,
00367 float minf,
00368 float maxf,
00369 bool logarithmic) const
00370 {
00371 int h = height();
00372
00373 if (logarithmic) {
00374
00375 static float lastminf = 0.0, lastmaxf = 0.0;
00376 static float logminf = 0.0, logmaxf = 0.0;
00377
00378 if (lastminf != minf) {
00379 lastminf = (minf == 0.0 ? 1.0 : minf);
00380 logminf = log10f(minf);
00381 }
00382 if (lastmaxf != maxf) {
00383 lastmaxf = (maxf < lastminf ? lastminf : maxf);
00384 logmaxf = log10f(maxf);
00385 }
00386
00387 if (logminf == logmaxf) return 0;
00388 return h - (h * (log10f(frequency) - logminf)) / (logmaxf - logminf);
00389
00390 } else {
00391
00392 if (minf == maxf) return 0;
00393 return h - (h * (frequency - minf)) / (maxf - minf);
00394 }
00395 }
00396
00397 float
00398 View::getFrequencyForY(int y,
00399 float minf,
00400 float maxf,
00401 bool logarithmic) const
00402 {
00403 int h = height();
00404
00405 if (logarithmic) {
00406
00407 static float lastminf = 0.0, lastmaxf = 0.0;
00408 static float logminf = 0.0, logmaxf = 0.0;
00409
00410 if (lastminf != minf) {
00411 lastminf = (minf == 0.0 ? 1.0 : minf);
00412 logminf = log10f(minf);
00413 }
00414 if (lastmaxf != maxf) {
00415 lastmaxf = (maxf < lastminf ? lastminf : maxf);
00416 logmaxf = log10f(maxf);
00417 }
00418
00419 if (logminf == logmaxf) return 0;
00420 return pow(10.f, logminf + ((logmaxf - logminf) * (h - y)) / h);
00421
00422 } else {
00423
00424 if (minf == maxf) return 0;
00425 return minf + ((h - y) * (maxf - minf)) / h;
00426 }
00427 }
00428
00429 int
00430 View::getZoomLevel() const
00431 {
00432 #ifdef DEBUG_VIEW_WIDGET_PAINT
00433
00434 #endif
00435 return m_zoomLevel;
00436 }
00437
00438 void
00439 View::setZoomLevel(size_t z)
00440 {
00441 if (m_zoomLevel != int(z)) {
00442 m_zoomLevel = z;
00443 emit zoomLevelChanged(z, m_followZoom);
00444 update();
00445 }
00446 }
00447
00448 bool
00449 View::hasLightBackground() const
00450 {
00451 bool darkPalette = false;
00452 if (m_manager) darkPalette = m_manager->getGlobalDarkBackground();
00453
00454 Layer::ColourSignificance maxSignificance = Layer::ColourAbsent;
00455 bool mostSignificantHasDarkBackground = false;
00456
00457 for (LayerList::const_iterator i = m_layers.begin();
00458 i != m_layers.end(); ++i) {
00459
00460 Layer::ColourSignificance s = (*i)->getLayerColourSignificance();
00461 bool light = (*i)->hasLightBackground();
00462
00463 if (int(s) > int(maxSignificance)) {
00464 maxSignificance = s;
00465 mostSignificantHasDarkBackground = !light;
00466 } else if (s == maxSignificance && !light) {
00467 mostSignificantHasDarkBackground = true;
00468 }
00469 }
00470
00471 if (int(maxSignificance) >= int(Layer::ColourAndBackgroundSignificant)) {
00472 return !mostSignificantHasDarkBackground;
00473 } else {
00474 return !darkPalette;
00475 }
00476 }
00477
00478 QColor
00479 View::getBackground() const
00480 {
00481 bool light = hasLightBackground();
00482
00483 QColor widgetbg = palette().window().color();
00484 bool widgetLight =
00485 (widgetbg.red() + widgetbg.green() + widgetbg.blue()) > 384;
00486
00487 if (widgetLight == light) {
00488 if (widgetLight) {
00489 return widgetbg.light();
00490 } else {
00491 return widgetbg.dark();
00492 }
00493 }
00494 else if (light) return Qt::white;
00495 else return Qt::black;
00496 }
00497
00498 QColor
00499 View::getForeground() const
00500 {
00501 bool light = hasLightBackground();
00502
00503 QColor widgetfg = palette().text().color();
00504 bool widgetLight =
00505 (widgetfg.red() + widgetfg.green() + widgetfg.blue()) > 384;
00506
00507 if (widgetLight != light) return widgetfg;
00508 else if (light) return Qt::black;
00509 else return Qt::white;
00510 }
00511
00512 View::LayerProgressBar::LayerProgressBar(QWidget *parent) :
00513 QProgressBar(parent)
00514 {
00515 }
00516
00517 void
00518 View::addLayer(Layer *layer)
00519 {
00520 delete m_cache;
00521 m_cache = 0;
00522
00523 SingleColourLayer *scl = dynamic_cast<SingleColourLayer *>(layer);
00524 if (scl) scl->setDefaultColourFor(this);
00525
00526 m_layers.push_back(layer);
00527
00528 m_progressBars[layer] = new LayerProgressBar(this);
00529 m_progressBars[layer]->setMinimum(0);
00530 m_progressBars[layer]->setMaximum(100);
00531 m_progressBars[layer]->setMinimumWidth(80);
00532
00533 QFont f(m_progressBars[layer]->font());
00534 int fs = Preferences::getInstance()->getViewFontSize();
00535 f.setPointSize(std::min(fs, int(ceil(fs * 0.85))));
00536
00537 m_progressBars[layer]->setFont(f);
00538 m_progressBars[layer]->hide();
00539
00540 connect(layer, SIGNAL(layerParametersChanged()),
00541 this, SLOT(layerParametersChanged()));
00542 connect(layer, SIGNAL(layerParameterRangesChanged()),
00543 this, SLOT(layerParameterRangesChanged()));
00544 connect(layer, SIGNAL(layerMeasurementRectsChanged()),
00545 this, SLOT(layerMeasurementRectsChanged()));
00546 connect(layer, SIGNAL(layerNameChanged()),
00547 this, SLOT(layerNameChanged()));
00548 connect(layer, SIGNAL(modelChanged()),
00549 this, SLOT(modelChanged()));
00550 connect(layer, SIGNAL(modelCompletionChanged()),
00551 this, SLOT(modelCompletionChanged()));
00552 connect(layer, SIGNAL(modelAlignmentCompletionChanged()),
00553 this, SLOT(modelAlignmentCompletionChanged()));
00554 connect(layer, SIGNAL(modelChanged(size_t, size_t)),
00555 this, SLOT(modelChanged(size_t, size_t)));
00556 connect(layer, SIGNAL(modelReplaced()),
00557 this, SLOT(modelReplaced()));
00558
00559 update();
00560
00561 emit propertyContainerAdded(layer);
00562 }
00563
00564 void
00565 View::removeLayer(Layer *layer)
00566 {
00567 if (m_deleting) {
00568 return;
00569 }
00570
00571 delete m_cache;
00572 m_cache = 0;
00573
00574 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
00575 if (*i == layer) {
00576 m_layers.erase(i);
00577 if (m_progressBars.find(layer) != m_progressBars.end()) {
00578 delete m_progressBars[layer];
00579 m_progressBars.erase(layer);
00580 }
00581 break;
00582 }
00583 }
00584
00585 disconnect(layer, SIGNAL(layerParametersChanged()),
00586 this, SLOT(layerParametersChanged()));
00587 disconnect(layer, SIGNAL(layerParameterRangesChanged()),
00588 this, SLOT(layerParameterRangesChanged()));
00589 disconnect(layer, SIGNAL(layerNameChanged()),
00590 this, SLOT(layerNameChanged()));
00591 disconnect(layer, SIGNAL(modelChanged()),
00592 this, SLOT(modelChanged()));
00593 disconnect(layer, SIGNAL(modelCompletionChanged()),
00594 this, SLOT(modelCompletionChanged()));
00595 disconnect(layer, SIGNAL(modelAlignmentCompletionChanged()),
00596 this, SLOT(modelAlignmentCompletionChanged()));
00597 disconnect(layer, SIGNAL(modelChanged(size_t, size_t)),
00598 this, SLOT(modelChanged(size_t, size_t)));
00599 disconnect(layer, SIGNAL(modelReplaced()),
00600 this, SLOT(modelReplaced()));
00601
00602 update();
00603
00604 emit propertyContainerRemoved(layer);
00605 }
00606
00607 Layer *
00608 View::getSelectedLayer()
00609 {
00610 if (m_haveSelectedLayer && !m_layers.empty()) {
00611 return getLayer(getLayerCount() - 1);
00612 } else {
00613 return 0;
00614 }
00615 }
00616
00617 const Layer *
00618 View::getSelectedLayer() const
00619 {
00620 return const_cast<const Layer *>(const_cast<View *>(this)->getSelectedLayer());
00621 }
00622
00623 void
00624 View::setViewManager(ViewManager *manager)
00625 {
00626 if (m_manager) {
00627 m_manager->disconnect(this, SLOT(globalCentreFrameChanged(unsigned long)));
00628 m_manager->disconnect(this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
00629 m_manager->disconnect(this, SLOT(viewManagerPlaybackFrameChanged(unsigned long)));
00630 m_manager->disconnect(this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
00631 m_manager->disconnect(this, SLOT(toolModeChanged()));
00632 m_manager->disconnect(this, SLOT(selectionChanged()));
00633 m_manager->disconnect(this, SLOT(overlayModeChanged()));
00634 m_manager->disconnect(this, SLOT(zoomWheelsEnabledChanged()));
00635 disconnect(m_manager, SLOT(viewCentreFrameChanged(unsigned long, bool, PlaybackFollowMode)));
00636 disconnect(m_manager, SLOT(zoomLevelChanged(unsigned long, bool)));
00637 }
00638
00639 m_manager = manager;
00640
00641 connect(m_manager, SIGNAL(globalCentreFrameChanged(unsigned long)),
00642 this, SLOT(globalCentreFrameChanged(unsigned long)));
00643 connect(m_manager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
00644 this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
00645 connect(m_manager, SIGNAL(playbackFrameChanged(unsigned long)),
00646 this, SLOT(viewManagerPlaybackFrameChanged(unsigned long)));
00647
00648 connect(m_manager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
00649 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
00650
00651 connect(m_manager, SIGNAL(toolModeChanged()),
00652 this, SLOT(toolModeChanged()));
00653 connect(m_manager, SIGNAL(selectionChanged()),
00654 this, SLOT(selectionChanged()));
00655 connect(m_manager, SIGNAL(inProgressSelectionChanged()),
00656 this, SLOT(selectionChanged()));
00657 connect(m_manager, SIGNAL(overlayModeChanged()),
00658 this, SLOT(overlayModeChanged()));
00659 connect(m_manager, SIGNAL(zoomWheelsEnabledChanged()),
00660 this, SLOT(zoomWheelsEnabledChanged()));
00661
00662 connect(this, SIGNAL(centreFrameChanged(unsigned long, bool,
00663 PlaybackFollowMode)),
00664 m_manager, SLOT(viewCentreFrameChanged(unsigned long, bool,
00665 PlaybackFollowMode)));
00666
00667 connect(this, SIGNAL(zoomLevelChanged(unsigned long, bool)),
00668 m_manager, SLOT(viewZoomLevelChanged(unsigned long, bool)));
00669
00670 if (m_followPlay == PlaybackScrollPage) {
00671
00672 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
00673 } else if (m_followPlay == PlaybackScrollContinuous) {
00674
00675 setCentreFrame(m_manager->getPlaybackFrame(), false);
00676 } else if (m_followPan) {
00677
00678 setCentreFrame(m_manager->getGlobalCentreFrame(), false);
00679 }
00680 if (m_followZoom) setZoomLevel(m_manager->getGlobalZoom());
00681
00682 toolModeChanged();
00683 }
00684
00685 void
00686 View::setFollowGlobalPan(bool f)
00687 {
00688 m_followPan = f;
00689 emit propertyContainerPropertyChanged(m_propertyContainer);
00690 }
00691
00692 void
00693 View::setFollowGlobalZoom(bool f)
00694 {
00695 m_followZoom = f;
00696 emit propertyContainerPropertyChanged(m_propertyContainer);
00697 }
00698
00699 void
00700 View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style) const
00701 {
00702 if (style == OutlinedText) {
00703
00704 paint.save();
00705
00706 QColor penColour, surroundColour;
00707
00708 penColour = getForeground();
00709 surroundColour = getBackground();
00710
00711 paint.setPen(surroundColour);
00712
00713 for (int dx = -1; dx <= 1; ++dx) {
00714 for (int dy = -1; dy <= 1; ++dy) {
00715 if (!(dx || dy)) continue;
00716 paint.drawText(x + dx, y + dy, text);
00717 }
00718 }
00719
00720 paint.setPen(penColour);
00721
00722 paint.drawText(x, y, text);
00723
00724 paint.restore();
00725
00726 } else {
00727
00728 std::cerr << "ERROR: View::drawVisibleText: Boxed style not yet implemented!" << std::endl;
00729 }
00730 }
00731
00732 void
00733 View::setPlaybackFollow(PlaybackFollowMode m)
00734 {
00735 m_followPlay = m;
00736 emit propertyContainerPropertyChanged(m_propertyContainer);
00737 }
00738
00739 void
00740 View::modelChanged()
00741 {
00742 QObject *obj = sender();
00743
00744 #ifdef DEBUG_VIEW_WIDGET_PAINT
00745 std::cerr << "View(" << this << ")::modelChanged()" << std::endl;
00746 #endif
00747
00748
00749
00750
00751 bool recreate = false;
00752
00753 bool discard;
00754 LayerList scrollables = getScrollableBackLayers(false, discard);
00755 for (LayerList::const_iterator i = scrollables.begin();
00756 i != scrollables.end(); ++i) {
00757 if (*i == obj || (*i)->getModel() == obj) {
00758 recreate = true;
00759 break;
00760 }
00761 }
00762
00763 if (recreate) {
00764 delete m_cache;
00765 m_cache = 0;
00766 }
00767
00768 emit layerModelChanged();
00769
00770 checkProgress(obj);
00771
00772 update();
00773 }
00774
00775 void
00776 View::modelChanged(size_t startFrame, size_t endFrame)
00777 {
00778 QObject *obj = sender();
00779
00780 long myStartFrame = getStartFrame();
00781 size_t myEndFrame = getEndFrame();
00782
00783 #ifdef DEBUG_VIEW_WIDGET_PAINT
00784 std::cerr << "View(" << this << ")::modelChanged(" << startFrame << "," << endFrame << ") [me " << myStartFrame << "," << myEndFrame << "]" << std::endl;
00785 #endif
00786
00787 if (myStartFrame > 0 && endFrame < size_t(myStartFrame)) {
00788 checkProgress(obj);
00789 return;
00790 }
00791 if (startFrame > myEndFrame) {
00792 checkProgress(obj);
00793 return;
00794 }
00795
00796
00797
00798
00799 bool recreate = false;
00800
00801 bool discard;
00802 LayerList scrollables = getScrollableBackLayers(false, discard);
00803 for (LayerList::const_iterator i = scrollables.begin();
00804 i != scrollables.end(); ++i) {
00805 if (*i == obj || (*i)->getModel() == obj) {
00806 recreate = true;
00807 break;
00808 }
00809 }
00810
00811 if (recreate) {
00812 delete m_cache;
00813 m_cache = 0;
00814 }
00815
00816 if (long(startFrame) < myStartFrame) startFrame = myStartFrame;
00817 if (endFrame > myEndFrame) endFrame = myEndFrame;
00818
00819 checkProgress(obj);
00820
00821 update();
00822 }
00823
00824 void
00825 View::modelCompletionChanged()
00826 {
00827
00828
00829 QObject *obj = sender();
00830 checkProgress(obj);
00831 }
00832
00833 void
00834 View::modelAlignmentCompletionChanged()
00835 {
00836
00837
00838 QObject *obj = sender();
00839 checkProgress(obj);
00840 }
00841
00842 void
00843 View::modelReplaced()
00844 {
00845 #ifdef DEBUG_VIEW_WIDGET_PAINT
00846 std::cerr << "View(" << this << ")::modelReplaced()" << std::endl;
00847 #endif
00848 delete m_cache;
00849 m_cache = 0;
00850
00851 update();
00852 }
00853
00854 void
00855 View::layerParametersChanged()
00856 {
00857 Layer *layer = dynamic_cast<Layer *>(sender());
00858
00859 #ifdef DEBUG_VIEW_WIDGET_PAINT
00860 std::cerr << "View::layerParametersChanged()" << std::endl;
00861 #endif
00862
00863 delete m_cache;
00864 m_cache = 0;
00865 update();
00866
00867 if (layer) {
00868 emit propertyContainerPropertyChanged(layer);
00869 }
00870 }
00871
00872 void
00873 View::layerParameterRangesChanged()
00874 {
00875 Layer *layer = dynamic_cast<Layer *>(sender());
00876 if (layer) emit propertyContainerPropertyRangeChanged(layer);
00877 }
00878
00879 void
00880 View::layerMeasurementRectsChanged()
00881 {
00882 Layer *layer = dynamic_cast<Layer *>(sender());
00883 if (layer) update();
00884 }
00885
00886 void
00887 View::layerNameChanged()
00888 {
00889 Layer *layer = dynamic_cast<Layer *>(sender());
00890 if (layer) emit propertyContainerNameChanged(layer);
00891 }
00892
00893 void
00894 View::globalCentreFrameChanged(unsigned long rf)
00895 {
00896 if (m_followPan) {
00897 size_t f = alignFromReference(rf);
00898 #ifdef DEBUG_VIEW_WIDGET_PAINT
00899 std::cerr << "View[" << this << "]::globalCentreFrameChanged(" << rf
00900 << "): setting centre frame to " << f << std::endl;
00901 #endif
00902 setCentreFrame(f, false);
00903 }
00904 }
00905
00906 void
00907 View::viewCentreFrameChanged(View *, unsigned long )
00908 {
00909
00910 }
00911
00912 void
00913 View::viewManagerPlaybackFrameChanged(unsigned long f)
00914 {
00915 if (m_manager) {
00916 if (sender() != m_manager) return;
00917 }
00918
00919 f = getAlignedPlaybackFrame();
00920
00921 if (m_playPointerFrame == f) return;
00922 bool visible = (getXForFrame(m_playPointerFrame) != getXForFrame(f));
00923 size_t oldPlayPointerFrame = m_playPointerFrame;
00924 m_playPointerFrame = f;
00925 if (!visible) return;
00926
00927 switch (m_followPlay) {
00928
00929 case PlaybackScrollContinuous:
00930 if (QApplication::mouseButtons() == Qt::NoButton) {
00931 setCentreFrame(f, false);
00932 }
00933 break;
00934
00935 case PlaybackScrollPage:
00936 {
00937 int xold = getXForFrame(oldPlayPointerFrame);
00938 update(xold - 1, 0, 3, height());
00939
00940 long w = getEndFrame() - getStartFrame();
00941 w -= w/5;
00942 long sf = (f / w) * w - w/8;
00943
00944 if (m_manager &&
00945 m_manager->isPlaying() &&
00946 m_manager->getPlaySelectionMode()) {
00947 MultiSelection::SelectionList selections = m_manager->getSelections();
00948 if (!selections.empty()) {
00949 size_t selectionStart = selections.begin()->getStartFrame();
00950 if (sf < long(selectionStart) - w / 10) {
00951 sf = long(selectionStart) - w / 10;
00952 }
00953 }
00954 }
00955
00956 #ifdef DEBUG_VIEW_WIDGET_PAINT
00957 std::cerr << "PlaybackScrollPage: f = " << f << ", sf = " << sf << ", start frame "
00958 << getStartFrame() << std::endl;
00959 #endif
00960
00961
00962
00963
00964 int xnew = getXForFrame(m_playPointerFrame);
00965
00966 #ifdef DEBUG_VIEW_WIDGET_PAINT
00967 std::cerr << "xnew = " << xnew << ", width = " << width() << std::endl;
00968 #endif
00969
00970 if (xnew < width()/8 || xnew > (width()*7)/8) {
00971 if (QApplication::mouseButtons() == Qt::NoButton) {
00972 long offset = getFrameForX(width()/2) - getStartFrame();
00973 long newCentre = sf + offset;
00974 bool changed = setCentreFrame(newCentre, false);
00975 if (changed) {
00976 xold = getXForFrame(oldPlayPointerFrame);
00977 update(xold - 1, 0, 3, height());
00978 }
00979 }
00980 }
00981
00982 update(xnew - 1, 0, 3, height());
00983
00984 break;
00985 }
00986
00987 case PlaybackIgnore:
00988 if (long(f) >= getStartFrame() && f < getEndFrame()) {
00989 update();
00990 }
00991 break;
00992 }
00993 }
00994
00995 void
00996 View::viewZoomLevelChanged(View *p, unsigned long z, bool locked)
00997 {
00998 #ifdef DEBUG_VIEW_WIDGET_PAINT
00999 std::cerr << "View[" << this << "]: viewZoomLevelChanged(" << p << ", " << z << ", " << locked << ")" << std::endl;
01000 #endif
01001 if (m_followZoom && p != this && locked) {
01002 setZoomLevel(z);
01003 }
01004 }
01005
01006 void
01007 View::selectionChanged()
01008 {
01009 if (m_selectionCached) {
01010 delete m_cache;
01011 m_cache = 0;
01012 m_selectionCached = false;
01013 }
01014 update();
01015 }
01016
01017 size_t
01018 View::getFirstVisibleFrame() const
01019 {
01020 long f0 = getStartFrame();
01021 size_t f = getModelsStartFrame();
01022 if (f0 < 0 || f0 < long(f)) return f;
01023 return f0;
01024 }
01025
01026 size_t
01027 View::getLastVisibleFrame() const
01028 {
01029 size_t f0 = getEndFrame();
01030 size_t f = getModelsEndFrame();
01031 if (f0 > f) return f;
01032 return f0;
01033 }
01034
01035 size_t
01036 View::getModelsStartFrame() const
01037 {
01038 bool first = true;
01039 size_t startFrame = 0;
01040
01041 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01042
01043 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
01044
01045 size_t thisStartFrame = (*i)->getModel()->getStartFrame();
01046
01047 if (first || thisStartFrame < startFrame) {
01048 startFrame = thisStartFrame;
01049 }
01050 first = false;
01051 }
01052 }
01053 return startFrame;
01054 }
01055
01056 size_t
01057 View::getModelsEndFrame() const
01058 {
01059 bool first = true;
01060 size_t endFrame = 0;
01061
01062 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01063
01064 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
01065
01066 size_t thisEndFrame = (*i)->getModel()->getEndFrame();
01067
01068 if (first || thisEndFrame > endFrame) {
01069 endFrame = thisEndFrame;
01070 }
01071 first = false;
01072 }
01073 }
01074
01075 if (first) return getModelsStartFrame();
01076 return endFrame;
01077 }
01078
01079 int
01080 View::getModelsSampleRate() const
01081 {
01083
01084
01085
01087
01088 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01089 if ((*i)->getModel() && (*i)->getModel()->isOK()) {
01090 return (*i)->getModel()->getSampleRate();
01091 }
01092 }
01093 return 0;
01094 }
01095
01096 View::ModelSet
01097 View::getModels()
01098 {
01099 ModelSet models;
01100
01101 for (int i = 0; i < getLayerCount(); ++i) {
01102
01103 Layer *layer = getLayer(i);
01104
01105 if (dynamic_cast<TimeRulerLayer *>(layer)) {
01106 continue;
01107 }
01108
01109 if (layer && layer->getModel()) {
01110 Model *model = layer->getModel();
01111 models.insert(model);
01112 }
01113 }
01114
01115 return models;
01116 }
01117
01118 Model *
01119 View::getAligningModel() const
01120 {
01121 if (!m_manager ||
01122 !m_manager->getAlignMode() ||
01123 !m_manager->getPlaybackModel()) {
01124 return 0;
01125 }
01126
01127 Model *anyModel = 0;
01128 Model *alignedModel = 0;
01129 Model *goodModel = 0;
01130
01131 for (LayerList::const_iterator i = m_layers.begin();
01132 i != m_layers.end(); ++i) {
01133
01134 Layer *layer = *i;
01135
01136 if (!layer) continue;
01137 if (dynamic_cast<TimeRulerLayer *>(layer)) continue;
01138
01139 Model *model = (*i)->getModel();
01140 if (!model) continue;
01141
01142 anyModel = model;
01143
01144 if (model->getAlignmentReference()) {
01145 alignedModel = model;
01146 if (layer->isLayerOpaque() ||
01147 dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
01148 goodModel = model;
01149 }
01150 }
01151 }
01152
01153 if (goodModel) return goodModel;
01154 else if (alignedModel) return alignedModel;
01155 else return anyModel;
01156 }
01157
01158 size_t
01159 View::alignFromReference(size_t f) const
01160 {
01161 if (!m_manager->getAlignMode()) return f;
01162 Model *aligningModel = getAligningModel();
01163 if (!aligningModel) return f;
01164 return aligningModel->alignFromReference(f);
01165 }
01166
01167 size_t
01168 View::alignToReference(size_t f) const
01169 {
01170 if (!m_manager->getAlignMode()) return f;
01171 Model *aligningModel = getAligningModel();
01172 if (!aligningModel) return f;
01173 return aligningModel->alignToReference(f);
01174 }
01175
01176 int
01177 View::getAlignedPlaybackFrame() const
01178 {
01179 int pf = m_manager->getPlaybackFrame();
01180 if (!m_manager->getAlignMode()) return pf;
01181
01182 Model *aligningModel = getAligningModel();
01183 if (!aligningModel) return pf;
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194 int af = aligningModel->alignFromReference(pf);
01195
01196
01197 return af;
01198 }
01199
01200 bool
01201 View::areLayersScrollable() const
01202 {
01203
01204 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01205 if (!(*i)->isLayerScrollable(this)) return false;
01206 }
01207 return true;
01208 }
01209
01210 View::LayerList
01211 View::getScrollableBackLayers(bool testChanged, bool &changed) const
01212 {
01213 changed = false;
01214
01215
01216
01217
01218 LayerList scrollables;
01219 bool metUnscrollable = false;
01220
01221 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01222
01223
01224
01225
01226 if ((*i)->isLayerDormant(this)) continue;
01227 if ((*i)->isLayerOpaque()) {
01228
01229 scrollables.clear();
01230 if (metUnscrollable) break;
01231 }
01232 if (!metUnscrollable && (*i)->isLayerScrollable(this)) {
01233 scrollables.push_back(*i);
01234 } else {
01235 metUnscrollable = true;
01236 }
01237 }
01238
01239 if (testChanged && scrollables != m_lastScrollableBackLayers) {
01240 m_lastScrollableBackLayers = scrollables;
01241 changed = true;
01242 }
01243 return scrollables;
01244 }
01245
01246 View::LayerList
01247 View::getNonScrollableFrontLayers(bool testChanged, bool &changed) const
01248 {
01249 changed = false;
01250 LayerList nonScrollables;
01251
01252
01253
01254
01255 bool started = false;
01256
01257 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01258 if ((*i)->isLayerDormant(this)) continue;
01259 if (!started && (*i)->isLayerScrollable(this)) {
01260 continue;
01261 }
01262 started = true;
01263 if ((*i)->isLayerOpaque()) {
01264
01265 nonScrollables.clear();
01266 }
01267 nonScrollables.push_back(*i);
01268 }
01269
01270 if (testChanged && nonScrollables != m_lastNonScrollableBackLayers) {
01271 m_lastNonScrollableBackLayers = nonScrollables;
01272 changed = true;
01273 }
01274
01275 return nonScrollables;
01276 }
01277
01278 size_t
01279 View::getZoomConstraintBlockSize(size_t blockSize,
01280 ZoomConstraint::RoundingDirection dir)
01281 const
01282 {
01283 size_t candidate = blockSize;
01284 bool haveCandidate = false;
01285
01286 PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
01287
01288 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01289
01290 const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
01291 if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
01292
01293 size_t thisBlockSize =
01294 zoomConstraint->getNearestBlockSize(blockSize, dir);
01295
01296
01297
01298 if (!haveCandidate ||
01299 (thisBlockSize > blockSize && thisBlockSize > candidate) ||
01300 (thisBlockSize < blockSize && thisBlockSize < candidate)) {
01301 candidate = thisBlockSize;
01302 haveCandidate = true;
01303 }
01304 }
01305
01306 return candidate;
01307 }
01308
01309 bool
01310 View::areLayerColoursSignificant() const
01311 {
01312 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
01313 if ((*i)->getLayerColourSignificance() ==
01314 Layer::ColourHasMeaningfulValue) return true;
01315 if ((*i)->isLayerOpaque()) break;
01316 }
01317 return false;
01318 }
01319
01320 bool
01321 View::hasTopLayerTimeXAxis() const
01322 {
01323 LayerList::const_iterator i = m_layers.end();
01324 if (i == m_layers.begin()) return false;
01325 --i;
01326 return (*i)->hasTimeXAxis();
01327 }
01328
01329 void
01330 View::zoom(bool in)
01331 {
01332 int newZoomLevel = m_zoomLevel;
01333
01334 if (in) {
01335 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1,
01336 ZoomConstraint::RoundDown);
01337 } else {
01338 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1,
01339 ZoomConstraint::RoundUp);
01340 }
01341
01342 if (newZoomLevel != m_zoomLevel) {
01343 setZoomLevel(newZoomLevel);
01344 }
01345 }
01346
01347 void
01348 View::scroll(bool right, bool lots)
01349 {
01350 long delta;
01351 if (lots) {
01352 delta = (getEndFrame() - getStartFrame()) / 2;
01353 } else {
01354 delta = (getEndFrame() - getStartFrame()) / 20;
01355 }
01356 if (right) delta = -delta;
01357
01358 if (int(m_centreFrame) < delta) {
01359 setCentreFrame(0);
01360 } else if (int(m_centreFrame) - delta >= int(getModelsEndFrame())) {
01361 setCentreFrame(getModelsEndFrame());
01362 } else {
01363 setCentreFrame(m_centreFrame - delta);
01364 }
01365 }
01366
01367 void
01368 View::checkProgress(void *object)
01369 {
01370 if (!m_showProgress) return;
01371
01372 int ph = height();
01373
01374 for (ProgressMap::const_iterator i = m_progressBars.begin();
01375 i != m_progressBars.end(); ++i) {
01376
01377 if (i->first == object) {
01378
01379 int completion = i->first->getCompletion(this);
01380 QString text = i->first->getPropertyContainerName();
01381
01382 if (completion >= 100) {
01383
01385 Model *model = i->first->getModel();
01386 RangeSummarisableTimeValueModel *wfm =
01387 dynamic_cast<RangeSummarisableTimeValueModel *>(model);
01388 if (wfm ||
01389 (wfm = dynamic_cast<RangeSummarisableTimeValueModel *>
01390 (model->getSourceModel()))) {
01391 completion = wfm->getAlignmentCompletion();
01392 if (completion < 100) {
01393 text = tr("Alignment");
01394 }
01395 }
01396 }
01397
01398 if (completion >= 100) {
01399
01400 i->second->hide();
01401
01402 } else {
01403
01404 i->second->setText(text);
01405
01406 i->second->setValue(completion);
01407 i->second->move(0, ph - i->second->height());
01408
01409 i->second->show();
01410 i->second->update();
01411
01412 ph -= i->second->height();
01413 }
01414 } else {
01415 if (i->second->isVisible()) {
01416 ph -= i->second->height();
01417 }
01418 }
01419 }
01420 }
01421
01422 void
01423 View::setPaintFont(QPainter &paint)
01424 {
01425 QFont font(paint.font());
01426 font.setPointSize(Preferences::getInstance()->getViewFontSize());
01427 paint.setFont(font);
01428 }
01429
01430 void
01431 View::paintEvent(QPaintEvent *e)
01432 {
01433
01434
01435
01436 if (m_layers.empty()) {
01437 QFrame::paintEvent(e);
01438 return;
01439 }
01440
01441
01442
01450 QPainter paint;
01451 bool repaintCache = false;
01452 bool paintedCacheRect = false;
01453
01454 QRect cacheRect(rect());
01455
01456 if (e) {
01457 cacheRect &= e->rect();
01458 #ifdef DEBUG_VIEW_WIDGET_PAINT
01459 std::cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
01460 << ", my rect " << width() << "x" << height() << std::endl;
01461 #endif
01462 }
01463
01464 QRect nonCacheRect(cacheRect);
01465
01466
01467
01468
01469 bool layersChanged = false;
01470 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
01471 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged);
01472 bool selectionCacheable = nonScrollables.empty();
01473 bool haveSelections = m_manager && !m_manager->getSelections().empty();
01474 bool selectionDrawn = false;
01475
01476
01477
01478
01479
01480 if (!selectionCacheable) {
01481 selectionCacheable = true;
01482 for (LayerList::const_iterator i = nonScrollables.begin();
01483 i != nonScrollables.end(); ++i) {
01484 if ((*i)->isLayerOpaque()) {
01485 selectionCacheable = false;
01486 break;
01487 }
01488 }
01489 }
01490
01491 if (selectionCacheable) {
01492 QPoint localPos;
01493 bool closeToLeft, closeToRight;
01494 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
01495 selectionCacheable = false;
01496 }
01497 }
01498
01499 #ifdef DEBUG_VIEW_WIDGET_PAINT
01500 std::cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
01501 << " scrollable back layers and " << nonScrollables.size()
01502 << " non-scrollable front layers" << std::endl;
01503 std::cerr << "haveSelections " << haveSelections << ", selectionCacheable "
01504 << selectionCacheable << ", m_selectionCached " << m_selectionCached << std::endl;
01505 #endif
01506
01507 if (layersChanged || scrollables.empty() ||
01508 (haveSelections && (selectionCacheable != m_selectionCached))) {
01509 delete m_cache;
01510 m_cache = 0;
01511 m_selectionCached = false;
01512 }
01513
01514 if (!scrollables.empty()) {
01515
01516 #ifdef DEBUG_VIEW_WIDGET_PAINT
01517 std::cerr << "View(" << this << "): cache " << m_cache << ", cache zoom "
01518 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << std::endl;
01519 #endif
01520
01521 if (!m_cache ||
01522 m_cacheZoomLevel != m_zoomLevel ||
01523 width() != m_cache->width() ||
01524 height() != m_cache->height()) {
01525
01526
01527
01528 if (cacheRect.width() < width()/10) {
01529 delete m_cache;
01530 m_cache = 0;
01531 #ifdef DEBUG_VIEW_WIDGET_PAINT
01532 std::cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << std::endl;
01533 #endif
01534 } else {
01535 delete m_cache;
01536 m_cache = new QPixmap(width(), height());
01537 #ifdef DEBUG_VIEW_WIDGET_PAINT
01538 std::cerr << "View(" << this << ")::paintEvent: recreated cache" << std::endl;
01539 #endif
01540 cacheRect = rect();
01541 repaintCache = true;
01542 }
01543
01544 } else if (m_cacheCentreFrame != m_centreFrame) {
01545
01546 long dx =
01547 getXForFrame(m_cacheCentreFrame) -
01548 getXForFrame(m_centreFrame);
01549
01550 if (dx > -width() && dx < width()) {
01551 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC)
01552
01553
01554 static QPixmap *tmpPixmap = 0;
01555 if (!tmpPixmap ||
01556 tmpPixmap->width() != width() ||
01557 tmpPixmap->height() != height()) {
01558 delete tmpPixmap;
01559 tmpPixmap = new QPixmap(width(), height());
01560 }
01561 paint.begin(tmpPixmap);
01562 paint.drawPixmap(0, 0, *m_cache);
01563 paint.end();
01564 paint.begin(m_cache);
01565 paint.drawPixmap(dx, 0, *tmpPixmap);
01566 paint.end();
01567 #else
01568
01569 paint.begin(m_cache);
01570 paint.drawPixmap(dx, 0, *m_cache);
01571 paint.end();
01572 #endif
01573
01574 if (dx < 0) {
01575 cacheRect = QRect(width() + dx, 0, -dx, height());
01576 } else {
01577 cacheRect = QRect(0, 0, dx, height());
01578 }
01579 #ifdef DEBUG_VIEW_WIDGET_PAINT
01580 std::cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << std::endl;
01581 #endif
01582 } else {
01583 cacheRect = rect();
01584 #ifdef DEBUG_VIEW_WIDGET_PAINT
01585 std::cerr << "View(" << this << ")::paintEvent: scrolling too far" << std::endl;
01586 #endif
01587 }
01588 repaintCache = true;
01589
01590 } else {
01591 #ifdef DEBUG_VIEW_WIDGET_PAINT
01592 std::cerr << "View(" << this << ")::paintEvent: cache is good" << std::endl;
01593 #endif
01594 paint.begin(this);
01595 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
01596 paint.end();
01597 QFrame::paintEvent(e);
01598 paintedCacheRect = true;
01599 }
01600
01601 m_cacheCentreFrame = m_centreFrame;
01602 m_cacheZoomLevel = m_zoomLevel;
01603 }
01604
01605 #ifdef DEBUG_VIEW_WIDGET_PAINT
01606
01607 #endif
01608
01609
01610
01611 if (!paintedCacheRect) {
01612
01613 if (repaintCache) paint.begin(m_cache);
01614 else paint.begin(this);
01615 setPaintFont(paint);
01616 paint.setClipRect(cacheRect);
01617
01618 paint.setPen(getBackground());
01619 paint.setBrush(getBackground());
01620 paint.drawRect(cacheRect);
01621
01622 paint.setPen(getForeground());
01623 paint.setBrush(Qt::NoBrush);
01624
01625 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
01626 paint.setRenderHint(QPainter::Antialiasing, false);
01627 paint.save();
01628 (*i)->paint(this, paint, cacheRect);
01629 paint.restore();
01630 }
01631
01632 if (haveSelections && selectionCacheable) {
01633 drawSelections(paint);
01634 m_selectionCached = repaintCache;
01635 selectionDrawn = true;
01636 }
01637
01638 paint.end();
01639
01640 if (repaintCache) {
01641 cacheRect |= (e ? e->rect() : rect());
01642 paint.begin(this);
01643 paint.drawPixmap(cacheRect, *m_cache, cacheRect);
01644 paint.end();
01645 }
01646 }
01647
01648
01649
01650
01651
01652 nonCacheRect |= cacheRect;
01653
01654 paint.begin(this);
01655 paint.setClipRect(nonCacheRect);
01656 setPaintFont(paint);
01657 if (scrollables.empty()) {
01658 paint.setPen(getBackground());
01659 paint.setBrush(getBackground());
01660 paint.drawRect(nonCacheRect);
01661 }
01662
01663 paint.setPen(getForeground());
01664 paint.setBrush(Qt::NoBrush);
01665
01666 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
01667
01668 (*i)->paint(this, paint, nonCacheRect);
01669 }
01670
01671 paint.end();
01672
01673 paint.begin(this);
01674 setPaintFont(paint);
01675 if (e) paint.setClipRect(e->rect());
01676 if (!m_selectionCached) {
01677 drawSelections(paint);
01678 }
01679 paint.end();
01680
01681 bool showPlayPointer = true;
01682 if (m_followPlay == PlaybackScrollContinuous) {
01683 showPlayPointer = false;
01684 } else if (long(m_playPointerFrame) <= getStartFrame() ||
01685 m_playPointerFrame >= getEndFrame()) {
01686 showPlayPointer = false;
01687 } else if (m_manager && !m_manager->isPlaying()) {
01688 if (m_playPointerFrame == getCentreFrame() &&
01689 m_followPlay != PlaybackIgnore) {
01690 showPlayPointer = false;
01691 }
01692 }
01693
01694 if (showPlayPointer) {
01695
01696 paint.begin(this);
01697
01698 int playx = getXForFrame(m_playPointerFrame);
01699
01700 paint.setPen(getForeground());
01701 paint.drawLine(playx - 1, 0, playx - 1, height() - 1);
01702 paint.drawLine(playx + 1, 0, playx + 1, height() - 1);
01703 paint.drawPoint(playx, 0);
01704 paint.drawPoint(playx, height() - 1);
01705 paint.setPen(getBackground());
01706 paint.drawLine(playx, 1, playx, height() - 2);
01707
01708 paint.end();
01709 }
01710
01711 QFrame::paintEvent(e);
01712 }
01713
01714 void
01715 View::drawSelections(QPainter &paint)
01716 {
01717 if (!hasTopLayerTimeXAxis()) return;
01718
01719 MultiSelection::SelectionList selections;
01720
01721 if (m_manager) {
01722 selections = m_manager->getSelections();
01723 if (m_manager->haveInProgressSelection()) {
01724 bool exclusive;
01725 Selection inProgressSelection =
01726 m_manager->getInProgressSelection(exclusive);
01727 if (exclusive) selections.clear();
01728 selections.insert(inProgressSelection);
01729 }
01730 }
01731
01732 paint.save();
01733
01734 bool translucent = !areLayerColoursSignificant();
01735
01736 if (translucent) {
01737 paint.setBrush(QColor(150, 150, 255, 80));
01738 } else {
01739 paint.setBrush(Qt::NoBrush);
01740 }
01741
01742 int sampleRate = getModelsSampleRate();
01743
01744 QPoint localPos;
01745 long illuminateFrame = -1;
01746 bool closeToLeft, closeToRight;
01747
01748 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
01749 illuminateFrame = getFrameForX(localPos.x());
01750 }
01751
01752 const QFontMetrics &metrics = paint.fontMetrics();
01753
01754 for (MultiSelection::SelectionList::iterator i = selections.begin();
01755 i != selections.end(); ++i) {
01756
01757 int p0 = getXForFrame(alignFromReference(i->getStartFrame()));
01758 int p1 = getXForFrame(alignFromReference(i->getEndFrame()));
01759
01760 if (p1 < 0 || p0 > width()) continue;
01761
01762 #ifdef DEBUG_VIEW_WIDGET_PAINT
01763 std::cerr << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << std::endl;
01764 #endif
01765
01766 bool illuminateThis =
01767 (illuminateFrame >= 0 && i->contains(illuminateFrame));
01768
01769 paint.setPen(QColor(150, 150, 255));
01770
01771 if (translucent && shouldLabelSelections()) {
01772 paint.drawRect(p0, -1, p1 - p0, height() + 1);
01773 } else {
01774
01775
01776
01777
01778 paint.drawRect(p0, 0, p1 - p0, height() - 1);
01779 }
01780
01781 if (illuminateThis) {
01782 paint.save();
01783 paint.setPen(QPen(getForeground(), 2));
01784 if (closeToLeft) {
01785 paint.drawLine(p0, 1, p1, 1);
01786 paint.drawLine(p0, 0, p0, height());
01787 paint.drawLine(p0, height() - 1, p1, height() - 1);
01788 } else if (closeToRight) {
01789 paint.drawLine(p0, 1, p1, 1);
01790 paint.drawLine(p1, 0, p1, height());
01791 paint.drawLine(p0, height() - 1, p1, height() - 1);
01792 } else {
01793 paint.setBrush(Qt::NoBrush);
01794 paint.drawRect(p0, 1, p1 - p0, height() - 2);
01795 }
01796 paint.restore();
01797 }
01798
01799 if (sampleRate && shouldLabelSelections() && m_manager &&
01800 m_manager->shouldShowSelectionExtents()) {
01801
01802 QString startText = QString("%1 / %2")
01803 .arg(QString::fromStdString
01804 (RealTime::frame2RealTime
01805 (i->getStartFrame(), sampleRate).toText(true)))
01806 .arg(i->getStartFrame());
01807
01808 QString endText = QString(" %1 / %2")
01809 .arg(QString::fromStdString
01810 (RealTime::frame2RealTime
01811 (i->getEndFrame(), sampleRate).toText(true)))
01812 .arg(i->getEndFrame());
01813
01814 QString durationText = QString("(%1 / %2) ")
01815 .arg(QString::fromStdString
01816 (RealTime::frame2RealTime
01817 (i->getEndFrame() - i->getStartFrame(), sampleRate)
01818 .toText(true)))
01819 .arg(i->getEndFrame() - i->getStartFrame());
01820
01821 int sw = metrics.width(startText),
01822 ew = metrics.width(endText),
01823 dw = metrics.width(durationText);
01824
01825 int sy = metrics.ascent() + metrics.height() + 4;
01826 int ey = sy;
01827 int dy = sy + metrics.height();
01828
01829 int sx = p0 + 2;
01830 int ex = sx;
01831 int dx = sx;
01832
01833 if (sw + ew > (p1 - p0)) {
01834 ey += metrics.height();
01835 dy += metrics.height();
01836 }
01837
01838 if (ew < (p1 - p0)) {
01839 ex = p1 - 2 - ew;
01840 }
01841
01842 if (dw < (p1 - p0)) {
01843 dx = p1 - 2 - dw;
01844 }
01845
01846 paint.drawText(sx, sy, startText);
01847 paint.drawText(ex, ey, endText);
01848 paint.drawText(dx, dy, durationText);
01849 }
01850 }
01851
01852 paint.restore();
01853 }
01854
01855 void
01856 View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r,
01857 bool focus) const
01858 {
01859
01860
01861
01862 if (r.x() + r.width() < 0 || r.x() >= width()) return;
01863
01864 if (r.width() != 0 || r.height() != 0) {
01865 paint.save();
01866 if (focus) {
01867 paint.setPen(Qt::NoPen);
01868 QColor brushColour(Qt::black);
01869 brushColour.setAlpha(hasLightBackground() ? 15 : 40);
01870 paint.setBrush(brushColour);
01871 if (r.x() > 0) {
01872 paint.drawRect(0, 0, r.x(), height());
01873 }
01874 if (r.x() + r.width() < width()) {
01875 paint.drawRect(r.x() + r.width(), 0, width()-r.x()-r.width(), height());
01876 }
01877 if (r.y() > 0) {
01878 paint.drawRect(r.x(), 0, r.width(), r.y());
01879 }
01880 if (r.y() + r.height() < height()) {
01881 paint.drawRect(r.x(), r.y() + r.height(), r.width(), height()-r.y()-r.height());
01882 }
01883 paint.setBrush(Qt::NoBrush);
01884 }
01885 paint.setPen(Qt::green);
01886 paint.drawRect(r);
01887 paint.restore();
01888 } else {
01889 paint.save();
01890 paint.setPen(Qt::green);
01891 paint.drawPoint(r.x(), r.y());
01892 paint.restore();
01893 }
01894
01895 if (!focus) return;
01896
01897 paint.save();
01898 QFont fn = paint.font();
01899 if (fn.pointSize() > 8) {
01900 fn.setPointSize(fn.pointSize() - 1);
01901 paint.setFont(fn);
01902 }
01903
01904 int fontHeight = paint.fontMetrics().height();
01905 int fontAscent = paint.fontMetrics().ascent();
01906
01907 float v0, v1;
01908 QString u0, u1;
01909 bool b0 = false, b1 = false;
01910
01911 QString axs, ays, bxs, bys, dxs, dys;
01912
01913 int axx, axy, bxx, bxy, dxx, dxy;
01914 int aw = 0, bw = 0, dw = 0;
01915
01916 int labelCount = 0;
01917
01918
01919
01920 if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) {
01921 axs = QString("%1 %2").arg(v0).arg(u0);
01922 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
01923 axs = QString("%1 (%2)").arg(axs)
01924 .arg(Pitch::getPitchLabelForFrequency(v0));
01925 }
01926 aw = paint.fontMetrics().width(axs);
01927 ++labelCount;
01928 }
01929
01930
01931
01932 if (r.width() > 0) {
01933 if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) {
01934 bxs = QString("%1 %2").arg(v1).arg(u1);
01935 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
01936 bxs = QString("%1 (%2)").arg(bxs)
01937 .arg(Pitch::getPitchLabelForFrequency(v1));
01938 }
01939 bw = paint.fontMetrics().width(bxs);
01940 }
01941 }
01942
01943
01944
01945 if (b0 && b1 && v1 != v0 && u0 == u1) {
01946 dxs = QString("[%1 %2]").arg(fabs(v1 - v0)).arg(u1);
01947 dw = paint.fontMetrics().width(dxs);
01948 }
01949
01950 b0 = false;
01951 b1 = false;
01952
01953
01954
01955 if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) {
01956 ays = QString("%1 %2").arg(v0).arg(u0);
01957 if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
01958 ays = QString("%1 (%2)").arg(ays)
01959 .arg(Pitch::getPitchLabelForFrequency(v0));
01960 }
01961 aw = std::max(aw, paint.fontMetrics().width(ays));
01962 ++labelCount;
01963 }
01964
01965
01966
01967 if (r.height() > 0) {
01968 if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) {
01969 bys = QString("%1 %2").arg(v1).arg(u1);
01970 if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
01971 bys = QString("%1 (%2)").arg(bys)
01972 .arg(Pitch::getPitchLabelForFrequency(v1));
01973 }
01974 bw = std::max(bw, paint.fontMetrics().width(bys));
01975 }
01976 }
01977
01978 bool bd = false;
01979 float dy = 0.f;
01980 QString du;
01981
01982
01983
01984 if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(),
01985 dy, du)) &&
01986 dy != 0) {
01987 if (du != "") {
01988 if (du == "Hz") {
01989 int semis;
01990 float cents;
01991 semis = Pitch::getPitchForFrequencyDifference(v0, v1, ¢s);
01992 dys = QString("[%1 %2 (%3)]")
01993 .arg(dy).arg(du)
01994 .arg(Pitch::getLabelForPitchRange(semis, cents));
01995 } else {
01996 dys = QString("[%1 %2]").arg(dy).arg(du);
01997 }
01998 } else {
01999 dys = QString("[%1]").arg(dy);
02000 }
02001 dw = std::max(dw, paint.fontMetrics().width(dys));
02002 }
02003
02004 int mw = r.width();
02005 int mh = r.height();
02006
02007 bool edgeLabelsInside = false;
02008 bool sizeLabelsInside = false;
02009
02010 if (mw < std::max(aw, std::max(bw, dw)) + 4) {
02011
02012 } else if (mw < aw + bw + 4) {
02013 if (mh > fontHeight * labelCount * 3 + 4) {
02014 edgeLabelsInside = true;
02015 sizeLabelsInside = true;
02016 } else if (mh > fontHeight * labelCount * 2 + 4) {
02017 edgeLabelsInside = true;
02018 }
02019 } else if (mw < aw + bw + dw + 4) {
02020 if (mh > fontHeight * labelCount * 3 + 4) {
02021 edgeLabelsInside = true;
02022 sizeLabelsInside = true;
02023 } else if (mh > fontHeight * labelCount + 4) {
02024 edgeLabelsInside = true;
02025 }
02026 } else {
02027 if (mh > fontHeight * labelCount + 4) {
02028 edgeLabelsInside = true;
02029 sizeLabelsInside = true;
02030 }
02031 }
02032
02033 if (edgeLabelsInside) {
02034
02035 axx = r.x() + 2;
02036 axy = r.y() + fontAscent + 2;
02037
02038 bxx = r.x() + r.width() - bw - 2;
02039 bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
02040
02041 } else {
02042
02043 axx = r.x() - aw - 2;
02044 axy = r.y() + fontAscent;
02045
02046 bxx = r.x() + r.width() + 2;
02047 bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
02048 }
02049
02050 dxx = r.width()/2 + r.x() - dw/2;
02051
02052 if (sizeLabelsInside) {
02053
02054 dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
02055
02056 } else {
02057
02058 dxy = r.y() + r.height() + fontAscent + 2;
02059 }
02060
02061 if (axs != "") {
02062 drawVisibleText(paint, axx, axy, axs, OutlinedText);
02063 axy += fontHeight;
02064 }
02065
02066 if (ays != "") {
02067 drawVisibleText(paint, axx, axy, ays, OutlinedText);
02068 axy += fontHeight;
02069 }
02070
02071 if (bxs != "") {
02072 drawVisibleText(paint, bxx, bxy, bxs, OutlinedText);
02073 bxy += fontHeight;
02074 }
02075
02076 if (bys != "") {
02077 drawVisibleText(paint, bxx, bxy, bys, OutlinedText);
02078 bxy += fontHeight;
02079 }
02080
02081 if (dxs != "") {
02082 drawVisibleText(paint, dxx, dxy, dxs, OutlinedText);
02083 dxy += fontHeight;
02084 }
02085
02086 if (dys != "") {
02087 drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
02088 dxy += fontHeight;
02089 }
02090
02091 paint.restore();
02092 }
02093
02094 bool
02095 View::render(QPainter &paint, int xorigin, size_t f0, size_t f1)
02096 {
02097 size_t x0 = f0 / m_zoomLevel;
02098 size_t x1 = f1 / m_zoomLevel;
02099
02100 size_t w = x1 - x0;
02101
02102 size_t origCentreFrame = m_centreFrame;
02103
02104 bool someLayersIncomplete = false;
02105
02106 for (LayerList::iterator i = m_layers.begin();
02107 i != m_layers.end(); ++i) {
02108
02109 int c = (*i)->getCompletion(this);
02110 if (c < 100) {
02111 someLayersIncomplete = true;
02112 break;
02113 }
02114 }
02115
02116 if (someLayersIncomplete) {
02117
02118 QProgressDialog progress(tr("Waiting for layers to be ready..."),
02119 tr("Cancel"), 0, 100, this);
02120
02121 int layerCompletion = 0;
02122
02123 while (layerCompletion < 100) {
02124
02125 for (LayerList::iterator i = m_layers.begin();
02126 i != m_layers.end(); ++i) {
02127
02128 int c = (*i)->getCompletion(this);
02129 if (i == m_layers.begin() || c < layerCompletion) {
02130 layerCompletion = c;
02131 }
02132 }
02133
02134 if (layerCompletion >= 100) break;
02135
02136 progress.setValue(layerCompletion);
02137 qApp->processEvents();
02138 if (progress.wasCanceled()) {
02139 update();
02140 return false;
02141 }
02142
02143 usleep(50000);
02144 }
02145 }
02146
02147 QProgressDialog progress(tr("Rendering image..."),
02148 tr("Cancel"), 0, w / width(), this);
02149
02150 for (size_t x = 0; x < w; x += width()) {
02151
02152 progress.setValue(x / width());
02153 qApp->processEvents();
02154 if (progress.wasCanceled()) {
02155 m_centreFrame = origCentreFrame;
02156 update();
02157 return false;
02158 }
02159
02160 m_centreFrame = f0 + (x + width()/2) * m_zoomLevel;
02161
02162 QRect chunk(0, 0, width(), height());
02163
02164 paint.setPen(getBackground());
02165 paint.setBrush(getBackground());
02166
02167 paint.drawRect(QRect(xorigin + x, 0, width(), height()));
02168
02169 paint.setPen(getForeground());
02170 paint.setBrush(Qt::NoBrush);
02171
02172 for (LayerList::iterator i = m_layers.begin();
02173 i != m_layers.end(); ++i) {
02174
02175 paint.setRenderHint(QPainter::Antialiasing, false);
02176
02177 paint.save();
02178 paint.translate(xorigin + x, 0);
02179
02180 std::cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << std::endl;
02181
02182 (*i)->paint(this, paint, chunk);
02183
02184 paint.restore();
02185 }
02186 }
02187
02188 m_centreFrame = origCentreFrame;
02189 update();
02190 return true;
02191 }
02192
02193 QImage *
02194 View::toNewImage()
02195 {
02196 size_t f0 = getModelsStartFrame();
02197 size_t f1 = getModelsEndFrame();
02198
02199 return toNewImage(f0, f1);
02200 }
02201
02202 QImage *
02203 View::toNewImage(size_t f0, size_t f1)
02204 {
02205 size_t x0 = f0 / getZoomLevel();
02206 size_t x1 = f1 / getZoomLevel();
02207
02208 QImage *image = new QImage(x1 - x0, height(), QImage::Format_RGB32);
02209
02210 QPainter *paint = new QPainter(image);
02211 if (!render(*paint, 0, f0, f1)) {
02212 delete paint;
02213 delete image;
02214 return 0;
02215 } else {
02216 delete paint;
02217 return image;
02218 }
02219 }
02220
02221 QSize
02222 View::getImageSize()
02223 {
02224 size_t f0 = getModelsStartFrame();
02225 size_t f1 = getModelsEndFrame();
02226
02227 return getImageSize(f0, f1);
02228 }
02229
02230 QSize
02231 View::getImageSize(size_t f0, size_t f1)
02232 {
02233 size_t x0 = f0 / getZoomLevel();
02234 size_t x1 = f1 / getZoomLevel();
02235
02236 return QSize(x1 - x0, height());
02237 }
02238
02239 void
02240 View::toXml(QTextStream &stream,
02241 QString indent, QString extraAttributes) const
02242 {
02243 stream << indent;
02244
02245 stream << QString("<view "
02246 "centre=\"%1\" "
02247 "zoom=\"%2\" "
02248 "followPan=\"%3\" "
02249 "followZoom=\"%4\" "
02250 "tracking=\"%5\" "
02251 " %6>\n")
02252 .arg(m_centreFrame)
02253 .arg(m_zoomLevel)
02254 .arg(m_followPan)
02255 .arg(m_followZoom)
02256 .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
02257 m_followPlay == PlaybackScrollPage ? "page" : "ignore")
02258 .arg(extraAttributes);
02259
02260 for (size_t i = 0; i < m_layers.size(); ++i) {
02261 bool visible = !m_layers[i]->isLayerDormant(this);
02262 m_layers[i]->toBriefXml(stream, indent + " ",
02263 QString("visible=\"%1\"")
02264 .arg(visible ? "true" : "false"));
02265 }
02266
02267 stream << indent + "</view>\n";
02268 }
02269
02270 ViewPropertyContainer::ViewPropertyContainer(View *v) :
02271 m_v(v)
02272 {
02273 connect(m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
02274 this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
02275 }
02276