annotate view/View.cpp @ 1330:c1f719094c25 zoom

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