annotate view/View.cpp @ 312:6de6f78b13a1

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